-
-
Notifications
You must be signed in to change notification settings - Fork 140
Expand file tree
/
Copy pathDCCConsist.cpp
More file actions
112 lines (100 loc) · 3.8 KB
/
DCCConsist.cpp
File metadata and controls
112 lines (100 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "DCCConsist.h"
#include "LocoSlot.h"
#include "StringFormatter.h"
#include "DIAG.h"
bool DCCConsist::parse(Print * stream, byte params, int16_t p[]) {
if (params==0) {
for (auto slot=LocoSlot::getFirst();slot;slot=slot->getNext()) {
if (slot->isConsistLead()) {
StringFormatter::send(stream,F("<^"));
for (auto cslot=slot;cslot;cslot=cslot->getConsistNext()) {
StringFormatter::send(stream,
cslot->isConsistReverse() ? F(" -%d") : F(" %d"),
cslot->getLoco());
}
StringFormatter::send(stream,F(" >\n"));
}
}
return true;
}
// Detect any invalid locoids or duplicates
for (byte i=0;i<params;i++) {
uint16_t locoId=abs(p[i]);
if (locoId<1 || locoId>10239) {
StringFormatter::send(stream,F("<* Invalid locoid %d *>"),p[i]);
return false;
}
for (byte j=i+1;j<params;j++) {
if (abs(p[j])==locoId) {
StringFormatter::send(stream,F("<* Duplicate locoid %d *>"),p[i]);
return false;
}
}
}
// Cross check other consists
// if p[0] is a consist lead, kill its consist first
auto slot=LocoSlot::getSlot(abs(p[0]),false);
if (slot && slot->isConsistLead()) {
DCCConsist::deleteAnyConsist(p[0]);
}
if (params<2) return true; // we only had to delete
for (byte i=0;i<params;i++) {
auto slot=LocoSlot::getSlot(abs(p[i]),false);
if (slot && (slot->isConsistLead() || slot->isConsistFollower())) {
StringFormatter::send(stream,F("<* Loco %d in another consist *>"),abs(p[i]));
return false;
}
}
auto leadLoco=LocoSlot::getSlot(abs(p[0]),true);
leadLoco->setConsistReverse(p[0]<0);
LocoSlot * prev=leadLoco;
for (byte i=1;i<params;i++) {
auto slot=LocoSlot::getSlot(abs(p[i]),true);
slot->setConsistLead(leadLoco);
slot->setConsistReverse(p[i]<0);
prev->setConsistNext(slot);
prev=slot;
}
return true;
}
void DCCConsist::deleteAnyConsist(int16_t locoid) {
locoid=abs(locoid); // in case of (valid) negative
auto slot=LocoSlot::getSlot(locoid,false);
if (!slot) return; // no such loco, nothing to do
if (!slot->isConsistLead()) slot=slot->getConsistLead();
if (!slot) return; // not in consist, nothing to do
while(slot) {
auto next=slot->getConsistNext();
slot->setConsistLead(nullptr);
slot->setConsistNext(nullptr);
slot->setConsistReverse(false);
slot=next;
}
}
bool DCCConsist::addLocoToConsist(uint16_t consistId,uint16_t locoId, bool revesed) {
if (consistId<1 || consistId>10239) return false;
if (locoId<1 || locoId>10239) return false;
if (locoId==consistId) return true; // cant add lead to itself
auto leadSlot=LocoSlot::getSlot(consistId,true);
if (!leadSlot) return false; // no ram
// back up to lead of existing consist
while(leadSlot->getConsistLead()) {
leadSlot=leadSlot->getConsistLead();
}
// find tail of consist
auto tailSlot=leadSlot;
while(tailSlot->getConsistNext()) {
tailSlot=tailSlot->getConsistNext();
}
auto addSlot=LocoSlot::getSlot(locoId,true);
if (!addSlot) return false; // no ram
if (addSlot->isConsistLead() || addSlot->isConsistFollower()) {
DIAG(F("Loco %d already in a consist"),locoId);
return false; // already in consist
}
// All OK so chain in. (belt and braces prevent self reference loop)
addSlot->setConsistReverse(revesed);
if (addSlot!=leadSlot) addSlot->setConsistLead(leadSlot);
if (tailSlot!=addSlot) tailSlot->setConsistNext(addSlot);
return true;
}