diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index d796d2a..465e6f4 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -87,6 +87,8 @@ LookList * RMFT2::onClockLookup=NULL; LookList * RMFT2::onRotateLookup=NULL; #endif LookList * RMFT2::onOverloadLookup=NULL; +LookList * RMFT2::onBlockEnterLookup=NULL; +LookList * RMFT2::onBlockExitLookup=NULL; byte * RMFT2::routeStateArray=nullptr; const FSH * * RMFT2::routeCaptionArray=nullptr; int16_t * RMFT2::stashArray=nullptr; @@ -131,11 +133,11 @@ int16_t LookList::find(int16_t value) { void LookList::chain(LookList * chain) { m_chain=chain; } -void LookList::handleEvent(const FSH* reason,int16_t id) { +void LookList::handleEvent(const FSH* reason,int16_t id, int16_t loco) { // New feature... create multiple ONhandlers for (int i=0;i0 && this->onEventStartPosition==-1) DCC::setThrottle(loco,1,DCC::getThrottleDirection(loco)); setFlag(taskId,0,TASK_FLAG); // we are no longer using this id if (next==this) loopTask=NULL; @@ -428,23 +437,9 @@ RMFT2::~RMFT2() { void RMFT2::createNewTask(int route, uint16_t cab) { int pc=routeLookup->find(route); if (pc<0) return; - RMFT2* task=new RMFT2(pc); - task->loco=cab; + new RMFT2(pc,cab); } -void RMFT2::driveLoco(byte speed) { - if (loco<=0) return; // Prevent broadcast! - //if (diag) DIAG(F("EXRAIL drive %d %d %d"),loco,speed,forward^invert); - /* TODO..... - power on appropriate track if DC or main if dcc - if (TrackManager::getMainPowerMode()==POWERMODE::OFF) { - TrackManager::setMainPower(POWERMODE::ON); - } - **********/ - - DCC::setThrottle(loco,speed, forward^invert); - speedo=speed; -} bool RMFT2::readSensor(uint16_t sensorId) { // Exrail operands are unsigned but we need the signed version as inserted by the macros. @@ -499,7 +494,7 @@ bool RMFT2::skipIfBlock() { if (cv & LONG_ADDR_MARKER) { // maker bit indicates long addr progtrackLocoId = cv ^ LONG_ADDR_MARKER; // remove marker bit to get real long addr if (progtrackLocoId <= HIGHEST_SHORT_ADDR ) { // out of range for long addr - DIAG(F("Long addr %d <= %d unsupported"), progtrackLocoId, HIGHEST_SHORT_ADDR); + DIAG(F("Long addr %d <= %d unsupported\n"), progtrackLocoId, HIGHEST_SHORT_ADDR); progtrackLocoId = -1; } } else { @@ -507,6 +502,15 @@ bool RMFT2::skipIfBlock() { } } +void RMFT2::pause() { + if (loco) + pauseSpeed=DCC::getThrottleSpeedByte(loco); +} +void RMFT2::resume() { + if (loco) + DCC::setThrottle(loco,pauseSpeed & 0x7f, pauseSpeed & 0x80); +} + void RMFT2::loop() { if (compileFeatures & FEATURE_SENSOR) EXRAILSensor::checkAll(); @@ -571,18 +575,15 @@ void RMFT2::loop2() { #endif case OPCODE_REV: - forward = false; - driveLoco(operand); + if (loco) DCC::setThrottle(loco,operand,invert); break; case OPCODE_FWD: - forward = true; - driveLoco(operand); - break; + if (loco) DCC::setThrottle(loco,operand,!invert); + break; case OPCODE_SPEED: - forward=DCC::getThrottleDirection(loco)^invert; - driveLoco(operand); + if (loco) DCC::setThrottle(loco,operand,DCC::getThrottleDirection(loco)); break; case OPCODE_FORGET: @@ -594,12 +595,11 @@ void RMFT2::loop2() { case OPCODE_INVERT_DIRECTION: invert= !invert; - driveLoco(speedo); break; case OPCODE_RESERVE: if (getFlag(operand,SECTION_FLAG)) { - driveLoco(0); + if (loco) DCC::setThrottle(loco,0,DCC::getThrottleDirection(loco)); delayMe(500); return; } @@ -697,6 +697,10 @@ void RMFT2::loop2() { break; case OPCODE_PAUSE: + // all tasks save their speed bytes + pause(); + for (RMFT2 * t=next; t!=this;t=t->next) t->pause(); + DCC::setThrottle(0,1,true); // pause all locos on the track pausingTask=this; break; @@ -741,8 +745,8 @@ void RMFT2::loop2() { case OPCODE_RESUME: pausingTask=NULL; - driveLoco(speedo); - for (RMFT2 * t=next; t!=this;t=t->next) if (t->loco >0) t->driveLoco(t->speedo); + resume(); + for (RMFT2 * t=next; t!=this;t=t->next) t->resume(); break; case OPCODE_IF: // do next operand if sensor set @@ -853,8 +857,7 @@ void RMFT2::loop2() { case OPCODE_DRIVE: { - byte analogSpeed=IODevice::readAnalogue(operand) *127 / 1024; - if (speedo!=analogSpeed) driveLoco(analogSpeed); + // Non functional but reserved break; } @@ -944,8 +947,6 @@ void RMFT2::loop2() { // which is intended so it can be checked // from within EXRAIL loco=progtrackLocoId; - speedo=0; - forward=true; invert=false; break; #endif @@ -967,16 +968,13 @@ void RMFT2::loop2() { { int newPc=routeLookup->find(getOperand(1)); if (newPc<0) break; - RMFT2* newtask=new RMFT2(newPc); // create new task - newtask->loco=operand; + new RMFT2(newPc,operand); // create new task } break; case OPCODE_SETLOCO: { loco=operand; - speedo=0; - forward=true; invert=false; } break; @@ -1110,7 +1108,8 @@ void RMFT2::loop2() { case OPCODE_ONROTATE: #endif case OPCODE_ONOVERLOAD: - + case OPCODE_ONBLOCKENTER: + case OPCODE_ONBLOCKEXIT: break; default: @@ -1302,6 +1301,14 @@ void RMFT2::activateEvent(int16_t addr, bool activate) { else onDeactivateLookup->handleEvent(F("DEACTIVATE"),addr); } +void RMFT2::blockEvent(int16_t block, int16_t loco, bool entering) { + if (compileFeatures & FEATURE_BLOCK) { + // Hunt for an ONBLOCKENTER/ONBLOCKEXIT for this accessory + if (entering) onBlockEnterLookup->handleEvent(F("BLOCKENTER"),block,loco); + else onBlockExitLookup->handleEvent(F("BLOCKEXIT"),block,loco); + } +} + void RMFT2::changeEvent(int16_t vpin, bool change) { // Hunt for an ONCHANGE for this sensor if (change) onChangeLookup->handleEvent(F("CHANGE"),vpin); @@ -1357,7 +1364,7 @@ void RMFT2::killBlinkOnVpin(VPIN pin, uint16_t count) { } } -void RMFT2::startNonRecursiveTask(const FSH* reason, int16_t id,int pc) { +void RMFT2::startNonRecursiveTask(const FSH* reason, int16_t id,int pc, int16_t loco) { // Check we dont already have a task running this handler RMFT2 * task=loopTask; while(task) { @@ -1369,7 +1376,7 @@ void RMFT2::startNonRecursiveTask(const FSH* reason, int16_t id,int pc) { if (task==loopTask) break; } - task=new RMFT2(pc); // new task starts at this instruction + task=new RMFT2(pc,loco); // new task starts at this instruction task->onEventStartPosition=pc; // flag for recursion detector } diff --git a/EXRAIL2.h b/EXRAIL2.h index ff45a69..82fdf13 100644 --- a/EXRAIL2.h +++ b/EXRAIL2.h @@ -75,8 +75,9 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,OPCODE_TOGGLE_TURNOUT, OPCODE_ROUTE_ACTIVE,OPCODE_ROUTE_INACTIVE,OPCODE_ROUTE_HIDDEN, OPCODE_ROUTE_DISABLED, OPCODE_STASH,OPCODE_CLEAR_STASH,OPCODE_CLEAR_ALL_STASH,OPCODE_PICKUP_STASH, - OPCODE_ONBUTTON,OPCODE_ONSENSOR, + OPCODE_ONBUTTON,OPCODE_ONSENSOR, OPCODE_NEOPIXEL, + OPCODE_ONBLOCKENTER,OPCODE_ONBLOCKEXIT, // OPcodes below this point are skip-nesting IF operations // placed here so that they may be skipped as a group // see skipIfBlock() @@ -136,6 +137,7 @@ enum SignalType { static const byte FEATURE_STASH = 0x08; static const byte FEATURE_BLINK = 0x04; static const byte FEATURE_SENSOR = 0x02; + static const byte FEATURE_BLOCK = 0x01; // Flag bits for status of hardware and TPL @@ -162,7 +164,7 @@ class LookList { int16_t findPosition(int16_t value); // finds index int16_t size(); void stream(Print * _stream); - void handleEvent(const FSH* reason,int16_t id); + void handleEvent(const FSH* reason,int16_t id, int16_t loco=0); private: int16_t m_size; @@ -176,8 +178,7 @@ class LookList { public: static void begin(); static void loop(); - RMFT2(int progCounter); - RMFT2(int route, uint16_t cab); + RMFT2(int progCounter, int16_t cab=0); ~RMFT2(); static void readLocoCallback(int16_t cv); static void createNewTask(int route, uint16_t cab); @@ -187,6 +188,7 @@ class LookList { static void clockEvent(int16_t clocktime, bool change); static void rotateEvent(int16_t id, bool change); static void powerEvent(int16_t track, bool overload); + static void blockEvent(int16_t block, int16_t loco, bool entering); static bool signalAspectEvent(int16_t address, byte aspect ); // Throttle Info Access functions built by exrail macros static const byte rosterNameCount; @@ -200,7 +202,7 @@ class LookList { static const FSH * getRosterFunctions(int16_t id); static const FSH * getTurntableDescription(int16_t id); static const FSH * getTurntablePositionDescription(int16_t turntableId, uint8_t positionId); - static void startNonRecursiveTask(const FSH* reason, int16_t id,int pc); + static void startNonRecursiveTask(const FSH* reason, int16_t id,int pc, int16_t loco=0); static bool readSensor(uint16_t sensorId); static bool isSignal(int16_t id,char rag); static SIGNAL_DEFINITION getSignalSlot(int16_t slotno); @@ -224,7 +226,6 @@ private: static RMFT2 * loopTask; static RMFT2 * pausingTask; void delayMe(long millisecs); - void driveLoco(byte speedo); bool skipIfBlock(); bool readLoco(); void loop2(); @@ -233,6 +234,8 @@ private: void printMessage2(const FSH * msg); void thrungeString(uint32_t strfar, thrunger mode, byte id=0); uint16_t getOperand(byte n); + void pause(); + void resume(); static bool diag; static const HIGHFLASH3 byte RouteCode[]; @@ -254,6 +257,9 @@ private: static LookList * onRotateLookup; #endif static LookList * onOverloadLookup; + static LookList * onBlockEnterLookup; + static LookList * onBlockExitLookup; + static const int countLCCLookup; static int onLCCLookup[]; @@ -278,9 +284,8 @@ private: byte taskId; BlinkState blinkState; // includes AT_TIMEOUT flag. uint16_t loco; - bool forward; bool invert; - byte speedo; + byte pauseSpeed; int onEventStartPosition; byte stackDepth; int callStack[MAX_STACK_DEPTH]; diff --git a/EXRAIL2MacroReset.h b/EXRAIL2MacroReset.h index 1f4afc8..1fcb878 100644 --- a/EXRAIL2MacroReset.h +++ b/EXRAIL2MacroReset.h @@ -110,6 +110,8 @@ #undef ONACTIVATE #undef ONACTIVATEL #undef ONAMBER +#undef ONBLOCKENTER +#undef ONBLOCKEXIT #undef ONDEACTIVATE #undef ONDEACTIVATEL #undef ONCLOSE @@ -281,6 +283,8 @@ #define ONACTIVATE(addr,subaddr) #define ONACTIVATEL(linear) #define ONAMBER(signal_id) +#define ONBLOCKENTER(blockid) +#define ONBLOCKEXIT(blockid) #define ONTIME(value) #define ONCLOCKTIME(hours,mins) #define ONCLOCKMINS(mins) diff --git a/EXRAIL2Parser.cpp b/EXRAIL2Parser.cpp index a26d78a..61cd18b 100644 --- a/EXRAIL2Parser.cpp +++ b/EXRAIL2Parser.cpp @@ -210,6 +210,14 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16 default: break; } + + case 'K': // Block enter + case 'k': // Block exit + if (paramCount!=2) break; + blockEvent(p[0],p[1],opcode=='K'); + opcode=0; + break; + default: // other commands pass through break; } @@ -228,11 +236,9 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { ); } else { - StringFormatter::send(stream,F("\nID=%d,PC=%d,LOCO=%d%c,SPEED=%d%c"), + StringFormatter::send(stream,F("\nID=%d,PC=%d,LOCO=%d %c"), (int)(task->taskId),task->progCounter,task->loco, - task->invert?'I':' ', - task->speedo, - task->forward?'F':'R' + task->invert?'I':' ' ); } task=task->next; @@ -276,19 +282,27 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { switch (p[0]) { case "PAUSE"_hk: // if (paramCount!=1) return false; - DCC::setThrottle(0,1,true); // pause all locos on the track + { // pause all tasks + RMFT2 * task=loopTask; + while(task) { + task->pause(); + task=task->next; + if (task==loopTask) break; + } + } + DCC::setThrottle(0,1,true); // stop all locos on the track pausingTask=(RMFT2 *)1; // Impossible task address return true; case "RESUME"_hk: // if (paramCount!=1) return false; pausingTask=NULL; - { + { // resume all tasks RMFT2 * task=loopTask; while(task) { - if (task->loco) task->driveLoco(task->speedo); - task=task->next; - if (task==loopTask) break; + task->resume(); + task=task->next; + if (task==loopTask) break; } } return true; @@ -301,8 +315,7 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { uint16_t cab=(paramCount==2)? 0 : p[1]; int pc=routeLookup->find(route); if (pc<0) return false; - RMFT2* task=new RMFT2(pc); - task->loco=cab; + new RMFT2(pc,cab); } return true; diff --git a/EXRAILMacros.h b/EXRAILMacros.h index 7fcfc73..4bc1ace 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -226,6 +226,10 @@ bool exrailHalSetup() { #define ONBUTTON(vpin) | FEATURE_SENSOR #undef ONSENSOR #define ONSENSOR(vpin) | FEATURE_SENSOR +#undef ONBLOCKENTER +#define ONBLOCKENTER(blockid) | FEATURE_BLOCK +#undef ONBLOCKEXIT +#define ONBLOCKEXIT(blockid) | FEATURE_BLOCK const byte RMFT2::compileFeatures = 0 #include "myAutomation.h" @@ -570,6 +574,8 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup]; #define ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr), #define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3), #define ONAMBER(signal_id) OPCODE_ONAMBER,V(signal_id), +#define ONBLOCKENTER(block_id) OPCODE_ONBLOCKENTER,V(block_id), +#define ONBLOCKEXIT(block_id) OPCODE_ONBLOCKEXIT,V(block_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),\