mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-24 21:21:24 +01:00
ACK diagnostics
Type <D 1> to enable
This commit is contained in:
parent
5269177f2e
commit
bec57345f1
68
DCC.cpp
68
DCC.cpp
@ -24,6 +24,7 @@ const byte FN_GROUP_5=0x10;
|
|||||||
|
|
||||||
|
|
||||||
void DCC::begin() {
|
void DCC::begin() {
|
||||||
|
debugMode=false;
|
||||||
DCCWaveform::begin();
|
DCCWaveform::begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +275,10 @@ void DCC::forgetAllLocos() { // removes all speed reminders
|
|||||||
for (int i=0;i<MAX_LOCOS;i++) speedTable[i].loco=0;
|
for (int i=0;i<MAX_LOCOS;i++) speedTable[i].loco=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DCC::setDebug(bool on) {
|
||||||
|
debugMode=on;
|
||||||
|
}
|
||||||
|
|
||||||
byte DCC::loopStatus=0;
|
byte DCC::loopStatus=0;
|
||||||
|
|
||||||
void DCC::loop() {
|
void DCC::loop() {
|
||||||
@ -399,6 +404,9 @@ byte DCC::ackManagerBitNum;
|
|||||||
bool DCC::ackReceived;
|
bool DCC::ackReceived;
|
||||||
int DCC::ackTriggerMilliamps;
|
int DCC::ackTriggerMilliamps;
|
||||||
unsigned long DCC::ackPulseStart;
|
unsigned long DCC::ackPulseStart;
|
||||||
|
int DCC::ackMaxCurrent;
|
||||||
|
int DCC::ackPollCount;
|
||||||
|
bool DCC::debugMode=false;
|
||||||
|
|
||||||
ACK_CALLBACK DCC::ackManagerCallback;
|
ACK_CALLBACK DCC::ackManagerCallback;
|
||||||
|
|
||||||
@ -408,7 +416,8 @@ void DCC::ackManagerSetup(int cv, byte byteValueOrBitnum, ackOp const program[]
|
|||||||
ackManagerByte = byteValueOrBitnum;
|
ackManagerByte = byteValueOrBitnum;
|
||||||
ackManagerBitNum=byteValueOrBitnum;
|
ackManagerBitNum=byteValueOrBitnum;
|
||||||
ackManagerCallback = callback;
|
ackManagerCallback = callback;
|
||||||
|
ackMaxCurrent=0;
|
||||||
|
ackPollCount=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const byte RESET_MIN=8; // tuning of reset counter before sending message
|
const byte RESET_MIN=8; // tuning of reset counter before sending message
|
||||||
@ -419,15 +428,14 @@ void DCC::ackManagerLoop() {
|
|||||||
// 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=pgm_read_byte_near(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;
|
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case BASELINE:
|
case BASELINE:
|
||||||
if (resets<RESET_MIN) return; // try later
|
if (resets<RESET_MIN) return; // try later
|
||||||
ackTriggerMilliamps=Hardware::getCurrentMilliamps(false) + ACK_MIN_PULSE;
|
ackTriggerMilliamps=Hardware::getCurrentMilliamps(false) + ACK_MIN_PULSE;
|
||||||
// DIAG(F("\nBASELINE trigger mA=%d\n"),ackTriggerMilliamps);
|
if (debugMode) DIAG(F("\nACK_BASELINE trigger mA=%d\n"),ackTriggerMilliamps);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case W0: // write 0 bit
|
case W0: // write 0 bit
|
||||||
@ -438,6 +446,8 @@ void DCC::ackManagerLoop() {
|
|||||||
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
||||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 6);
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 6);
|
||||||
ackPulseStart=0;
|
ackPulseStart=0;
|
||||||
|
ackMaxCurrent=0;
|
||||||
|
ackPollCount=0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -447,16 +457,20 @@ void DCC::ackManagerLoop() {
|
|||||||
byte message[] = {cv1(WRITE_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
byte message[] = {cv1(WRITE_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
||||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 6);
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 6);
|
||||||
ackPulseStart=0;
|
ackPulseStart=0;
|
||||||
|
ackMaxCurrent=0;
|
||||||
|
ackPollCount=0;
|
||||||
}
|
}
|
||||||
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);
|
if (debugMode) 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);
|
||||||
ackPulseStart=0;
|
ackPulseStart=0;
|
||||||
|
ackMaxCurrent=0;
|
||||||
|
ackPollCount=0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -464,23 +478,29 @@ void DCC::ackManagerLoop() {
|
|||||||
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);
|
if (debugMode) DIAG(F("\nV%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);
|
||||||
ackPulseStart=0;
|
ackPulseStart=0;
|
||||||
|
ackMaxCurrent=0;
|
||||||
|
ackPollCount=0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WACK: // wait for ack (or absence of ack)
|
case WACK: // wait for ack (or absence of ack)
|
||||||
|
{
|
||||||
if (resets > 6) { //ACK timeout
|
if (resets > 6) { //ACK timeout
|
||||||
// DIAG(F("\nWACK fail %d\n"), resets);
|
if (debugMode) DIAG(F("\nWACK fail polls=%d, resets=%d, max=%dmA"), ackPollCount, resets, ackMaxCurrent);
|
||||||
ackReceived = false;
|
ackReceived = false;
|
||||||
break; // move on to next prog step
|
break; // move on to next prog step
|
||||||
}
|
}
|
||||||
|
|
||||||
current=Hardware::getCurrentMilliamps(false);
|
int current=Hardware::getCurrentMilliamps(false);
|
||||||
|
if (current > ackMaxCurrent) ackMaxCurrent=current;
|
||||||
|
|
||||||
|
ackPollCount++;
|
||||||
|
|
||||||
// An ACK is a pulse lasting between 4.5 and 8.5 mSecs (refer @haba)
|
// An ACK is a pulse lasting between 4.5 and 8.5 mSecs (refer @haba)
|
||||||
|
|
||||||
if (current>ackTriggerMilliamps) {
|
if (current>ackTriggerMilliamps) {
|
||||||
@ -490,22 +510,25 @@ void DCC::ackManagerLoop() {
|
|||||||
|
|
||||||
// not in pulse
|
// not in pulse
|
||||||
if (ackPulseStart==0) return; // keep waiting for leading edge
|
if (ackPulseStart==0) return; // keep waiting for leading edge
|
||||||
{ // detected trailing edge of pulse
|
|
||||||
|
// detected trailing edge of pulse
|
||||||
long pulseDuration=micros()-ackPulseStart;
|
long pulseDuration=micros()-ackPulseStart;
|
||||||
if (pulseDuration>4500 && pulseDuration<8000) {
|
|
||||||
|
if (pulseDuration>4000 && pulseDuration<9000) {
|
||||||
|
if (debugMode) DIAG(F("\nWACK-OK polls=%d, max=%dmA, pulse=%duS"),ackPollCount, ackMaxCurrent, pulseDuration);
|
||||||
ackReceived=true;
|
ackReceived=true;
|
||||||
DCCWaveform::progTrack.killRemainingRepeats(); // probably no need after 8.5ms!!
|
DCCWaveform::progTrack.killRemainingRepeats(); // probably no need after 8.5ms!!
|
||||||
break; // we have a genuine ACK result
|
break; // we have a genuine ACK result
|
||||||
}
|
}
|
||||||
}
|
if (debugMode) DIAG(F("\nWACK-bad pulse polls=%d, max=%dmA, pulse=%duS"), ackPollCount, ackMaxCurrent, pulseDuration);
|
||||||
ackPulseStart=0; // We have detected a too-short or too-long pulse so ignore and wait for next leading edge
|
ackPulseStart=0; // We have detected a too-short or too-long pulse so ignore and wait for next leading edge
|
||||||
return; // keep waiting
|
return; // keep waiting
|
||||||
|
}
|
||||||
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; // all done now
|
ackManagerProg = NULL; // all done now
|
||||||
(ackManagerCallback)(opcode==ITC0?0:1);
|
callback(opcode==ITC0?0:1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -513,7 +536,7 @@ void DCC::ackManagerLoop() {
|
|||||||
case ITCB: // If True callback(byte)
|
case ITCB: // If True callback(byte)
|
||||||
if (ackReceived) {
|
if (ackReceived) {
|
||||||
ackManagerProg = NULL; // all done now
|
ackManagerProg = NULL; // all done now
|
||||||
(ackManagerCallback)(ackManagerByte);
|
callback(ackManagerByte);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -521,14 +544,14 @@ void DCC::ackManagerLoop() {
|
|||||||
case NAKFAIL: // If nack callback(-1)
|
case NAKFAIL: // If nack callback(-1)
|
||||||
if (!ackReceived) {
|
if (!ackReceived) {
|
||||||
ackManagerProg = NULL; // all done now
|
ackManagerProg = NULL; // all done now
|
||||||
(ackManagerCallback)(-1);
|
callback(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FAIL: // callback(-1)
|
case FAIL: // callback(-1)
|
||||||
ackManagerProg = NULL;
|
ackManagerProg = NULL;
|
||||||
(ackManagerCallback)(-1);
|
callback(-1);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case STARTMERGE:
|
case STARTMERGE:
|
||||||
@ -560,7 +583,7 @@ void DCC::ackManagerLoop() {
|
|||||||
case COMBINELOCOID:
|
case COMBINELOCOID:
|
||||||
// ackManagerStash is cv17, ackManagerByte is CV 18
|
// ackManagerStash is cv17, ackManagerByte is CV 18
|
||||||
ackManagerProg=NULL;
|
ackManagerProg=NULL;
|
||||||
(ackManagerCallback)( ackManagerByte + ((ackManagerStash - 192) << 8));
|
callback( ackManagerByte + ((ackManagerStash - 192) << 8));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case ITSKIP:
|
case ITSKIP:
|
||||||
@ -570,17 +593,20 @@ void DCC::ackManagerLoop() {
|
|||||||
ackManagerProg++;
|
ackManagerProg++;
|
||||||
opcode=pgm_read_byte_near(ackManagerProg);
|
opcode=pgm_read_byte_near(ackManagerProg);
|
||||||
}
|
}
|
||||||
// DIAG(F("\nSKIPTARGET located\n"));
|
|
||||||
break;
|
break;
|
||||||
case SKIPTARGET:
|
case SKIPTARGET:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// DIAG(F("!! ackOp %d FAULT!!"),opcode);
|
DIAG(F("!! ackOp %d FAULT!!"),opcode);
|
||||||
ackManagerProg=NULL;
|
ackManagerProg=NULL;
|
||||||
(ackManagerCallback)( -1);
|
callback( -1);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} // end of switch
|
} // end of switch
|
||||||
ackManagerProg++;
|
ackManagerProg++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void DCC::callback(int value) {
|
||||||
|
if (debugMode) DIAG(F("\nCallback(%d)\n"),value);
|
||||||
|
(ackManagerCallback)( value);
|
||||||
|
}
|
||||||
|
5
DCC.h
5
DCC.h
@ -44,6 +44,7 @@ class DCC {
|
|||||||
static void setFn( int cab, byte functionNumber, bool on);
|
static void setFn( int cab, byte functionNumber, bool on);
|
||||||
static void setAccessory(int aAdd, byte aNum, bool activate) ;
|
static void setAccessory(int aAdd, byte aNum, bool activate) ;
|
||||||
static bool writeTextPacket( byte *b, int nBytes);
|
static bool writeTextPacket( byte *b, int nBytes);
|
||||||
|
static void setDebug(bool on);
|
||||||
|
|
||||||
// ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1
|
// ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1
|
||||||
static void readCV(int cv, ACK_CALLBACK callback);
|
static void readCV(int cv, ACK_CALLBACK callback);
|
||||||
@ -75,6 +76,8 @@ private:
|
|||||||
static byte cv2(int cv);
|
static byte cv2(int cv);
|
||||||
static int lookupSpeedTable(int locoId);
|
static int lookupSpeedTable(int locoId);
|
||||||
static void issueReminders();
|
static void issueReminders();
|
||||||
|
static void callback(int value);
|
||||||
|
static bool debugMode;
|
||||||
|
|
||||||
// ACK MANAGER
|
// ACK MANAGER
|
||||||
static ackOp const * ackManagerProg;
|
static ackOp const * ackManagerProg;
|
||||||
@ -84,6 +87,8 @@ private:
|
|||||||
static byte ackManagerStash;
|
static byte ackManagerStash;
|
||||||
static bool ackReceived;
|
static bool ackReceived;
|
||||||
static int ackTriggerMilliamps;
|
static int ackTriggerMilliamps;
|
||||||
|
static int ackMaxCurrent;
|
||||||
|
static int ackPollCount;
|
||||||
static unsigned long ackPulseStart;
|
static unsigned long ackPulseStart;
|
||||||
static ACK_CALLBACK ackManagerCallback;
|
static ACK_CALLBACK ackManagerCallback;
|
||||||
static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback);
|
static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback);
|
||||||
|
@ -227,6 +227,11 @@ void DCCEXParser::parse(Print & stream, const byte *com) {
|
|||||||
StringFormatter::send(stream,F("\n"));
|
StringFormatter::send(stream,F("\n"));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 'D': // < >
|
||||||
|
DCC::setDebug(p[0]==1);
|
||||||
|
DIAG(F("\nDCC DEBUG MODE %d"),p[0]==1);
|
||||||
|
return;
|
||||||
|
|
||||||
default: //anything else will drop out to <X>
|
default: //anything else will drop out to <X>
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user