diff --git a/DCCACK.cpp b/DCCACK.cpp
index 1b339ee..8a074b4 100644
--- a/DCCACK.cpp
+++ b/DCCACK.cpp
@@ -351,7 +351,7 @@ void DCCACK::callback(int value) {
switch (callbackState) {
case AFTER_READ:
- if (ackManagerRejoin && autoPowerOff) {
+ if (ackManagerRejoin && !autoPowerOff) {
progDriver->setPower(POWERMODE::OFF);
callbackStart=millis();
callbackState=WAITING_30;
diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp
index aaf733c..53cb5ce 100644
--- a/DCCEXParser.cpp
+++ b/DCCEXParser.cpp
@@ -25,6 +25,79 @@
* You should have received a copy of the GNU General Public License
* along with CommandStation. If not, see .
*/
+
+/*
+List of single character OPCODEs in use for reference.
+
+When determining a new OPCODE for a new feature, refer to this list as the source of truth.
+
+Once a new OPCODE is decided upon, update this list.
+
+ Character, Usage
+ /, |EX-R| interactive commands
+ -, Remove from reminder table
+ =, |TM| configuration
+ !, Emergency stop
+ @, Reserved for future use - LCD messages to JMRI
+ #, Request number of supported cabs/locos; heartbeat
+ +, WiFi AT commands
+ ?, Reserved for future use
+ 0, Track power off
+ 1, Track power on
+ a, DCC accessory control
+ A,
+ b, Write CV bit on main
+ B, Write CV bit
+ c, Request current command
+ C,
+ d,
+ D, Diagnostic commands
+ e, Erase EEPROM
+ E, Store configuration in EEPROM
+ f, Loco decoder function control (deprecated)
+ F, Loco decoder function control
+ g,
+ G,
+ h,
+ H, Turnout state broadcast
+ i, Reserved for future use - Turntable object broadcast
+ I, Reserved for future use - Turntable object command and control
+ j, Throttle responses
+ J, Throttle queries
+ k, Reserved for future use - Potentially Railcom
+ K, Reserved for future use - Potentially Railcom
+ l, Loco speedbyte/function map broadcast
+ L,
+ m,
+ M, Write DCC packet
+ n,
+ N,
+ o,
+ O, Output broadcast
+ p, Broadcast power state
+ P, Write DCC packet
+ q, Sensor deactivated
+ Q, Sensor activated
+ r, Broadcast address read on programming track
+ R, Read CVs
+ s, Display status
+ S, Sensor configuration
+ t, Cab/loco update command
+ T, Turnout configuration/control
+ u, Reserved for user commands
+ U, Reserved for user commands
+ v,
+ V, Verify CVs
+ w, Write CV on main
+ W, Write CV
+ x,
+ X, Invalid command
+ y,
+ Y, Output broadcast
+ z,
+ Z, Output configuration/control
+*/
+
#include "StringFormatter.h"
#include "DCCEXParser.h"
#include "DCC.h"
@@ -378,12 +451,16 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
#ifndef DISABLE_PROG
case 'w': // WRITE CV on MAIN
- DCC::writeCVByteMain(p[0], p[1], p[2]);
- return;
+ if (params != 3)
+ break;
+ DCC::writeCVByteMain(p[0], p[1], p[2]);
+ return;
case 'b': // WRITE CV BIT ON MAIN
- DCC::writeCVBitMain(p[0], p[1], p[2], p[3]);
- return;
+ if (params != 4)
+ break;
+ DCC::writeCVBitMain(p[0], p[1], p[2], p[3]);
+ return;
#endif
case 'M': // WRITE TRANSPARENT DCC PACKET MAIN
@@ -406,14 +483,16 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
#ifndef DISABLE_PROG
case 'W': // WRITE CV ON PROG
- if (!stashCallback(stream, p, ringStream))
- break;
+ if (!stashCallback(stream, p, ringStream))
+ break;
if (params == 1) // Write new loco id (clearing consist and managing short/long)
DCC::setLocoId(p[0],callback_Wloco);
else if (params == 4) // WRITE CV ON PROG
DCC::writeCVByte(p[0], p[1], callback_W4);
- else // WRITE CV ON PROG
+ else if (params == 2) // WRITE CV ON PROG
DCC::writeCVByte(p[0], p[1], callback_W);
+ else
+ break;
return;
case 'V': // VERIFY CV ON PROG
@@ -433,9 +512,11 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
}
break;
- case 'B': // WRITE CV BIT ON PROG
+ case 'B': // WRITE CV BIT ON PROG or
+ if (params != 3 && params != 5)
+ break;
if (!stashCallback(stream, p, ringStream))
- break;
+ break;
DCC::writeCVBit(p[0], p[1], p[2], callback_B);
return;
@@ -565,12 +646,12 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
case ' ': // < >
StringFormatter::send(stream, F("\n"));
return;
-
+#ifndef DISABLE_DIAG
case 'D': // < >
if (parseD(stream, params, p))
return;
- return;
-
+ break;
+#endif
case '=': // <= Track manager control >
if (TrackManager::parseJ(stream, params, p))
return;
diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp
index 95ba6a2..e5509b9 100644
--- a/EXRAIL2.cpp
+++ b/EXRAIL2.cpp
@@ -2,7 +2,7 @@
* © 2021 Neil McKechnie
* © 2021-2023 Harald Barth
* © 2020-2023 Chris Harlow
- * © 2022 Colin Murdoch
+ * © 2022-2023 Colin Murdoch
* All rights reserved.
*
* This file is part of CommandStation-EX
@@ -97,6 +97,7 @@ LookList * RMFT2::onAmberLookup=NULL;
LookList * RMFT2::onGreenLookup=NULL;
LookList * RMFT2::onChangeLookup=NULL;
LookList * RMFT2::onClockLookup=NULL;
+LookList * RMFT2::onOverloadLookup=NULL;
#define GET_OPCODE GETHIGHFLASH(RMFT2::RouteCode,progCounter)
#define SKIPOP progCounter+=3
@@ -178,6 +179,7 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
onGreenLookup=LookListLoader(OPCODE_ONGREEN);
onChangeLookup=LookListLoader(OPCODE_ONCHANGE);
onClockLookup=LookListLoader(OPCODE_ONTIME);
+ onOverloadLookup=LookListLoader(OPCODE_ONOVERLOAD);
// Second pass startup, define any turnouts or servos, set signals red
@@ -198,6 +200,7 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
case OPCODE_AT:
case OPCODE_ATTIMEOUT2:
case OPCODE_AFTER:
+ case OPCODE_AFTEROVERLOAD:
case OPCODE_IF:
case OPCODE_IFNOT: {
int16_t pin = (int16_t)operand;
@@ -734,7 +737,17 @@ void RMFT2::loop2() {
}
if (millis()-waitAfter < 500 ) return;
break;
-
+
+ case OPCODE_AFTEROVERLOAD: // waits for the power to be turned back on - either by power routine or button
+ if (!TrackManager::isPowerOn(operand)) {
+ // reset timer to half a second and keep waiting
+ waitAfter=millis();
+ delayMe(50);
+ return;
+ }
+ if (millis()-waitAfter < 500 ) return;
+ break;
+
case OPCODE_LATCH:
setFlag(operand,LATCH_FLAG);
break;
@@ -1040,6 +1053,7 @@ void RMFT2::loop2() {
case OPCODE_ONGREEN:
case OPCODE_ONCHANGE:
case OPCODE_ONTIME:
+ case OPCODE_ONOVERLOAD:
break;
@@ -1194,6 +1208,16 @@ void RMFT2::clockEvent(int16_t clocktime, bool change) {
}
}
+void RMFT2::powerEvent(int16_t track, bool overload) {
+ // Hunt for an ONOVERLOAD for this item
+ if (Diag::CMD)
+ DIAG(F("Looking for Power event on track : %c"), track);
+ if (overload) {
+ handleEvent(F("POWER"),onOverloadLookup,track);
+ }
+}
+
+
void RMFT2::handleEvent(const FSH* reason,LookList* handlers, int16_t id) {
int pc= handlers->find(id);
if (pc<0) return;
diff --git a/EXRAIL2.h b/EXRAIL2.h
index 0cc995d..f43d7d4 100644
--- a/EXRAIL2.h
+++ b/EXRAIL2.h
@@ -1,7 +1,7 @@
/*
* © 2021 Neil McKechnie
* © 2020-2022 Chris Harlow
- * © 2022 Colin Murdoch
+ * © 2022-2023 Colin Murdoch
* © 2023 Harald Barth
* All rights reserved.
*
@@ -35,7 +35,8 @@
enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
OPCODE_FWD,OPCODE_REV,OPCODE_SPEED,OPCODE_INVERT_DIRECTION,
OPCODE_RESERVE,OPCODE_FREE,
- OPCODE_AT,OPCODE_AFTER,OPCODE_AUTOSTART,
+ OPCODE_AT,OPCODE_AFTER,
+ OPCODE_AFTEROVERLOAD,OPCODE_AUTOSTART,
OPCODE_ATGTE,OPCODE_ATLT,
OPCODE_ATTIMEOUT1,OPCODE_ATTIMEOUT2,
OPCODE_LATCH,OPCODE_UNLATCH,OPCODE_SET,OPCODE_RESET,
@@ -63,6 +64,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
OPCODE_ONCLOCKTIME,
OPCODE_ONTIME,
OPCODE_LCC,OPCODE_ONLCC,
+ OPCODE_ONOVERLOAD,
// OPcodes below this point are skip-nesting IF operations
// placed here so that they may be skipped as a group
@@ -131,6 +133,7 @@ class LookList {
static void activateEvent(int16_t addr, bool active);
static void changeEvent(int16_t id, bool change);
static void clockEvent(int16_t clocktime, bool change);
+ static void powerEvent(int16_t track, bool overload);
static const int16_t SERVO_SIGNAL_FLAG=0x4000;
static const int16_t ACTIVE_HIGH_SIGNAL_FLAG=0x2000;
static const int16_t DCC_SIGNAL_FLAG=0x1000;
@@ -190,6 +193,8 @@ private:
static LookList * onGreenLookup;
static LookList * onChangeLookup;
static LookList * onClockLookup;
+ static LookList * onOverloadLookup;
+
static const int countLCCLookup;
static int onLCCLookup[];
diff --git a/EXRAIL2MacroReset.h b/EXRAIL2MacroReset.h
index 9ea1a36..a952d90 100644
--- a/EXRAIL2MacroReset.h
+++ b/EXRAIL2MacroReset.h
@@ -1,6 +1,6 @@
/*
* © 2020-2022 Chris Harlow. All rights reserved.
- * © 2022 Colin Murdoch
+ * © 2022-2023 Colin Murdoch
* © 2023 Harald Barth
*
* This file is part of CommandStation-EX
@@ -27,6 +27,7 @@
#undef ACTIVATE
#undef ACTIVATEL
#undef AFTER
+#undef AFTEROVERLOAD
#undef ALIAS
#undef AMBER
#undef ANOUT
@@ -95,6 +96,7 @@
#undef ONTIME
#undef ONCLOCKTIME
#undef ONCLOCKMINS
+#undef ONOVERLOAD
#undef ONGREEN
#undef ONRED
#undef ONTHROW
@@ -154,6 +156,7 @@
#define ACTIVATE(addr,subaddr)
#define ACTIVATEL(addr)
#define AFTER(sensor_id)
+#define AFTEROVERLOAD(track_id)
#define ALIAS(name,value...)
#define AMBER(signal_id)
#define ANOUT(vpin,value,param1,param2)
@@ -218,6 +221,7 @@
#define ONTIME(value)
#define ONCLOCKTIME(hours,mins)
#define ONCLOCKMINS(mins)
+#define ONOVERLOAD(track_id)
#define ONDEACTIVATE(addr,subaddr)
#define ONDEACTIVATEL(linear)
#define ONCLOSE(turnout_id)
diff --git a/EXRAILMacros.h b/EXRAILMacros.h
index 18abf7a..0127610 100644
--- a/EXRAILMacros.h
+++ b/EXRAILMacros.h
@@ -1,7 +1,7 @@
/*
* © 2021 Neil McKechnie
* © 2020-2022 Chris Harlow
- * © 2022 Colin Murdoch
+ * © 2022-2023 Colin Murdoch
* © 2023 Harald Barth
* All rights reserved.
*
@@ -266,6 +266,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
#define ACTIVATE(addr,subaddr) OPCODE_DCCACTIVATE,V(addr<<3 | subaddr<<1 | 1),
#define ACTIVATEL(addr) OPCODE_DCCACTIVATE,V((addr+3)<<1 | 1),
#define AFTER(sensor_id) OPCODE_AT,V(sensor_id),OPCODE_AFTER,V(sensor_id),
+#define AFTEROVERLOAD(track_id) OPCODE_AFTEROVERLOAD,V(TRACK_NUMBER_##track_id),
#define ALIAS(name,value...)
#define AMBER(signal_id) OPCODE_AMBER,V(signal_id),
#define ANOUT(vpin,value,param1,param2) OPCODE_SERVO,V(vpin),OPCODE_PAD,V(value),OPCODE_PAD,V(param1),OPCODE_PAD,V(param2),
@@ -335,6 +336,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
#define ONTIME(value) OPCODE_ONTIME,V(value),
#define ONCLOCKTIME(hours,mins) OPCODE_ONTIME,V((STRIP_ZERO(hours)*60)+STRIP_ZERO(mins)),
#define ONCLOCKMINS(mins) ONCLOCKTIME(25,mins)
+#define ONOVERLOAD(track_id) OPCODE_ONOVERLOAD,V(TRACK_NUMBER_##track_id),
#define ONDEACTIVATE(addr,subaddr) OPCODE_ONDEACTIVATE,V(addr<<2|subaddr),
#define ONDEACTIVATEL(linear) OPCODE_ONDEACTIVATE,V(linear+3),
#define ONGREEN(signal_id) OPCODE_ONGREEN,V(signal_id),
diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h
index ae005b5..98afa03 100644
--- a/GITHUB_SHA.h
+++ b/GITHUB_SHA.h
@@ -1 +1 @@
-#define GITHUB_SHA "3bddf4d"
+#define GITHUB_SHA "devel-202308302157Z"
diff --git a/IODevice.h b/IODevice.h
index 769e111..4eb24e5 100644
--- a/IODevice.h
+++ b/IODevice.h
@@ -29,8 +29,13 @@
// Define symbol IO_NO_HAL to reduce FLASH footprint when HAL features not required
// The HAL is disabled by default on Nano and Uno platforms, because of limited flash space.
-#if defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_UNO)
-#define IO_NO_HAL
+#include "defines.h"
+#if defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_UNO)
+ #if defined(DISABLE_DIAG) && defined(DISABLE_EEPROM) && defined(DISABLE_PROG)
+ #warning you have sacrificed DIAG for HAL
+ #else
+ #define IO_NO_HAL
+ #endif
#endif
// Define symbol IO_SWITCH_OFF_SERVO to set the PCA9685 output to 0 when an
diff --git a/IO_PCA9555.h b/IO_PCA9555.h
index 137e287..e493165 100644
--- a/IO_PCA9555.h
+++ b/IO_PCA9555.h
@@ -30,8 +30,8 @@
class PCA9555 : public GPIOBase {
public:
- static void create(VPIN vpin, int nPins, uint8_t I2CAddress, int interruptPin=-1) {
- new PCA9555(vpin, min(nPins,16), I2CAddress, interruptPin);
+ static void create(VPIN vpin, uint8_t nPins, I2CAddress i2cAddress, int interruptPin=-1) {
+ if (checkNoOverlap(vpin, nPins, i2cAddress)) new PCA9555(vpin,nPins, i2cAddress, interruptPin);
}
// Constructor
diff --git a/MotorDriver.cpp b/MotorDriver.cpp
index d5dca13..4644ad5 100644
--- a/MotorDriver.cpp
+++ b/MotorDriver.cpp
@@ -4,6 +4,7 @@
* © 2021 Fred Decker
* © 2020-2023 Harald Barth
* © 2020-2021 Chris Harlow
+ * © 2023 Colin Murdoch
* All rights reserved.
*
* This file is part of CommandStation-EX
@@ -26,6 +27,7 @@
#include "DCCWaveform.h"
#include "DCCTimer.h"
#include "DIAG.h"
+#include "EXRAIL2.h"
unsigned long MotorDriver::globalOverloadStart = 0;
@@ -613,7 +615,9 @@ void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) {
// adjust next wait time
power_sample_overload_wait *= 2;
if (power_sample_overload_wait > POWER_SAMPLE_RETRY_MAX)
- power_sample_overload_wait = POWER_SAMPLE_RETRY_MAX;
+ power_sample_overload_wait = POWER_SAMPLE_RETRY_MAX;
+ DIAG(F("Calling EXRAIL"));
+ RMFT2::powerEvent(trackno, true); // Tell EXRAIL we have an overload
// power on test
DIAG(F("TRACK %c POWER RESTORE (after %4M)"), trackno + 'A', mslpc);
setPower(POWERMODE::ALERT);
diff --git a/TrackManager.cpp b/TrackManager.cpp
index 0f69235..bd7c623 100644
--- a/TrackManager.cpp
+++ b/TrackManager.cpp
@@ -1,6 +1,7 @@
/*
* © 2022 Chris Harlow
* © 2022 Harald Barth
+ * © 2023 Colin Murdoch
* All rights reserved.
*
* This file is part of DCC++EX
@@ -53,7 +54,7 @@ bool TrackManager::progTrackSyncMain=false;
bool TrackManager::progTrackBoosted=false;
int16_t TrackManager::joinRelay=UNUSED_PIN;
#ifdef ARDUINO_ARCH_ESP32
-byte TrackManager::tempProgTrack=MAX_TRACKS+1;
+byte TrackManager::tempProgTrack=MAX_TRACKS+1; // MAX_TRACKS+1 is the unused flag
#endif
#ifdef ANALOG_READ_INTERRUPT
@@ -505,7 +506,12 @@ void TrackManager::setJoin(bool joined) {
}
} else {
if (tempProgTrack != MAX_TRACKS+1) {
+ // as setTrackMode with TRACK_MODE_PROG defaults to
+ // power off, we will take the current power state
+ // of our track and then preserve that state.
+ POWERMODE tPTmode = track[tempProgTrack]->getPower(); //get current power status of this track
setTrackMode(tempProgTrack, TRACK_MODE_PROG);
+ track[tempProgTrack]->setPower(tPTmode); //set track status as it was before
tempProgTrack = MAX_TRACKS+1;
}
}
@@ -513,3 +519,10 @@ void TrackManager::setJoin(bool joined) {
progTrackSyncMain=joined;
if (joinRelay!=UNUSED_PIN) digitalWrite(joinRelay,joined?HIGH:LOW);
}
+
+bool TrackManager::isPowerOn(byte t) {
+ if (track[t]->getPower()!=POWERMODE::ON)
+ return false;
+ return true;
+ }
+
diff --git a/TrackManager.h b/TrackManager.h
index 965cfa3..60d5f24 100644
--- a/TrackManager.h
+++ b/TrackManager.h
@@ -1,6 +1,8 @@
/*
* © 2022 Chris Harlow
* © 2022 Harald Barth
+ * © 2023 Colin Murdoch
+ *
* All rights reserved.
*
* This file is part of CommandStation-EX
@@ -77,6 +79,7 @@ class TrackManager {
static void reportCurrent(Print* stream);
static void reportObsoleteCurrent(Print* stream);
static void streamTrackState(Print* stream, byte t);
+ static bool isPowerOn(byte t);
static int16_t joinRelay;
static bool progTrackSyncMain; // true when prog track is a siding switched to main
diff --git a/WifiInterface.cpp b/WifiInterface.cpp
index 7511af6..ab36957 100644
--- a/WifiInterface.cpp
+++ b/WifiInterface.cpp
@@ -200,7 +200,21 @@ wifiSerialState WifiInterface::setup2(const FSH* SSid, const FSH* password,
// Display the AT version information
StringFormatter::send(wifiStream, F("AT+GMR\r\n"));
- checkForOK(2000, true, false); // Makes this visible on the console
+ if (checkForOK(2000, F("AT version:"), true, false)) {
+ char version[] = "0.0.0.0";
+ for (int i=0; i<8;i++) {
+ while(!wifiStream->available());
+ version[i]=wifiStream->read();
+ StringFormatter::printEscape(version[i]);
+ if ((version[0] == '0') ||
+ (version[0] == '2' && version[2] == '0') ||
+ (version[0] == '2' && version[2] == '2' && version[4] == '0' && version[6] == '0')) {
+ SSid = F("DCCEX_SAYS_BROKEN_FIRMWARE");
+ forceAP = true;
+ }
+ }
+ }
+ checkForOK(2000, true, false);
#ifdef DONT_TOUCH_WIFI_CONF
DIAG(F("DONT_TOUCH_WIFI_CONF was set: Using existing config"));
diff --git a/myHal.cpp_example.txt b/myHal.cpp_example.txt
index d93ea5c..5e9fec4 100644
--- a/myHal.cpp_example.txt
+++ b/myHal.cpp_example.txt
@@ -51,7 +51,7 @@ void halSetup() {
// Create a 20x4 LCD display device as display number 2
// (line 0 is written by EX-RAIL 'SCREEN(2, 0, "text")').
- // HALDisplay(2, 0x27, 20, 4);
+ // HALDisplay::create(2, 0x27, 20, 4);
//=======================================================================
diff --git a/version.h b/version.h
index 449b18e..881e992 100644
--- a/version.h
+++ b/version.h
@@ -3,7 +3,7 @@
#include "StringFormatter.h"
-#define VERSION "5.0.1LCC"
+#define VERSION "5.1.5LCC"
// 5.0.0 - Make 4.2.69 the 5.0.0 release
// 4.2.69 - Bugfix: Make work in DC mode
// 4.2.68 - Rename track mode OFF to NONE