mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-24 16:46:13 +01:00
Compare commits
39 Commits
1b069aa941
...
90c2a77007
Author | SHA1 | Date | |
---|---|---|---|
|
90c2a77007 | ||
|
27a5f76a8d | ||
|
754bd99381 | ||
|
650e411a4f | ||
|
0978bb0c11 | ||
|
6eb7051fd6 | ||
|
5726844c83 | ||
|
0214a55b23 | ||
|
7db4a9575a | ||
|
8b8e9e4919 | ||
|
ce84974967 | ||
|
034c441c34 | ||
|
d5978b1578 | ||
|
ea4f90d5fc | ||
|
1181fd855d | ||
|
a092e06a6f | ||
|
68fd56e7fc | ||
|
370dae0ab8 | ||
|
bef4b2ec35 | ||
|
fe618d0b85 | ||
|
52cfc18754 | ||
|
25bbfa4c68 | ||
|
2a46b96083 | ||
|
17c004aecf | ||
|
9e3ae21bb8 | ||
|
04f0f56348 | ||
|
9333beda49 | ||
|
aacb980dc8 | ||
|
8052090e0f | ||
|
46289fa78c | ||
|
b3cafd126e | ||
|
c55fa9f9d2 | ||
|
210d96a3e3 | ||
|
42f3c7c128 | ||
|
6cd7002e91 | ||
|
085762e800 | ||
|
2db2b0ecc6 | ||
|
fd58a749ef | ||
|
3bddf4dfd1 |
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -13,3 +13,5 @@ myFilter.cpp
|
|||
my*.h
|
||||
!my*.example.h
|
||||
compile_commands.json
|
||||
newcode.txt.old
|
||||
UserAddin.txt
|
||||
|
|
|
@ -162,7 +162,7 @@ void CommandDistributor::broadcastTurnout(int16_t id, bool isClosed ) {
|
|||
}
|
||||
|
||||
void CommandDistributor::broadcastTurntable(int16_t id, uint8_t position, bool moving) {
|
||||
broadcastReply(COMMAND_TYPE, F("<i %d %d %d>\n"), id, position, moving);
|
||||
broadcastReply(COMMAND_TYPE, F("<I %d %d %d>\n"), id, position, moving);
|
||||
}
|
||||
|
||||
void CommandDistributor::broadcastClockTime(int16_t time, int8_t rate) {
|
||||
|
@ -269,6 +269,6 @@ void CommandDistributor::broadcastRaw(clientType type, char * msg) {
|
|||
broadcastReply(type, F("%s"),msg);
|
||||
}
|
||||
|
||||
void CommandDistributor::broadcastTrackState(const FSH* format,byte trackLetter,int16_t dcAddr) {
|
||||
broadcastReply(COMMAND_TYPE, format,trackLetter,dcAddr);
|
||||
void CommandDistributor::broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr) {
|
||||
broadcastReply(COMMAND_TYPE, format,trackLetter, dcAddr);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public :
|
|||
static int16_t retClockTime();
|
||||
static void broadcastPower();
|
||||
static void broadcastRaw(clientType type,char * msg);
|
||||
static void broadcastTrackState(const FSH* format,byte trackLetter,int16_t dcAddr);
|
||||
static void broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr);
|
||||
template<typename... Targs> static void broadcastReply(clientType type, Targs... msg);
|
||||
static void forget(byte clientId);
|
||||
|
||||
|
|
200
DCCEXParser.cpp
200
DCCEXParser.cpp
|
@ -60,14 +60,14 @@ Once a new OPCODE is decided upon, update this list.
|
|||
G,
|
||||
h,
|
||||
H, Turnout state broadcast
|
||||
i, Reserved for future use - Turntable object broadcast
|
||||
I, Reserved for future use - Turntable object command and control
|
||||
i, Server details string
|
||||
I, Turntable object command, control, and broadcast
|
||||
j, Throttle responses
|
||||
J, Throttle queries
|
||||
k, Reserved for future use - Potentially Railcom
|
||||
K, Reserved for future use - Potentially Railcom
|
||||
l, Loco speedbyte/function map broadcast
|
||||
L,
|
||||
L, Reserved for LCC interface (implemented in EXRAIL)
|
||||
m,
|
||||
M, Write DCC packet
|
||||
n,
|
||||
|
@ -122,7 +122,7 @@ Once a new OPCODE is decided upon, update this list.
|
|||
for (int16_t i=0;;i+=sizeof(flashList[0])) { \
|
||||
int16_t value=GETHIGHFLASHW(flashList,i); \
|
||||
if (value==INT16_MAX) break; \
|
||||
if (value != 0) StringFormatter::send(stream,F(" %d"),value); \
|
||||
StringFormatter::send(stream,F(" %d"),value); \
|
||||
}
|
||||
|
||||
|
||||
|
@ -157,6 +157,7 @@ const int16_t HASH_KEYWORD_VPIN=-415;
|
|||
const int16_t HASH_KEYWORD_A='A';
|
||||
const int16_t HASH_KEYWORD_C='C';
|
||||
const int16_t HASH_KEYWORD_G='G';
|
||||
const int16_t HASH_KEYWORD_H='H';
|
||||
const int16_t HASH_KEYWORD_I='I';
|
||||
const int16_t HASH_KEYWORD_O='O';
|
||||
const int16_t HASH_KEYWORD_P='P';
|
||||
|
@ -552,69 +553,131 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||
|
||||
case '1': // POWERON <1 [MAIN|PROG|JOIN]>
|
||||
{
|
||||
bool main=false;
|
||||
bool prog=false;
|
||||
bool join=false;
|
||||
if (params > 1) break;
|
||||
if (params==0) { // All
|
||||
main=true;
|
||||
prog=true;
|
||||
}
|
||||
if (params==1) {
|
||||
if (p[0]==HASH_KEYWORD_MAIN) { // <1 MAIN>
|
||||
main=true;
|
||||
}
|
||||
bool main=false;
|
||||
bool prog=false;
|
||||
bool join=false;
|
||||
bool singletrack=false;
|
||||
//byte t=0;
|
||||
if (params > 1) break;
|
||||
if (params==0) { // All
|
||||
main=true;
|
||||
prog=true;
|
||||
}
|
||||
if (params==1) {
|
||||
if (p[0]==HASH_KEYWORD_MAIN) { // <1 MAIN>
|
||||
main=true;
|
||||
}
|
||||
#ifndef DISABLE_PROG
|
||||
else if (p[0] == HASH_KEYWORD_JOIN) { // <1 JOIN>
|
||||
main=true;
|
||||
prog=true;
|
||||
join=true;
|
||||
}
|
||||
else if (p[0]==HASH_KEYWORD_PROG) { // <1 PROG>
|
||||
prog=true;
|
||||
}
|
||||
else if (p[0] == HASH_KEYWORD_JOIN) { // <1 JOIN>
|
||||
main=true;
|
||||
prog=true;
|
||||
join=true;
|
||||
}
|
||||
else if (p[0]==HASH_KEYWORD_PROG) { // <1 PROG>
|
||||
prog=true;
|
||||
}
|
||||
#endif
|
||||
else break; // will reply <X>
|
||||
}
|
||||
TrackManager::setJoin(join);
|
||||
if (main) TrackManager::setMainPower(POWERMODE::ON);
|
||||
if (prog) TrackManager::setProgPower(POWERMODE::ON);
|
||||
//else if (p[0] >= 'A' && p[0] <= 'H') { // <1 A-H>
|
||||
else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H>
|
||||
byte t = (p[0] - 'A');
|
||||
//DIAG(F("Processing track - %d "), t);
|
||||
if (TrackManager::isProg(t)) {
|
||||
main = false;
|
||||
prog = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
main=true;
|
||||
prog=false;
|
||||
}
|
||||
singletrack=true;
|
||||
if (main) TrackManager::setTrackPower(false, false, POWERMODE::ON, t);
|
||||
if (prog) TrackManager::setTrackPower(true, false, POWERMODE::ON, t);
|
||||
|
||||
StringFormatter::send(stream, F("<1 %c>\n"), t+'A');
|
||||
//CommandDistributor::broadcastPower();
|
||||
//TrackManager::streamTrackState(NULL,t);
|
||||
return;
|
||||
}
|
||||
|
||||
else break; // will reply <X>
|
||||
}
|
||||
|
||||
if (!singletrack) {
|
||||
TrackManager::setJoin(join);
|
||||
if (join) TrackManager::setJoinPower(POWERMODE::ON);
|
||||
else {
|
||||
if (main) TrackManager::setMainPower(POWERMODE::ON);
|
||||
if (prog) TrackManager::setProgPower(POWERMODE::ON);
|
||||
}
|
||||
CommandDistributor::broadcastPower();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CommandDistributor::broadcastPower();
|
||||
return;
|
||||
}
|
||||
|
||||
case '0': // POWEROFF <0 [MAIN | PROG] >
|
||||
{
|
||||
bool main=false;
|
||||
bool prog=false;
|
||||
if (params > 1) break;
|
||||
if (params==0) { // All
|
||||
main=true;
|
||||
prog=true;
|
||||
}
|
||||
if (params==1) {
|
||||
if (p[0]==HASH_KEYWORD_MAIN) { // <0 MAIN>
|
||||
main=true;
|
||||
}
|
||||
bool main=false;
|
||||
bool prog=false;
|
||||
bool singletrack=false;
|
||||
//byte t=0;
|
||||
if (params > 1) break;
|
||||
if (params==0) { // All
|
||||
main=true;
|
||||
prog=true;
|
||||
}
|
||||
if (params==1) {
|
||||
if (p[0]==HASH_KEYWORD_MAIN) { // <0 MAIN>
|
||||
main=true;
|
||||
}
|
||||
#ifndef DISABLE_PROG
|
||||
else if (p[0]==HASH_KEYWORD_PROG) { // <0 PROG>
|
||||
prog=true;
|
||||
}
|
||||
else if (p[0]==HASH_KEYWORD_PROG) { // <0 PROG>
|
||||
prog=true;
|
||||
}
|
||||
#endif
|
||||
else break; // will reply <X>
|
||||
}
|
||||
//else if (p[0] >= 'A' && p[0] <= 'H') { // <1 A-H>
|
||||
else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H>
|
||||
byte t = (p[0] - 'A');
|
||||
//DIAG(F("Processing track - %d "), t);
|
||||
if (TrackManager::isProg(t)) {
|
||||
main = false;
|
||||
prog = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
main=true;
|
||||
prog=false;
|
||||
}
|
||||
singletrack=true;
|
||||
TrackManager::setJoin(false);
|
||||
if (main) TrackManager::setTrackPower(false, false, POWERMODE::OFF, t);
|
||||
if (prog) {
|
||||
TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off
|
||||
TrackManager::setTrackPower(true, false, POWERMODE::OFF, t);
|
||||
}
|
||||
StringFormatter::send(stream, F("<0 %c>\n"), t+'A');
|
||||
//CommandDistributor::broadcastPower();
|
||||
//TrackManager::streamTrackState(NULL, t);
|
||||
return;
|
||||
}
|
||||
|
||||
TrackManager::setJoin(false);
|
||||
if (main) TrackManager::setMainPower(POWERMODE::OFF);
|
||||
if (prog) {
|
||||
TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off
|
||||
TrackManager::setProgPower(POWERMODE::OFF);
|
||||
}
|
||||
else break; // will reply <X>
|
||||
}
|
||||
|
||||
CommandDistributor::broadcastPower();
|
||||
return;
|
||||
if (!singletrack) {
|
||||
TrackManager::setJoin(false);
|
||||
|
||||
if (main) TrackManager::setMainPower(POWERMODE::OFF);
|
||||
if (prog) {
|
||||
TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off
|
||||
TrackManager::setProgPower(POWERMODE::OFF);
|
||||
}
|
||||
CommandDistributor::broadcastPower();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
case '!': // ESTOP ALL <!>
|
||||
DCC::setThrottle(0,1,1); // this broadcasts speed 1(estop) and sets all reminders to speed 1.
|
||||
|
@ -742,11 +805,15 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||
SENDFLASHLIST(stream,RMFT2::rosterIdList)
|
||||
}
|
||||
else {
|
||||
const FSH * functionNames= RMFT2::getRosterFunctions(id);
|
||||
StringFormatter::send(stream,F(" %d \"%S\" \"%S\""),
|
||||
id, RMFT2::getRosterName(id),
|
||||
functionNames == NULL ? RMFT2::getRosterFunctions(0) : functionNames);
|
||||
}
|
||||
auto rosterName= RMFT2::getRosterName(id);
|
||||
if (!rosterName) rosterName=F("");
|
||||
|
||||
auto functionNames= RMFT2::getRosterFunctions(id);
|
||||
if (!functionNames) functionNames=RMFT2::getRosterFunctions(0);
|
||||
if (!functionNames) functionNames=F("");
|
||||
StringFormatter::send(stream,F(" %d \"%S\" \"%S\""),
|
||||
id, rosterName, functionNames);
|
||||
}
|
||||
#endif
|
||||
StringFormatter::send(stream, F(">\n"));
|
||||
return;
|
||||
|
@ -839,6 +906,9 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
|
|||
break;
|
||||
#endif
|
||||
|
||||
case 'L': // LCC interface implemented in EXRAIL parser
|
||||
break; // Will <X> if not intercepted by EXRAIL
|
||||
|
||||
default: //anything else will diagnose and drop out to <X>
|
||||
DIAG(F("Opcode=%c params=%d"), opcode, params);
|
||||
for (int i = 0; i < params; i++)
|
||||
|
@ -1145,7 +1215,7 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[])
|
|||
IODevice::DumpAll();
|
||||
else if (p[1] == HASH_KEYWORD_RESET)
|
||||
IODevice::reset();
|
||||
break;
|
||||
return true;
|
||||
#endif
|
||||
|
||||
case HASH_KEYWORD_TT: // <D TT vpin steps activity>
|
||||
|
@ -1181,7 +1251,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
|||
if (tto) {
|
||||
bool type = tto->isEXTT();
|
||||
uint8_t position = tto->getPosition();
|
||||
StringFormatter::send(stream, F("<i %d %d>\n"), type, position);
|
||||
StringFormatter::send(stream, F("<I %d %d>\n"), type, position);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1207,7 +1277,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
|||
if (!DCCTurntable::create(p[0])) return false;
|
||||
Turntable *tto = Turntable::get(p[0]);
|
||||
tto->addPosition(0, 0, p[2]);
|
||||
StringFormatter::send(stream, F("<i>\n"));
|
||||
StringFormatter::send(stream, F("<I>\n"));
|
||||
} else {
|
||||
if (!tto) return false;
|
||||
if (!tto->isEXTT()) return false;
|
||||
|
@ -1224,7 +1294,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
|||
if (!EXTTTurntable::create(p[0], (VPIN)p[2])) return false;
|
||||
Turntable *tto = Turntable::get(p[0]);
|
||||
tto->addPosition(0, 0, p[3]);
|
||||
StringFormatter::send(stream, F("<i>\n"));
|
||||
StringFormatter::send(stream, F("<I>\n"));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1238,7 +1308,7 @@ bool DCCEXParser::parseI(Print *stream, int16_t params, int16_t p[])
|
|||
// tto must exist, no more than 48 positions, angle 0 - 3600
|
||||
if (!tto || p[2] > 48 || p[4] < 0 || p[4] > 3600) return false;
|
||||
tto->addPosition(p[2], p[3], p[4]);
|
||||
StringFormatter::send(stream, F("<i>\n"));
|
||||
StringFormatter::send(stream, F("<I>\n"));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
122
EXRAIL2.cpp
122
EXRAIL2.cpp
|
@ -85,7 +85,7 @@ RMFT2 * RMFT2::pausingTask=NULL; // Task causing a PAUSE.
|
|||
// when pausingTask is set, that is the ONLY task that gets any service,
|
||||
// and all others will have their locos stopped, then resumed after the pausing task resumes.
|
||||
byte RMFT2::flags[MAX_FLAGS];
|
||||
|
||||
Print * RMFT2::LCCSerial=0;
|
||||
LookList * RMFT2::sequenceLookup=NULL;
|
||||
LookList * RMFT2::onThrowLookup=NULL;
|
||||
LookList * RMFT2::onCloseLookup=NULL;
|
||||
|
@ -176,23 +176,26 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
|
|||
onCloseLookup=LookListLoader(OPCODE_ONCLOSE);
|
||||
onActivateLookup=LookListLoader(OPCODE_ONACTIVATE);
|
||||
onDeactivateLookup=LookListLoader(OPCODE_ONDEACTIVATE);
|
||||
onRedLookup=LookListLoader(OPCODE_ONRED);
|
||||
onAmberLookup=LookListLoader(OPCODE_ONAMBER);
|
||||
onGreenLookup=LookListLoader(OPCODE_ONGREEN);
|
||||
onChangeLookup=LookListLoader(OPCODE_ONCHANGE);
|
||||
onClockLookup=LookListLoader(OPCODE_ONTIME);
|
||||
#ifndef IO_NO_HAL
|
||||
onRotateLookup=LookListLoader(OPCODE_ONROTATE);
|
||||
#endif
|
||||
onOverloadLookup=LookListLoader(OPCODE_ONOVERLOAD);
|
||||
// onLCCLookup is not the same so not loaded here.
|
||||
|
||||
// Second pass startup, define any turnouts or servos, set signals red
|
||||
// add sequences onRoutines to the lookups
|
||||
if (compileFeatures & FEATURE_SIGNAL) {
|
||||
onRedLookup=LookListLoader(OPCODE_ONRED);
|
||||
onAmberLookup=LookListLoader(OPCODE_ONAMBER);
|
||||
onGreenLookup=LookListLoader(OPCODE_ONGREEN);
|
||||
for (int sigslot=0;;sigslot++) {
|
||||
VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8);
|
||||
if (sigid==0) break; // end of signal list
|
||||
doSignal(sigid & SIGNAL_ID_MASK, SIGNAL_RED);
|
||||
}
|
||||
}
|
||||
|
||||
int progCounter;
|
||||
for (progCounter=0;; SKIPOP){
|
||||
|
@ -343,13 +346,65 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16
|
|||
reject=!parseSlash(stream,paramCount,p);
|
||||
opcode=0;
|
||||
break;
|
||||
case 'L':
|
||||
if (compileFeatures & FEATURE_LCC) {
|
||||
// This entire code block is compiled out if LLC macros not used
|
||||
if (paramCount==0) { //<L> LCC adapter introducing self
|
||||
LCCSerial=stream; // now we know where to send events we raise
|
||||
|
||||
// loop through all possible sent events
|
||||
for (int progCounter=0;; SKIPOP) {
|
||||
byte opcode=GET_OPCODE;
|
||||
if (opcode==OPCODE_ENDEXRAIL) break;
|
||||
if (opcode==OPCODE_LCC) StringFormatter::send(stream,F("<LS x%h>\n"),getOperand(progCounter,0));
|
||||
if (opcode==OPCODE_LCCX) { // long form LCC
|
||||
StringFormatter::send(stream,F("<LS x%h%h%h%h>\n"),
|
||||
getOperand(progCounter,1),
|
||||
getOperand(progCounter,2),
|
||||
getOperand(progCounter,3),
|
||||
getOperand(progCounter,0)
|
||||
);
|
||||
}}
|
||||
|
||||
// we stream the hex events we wish to listen to
|
||||
// and at the same time build the event index looku.
|
||||
|
||||
|
||||
int eventIndex=0;
|
||||
for (int progCounter=0;; SKIPOP) {
|
||||
byte opcode=GET_OPCODE;
|
||||
if (opcode==OPCODE_ENDEXRAIL) break;
|
||||
if (opcode==OPCODE_ONLCC) {
|
||||
onLCCLookup[eventIndex]=progCounter; // TODO skip...
|
||||
StringFormatter::send(stream,F("<LL %d x%h%h%h:%h>\n"),
|
||||
eventIndex,
|
||||
getOperand(progCounter,1),
|
||||
getOperand(progCounter,2),
|
||||
getOperand(progCounter,3),
|
||||
getOperand(progCounter,0)
|
||||
);
|
||||
eventIndex++;
|
||||
}
|
||||
}
|
||||
StringFormatter::send(stream,F("<LR>\n")); // Ready to rumble
|
||||
opcode=0;
|
||||
break;
|
||||
}
|
||||
if (paramCount==1) { // <L eventid> LCC event arrived from adapter
|
||||
int16_t eventid=p[0];
|
||||
reject=eventid<0 || eventid>=countLCCLookup;
|
||||
if (!reject) startNonRecursiveTask(F("LCC"),eventid,onLCCLookup[eventid]);
|
||||
opcode=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: // other commands pass through
|
||||
break;
|
||||
}
|
||||
if (reject) {
|
||||
opcode=0;
|
||||
StringFormatter::send(stream,F("<X>"));
|
||||
StringFormatter::send(stream,F("<X>\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,17 +432,19 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
|
|||
if (flag & LATCH_FLAG) StringFormatter::send(stream,F(" LATCHED"));
|
||||
}
|
||||
}
|
||||
// do the signals
|
||||
// flags[n] represents the state of the nth signal in the table
|
||||
for (int sigslot=0;;sigslot++) {
|
||||
VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8);
|
||||
if (sigid==0) break; // end of signal list
|
||||
byte flag=flags[sigslot] & SIGNAL_MASK; // obtain signal flags for this id
|
||||
StringFormatter::send(stream,F("\n%S[%d]"),
|
||||
(flag == SIGNAL_RED)? F("RED") : (flag==SIGNAL_GREEN) ? F("GREEN") : F("AMBER"),
|
||||
sigid & SIGNAL_ID_MASK);
|
||||
}
|
||||
|
||||
if (compileFeatures & FEATURE_SIGNAL) {
|
||||
// do the signals
|
||||
// flags[n] represents the state of the nth signal in the table
|
||||
for (int sigslot=0;;sigslot++) {
|
||||
VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8);
|
||||
if (sigid==0) break; // end of signal list
|
||||
byte flag=flags[sigslot] & SIGNAL_MASK; // obtain signal flags for this id
|
||||
StringFormatter::send(stream,F("\n%S[%d]"),
|
||||
(flag == SIGNAL_RED)? F("RED") : (flag==SIGNAL_GREEN) ? F("GREEN") : F("AMBER"),
|
||||
sigid & SIGNAL_ID_MASK);
|
||||
}
|
||||
}
|
||||
StringFormatter::send(stream,F(" *>\n"));
|
||||
return true;
|
||||
}
|
||||
|
@ -781,6 +838,20 @@ void RMFT2::loop2() {
|
|||
CommandDistributor::broadcastPower();
|
||||
break;
|
||||
|
||||
case OPCODE_SET_POWER:
|
||||
// operand is TRACK_POWER , trackid
|
||||
//byte thistrack=getOperand(1);
|
||||
switch (operand) {
|
||||
case TRACK_POWER_0:
|
||||
TrackManager::setTrackPower(TrackManager::isProg(getOperand(1)), false, POWERMODE::OFF, getOperand(1));
|
||||
break;
|
||||
case TRACK_POWER_1:
|
||||
TrackManager::setTrackPower(TrackManager::isProg(getOperand(1)), false, POWERMODE::ON, getOperand(1));
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_SET_TRACK:
|
||||
// operand is trackmode<<8 | track id
|
||||
// If DC/DCX use my loco for DC address
|
||||
|
@ -1021,6 +1092,20 @@ void RMFT2::loop2() {
|
|||
}
|
||||
break;
|
||||
|
||||
case OPCODE_LCC: // short form LCC
|
||||
if ((compileFeatures & FEATURE_LCC) && LCCSerial)
|
||||
StringFormatter::send(LCCSerial,F("<L x%h>"),(uint16_t)operand);
|
||||
break;
|
||||
|
||||
case OPCODE_LCCX: // long form LCC
|
||||
if ((compileFeatures & FEATURE_LCC) && LCCSerial)
|
||||
StringFormatter::send(LCCSerial,F("<L x%h%h%h%h>\n"),
|
||||
getOperand(progCounter,1),
|
||||
getOperand(progCounter,2),
|
||||
getOperand(progCounter,3),
|
||||
getOperand(progCounter,0)
|
||||
);
|
||||
break;
|
||||
|
||||
case OPCODE_SERVO: // OPCODE_SERVO,V(vpin),OPCODE_PAD,V(position),OPCODE_PAD,V(profile),OPCODE_PAD,V(duration)
|
||||
IODevice::writeAnalogue(operand,getOperand(1),getOperand(2),getOperand(3));
|
||||
|
@ -1058,6 +1143,7 @@ void RMFT2::loop2() {
|
|||
case OPCODE_SERVOTURNOUT: // Turnout definition ignored at runtime
|
||||
case OPCODE_PINTURNOUT: // Turnout definition ignored at runtime
|
||||
case OPCODE_ONCLOSE: // Turnout event catchers ignored here
|
||||
case OPCODE_ONLCC: // LCC event catchers ignored here
|
||||
case OPCODE_ONTHROW:
|
||||
case OPCODE_ONACTIVATE: // Activate event catchers ignored here
|
||||
case OPCODE_ONDEACTIVATE:
|
||||
|
@ -1127,6 +1213,7 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
|||
}
|
||||
|
||||
/* static */ void RMFT2::doSignal(int16_t id,char rag) {
|
||||
if (!(compileFeatures & FEATURE_SIGNAL)) return; // dont compile code below
|
||||
if (diag) DIAG(F(" doSignal %d %x"),id,rag);
|
||||
|
||||
// Schedule any event handler for this signal change.
|
||||
|
@ -1194,6 +1281,7 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
|
|||
}
|
||||
|
||||
/* static */ bool RMFT2::isSignal(int16_t id,char rag) {
|
||||
if (!(compileFeatures & FEATURE_SIGNAL)) return false;
|
||||
int16_t sigslot=getSignalSlot(id);
|
||||
if (sigslot<0) return false;
|
||||
return (flags[sigslot] & SIGNAL_MASK) == rag;
|
||||
|
@ -1246,8 +1334,10 @@ void RMFT2::powerEvent(int16_t track, bool overload) {
|
|||
|
||||
void RMFT2::handleEvent(const FSH* reason,LookList* handlers, int16_t id) {
|
||||
int pc= handlers->find(id);
|
||||
if (pc<0) return;
|
||||
if (pc>=0) startNonRecursiveTask(reason,id,pc);
|
||||
}
|
||||
|
||||
void RMFT2::startNonRecursiveTask(const FSH* reason, int16_t id,int pc) {
|
||||
// Check we dont already have a task running this handler
|
||||
RMFT2 * task=loopTask;
|
||||
while(task) {
|
||||
|
|
20
EXRAIL2.h
20
EXRAIL2.h
|
@ -59,15 +59,14 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
|||
OPCODE_ROSTER,OPCODE_KILLALL,
|
||||
OPCODE_ROUTE,OPCODE_AUTOMATION,OPCODE_SEQUENCE,
|
||||
OPCODE_ENDTASK,OPCODE_ENDEXRAIL,
|
||||
OPCODE_SET_TRACK,
|
||||
OPCODE_SET_TRACK,OPCODE_SET_POWER,
|
||||
OPCODE_ONRED,OPCODE_ONAMBER,OPCODE_ONGREEN,
|
||||
OPCODE_ONCHANGE,
|
||||
OPCODE_ONCLOCKTIME,
|
||||
OPCODE_ONTIME,
|
||||
#ifndef IO_NO_HAL
|
||||
OPCODE_TTADDPOSITION,OPCODE_DCCTURNTABLE,OPCODE_EXTTTURNTABLE,
|
||||
OPCODE_ONROTATE,OPCODE_ROTATE,OPCODE_IFTTPOSITION,OPCODE_WAITFORTT,
|
||||
#endif
|
||||
OPCODE_ONROTATE,OPCODE_ROTATE,OPCODE_WAITFORTT,
|
||||
OPCODE_LCC,OPCODE_LCCX,OPCODE_ONLCC,
|
||||
OPCODE_ONOVERLOAD,
|
||||
|
||||
// OPcodes below this point are skip-nesting IF operations
|
||||
|
@ -81,7 +80,8 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
|||
OPCODE_IFRANDOM,OPCODE_IFRESERVE,
|
||||
OPCODE_IFCLOSED,OPCODE_IFTHROWN,
|
||||
OPCODE_IFRE,
|
||||
OPCODE_IFLOCO
|
||||
OPCODE_IFLOCO,
|
||||
OPCODE_IFTTPOSITION
|
||||
};
|
||||
|
||||
// Ensure thrunge_lcd is put last as there may be more than one display,
|
||||
|
@ -95,6 +95,10 @@ enum thrunger: byte {
|
|||
thrunge_lcd, // Must be last!!
|
||||
};
|
||||
|
||||
// Flag bits for compile time features.
|
||||
static const byte FEATURE_SIGNAL= 0x80;
|
||||
static const byte FEATURE_LCC = 0x40;
|
||||
static const byte FEATURE_ROSTER= 0x20;
|
||||
|
||||
|
||||
// Flag bits for status of hardware and TPL
|
||||
|
@ -174,6 +178,7 @@ private:
|
|||
OPCODE op2=OPCODE_ENDEXRAIL,OPCODE op3=OPCODE_ENDEXRAIL);
|
||||
static void handleEvent(const FSH* reason,LookList* handlers, int16_t id);
|
||||
static uint16_t getOperand(int progCounter,byte n);
|
||||
static void startNonRecursiveTask(const FSH* reason, int16_t id,int pc);
|
||||
static RMFT2 * loopTask;
|
||||
static RMFT2 * pausingTask;
|
||||
void delayMe(long millisecs);
|
||||
|
@ -192,6 +197,7 @@ private:
|
|||
static const HIGHFLASH byte RouteCode[];
|
||||
static const HIGHFLASH int16_t SignalDefinitions[];
|
||||
static byte flags[MAX_FLAGS];
|
||||
static Print * LCCSerial;
|
||||
static LookList * sequenceLookup;
|
||||
static LookList * onThrowLookup;
|
||||
static LookList * onCloseLookup;
|
||||
|
@ -207,6 +213,10 @@ private:
|
|||
#endif
|
||||
static LookList * onOverloadLookup;
|
||||
|
||||
static const int countLCCLookup;
|
||||
static int onLCCLookup[];
|
||||
static const byte compileFeatures;
|
||||
|
||||
// Local variables - exist for each instance/task
|
||||
RMFT2 *next; // loop chain
|
||||
int progCounter; // Byte offset of next route opcode in ROUTES table
|
||||
|
|
|
@ -86,6 +86,8 @@
|
|||
#undef LATCH
|
||||
#undef LCD
|
||||
#undef SCREEN
|
||||
#undef LCC
|
||||
#undef LCCX
|
||||
#undef LCN
|
||||
#undef MOVETT
|
||||
#undef ONACTIVATE
|
||||
|
@ -94,6 +96,7 @@
|
|||
#undef ONDEACTIVATE
|
||||
#undef ONDEACTIVATEL
|
||||
#undef ONCLOSE
|
||||
#undef ONLCC
|
||||
#undef ONTIME
|
||||
#undef ONCLOCKTIME
|
||||
#undef ONCLOCKMINS
|
||||
|
@ -138,6 +141,7 @@
|
|||
#undef SERVO_SIGNAL
|
||||
#undef SET
|
||||
#undef SET_TRACK
|
||||
#undef SET_POWER
|
||||
#undef SETLOCO
|
||||
#undef SIGNAL
|
||||
#undef SIGNALH
|
||||
|
@ -192,7 +196,7 @@
|
|||
#define ENDTASK
|
||||
#define ESTOP
|
||||
#define EXRAIL
|
||||
#define EXTT_TURNTABLE(id,vpin,i2c_address,home,description)
|
||||
#define EXTT_TURNTABLE(id,vpin,home,description)
|
||||
#define FADE(pin,value,ms)
|
||||
#define FOFF(func)
|
||||
#define FOLLOW(route)
|
||||
|
@ -221,6 +225,8 @@
|
|||
#define JOIN
|
||||
#define KILLALL
|
||||
#define LATCH(sensor_id)
|
||||
#define LCC(eventid)
|
||||
#define LCCX(senderid,eventid)
|
||||
#define LCD(row,msg)
|
||||
#define SCREEN(display,row,msg)
|
||||
#define LCN(msg)
|
||||
|
@ -235,6 +241,7 @@
|
|||
#define ONDEACTIVATE(addr,subaddr)
|
||||
#define ONDEACTIVATEL(linear)
|
||||
#define ONCLOSE(turnout_id)
|
||||
#define ONLCC(sender,event)
|
||||
#define ONGREEN(signal_id)
|
||||
#define ONRED(signal_id)
|
||||
#define ONROTATE(turntable_id)
|
||||
|
@ -275,6 +282,7 @@
|
|||
#define SERVO_TURNOUT(id,pin,activeAngle,inactiveAngle,profile,description...)
|
||||
#define SET(pin)
|
||||
#define SET_TRACK(track,mode)
|
||||
#define SET_POWER(track,onoff)
|
||||
#define SETLOCO(loco)
|
||||
#define SIGNAL(redpin,amberpin,greenpin)
|
||||
#define SIGNALH(redpin,amberpin,greenpin)
|
||||
|
|
|
@ -63,6 +63,11 @@
|
|||
// (10#mins)%100)
|
||||
#define STRIP_ZERO(value) 10##value%100
|
||||
|
||||
// These constants help EXRAIL macros convert Track Power e.g. SET_POWER(A ON|OFF).
|
||||
//const byte TRACK_POWER_0=0, TRACK_POWER_OFF=0;
|
||||
//const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
||||
|
||||
|
||||
// Pass 1 Implements aliases
|
||||
#include "EXRAIL2MacroReset.h"
|
||||
#undef ALIAS
|
||||
|
@ -74,12 +79,34 @@
|
|||
#include "EXRAIL2MacroReset.h"
|
||||
#undef HAL
|
||||
#define HAL(haltype,params...) haltype::create(params);
|
||||
#undef EXTT_TURNTABLE
|
||||
#define EXTT_TURNTABLE(id,vpin,i2c_address,home,description...) EXTurntable::create(vpin,1,i2c_address);
|
||||
void exrailHalSetup() {
|
||||
#include "myAutomation.h"
|
||||
}
|
||||
|
||||
// Pass 1c detect compile time featurtes
|
||||
#include "EXRAIL2MacroReset.h"
|
||||
#undef SIGNAL
|
||||
#define SIGNAL(redpin,amberpin,greenpin) | FEATURE_SIGNAL
|
||||
#undef SIGNALH
|
||||
#define SIGNALH(redpin,amberpin,greenpin) | FEATURE_SIGNAL
|
||||
#undef SERVO_SIGNAL
|
||||
#define SERVO_SIGNAL(vpin,redval,amberval,greenval) | FEATURE_SIGNAL
|
||||
#undef DCC_SIGNAL
|
||||
#define DCC_SIGNAL(id,addr,subaddr) | FEATURE_SIGNAL
|
||||
#undef VIRTUAL_SIGNAL
|
||||
#define VIRTUAL_SIGNAL(id) | FEATURE_SIGNAL
|
||||
|
||||
#undef LCC
|
||||
#define LCC(eventid) | FEATURE_LCC
|
||||
#undef LCCX
|
||||
#define LCCX(senderid,eventid) | FEATURE_LCC
|
||||
#undef ONLCC
|
||||
#define ONLCC(senderid,eventid) | FEATURE_LCC
|
||||
|
||||
const byte RMFT2::compileFeatures = 0
|
||||
#include "myAutomation.h"
|
||||
;
|
||||
|
||||
// Pass 2 create throttle route list
|
||||
#include "EXRAIL2MacroReset.h"
|
||||
#undef ROUTE
|
||||
|
@ -197,7 +224,7 @@ const FSH * RMFT2::getTurnoutDescription(int16_t turnoutid) {
|
|||
#undef DCC_TURNTABLE
|
||||
#define DCC_TURNTABLE(id,home,description...) O_DESC(id,description)
|
||||
#undef EXTT_TURNTABLE
|
||||
#define EXTT_TURNTABLE(id,vpin,i2c_address,home,description...) O_DESC(id,description)
|
||||
#define EXTT_TURNTABLE(id,vpin,home,description...) O_DESC(id,description)
|
||||
|
||||
const FSH * RMFT2::getTurntableDescription(int16_t turntableId) {
|
||||
switch (turntableId) {
|
||||
|
@ -273,6 +300,16 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
|
|||
#include "myAutomation.h"
|
||||
0,0,0,0 };
|
||||
|
||||
// Pass 9 ONLCC counter and lookup array
|
||||
#include "EXRAIL2MacroReset.h"
|
||||
#undef ONLCC
|
||||
#define ONLCC(sender,event) +1
|
||||
|
||||
const int RMFT2::countLCCLookup=0
|
||||
#include "myAutomation.h"
|
||||
;
|
||||
int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
|
||||
|
||||
// Last Pass : create main routes table
|
||||
// Only undef the macros, not dummy them.
|
||||
#define RMFT2_UNDEF_ONLY
|
||||
|
@ -317,7 +354,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
|
|||
#define ESTOP OPCODE_SPEED,V(1),
|
||||
#define EXRAIL
|
||||
#ifndef IO_NO_HAL
|
||||
#define EXTT_TURNTABLE(id,vpin,i2c_address,home,description...) OPCODE_EXTTTURNTABLE,V(id),OPCODE_PAD,V(vpin),OPCODE_PAD,V(i2c_address),OPCODE_PAD,V(home),
|
||||
#define EXTT_TURNTABLE(id,vpin,home,description...) OPCODE_EXTTTURNTABLE,V(id),OPCODE_PAD,V(vpin),OPCODE_PAD,V(home),
|
||||
#endif
|
||||
#define FADE(pin,value,ms) OPCODE_SERVO,V(pin),OPCODE_PAD,V(value),OPCODE_PAD,V(PCA9685::ProfileType::UseDuration|PCA9685::NoPowerOff),OPCODE_PAD,V(ms/100L),
|
||||
#define FOFF(func) OPCODE_FOFF,V(func),
|
||||
|
@ -349,6 +386,11 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
|
|||
#define JOIN OPCODE_JOIN,0,0,
|
||||
#define KILLALL OPCODE_KILLALL,0,0,
|
||||
#define LATCH(sensor_id) OPCODE_LATCH,V(sensor_id),
|
||||
#define LCC(eventid) OPCODE_LCC,V(eventid),
|
||||
#define LCCX(sender,event) OPCODE_LCCX,V(event),\
|
||||
OPCODE_PAD,V((((uint64_t)sender)>>32)&0xFFFF),\
|
||||
OPCODE_PAD,V((((uint64_t)sender)>>16)&0xFFFF),\
|
||||
OPCODE_PAD,V((((uint64_t)sender)>>0)&0xFFFF),
|
||||
#define LCD(id,msg) PRINT(msg)
|
||||
#define SCREEN(display,id,msg) PRINT(msg)
|
||||
#define LCN(msg) PRINT(msg)
|
||||
|
@ -357,6 +399,10 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
|
|||
#define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3),
|
||||
#define ONAMBER(signal_id) OPCODE_ONAMBER,V(signal_id),
|
||||
#define ONCLOSE(turnout_id) OPCODE_ONCLOSE,V(turnout_id),
|
||||
#define ONLCC(sender,event) OPCODE_ONLCC,V(event),\
|
||||
OPCODE_PAD,V((((uint64_t)sender)>>32)&0xFFFF),\
|
||||
OPCODE_PAD,V((((uint64_t)sender)>>16)&0xFFFF),\
|
||||
OPCODE_PAD,V((((uint64_t)sender)>>0)&0xFFFF),
|
||||
#define ONTIME(value) OPCODE_ONTIME,V(value),
|
||||
#define ONCLOCKTIME(hours,mins) OPCODE_ONTIME,V((STRIP_ZERO(hours)*60)+STRIP_ZERO(mins)),
|
||||
#define ONCLOCKMINS(mins) ONCLOCKTIME(25,mins)
|
||||
|
@ -407,6 +453,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
|
|||
#define SERVO_TURNOUT(id,pin,activeAngle,inactiveAngle,profile,description...) OPCODE_SERVOTURNOUT,V(id),OPCODE_PAD,V(pin),OPCODE_PAD,V(activeAngle),OPCODE_PAD,V(inactiveAngle),OPCODE_PAD,V(PCA9685::ProfileType::profile),
|
||||
#define SET(pin) OPCODE_SET,V(pin),
|
||||
#define SET_TRACK(track,mode) OPCODE_SET_TRACK,V(TRACK_MODE_##mode <<8 | TRACK_NUMBER_##track),
|
||||
#define SET_POWER(track,onoff) OPCODE_SET_POWER,V(TRACK_POWER_##onoff),OPCODE_PAD, V(TRACK_NUMBER_##track),
|
||||
#define SETLOCO(loco) OPCODE_SETLOCO,V(loco),
|
||||
#define SIGNAL(redpin,amberpin,greenpin)
|
||||
#define SIGNALH(redpin,amberpin,greenpin)
|
||||
|
|
|
@ -117,6 +117,7 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) {
|
|||
case 'o': stream->print(va_arg(args, int), OCT); break;
|
||||
case 'x': stream->print((unsigned int)va_arg(args, unsigned int), HEX); break;
|
||||
case 'X': stream->print((unsigned long)va_arg(args, unsigned long), HEX); break;
|
||||
case 'h': printHex(stream,(unsigned int)va_arg(args, unsigned int)); break;
|
||||
case 'M':
|
||||
{ // this prints a unsigned long microseconds time in readable format
|
||||
unsigned long time = va_arg(args, long);
|
||||
|
@ -218,4 +219,15 @@ void StringFormatter::printPadded(Print* stream, long value, byte width, bool fo
|
|||
if (!formatLeft) stream->print(value, DEC);
|
||||
}
|
||||
|
||||
// printHex prints the full 2 byte hex with leading zeros, unlike print(value,HEX)
|
||||
const char FLASH hexchars[]="0123456789ABCDEF";
|
||||
void StringFormatter::printHex(Print * stream,uint16_t value) {
|
||||
char result[5];
|
||||
for (int i=3;i>=0;i--) {
|
||||
result[i]=GETFLASH(hexchars+(value & 0x0F));
|
||||
value>>=4;
|
||||
}
|
||||
result[4]='\0';
|
||||
stream->print(result);
|
||||
}
|
||||
|
|
@ -49,6 +49,7 @@ class StringFormatter
|
|||
static void lcd2(uint8_t display, byte row, const FSH* input...);
|
||||
static void printEscapes(char * input);
|
||||
static void printEscape( char c);
|
||||
static void printHex(Print * stream,uint16_t value);
|
||||
|
||||
private:
|
||||
static void send2(Print * serial, const FSH* input,va_list args);
|
||||
|
|
144
TrackManager.cpp
144
TrackManager.cpp
|
@ -26,7 +26,8 @@
|
|||
#include "MotorDriver.h"
|
||||
#include "DCCTimer.h"
|
||||
#include "DIAG.h"
|
||||
#include"CommandDistributor.h"
|
||||
#include "CommandDistributor.h"
|
||||
#include "DCCEXParser.h"
|
||||
// Virtualised Motor shield multi-track hardware Interface
|
||||
#define FOR_EACH_TRACK(t) for (byte t=0;t<=lastTrack;t++)
|
||||
|
||||
|
@ -331,6 +332,7 @@ bool TrackManager::parseJ(Print *stream, int16_t params, int16_t p[])
|
|||
FOR_EACH_TRACK(t)
|
||||
streamTrackState(stream,t);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
p[0]-=HASH_KEYWORD_A; // convert A... to 0....
|
||||
|
@ -365,32 +367,36 @@ void TrackManager::streamTrackState(Print* stream, byte t) {
|
|||
// null stream means send to commandDistributor for broadcast
|
||||
if (track[t]==NULL) return;
|
||||
auto format=F("");
|
||||
bool pstate = TrackManager::isPowerOn(t);
|
||||
|
||||
switch(track[t]->getMode()) {
|
||||
case TRACK_MODE_MAIN:
|
||||
format=F("<= %c MAIN>\n");
|
||||
if (pstate) {format=F("<= %c MAIN ON>\n");} else {format = F("<= %c MAIN OFF>\n");}
|
||||
break;
|
||||
#ifndef DISABLE_PROG
|
||||
case TRACK_MODE_PROG:
|
||||
format=F("<= %c PROG>\n");
|
||||
if (pstate) {format=F("<= %c PROG ON>\n");} else {format=F("<= %c PROG OFF>\n");}
|
||||
break;
|
||||
#endif
|
||||
case TRACK_MODE_NONE:
|
||||
format=F("<= %c NONE>\n");
|
||||
if (pstate) {format=F("<= %c NONE ON>\n");} else {format=F("<= %c NONE OFF>\n");}
|
||||
break;
|
||||
case TRACK_MODE_EXT:
|
||||
format=F("<= %c EXT>\n");
|
||||
if (pstate) {format=F("<= %c EXT ON>\n");} else {format=F("<= %c EXT OFF>\n");}
|
||||
break;
|
||||
case TRACK_MODE_DC:
|
||||
format=F("<= %c DC %d>\n");
|
||||
if (pstate) {format=F("<= %c DC %d ON>\n");} else {format=F("<= %c DC %d OFF>\n");}
|
||||
break;
|
||||
case TRACK_MODE_DCX:
|
||||
format=F("<= %c DCX %d>\n");
|
||||
if (pstate) {format=F("<= %c DCX %d ON>\n");} else {format=F("<= %c DCX %d OFF>\n");}
|
||||
break;
|
||||
default:
|
||||
break; // unknown, dont care
|
||||
}
|
||||
if (stream) StringFormatter::send(stream,format,'A'+t,trackDCAddr[t]);
|
||||
else CommandDistributor::broadcastTrackState(format,'A'+t,trackDCAddr[t]);
|
||||
|
||||
if (stream) StringFormatter::send(stream,format,'A'+t, trackDCAddr[t]);
|
||||
else CommandDistributor::broadcastTrackState(format,'A'+t, trackDCAddr[t]);
|
||||
|
||||
}
|
||||
|
||||
byte TrackManager::nextCycleTrack=MAX_TRACKS;
|
||||
|
@ -424,49 +430,70 @@ std::vector<MotorDriver *>TrackManager::getMainDrivers() {
|
|||
}
|
||||
#endif
|
||||
|
||||
void TrackManager::setPower2(bool setProg,POWERMODE mode) {
|
||||
void TrackManager::setPower2(bool setProg,bool setJoin, POWERMODE mode) {
|
||||
if (!setProg) mainPowerGuess=mode;
|
||||
FOR_EACH_TRACK(t) {
|
||||
MotorDriver * driver=track[t];
|
||||
if (!driver) continue;
|
||||
switch (track[t]->getMode()) {
|
||||
case TRACK_MODE_MAIN:
|
||||
if (setProg) break;
|
||||
// toggle brake before turning power on - resets overcurrent error
|
||||
// on the Pololu board if brake is wired to ^D2.
|
||||
// XXX see if we can make this conditional
|
||||
driver->setBrake(true);
|
||||
driver->setBrake(false); // DCC runs with brake off
|
||||
driver->setPower(mode);
|
||||
break;
|
||||
case TRACK_MODE_DC:
|
||||
case TRACK_MODE_DCX:
|
||||
if (setProg) break;
|
||||
driver->setBrake(true); // DC starts with brake on
|
||||
applyDCSpeed(t); // speed match DCC throttles
|
||||
driver->setPower(mode);
|
||||
break;
|
||||
case TRACK_MODE_PROG:
|
||||
if (!setProg) break;
|
||||
driver->setBrake(true);
|
||||
driver->setBrake(false);
|
||||
driver->setPower(mode);
|
||||
break;
|
||||
case TRACK_MODE_EXT:
|
||||
driver->setBrake(true);
|
||||
driver->setBrake(false);
|
||||
driver->setPower(mode);
|
||||
break;
|
||||
case TRACK_MODE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
TrackManager::setTrackPower(setProg, setJoin, mode, t);
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void TrackManager::setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack) {
|
||||
|
||||
//DIAG(F("SetTrackPower Processing Track %d"), thistrack);
|
||||
MotorDriver * driver=track[thistrack];
|
||||
if (!driver) return;
|
||||
|
||||
switch (track[thistrack]->getMode()) {
|
||||
case TRACK_MODE_MAIN:
|
||||
if (setProg) break;
|
||||
// toggle brake before turning power on - resets overcurrent error
|
||||
// on the Pololu board if brake is wired to ^D2.
|
||||
// XXX see if we can make this conditional
|
||||
driver->setBrake(true);
|
||||
driver->setBrake(false); // DCC runs with brake off
|
||||
driver->setPower(mode);
|
||||
break;
|
||||
case TRACK_MODE_DC:
|
||||
case TRACK_MODE_DCX:
|
||||
//DIAG(F("Processing track - %d setProg %d"), thistrack, setProg);
|
||||
if (setProg || setJoin) break;
|
||||
driver->setBrake(true); // DC starts with brake on
|
||||
applyDCSpeed(thistrack); // speed match DCC throttles
|
||||
driver->setPower(mode);
|
||||
break;
|
||||
case TRACK_MODE_PROG:
|
||||
if (!setProg && !setJoin) break;
|
||||
driver->setBrake(true);
|
||||
driver->setBrake(false);
|
||||
driver->setPower(mode);
|
||||
break;
|
||||
case TRACK_MODE_EXT:
|
||||
driver->setBrake(true);
|
||||
driver->setBrake(false);
|
||||
driver->setPower(mode);
|
||||
break;
|
||||
case TRACK_MODE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TrackManager::reportPowerChange(Print* stream, byte thistrack) {
|
||||
// This function is for backward JMRI compatibility only
|
||||
// It reports the first track only, as main, regardless of track settings.
|
||||
// <c MeterName value C/V unit min max res warn>
|
||||
int maxCurrent=track[0]->raw2mA(track[0]->getRawCurrentTripValue());
|
||||
StringFormatter::send(stream, F("<c CurrentMAIN %d C Milli 0 %d 1 %d>\n"),
|
||||
track[0]->raw2mA(track[0]->getCurrentRaw(false)), maxCurrent, maxCurrent);
|
||||
}
|
||||
|
||||
POWERMODE TrackManager::getProgPower() {
|
||||
FOR_EACH_TRACK(t)
|
||||
if (track[t]->getMode()==TRACK_MODE_PROG)
|
||||
return track[t]->getPower();
|
||||
return track[t]->getPower();
|
||||
return POWERMODE::OFF;
|
||||
}
|
||||
|
||||
|
@ -538,3 +565,32 @@ bool TrackManager::isPowerOn(byte t) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TrackManager::isProg(byte t) {
|
||||
if (track[t]->getMode()==TRACK_MODE_PROG)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
byte TrackManager::returnMode(byte t) {
|
||||
return (track[t]->getMode());
|
||||
}
|
||||
|
||||
int16_t TrackManager::returnDCAddr(byte t) {
|
||||
return (trackDCAddr[t]);
|
||||
}
|
||||
|
||||
const char* TrackManager::getModeName(byte Mode) {
|
||||
|
||||
//DIAG(F("PowerMode %d"), Mode);
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
case 1: return "NONE";
|
||||
case 2: return "MAIN";
|
||||
case 4: return "PROG";
|
||||
case 8: return "DC";
|
||||
case 16: return "DCX";
|
||||
case 32: return "EXT";
|
||||
default: return "----";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,10 @@ const byte TRACK_NUMBER_5=5, TRACK_NUMBER_F=5;
|
|||
const byte TRACK_NUMBER_6=6, TRACK_NUMBER_G=6;
|
||||
const byte TRACK_NUMBER_7=7, TRACK_NUMBER_H=7;
|
||||
|
||||
// These constants help EXRAIL macros convert Track Power e.g. SET_POWER(A ON|OFF).
|
||||
const byte TRACK_POWER_0=0, TRACK_POWER_OFF=0;
|
||||
const byte TRACK_POWER_1=1, TRACK_POWER_ON=1;
|
||||
|
||||
class TrackManager {
|
||||
public:
|
||||
static void Setup(const FSH * shieldName,
|
||||
|
@ -60,10 +64,14 @@ class TrackManager {
|
|||
#ifdef ARDUINO_ARCH_ESP32
|
||||
static std::vector<MotorDriver *>getMainDrivers();
|
||||
#endif
|
||||
static void setPower2(bool progTrack,POWERMODE mode);
|
||||
|
||||
static void setPower2(bool progTrack,bool joinTrack,POWERMODE mode);
|
||||
static void setPower(POWERMODE mode) {setMainPower(mode); setProgPower(mode);}
|
||||
static void setMainPower(POWERMODE mode) {setPower2(false,mode);}
|
||||
static void setProgPower(POWERMODE mode) {setPower2(true,mode);}
|
||||
static void setMainPower(POWERMODE mode) {setPower2(false,false,mode);}
|
||||
static void setProgPower(POWERMODE mode) {setPower2(true,false,mode);}
|
||||
static void setJoinPower(POWERMODE mode) {setPower2(false,true,mode);}
|
||||
static void setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack);
|
||||
|
||||
|
||||
static const int16_t MAX_TRACKS=8;
|
||||
static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0);
|
||||
|
@ -77,9 +85,14 @@ class TrackManager {
|
|||
static void sampleCurrent();
|
||||
static void reportGauges(Print* stream);
|
||||
static void reportCurrent(Print* stream);
|
||||
static void reportPowerChange(Print* stream, byte thistrack);
|
||||
static void reportObsoleteCurrent(Print* stream);
|
||||
static void streamTrackState(Print* stream, byte t);
|
||||
static bool isPowerOn(byte t);
|
||||
static bool isProg(byte t);
|
||||
static byte returnMode(byte t);
|
||||
static int16_t returnDCAddr(byte t);
|
||||
static const char* getModeName(byte Mode);
|
||||
|
||||
static int16_t joinRelay;
|
||||
static bool progTrackSyncMain; // true when prog track is a siding switched to main
|
||||
|
|
|
@ -185,7 +185,7 @@ public:
|
|||
for (Turntable *tto = _firstTurntable; tto != 0; tto = tto->_nextTurntable)
|
||||
if (!tto->isHidden()) {
|
||||
gotOne = true;
|
||||
StringFormatter::send(stream, F("<i %d %d>\n"), tto->getId(), tto->getPosition());
|
||||
StringFormatter::send(stream, F("<I %d %d>\n"), tto->getId(), tto->getPosition());
|
||||
}
|
||||
return gotOne;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
//#include "IO_TouchKeypad.h // Touch keypad with 16 keys
|
||||
//#include "IO_EXTurntable.h" // Turntable-EX turntable controller
|
||||
//#include "IO_EXFastClock.h" // FastClock driver
|
||||
//#include "IO_PCA9555.h" // 16-bit I/O expander (NXP & Texas Instruments).
|
||||
|
||||
//==========================================================================
|
||||
// The function halSetup() is invoked from CS if it exists within the build.
|
||||
|
|
11
version.h
11
version.h
|
@ -3,7 +3,16 @@
|
|||
|
||||
#include "StringFormatter.h"
|
||||
|
||||
#define VERSION "5.1.11"
|
||||
#define VERSION "5.1.16"
|
||||
// 5.1.16 - Remove I2C address from EXTT_TURNTABLE macro to work with MUX, requires separate HAL macro to create
|
||||
// 5.1.15 - LCC/Adapter support and Exrail feature-compile-out.
|
||||
// 5.1.14 - Fixed IFTTPOSITION
|
||||
// 5.1.13 - Changed turntable broadcast from i to I due to server string conflict
|
||||
// 5.1.12 - Added Power commands <0 A> & <1 A> etc. and update to <=>
|
||||
// Added EXRAIL SET_POWER(track, ON/OFF)
|
||||
// Fixed a problem whereby <1 MAIN> also powered on PROG track
|
||||
// Added functions to TrackManager.cpp to allow UserAddin code for power display on OLED/LCD
|
||||
// Added - returnMode(byte t), returnDCAddr(byte t) & getModeName(byte Mode)
|
||||
// 5.1.11 - STM32F4xx revised I2C clock setup, no correctly sets clock and has fully variable frequency selection
|
||||
// 5.1.10 - STM32F4xx DCCEXanalogWrite to handle PWM generation for TrackManager DC/DCX
|
||||
// - STM32F4xx DCC 58uS timer now using non-PWM output timers where possible
|
||||
|
|
Loading…
Reference in New Issue
Block a user