diff --git a/DCC.cpp b/DCC.cpp index 6fe07c1..854f9b2 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -659,6 +659,7 @@ void DCC::ackManagerLoop() { // (typically waiting for a reset counter or ACK waiting, or when all finished.) switch (opcode) { case BASELINE: + setProgTrackSyncMain(false); if (DCCWaveform::progTrack.getPowerMode() == POWERMODE::OFF) { if (Diag::ACK) DIAG(F("\nAuto Prog power on")); DCCWaveform::progTrack.setPowerMode(POWERMODE::ON); @@ -725,23 +726,20 @@ void DCC::ackManagerLoop() { case ITC0: case ITC1: // If True Callback(0 or 1) (if prevous WACK got an ACK) if (ackReceived) { - ackManagerProg = NULL; // all done now - callback(opcode==ITC0?0:1); + callback(opcode==ITC0?0:1); return; } break; case ITCB: // If True callback(byte) if (ackReceived) { - ackManagerProg = NULL; // all done now callback(ackManagerByte); return; } break; - case ITCB7: // If True callback(byte & 0xF) + case ITCB7: // If True callback(byte & 0x7F) if (ackReceived) { - ackManagerProg = NULL; // all done now callback(ackManagerByte & 0x7F); return; } @@ -749,15 +747,13 @@ void DCC::ackManagerLoop() { case NAKFAIL: // If nack callback(-1) if (!ackReceived) { - ackManagerProg = NULL; // all done now - callback(-1); + callback(-1); return; } break; case FAIL: // callback(-1) - ackManagerProg = NULL; - callback(-1); + callback(-1); return; case STARTMERGE: @@ -801,7 +797,6 @@ void DCC::ackManagerLoop() { case COMBINELOCOID: // ackManagerStash is cv17, ackManagerByte is CV 18 - ackManagerProg=NULL; callback( ackManagerByte + ((ackManagerStash - 192) << 8)); return; @@ -817,7 +812,6 @@ void DCC::ackManagerLoop() { break; default: DIAG(F("\n!! ackOp %d FAULT!!"),opcode); - ackManagerProg=NULL; callback( -1); return; @@ -826,6 +820,7 @@ void DCC::ackManagerLoop() { } } void DCC::callback(int value) { + ackManagerProg=NULL; // no more steps to execute if (DCCWaveform::progTrack.autoPowerOff) { if (Diag::ACK) DIAG(F("\nAuto Prog power off")); DCCWaveform::progTrack.doAutoPowerOff(); diff --git a/WiThrottle.cpp b/WiThrottle.cpp index e3c817a..f824771 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -207,6 +207,7 @@ int WiThrottle::getLocoId(byte * cmd) { if (cmd[0]!='L' && cmd[0]!='S') return 0; // should not match any locos return getInt(cmd+1); } + void WiThrottle::multithrottle(RingStream * stream, byte * cmd){ char throttleChar=cmd[1]; int locoid=getLocoId(cmd+3); // -1 for * @@ -217,6 +218,17 @@ void WiThrottle::multithrottle(RingStream * stream, byte * cmd){ // DIAG(F("\nMultithrottle aval=%c cab=%d"), aval[0],locoid); switch(cmd[2]) { case '+': // add loco request + if (cmd[3]=='*') { + // M+* means get loco from prog track, then join tracks ready to drive away + // Stash the things the callback will need later + stashStream= stream; + stashClient=stream->peekTargetMark(); + stashThrottleChar=throttleChar; + stashInstance=this; + // ask DCC to call us back when the loco id has been read + DCC::getLocoId(getLocoCallback); // will remove any previous join + return; // return nothing in stream as response is sent later in the callback + } //return error if address zero requested if (locoid==0) { StringFormatter::send(stream, F("HMAddress '0' not supported!\n"), cmd[3] ,locoid); @@ -236,7 +248,7 @@ void WiThrottle::multithrottle(RingStream * stream, byte * cmd){ //Get known Fn states from DCC for(int fKey=0; fKey<=28; fKey++) { int fstate=DCC::getFn(locoid,fKey); - if (fstate>=0) StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"),throttleChar,cmd[3],locoid,fstate,fKey); + if (fstate>=0) StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"),throttleChar,cmd[3],locoid,fstate,fKey); } StringFormatter::send(stream, F("M%cA%c%d<;>V%d\n"), throttleChar, cmd[3], locoid, DCCToWiTSpeed(DCC::getThrottleSpeed(locoid))); StringFormatter::send(stream, F("M%cA%c%d<;>R%d\n"), throttleChar, cmd[3], locoid, DCC::getThrottleDirection(locoid)); @@ -367,4 +379,24 @@ void WiThrottle::checkHeartbeat() { char WiThrottle::LorS(int cab) { return (cab<127)?'S':'L'; -} +} + +// Drive Away feature. Callback handling + +RingStream * WiThrottle::stashStream; +WiThrottle * WiThrottle::stashInstance; +byte WiThrottle::stashClient; +char WiThrottle::stashThrottleChar; + +void WiThrottle::getLocoCallback(int locoid) { + stashStream->mark(stashClient); + if (locoid<0) StringFormatter::send(stashStream,F("HMNo loco found on prog track\n")); + else { + char addcmd[20]={'M',stashThrottleChar,'+',LorS(locoid) }; + itoa(locoid,addcmd+4,10); + stashInstance->multithrottle(stashStream, (byte *)addcmd); + DCCWaveform::progTrack.setPowerMode(POWERMODE::ON); + DCC::setProgTrackSyncMain(true); // <1 JOIN> so we can drive loco away + } + stashStream->commit(); +} diff --git a/WiThrottle.h b/WiThrottle.h index 161020d..b065d4f 100644 --- a/WiThrottle.h +++ b/WiThrottle.h @@ -60,6 +60,14 @@ class WiThrottle { void multithrottle(RingStream * stream, byte * cmd); void locoAction(RingStream * stream, byte* aval, char throttleChar, int cab); void accessory(RingStream *, byte* cmd); - void checkHeartbeat(); + void checkHeartbeat(); + + // callback stuff to support prog track acquire + static RingStream * stashStream; + static WiThrottle * stashInstance; + static byte stashClient; + static char stashThrottleChar; + static void getLocoCallback(int locoid); + }; #endif