From 0b9ec7460ba461d5602b6e06843d6be8468f385f Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sat, 28 Oct 2023 19:18:59 +0200 Subject: [PATCH 01/10] Bugfix version detection logic and better message --- WifiInterface.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/WifiInterface.cpp b/WifiInterface.cpp index ab36957..27830bb 100644 --- a/WifiInterface.cpp +++ b/WifiInterface.cpp @@ -206,12 +206,13 @@ wifiSerialState WifiInterface::setup2(const FSH* SSid, const FSH* password, 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; - } + } + if ((version[0] == '0') || + (version[0] == '2' && version[2] == '0') || + (version[0] == '2' && version[2] == '2' && version[4] == '0' && version[6] == '0')) { + DIAG(F("You need to up/downgrade the ESP firmware")); + SSid = F("UPDATE_ESP_FIRMWARE"); + forceAP = true; } } checkForOK(2000, true, false); From 659c58b30766a7b8dd2b4d2677d90663af8fefcf Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sat, 28 Oct 2023 19:20:33 +0200 Subject: [PATCH 02/10] version 5.0.5 --- version.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/version.h b/version.h index 1610054..69b9002 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.0.4" +#define VERSION "5.0.5" +// 5.0.5 - Bugfix version detection logic and better message // 5.0.4 - Bugfix: misses default roster. // 5.0.3 - Check bad AT firmware version // 5.0.2 - Bugfix: ESP32 30ms off time From 749a859db551113567faae3248c575dbf6440ece Mon Sep 17 00:00:00 2001 From: Asbelos Date: Wed, 1 Nov 2023 20:13:05 +0000 Subject: [PATCH 03/10] Bugfix TURNOUTL --- EXRAILMacros.h | 2 ++ version.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/EXRAILMacros.h b/EXRAILMacros.h index 66b0111..4bbabfc 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -172,6 +172,8 @@ void RMFT2::printMessage(uint16_t id) { #include "EXRAIL2MacroReset.h" #undef TURNOUT #define TURNOUT(id,addr,subaddr,description...) O_DESC(id,description) +#undef TURNOUTL +#define TURNOUTL(id,addr,description...) O_DESC(id,description) #undef PIN_TURNOUT #define PIN_TURNOUT(id,pin,description...) O_DESC(id,description) #undef SERVO_TURNOUT diff --git a/version.h b/version.h index 69b9002..196d9ca 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.0.5" +#define VERSION "5.0.6" +// 5.0.6 - Bugfix lost TURNOUTL description // 5.0.5 - Bugfix version detection logic and better message // 5.0.4 - Bugfix: misses default roster. // 5.0.3 - Check bad AT firmware version From a981f83bb9c376d01245c328c5de7d7bf25ebfb2 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 6 Nov 2023 22:11:31 +0100 Subject: [PATCH 04/10] Only flag 2.2.0.0-dev as broken, not 2.2.0.0 --- WifiInterface.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WifiInterface.cpp b/WifiInterface.cpp index 27830bb..8b2251a 100644 --- a/WifiInterface.cpp +++ b/WifiInterface.cpp @@ -201,15 +201,16 @@ wifiSerialState WifiInterface::setup2(const FSH* SSid, const FSH* password, // Display the AT version information StringFormatter::send(wifiStream, F("AT+GMR\r\n")); if (checkForOK(2000, F("AT version:"), true, false)) { - char version[] = "0.0.0.0"; - for (int i=0; i<8;i++) { + char version[] = "0.0.0.0-xxx"; + for (int i=0; i<11;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')) { + (version[0] == '2' && version[2] == '2' && version[4] == '0' && version[6] == '0' + && version[7] == '-' && version[8] == 'd' && version[9] == 'e' && version[10] == 'v')) { DIAG(F("You need to up/downgrade the ESP firmware")); SSid = F("UPDATE_ESP_FIRMWARE"); forceAP = true; From 387ea019bdc483667bcbcf45205a56330d615aee Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 6 Nov 2023 22:11:56 +0100 Subject: [PATCH 05/10] version 5.0.7 --- version.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/version.h b/version.h index 196d9ca..ca9e99f 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.0.6" +#define VERSION "5.0.7" +// 5.0.7 - Only flag 2.2.0.0-dev as broken, not 2.2.0.0 // 5.0.6 - Bugfix lost TURNOUTL description // 5.0.5 - Bugfix version detection logic and better message // 5.0.4 - Bugfix: misses default roster. From c5168f030fa64330a1f0e09d6637a3817fe5e067 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Wed, 10 Jan 2024 08:15:30 +0100 Subject: [PATCH 06/10] Do not crash on turnouts without description --- EXRAIL2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 0e17ea9..1d97e7f 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -259,8 +259,9 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { } void RMFT2::setTurnoutHiddenState(Turnout * t) { - // turnout descriptions are in low flash F strings - t->setHidden(GETFLASH(getTurnoutDescription(t->getId()))==0x01); + // turnout descriptions are in low flash F strings + const FSH *desc = getTurnoutDescription(t->getId()); + if (desc) t->setHidden(GETFLASH(desc)==0x01); } char RMFT2::getRouteType(int16_t id) { From 818e05b4253a1a0980abb3a0bbef38a8c662bb1a Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Wed, 10 Jan 2024 08:37:54 +0100 Subject: [PATCH 07/10] version 5.0.8 --- version.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/version.h b/version.h index ca9e99f..bb5bef8 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.0.7" +#define VERSION "5.0.8" +// 5.0.8 - Bugfix: Do not crash on turnouts without description // 5.0.7 - Only flag 2.2.0.0-dev as broken, not 2.2.0.0 // 5.0.6 - Bugfix lost TURNOUTL description // 5.0.5 - Bugfix version detection logic and better message From fb414a7a506f078d2a075d65c7b171ae4399ef63 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Thu, 18 Jan 2024 08:20:33 +0100 Subject: [PATCH 08/10] Bugfix: allocate enough bytes for digital pins. Add more sanity checks when allocating memory --- IO_EXIOExpander.h | 88 +++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 675d66c..db08e70 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -1,5 +1,6 @@ /* * © 2022, Peter Cole. All rights reserved. + * © 2024, Harald Barth. All rights reserved. * * This file is part of EX-CommandStation * @@ -98,34 +99,53 @@ private: _numAnaloguePins = receiveBuffer[2]; // See if we already have suitable buffers assigned - size_t digitalBytesNeeded = (_numDigitalPins + 7) / 8; - if (_digitalPinBytes < digitalBytesNeeded) { - // Not enough space, free any existing buffer and allocate a new one - if (_digitalPinBytes > 0) free(_digitalInputStates); - _digitalInputStates = (byte*) calloc(_digitalPinBytes, 1); - _digitalPinBytes = digitalBytesNeeded; - } - size_t analogueBytesNeeded = _numAnaloguePins * 2; - if (_analoguePinBytes < analogueBytesNeeded) { - // Free any existing buffers and allocate new ones. - if (_analoguePinBytes > 0) { - free(_analogueInputBuffer); - free(_analogueInputStates); - free(_analoguePinMap); + if (_numDigitalPins>0) { + size_t digitalBytesNeeded = (_numDigitalPins + 7) / 8; + if (_digitalPinBytes < digitalBytesNeeded) { + // Not enough space, free any existing buffer and allocate a new one + if (_digitalPinBytes > 0) free(_digitalInputStates); + if ((_digitalInputStates = (byte*) calloc(digitalBytesNeeded, 1)) != NULL) { + _digitalPinBytes = digitalBytesNeeded; + } else { + DIAG(F("EX-IOExpander I2C:%s ERROR alloc %d bytes"), _I2CAddress.toString(), digitalBytesNeeded); + _deviceState = DEVSTATE_FAILED; + _digitalPinBytes = 0; + return; + } } - _analogueInputStates = (uint8_t*) calloc(analogueBytesNeeded, 1); - _analogueInputBuffer = (uint8_t*) calloc(analogueBytesNeeded, 1); - _analoguePinMap = (uint8_t*) calloc(_numAnaloguePins, 1); - _analoguePinBytes = analogueBytesNeeded; } - } else { - DIAG(F("EX-IOExpander I2C:%s ERROR configuring device"), _I2CAddress.toString()); - _deviceState = DEVSTATE_FAILED; - return; - } - } - // We now need to retrieve the analogue pin map - if (status == I2C_STATUS_OK) { + if (_numAnaloguePins>0) { + size_t analogueBytesNeeded = _numAnaloguePins * 2; + if (_analoguePinBytes < analogueBytesNeeded) { + // Free any existing buffers and allocate new ones. + if (_analoguePinBytes > 0) { + free(_analogueInputBuffer); + free(_analogueInputStates); + free(_analoguePinMap); + } + _analogueInputStates = (uint8_t*) calloc(analogueBytesNeeded, 1); + _analogueInputBuffer = (uint8_t*) calloc(analogueBytesNeeded, 1); + _analoguePinMap = (uint8_t*) calloc(_numAnaloguePins, 1); + if (_analogueInputStates != NULL && + _analogueInputBuffer != NULL && + _analoguePinMap != NULL) { + _analoguePinBytes = analogueBytesNeeded; + } else { + DIAG(F("EX-IOExpander I2C:%s ERROR alloc analog pin bytes"), _I2CAddress.toString()); + _deviceState = DEVSTATE_FAILED; + _analoguePinBytes = 0; + return; + } + } + } + } else { + DIAG(F("EX-IOExpander I2C:%s ERROR configuring device"), _I2CAddress.toString()); + _deviceState = DEVSTATE_FAILED; + return; + } + } + // We now need to retrieve the analogue pin map if there are analogue pins + if (status == I2C_STATUS_OK && _numAnaloguePins>0) { commandBuffer[0] = EXIOINITA; status = I2CManager.read(_I2CAddress, _analoguePinMap, _numAnaloguePins, commandBuffer, 1); } @@ -239,7 +259,7 @@ private: // If we're not doing anything now, check to see if a new input transfer is due. if (_readState == RDS_IDLE) { - if (currentMicros - _lastDigitalRead > _digitalRefresh) { // Delay for digital read refresh + if (_numDigitalPins>0 && currentMicros - _lastDigitalRead > _digitalRefresh) { // Delay for digital read refresh // Issue new read request for digital states. As the request is non-blocking, the buffer has to // be allocated from heap (object state). _readCommandBuffer[0] = EXIORDD; @@ -247,7 +267,7 @@ private: // non-blocking read _lastDigitalRead = currentMicros; _readState = RDS_DIGITAL; - } else if (currentMicros - _lastAnalogueRead > _analogueRefresh) { // Delay for analogue read refresh + } else if (_numAnaloguePins>0 && currentMicros - _lastAnalogueRead > _analogueRefresh) { // Delay for analogue read refresh // Issue new read for analogue input states _readCommandBuffer[0] = EXIORDAN; I2CManager.read(_I2CAddress, _analogueInputBuffer, @@ -362,14 +382,14 @@ private: uint8_t _minorVer = 0; uint8_t _patchVer = 0; - uint8_t* _digitalInputStates; - uint8_t* _analogueInputStates; - uint8_t* _analogueInputBuffer; // buffer for I2C input transfers + uint8_t* _digitalInputStates = NULL; + uint8_t* _analogueInputStates = NULL; + uint8_t* _analogueInputBuffer = NULL; // buffer for I2C input transfers uint8_t _readCommandBuffer[1]; - uint8_t _digitalPinBytes = 0; // Size of allocated memory buffer (may be longer than needed) - uint8_t _analoguePinBytes = 0; // Size of allocated memory buffers (may be longer than needed) - uint8_t* _analoguePinMap; + uint8_t _digitalPinBytes = 0; // Size of allocated memory buffer (may be longer than needed) + uint8_t _analoguePinBytes = 0; // Size of allocated memory buffer (may be longer than needed) + uint8_t* _analoguePinMap = NULL; I2CRB _i2crb; enum {RDS_IDLE, RDS_DIGITAL, RDS_ANALOGUE}; // Read operation states From 3b162996ad42546486b812e22d3ed6daee857d19 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sun, 21 Jan 2024 07:13:53 +1000 Subject: [PATCH 09/10] EX-IO fixes in version --- version.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/version.h b/version.h index bb5bef8..bf7048f 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,9 @@ #include "StringFormatter.h" -#define VERSION "5.0.8" +#define VERSION "5.0.9" +// 5.0.9 - EX-IOExpander bug fix for memory allocation +// - EX-IOExpander bug fix to allow for devices with no analogue or no digital pins // 5.0.8 - Bugfix: Do not crash on turnouts without description // 5.0.7 - Only flag 2.2.0.0-dev as broken, not 2.2.0.0 // 5.0.6 - Bugfix lost TURNOUTL description From 28d60d49849c8fc4b0ff0f933222c052ba7c90aa Mon Sep 17 00:00:00 2001 From: Peter Akers Date: Fri, 16 Feb 2024 18:02:40 +1000 Subject: [PATCH 10/10] Update README.md --- README.md | 82 +++++++++++++++---------------------------------------- 1 file changed, 22 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index f820075..9c8f627 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,39 @@ -# What is DCC++ EX? -DCC++ EX is the organization maintaining several codebases that together represent a fully open source DCC system. Currently, this includes the following: +# What is DCC-EX? +DCC-EX is a team of dedicated enthusiasts producing open source DCC & DC solutions for you to run your complete model railroad layout. Our easy to use, do-it-yourself, and free open source products run on off-the-shelf Arduino technology and are supported by numerous third party hardware and apps like JMRI, Engine Driver, wiThrottle, Rocrail and more. -* [CommandStation-EX](https://github.com/DCC-EX/CommandStation-EX/releases) - the latest take on the DCC++ command station for controlling your trains. Runs on an Arduino board, and includes advanced features such as a WiThrottle server implementation, turnout operation, general purpose inputs and outputs (I/O), and JMRI integration. -* [exWebThrottle](https://github.com/DCC-EX/exWebThrottle) - a simple web based controller for your DCC++ command station. -* [BaseStation-installer](https://github.com/DCC-EX/BaseStation-Installer) - an installer executable that takes care of downloading and installing DCC++ firmware onto your hardware setup. -* [BaseStation-Classic](https://github.com/DCC-EX/BaseStation-Classic) - the original DCC++ software, packaged in a stable release. No active development, bug fixes only. +Currently, our products include the following: -A basic DCC++ EX hardware setup can use easy to find, widely avalable Arduino boards that you can assemble yourself. - -Both CommandStation-EX and BaseStation-Classic support much of the NMRA Digital Command Control (DCC) [standards](http://www.nmra.org/dcc-working-group "NMRA DCC Working Group"), including: - -* simultaneous control of multiple locomotives -* 2-byte and 4-byte locomotive addressing -* 28 or 128-step speed throttling -* Activate/de-activate all accessory function addresses 0-2048 -* Control of all cab functions F0-F28 and F29-F68 -* Main Track: Write configuration variable bytes and set/clear specific configuration variable (CV) bits (aka Programming on Main or POM) -* Programming Track: Same as the main track with the addition of reading configuration variable bytes -* And many more custom features. see [What's new in CommandStation-EX?](#whats-new-in-commandstation-ex) +* [EX-CommandStation](https://github.com/DCC-EX/CommandStation-EX/releases) +* [EX-WebThrottle](https://github.com/DCC-EX/exWebThrottle) +* [EX-Installer](https://github.com/DCC-EX/EX-Installer) +* [EX-MotoShield8874](https://dcc-ex.com/reference/hardware/motorboards/ex-motor-shield-8874.html#gsc.tab=0) +* [EX-DCCInspector](https://github.com/DCC-EX/DCCInspector-EX) +* [EX-Toolbox](https://github.com/DCC-EX/EX-Toolbox) +* [EX-Turntable](https://github.com/DCC-EX/EX-Turntable) +* [EX-IOExpander](https://github.com/DCC-EX/EX-IOExpander) +* [EX-FastClock](https://github.com/DCC-EX/EX-FastClock) +* [DCCEXProtocol](https://github.com/DCC-EX/DCCEXProtocol) +Details of these projects can be found on [our web site](https://dcc-ex.com/). # What’s in this Repository? -This repository, CommandStation-EX, contains a complete DCC++ EX Commmand Station sketch designed for compiling and uploading into an Arduino Uno, Mega, or Nano. +This repository, CommandStation-EX, contains a complete DCC-EX *EX-CommmandStation* sketch designed for compiling and uploading into an Arduino Uno, Mega, or Nano. To utilize this sketch, you can use the following: -1. (beginner) our [automated installer](https://github.com/DCC-EX/BaseStation-Installer) +1. (recommended for all levels of user) our [automated installer](https://github.com/DCC-EX/EX-Installer) 2. (intermediate) download the latest version from the [releases page](https://github.com/DCC-EX/CommandStation-EX/releases) 3. (advanced) use git clone on this repository -Not using the installer? Open the file "CommandStation-EX.ino" in the -Arduino IDE. Please do not rename the folder containing the sketch -code, nor add any files in that folder. The Arduino IDE relies on the -structure and name of the folder to properly display and compile the -code. Rename or copy config.example.h to config.h. If you do not have -the standard setup, you must edit config.h according to the help texts -in config.h. +Refer to [our web site](https://https://dcc-ex.com/ex-commandstation/get-started/index.html#/) for the hardware required for this project. -## What's new in CommandStation-EX? +**We seriously recommend using the EX-Installer**, however if you choose not to use the installer... -* WiThrottle server built in. Connect Engine Driver or WiThrottle clients directly to your Command Station (or through JMRI as before) -* WiFi and Ethernet shield support -* No more jumpers or soldering! -* Direct support for all the most popular motor control boards including single pin (Arduino) or dual pin (IBT_2) type PWM inputs without the need for an adapter circuit -* I2C Display support (LCD and OLED) -* Improved short circuit detection and automatic reset from an overload -* Current reading, sensing and ACK detection settings in milliAmps instead of just pin readings -* Improved adherence to the NMRA DCC specification -* Complete support for all the old commands and front ends like JMRI -* Railcom cutout (beta) -* Simpler, modular, faster code with an API Library for developers for easy expansion -* New features and functions in JMRI -* Ability to join MAIN and PROG tracks into one MAIN track to run your locos -* "Drive-Away" feature - Throttles with support, like Engine Driver, can allow a loco to be programmed on a usable, electrically isolated programming track and then drive off onto the main track -* Diagnostic commands to test decoders that aren't reading or writing correctly -* Support for Uno, Nano, Mega, Nano Every and Teensy microcontrollers -* User Functions: Filter regular commands (like a turnout or output command) and pass it to your own function or accessory -* Support for LCN (layout control nodes) -* mySetup.h file that acts like an Autoexec.Bat command to send startup commands to the CS -* High Accuracty Waveform option for rock steady DCC signals -* New current response outputs current in mA, overlimit current, and maximum board capable current. Support for new current meter in JMRI -* USB Browser based EX-WebThrottle -* New, simpler, function control command -* Number of locos discovery command `<#>` -* Emergency stop command -* Release cabs from memory command <-> all cabs, <- CAB> for just one loco address -* Automatic slot (register) management -* Automation (coming soon) - -NOTE: DCC-EX is a major rewrite to the code. We started over and rebuilt it from the ground up! For what that means, you can read [HERE](https://dcc-ex.com/about/rewrite.html). +* Open the file ``CommandStation-EX.ino`` in the Arduino IDE or Visual Studio Code (VSC). Please do not rename the folder containing the sketch code, nor add any files in that folder. The Arduino IDE relies on the structure and name of the folder to properly display and compile the code. +* Rename or copy ``config.example.h`` to ``config.h``. +* You must edit ``config.h`` according to the help texts in ``config.h``. # More information -You can learn more at the [DCC++ EX website](https://dcc-ex.com/) +You can learn more at the [DCC-EX website](https://dcc-ex.com/) -- November 14, 2020