1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-03-15 10:33:07 +01:00

Compare commits

..

31 Commits

Author SHA1 Message Date
Kcsmith0708
136f716be5
Merge 50bf1789f7 into d705626f4a 2024-07-01 16:35:53 +01:00
Ash-4
d705626f4a
<0 PROG> updated to undo JOIN
Update of the commit message for 5.2.64
2024-06-30 21:29:34 -05:00
Ash-4
c97284c15f inrush overfault on stm32EC-Ash 2024-06-30 20:32:08 -05:00
pmantoine
df1f365c1e Add WIFI_LED option for ESP32, edits for config.example.h 2024-06-29 16:22:23 +08:00
Harald Barth
023c004842 version 5.2.62 2024-06-18 22:21:51 +02:00
Harald Barth
2481f1c5d6 Allow acks longer than 65535us and specify ack length in the <C ACK MAX 20 MS> format 2024-06-18 22:18:23 +02:00
Asbelos
7dadecb5df Typo in KeywordHasher 2024-06-13 16:09:28 +01:00
Asbelos
6ef312b510 5.2.61 2024-06-13 13:08:40 +01:00
Asbelos
97f9fb4813 Squashed commit of the following:
commit a2b3ee8b5d52c2eefa461ace8f95c7f782a58efc
Merge: fc1217b 3d6c935
Author: Asbelos <asbelos@btinternet.com>
Date:   Thu Jun 13 11:58:00 2024 +0100

    Merge branch 'devel' into devel_merg

commit fc1217b8fa27a83174a4cf3bb82666f075103637
Author: Asbelos <asbelos@btinternet.com>
Date:   Thu Jun 13 11:57:12 2024 +0100

    Update EXRAIL2Parser.cpp

commit b89508671c
Author: Asbelos <asbelos@btinternet.com>
Date:   Wed Jun 12 16:25:17 2024 +0100

    Separate <L> polling cycle

commit 9f1257bc6c
Merge: a2fb585 5f65fd5
Author: Asbelos <asbelos@btinternet.com>
Date:   Wed Jun 12 10:57:09 2024 +0100

    Merge branch 'devel' into devel_merg

commit a2fb58584f
Author: Asbelos <asbelos@btinternet.com>
Date:   Fri May 31 19:49:39 2024 +0100

    ACON/ACOF 32 bit + 1=OFF

commit fca4ea052e
Author: Asbelos <asbelos@btinternet.com>
Date:   Fri May 31 12:09:38 2024 +0100

    Rename to ACON/ACOF terminology

commit 0d07aa6271
Author: Asbelos <asbelos@btinternet.com>
Date:   Thu May 30 19:59:29 2024 +0100

    MERG macris in exrail
2024-06-13 13:01:33 +01:00
Harald Barth
3d6c935308 EXCSB1 motor driver definitions 2024-06-11 23:10:18 +02:00
Harald Barth
fba9a30813 ESP32: Espressif deprecated ADC_ATTEN_DB_11 2024-06-11 23:09:41 +02:00
Harald Barth
5f65fd5944 tag with date 2024-06-02 21:45:43 +02:00
Harald Barth
a26610bc7f ESP32: More version locking 2024-06-02 21:44:25 +02:00
Harald Barth
264a53dacf ESP32: Refuse IDF5 2024-06-02 21:10:57 +02:00
Harald Barth
0c96d4ffc2 version 5.2.60 2024-05-23 22:46:47 +02:00
Harald Barth
843fa42692 Remove inrush throttle after half good time so that we go to mode overload if problem persists 2024-05-23 22:41:50 +02:00
Harald Barth
b17dc5a0dd Bugfix: Opcode AFTEROVERLOAD does not have an argument that is a pin and needs to be initialized 2024-05-23 22:39:43 +02:00
pmantoine
449a5f1670 STM32 updates for serial ports etc. 2024-05-22 07:16:25 +08:00
Asbelos
06b8995861 ALIAS(named pins) 2024-05-21 20:04:11 +01:00
Harald Barth
2172d2e175 make WDT time longer to work around bootloader bug 2024-05-11 08:46:25 +02:00
Harald Barth
86291cbec4 signal id of 0 does not work 2024-05-11 07:45:28 +02:00
Harald Barth
66791b19f5 remove stupid comment 2024-05-11 07:43:24 +02:00
Harald Barth
6689a1d35f version 5.2.57 2024-05-09 17:11:09 +02:00
Harald Barth
91818ed80c apply mode by binart bit match and not by equality 2024-05-09 17:06:33 +02:00
Harald Barth
86310aea4f getSignalSlot minor typo (and indent/comments) fix 2024-05-09 15:18:00 +02:00
pmantoine
a610e83f6e Bugfix and refactor for EXRAIL getSignalSlot 2024-05-07 18:20:37 +08:00
pmantoine
1449dc7bac EXRAIL move isSignal to public for STEALTH 2024-05-07 15:12:37 +08:00
pmantoine
bd11cfbf8b Bugfix EXRAIL active high signal handling 2024-05-07 11:29:49 +08:00
pmantoine
16214fad66 EX-Fastclock bugfix for address check 2024-05-07 11:13:19 +08:00
pmantoine
76ad3ee48d STM32 bug fixes, port usage 2024-05-07 11:10:39 +08:00
Asbelos
742b100f65 Comments only 2024-05-02 09:48:18 +01:00
22 changed files with 255 additions and 76 deletions

View File

@ -27,8 +27,8 @@
#include "DCCWaveform.h" #include "DCCWaveform.h"
#include "TrackManager.h" #include "TrackManager.h"
unsigned int DCCACK::minAckPulseDuration = 2000; // micros unsigned long DCCACK::minAckPulseDuration = 2000; // micros
unsigned int DCCACK::maxAckPulseDuration = 20000; // micros unsigned long DCCACK::maxAckPulseDuration = 20000; // micros
MotorDriver * DCCACK::progDriver=NULL; MotorDriver * DCCACK::progDriver=NULL;
ackOp const * DCCACK::ackManagerProg; ackOp const * DCCACK::ackManagerProg;
@ -50,8 +50,8 @@ volatile uint8_t DCCACK::numAckSamples=0;
uint8_t DCCACK::trailingEdgeCounter=0; uint8_t DCCACK::trailingEdgeCounter=0;
unsigned int DCCACK::ackPulseDuration; // micros unsigned long DCCACK::ackPulseDuration; // micros
unsigned long DCCACK::ackPulseStart; // micros unsigned long DCCACK::ackPulseStart; // micros
volatile bool DCCACK::ackDetected; volatile bool DCCACK::ackDetected;
unsigned long DCCACK::ackCheckStart; // millis unsigned long DCCACK::ackCheckStart; // millis
volatile bool DCCACK::ackPending; volatile bool DCCACK::ackPending;
@ -127,7 +127,7 @@ bool DCCACK::checkResets(uint8_t numResets) {
void DCCACK::setAckBaseline() { void DCCACK::setAckBaseline() {
int baseline=progDriver->getCurrentRaw(); int baseline=progDriver->getCurrentRaw();
ackThreshold= baseline + progDriver->mA2raw(ackLimitmA); ackThreshold= baseline + progDriver->mA2raw(ackLimitmA);
if (Diag::ACK) DIAG(F("ACK baseline=%d/%dmA Threshold=%d/%dmA Duration between %uus and %uus"), if (Diag::ACK) DIAG(F("ACK baseline=%d/%dmA Threshold=%d/%dmA Duration between %lus and %lus"),
baseline,progDriver->raw2mA(baseline), baseline,progDriver->raw2mA(baseline),
ackThreshold,progDriver->raw2mA(ackThreshold), ackThreshold,progDriver->raw2mA(ackThreshold),
minAckPulseDuration, maxAckPulseDuration); minAckPulseDuration, maxAckPulseDuration);
@ -146,7 +146,7 @@ void DCCACK::setAckPending() {
byte DCCACK::getAck() { byte DCCACK::getAck() {
if (ackPending) return (2); // still waiting if (ackPending) return (2); // still waiting
if (Diag::ACK) DIAG(F("%S after %dmS max=%d/%dmA pulse=%uuS samples=%d gaps=%d"),ackDetected?F("ACK"):F("NO-ACK"), ackCheckDuration, if (Diag::ACK) DIAG(F("%S after %dmS max=%d/%dmA pulse=%luS samples=%d gaps=%d"),ackDetected?F("ACK"):F("NO-ACK"), ackCheckDuration,
ackMaxCurrent,progDriver->raw2mA(ackMaxCurrent), ackPulseDuration, numAckSamples, numAckGaps); ackMaxCurrent,progDriver->raw2mA(ackMaxCurrent), ackPulseDuration, numAckSamples, numAckGaps);
if (ackDetected) return (1); // Yes we had an ack if (ackDetected) return (1); // Yes we had an ack
return(0); // pending set off but not detected means no ACK. return(0); // pending set off but not detected means no ACK.

View File

@ -79,10 +79,10 @@ class DCCACK {
static inline void setAckLimit(int mA) { static inline void setAckLimit(int mA) {
ackLimitmA = mA; ackLimitmA = mA;
} }
static inline void setMinAckPulseDuration(unsigned int i) { static inline void setMinAckPulseDuration(unsigned long i) {
minAckPulseDuration = i; minAckPulseDuration = i;
} }
static inline void setMaxAckPulseDuration(unsigned int i) { static inline void setMaxAckPulseDuration(unsigned long i) {
maxAckPulseDuration = i; maxAckPulseDuration = i;
} }
@ -126,11 +126,11 @@ class DCCACK {
static unsigned long ackCheckStart; // millis static unsigned long ackCheckStart; // millis
static unsigned int ackCheckDuration; // millis static unsigned int ackCheckDuration; // millis
static unsigned int ackPulseDuration; // micros static unsigned long ackPulseDuration; // micros
static unsigned long ackPulseStart; // micros static unsigned long ackPulseStart; // micros
static unsigned int minAckPulseDuration ; // micros static unsigned long minAckPulseDuration ; // micros
static unsigned int maxAckPulseDuration ; // micros static unsigned long maxAckPulseDuration ; // micros
static MotorDriver* progDriver; static MotorDriver* progDriver;
static volatile uint8_t numAckGaps; static volatile uint8_t numAckGaps;
static volatile uint8_t numAckSamples; static volatile uint8_t numAckSamples;

View File

@ -2,7 +2,7 @@
* © 2022 Paul M Antoine * © 2022 Paul M Antoine
* © 2021 Neil McKechnie * © 2021 Neil McKechnie
* © 2021 Mike S * © 2021 Mike S
* © 2021 Herb Morton * © 2021-2024 Herb Morton
* © 2020-2023 Harald Barth * © 2020-2023 Harald Barth
* © 2020-2021 M Steve Todd * © 2020-2021 M Steve Todd
* © 2020-2021 Fred Decker * © 2020-2021 Fred Decker
@ -70,8 +70,8 @@ Once a new OPCODE is decided upon, update this list.
L, Reserved for LCC interface (implemented in EXRAIL) L, Reserved for LCC interface (implemented in EXRAIL)
m, message to throttles broadcast m, message to throttles broadcast
M, Write DCC packet M, Write DCC packet
n, n, Reserved for SensorCam
N, N, Reserved for Sensorcam
o, o,
O, Output broadcast O, Output broadcast
p, Broadcast power state p, Broadcast power state
@ -91,10 +91,10 @@ Once a new OPCODE is decided upon, update this list.
w, Write CV on main w, Write CV on main
W, Write CV W, Write CV
x, x,
X, Invalid command X, Invalid command response
y, y,
Y, Output broadcast Y, Output broadcast
z, z, Direct output
Z, Output configuration/control Z, Output configuration/control
*/ */
@ -563,6 +563,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
} }
#ifndef DISABLE_PROG #ifndef DISABLE_PROG
else if (p[0]=="PROG"_hk) { // <0 PROG> else if (p[0]=="PROG"_hk) { // <0 PROG>
TrackManager::setJoin(false);
TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off
TrackManager::setTrackPower(TRACK_MODE_PROG, POWERMODE::OFF); TrackManager::setTrackPower(TRACK_MODE_PROG, POWERMODE::OFF);
} }
@ -1073,15 +1074,24 @@ bool DCCEXParser::parseC(Print *stream, int16_t params, int16_t p[]) {
#ifndef DISABLE_PROG #ifndef DISABLE_PROG
case "ACK"_hk: // <D ACK ON/OFF> <D ACK [LIMIT|MIN|MAX|RETRY] Value> case "ACK"_hk: // <D ACK ON/OFF> <D ACK [LIMIT|MIN|MAX|RETRY] Value>
if (params >= 3) { if (params >= 3) {
long duration;
if (p[1] == "LIMIT"_hk) { if (p[1] == "LIMIT"_hk) {
DCCACK::setAckLimit(p[2]); DCCACK::setAckLimit(p[2]);
LCD(1, F("Ack Limit=%dmA"), p[2]); // <D ACK LIMIT 42> LCD(1, F("Ack Limit=%dmA"), p[2]); // <D ACK LIMIT 42>
} else if (p[1] == "MIN"_hk) { } else if (p[1] == "MIN"_hk) {
DCCACK::setMinAckPulseDuration(p[2]); if (params == 4 && p[3] == "MS"_hk)
LCD(0, F("Ack Min=%uus"), p[2]); // <D ACK MIN 1500> duration = p[2] * 1000L;
else
duration = p[2];
DCCACK::setMinAckPulseDuration(duration);
LCD(0, F("Ack Min=%lus"), duration); // <D ACK MIN 1500>
} else if (p[1] == "MAX"_hk) { } else if (p[1] == "MAX"_hk) {
DCCACK::setMaxAckPulseDuration(p[2]); if (params == 4 && p[3] == "MS"_hk) // <D ACK MAX 80 MS>
LCD(0, F("Ack Max=%uus"), p[2]); // <D ACK MAX 9000> duration = p[2] * 1000L;
else
duration = p[2];
DCCACK::setMaxAckPulseDuration(duration);
LCD(0, F("Ack Max=%lus"), duration); // <D ACK MAX 9000>
} else if (p[1] == "RETRY"_hk) { } else if (p[1] == "RETRY"_hk) {
if (p[2] >255) p[2]=3; if (p[2] >255) p[2]=3;
LCD(0, F("Ack Retry=%d Sum=%d"), p[2], DCCACK::setAckRetry(p[2])); // <D ACK RETRY 2> LCD(0, F("Ack Retry=%d Sum=%d"), p[2], DCCACK::setAckRetry(p[2])); // <D ACK RETRY 2>

View File

@ -185,8 +185,10 @@ int DCCTimer::freeMemory() {
} }
void DCCTimer::reset() { void DCCTimer::reset() {
wdt_enable( WDTO_15MS); // set Arduino watchdog timer for 15ms // 250ms chosen to circumwent bootloader bug which
delay(50); // wait for the prescaller time to expire // hangs at too short timepout (like 15ms)
wdt_enable( WDTO_250MS); // set Arduino watchdog timer for 250ms
delay(500); // wait for it to happen
} }

View File

@ -76,8 +76,13 @@ int DCCTimer::freeMemory() {
#endif #endif
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#include "esp_idf_version.h"
#if ESP_IDF_VERSION_MAJOR > 4
#error "DCC-EX does not support compiling with IDF version 5.0 or later. Downgrade your ESP32 library to a version that contains IDE version 4. Arduino ESP32 library 3.0.0 is too new. Downgrade to one of 2.0.9 to 2.0.17"
#endif
#include "DIAG.h" #include "DIAG.h"
#include <driver/adc.h> #include <driver/adc.h>
#include <soc/sens_reg.h> #include <soc/sens_reg.h>
@ -292,7 +297,12 @@ void DCCTimer::DCCEXInrushControlOn(uint8_t pin, int duty, bool inverted) {
int ADCee::init(uint8_t pin) { int ADCee::init(uint8_t pin) {
pinMode(pin, ANALOG); pinMode(pin, ANALOG);
adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_width(ADC_WIDTH_BIT_12);
// Espressif deprecated ADC_ATTEN_DB_11 somewhere between 2.0.9 and 2.0.17
#ifdef ADC_ATTEN_11db
adc1_config_channel_atten(pinToADC1Channel(pin),ADC_ATTEN_11db);
#else
adc1_config_channel_atten(pinToADC1Channel(pin),ADC_ATTEN_DB_11); adc1_config_channel_atten(pinToADC1Channel(pin),ADC_ATTEN_DB_11);
#endif
return adc1_get_raw(pinToADC1Channel(pin)); return adc1_get_raw(pinToADC1Channel(pin));
} }
int16_t ADCee::ADCmax() { int16_t ADCee::ADCmax() {

View File

@ -36,7 +36,20 @@
#include "DIAG.h" #include "DIAG.h"
#include <wiring_private.h> #include <wiring_private.h>
#if defined(ARDUINO_NUCLEO_F401RE) || defined(ARDUINO_NUCLEO_F411RE) #if defined(ARDUINO_NUCLEO_F401RE)
// Nucleo-64 boards don't have additional serial ports defined by default
// Serial1 is available on the F401RE, but not hugely convenient.
// Rx pin on PB7 is useful, but all the Tx pins map to Arduino digital pins, specifically:
// PA9 == D8
// PB6 == D10
// of which D8 is needed by the standard and EX8874 motor shields. D10 would be used if a second
// EX8874 is stacked. So only disable this if using a second motor shield.
HardwareSerial Serial1(PB7, PB6); // Rx=PB7, Tx=PB6 -- CN7 pin 17 and CN10 pin 17
// Serial2 is defined to use USART2 by default, but is in fact used as the diag console
// via the debugger on the Nucleo-64. It is therefore unavailable for other DCC-EX uses like WiFi, DFPlayer, etc.
// Let's define Serial6 as an additional serial port (the only other option for the F401RE)
HardwareSerial Serial6(PA12, PA11); // Rx=PA12, Tx=PA11 -- CN10 pins 12 and 14 - F401RE
#elif defined(ARDUINO_NUCLEO_F411RE)
// Nucleo-64 boards don't have additional serial ports defined by default // Nucleo-64 boards don't have additional serial ports defined by default
HardwareSerial Serial1(PB7, PA15); // Rx=PB7, Tx=PA15 -- CN7 pins 17 and 21 - F411RE HardwareSerial Serial1(PB7, PA15); // Rx=PB7, Tx=PA15 -- CN7 pins 17 and 21 - F411RE
// Serial2 is defined to use USART2 by default, but is in fact used as the diag console // Serial2 is defined to use USART2 by default, but is in fact used as the diag console
@ -54,7 +67,7 @@ HardwareSerial Serial3(PC11, PC10); // Rx=PC11, Tx=PC10 -- USART3 - F446RE
HardwareSerial Serial5(PD2, PC12); // Rx=PD2, Tx=PC12 -- UART5 - F446RE HardwareSerial Serial5(PD2, PC12); // Rx=PD2, Tx=PC12 -- UART5 - F446RE
// On the F446RE, Serial4 and Serial6 also use pins we can't readily map while using the Arduino pins // On the F446RE, Serial4 and Serial6 also use pins we can't readily map while using the Arduino pins
#elif defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F413ZH) || defined(ARDUINO_NUCLEO_F446ZE) || \ #elif defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F413ZH) || defined(ARDUINO_NUCLEO_F446ZE) || \
defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F439ZI) defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F4X9ZI)
// Nucleo-144 boards don't have Serial1 defined by default // Nucleo-144 boards don't have Serial1 defined by default
HardwareSerial Serial6(PG9, PG14); // Rx=PG9, Tx=PG14 -- USART6 HardwareSerial Serial6(PG9, PG14); // Rx=PG9, Tx=PG14 -- USART6
HardwareSerial Serial5(PD2, PC12); // Rx=PD2, Tx=PC12 -- UART5 HardwareSerial Serial5(PD2, PC12); // Rx=PD2, Tx=PC12 -- UART5

View File

@ -1,4 +1,5 @@
/* /*
* © 2024 Paul M. Antoine
* © 2021 Neil McKechnie * © 2021 Neil McKechnie
* © 2021-2023 Harald Barth * © 2021-2023 Harald Barth
* © 2020-2023 Chris Harlow * © 2020-2023 Chris Harlow
@ -227,7 +228,6 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
case OPCODE_AT: case OPCODE_AT:
case OPCODE_ATTIMEOUT2: case OPCODE_ATTIMEOUT2:
case OPCODE_AFTER: case OPCODE_AFTER:
case OPCODE_AFTEROVERLOAD:
case OPCODE_IF: case OPCODE_IF:
case OPCODE_IFNOT: { case OPCODE_IFNOT: {
int16_t pin = (int16_t)operand; int16_t pin = (int16_t)operand;
@ -1000,6 +1000,14 @@ void RMFT2::loop2() {
if ((compileFeatures & FEATURE_LCC) && LCCSerial) if ((compileFeatures & FEATURE_LCC) && LCCSerial)
StringFormatter::send(LCCSerial,F("<L x%h>"),(uint16_t)operand); StringFormatter::send(LCCSerial,F("<L x%h>"),(uint16_t)operand);
break; break;
case OPCODE_ACON: // MERG adapter
case OPCODE_ACOF:
if ((compileFeatures & FEATURE_LCC) && LCCSerial)
StringFormatter::send(LCCSerial,F("<L x%c%h%h>"),
opcode==OPCODE_ACON?'0':'1',
(uint16_t)operand,getOperand(progCounter,1));
break;
case OPCODE_LCCX: // long form LCC case OPCODE_LCCX: // long form LCC
if ((compileFeatures & FEATURE_LCC) && LCCSerial) if ((compileFeatures & FEATURE_LCC) && LCCSerial)
@ -1088,6 +1096,8 @@ void RMFT2::loop2() {
case OPCODE_PINTURNOUT: // Turnout definition ignored at runtime case OPCODE_PINTURNOUT: // Turnout definition ignored at runtime
case OPCODE_ONCLOSE: // Turnout event catchers ignored here case OPCODE_ONCLOSE: // Turnout event catchers ignored here
case OPCODE_ONLCC: // LCC event catchers ignored here case OPCODE_ONLCC: // LCC event catchers ignored here
case OPCODE_ONACON: // MERG event catchers ignored here
case OPCODE_ONACOF: // MERG event catchers ignored here
case OPCODE_ONTHROW: case OPCODE_ONTHROW:
case OPCODE_ONACTIVATE: // Activate event catchers ignored here case OPCODE_ONACTIVATE: // Activate event catchers ignored here
case OPCODE_ONDEACTIVATE: case OPCODE_ONDEACTIVATE:
@ -1143,20 +1153,25 @@ void RMFT2::kill(const FSH * reason, int operand) {
} }
int16_t RMFT2::getSignalSlot(int16_t id) { int16_t RMFT2::getSignalSlot(int16_t id) {
for (int sigslot=0;;sigslot++) {
int16_t sighandle=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8); if (id > 0) {
if (sighandle==0) { // end of signal list int sigslot = 0;
DIAG(F("EXRAIL Signal %d not defined"), id); int16_t sighandle = 0;
return -1; // Trundle down the signal list until we reach the end
} while ((sighandle = GETHIGHFLASHW(RMFT2::SignalDefinitions, sigslot * 8)) != 0)
VPIN sigid = sighandle & SIGNAL_ID_MASK; {
// sigid is the signal id used in RED/AMBER/GREEN macro // sigid is the signal id used in RED/AMBER/GREEN macro
// for a LED signal it will be same as redpin // for a LED signal it will be same as redpin
// but for a servo signal it will also have SERVO_SIGNAL_FLAG set. // but for a servo signal it will also have SERVO_SIGNAL_FLAG set.
VPIN sigid = sighandle & SIGNAL_ID_MASK;
if (sigid != id) continue; // keep looking if (sigid == (VPIN)id) // cast to keep compiler happy but id is positive
return sigslot; // relative slot in signals table return sigslot; // found it
} sigslot++; // keep looking
};
}
// If we got here, we did not find the signal
DIAG(F("EXRAIL Signal %d not defined"), id);
return -1;
} }
/* static */ void RMFT2::doSignal(int16_t id,char rag) { /* static */ void RMFT2::doSignal(int16_t id,char rag) {
@ -1218,7 +1233,7 @@ int16_t RMFT2::getSignalSlot(int16_t id) {
if (rag==SIGNAL_AMBER && (amberpin==0)) rag=SIMAMBER; // special case this func only if (rag==SIGNAL_AMBER && (amberpin==0)) rag=SIMAMBER; // special case this func only
// Manage invert (HIGH on) pins // Manage invert (HIGH on) pins
bool aHigh=sigid & ACTIVE_HIGH_SIGNAL_FLAG; bool aHigh=sighandle & ACTIVE_HIGH_SIGNAL_FLAG;
// set the three pins // set the three pins
if (redpin) { if (redpin) {

View File

@ -69,6 +69,8 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,OPCODE_TOGGLE_TURNOUT,
OPCODE_TTADDPOSITION,OPCODE_DCCTURNTABLE,OPCODE_EXTTTURNTABLE, OPCODE_TTADDPOSITION,OPCODE_DCCTURNTABLE,OPCODE_EXTTTURNTABLE,
OPCODE_ONROTATE,OPCODE_ROTATE,OPCODE_WAITFORTT, OPCODE_ONROTATE,OPCODE_ROTATE,OPCODE_WAITFORTT,
OPCODE_LCC,OPCODE_LCCX,OPCODE_ONLCC, OPCODE_LCC,OPCODE_LCCX,OPCODE_ONLCC,
OPCODE_ACON, OPCODE_ACOF,
OPCODE_ONACON, OPCODE_ONACOF,
OPCODE_ONOVERLOAD, OPCODE_ONOVERLOAD,
OPCODE_ROUTE_ACTIVE,OPCODE_ROUTE_INACTIVE,OPCODE_ROUTE_HIDDEN, OPCODE_ROUTE_ACTIVE,OPCODE_ROUTE_INACTIVE,OPCODE_ROUTE_HIDDEN,
OPCODE_ROUTE_DISABLED, OPCODE_ROUTE_DISABLED,
@ -187,6 +189,7 @@ class LookList {
static const FSH * getTurntablePositionDescription(int16_t turntableId, uint8_t positionId); static const FSH * getTurntablePositionDescription(int16_t turntableId, uint8_t positionId);
static void startNonRecursiveTask(const FSH* reason, int16_t id,int pc); static void startNonRecursiveTask(const FSH* reason, int16_t id,int pc);
static bool readSensor(uint16_t sensorId); static bool readSensor(uint16_t sensorId);
static bool isSignal(int16_t id,char rag);
private: private:
static void ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16_t p[]); static void ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16_t p[]);
@ -196,7 +199,6 @@ private:
static bool getFlag(VPIN id,byte mask); static bool getFlag(VPIN id,byte mask);
static int16_t progtrackLocoId; static int16_t progtrackLocoId;
static void doSignal(int16_t id,char rag); static void doSignal(int16_t id,char rag);
static bool isSignal(int16_t id,char rag);
static int16_t getSignalSlot(int16_t id); static int16_t getSignalSlot(int16_t id);
static void setTurnoutHiddenState(Turnout * t); static void setTurnoutHiddenState(Turnout * t);
#ifndef IO_NO_HAL #ifndef IO_NO_HAL

View File

@ -99,6 +99,10 @@
#undef LCCX #undef LCCX
#undef LCN #undef LCN
#undef MOVETT #undef MOVETT
#undef ACON
#undef ACOF
#undef ONACON
#undef ONACOF
#undef MESSAGE #undef MESSAGE
#undef ONACTIVATE #undef ONACTIVATE
#undef ONACTIVATEL #undef ONACTIVATEL
@ -265,6 +269,10 @@
#define LCN(msg) #define LCN(msg)
#define MESSAGE(msg) #define MESSAGE(msg)
#define MOVETT(id,steps,activity) #define MOVETT(id,steps,activity)
#define ACON(eventid)
#define ACOF(eventid)
#define ONACON(eventid)
#define ONACOF(eventid)
#define ONACTIVATE(addr,subaddr) #define ONACTIVATE(addr,subaddr)
#define ONACTIVATEL(linear) #define ONACTIVATEL(linear)
#define ONAMBER(signal_id) #define ONAMBER(signal_id)

View File

@ -61,47 +61,85 @@ void RMFT2::ComandFilter(Print * stream, byte & opcode, byte & paramCount, int16
case 'L': case 'L':
// This entire code block is compiled out if LLC macros not used // This entire code block is compiled out if LLC macros not used
if (!(compileFeatures & FEATURE_LCC)) return; if (!(compileFeatures & FEATURE_LCC)) return;
static int lccProgCounter=0;
static int lccEventIndex=0;
if (paramCount==0) { //<L> LCC adapter introducing self if (paramCount==0) { //<L> LCC adapter introducing self
LCCSerial=stream; // now we know where to send events we raise LCCSerial=stream; // now we know where to send events we raise
opcode=0; // flag command as intercepted
// loop through all possible sent events // loop through all possible sent/waited events
for (int progCounter=0;; SKIPOP) { for (int progCounter=lccProgCounter;; SKIPOP) {
byte opcode=GET_OPCODE; byte exrailOpcode=GET_OPCODE;
if (opcode==OPCODE_ENDEXRAIL) break; switch (exrailOpcode) {
if (opcode==OPCODE_LCC) StringFormatter::send(stream,F("<LS x%h>\n"),getOperand(progCounter,0)); case OPCODE_ENDEXRAIL:
if (opcode==OPCODE_LCCX) { // long form LCC stream->print(F("<LR>\n")); // ready to roll
StringFormatter::send(stream,F("<LS x%h%h%h%h>\n"), lccProgCounter=0; // allow a second pass
lccEventIndex=0;
return;
case OPCODE_LCC:
StringFormatter::send(stream,F("<LS x%h>\n"),getOperand(progCounter,0));
SKIPOP;
lccProgCounter=progCounter;
return;
case OPCODE_LCCX: // long form LCC
StringFormatter::send(stream,F("<LS x%h%h%h%h>\n"),
getOperand(progCounter,1), getOperand(progCounter,1),
getOperand(progCounter,2), getOperand(progCounter,2),
getOperand(progCounter,3), getOperand(progCounter,3),
getOperand(progCounter,0) getOperand(progCounter,0)
); );
}} SKIPOP;SKIPOP;SKIPOP;SKIPOP;
lccProgCounter=progCounter;
return;
case OPCODE_ACON: // CBUS ACON
case OPCODE_ACOF: // CBUS ACOF
StringFormatter::send(stream,F("<LS x%c%h%h>\n"),
exrailOpcode==OPCODE_ACOF?'1':'0',
getOperand(progCounter,0),getOperand(progCounter,1));
SKIPOP;SKIPOP;
lccProgCounter=progCounter;
return;
// we stream the hex events we wish to listen to // we stream the hex events we wish to listen to
// and at the same time build the event index looku. // and at the same time build the event index looku.
case OPCODE_ONLCC:
int eventIndex=0;
for (int progCounter=0;; SKIPOP) {
byte opcode=GET_OPCODE;
if (opcode==OPCODE_ENDEXRAIL) break;
if (opcode==OPCODE_ONLCC) {
onLCCLookup[eventIndex]=progCounter; // TODO skip...
StringFormatter::send(stream,F("<LL %d x%h%h%h:%h>\n"), StringFormatter::send(stream,F("<LL %d x%h%h%h:%h>\n"),
eventIndex, lccEventIndex,
getOperand(progCounter,1), getOperand(progCounter,1),
getOperand(progCounter,2), getOperand(progCounter,2),
getOperand(progCounter,3), getOperand(progCounter,3),
getOperand(progCounter,0) getOperand(progCounter,0)
); );
eventIndex++; SKIPOP;SKIPOP;SKIPOP;SKIPOP;
} // start on handler at next
onLCCLookup[lccEventIndex]=progCounter;
lccEventIndex++;
lccProgCounter=progCounter;
return;
case OPCODE_ONACON:
case OPCODE_ONACOF:
StringFormatter::send(stream,F("<LL %d x%c%h%h>\n"),
lccEventIndex,
exrailOpcode==OPCODE_ONACOF?'1':'0',
getOperand(progCounter,0),getOperand(progCounter,1)
);
SKIPOP;SKIPOP;
// start on handler at next
onLCCLookup[lccEventIndex]=progCounter;
lccEventIndex++;
lccProgCounter=progCounter;
return;
default:
break;
}
} }
StringFormatter::send(stream,F("<LR>\n")); // Ready to rumble
opcode=0;
break;
} }
if (paramCount==1) { // <L eventid> LCC event arrived from adapter if (paramCount==1) { // <L eventid> LCC event arrived from adapter
int16_t eventid=p[0]; int16_t eventid=p[0];

View File

@ -75,7 +75,7 @@
// Pass 1 Implements aliases // Pass 1 Implements aliases
#include "EXRAIL2MacroReset.h" #include "EXRAIL2MacroReset.h"
#undef ALIAS #undef ALIAS
#define ALIAS(name,value...) const int name= 1##value##0 ==10 ? -__COUNTER__ : value##0/10; #define ALIAS(name,value...) const int name= #value[0] ? value+0: -__COUNTER__ ;
#include "myAutomation.h" #include "myAutomation.h"
// Pass 1d Detect sequence duplicates. // Pass 1d Detect sequence duplicates.
@ -189,6 +189,14 @@ bool exrailHalSetup() {
#define LCCX(senderid,eventid) | FEATURE_LCC #define LCCX(senderid,eventid) | FEATURE_LCC
#undef ONLCC #undef ONLCC
#define ONLCC(senderid,eventid) | FEATURE_LCC #define ONLCC(senderid,eventid) | FEATURE_LCC
#undef ACON
#define ACON(eventid) | FEATURE_LCC
#undef ACOF
#define ACOF(eventid) | FEATURE_LCC
#undef ONACON
#define ONACON(eventid) | FEATURE_LCC
#undef ONACOF
#define ONACOF(eventid) | FEATURE_LCC
#undef ROUTE_ACTIVE #undef ROUTE_ACTIVE
#define ROUTE_ACTIVE(id) | FEATURE_ROUTESTATE #define ROUTE_ACTIVE(id) | FEATURE_ROUTESTATE
#undef ROUTE_INACTIVE #undef ROUTE_INACTIVE
@ -429,10 +437,14 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
#include "myAutomation.h" #include "myAutomation.h"
0,0,0,0 }; 0,0,0,0 };
// Pass 9 ONLCC counter and lookup array // Pass 9 ONLCC/ ONMERG counter and lookup array
#include "EXRAIL2MacroReset.h" #include "EXRAIL2MacroReset.h"
#undef ONLCC #undef ONLCC
#define ONLCC(sender,event) +1 #define ONLCC(sender,event) +1
#undef ONACON
#define ONACON(event) +1
#undef ONACOF
#define ONACOF(event) +1
const int RMFT2::countLCCLookup=0 const int RMFT2::countLCCLookup=0
#include "myAutomation.h" #include "myAutomation.h"
@ -529,6 +541,10 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
OPCODE_PAD,V((((uint64_t)sender)>>32)&0xFFFF),\ OPCODE_PAD,V((((uint64_t)sender)>>32)&0xFFFF),\
OPCODE_PAD,V((((uint64_t)sender)>>16)&0xFFFF),\ OPCODE_PAD,V((((uint64_t)sender)>>16)&0xFFFF),\
OPCODE_PAD,V((((uint64_t)sender)>>0)&0xFFFF), OPCODE_PAD,V((((uint64_t)sender)>>0)&0xFFFF),
#define ACON(eventid) OPCODE_ACON,V(((uint32_t)eventid >>16) & 0xFFFF),OPCODE_PAD,V(eventid & 0xFFFF),
#define ACOF(eventid) OPCODE_ACOF,V(((uint32_t)eventid >>16) & 0xFFFF),OPCODE_PAD,V(eventid & 0xFFFF),
#define ONACON(eventid) OPCODE_ONACON,V((uint32_t)(eventid) >>16),OPCODE_PAD,V(eventid & 0xFFFF),
#define ONACOF(eventid) OPCODE_ONACOF,V((uint32_t)(eventid) >>16),OPCODE_PAD,V(eventid & 0xFFFF),
#define LCD(id,msg) PRINT(msg) #define LCD(id,msg) PRINT(msg)
#define SCREEN(display,id,msg) PRINT(msg) #define SCREEN(display,id,msg) PRINT(msg)
#define STEALTH(code...) PRINT(dummy) #define STEALTH(code...) PRINT(dummy)

View File

@ -1 +1 @@
#define GITHUB_SHA "devel-202404211704Z" #define GITHUB_SHA "devel-202406182019Z"

View File

@ -51,6 +51,7 @@ static void create(I2CAddress i2cAddress) {
// Start by assuming we will find the clock // Start by assuming we will find the clock
// Check if specified I2C address is responding (blocking operation) // Check if specified I2C address is responding (blocking operation)
// Returns I2C_STATUS_OK (0) if OK, or error code. // Returns I2C_STATUS_OK (0) if OK, or error code.
I2CManager.begin();
uint8_t _checkforclock = I2CManager.checkAddress(i2cAddress); uint8_t _checkforclock = I2CManager.checkAddress(i2cAddress);
DIAG(F("Clock check result - %d"), _checkforclock); DIAG(F("Clock check result - %d"), _checkforclock);
// XXXX change thistosave2 bytes // XXXX change thistosave2 bytes

View File

@ -26,7 +26,7 @@
Thus "MAIN"_hk generates exactly the same run time vakue Thus "MAIN"_hk generates exactly the same run time vakue
as const int16_t HASH_KEYWORD_MAIN=11339 as const int16_t HASH_KEYWORD_MAIN=11339
*/ */
#ifndef KeywordHAsher_h #ifndef KeywordHasher_h
#define KeywordHasher_h #define KeywordHasher_h
#include <Arduino.h> #include <Arduino.h>

View File

@ -638,6 +638,10 @@ void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) {
} }
throttleInrush(false); throttleInrush(false);
setPower(POWERMODE::ON); setPower(POWERMODE::ON);
break;
}
if (goodtime > POWER_SAMPLE_ALERT_GOOD/2) {
throttleInrush(false);
} }
break; break;
} }

View File

@ -97,6 +97,18 @@
new MotorDriver(25/* 3*/, 19/*12*/, UNUSED_PIN, 13/*9*/, 35/*A2*/, 1.27, 5000, 36 /*A4*/), \ new MotorDriver(25/* 3*/, 19/*12*/, UNUSED_PIN, 13/*9*/, 35/*A2*/, 1.27, 5000, 36 /*A4*/), \
new MotorDriver(23/*11*/, 18/*13*/, UNUSED_PIN, 12/*8*/, 34/*A3*/, 1.27, 5000, 39 /*A5*/) new MotorDriver(23/*11*/, 18/*13*/, UNUSED_PIN, 12/*8*/, 34/*A3*/, 1.27, 5000, 39 /*A5*/)
// EX-CSB1 with integrated motor driver definition
#define EXCSB1 F("EXCSB1"),\
new MotorDriver(25, 0, UNUSED_PIN, -14, 34, 2.23, 5000, 19), \
new MotorDriver(27, 15, UNUSED_PIN, -2, 35, 2.23, 5000, 23)
// EX-CSB1 with EX-8874 stacked on top for 4 outputs
#define EXCSB1_WITH_EX8874 F("EXCSB1_WITH_EX8874"),\
new MotorDriver(25, 0, UNUSED_PIN, -14, 34, 2.23, 5000, 19), \
new MotorDriver(27, 15, UNUSED_PIN, -2, 35, 2.23, 5000, 23), \
new MotorDriver(26, 5, UNUSED_PIN, 13, 36, 1.52, 5000, 18), \
new MotorDriver(16, 4, UNUSED_PIN, 12, 39, 1.52, 5000, 17)
#else #else
// STANDARD shield on any Arduino Uno or Mega compatible with the original specification. // STANDARD shield on any Arduino Uno or Mega compatible with the original specification.
#define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \ #define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \

View File

@ -35,7 +35,7 @@
#define APPLY_BY_MODE(findmode,function) \ #define APPLY_BY_MODE(findmode,function) \
FOR_EACH_TRACK(t) \ FOR_EACH_TRACK(t) \
if (track[t]->getMode()==findmode) \ if (track[t]->getMode() & findmode) \
track[t]->function; track[t]->function;
MotorDriver * TrackManager::track[MAX_TRACKS] = { NULL }; MotorDriver * TrackManager::track[MAX_TRACKS] = { NULL };
@ -398,7 +398,7 @@ bool TrackManager::parseEqualSign(Print *stream, int16_t params, int16_t p[])
if (params==2 && p[1]=="AUTO"_hk) // <= id AUTO> if (params==2 && p[1]=="AUTO"_hk) // <= id AUTO>
return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_AUTOINV); return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_AUTOINV);
if (params==2 && p[1]=="INV"_hk) // <= id AUTO> if (params==2 && p[1]=="INV"_hk) // <= id INV>
return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_INV); return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_INV);
if (params==3 && p[1]=="DC"_hk && p[2]>0) // <= id DC cab> if (params==3 && p[1]=="DC"_hk && p[2]>0) // <= id DC cab>

View File

@ -147,6 +147,12 @@ bool WifiESP::setup(const char *SSid,
// enableCoreWDT(1); // enableCoreWDT(1);
// disableCoreWDT(0); // disableCoreWDT(0);
#ifdef WIFI_LED
// Turn off Wifi LED
pinMode(WIFI_LED, OUTPUT);
digitalWrite(WIFI_LED, 0);
#endif
// clean start // clean start
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.disconnect(true); WiFi.disconnect(true);
@ -247,6 +253,13 @@ bool WifiESP::setup(const char *SSid,
// no idea to go on // no idea to go on
return false; return false;
} }
#ifdef WIFI_LED
else{
// Turn on Wifi connected LED
digitalWrite(WIFI_LED, 1);
}
#endif
// Now Wifi is up, register the mDNS service // Now Wifi is up, register the mDNS service
if(!MDNS.begin(hostname)) { if(!MDNS.begin(hostname)) {

View File

@ -1,4 +1,5 @@
/* /*
* © 2022-2024 Paul M. Antoine
* © 2021 Fred Decker * © 2021 Fred Decker
* © 2020-2022 Harald Barth * © 2020-2022 Harald Barth
* © 2020-2022 Chris Harlow * © 2020-2022 Chris Harlow
@ -70,7 +71,7 @@ Stream * WifiInterface::wifiStream;
#define SERIAL3 Serial5 #define SERIAL3 Serial5
#elif defined(ARDUINO_NUCLEO_F413ZH) || defined(ARDUINO_NUCLEO_F429ZI) \ #elif defined(ARDUINO_NUCLEO_F413ZH) || defined(ARDUINO_NUCLEO_F429ZI) \
|| defined(ARDUINO_NUCLEO_F446ZE) || defined(ARDUINO_NUCLEO_F412ZG) \ || defined(ARDUINO_NUCLEO_F446ZE) || defined(ARDUINO_NUCLEO_F412ZG) \
|| defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F4X9ZI)
#define NUM_SERIAL 2 #define NUM_SERIAL 2
#define SERIAL1 Serial6 #define SERIAL1 Serial6
#else #else

View File

@ -307,11 +307,21 @@ The configuration file for DCC-EX Command Station
// //
//#define SERIAL_BT_COMMANDS //#define SERIAL_BT_COMMANDS
// BOOSTER PIN INPUT ON ESP32 // BOOSTER PIN INPUT ON ESP32 CS
// On ESP32 you have the possibility to define a pin as booster input // On ESP32 you have the possibility to define a pin as booster input
// Arduio pin D2 is GPIO 26 on ESPDuino32
// //
// Arduino pin D2 is GPIO 26 is Booster Input on ESPDuino32
//#define BOOSTER_INPUT 26 //#define BOOSTER_INPUT 26
//
// GPIO 32 is Booster Input on EX-CSB1
//#define BOOSTER_INPUT 32
// ESP32 LED Wifi Indicator
// GPIO 2 on ESPduino32
//#define WIFI_LED 2
//
// GPIO 33 on EX-CSB1
//#define WIFI_LED 33
// SABERTOOTH // SABERTOOTH
// //

View File

@ -164,7 +164,11 @@ monitor_echo = yes
build_flags = -mcall-prologues build_flags = -mcall-prologues
[env:ESP32] [env:ESP32]
platform = espressif32 ; Lock version to 6.7.0 as that is
; Arduino v2.0.16 (based on IDF v4.4.7)
; which is the latest version based
; on IDF v4. We can not use IDF v5.
platform = espressif32 @ 6.7.0
board = esp32dev board = esp32dev
framework = arduino framework = arduino
lib_deps = ${env.lib_deps} lib_deps = ${env.lib_deps}

View File

@ -3,7 +3,27 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "5.2.51" #define VERSION "5.2.64"
// 5.2.64 - Bugfix: <0 PROG> updated to undo JOIN
// 5.2.63 - Implement WIFI_LED for ESP32, ESPduino32 and EX-CSB1, that is turned on when STA mode connects or AP mode is up
// - Add BOOSTER_INPUT definitions for ESPduino32 and EX-CSB1 to config.example.h
// - Add WIFI_LED definitions for ESPduino32 and EX-CSB1 to config.example.h
// 5.2.62 - Allow acks way longer than standard
// 5.2.61 - Merg CBUS ACON/ACOF/ONACON/ONACOF Adapter interface.
// - LCC Adapter interface throttled startup,
// (Breaking change woith Adapter base code)
// 5.2.60 - Bugfix: Opcode AFTEROVERLOAD does not have an argument that is a pin and needs to be initialized
// - Remove inrush throttle after half good time so that we go to mode overload if problem persists
// 5.2.59 - STM32 bugfix correct Serial1 definition for Nucleo-F401RE
// - STM32 add support for ARDUINO_NUCLEO_F4X9ZI type to span F429/F439 in upcoming STM32duino release v2.8 as a result of our PR
// 5.2.58 - EXRAIL ALIAS allows named pins
// 5.2.57 - Bugfix autoreverse: Apply mode by binart bit match and not by equality
// 5.2.56 - Bugfix and refactor for EXRAIL getSignalSlot
// 5.2.55 - Move EXRAIL isSignal() to public to allow use in STEALTH call
// 5.2.54 - Bugfix for EXRAIL signal handling for active high
// 5.2.53 - Bugfix for EX-Fastclock, call I2CManager.begin() before checking I2C address
// 5.2.52 - Bugfix for ADCee() to handle ADC2 and ADC3 channel inputs on F446ZE and others
// - Add support for ports G and H on STM32 for ADCee() and MotorDriver pins/shadow regs
// 5.2.51 - Bugfix for SIGNAL: Distinguish between sighandle and sigid // 5.2.51 - Bugfix for SIGNAL: Distinguish between sighandle and sigid
// 5.2.50 - EXRAIL ONBUTTON/ONSENSOR observe LATCH // 5.2.50 - EXRAIL ONBUTTON/ONSENSOR observe LATCH
// 5.2.49 - EXRAIL additions: // 5.2.49 - EXRAIL additions: