diff --git a/DCC.cpp b/DCC.cpp index d573985..e7ca624 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -221,6 +221,22 @@ const ackOp PROGMEM WRITE_BIT1_PROG[] = { FAIL // callback (-1) }; +const ackOp PROGMEM VERIFY_BIT0_PROG[] = { + BASELINE, + V0, WACK, // validate bit is 0 + ITC0, // if acked, callback(0) + V1, WACK, // validate bit is 1 + ITC1, + FAIL // callback (-1) +}; +const ackOp PROGMEM VERIFY_BIT1_PROG[] = { + BASELINE, + V1, WACK, // validate bit is 1 + ITC1, // if acked, callback(1) + V0, WACK, + ITC0, + FAIL // callback (-1) +}; const ackOp PROGMEM READ_BIT_PROG[] = { BASELINE, @@ -239,6 +255,30 @@ const ackOp PROGMEM WRITE_BYTE_PROG[] = { FAIL // callback (-1) }; +const ackOp PROGMEM VERIFY_BYTE_PROG[] = { + BASELINE, + VB,WACK, // validate byte + ITCB, // if ok callback value + STARTMERGE, //clear bit and byte values ready for merge pass + // each bit is validated against 0 and the result inverted in MERGE + // this is because there tend to be more zeros in cv values than ones. + // There is no need for one validation as entire byte is validated at the end + V0, WACK, MERGE, // read and merge first tested bit (7) + ITSKIP, // do small excursion if there was no ack + SETBIT,(ackOp)7, + V1, WACK, NAKFAIL, // test if there is an ack on the inverse of this bit (7) + SETBIT,(ackOp)6, // and abort whole test if not else continue with bit (6) + SKIPTARGET, + V0, WACK, MERGE, // read and merge second tested bit (6) + V0, WACK, MERGE, // read and merge third tested bit (5) ... + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + V0, WACK, MERGE, + VB, WACK, ITCB, // verify merged byte and return it if acked ok + FAIL }; + const ackOp PROGMEM READ_CV_PROG[] = { BASELINE, @@ -268,6 +308,7 @@ const ackOp PROGMEM LOCO_ID_PROG[] = { SETCV,(ackOp)29, SETBIT,(ackOp)5, V0, WACK, ITSKIP, // Skip to SKIPTARGET if bit 5 of CV29 is zero + V1, WACK, NAKFAIL, // fast fail if no loco on track // Long locoid SETCV, (ackOp)17, // CV 17 is part of locoid STARTMERGE, @@ -329,6 +370,16 @@ void DCC::writeCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, else ackManagerSetup(cv, bitNum, bitValue?WRITE_BIT1_PROG:WRITE_BIT0_PROG, callback, blocking); } +void DCC::verifyCVByte(int cv, byte byteValue, ACK_CALLBACK callback, bool blocking) { + ackManagerSetup(cv, byteValue, VERIFY_BYTE_PROG, callback, blocking); +} + + +void DCC::verifyCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, bool blocking) { + if (bitNum >= 8) callback(-1); + else ackManagerSetup(cv, bitNum, bitValue?VERIFY_BIT1_PROG:VERIFY_BIT0_PROG, callback, blocking); +} + void DCC::readCVBit(int cv, byte bitNum, ACK_CALLBACK callback, bool blocking) { if (bitNum >= 8) callback(-1); diff --git a/DCC.h b/DCC.h index f62feb2..05e9f9e 100644 --- a/DCC.h +++ b/DCC.h @@ -81,6 +81,8 @@ class DCC { static void readCVBit(int cv, byte bitNum, ACK_CALLBACK callback, bool blocking=false); // -1 for error static void writeCVByte(int cv, byte byteValue, ACK_CALLBACK callback, bool blocking=false) ; static void writeCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, bool blocking=false); + static void verifyCVByte(int cv, byte byteValue, ACK_CALLBACK callback, bool blocking=false) ; + static void verifyCVBit(int cv, byte bitNum, bool bitValue, ACK_CALLBACK callback, bool blocking=false); static void getLocoId(ACK_CALLBACK callback, bool blocking=false); diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 8a13c58..b34698d 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -221,11 +221,19 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) { DCC::writeCVByte(p[0],p[1],callback_W,blocking); return; + case 'V': // VERIFY CV ON PROG + if (!stashCallback(stream,p)) break; + if (params==2) DCC::verifyCVByte(p[0],p[1],callback_Vbyte,blocking); + else if (params==3) DCC::verifyCVBit(p[0],p[1],p[2],callback_Vbit,blocking); + else break; + return; + case 'B': // WRITE CV BIT ON PROG if (!stashCallback(stream,p)) break; DCC::writeCVBit(p[0],p[1],p[2],callback_B,blocking); return; + case 'R': // READ CV ON PROG if (!stashCallback(stream,p)) break; DCC::readCV(p[0],callback_R,blocking); @@ -510,6 +518,15 @@ void DCCEXParser::callback_B(int result) { StringFormatter::send(stashStream,F(""), stashP[3],stashP[4], stashP[0],stashP[1],result==1?stashP[2]:-1); stashBusy=false; } +void DCCEXParser::callback_Vbit(int result) { + StringFormatter::send(stashStream,F(""), stashP[0], stashP[1],result); + stashBusy=false; +} +void DCCEXParser::callback_Vbyte(int result) { + StringFormatter::send(stashStream,F(""), stashP[0],result); + stashBusy=false; +} + void DCCEXParser::callback_R(int result) { StringFormatter::send(stashStream,F(""),stashP[1],stashP[2],stashP[0],result); stashBusy=false; diff --git a/DCCEXParser.h b/DCCEXParser.h index 9067340..a90e1b4 100644 --- a/DCCEXParser.h +++ b/DCCEXParser.h @@ -55,6 +55,8 @@ struct DCCEXParser static void callback_W(int result); static void callback_B(int result); static void callback_R(int result); + static void callback_Vbit(int result); + static void callback_Vbyte(int result); static FILTER_CALLBACK filterCallback; static void funcmap(int cab, byte value, byte fstart, byte fstop);