From f0cd96fed3985a8dd3ebd54537aeb047c48473d2 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 23 Aug 2021 12:43:14 +0100 Subject: [PATCH 01/10] Changes associated with RCN-213 DCC Accessory Packet format --- DCCEXParser.cpp | 4 ++-- LCDDisplay.h | 4 +--- Turnouts.cpp | 42 ++++++++++++++++++++++++++---------------- Turnouts.h | 23 ++++++++++++++--------- config.example.h | 23 +++++++++++++++++++++++ 5 files changed, 66 insertions(+), 30 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 2c50ac1..a6a68d8 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -682,10 +682,10 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) // By default turnout command uses 0=throw, 1=close, // but legacy DCC++ behaviour is 1=throw, 0=close. case 0: - state = Turnout::useLegacyTurnoutBehaviour; + state = Turnout::useClassicTurnoutCommands; break; case 1: - state = !Turnout::useLegacyTurnoutBehaviour; + state = !Turnout::useClassicTurnoutCommands; break; case HASH_KEYWORD_C: state = true; diff --git a/LCDDisplay.h b/LCDDisplay.h index 15ba524..6c6e150 100644 --- a/LCDDisplay.h +++ b/LCDDisplay.h @@ -21,9 +21,7 @@ #include #include "DisplayInterface.h" -#if __has_include ( "config.h") - #include "config.h" -#endif +#include "defines.h" // includes config.h as well // Allow maximum message length to be overridden from config.h #if !defined(MAX_MSG_SIZE) diff --git a/Turnouts.cpp b/Turnouts.cpp index 7b87153..a959cdd 100644 --- a/Turnouts.cpp +++ b/Turnouts.cpp @@ -20,13 +20,8 @@ * along with CommandStation. If not, see . */ -// Set the following definition to true for = throw and = close -// or to false for = close and = throw (the original way). -#ifndef USE_LEGACY_TURNOUT_BEHAVIOUR -#define USE_LEGACY_TURNOUT_BEHAVIOUR false -#endif -#include "defines.h" +#include "defines.h" // includes config.h #include "EEStore.h" #include "StringFormatter.h" #include "RMFT2.h" @@ -47,7 +42,12 @@ * Public static data */ int Turnout::turnoutlistHash = 0; - bool Turnout::useLegacyTurnoutBehaviour = USE_LEGACY_TURNOUT_BEHAVIOUR; + + #if defined(USE_RCN_213_TURNOUT_COMMANDS) + const bool Turnout::useClassicTurnoutCommands = false; + #else + const bool Turnout::useClassicTurnoutCommands = true; + #endif /* * Protected static functions @@ -74,9 +74,11 @@ turnoutlistHash++; } + // For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed; + // if consistency with RCN-213 has been selected, it is 0 for thrown and 1 for closed. void Turnout::printState(Print *stream) { StringFormatter::send(stream, F("\n"), - _turnoutData.id, _turnoutData.closed ^ useLegacyTurnoutBehaviour); + _turnoutData.id, _turnoutData.closed ^ useClassicTurnoutCommands); } // Remove nominated turnout from turnout linked list and delete the object. @@ -279,10 +281,12 @@ return tt; } + // For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed; + // if consistency with RCN-213 has been selected, it is 0 for thrown and 1 for closed. void ServoTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, _servoTurnoutData.vpin, _servoTurnoutData.thrownPosition, _servoTurnoutData.closedPosition, _servoTurnoutData.profile, - _turnoutData.closed ^ useLegacyTurnoutBehaviour); + _turnoutData.closed ^ useClassicTurnoutCommands); } // ServoTurnout-specific code for throwing or closing a servo turnout. @@ -312,6 +316,12 @@ * *************************************************************************************/ +#if defined(DCC_TURNOUTS_RCN_213) + const bool DCCTurnout::rcn213Compliant = true; +#else + const bool DCCTurnout::rcn213Compliant = false; +#endif + // DCCTurnoutData contains data specific to this subclass that is // written to EEPROM when the turnout is saved. struct DCCTurnoutData { @@ -363,19 +373,19 @@ void DCCTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, (((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3), - _turnoutData.closed ^ useLegacyTurnoutBehaviour); - // Also report using classic DCC++ syntax for DCC accessory turnouts + _turnoutData.closed ^ useClassicTurnoutCommands); + // Also report using classic DCC++ syntax for DCC accessory turnouts, since JMRI expects this. StringFormatter::send(stream, F("\n"), _turnoutData.id, (((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3), - _turnoutData.closed ^ useLegacyTurnoutBehaviour); + _turnoutData.closed ^ useClassicTurnoutCommands); } bool DCCTurnout::setClosedInternal(bool close) { // DCC++ Classic behaviour is that Throw writes a 1 in the packet, // and Close writes a 0. - // RCN-214 specifies that Throw is 0 and Close is 1. + // RCN-213 specifies that Throw is 0 and Close is 1. DCC::setAccessory((((_dccTurnoutData.address-1) >> 2) + 1), - ((_dccTurnoutData.address-1) & 3), close ^ useLegacyTurnoutBehaviour); + ((_dccTurnoutData.address-1) & 3), close ^ !rcn213Compliant); _turnoutData.closed = close; return true; } @@ -439,7 +449,7 @@ void VpinTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, _vpinTurnoutData.vpin, - _turnoutData.closed ^ useLegacyTurnoutBehaviour); + _turnoutData.closed ^ useClassicTurnoutCommands); } bool VpinTurnout::setClosedInternal(bool close) { @@ -503,6 +513,6 @@ void LCNTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, - _turnoutData.closed ^ useLegacyTurnoutBehaviour); + _turnoutData.closed ^ useClassicTurnoutCommands); } diff --git a/Turnouts.h b/Turnouts.h index 45f60a6..27b1444 100644 --- a/Turnouts.h +++ b/Turnouts.h @@ -104,8 +104,8 @@ public: * Static data */ static int turnoutlistHash; - static bool useLegacyTurnoutBehaviour; - + static const bool useClassicTurnoutCommands; + /* * Public base class functions */ @@ -182,11 +182,12 @@ private: } _servoTurnoutData; // 6 bytes // Constructor - ServoTurnout(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed = true); + ServoTurnout(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed); public: // Create function - static Turnout *create(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed = true); + // If the initial state isn't specified, use true for RCN-213 consistency and false for DCC++ classic compatibility. + static Turnout *create(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed = !useClassicTurnoutCommands); // Load a Servo turnout definition from EEPROM. The common Turnout data has already been read at this point. static Turnout *load(struct TurnoutData *turnoutData); @@ -223,6 +224,8 @@ public: static Turnout *load(struct TurnoutData *turnoutData); void print(Print *stream) override; + static const bool rcn213Compliant; + protected: bool setClosedInternal(bool close) override; void save() override; @@ -243,11 +246,12 @@ private: } _vpinTurnoutData; // 2 bytes // Constructor - VpinTurnout(uint16_t id, VPIN vpin, bool closed=true); + VpinTurnout(uint16_t id, VPIN vpin, bool closed); public: // Create function - static Turnout *create(uint16_t id, VPIN vpin, bool closed=true); + // If the initial state isn't specified, use true for RCN-213 consistency and false for DCC++ classic compatibility. + static Turnout *create(uint16_t id, VPIN vpin, bool closed=!useClassicTurnoutCommands); // Load a VPIN turnout definition from EEPROM. The common Turnout data has already been read at this point. static Turnout *load(struct TurnoutData *turnoutData); @@ -270,12 +274,13 @@ private: // struct LCNTurnoutData { // } _lcnTurnoutData; // 0 bytes - // Constructor - LCNTurnout(uint16_t id, bool closed=true); + // Constructor + LCNTurnout(uint16_t id, bool closed); public: // Create function - static Turnout *create(uint16_t id, bool closed=true); + // If the initial state isn't specified, use true for RCN-213 consistency and false for DCC++ classic compatibility. + static Turnout *create(uint16_t id, bool closed=!useClassicTurnoutCommands); bool setClosedInternal(bool close) override; diff --git a/config.example.h b/config.example.h index 0debbc2..3575cb0 100644 --- a/config.example.h +++ b/config.example.h @@ -129,4 +129,27 @@ The configuration file for DCC-EX Command Station #define SCROLLMODE 1 ///////////////////////////////////////////////////////////////////////////////////// +// +// DEFINE TURNOUTS/ACCESSORIES FOLLOW NORM RCN-213 +// +// According to norm RCN-213 a DCC packet with a 1 is closed/straight +// and one with a 0 is thrown/diverging. In DCC++ Classic, and in previous +// versions of DCC++EX, a throw command was implemented in the packet as +// '1' and a close command as '0'. The #define below makes the states +// match with the norm. But we don't want to cause havoc on existent layouts, +// so we define this only for new installations. If you don't want this, +// don't add it to your config.h. +#define DCC_TURNOUTS_RCN_213 +// In addition to the above, there is an option to allow the values in the commands +// sent and received from JMRI to be changed to be consistent with the definition in +// RCN-213. In DCC++ Classic and in previous versions of DCC++EX, a command +// requested a 'throw' and requested a 'close'. +// The macro below, when present, allows this behaviour to be reversed so that a +// requests the turnout to 'close' and requests it to 'throw'. +// This should only be used if the command processor (JMRI) writing to the serial port +// supports it, otherwise turnout operation commands received over the serial port +// will be reversed. +//#define USE_RCN_213_TURNOUT_COMMANDS + +///////////////////////////////////////////////////////////////////////////////////// From 69c4733f2b2c94837cdde5b14a5073977ae1eea0 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 23 Aug 2021 15:26:23 +0100 Subject: [PATCH 02/10] Initialise turnouts to Closed by default Ensure that the servo, VPIN and LCN turnouts are all initialised to closed if no initial state is provided in the create call or in EEPROM. This applies irrespective of the RCN-213 configuration settings. --- Turnouts.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Turnouts.h b/Turnouts.h index 27b1444..e1cf075 100644 --- a/Turnouts.h +++ b/Turnouts.h @@ -186,8 +186,7 @@ private: public: // Create function - // If the initial state isn't specified, use true for RCN-213 consistency and false for DCC++ classic compatibility. - static Turnout *create(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed = !useClassicTurnoutCommands); + static Turnout *create(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed=true); // Load a Servo turnout definition from EEPROM. The common Turnout data has already been read at this point. static Turnout *load(struct TurnoutData *turnoutData); @@ -223,7 +222,7 @@ public: // Load a VPIN turnout definition from EEPROM. The common Turnout data has already been read at this point. static Turnout *load(struct TurnoutData *turnoutData); void print(Print *stream) override; - + // Flag whether DCC Accessory packets are to contain 1=close/0=throw(RCN-213) or 1=throw/0-close (DCC++ Classic) static const bool rcn213Compliant; protected: @@ -250,8 +249,7 @@ private: public: // Create function - // If the initial state isn't specified, use true for RCN-213 consistency and false for DCC++ classic compatibility. - static Turnout *create(uint16_t id, VPIN vpin, bool closed=!useClassicTurnoutCommands); + static Turnout *create(uint16_t id, VPIN vpin, bool closed=true); // Load a VPIN turnout definition from EEPROM. The common Turnout data has already been read at this point. static Turnout *load(struct TurnoutData *turnoutData); @@ -279,8 +277,7 @@ private: public: // Create function - // If the initial state isn't specified, use true for RCN-213 consistency and false for DCC++ classic compatibility. - static Turnout *create(uint16_t id, bool closed=!useClassicTurnoutCommands); + static Turnout *create(uint16_t id, bool closed=true); bool setClosedInternal(bool close) override; From 0d235b65d3e91a539dd57bb925d16e933ed26534 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 23 Aug 2021 17:36:50 +0100 Subject: [PATCH 03/10] Turnouts - make code clearer. Overlay of flags bits added in struct TurnoutData,, called flags. This simplifies the the EEPROM update code. --- Turnouts.cpp | 6 +++--- Turnouts.h | 11 ++++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Turnouts.cpp b/Turnouts.cpp index a959cdd..8c022d0 100644 --- a/Turnouts.cpp +++ b/Turnouts.cpp @@ -139,7 +139,7 @@ // Write byte containing new closed/thrown state to EEPROM if required. Note that eepromAddress // is always zero for LCN turnouts. if (EEStore::eeStore->data.nTurnouts > 0 && tt->_eepromAddress > 0) - EEPROM.put(tt->_eepromAddress, *((uint8_t *) &tt->_turnoutData)); + EEPROM.put(tt->_eepromAddress, tt->_turnoutData.flags); #if defined(RMFT_ACTIVE) RMFT2::turnoutEvent(id, closeFlag); @@ -174,7 +174,7 @@ Turnout *tt = 0; // Read turnout type from EEPROM struct TurnoutData turnoutData; - int eepromAddress = EEStore::pointer(); // Address of byte containing the closed flag. + int eepromAddress = EEStore::pointer() + offsetof(struct TurnoutData, flags); // Address of byte containing the closed flag. EEPROM.get(EEStore::pointer(), turnoutData); EEStore::advance(sizeof(turnoutData)); @@ -198,7 +198,7 @@ } if (tt) { // Save EEPROM address in object. Note that LCN turnouts always have eepromAddress of zero. - tt->_eepromAddress = eepromAddress; + tt->_eepromAddress = eepromAddress + offsetof(struct TurnoutData, flags); } #ifdef EESTOREDEBUG diff --git a/Turnouts.h b/Turnouts.h index e1cf075..9c14089 100644 --- a/Turnouts.h +++ b/Turnouts.h @@ -53,9 +53,14 @@ protected: // vice versa. If the turnout has been saved, then this byte is rewritten // when changed in RAM. The 'closed' flag must be located in the first byte. struct TurnoutData { - bool closed : 1; - bool _rfu: 2; - uint8_t turnoutType : 5; + union { + struct { + bool closed : 1; + bool _rfu: 2; + uint8_t turnoutType : 5; + }; + uint8_t flags; + }; uint16_t id; } _turnoutData; // 3 bytes From 425de3fcc79fd8fe4262b8ec8aee617e05580d97 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Mon, 23 Aug 2021 20:41:30 +0100 Subject: [PATCH 04/10] Create mySetup.cpp_example.txt Provide an example showing directives for HAL device configuration. --- mySetup.cpp_example.txt | 139 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 mySetup.cpp_example.txt diff --git a/mySetup.cpp_example.txt b/mySetup.cpp_example.txt new file mode 100644 index 0000000..949088a --- /dev/null +++ b/mySetup.cpp_example.txt @@ -0,0 +1,139 @@ +// Sample mySetup.cpp file. +// +// To use this file, copy it to mySetup.cpp and uncomment the directives and/or +// edit them to satisfy your requirements. + +// Note that if the file has a .cpp extension it WILL be compiled into the build +// and the mySetup() function WILL be invoked. +// +// To prevent this, temporarily rename it to mySetup.txt or similar. +// + +#include "IODevice.h" +#include "Turnouts.h" +#include "Sensors.h" +#include "IO_HCSR04.h" + + +// The #if directive prevent compile errors for Uno and Nano by excluding the +// HAL directives from the build. +#if !defined(IO_NO_HAL) + + +// Examples of statically defined HAL directives (alternative to the create() call). +// These have to be outside of the mySetup() function. + + +// The following directive defines a PCA9685 PWM Servo driver module. +// The parameters are: +// First Vpin=100 +// Number of VPINs=16 (numbered 100-115) +// I2C address of module=0x40 + +//PCA9685 pwmModule1(100, 16, 0x40); + + +// The following directive defines an MCP23017 16-port I2C GPIO Extender module. +// The parameters are: +// First Vpin=164 +// Number of VPINs=16 (numbered 164-179) +// I2C address of module=0x20 + +//MCP23017 gpioModule2(164, 16, 0x20); + + +// Alternative form, which allows the INT pin of the module to request a scan +// by pulling Arduino pin 40 to ground. Means that the I2C isn't being polled +// all the time, only when a change takes place. Multiple modules' INT pins +// may be connected to the same Arduino pin. + +//MCP23017 gpioModule2(164, 16, 0x20, 40); + + +// The following directive defines an MCP23008 8-port I2C GPIO Extender module. +// The parameters are: +// First Vpin=300 +// Number of VPINs=8 (numbered 300-307) +// I2C address of module=0x22 + +//MCP23017 gpioModule3(300, 8, 0x22); + + +// The following directive defines a PCF8574 8-port I2C GPIO Extender module. +// The parameters are: +// First Vpin=200 +// Number of VPINs=8 (numbered 200-207) +// I2C address of module=0x23 + +//PCF8574 gpioModule4(200, 8, 0x23); + + +// Alternative form using INT pin (see above) + +//PCF8574 gpioModule4(200, 8, 0x23, 40); + + +// The following directive defines an HCSR04 ultrasonic module. +// The parameters are: +// Vpin=2000 (only one VPIN per directive) +// Number of VPINs=1 +// Arduino pin connected to TRIG=30 +// Arduino pin connected to ECHO=31 +// Minimum trigger range=20cm (VPIN goes to 1 when <20cm) +// Maximum trigger range=25cm (VPIN goes to 0 when >25cm) +// Note: Multiple devices can be configured by using a different ECHO pin +// for each one. The TRIG pin can be shared between multiple devices. +// Be aware that the 'ping' of one device may be received by another +// device and position them accordingly! + +//HCSR04 sonarModule1(2000, 30, 31, 20, 25); +//HCSR04 sonarModule2(2001, 30, 32, 20, 25); + + +// The function mySetup() is invoked from CS if it exists within the build. +// It is called just before mysetup.h is executed, so things set up within here can be +// referenced by commands in mySetup.h. + +void mySetup() { + + // Alternative way of creating MCP23017, which has to be within the mySetup() function + // The other devices can also be created in this way. The parameter lists for the + // create() function are identical to the parameter lists for the declarations. + + //MCP23017::create(180, 16, 0x21); + + + // Creating a Turnout + // Parameters: same as command for Servo turnouts + // ID and VPIN are 100, sonar moves between positions 102 and 490 with slow profile. + // Profile may be Instant, Fast, Medium, Slow or Bounce. + + //ServoTurnout::create(100, 100, 490, 102, PCA9685::Slow); + + + // DCC Accessory turnout + // Parameters: same as command for DCC Accessory turnouts + // ID=3000 + // Decoder address=23 + // Decoder subaddress = 1 + + //DCCTurnout::create(3000, 23, 1); + + + // Creating a Sensor + // Parameters: As for the command, + // id = 164, + // Vpin = 164 (configured above as pin 0 of an MCP23017) + // Pullup enable = 1 (enabled) + + //Sensor::create(164, 164, 1); + + + // Way of creating lots of identical sensors in a range + + //for (int i=165; i<180; i++) + // Sensor::create(i, i, 1); + +} + +#endif From c45337d5d488048bea04c721fdea77b793791085 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Tue, 24 Aug 2021 22:13:52 +0100 Subject: [PATCH 05/10] Enable pullups for Arduino input pins as a default (to match GPIO Extender modules). --- IODevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IODevice.cpp b/IODevice.cpp index 43db2f6..f151923 100644 --- a/IODevice.cpp +++ b/IODevice.cpp @@ -292,7 +292,7 @@ ArduinoPins::ArduinoPins(VPIN firstVpin, int nPins) { _pinPullups = (uint8_t *)calloc(2, arrayLen); _pinModes = (&_pinPullups[0]) + arrayLen; for (int i=0; i Date: Tue, 24 Aug 2021 22:15:50 +0100 Subject: [PATCH 06/10] Enable pullups for Arduino input pins as a default --- IODevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IODevice.cpp b/IODevice.cpp index f151923..e7b9dbd 100644 --- a/IODevice.cpp +++ b/IODevice.cpp @@ -292,7 +292,7 @@ ArduinoPins::ArduinoPins(VPIN firstVpin, int nPins) { _pinPullups = (uint8_t *)calloc(2, arrayLen); _pinModes = (&_pinPullups[0]) + arrayLen; for (int i=0; i Date: Tue, 24 Aug 2021 22:18:51 +0100 Subject: [PATCH 07/10] Revert to original DCC++ Classic Turnout command polarity. Revert to command being 'throw' and being 'close', for turnouts. --- DCCEXParser.cpp | 11 +++-------- Turnouts.cpp | 26 ++++++++++---------------- config.example.h | 11 ----------- 3 files changed, 13 insertions(+), 35 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index a6a68d8..f44df2f 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -679,22 +679,17 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) { bool state = false; switch (p[1]) { - // By default turnout command uses 0=throw, 1=close, - // but legacy DCC++ behaviour is 1=throw, 0=close. + // Turnout messages use 1=throw, 0=close. case 0: - state = Turnout::useClassicTurnoutCommands; - break; - case 1: - state = !Turnout::useClassicTurnoutCommands; - break; case HASH_KEYWORD_C: state = true; break; + case 1: case HASH_KEYWORD_T: state= false; break; default: - return false; + return false; // Invalid parameter } if (!Turnout::setClosed(p[0], state)) return false; diff --git a/Turnouts.cpp b/Turnouts.cpp index 8c022d0..552cd9d 100644 --- a/Turnouts.cpp +++ b/Turnouts.cpp @@ -42,12 +42,6 @@ * Public static data */ int Turnout::turnoutlistHash = 0; - - #if defined(USE_RCN_213_TURNOUT_COMMANDS) - const bool Turnout::useClassicTurnoutCommands = false; - #else - const bool Turnout::useClassicTurnoutCommands = true; - #endif /* * Protected static functions @@ -75,10 +69,9 @@ } // For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed; - // if consistency with RCN-213 has been selected, it is 0 for thrown and 1 for closed. void Turnout::printState(Print *stream) { StringFormatter::send(stream, F("\n"), - _turnoutData.id, _turnoutData.closed ^ useClassicTurnoutCommands); + _turnoutData.id, !_turnoutData.closed); } // Remove nominated turnout from turnout linked list and delete the object. @@ -207,7 +200,7 @@ return tt; } - // Display, on the specified stream, the current state of the turnout (1 or 0). + // Display, on the specified stream, the current state of the turnout (1=thrown or 0=closed). void Turnout::printState(uint16_t id, Print *stream) { Turnout *tt = get(id); if (!tt) tt->printState(stream); @@ -281,12 +274,11 @@ return tt; } - // For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed; - // if consistency with RCN-213 has been selected, it is 0 for thrown and 1 for closed. + // For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed void ServoTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, _servoTurnoutData.vpin, _servoTurnoutData.thrownPosition, _servoTurnoutData.closedPosition, _servoTurnoutData.profile, - _turnoutData.closed ^ useClassicTurnoutCommands); + !_turnoutData.closed); } // ServoTurnout-specific code for throwing or closing a servo turnout. @@ -373,11 +365,11 @@ void DCCTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, (((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3), - _turnoutData.closed ^ useClassicTurnoutCommands); + !_turnoutData.closed); // Also report using classic DCC++ syntax for DCC accessory turnouts, since JMRI expects this. StringFormatter::send(stream, F("\n"), _turnoutData.id, (((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3), - _turnoutData.closed ^ useClassicTurnoutCommands); + !_turnoutData.closed); } bool DCCTurnout::setClosedInternal(bool close) { @@ -447,9 +439,10 @@ return tt; } + // Report 1 for thrown, 0 for closed. void VpinTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, _vpinTurnoutData.vpin, - _turnoutData.closed ^ useClassicTurnoutCommands); + !_turnoutData.closed); } bool VpinTurnout::setClosedInternal(bool close) { @@ -511,8 +504,9 @@ //void save() override { } //static Turnout *load(struct TurnoutData *turnoutData) { + // Report 1 for thrown, 0 for closed. void LCNTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, - _turnoutData.closed ^ useClassicTurnoutCommands); + !_turnoutData.closed); } diff --git a/config.example.h b/config.example.h index 3575cb0..6c5c69a 100644 --- a/config.example.h +++ b/config.example.h @@ -141,15 +141,4 @@ The configuration file for DCC-EX Command Station // don't add it to your config.h. #define DCC_TURNOUTS_RCN_213 -// In addition to the above, there is an option to allow the values in the commands -// sent and received from JMRI to be changed to be consistent with the definition in -// RCN-213. In DCC++ Classic and in previous versions of DCC++EX, a command -// requested a 'throw' and requested a 'close'. -// The macro below, when present, allows this behaviour to be reversed so that a -// requests the turnout to 'close' and requests it to 'throw'. -// This should only be used if the command processor (JMRI) writing to the serial port -// supports it, otherwise turnout operation commands received over the serial port -// will be reversed. -//#define USE_RCN_213_TURNOUT_COMMANDS - ///////////////////////////////////////////////////////////////////////////////////// From d0fed2dd3859795fc4cbfc4b3e0b3fc4ef4f77b7 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Tue, 24 Aug 2021 23:02:24 +0100 Subject: [PATCH 08/10] Make LCD output to I2C synchronous. Temporary work-around to problems with LCD driver, until I can look at it in depth. --- LiquidCrystal_I2C.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/LiquidCrystal_I2C.cpp b/LiquidCrystal_I2C.cpp index e6b3cdb..865868a 100644 --- a/LiquidCrystal_I2C.cpp +++ b/LiquidCrystal_I2C.cpp @@ -59,6 +59,8 @@ LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t lcd_cols, backlight(); lcdDisplay = this; } + // Initialise request block for comms. + requestBlock.setWriteParams(lcd_Addr, outputBuffer, sizeof(outputBuffer)); } void LiquidCrystal_I2C::begin() { @@ -190,13 +192,15 @@ void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) { mode |= _backlightval; uint8_t highnib = (((value >> 4) & 0x0f) << BACKPACK_DATA_BITS) | mode; uint8_t lownib = ((value & 0x0f) << BACKPACK_DATA_BITS) | mode; + // Wait for previous request to complete before writing to outputbuffer. + requestBlock.wait(); // Send both nibbles uint8_t len = 0; outputBuffer[len++] = highnib|En; outputBuffer[len++] = highnib; outputBuffer[len++] = lownib|En; outputBuffer[len++] = lownib; - I2CManager.write(_Addr, outputBuffer, len, &requestBlock); + I2CManager.write(_Addr, outputBuffer, len); } // write 4 data bits to the HD44780 LCD controller. @@ -210,7 +214,7 @@ void LiquidCrystal_I2C::write4bits(uint8_t value) { uint8_t len = 0; outputBuffer[len++] = _data|En; outputBuffer[len++] = _data; - I2CManager.write(_Addr, outputBuffer, len, &requestBlock); + I2CManager.write(_Addr, outputBuffer, len); } // write a byte to the PCF8574 I2C interface. We don't need to set @@ -219,5 +223,5 @@ void LiquidCrystal_I2C::expanderWrite(uint8_t value) { // Wait for previous request to complete before writing to outputbuffer. requestBlock.wait(); outputBuffer[0] = value | _backlightval; - I2CManager.write(_Addr, outputBuffer, 1, &requestBlock); + I2CManager.write(_Addr, outputBuffer, 1); } \ No newline at end of file From 80fc9e8a686293cc8c2009755efc73fe44d34e66 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Wed, 25 Aug 2021 00:29:57 +0100 Subject: [PATCH 09/10] Make LCD Display I2C calls synchronous. --- LiquidCrystal_I2C.cpp | 6 +++--- LiquidCrystal_I2C.h | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/LiquidCrystal_I2C.cpp b/LiquidCrystal_I2C.cpp index 865868a..d7953f7 100644 --- a/LiquidCrystal_I2C.cpp +++ b/LiquidCrystal_I2C.cpp @@ -200,7 +200,7 @@ void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) { outputBuffer[len++] = highnib; outputBuffer[len++] = lownib|En; outputBuffer[len++] = lownib; - I2CManager.write(_Addr, outputBuffer, len); + I2CManager.write(_Addr, outputBuffer, len); // Write command synchronously } // write 4 data bits to the HD44780 LCD controller. @@ -214,7 +214,7 @@ void LiquidCrystal_I2C::write4bits(uint8_t value) { uint8_t len = 0; outputBuffer[len++] = _data|En; outputBuffer[len++] = _data; - I2CManager.write(_Addr, outputBuffer, len); + I2CManager.write(_Addr, outputBuffer, len); // Write command synchronously } // write a byte to the PCF8574 I2C interface. We don't need to set @@ -223,5 +223,5 @@ void LiquidCrystal_I2C::expanderWrite(uint8_t value) { // Wait for previous request to complete before writing to outputbuffer. requestBlock.wait(); outputBuffer[0] = value | _backlightval; - I2CManager.write(_Addr, outputBuffer, 1); + I2CManager.write(_Addr, outputBuffer, 1); // Write command synchronously } \ No newline at end of file diff --git a/LiquidCrystal_I2C.h b/LiquidCrystal_I2C.h index 6d65541..6cd4384 100644 --- a/LiquidCrystal_I2C.h +++ b/LiquidCrystal_I2C.h @@ -90,7 +90,8 @@ private: I2CRB requestBlock; uint8_t outputBuffer[4]; - bool isBusy() { return requestBlock.isBusy(); } + // I/O is synchronous, so if this is called we're not busy! + bool isBusy() { return false; } }; #endif From fa04fa508448e49042828c5f3812bc8c132a942a Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Wed, 25 Aug 2021 00:34:19 +0100 Subject: [PATCH 10/10] I2C Manager, adjust loop code. loop() contains startTransaction which is called after handleInterrupt(). However, startTransaction is called within handleInterrupt so remove the extra call. This appears to solve strange problems encountered with the LCD display. --- I2CManager_NonBlocking.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/I2CManager_NonBlocking.h b/I2CManager_NonBlocking.h index 920cecd..41e9283 100644 --- a/I2CManager_NonBlocking.h +++ b/I2CManager_NonBlocking.h @@ -164,8 +164,6 @@ void I2CManagerClass::loop() { #if !defined(I2C_USE_INTERRUPTS) handleInterrupt(); #endif - // If free, initiate next transaction - startTransaction(); checkForTimeout(); }