1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-04-09 15:00:12 +02:00

EXRAIL parser

This commit is contained in:
Asbelos 2025-04-04 13:04:56 +01:00
parent 91e8f89fe2
commit 6087486b91
3 changed files with 61 additions and 45 deletions

View File

@ -117,8 +117,7 @@ These macros are included into the DCCEXParser::execute function so
// helper macro to check track letter // helper macro to check track letter
#define CHECKTRACK CHECK(track>='A' && track<='H', Invalid track A..H) #define CHECKTRACK CHECK(track>='A' && track<='H', Invalid track A..H)
// helper macro to hide command from documentation extractor
#define ZZ_nodoc ZZ
ZZBEGIN ZZBEGIN
ZZ(#) // Request number of simultaneously supported locos ZZ(#) // Request number of simultaneously supported locos

View File

@ -32,4 +32,6 @@
#define CHECK(x,...) if (!(x)) { DCCEXParser::checkFailedFormat=#__VA_ARGS__[0]?F(#__VA_ARGS__):F(#x); return false;} #define CHECK(x,...) if (!(x)) { DCCEXParser::checkFailedFormat=#__VA_ARGS__[0]?F(#__VA_ARGS__):F(#x); return false;}
#define REPLY(format,...) StringFormatter::send(stream,F(format), ##__VA_ARGS__); #define REPLY(format,...) StringFormatter::send(stream,F(format), ##__VA_ARGS__);
#define EXPECT_CALLBACK CHECK(stashCallback(stream, p, ringStream)) #define EXPECT_CALLBACK CHECK(stashCallback(stream, p, ringStream))
// helper macro to hide command from documentation extractor
#define ZZ_nodoc ZZ

View File

@ -163,35 +163,41 @@ return true;
bool RMFT2::parseCommands(Print * stream, byte opcode, byte params, int16_t p[]) { bool RMFT2::parseCommands(Print * stream, byte opcode, byte params, int16_t p[]) {
ZZBEGIN ZZBEGIN
ZZ(D,EXRAIL,ON) diag=1; // <D EXRAIL ON> - turn on diagnostics ZZ(D,EXRAIL,ON) // EXRAIL diagnostics on
ZZ(D,EXRAIL,OFF) diag=0; // <D EXRAIL OFF> - turn off diagnostics diag=1;
ZZ(D,EXRAIL,onoff) diag=onoff; ZZ(D,EXRAIL,OFF) // EXRAIL doagnostics off
ZZ(A,address,aspect) // Aspect may intercept or be left for normal parse diag=0; // <D EXRAIL OFF> - turn off diagnostics
return signalAspectEvent(address,aspect);
ZZ(L) //LCC adapter introducing self // This is not documented here because its an override of the one in DCCEXParserCommands.h
CHECK(streamLCC(stream),no LCC/CBUS events) ZZ_nodoc(A,address,aspect) // Send DCC extended accessory (aspect) and syncronize any signal on this address
ZZ(L,eventid) // loop through all possible sent/waited events return signalAspectEvent(address,aspect);
CHECK(eventid>=0 && eventid<countLCCLookup) ZZ(L) // LCC/CBUS adapter introducing self
startNonRecursiveTask(F("LCC"),eventid,onLCCLookup[eventid]); CHECK(streamLCC(stream),no LCC/CBUS events)
ZZ(L,eventid) // LCC incoming event
ZZ(J,A) REPLY("<jA") routeLookup->stream(stream); REPLY(">\n") CHECK(eventid>=0 && eventid<countLCCLookup)
ZZ(J,A,id) REPLY("<jA %d %c \"%S\">\n",id, getRouteType(id), getRouteDescription(id)); startNonRecursiveTask(F("LCC"),eventid,onLCCLookup[eventid]);
if (compileFeatures & FEATURE_ROUTESTATE) {
// Send any non-default button states or captions ZZ(J,A) // List automation ids
int16_t statePos=routeLookup->findPosition(id); REPLY("<jA") routeLookup->stream(stream); REPLY(">\n")
if (statePos>=0) { ZZ(J,A,id) // list automation details
if (routeStateArray[statePos]) REPLY("<jA %d %c \"%S\">\n",id, getRouteType(id), getRouteDescription(id));
REPLY("<jB %d %d>\n", id, routeStateArray[statePos]); if (compileFeatures & FEATURE_ROUTESTATE) {
if (routeCaptionArray[statePos]) // Send any non-default button states or captions
REPLY("<jB %d \"%S\">\n", id,routeCaptionArray[statePos]); int16_t statePos=routeLookup->findPosition(id);
} if (statePos>=0) {
} if (routeStateArray[statePos]) REPLY("<jB %d %d>\n", id, routeStateArray[statePos]);
ZZ(K,blockid,loco) blockEvent(blockid,loco,true); if (routeCaptionArray[statePos]) REPLY("<jB %d \"%S\">\n", id,routeCaptionArray[statePos]);
ZZ(k,blockid,loco) blockEvent(blockid,loco,false); }
ZZ(/) streamStatus(stream); }
ZZ(/,PAUSE) ZZ(K,blockid,loco) // Loco entering Block
// pause all tasks blockEvent(blockid,loco,true);
ZZ(k,blockid,loco) // Loco exiting block
blockEvent(blockid,loco,false);
ZZ(/) // Stream EXRAIL status
streamStatus(stream);
ZZ(/,PAUSE) // pause all tasks
RMFT2 * task=loopTask; RMFT2 * task=loopTask;
while(task) { while(task) {
task->pause(); task->pause();
@ -201,7 +207,7 @@ bool RMFT2::parseCommands(Print * stream, byte opcode, byte params, int16_t p[])
DCC::estopAll(); // pause all locos on the track DCC::estopAll(); // pause all locos on the track
pausingTask=(RMFT2 *)1; // Impossible task address pausingTask=(RMFT2 *)1; // Impossible task address
ZZ(/,RESUME) ZZ(/,RESUME) // Resume all tasks
pausingTask=NULL; pausingTask=NULL;
RMFT2 * task=loopTask; RMFT2 * task=loopTask;
while(task) { while(task) {
@ -209,18 +215,20 @@ bool RMFT2::parseCommands(Print * stream, byte opcode, byte params, int16_t p[])
task=task->next; task=task->next;
if (task==loopTask) break; if (task==loopTask) break;
} }
ZZ(/,START,route)
ZZ(/,START,route) // Start a route or sequence
auto pc=routeLookup->find(route); auto pc=routeLookup->find(route);
CHECK(pc>=0,route not found) CHECK(pc>=0,route not found)
new RMFT2(pc,0); // no cab for route start new RMFT2(pc,0); // no cab for route start
ZZ(/,START,cab,route) ZZ(/,START,loco,route) // Start an AUTOMATION or sequence with a loco
auto pc=routeLookup->find(route); auto pc=routeLookup->find(route);
CHECK(pc>=0, route not found) CHECK(pc>=0, route not found)
new RMFT2(pc,cab); // no cab for route start new RMFT2(pc,loco);
ZZ(/,KILL,ALL) while (loopTask) loopTask->kill(F("KILL ALL")); // destructor changes loopTask ZZ(/,KILL,ALL) // Kill all exrail tasks
ZZ(/,KILL,taskid) while (loopTask) loopTask->kill(F("KILL ALL")); // destructor changes loopTask
ZZ(/,KILL,taskid) // Kill specific exrail tasks
CHECK(taskid>=0 && taskid<MAX_FLAGS) CHECK(taskid>=0 && taskid<MAX_FLAGS)
auto task=loopTask; auto task=loopTask;
bool found=false; bool found=false;
@ -233,13 +241,20 @@ bool RMFT2::parseCommands(Print * stream, byte opcode, byte params, int16_t p[])
task=task->next; task=task->next;
if (task==loopTask) break; if (task==loopTask) break;
} }
CHECK(found); CHECK(found, task not found)
ZZ(/,RESERVE,section) CHECK(setFlag(section,SECTION_FLAG),invalid section) ZZ(/,RESERVE,section) // Flag section as reserved
ZZ(/,FREE,section) CHECK(setFlag(section,0,SECTION_FLAG),invalid section) CHECK(setFlag(section,SECTION_FLAG),invalid section)
ZZ(/,LATCH,latch) CHECK(setFlag(latch,LATCH_FLAG),invalid section) ZZ(/,FREE,section) // Free reserve on section
ZZ(/,UNLATCH,latch) CHECK(setFlag(latch,0,LATCH_FLAG),invalid section) CHECK(setFlag(section,0,SECTION_FLAG),invalid section)
ZZ(/,RED,signal) doSignal(signal,SIGNAL_RED); ZZ(/,LATCH,latch) // Set pin latch
ZZ(/,AMBER,signal) doSignal(signal,SIGNAL_AMBER); CHECK(setFlag(latch,LATCH_FLAG),invalid section)
ZZ(/,GREEN,signal) doSignal(signal,SIGNAL_GREEN); ZZ(/,UNLATCH,latch) // Removeve pin latch
CHECK(setFlag(latch,0,LATCH_FLAG),invalid section)
ZZ(/,RED,signal) // Set signal to Red
doSignal(signal,SIGNAL_RED);
ZZ(/,AMBER,signal) // set Signal to Amber
doSignal(signal,SIGNAL_AMBER);
ZZ(/,GREEN,signal) // Set signal to Green
doSignal(signal,SIGNAL_GREEN);
ZZEND ZZEND
} }