1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-23 08:06:13 +01:00

Ack updates and diags commented out

ACK logic now seems to work.
This commit is contained in:
Asbelos 2020-06-07 16:29:53 +01:00
parent 026ee0b7a8
commit d1843fe38e
3 changed files with 61 additions and 57 deletions

View File

@ -2,36 +2,29 @@
#include "DIAG.h" #include "DIAG.h"
#include "DCCEXParser.h" #include "DCCEXParser.h"
/* this code is here to test the waveforwe generator and reveal the issues involved in programming track operations. /* this code is here to test the waveform generator and reveal the issues involved in programming track operations.
It tests the Waveform genartor and demonstrates how a DCC API function can be simply written It tests the Waveform genartor and demonstrates how a DCC API function can be simply written
to transmit and receive DCC data on the programming track. to transmit and receive DCC data on the programming track.
Once soem CVs have been listed, it then drops into JMRI input moce so you can play. Once started, it continues to operate as a DCC++ compaitible command parser
Important... Config.h contains hardware specific confioguration settings Important... Config.h contains hardware specific confioguration settings
that you will need to check. that you will need to check.
*/ */
void myCallback(int result) {
DIAG(F("\n Reading CV 1 callback result=%d"),result);
const int cvnums[] = {1, 2, 3, 4, 5, 8, 17, 18, 19, 21, 22, 29}; }
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
DCC::begin(); DCC::begin();
// DIAG(F("\n===== CVReader begin ==============================\n")); DIAG(F("\n===== CVReader demonstrating DCC::readCV call ==========\n"));
// DCC::readCV(1,myCallback); // myCallback will be called with the result
// for (byte x = 0; x < sizeof(cvnums) / sizeof(cvnums[0]); x++) { DIAG(F("\n===== DCC::readCV has returned, but wont be executed until we are in loop() ======\n"));
// int value = DCC::readCV(cvnums[x]); DIAG(F("\nReady for JMRI commands\n"));
// DIAG(F("\nCV %d = %d 0x%x %s\n"), cvnums[x], value, value, value >= 0 ? " VERIFIED OK" : "FAILED VERIFICATION");
// }
// DIAG(F("\n===== CVReader done ==============================\n"));
DIAG(F("\nReady for JMRI commands\n"));
} }
void loop() { void loop() {

81
DCC.cpp
View File

@ -108,14 +108,14 @@ void DCC::writeCVBitMain(int cab, int cv, byte bNum, bool bValue) {
const ackOp WRITE_BIT0_PROG[] = { const ackOp PROGMEM WRITE_BIT0_PROG[] = {
BASELINE, BASELINE,
W0,WACK, W0,WACK,
V0, WACK, // validate bit is 0 V0, WACK, // validate bit is 0
ITC1, // if acked, callback(1) ITC1, // if acked, callback(1)
FAIL // callback (-1) FAIL // callback (-1)
}; };
const ackOp WRITE_BIT1_PROG[] = { const ackOp PROGMEM WRITE_BIT1_PROG[] = {
BASELINE, BASELINE,
W1,WACK, W1,WACK,
V1, WACK, // validate bit is 1 V1, WACK, // validate bit is 1
@ -124,7 +124,7 @@ const ackOp WRITE_BIT1_PROG[] = {
}; };
const ackOp READ_BIT_PROG[] = { const ackOp PROGMEM READ_BIT_PROG[] = {
BASELINE, BASELINE,
V1, WACK, // validate bit is 1 V1, WACK, // validate bit is 1
ITC1, // if acked, callback(1) ITC1, // if acked, callback(1)
@ -133,7 +133,7 @@ const ackOp READ_BIT_PROG[] = {
FAIL // bit not readable FAIL // bit not readable
}; };
const ackOp WRITE_BYTE_PROG[] = { const ackOp PROGMEM WRITE_BYTE_PROG[] = {
BASELINE, BASELINE,
WB,WACK, // Write WB,WACK, // Write
VB,WACK, // validate byte VB,WACK, // validate byte
@ -142,9 +142,9 @@ const ackOp WRITE_BYTE_PROG[] = {
}; };
const ackOp READ_CV_PROG[] = { const ackOp PROGMEM READ_CV_PROG[] = {
BASELINE, BASELINE,
ZERO, //clear bit and byte values STARTMERGE, //clear bit and byte values ready for merge pass
// each bit is validated against 1 (no need for zero validation as entire byte is validated at the end) // each bit is validated against 1 (no need for zero validation as entire byte is validated at the end)
V1, WACK, MERGE, // read and merge bit 0 V1, WACK, MERGE, // read and merge bit 0
V1, WACK, MERGE, // read and merge bit 1 etc V1, WACK, MERGE, // read and merge bit 1 etc
@ -277,19 +277,27 @@ void DCC::ackManagerSetup(int cv, byte byteValueOrBitnum, ackOp const program[]
} }
#define RESET_MIN 8 const byte RESET_MIN=8; // tuning of reset counter before sending message
void DCC::ackManagerLoop() { void DCC::ackManagerLoop() {
while (ackManagerProg) { while (ackManagerProg) {
// breaks from this switch will step to next prog entry // breaks from this switch will step to next prog entry
// returns from this switch will stay on same entry (typically WACK waiting and when all finished.) // returns from this switch will stay on same entry (typically WACK waiting and when all finished.)
byte opcode=*ackManagerProg; byte opcode=pgm_read_byte_near(ackManagerProg);
// DIAG(F("apAck %d\n"),opcode);
int resets=DCCWaveform::progTrack.sentResetsSincePacket; int resets=DCCWaveform::progTrack.sentResetsSincePacket;
int current;
// DIAG(F("\nopAck %d"),opcode);
switch (opcode) { switch (opcode) {
case W0: // write bit case BASELINE:
case W1: // write bit if (resets<RESET_MIN) return; // try later
ackTriggerMilliamps=Hardware::getCurrentMilliamps(false) + ACK_MIN_PULSE;
// DIAG(F("\nBASELINE trigger mA=%d\n"),ackTriggerMilliamps);
break;
case W0: // write 0 bit
case W1: // write 1 bit
{ {
if (resets<RESET_MIN) return; // try later if (resets<RESET_MIN) return; // try later
byte instruction = WRITE_BIT | (opcode==W1 ? BIT_ON : BIT_OFF) | ackManagerBitNum; byte instruction = WRITE_BIT | (opcode==W1 ? BIT_ON : BIT_OFF) | ackManagerBitNum;
@ -297,6 +305,7 @@ void DCC::ackManagerLoop() {
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 6); DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 6);
} }
break; break;
case WB: // write byte case WB: // write byte
{ {
if (resets<RESET_MIN) return; // try later if (resets<RESET_MIN) return; // try later
@ -304,78 +313,80 @@ void DCC::ackManagerLoop() {
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 6); DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 6);
} }
break; break;
case VB: // Issue validate Byte packet case VB: // Issue validate Byte packet
{ {
if (resets<RESET_MIN) return; // try later if (resets<RESET_MIN) return; // try later
DIAG(F("\nVB %d %d"),ackManagerCv,ackManagerByte); // DIAG(F("\nVB %d %d"),ackManagerCv,ackManagerByte);
byte message[] = { cv1(VERIFY_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte}; byte message[] = { cv1(VERIFY_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 5); DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 5);
} }
break; break;
case V0: case V0:
case V1: // Issue validate bit=0 or bit=1 packet case V1: // Issue validate bit=0 or bit=1 packet
{ {
if (resets<RESET_MIN) return; // try later if (resets<RESET_MIN) return; // try later
DIAG(F("V%d cv=%d bit=%d"),opcode==V1, ackManagerCv,ackManagerBitNum); // DIAG(F("V%d cv=%d bit=%d"),opcode==V1, ackManagerCv,ackManagerBitNum);
byte instruction = VERIFY_BIT | (opcode==V0?BIT_OFF:BIT_ON) | ackManagerBitNum; byte instruction = VERIFY_BIT | (opcode==V0?BIT_OFF:BIT_ON) | ackManagerBitNum;
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction }; byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 5); DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 5);
} }
break; break;
case WACK: // wait for ack (or absence of ack) case WACK: // wait for ack (or absence of ack)
{
if (resets > 6) { if (resets > 6) { //ACK timeout
DIAG(F("\nWACK fail %d\n"), resets); // DIAG(F("\nWACK fail %d\n"), resets);
ackReceived = false; ackReceived = false;
break; // move on to next prog step break; // move on to next prog step
} }
int current=Hardware::getCurrentMilliamps(false); current=Hardware::getCurrentMilliamps(false);
if (current > ackTriggerMilliamps) { if (current > ackTriggerMilliamps) { //ACK detected
DIAG(F("\nWACK ok %dmA, after %d resets\n"), current,resets); // DIAG(F("\nACK %dmA, after %d resets\n"), current,resets);
ackReceived = true; ackReceived = true;
DCCWaveform::progTrack.killRemainingRepeats(); DCCWaveform::progTrack.killRemainingRepeats();
break; // move on tho next step break; // move on tho next step
} }
}
return; // maintain place for next poll cycle. return; // check again on next loop cycle.
case ITC0: case ITC0:
case ITC1: // If True Callback(0 or 1) (if prevous WACK got an ACK) case ITC1: // If True Callback(0 or 1) (if prevous WACK got an ACK)
if (ackReceived) { if (ackReceived) {
ackManagerProg = NULL; ackManagerProg = NULL; // all done now
(ackManagerCallback)(opcode==ITC0?0:1); (ackManagerCallback)(opcode==ITC0?0:1);
return; return;
} }
break; break;
case ITCB: // If True callback(byte) case ITCB: // If True callback(byte)
if (ackReceived) { if (ackReceived) {
ackManagerProg = NULL; ackManagerProg = NULL; // all done now
(ackManagerCallback)(ackManagerByte); (ackManagerCallback)(ackManagerByte);
return; return;
} }
break; break;
case MERGE: // Merge previous wack response with byte value and increment bit number (use for reading CV bytes)
ackManagerByte <<= 1;
if (ackReceived) ackManagerByte |= 1;
ackManagerBitNum--;
break;
case FAIL: // callback(-1) case FAIL: // callback(-1)
ackManagerProg = NULL; ackManagerProg = NULL;
(ackManagerCallback)(-1); (ackManagerCallback)(-1);
return; return;
case ZERO:
case STARTMERGE:
ackManagerBitNum=7; ackManagerBitNum=7;
ackManagerByte=0; ackManagerByte=0;
break; break;
case BASELINE:
if (resets<RESET_MIN) return; // try later case MERGE: // Merge previous wack response with byte value and update bit number (use for reading CV bytes)
ackTriggerMilliamps=Hardware::getCurrentMilliamps(false) + ACK_MIN_PULSE; ackManagerByte <<= 1;
DIAG(F("BASELINE mA=%d"),ackTriggerMilliamps); if (ackReceived) ackManagerByte |= 1;
ackManagerBitNum--;
break; break;
} // end of switch
} // end of switch
ackManagerProg++; ackManagerProg++;
} }
} }

12
DCC.h
View File

@ -6,19 +6,19 @@
typedef void (*ACK_CALLBACK)(int result); typedef void (*ACK_CALLBACK)(int result);
enum ackOp { // Program opcodes for the ack Manager enum ackOp { // Program opcodes for the ack Manager
W0,W1, // issue write bit BASELINE, // ensure enough resets sent before starting and obtain baseline current
WB, // issue write byte W0,W1, // issue write bit (0..1) packet
WB, // issue write byte packet
VB, // Issue validate Byte packet VB, // Issue validate Byte packet
V0, // Issue validate bit=0 packet V0, // Issue validate bit=0 packet
V1, // issue validate bit=1 packlet V1, // issue validate bit=1 packlet
WACK, // wait for ack (or absence of ack) WACK, // wait for ack (or absence of ack)
ITC1, // If True Callback(1) (if prevous WACK got an ACK) ITC1, // If True Callback(1) (if prevous WACK got an ACK)
ITC0, // If True callback(0); ITC0, // If True callback(0);
ITCB, // IOf True callback(byte) ITCB, // If True callback(byte)
MERGE, // Merge previous wack response with byte value and increment bit number (use for readimng CV bytes)
FAIL, // callback(-1) FAIL, // callback(-1)
ZERO, // Clear bit and byte STARTMERGE, // Clear bit and byte settings ready for merge pass
BASELINE // ensure enough resets sent before starting and obtain baseline MERGE // Merge previous wack response with byte value and decrement bit number (use for readimng CV bytes)
}; };
class DCC { class DCC {