diff --git a/DCC.cpp b/DCC.cpp index 421dd9b..f192ef5 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -399,6 +399,44 @@ const ackOp PROGMEM LOCO_ID_PROG[] = { FAIL }; +const ackOp PROGMEM SHORT_LOCO_ID_PROG[] = { + BASELINE, + SETCV,(ackOp)19, + SETBYTE, (ackOp)0, + WB,WACK, // ignore router without cv19 support + // Turn off long address flag + SETCV,(ackOp)29, + SETBIT,(ackOp)5, + W0,WACK,NAKFAIL, + SETCV, (ackOp)1, + SETBYTEL, // low byte of word + WB,WACK,NAKFAIL, + VB,WACK,ITCB, + FAIL +}; + +const ackOp PROGMEM LONG_LOCO_ID_PROG[] = { + BASELINE, + // Clear consist CV 19 + SETCV,(ackOp)19, + SETBYTE, (ackOp)0, + WB,WACK, // ignore router without cv19 support + // Turn on long address flag cv29 bit 5 + SETCV,(ackOp)29, + SETBIT,(ackOp)5, + W1,WACK,NAKFAIL, + // Store high byte of address in cv 17 + SETCV, (ackOp)17, + SETBYTEH, // high byte of word + WB,WACK,NAKFAIL, + VB,WACK,NAKFAIL, + // store + SETCV, (ackOp)18, + SETBYTEL, // low byte of word + WB,WACK,NAKFAIL, + VB,WACK,ITC1, // callback(1) means Ok + FAIL +}; // On the following prog-track functions blocking defaults to false. // blocking=true forces the API to block, waiting for the response and invoke the callback BEFORE returning. @@ -441,6 +479,13 @@ void DCC::getLocoId(ACK_CALLBACK callback, bool blocking) { ackManagerSetup(0,0, LOCO_ID_PROG, callback, blocking); } +void DCC::setLocoId(int id,ACK_CALLBACK callback, bool blocking) { + if (id<=0 || id>9999) callback(-1); + int wordval; + if (id<=127) ackManagerSetup(id,SHORT_LOCO_ID_PROG, callback, blocking); + else ackManagerSetup(id | 0xc000,LONG_LOCO_ID_PROG, callback, blocking); +} + void DCC::forgetLoco(int cab) { // removes any speed reminders for this loco int reg=lookupSpeedTable(cab); if (reg>=0) speedTable[reg].loco=0; @@ -573,7 +618,8 @@ int DCC::nextLoco = 0; ackOp const * DCC::ackManagerProg; byte DCC::ackManagerByte; byte DCC::ackManagerStash; -int DCC::ackManagerCv; +int DCC::ackManagerWord; +int DCC::ackManagerCv; byte DCC::ackManagerBitNum; bool DCC::ackReceived; @@ -588,6 +634,13 @@ void DCC::ackManagerSetup(int cv, byte byteValueOrBitnum, ackOp const program[] if (blocking) ackManagerLoop(blocking); } +void DCC::ackManagerSetup(int wordval, ackOp const program[], ACK_CALLBACK callback, bool blocking) { + ackManagerWord=wordval; + ackManagerProg = program; + ackManagerCallback = callback; + if (blocking) ackManagerLoop(blocking); +} + const byte RESET_MIN=8; // tuning of reset counter before sending message // checkRessets return true if the caller should yield back to loop and try later. @@ -742,6 +795,14 @@ void DCC::ackManagerLoop(bool blocking) { ackManagerByte=pgm_read_byte_near(ackManagerProg); break; + case SETBYTEH: + ackManagerByte=highByte(ackManagerWord); + break; + + case SETBYTEL: + ackManagerByte=lowByte(ackManagerWord); + break; + case STASHLOCOID: ackManagerStash=ackManagerByte; // stash value from CV17 break; diff --git a/DCC.h b/DCC.h index d7430c6..d8a1b6b 100644 --- a/DCC.h +++ b/DCC.h @@ -45,6 +45,8 @@ enum ackOp SETBIT, // sets bit number to next prog byte SETCV, // sets cv number to next prog byte SETBYTE, // sets current byte to next prog byte + SETBYTEH, // sets current byte to word high byte + SETBYTEL, // sets current byte to word low 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 @@ -90,6 +92,7 @@ public: static void verifyCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, bool blocking = false); static void getLocoId(ACK_CALLBACK callback, bool blocking = false); + static void setLocoId(int id,ACK_CALLBACK callback, bool blocking = false); // Enhanced API functions static void forgetLoco(int cab); // removes any speed reminders for this loco @@ -126,10 +129,12 @@ private: static byte ackManagerByte; static byte ackManagerBitNum; static int ackManagerCv; + static int ackManagerWord; static byte ackManagerStash; static bool ackReceived; static ACK_CALLBACK ackManagerCallback; static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback, bool blocking); + static void ackManagerSetup(int wordval, ackOp const program[], ACK_CALLBACK callback, bool blocking); static void ackManagerLoop(bool blocking); static bool checkResets(bool blocking, uint8_t numResets); static const int PROG_REPEATS = 8; // repeats of programming commands (some decoders need at least 8 to be reliable) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index fd1cea0..efbba32 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -351,9 +351,12 @@ void DCCEXParser::parse(Print *stream, byte *com, bool blocking) return; case 'W': // WRITE CV ON PROG - if (!stashCallback(stream, p)) - break; - DCC::writeCVByte(p[0], p[1], callback_W, blocking); + if (!stashCallback(stream, p)) + break; + if (params == 1) // Write new loco id (clearing consist and managing short/long) + DCC::setLocoId(p[0],callback_Wloco, blocking); + else // WRITE CV ON PROG + DCC::writeCVByte(p[0], p[1], callback_W, blocking); return; case 'V': // VERIFY CV ON PROG @@ -780,6 +783,13 @@ void DCCEXParser::callback_R(int result) void DCCEXParser::callback_Rloco(int result) { - StringFormatter::send(stashStream, F(""), result); + StringFormatter::send(stashStream, F(""), result & 0x3FFF); + stashBusy = false; +} + +void DCCEXParser::callback_Wloco(int result) +{ + if (result==1) result=stashP[0]; // pick up original requested id from command + StringFormatter::send(stashStream, F(""), result); stashBusy = false; } diff --git a/DCCEXParser.h b/DCCEXParser.h index bef1199..8304e95 100644 --- a/DCCEXParser.h +++ b/DCCEXParser.h @@ -59,6 +59,7 @@ struct DCCEXParser static void callback_B(int result); static void callback_R(int result); static void callback_Rloco(int result); + static void callback_Wloco(int result); static void callback_Vbit(int result); static void callback_Vbyte(int result); static FILTER_CALLBACK filterCallback;