1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-23 12:51:24 +01:00

Merge pull request #121 from DCC-EX/ConsistR

Startup commands and < R > and < W > commands
This commit is contained in:
Asbelos 2021-01-21 11:16:15 +00:00 committed by GitHub
commit 3818a16808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 145 additions and 12 deletions

View File

@ -53,11 +53,17 @@ void setup()
// waveform generation. e.g. DCC::begin(STANDARD_MOTOR_SHIELD,2); to use timer 2 // waveform generation. e.g. DCC::begin(STANDARD_MOTOR_SHIELD,2); to use timer 2
DCC::begin(MOTOR_SHIELD_TYPE); DCC::begin(MOTOR_SHIELD_TYPE);
#if defined(RMFT_ACTIVE) #if defined(RMFT_ACTIVE)
RMFT::begin(); RMFT::begin();
#endif #endif
#if __has_include ( "mySetup.h")
#define SETUP(cmd) serialParser.parse(F(cmd))
#include "mySetup.h"
#undef SETUP
#endif
LCD(1,F("Ready")); LCD(1,F("Ready"));
} }

105
DCC.cpp
View File

@ -331,10 +331,31 @@ const ackOp PROGMEM READ_CV_PROG[] = {
const ackOp PROGMEM LOCO_ID_PROG[] = { const ackOp PROGMEM LOCO_ID_PROG[] = {
BASELINE, BASELINE,
SETCV, (ackOp)1,
SETBIT, (ackOp)7,
V0,WACK,NAKFAIL, // test CV 1 bit 7 is a zero... NAK means no loco found
SETCV, (ackOp)19, // CV 19 is consist setting
SETBYTE, (ackOp)0,
VB, WACK, ITSKIP, // ignore consist if cv19 is zero (no consist)
SETBYTE, (ackOp)128,
VB, WACK, ITSKIP, // ignore consist if cv19 is 128 (no consist, direction bit set)
STARTMERGE, // Setup to read cv 19
V0, WACK, MERGE,
V0, WACK, MERGE,
V0, WACK, MERGE,
V0, WACK, MERGE,
V0, WACK, MERGE,
V0, WACK, MERGE,
V0, WACK, MERGE,
V0, WACK, MERGE,
VB, WACK, ITCB7, // return 7 bits only, No_ACK means CV19 not supported so ignore it
SKIPTARGET, // continue here if CV 19 is zero or fails all validation
SETCV,(ackOp)29, SETCV,(ackOp)29,
SETBIT,(ackOp)5, SETBIT,(ackOp)5,
V0, WACK, ITSKIP, // Skip to SKIPTARGET if bit 5 of CV29 is zero 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 // Long locoid
SETCV, (ackOp)17, // CV 17 is part of locoid SETCV, (ackOp)17, // CV 17 is part of locoid
STARTMERGE, STARTMERGE,
@ -366,7 +387,7 @@ const ackOp PROGMEM LOCO_ID_PROG[] = {
SKIPTARGET, SKIPTARGET,
SETCV, (ackOp)1, SETCV, (ackOp)1,
STARTMERGE, STARTMERGE,
V0, WACK, MERGE, // read and merge bit 1 etc SETBIT, (ackOp)6, // skip over first bit as we know its a zero
V0, WACK, MERGE, V0, WACK, MERGE,
V0, WACK, MERGE, V0, WACK, MERGE,
V0, WACK, MERGE, V0, WACK, MERGE,
@ -378,6 +399,44 @@ const ackOp PROGMEM LOCO_ID_PROG[] = {
FAIL 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. // 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. // blocking=true forces the API to block, waiting for the response and invoke the callback BEFORE returning.
@ -420,6 +479,13 @@ void DCC::getLocoId(ACK_CALLBACK callback, bool blocking) {
ackManagerSetup(0,0, LOCO_ID_PROG, callback, 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 void DCC::forgetLoco(int cab) { // removes any speed reminders for this loco
int reg=lookupSpeedTable(cab); int reg=lookupSpeedTable(cab);
if (reg>=0) speedTable[reg].loco=0; if (reg>=0) speedTable[reg].loco=0;
@ -552,7 +618,8 @@ int DCC::nextLoco = 0;
ackOp const * DCC::ackManagerProg; ackOp const * DCC::ackManagerProg;
byte DCC::ackManagerByte; byte DCC::ackManagerByte;
byte DCC::ackManagerStash; byte DCC::ackManagerStash;
int DCC::ackManagerCv; int DCC::ackManagerWord;
int DCC::ackManagerCv;
byte DCC::ackManagerBitNum; byte DCC::ackManagerBitNum;
bool DCC::ackReceived; bool DCC::ackReceived;
@ -567,6 +634,13 @@ void DCC::ackManagerSetup(int cv, byte byteValueOrBitnum, ackOp const program[]
if (blocking) ackManagerLoop(blocking); 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 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. // checkRessets return true if the caller should yield back to loop and try later.
@ -668,7 +742,15 @@ void DCC::ackManagerLoop(bool blocking) {
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
callback(ackManagerByte); callback(ackManagerByte);
return;
}
break;
case ITCB7: // If True callback(byte & 0xF)
if (ackReceived) {
ackManagerProg = NULL; // all done now
callback(ackManagerByte & 0x7F);
return; return;
} }
break; break;
@ -708,6 +790,19 @@ void DCC::ackManagerLoop(bool blocking) {
ackManagerCv=pgm_read_byte_near(ackManagerProg); ackManagerCv=pgm_read_byte_near(ackManagerProg);
break; break;
case SETBYTE:
ackManagerProg++;
ackManagerByte=pgm_read_byte_near(ackManagerProg);
break;
case SETBYTEH:
ackManagerByte=highByte(ackManagerWord);
break;
case SETBYTEL:
ackManagerByte=lowByte(ackManagerWord);
break;
case STASHLOCOID: case STASHLOCOID:
ackManagerStash=ackManagerByte; // stash value from CV17 ackManagerStash=ackManagerByte; // stash value from CV17
break; break;
@ -724,6 +819,8 @@ void DCC::ackManagerLoop(bool blocking) {
while (opcode!=SKIPTARGET) { while (opcode!=SKIPTARGET) {
ackManagerProg++; ackManagerProg++;
opcode=pgm_read_byte_near(ackManagerProg); opcode=pgm_read_byte_near(ackManagerProg);
// Jump over second byte of any 2-byte opcodes.
if (opcode==SETBIT || opcode==SETBYTE || opcode==SETCV) ackManagerProg++;
} }
break; break;
case SKIPTARGET: case SKIPTARGET:

7
DCC.h
View File

@ -37,12 +37,16 @@ enum ackOp
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, // If True callback(byte) ITCB, // If True callback(byte)
ITCB7, // If True callback(byte &0x7F)
NAKFAIL, // if false callback(-1) NAKFAIL, // if false callback(-1)
FAIL, // callback(-1) FAIL, // callback(-1)
STARTMERGE, // Clear bit and byte settings ready for merge pass 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 SETBIT, // sets bit number to next prog byte
SETCV, // sets cv 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 STASHLOCOID, // keeps current byte value for later
COMBINELOCOID, // combines current value with stashed value and returns it COMBINELOCOID, // combines current value with stashed value and returns it
ITSKIP, // skip to SKIPTARGET if ack true ITSKIP, // skip to SKIPTARGET if ack true
@ -88,6 +92,7 @@ public:
static void verifyCVBit(int cv, byte bitNum, bool bitValue, 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); static void getLocoId(ACK_CALLBACK callback, bool blocking = false);
static void setLocoId(int id,ACK_CALLBACK callback, bool blocking = false);
// Enhanced API functions // Enhanced API functions
static void forgetLoco(int cab); // removes any speed reminders for this loco static void forgetLoco(int cab); // removes any speed reminders for this loco
@ -124,10 +129,12 @@ private:
static byte ackManagerByte; static byte ackManagerByte;
static byte ackManagerBitNum; static byte ackManagerBitNum;
static int ackManagerCv; static int ackManagerCv;
static int ackManagerWord;
static byte ackManagerStash; static byte ackManagerStash;
static bool ackReceived; static bool ackReceived;
static ACK_CALLBACK ackManagerCallback; static ACK_CALLBACK ackManagerCallback;
static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback, bool blocking); 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 void ackManagerLoop(bool blocking);
static bool checkResets(bool blocking, uint8_t numResets); 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) static const int PROG_REPEATS = 8; // repeats of programming commands (some decoders need at least 8 to be reliable)

View File

@ -236,6 +236,14 @@ void DCCEXParser::setAtCommandCallback(AT_COMMAND_CALLBACK callback)
atCommandCallback = callback; atCommandCallback = callback;
} }
// Parse an F() string
void DCCEXParser::parse(const __FlashStringHelper * cmd) {
int size=strlen_P((char *)cmd)+1;
char buffer[size];
strcpy_P(buffer,(char *)cmd);
parse(&Serial,(byte *)buffer,true);
}
// See documentation on DCC class for info on this section // See documentation on DCC class for info on this section
void DCCEXParser::parse(Print *stream, byte *com, bool blocking) void DCCEXParser::parse(Print *stream, byte *com, bool blocking)
{ {
@ -351,9 +359,12 @@ void DCCEXParser::parse(Print *stream, byte *com, bool blocking)
return; return;
case 'W': // WRITE CV ON PROG <W CV VALUE CALLBACKNUM CALLBACKSUB> case 'W': // WRITE CV ON PROG <W CV VALUE CALLBACKNUM CALLBACKSUB>
if (!stashCallback(stream, p)) if (!stashCallback(stream, p))
break; break;
DCC::writeCVByte(p[0], p[1], callback_W, blocking); if (params == 1) // <W id> Write new loco id (clearing consist and managing short/long)
DCC::setLocoId(p[0],callback_Wloco, blocking);
else // WRITE CV ON PROG <W CV VALUE [CALLBACKNUM] [CALLBACKSUB]>
DCC::writeCVByte(p[0], p[1], callback_W, blocking);
return; return;
case 'V': // VERIFY CV ON PROG <V CV VALUE> <V CV BIT 0|1> case 'V': // VERIFY CV ON PROG <V CV VALUE> <V CV BIT 0|1>
@ -780,6 +791,13 @@ void DCCEXParser::callback_R(int result)
void DCCEXParser::callback_Rloco(int result) void DCCEXParser::callback_Rloco(int result)
{ {
StringFormatter::send(stashStream, F("<r %d>"), result); StringFormatter::send(stashStream, F("<r %d>"), 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("<w %d>"), result);
stashBusy = false; stashBusy = false;
} }

View File

@ -28,6 +28,7 @@ struct DCCEXParser
DCCEXParser(); DCCEXParser();
void loop(Stream & stream); void loop(Stream & stream);
void parse(Print * stream, byte * command, bool blocking); void parse(Print * stream, byte * command, bool blocking);
void parse(const __FlashStringHelper * cmd);
void flush(); void flush();
static void setFilter(FILTER_CALLBACK filter); static void setFilter(FILTER_CALLBACK filter);
static void setRMFTFilter(FILTER_CALLBACK filter); static void setRMFTFilter(FILTER_CALLBACK filter);
@ -59,6 +60,7 @@ struct DCCEXParser
static void callback_B(int result); static void callback_B(int result);
static void callback_R(int result); static void callback_R(int result);
static void callback_Rloco(int result); static void callback_Rloco(int result);
static void callback_Wloco(int result);
static void callback_Vbit(int result); static void callback_Vbit(int result);
static void callback_Vbyte(int result); static void callback_Vbyte(int result);
static FILTER_CALLBACK filterCallback; static FILTER_CALLBACK filterCallback;

View File

@ -4,7 +4,10 @@
#include "StringFormatter.h" #include "StringFormatter.h"
// const char VERSION[] PROGMEM ="0.2.0"; // const char VERSION[] PROGMEM ="0.2.0";
#define VERSION "3.0.2" #define VERSION "3.0.3"
// 3.0.3 Includes:
// <W addr> command to write loco address and clear consist
// <R> command will allow for consist address
// Startup commands implemented
#endif #endif