diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index bc2e759..b0e9801 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -519,11 +519,23 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream) switch(p[0]) { case HASH_KEYWORD_A: // returns automations/routes StringFormatter::send(stream, F(" #ifdef EXRAIL_ACTIVE - if (params==1) sendFlashList(stream,RMFT2::routeIdList); - else StringFormatter::send(stream,F(" %d \"%S\""), - id, RMFT2::getRouteDescription(id)); -#endif + sendFlashList(stream,RMFT2::automationIdList); + sendFlashList(stream,RMFT2::routeIdList); +#endif + } + else { // + StringFormatter::send(stream,F(" %d %c \"%S\""), + id, +#ifdef EXRAIL_ACTIVE + RMFT2::getRouteType(id), // A/R + RMFT2::getRouteDescription(id) +#else + 'X',F("") +#endif + ); + } StringFormatter::send(stream, F(">\n")); return; case HASH_KEYWORD_R: // returns rosters @@ -540,15 +552,14 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream) if (params==1) { // for ( Turnout * t=Turnout::first(); t; t=t->next()) { if (t->isHidden()) continue; - StringFormatter::send(stream, F(" %c%d"), - t->isThrown()?'-':' ',t->getId()); + StringFormatter::send(stream, F(" %d"),t->getId()); } } else { // Turnout * t=Turnout::get(id); if (t && !t->isHidden()) - StringFormatter::send(stream, F(" %d \"%S\""), - id, + StringFormatter::send(stream, F(" %d %c \"%S\""), + id,t->isThrown()?'T':'C', #ifdef EXRAIL_ACTIVE RMFT2::getTurnoutDescription(id) #else diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 583bbd9..55be05a 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -260,7 +260,20 @@ int16_t LookList::find(int16_t value) { void RMFT2::setTurnoutHiddenState(Turnout * t) { t->setHidden(GETFLASH(getTurnoutDescription(t->getId()))==0x01); } - + +char RMFT2::getRouteType(int16_t id) { + for (int16_t i=0;;i+=2) { + int16_t rid= GETFLASHW(routeIdList+i); + if (rid==id) return 'R'; + if (rid==0) break; + } + for (int16_t i=0;;i+=2) { + int16_t rid= GETFLASHW(automationIdList+i); + if (rid==id) return 'A'; + if (rid==0) break; + } + return 'X'; +} // This filter intercepts <> commands to do the following: // - Implement RMFT specific commands/diagnostics // - Reject/modify JMRI commands that would interfere with RMFT processing diff --git a/EXRAIL2.h b/EXRAIL2.h index 2d3807b..616b05d 100644 --- a/EXRAIL2.h +++ b/EXRAIL2.h @@ -97,8 +97,10 @@ class LookList { // Throttle Info Access functions built by exrail macros static const byte rosterNameCount; static const int16_t FLASH routeIdList[]; + static const int16_t FLASH automationIdList[]; static const int16_t FLASH rosterIdList[]; static const FSH * getRouteDescription(int16_t id); + static char getRouteType(int16_t id); static const FSH * getTurnoutDescription(int16_t id); static const FSH * getRosterName(int16_t id); static const FSH * getRosterFunctions(int16_t id); diff --git a/EXRAILMacros.h b/EXRAILMacros.h index 07405fe..c11bd35 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -65,11 +65,16 @@ #include "EXRAIL2MacroReset.h" #undef ROUTE #define ROUTE(id, description) id, -#undef AUTOMATION -#define AUTOMATION(id, description) -id, const int16_t FLASH RMFT2::routeIdList[]= { #include "myAutomation.h" 0}; +// Pass 2a create throttle automation list +#include "EXRAIL2MacroReset.h" +#undef AUTOMATION +#define AUTOMATION(id, description) id, +const int16_t FLASH RMFT2::automationIdList[]= { + #include "myAutomation.h" + 0}; // Pass 3 Create route descriptions: #undef ROUTE diff --git a/Release_Notes/ThrottleAssists.md b/Release_Notes/ThrottleAssists.md new file mode 100644 index 0000000..41d0250 --- /dev/null +++ b/Release_Notes/ThrottleAssists.md @@ -0,0 +1,55 @@ +Throttle Assist updates for versiuon 4.? + +Chris Harlow April 2022 + +There are a number of additional throttle information commands that have been implemented to assist throttle authors to obtain information from the Command Station in order to implement turnout, route/automation and roster features which are already found in the Withrottle implementations. +These commands are new and not overlapped with the existing commands which are probabaly due to be obsoleted as they are over complex and unfit for purpose. + +Turnouts: + +The conventional turnout definition commands and the `````` responses do not contain information about the turnout description which may have been provided in an EXRAIL script. A turnout description is much more user friendly than T123 and having a list helps the throttle UI build a suitable set of buttons. + +`````` command returns a list of turnout ids. The throttle should be uninterested in the turnout technology used but needs to know the ids it can throw/close and monitor the current state. +e.g. response `````` + +````` requests info on turnout 17. +e.g. response `````` or `````` +(T=thrown, C=closed) +or `````` indicating turnout description not given. +or `````` indicating turnout unknown. + +Note: It is still the throttles responsibility to monitor the status broadcasts. + (TBD I'm thinking that the existing broadcast is messy and needs cleaning up) + However, I'm not keen on dynamically created/deleted turnouts so I have no intention of providing a command that indicates the turnout list has been updated since the throttle started. + Also note that turnouts marked in EXRAIL with the HIDDEN keyword instead of a "description" will NOT show up in these commands. + + + Automations/Routes + + A throttle need to know which EXRAIL Automations and Routes it can show the user. + + `````` Returns a list of Automations/Routes + e.g. `````` + Indicates route/automation ids. + Information on each route needs to be obtained by + `````` + returns e.g. `````` for a route + or `````` for an automation. + + Whats the difference: + A Route is just a call to an EXRAIL ROUTE, traditionally to set some turnouts or signals but can be used to perform any kind of EXRAIL function... but its not expecting to know the loco. + Thus a route can be triggered by sending in for example ``````. + + An Automation is a handoff of the last accessed loco id to an EXRAIL AUTOMATION which would typically drive the loco away. + Thus an Automation expects a start command with a cab id + e.g. `````` + + + Roster Information: + The `````` command requests a list of cab ids from the roster. + e.g. responding `````` + or for none. + + Each Roster entry had a name and descripotion + + diff --git a/WiThrottle.cpp b/WiThrottle.cpp index 72ee75a..7459a9c 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -139,14 +139,15 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) { exRailSent=true; #ifdef EXRAIL_ACTIVE StringFormatter::send(stream,F("PRT]\\[Routes}|{Route]\\[Set}|{2]\\[Handoff}|{4\nPRL")); - for (int ix=0;;ix+=2) { - int16_t id=GETFLASHW(RMFT2::routeIdList+ix); - if (id==0) break; - bool isRoute=id<0; - if (isRoute) id=-id; - const FSH * desc=RMFT2::getRouteDescription(id); - StringFormatter::send(stream,F("]\\[%c%d}|{%S}|{%c"), - isRoute?'R':'A',id,desc, isRoute?'2':'4'); + for (byte pass=0;pass<2;pass++) { + + for (int ix=0;;ix+=2) { + int16_t id=GETFLASHW((pass?RMFT2::routeIdList:RMFT2::automationIdList)+ix); + if (id==0) break; + const FSH * desc=RMFT2::getRouteDescription(id); + StringFormatter::send(stream,F("]\\[%c%d}|{%S}|{%c"), + pass?'A':'R',id,desc, pass?'4':'2'); + } } StringFormatter::send(stream,F("\n")); #endif