diff --git a/CVReader.ino b/CVReader.ino index 5ab4a43..7979c12 100644 --- a/CVReader.ino +++ b/CVReader.ino @@ -14,16 +14,16 @@ */ void myCallback(int result) { - DIAG(F("\n Reading CV 1 callback result=%d"),result); + DIAG(F("\n getting Loco Id callback result=%d"),result); } void setup() { Serial.begin(115200); DCC::begin(); - DIAG(F("\n===== CVReader demonstrating DCC::readCV call ==========\n")); - DCC::readCV(1,myCallback); // myCallback will be called with the result - DIAG(F("\n===== DCC::readCV has returned, but wont be executed until we are in loop() ======\n")); + DIAG(F("\n===== CVReader demonstrating DCC::getLocoId() call ==========\n")); + DCC::getLocoId(myCallback); // myCallback will be called with the result + DIAG(F("\n===== DCC::getLocoId has returned, but wont be executed until we are in loop() ======\n")); DIAG(F("\nReady for JMRI commands\n")); } diff --git a/DCC.cpp b/DCC.cpp index f08f1ca..f3b895c 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -160,6 +160,55 @@ const ackOp PROGMEM READ_CV_PROG[] = { FAIL }; // verification failed +const ackOp PROGMEM LOCO_ID_PROG[] = { + BASELINE, + SETCV,(ackOp)29, + SETBIT,(ackOp)5, + V0, WACK, ITSKIP, // Skip to SKIPTARGET if bit 5 of CV29 is zero + // Long locoid + SETCV, (ackOp)17, // CV 17 is part of locoid + STARTMERGE, + V0, WACK, MERGE, // read and merge bit 1 etc + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + VB, WACK, NAKFAIL, // verify merged byte and return -1 it if not acked ok + STASHLOCOID, // keep stashed cv 17 for later + // Read 2nd part from CV 18 + SETCV, (ackOp)18, + STARTMERGE, + V0, WACK, MERGE, // read and merge bit 1 etc + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + VB, WACK, NAKFAIL, // verify merged byte and return -1 it if not acked ok + COMBINELOCOID, // Combile byte with stash to make long locoid and callback + + // ITSKIP Skips to here if CV 29 bit 5 was zero. so read CV 1 and return that + SKIPTARGET, + SETCV, (ackOp)1, + STARTMERGE, + V0, WACK, MERGE, // read and merge bit 1 etc + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + VB, WACK, ITCB, // verify merged byte and callback + FAIL + }; + + void DCC::writeCVByte(int cv, byte byteValue, ACK_CALLBACK callback) { ackManagerSetup(cv, byteValue, WRITE_BYTE_PROG, callback); @@ -181,6 +230,9 @@ void DCC::readCV(int cv, ACK_CALLBACK callback) { ackManagerSetup(cv, 0,READ_CV_PROG, callback); } +void DCC::getLocoId(ACK_CALLBACK callback) { + ackManagerSetup(0,0, LOCO_ID_PROG, callback); +} void DCC::loop() { DCCWaveform::loop(); // power overload checks @@ -205,27 +257,6 @@ void DCC::loop() { } } -void DCC::getLocoId(ACK_CALLBACK callback) { - callback(-1); // Not yet implemented -// -// switch (readCVBit(29, 5)) { -// case 1: -// // long address : get CV#17 and CV#18 -// { -// int cv17 = readCV(17); -// -// if (cv17 < 0) break; -// int cv18 = readCV(18); -// if (cv18 < 0) break; -// return cv18 + ((cv17 - 192) << 8); -// } -// case 0: // short address in CV1 -// return readCV(1); -// default: // No response or loco -// break; -// } -// return -1; -} ///// Private helper functions below here ///////////////////// @@ -263,6 +294,7 @@ int DCC::nextLoco = 0; //ACK MANAGER ackOp const * DCC::ackManagerProg; byte DCC::ackManagerByte; +byte DCC::ackManagerStash; int DCC::ackManagerCv; byte DCC::ackManagerBitNum; bool DCC::ackReceived; @@ -372,6 +404,14 @@ void DCC::ackManagerLoop() { } break; + case NAKFAIL: // If nack callback(-1) + if (!ackReceived) { + ackManagerProg = NULL; // all done now + (ackManagerCallback)(-1); + return; + } + break; + case FAIL: // callback(-1) ackManagerProg = NULL; (ackManagerCallback)(-1); @@ -388,7 +428,44 @@ void DCC::ackManagerLoop() { if (!ackReceived) ackManagerByte |= 1; ackManagerBitNum--; break; + + case SETBIT: + ackManagerProg++; + ackManagerBitNum=pgm_read_byte_near(ackManagerProg); + break; + + case SETCV: + ackManagerProg++; + ackManagerCv=pgm_read_byte_near(ackManagerProg); + break; + + case STASHLOCOID: + ackManagerStash=ackManagerByte; // stash value from CV17 + break; + case COMBINELOCOID: + // ackManagerStash is cv17, ackManagerByte is CV 18 + ackManagerProg=NULL; + (ackManagerCallback)( ackManagerByte + ((ackManagerStash - 192) << 8)); + return; + + case ITSKIP: + if (!ackReceived) break; + // SKIP opcodes until SKIPTARGET found + while (opcode!=SKIPTARGET) { + ackManagerProg++; + opcode=pgm_read_byte_near(ackManagerProg); + } + // DIAG(F("\nSKIPTARGET located\n")); + break; + case SKIPTARGET: + break; + default: + // DIAG(F("!! ackOp %d FAULT!!"),opcode); + ackManagerProg=NULL; + (ackManagerCallback)( -1); + return; + } // end of switch ackManagerProg++; } diff --git a/DCC.h b/DCC.h index 9562513..4889f7a 100644 --- a/DCC.h +++ b/DCC.h @@ -16,9 +16,16 @@ WACK, // wait for ack (or absence of ack) ITC1, // If True Callback(1) (if prevous WACK got an ACK) ITC0, // If True callback(0); ITCB, // If True callback(byte) +NAKFAIL, // if false callback(-1) FAIL, // callback(-1) STARTMERGE, // Clear bit and byte settings ready for merge pass -MERGE // Merge previous wack response with byte value and decrement bit number (use for readimng CV bytes) +MERGE, // Merge previous wack response with byte value and decrement bit number (use for readimng CV bytes) +SETBIT, // sets bit number to next prog byte +SETCV, // sets cv number to next prog byte +STASHLOCOID, // keeps current byte value for later +COMBINELOCOID, // combines current value with stashed value and returns it +ITSKIP, // skip to SKIPTARGET if ack true +SKIPTARGET=0xFF // jump to target }; class DCC { @@ -62,6 +69,7 @@ private: static byte ackManagerByte; static byte ackManagerBitNum; static int ackManagerCv; + static byte ackManagerStash; static bool ackReceived; static int ackTriggerMilliamps; static ACK_CALLBACK ackManagerCallback;