From 42075f838ecc5f52da388b3a3fda1f08906dabf8 Mon Sep 17 00:00:00 2001 From: mstevetodd Date: Mon, 4 Jan 2021 10:57:03 -0500 Subject: [PATCH 01/13] should send turnout definitions, not just states (#110) * use int, not byte for witSpeed * add turnout, sensor and output states to 's'tatus message * should send turnout definitions, not just states --- DCCEXParser.cpp | 11 ++++++----- Turnouts.cpp | 7 +++++++ Turnouts.h | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 0a78676..753f69b 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -445,7 +445,7 @@ void DCCEXParser::parse(Print *stream, byte *com, bool blocking) case 's': // StringFormatter::send(stream, F(""), DCCWaveform::mainTrack.getPowerMode() == POWERMODE::ON); StringFormatter::send(stream, F(""), F(VERSION), F(ARDUINO_TYPE), DCC::getMotorShieldName(), F(GITHUB_SHA)); - parseT(stream, 0, p); //send all Turnout states + Turnout::printAll(stream); //send all Turnout states Output::printAll(stream); //send all Output states Sensor::printAll(stream); //send all Sensor states // TODO Send stats of speed reminders table @@ -529,7 +529,7 @@ bool DCCEXParser::parseZ(Print *stream, int params, int p[]) StringFormatter::send(stream, F("")); return true; - case 0: // + case 0: // list Output definitions { bool gotone = false; for (Output *tt = Output::firstOutput; tt != NULL; tt = tt->nextOutput) @@ -591,13 +591,14 @@ bool DCCEXParser::parseT(Print *stream, int params, int p[]) { switch (params) { - case 0: // list all turnout states + case 0: // list turnout definitions { bool gotOne = false; for (Turnout *tt = Turnout::firstTurnout; tt != NULL; tt = tt->nextTurnout) { gotOne = true; - StringFormatter::send(stream, F(""), tt->data.id, (tt->data.tStatus & STATUS_ACTIVE)!=0); + StringFormatter::send(stream, F(""), tt->data.id, tt->data.address, + tt->data.subAddress, (tt->data.tStatus & STATUS_ACTIVE)!=0); } return gotOne; // will if none found } @@ -646,7 +647,7 @@ bool DCCEXParser::parseS(Print *stream, int params, int p[]) StringFormatter::send(stream, F("")); return true; - case 0: // list sensor states + case 0: // list sensor definitions if (Sensor::firstSensor == NULL) return false; for (Sensor *tt = Sensor::firstSensor; tt != NULL; tt = tt->nextSensor) diff --git a/Turnouts.cpp b/Turnouts.cpp index 45b3c1b..03093a1 100644 --- a/Turnouts.cpp +++ b/Turnouts.cpp @@ -21,10 +21,17 @@ #include "Turnouts.h" #include "EEStore.h" #include "PWMServoDriver.h" +#include "StringFormatter.h" #ifdef EESTOREDEBUG #include "DIAG.h" #endif +// print all turnout states to stream +void Turnout::printAll(Print *stream){ + for (Turnout *tt = Turnout::firstTurnout; tt != NULL; tt = tt->nextTurnout) + StringFormatter::send(stream, F(""), tt->data.id, (tt->data.tStatus & STATUS_ACTIVE)!=0); +} // Turnout::printAll + bool Turnout::activate(int n,bool state){ #ifdef EESTOREDEBUG DIAG(F("\nTurnout::activate(%d,%d)\n"),n,state); diff --git a/Turnouts.h b/Turnouts.h index 2aff97d..186149b 100644 --- a/Turnouts.h +++ b/Turnouts.h @@ -49,6 +49,7 @@ class Turnout { static Turnout *create(int id , byte pin , int activeAngle, int inactiveAngle); static Turnout *create(int id); void activate(bool state); + static void printAll(Print *); #ifdef EESTOREDEBUG void print(Turnout *tt); #endif From 0618a0bd72c974ecd130ad95ac3d9d6f3e45e212 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 5 Jan 2021 13:05:17 -0500 Subject: [PATCH 02/13] RMFT Hooks (#112) These hooks do NOT require RMFT code to be present.... but they offer the hooks that RMFT will need when available. authored-by: Asbelos --- CommandStation-EX.ino | 9 +++++++++ DCCEX.h | 6 +++++- DCCEXParser.cpp | 7 +++++++ DCCEXParser.h | 2 ++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index 8b75fc4..18f2aaa 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -53,6 +53,11 @@ void setup() // waveform generation. e.g. DCC::begin(STANDARD_MOTOR_SHIELD,2); to use timer 2 DCC::begin(MOTOR_SHIELD_TYPE); + + #if defined(RMFT_ACTIVE) + RMFT::begin(); + #endif + LCD(1,F("Ready")); } @@ -75,6 +80,10 @@ void loop() EthernetInterface::loop(); #endif +#if defined(RMFT_ACTIVE) + RMFT::loop(); +#endif + LCDDisplay::loop(); // ignored if LCD not in use // Optionally report any decrease in memory (will automatically trigger on first call) diff --git a/DCCEX.h b/DCCEX.h index d89d581..2d1d183 100644 --- a/DCCEX.h +++ b/DCCEX.h @@ -15,6 +15,10 @@ #endif #include "LCD_Implementation.h" #include "freeMemory.h" -#include +#if __has_include ( "myAutomation.h") + #include "RMFT.h" + #define RMFT_ACTIVE +#endif + #endif diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 753f69b..c488fc1 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -221,11 +221,16 @@ int DCCEXParser::splitHexValues(int result[MAX_PARAMS], const byte *cmd) } FILTER_CALLBACK DCCEXParser::filterCallback = 0; +FILTER_CALLBACK DCCEXParser::filterRMFTCallback = 0; AT_COMMAND_CALLBACK DCCEXParser::atCommandCallback = 0; void DCCEXParser::setFilter(FILTER_CALLBACK filter) { filterCallback = filter; } +void DCCEXParser::setRMFTFilter(FILTER_CALLBACK filter) +{ + filterRMFTCallback = filter; +} void DCCEXParser::setAtCommandCallback(AT_COMMAND_CALLBACK callback) { atCommandCallback = callback; @@ -245,6 +250,8 @@ void DCCEXParser::parse(Print *stream, byte *com, bool blocking) if (filterCallback) filterCallback(stream, opcode, params, p); + if (filterRMFTCallback && opcode!='\0') + filterRMFTCallback(stream, opcode, params, p); // Functions return from this switch if complete, break from switch implies error to send switch (opcode) diff --git a/DCCEXParser.h b/DCCEXParser.h index ec0286d..bef1199 100644 --- a/DCCEXParser.h +++ b/DCCEXParser.h @@ -30,6 +30,7 @@ struct DCCEXParser void parse(Print * stream, byte * command, bool blocking); void flush(); static void setFilter(FILTER_CALLBACK filter); + static void setRMFTFilter(FILTER_CALLBACK filter); static void setAtCommandCallback(AT_COMMAND_CALLBACK filter); static const int MAX_PARAMS=10; // Must not exceed this @@ -61,6 +62,7 @@ struct DCCEXParser static void callback_Vbit(int result); static void callback_Vbyte(int result); static FILTER_CALLBACK filterCallback; + static FILTER_CALLBACK filterRMFTCallback; static AT_COMMAND_CALLBACK atCommandCallback; static void funcmap(int cab, byte value, byte fstart, byte fstop); From 895b2aaaaaee935b92fef5d41c0487dfa6db9fd2 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 7 Jan 2021 20:58:23 +0000 Subject: [PATCH 03/13] Implement mySetup.h facility --- CommandStation-EX.ino | 10 ++++++++-- DCCEXParser.cpp | 8 ++++++++ DCCEXParser.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index 18f2aaa..c0c3a1d 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -53,11 +53,17 @@ void setup() // waveform generation. e.g. DCC::begin(STANDARD_MOTOR_SHIELD,2); to use timer 2 DCC::begin(MOTOR_SHIELD_TYPE); - + #if defined(RMFT_ACTIVE) RMFT::begin(); #endif - + + #if __has_include ( "mySetup.h") + #define SETUP(cmd) serialParser.parse(F(cmd)) + #include "mySetup.h" + #undef SETUP + #endif + LCD(1,F("Ready")); } diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index c488fc1..59d0b74 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -236,6 +236,14 @@ void DCCEXParser::setAtCommandCallback(AT_COMMAND_CALLBACK 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 void DCCEXParser::parse(Print *stream, byte *com, bool blocking) { diff --git a/DCCEXParser.h b/DCCEXParser.h index bef1199..d2423d0 100644 --- a/DCCEXParser.h +++ b/DCCEXParser.h @@ -28,6 +28,7 @@ struct DCCEXParser DCCEXParser(); void loop(Stream & stream); void parse(Print * stream, byte * command, bool blocking); + void parse(const __FlashStringHelper * cmd); void flush(); static void setFilter(FILTER_CALLBACK filter); static void setRMFTFilter(FILTER_CALLBACK filter); From 418d8eb1b2e17ebc0a5623747612d5bd5fa5ccc9 Mon Sep 17 00:00:00 2001 From: mstevetodd Date: Fri, 8 Jan 2021 16:57:32 -0500 Subject: [PATCH 04/13] send milliAmps and meter setup for new JMRI Meter function (#113) * send milliAmps and meter setup for new JMRI Meter function --- DCCEXParser.cpp | 5 ++++- DCCWaveform.h | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index c488fc1..fd1cea0 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -442,7 +442,10 @@ void DCCEXParser::parse(Print *stream, byte *com, bool blocking) return; case 'c': // READ CURRENT - StringFormatter::send(stream, F(""), DCCWaveform::mainTrack.get1024Current()); + // + StringFormatter::send(stream, F(""), DCCWaveform::mainTrack.getCurrentmA(), DCCWaveform::mainTrack.getMaxmA()); + // StringFormatter::send(stream, F(""), DCCWaveform::progTrack.getCurrentmA(), DCCWaveform::progTrack.getMaxmA()); + StringFormatter::send(stream, F(""), DCCWaveform::mainTrack.get1024Current()); //'a' message deprecated, remove once JMRI 4.22 is available return; case 'Q': // SENSORS diff --git a/DCCWaveform.h b/DCCWaveform.h index b51e79f..3755979 100644 --- a/DCCWaveform.h +++ b/DCCWaveform.h @@ -58,9 +58,20 @@ class DCCWaveform { void checkPowerOverload(); int getLastCurrent(); inline int get1024Current() { - if (powerMode == POWERMODE::ON) - return (int)(lastCurrent*(long int)1024/motorDriver->getRawCurrentTripValue()); - return 0; + if (powerMode == POWERMODE::ON) + return (int)(lastCurrent*(long int)1024/motorDriver->getRawCurrentTripValue()); + return 0; + } + inline int getCurrentmA() { + if (powerMode == POWERMODE::ON) + return motorDriver->raw2mA(lastCurrent); + return 0; + } + inline int getMaxmA() { + if (maxmA == 0) { //only calculate this for first request, it doesn't change + maxmA = motorDriver->raw2mA(motorDriver->getRawCurrentTripValue()); + } + return maxmA; } void schedulePacket(const byte buffer[], byte byteCount, byte repeats); volatile bool packetPending; @@ -112,7 +123,7 @@ class DCCWaveform { byte pendingLength; byte pendingRepeats; int lastCurrent; - + int maxmA; // current sampling POWERMODE powerMode; From 7b4e5546b6b6e1c20060389fb2dc3e9c1b8ff9bf Mon Sep 17 00:00:00 2001 From: Fred Date: Fri, 8 Jan 2021 16:58:22 -0500 Subject: [PATCH 05/13] Update version.h --- version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.h b/version.h index e60dd91..43f4764 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,7 @@ #include "StringFormatter.h" // const char VERSION[] PROGMEM ="0.2.0"; -#define VERSION "3.0.1" +#define VERSION "3.0.2" #endif From 82a4b4880892a6a0c91d40a5a662f1b838149d41 Mon Sep 17 00:00:00 2001 From: Fred Date: Fri, 8 Jan 2021 17:03:43 -0500 Subject: [PATCH 06/13] Update Prod-Release-Notes.md --- Release - Architecture Doc/Prod-Release-Notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Release - Architecture Doc/Prod-Release-Notes.md b/Release - Architecture Doc/Prod-Release-Notes.md index 1a04b09..eeaa466 100644 --- a/Release - Architecture Doc/Prod-Release-Notes.md +++ b/Release - Architecture Doc/Prod-Release-Notes.md @@ -4,6 +4,10 @@ The DCC-EX Team is pleased to release CommandStation-EX-v3.0.0 as a Production R - **Consisting through JMRI** - currently does not work in this release. A number of testers were able to develop a work around. If interested enter a Support Ticket. - **Wi-Fi** - works, but can be challenging to use if you want to switch between AP mode and STA station mode. - **Pololu Motor Shield** - is supported with this release, but the user may have to play around with some timings to enable programming mode due to limitation in its current sensing circuitry + +**Summary of the key new features added to CommandStation-EX V3.0.2:** +- **Create new output for current in mA for ```` command** - New current response outputs current in mA, overlimit current, and maximum board capable current +- **Simultaneously update JMRI to handle new current meter** **Summary of the key new features added to CommandStation-EX V3.0.1:** - **Add back fix for jitter** From b537d7a31849f091b18c70c0b6c226b2c5271306 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 17 Jan 2021 13:22:16 +0000 Subject: [PATCH 07/13] command consist support R command will return address suitable for throttle if consist has been setup. --- DCC.cpp | 42 +++++++++++++++++++++++++++++++++++++++--- DCC.h | 2 ++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index 96868ca..421dd9b 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -331,10 +331,31 @@ const ackOp PROGMEM READ_CV_PROG[] = { const ackOp PROGMEM LOCO_ID_PROG[] = { 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, 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, @@ -366,7 +387,7 @@ const ackOp PROGMEM LOCO_ID_PROG[] = { SKIPTARGET, SETCV, (ackOp)1, 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, @@ -668,7 +689,15 @@ void DCC::ackManagerLoop(bool blocking) { case ITCB: // If True callback(byte) if (ackReceived) { 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; } break; @@ -708,6 +737,11 @@ void DCC::ackManagerLoop(bool blocking) { ackManagerCv=pgm_read_byte_near(ackManagerProg); break; + case SETBYTE: + ackManagerProg++; + ackManagerByte=pgm_read_byte_near(ackManagerProg); + break; + case STASHLOCOID: ackManagerStash=ackManagerByte; // stash value from CV17 break; @@ -724,6 +758,8 @@ void DCC::ackManagerLoop(bool blocking) { while (opcode!=SKIPTARGET) { 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; case SKIPTARGET: diff --git a/DCC.h b/DCC.h index 122e934..d7430c6 100644 --- a/DCC.h +++ b/DCC.h @@ -37,12 +37,14 @@ enum ackOp ITC1, // If True Callback(1) (if prevous WACK got an ACK) ITC0, // If True callback(0); ITCB, // If True callback(byte) + ITCB7, // If True callback(byte &0x7F) NAKFAIL, // if false callback(-1) FAIL, // callback(-1) 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) SETBIT, // sets bit number to next prog byte SETCV, // sets cv number to next prog byte + SETBYTE, // sets current byte to next prog 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 From 7d90e4241a3e27f6348a9f7a0fa9eaa3ed711d6b Mon Sep 17 00:00:00 2001 From: Asbelos Date: Mon, 18 Jan 2021 10:06:46 +0000 Subject: [PATCH 08/13] Add command Automatically clears consist and manages short/long addresses --- DCC.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++- DCC.h | 5 ++++ DCCEXParser.cpp | 18 ++++++++++---- DCCEXParser.h | 1 + 4 files changed, 82 insertions(+), 5 deletions(-) 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; From 611838d60c8503dfe5c11e5b2c2e8f83d35da219 Mon Sep 17 00:00:00 2001 From: mstevetodd Date: Mon, 18 Jan 2021 17:46:41 -0500 Subject: [PATCH 09/13] add warn/trip level to meter response (#120) * send milliAmps and meter setup for new JMRI Meter function * add warn/trip level to meter response provides support for separate max vs trip levels --- DCCEXParser.cpp | 8 ++++---- DCCWaveform.h | 9 ++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index fd1cea0..3ecdb61 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -441,10 +441,10 @@ void DCCEXParser::parse(Print *stream, byte *com, bool blocking) } return; - case 'c': // READ CURRENT - // - StringFormatter::send(stream, F(""), DCCWaveform::mainTrack.getCurrentmA(), DCCWaveform::mainTrack.getMaxmA()); - // StringFormatter::send(stream, F(""), DCCWaveform::progTrack.getCurrentmA(), DCCWaveform::progTrack.getMaxmA()); + case 'c': // SEND METER RESPONSES + // + StringFormatter::send(stream, F(""), DCCWaveform::mainTrack.getCurrentmA(), + DCCWaveform::mainTrack.getMaxmA(), DCCWaveform::mainTrack.getTripmA()); StringFormatter::send(stream, F(""), DCCWaveform::mainTrack.get1024Current()); //'a' message deprecated, remove once JMRI 4.22 is available return; diff --git a/DCCWaveform.h b/DCCWaveform.h index 3755979..7908e02 100644 --- a/DCCWaveform.h +++ b/DCCWaveform.h @@ -69,10 +69,16 @@ class DCCWaveform { } inline int getMaxmA() { if (maxmA == 0) { //only calculate this for first request, it doesn't change - maxmA = motorDriver->raw2mA(motorDriver->getRawCurrentTripValue()); + maxmA = motorDriver->raw2mA(motorDriver->getRawCurrentTripValue()); //TODO: replace with actual max value or calc } return maxmA; } + inline int getTripmA() { + if (tripmA == 0) { //only calculate this for first request, it doesn't change + tripmA = motorDriver->raw2mA(motorDriver->getRawCurrentTripValue()); + } + return tripmA; + } void schedulePacket(const byte buffer[], byte byteCount, byte repeats); volatile bool packetPending; volatile byte sentResetsSincePacket; @@ -124,6 +130,7 @@ class DCCWaveform { byte pendingRepeats; int lastCurrent; int maxmA; + int tripmA; // current sampling POWERMODE powerMode; From 2ce4c8066e49c6bbbc5073db480c860644d00736 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 21 Jan 2021 11:10:52 +0000 Subject: [PATCH 10/13] Update version.h --- version.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/version.h b/version.h index 43f4764..e47b1ec 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,10 @@ #include "StringFormatter.h" // const char VERSION[] PROGMEM ="0.2.0"; -#define VERSION "3.0.2" - +#define VERSION "3.0.3" +// 3.0.3 Includes: +// command to write loco address and clear consist +// command will allow for consist address +// Startup commands implemented #endif From 7c7305ba1d3846cd32bdb6cb7e66db09cf5a3767 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 21 Jan 2021 10:08:35 -0500 Subject: [PATCH 11/13] Update Prod-Release-Notes.md --- Release - Architecture Doc/Prod-Release-Notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Release - Architecture Doc/Prod-Release-Notes.md b/Release - Architecture Doc/Prod-Release-Notes.md index eeaa466..e0c89c4 100644 --- a/Release - Architecture Doc/Prod-Release-Notes.md +++ b/Release - Architecture Doc/Prod-Release-Notes.md @@ -4,6 +4,10 @@ The DCC-EX Team is pleased to release CommandStation-EX-v3.0.0 as a Production R - **Consisting through JMRI** - currently does not work in this release. A number of testers were able to develop a work around. If interested enter a Support Ticket. - **Wi-Fi** - works, but can be challenging to use if you want to switch between AP mode and STA station mode. - **Pololu Motor Shield** - is supported with this release, but the user may have to play around with some timings to enable programming mode due to limitation in its current sensing circuitry +**Summary of the key new features added to CommandStation-EX V3.0.3** + - ** command to write loco address and clear consist** + - ** command will allow for consist address** + - **Startup commands implemented** **Summary of the key new features added to CommandStation-EX V3.0.2:** - **Create new output for current in mA for ```` command** - New current response outputs current in mA, overlimit current, and maximum board capable current From a91dc981841e48bd6b5ffb846108d41b265e4ec4 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 21 Jan 2021 10:13:38 -0500 Subject: [PATCH 12/13] Update Prod-Release-Notes.md --- Release - Architecture Doc/Prod-Release-Notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Release - Architecture Doc/Prod-Release-Notes.md b/Release - Architecture Doc/Prod-Release-Notes.md index e0c89c4..35e8f4b 100644 --- a/Release - Architecture Doc/Prod-Release-Notes.md +++ b/Release - Architecture Doc/Prod-Release-Notes.md @@ -4,6 +4,7 @@ The DCC-EX Team is pleased to release CommandStation-EX-v3.0.0 as a Production R - **Consisting through JMRI** - currently does not work in this release. A number of testers were able to develop a work around. If interested enter a Support Ticket. - **Wi-Fi** - works, but can be challenging to use if you want to switch between AP mode and STA station mode. - **Pololu Motor Shield** - is supported with this release, but the user may have to play around with some timings to enable programming mode due to limitation in its current sensing circuitry + **Summary of the key new features added to CommandStation-EX V3.0.3** - ** command to write loco address and clear consist** - ** command will allow for consist address** From f646f12c655801e208abbae70c7dd9c3454d87f2 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 21 Jan 2021 10:19:34 -0500 Subject: [PATCH 13/13] Update Prod-Release-Notes.md --- Release - Architecture Doc/Prod-Release-Notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release - Architecture Doc/Prod-Release-Notes.md b/Release - Architecture Doc/Prod-Release-Notes.md index 35e8f4b..0893e1a 100644 --- a/Release - Architecture Doc/Prod-Release-Notes.md +++ b/Release - Architecture Doc/Prod-Release-Notes.md @@ -1,7 +1,7 @@ The DCC-EX Team is pleased to release CommandStation-EX-v3.0.0 as a Production Release. This release is a major re-write of earlier versions. We've re-architected the code-base so that it can better handle new features going forward. **Known Bugs:** - - **Consisting through JMRI** - currently does not work in this release. A number of testers were able to develop a work around. If interested enter a Support Ticket. + - **Consisting through JMRI** - currently does not work in this release. You may use the command to do this manually. - **Wi-Fi** - works, but can be challenging to use if you want to switch between AP mode and STA station mode. - **Pololu Motor Shield** - is supported with this release, but the user may have to play around with some timings to enable programming mode due to limitation in its current sensing circuitry