mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-24 21:21:24 +01:00
Merge pull request #185 from DCC-EX/EX-RAIL-neil-RCN213
Ex rail neil rcn213
This commit is contained in:
commit
bad9e866f8
@ -700,22 +700,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::useLegacyTurnoutBehaviour;
|
||||
break;
|
||||
case 1:
|
||||
state = !Turnout::useLegacyTurnoutBehaviour;
|
||||
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;
|
||||
|
||||
|
@ -164,8 +164,6 @@ void I2CManagerClass::loop() {
|
||||
#if !defined(I2C_USE_INTERRUPTS)
|
||||
handleInterrupt();
|
||||
#endif
|
||||
// If free, initiate next transaction
|
||||
startTransaction();
|
||||
checkForTimeout();
|
||||
}
|
||||
|
||||
|
@ -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<arrayLen; i++) {
|
||||
_pinPullups[i] = 0;
|
||||
_pinPullups[i] = 0xff; // default to pullup on, for inputs
|
||||
_pinModes[i] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -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 command synchronously
|
||||
}
|
||||
|
||||
// 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 command synchronously
|
||||
}
|
||||
|
||||
// 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); // Write command synchronously
|
||||
}
|
@ -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
|
||||
|
44
Turnouts.cpp
44
Turnouts.cpp
@ -20,13 +20,8 @@
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Set the following definition to true for <T id 0> = throw and <T id 1> = close
|
||||
// or to false for <T id 0> = close and <T id 1> = 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,6 @@
|
||||
* Public static data
|
||||
*/
|
||||
int Turnout::turnoutlistHash = 0;
|
||||
bool Turnout::useLegacyTurnoutBehaviour = USE_LEGACY_TURNOUT_BEHAVIOUR;
|
||||
|
||||
/*
|
||||
* Protected static functions
|
||||
@ -74,9 +68,10 @@
|
||||
turnoutlistHash++;
|
||||
}
|
||||
|
||||
// For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed;
|
||||
void Turnout::printState(Print *stream) {
|
||||
StringFormatter::send(stream, F("<H %d %d>\n"),
|
||||
_turnoutData.id, _turnoutData.closed ^ useLegacyTurnoutBehaviour);
|
||||
_turnoutData.id, !_turnoutData.closed);
|
||||
}
|
||||
|
||||
// Remove nominated turnout from turnout linked list and delete the object.
|
||||
@ -137,7 +132,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);
|
||||
@ -172,7 +167,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));
|
||||
|
||||
@ -196,7 +191,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
|
||||
@ -205,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);
|
||||
@ -279,10 +274,11 @@
|
||||
return tt;
|
||||
}
|
||||
|
||||
// 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("<H %d SERVO %d %d %d %d %d>\n"), _turnoutData.id, _servoTurnoutData.vpin,
|
||||
_servoTurnoutData.thrownPosition, _servoTurnoutData.closedPosition, _servoTurnoutData.profile,
|
||||
_turnoutData.closed ^ useLegacyTurnoutBehaviour);
|
||||
!_turnoutData.closed);
|
||||
}
|
||||
|
||||
// ServoTurnout-specific code for throwing or closing a servo turnout.
|
||||
@ -312,6 +308,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 +365,19 @@
|
||||
void DCCTurnout::print(Print *stream) {
|
||||
StringFormatter::send(stream, F("<H %d DCC %d %d %d>\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);
|
||||
// Also report using classic DCC++ syntax for DCC accessory turnouts, since JMRI expects this.
|
||||
StringFormatter::send(stream, F("<H %d %d %d %d>\n"), _turnoutData.id,
|
||||
(((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3),
|
||||
_turnoutData.closed ^ useLegacyTurnoutBehaviour);
|
||||
!_turnoutData.closed);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -437,9 +439,10 @@
|
||||
return tt;
|
||||
}
|
||||
|
||||
// Report 1 for thrown, 0 for closed.
|
||||
void VpinTurnout::print(Print *stream) {
|
||||
StringFormatter::send(stream, F("<H %d VPIN %d %d>\n"), _turnoutData.id, _vpinTurnoutData.vpin,
|
||||
_turnoutData.closed ^ useLegacyTurnoutBehaviour);
|
||||
!_turnoutData.closed);
|
||||
}
|
||||
|
||||
bool VpinTurnout::setClosedInternal(bool close) {
|
||||
@ -501,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("<H %d LCN %d>\n"), _turnoutData.id,
|
||||
_turnoutData.closed ^ useLegacyTurnoutBehaviour);
|
||||
!_turnoutData.closed);
|
||||
}
|
||||
|
||||
|
17
Turnouts.h
17
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 {
|
||||
union {
|
||||
struct {
|
||||
bool closed : 1;
|
||||
bool _rfu: 2;
|
||||
uint8_t turnoutType : 5;
|
||||
};
|
||||
uint8_t flags;
|
||||
};
|
||||
uint16_t id;
|
||||
} _turnoutData; // 3 bytes
|
||||
|
||||
@ -104,7 +109,7 @@ public:
|
||||
* Static data
|
||||
*/
|
||||
static int turnoutlistHash;
|
||||
static bool useLegacyTurnoutBehaviour;
|
||||
static const bool useClassicTurnoutCommands;
|
||||
|
||||
/*
|
||||
* Public base class functions
|
||||
@ -182,11 +187,11 @@ 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);
|
||||
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);
|
||||
@ -222,6 +227,8 @@ 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:
|
||||
bool setClosedInternal(bool close) override;
|
||||
@ -243,7 +250,7 @@ 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
|
||||
@ -271,7 +278,7 @@ private:
|
||||
// } _lcnTurnoutData; // 0 bytes
|
||||
|
||||
// Constructor
|
||||
LCNTurnout(uint16_t id, bool closed=true);
|
||||
LCNTurnout(uint16_t id, bool closed);
|
||||
|
||||
public:
|
||||
// Create function
|
||||
|
@ -129,4 +129,16 @@ 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
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
139
mySetup.cpp_example.txt
Normal file
139
mySetup.cpp_example.txt
Normal file
@ -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 <T> 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 <T> 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 <S> 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
|
Loading…
Reference in New Issue
Block a user