diff --git a/DCC.cpp b/DCC.cpp index f42ddf7..2868abf 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -25,6 +25,7 @@ #include "version.h" #include "FSH.h" #include "IODevice.h" +#include "RMFT2.h" // This module is responsible for converting API calls into // messages to be sent to the waveform generator. @@ -253,6 +254,9 @@ void DCC::setAccessory(int address, byte number, bool activate) { b[1] = ((((address / 64) % 8) << 4) + (number % 4 << 1) + activate % 2) ^ 0xF8; // second byte is of the form 1AAACDDD, where C should be 1, and the least significant D represent activate/deactivate DCCWaveform::mainTrack.schedulePacket(b, 2, 4); // Repeat the packet four times +#if defined(RMFT_ACTIVE) + RMFT2::activateEvent(address<<2|number,activate); +#endif } // diff --git a/RMFT2.cpp b/RMFT2.cpp index 4277f92..7d96118 100644 --- a/RMFT2.cpp +++ b/RMFT2.cpp @@ -18,14 +18,15 @@ */ /* EXRAILPlus planned FEATURE additions - F1. DCC accessory packet opcodes (short and long form) - F2. ONAccessory catchers + F1. [DONE] DCC accessory packet opcodes (short and long form) + F2. [DONE] ONAccessory catchers F3. Turnout descriptions for Withrottle F4. Oled announcements (depends on HAL) F5. Withrottle roster info F6. Multi-occupancy semaphore F7. [DONE see AUTOSTART] Self starting sequences F8. Park/unpark + F9. Analog drive */ /* EXRAILPlus planned TRANSPARENT additions T1. [DONE] RAM based fast lookup for sequences ON* event catchers and signals. @@ -74,6 +75,8 @@ LookList * RMFT2::sequenceLookup=NULL; LookList * RMFT2::signalLookup=NULL; LookList * RMFT2::onThrowLookup=NULL; LookList * RMFT2::onCloseLookup=NULL; +LookList * RMFT2::onActivateLookup=NULL; +LookList * RMFT2::onDeactivateLookup=NULL; #define GET_OPCODE GETFLASH(RMFT2::RouteCode+progCounter) #define GET_OPERAND(n) GETFLASHW(RMFT2::RouteCode+progCounter+1+(n*3)) @@ -112,6 +115,8 @@ LookList * RMFT2::onCloseLookup=NULL; int sequenceCount=0; // to allow for seq 0 at start int onThrowCount=0; int onCloseCount=0; + int onActivateCount=0; + int onDeactivateCount=0; int signalCount=0; // first pass count sizes for fast lookup arrays @@ -137,6 +142,14 @@ LookList * RMFT2::onCloseLookup=NULL; onCloseCount++; break; + case OPCODE_ONACTIVATE: + onActivateCount++; + break; + + case OPCODE_ONDEACTIVATE: + onDeactivateCount++; + break; + default: // Ignore break; } @@ -147,6 +160,8 @@ LookList * RMFT2::onCloseLookup=NULL; signalLookup=new LookList(signalCount); onThrowLookup=new LookList(onThrowCount); onCloseLookup=new LookList(onCloseCount); + onActivateLookup=new LookList(onActivateCount); + onDeactivateLookup=new LookList(onDeactivateCount); // Second pass startup, define any turnouts or servos, set signals red // add signals, sequences onRoutines to the lookups @@ -217,6 +232,14 @@ LookList * RMFT2::onCloseLookup=NULL; onCloseLookup->add(operand,progCounter); break; + case OPCODE_ONACTIVATE: + onActivateLookup->add(operand,progCounter); + break; + + case OPCODE_ONDEACTIVATE: + onDeactivateLookup->add(operand,progCounter); + break; + case OPCODE_AUTOSTART: // automatically create a task from here at startup. new RMFT2(progCounter); @@ -660,6 +683,7 @@ void RMFT2::loop2() { case OPCODE_DRIVE: { + // IMCOMPLETE TODO PENDING HAL changes for analog read etc if (readSensor(operand)) break; byte analogSpeed=IODevice::readAnalogue(GET_OPERAND(1)) *127 / 1024; if (speedo!=analogSpeed) driveLoco(analogSpeed); @@ -798,7 +822,9 @@ void RMFT2::loop2() { case OPCODE_SERVOTURNOUT: // Turnout definition ignored at runtime case OPCODE_PINTURNOUT: // Turnout definition ignored at runtime case OPCODE_ONCLOSE: // Turnout event catcers ignored here - case OPCODE_ONTHROW: // Turnout definition ignored at runtime + case OPCODE_ONTHROW: + case OPCODE_ONACTIVATE: // Activate event catcers ignored here + case OPCODE_ONDEACTIVATE: break; default: @@ -848,9 +874,8 @@ void RMFT2::kill(const FSH * reason, int operand) { void RMFT2::turnoutEvent(int16_t turnoutId, bool closed) { // Hunt for an ONTHROW/ONCLOSE for this turnout - // caution hides class progCounter; - int progCounter= (closed?onCloseLookup:onThrowLookup)->find(turnoutId); - if (progCounter<0) return; + int pc= (closed?onCloseLookup:onThrowLookup)->find(turnoutId); + if (pc<0) return; // Check we dont already have a task running this turnout RMFT2 * task=loopTask; @@ -864,7 +889,27 @@ void RMFT2::kill(const FSH * reason, int operand) { } task->onTurnoutId=turnoutId; // flag for recursion detector - task=new RMFT2(progCounter); // new task starts at this instruction + task=new RMFT2(pc); // new task starts at this instruction + } + + void RMFT2::activateEvent(int16_t addr, bool activate) { + // Hunt for an ONACTIVATE/ONDEACTIVATE for this accessory + int pc= (activate?onActivateLookup:onDeactivateLookup)->find(addr); + if (pc<0) return; + + // Check we dont already have a task running this address + RMFT2 * task=loopTask; + while(task) { + if (task->onActivateAddr==addr) { + DIAG(F("Recursive ON(DE)ACTIVATE for %d"),addr); + return; + } + task=task->next; + if (task==loopTask) break; + } + + task->onActivateAddr=addr; // flag for recursion detector + task=new RMFT2(pc); // new task starts at this instruction } void RMFT2::printMessage2(const FSH * msg) { diff --git a/RMFT2.h b/RMFT2.h index 6fed768..2ebf8af 100644 --- a/RMFT2.h +++ b/RMFT2.h @@ -43,6 +43,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE, OPCODE_PAUSE, OPCODE_RESUME,OPCODE_POWEROFF, OPCODE_ONCLOSE, OPCODE_ONTHROW, OPCODE_SERVOTURNOUT, OPCODE_PINTURNOUT, OPCODE_PRINT,OPCODE_DCCACTIVATE, + OPCODE_ONACTIVATE,OPCODE_ONDEACTIVATE, OPCODE_ROUTE,OPCODE_AUTOMATION,OPCODE_SEQUENCE,OPCODE_ENDTASK,OPCODE_ENDEXRAIL }; @@ -81,6 +82,7 @@ class LookList { static void emitWithrottleRouteList(Print* stream); static void createNewTask(int route, uint16_t cab); static void turnoutEvent(int16_t id, bool closed); + static void activateEvent(int16_t addr, bool active); private: static void ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16_t p[]); static bool parseSlash(Print * stream, byte & paramCount, int16_t p[]) ; @@ -112,6 +114,8 @@ private: static LookList * signalLookup; static LookList * onThrowLookup; static LookList * onCloseLookup; + static LookList * onActivateLookup; + static LookList * onDeactivateLookup; // Local variables - exist for each instance/task RMFT2 *next; // loop chain @@ -126,6 +130,7 @@ private: bool invert; byte speedo; int16_t onTurnoutId; + int16_t onActivateAddr; byte stackDepth; int callStack[MAX_STACK_DEPTH]; }; diff --git a/RMFTMacros.h b/RMFTMacros.h index af0683c..5395725 100644 --- a/RMFTMacros.h +++ b/RMFTMacros.h @@ -94,6 +94,10 @@ #define LCN(msg) #define ONCLOSE(turnout_id) #define ONTHROW(turnout_id) +#define ONACTIVATE(addr,subaddr) +#define ONDEACTIVATE(addr,subaddr) +#define ONACTIVATEL(linear) +#define ONDEACTIVATEL(linear) #define PAUSE #define PRINT(msg) #define POM(cv,value) @@ -198,6 +202,10 @@ const int StringMacroTracker1=__COUNTER__; #undef LATCH #undef LCD #undef LCN +#undef ONACTIVATE +#undef ONDEACTIVATE +#undef ONACTIVATEL +#undef ONDEACTIVATEL #undef ONCLOSE #undef ONTHROW #undef PAUSE @@ -283,6 +291,10 @@ const int StringMacroTracker1=__COUNTER__; #define LATCH(sensor_id) OPCODE_LATCH,V(sensor_id), #define LCD(id,msg) PRINT(msg) #define LCN(msg) PRINT(msg) +#define ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr), +#define ONDEACTIVATE(addr,subaddr) OPCODE_ONDEACTIVATE,V(addr<<2|subaddr), +#define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3), +#define ONDEACTIVATEL(linear) OPCODE_ONDEACTIVATE,V(linear+3), #define ONCLOSE(turnout_id) OPCODE_ONCLOSE,V(turnout_id), #define ONTHROW(turnout_id) OPCODE_ONTHROW,V(turnout_id), #define PAUSE OPCODE_PAUSE,0,0,