1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-24 13:21:23 +01:00

Merge branch 'master' into Broadcast

This commit is contained in:
Asbelos 2021-12-05 12:13:39 +00:00
commit 0a40ef5ceb
17 changed files with 196 additions and 53 deletions

18
DCC.cpp
View File

@ -20,7 +20,9 @@
#include "DIAG.h" #include "DIAG.h"
#include "DCC.h" #include "DCC.h"
#include "DCCWaveform.h" #include "DCCWaveform.h"
#ifndef DISABLE_EEPROM
#include "EEStore.h" #include "EEStore.h"
#endif
#include "GITHUB_SHA.h" #include "GITHUB_SHA.h"
#include "version.h" #include "version.h"
#include "FSH.h" #include "FSH.h"
@ -56,9 +58,11 @@ void DCC::begin(const FSH * motorShieldName, MotorDriver * mainDriver, MotorDriv
// Initialise HAL layer before reading EEprom. // Initialise HAL layer before reading EEprom.
IODevice::begin(); IODevice::begin();
#ifndef DISABLE_EEPROM
// Load stuff from EEprom // Load stuff from EEprom
(void)EEPROM; // tell compiler not to warn this is unused (void)EEPROM; // tell compiler not to warn this is unused
EEStore::init(); EEStore::init();
#endif
DCCWaveform::begin(mainDriver,progDriver); DCCWaveform::begin(mainDriver,progDriver);
} }
@ -84,7 +88,7 @@ void DCC::setThrottle2( uint16_t cab, byte speedCode) {
uint8_t nB = 0; uint8_t nB = 0;
// DIAG(F("setSpeedInternal %d %x"),cab,speedCode); // DIAG(F("setSpeedInternal %d %x"),cab,speedCode);
if (cab > 127) if (cab > HIGHEST_SHORT_ADDR)
b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
b[nB++] = lowByte(cab); b[nB++] = lowByte(cab);
@ -124,7 +128,7 @@ void DCC::setFunctionInternal(int cab, byte byte1, byte byte2) {
byte b[4]; byte b[4];
byte nB = 0; byte nB = 0;
if (cab > 127) if (cab > HIGHEST_SHORT_ADDR)
b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
b[nB++] = lowByte(cab); b[nB++] = lowByte(cab);
if (byte1!=0) b[nB++] = byte1; if (byte1!=0) b[nB++] = byte1;
@ -153,7 +157,7 @@ void DCC::setFn( int cab, int16_t functionNumber, bool on) {
//non reminding advanced binary bit set //non reminding advanced binary bit set
byte b[5]; byte b[5];
byte nB = 0; byte nB = 0;
if (cab > 127) if (cab > HIGHEST_SHORT_ADDR)
b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
b[nB++] = lowByte(cab); b[nB++] = lowByte(cab);
if (functionNumber <= 127) { if (functionNumber <= 127) {
@ -262,7 +266,7 @@ void DCC::setAccessory(int address, byte number, bool activate) {
void DCC::writeCVByteMain(int cab, int cv, byte bValue) { void DCC::writeCVByteMain(int cab, int cv, byte bValue) {
byte b[5]; byte b[5];
byte nB = 0; byte nB = 0;
if (cab > 127) if (cab > HIGHEST_SHORT_ADDR)
b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
b[nB++] = lowByte(cab); b[nB++] = lowByte(cab);
@ -283,7 +287,7 @@ void DCC::writeCVBitMain(int cab, int cv, byte bNum, bool bValue) {
bValue = bValue % 2; bValue = bValue % 2;
bNum = bNum % 8; bNum = bNum % 8;
if (cab > 127) if (cab > HIGHEST_SHORT_ADDR)
b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
b[nB++] = lowByte(cab); b[nB++] = lowByte(cab);
@ -548,7 +552,7 @@ void DCC::setLocoId(int id,ACK_CALLBACK callback) {
callback(-1); callback(-1);
return; return;
} }
if (id<=127) if (id<=HIGHEST_SHORT_ADDR)
ackManagerSetup(id, SHORT_LOCO_ID_PROG, callback); ackManagerSetup(id, SHORT_LOCO_ID_PROG, callback);
else else
ackManagerSetup(id | 0xc000,LONG_LOCO_ID_PROG, callback); ackManagerSetup(id | 0xc000,LONG_LOCO_ID_PROG, callback);
@ -906,7 +910,7 @@ void DCC::ackManagerLoop() {
case COMBINELOCOID: case COMBINELOCOID:
// ackManagerStash is cv17, ackManagerByte is CV 18 // ackManagerStash is cv17, ackManagerByte is CV 18
callback( ackManagerByte + ((ackManagerStash - 192) << 8)); callback( LONG_ADDR_MARKER | ( ackManagerByte + ((ackManagerStash - 192) << 8)));
return; return;
case ITSKIP: case ITSKIP:

10
DCC.h
View File

@ -23,6 +23,16 @@
#include "MotorDrivers.h" #include "MotorDrivers.h"
#include "FSH.h" #include "FSH.h"
#include "defines.h"
#ifndef HIGHEST_SHORT_ADDR
#define HIGHEST_SHORT_ADDR 127
#else
#if HIGHEST_SHORT_ADDR > 127
#error short addr greater than 127 does not make sense
#endif
#endif
const uint16_t LONG_ADDR_MARKER = 0x4000;
typedef void (*ACK_CALLBACK)(int16_t result); typedef void (*ACK_CALLBACK)(int16_t result);
enum ackOp : byte enum ackOp : byte

View File

@ -56,7 +56,9 @@ const int16_t HASH_KEYWORD_ON = 2657;
const int16_t HASH_KEYWORD_DCC = 6436; const int16_t HASH_KEYWORD_DCC = 6436;
const int16_t HASH_KEYWORD_SLOW = -17209; const int16_t HASH_KEYWORD_SLOW = -17209;
const int16_t HASH_KEYWORD_PROGBOOST = -6353; const int16_t HASH_KEYWORD_PROGBOOST = -6353;
#ifndef DISABLE_EEPROM
const int16_t HASH_KEYWORD_EEPROM = -7168; const int16_t HASH_KEYWORD_EEPROM = -7168;
#endif
const int16_t HASH_KEYWORD_LIMIT = 27413; const int16_t HASH_KEYWORD_LIMIT = 27413;
const int16_t HASH_KEYWORD_MAX = 16244; const int16_t HASH_KEYWORD_MAX = 16244;
const int16_t HASH_KEYWORD_MIN = 15978; const int16_t HASH_KEYWORD_MIN = 15978;
@ -237,7 +239,9 @@ void DCCEXParser::parse(const FSH * cmd) {
void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream) void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
{ {
#ifndef DISABLE_EEPROM
(void)EEPROM; // tell compiler not to warn this is unused (void)EEPROM; // tell compiler not to warn this is unused
#endif
if (Diag::CMD) if (Diag::CMD)
DIAG(F("PARSING:%s"), com); DIAG(F("PARSING:%s"), com);
int16_t p[MAX_COMMAND_PARAMS]; int16_t p[MAX_COMMAND_PARAMS];
@ -327,7 +331,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
|| ((p[activep] & 0x01) != p[activep]) // invalid activate 0|1 || ((p[activep] & 0x01) != p[activep]) // invalid activate 0|1
) break; ) break;
// Honour the configuration option (config.h) which allows the <a> command to be reversed // Honour the configuration option (config.h) which allows the <a> command to be reversed
#ifdef DCC_ACCESSORY_RCN_213 #ifdef DCC_ACCESSORY_COMMAND_REVERSE
DCC::setAccessory(address, subaddress,p[activep]==0); DCC::setAccessory(address, subaddress,p[activep]==0);
#else #else
DCC::setAccessory(address, subaddress,p[activep]==1); DCC::setAccessory(address, subaddress,p[activep]==1);
@ -505,6 +509,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
// TODO Send stats of speed reminders table // TODO Send stats of speed reminders table
return; return;
#ifndef DISABLE_EEPROM
case 'E': // STORE EPROM <E> case 'E': // STORE EPROM <E>
EEStore::store(); EEStore::store();
StringFormatter::send(stream, F("<e %d %d %d>\n"), EEStore::eeStore->data.nTurnouts, EEStore::eeStore->data.nSensors, EEStore::eeStore->data.nOutputs); StringFormatter::send(stream, F("<e %d %d %d>\n"), EEStore::eeStore->data.nTurnouts, EEStore::eeStore->data.nSensors, EEStore::eeStore->data.nOutputs);
@ -514,7 +519,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
EEStore::clear(); EEStore::clear();
StringFormatter::send(stream, F("<O>\n")); StringFormatter::send(stream, F("<O>\n"));
return; return;
#endif
case ' ': // < > case ' ': // < >
StringFormatter::send(stream, F("\n")); StringFormatter::send(stream, F("\n"));
return; return;
@ -828,10 +833,12 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[])
break; // and <X> if we didnt restart break; // and <X> if we didnt restart
} }
#ifndef DISABLE_EEPROM
case HASH_KEYWORD_EEPROM: // <D EEPROM NumEntries> case HASH_KEYWORD_EEPROM: // <D EEPROM NumEntries>
if (params >= 2) if (params >= 2)
EEStore::dump(p[1]); EEStore::dump(p[1]);
return true; return true;
#endif
case HASH_KEYWORD_SPEED28: case HASH_KEYWORD_SPEED28:
DCC::setGlobalSpeedsteps(28); DCC::setGlobalSpeedsteps(28);
@ -921,10 +928,21 @@ void DCCEXParser::callback_R(int16_t result)
commitAsyncReplyStream(); commitAsyncReplyStream();
} }
void DCCEXParser::callback_Rloco(int16_t result) void DCCEXParser::callback_Rloco(int16_t result) {
{ const FSH * detail;
StringFormatter::send(getAsyncReplyStream(), F("<r %d>\n"), result); if (result<=0) {
commitAsyncReplyStream(); detail=F("<r ERROR %d>\n");
} else {
bool longAddr=result & LONG_ADDR_MARKER; //long addr
if (longAddr)
result = result^LONG_ADDR_MARKER;
if (longAddr && result <= HIGHEST_SHORT_ADDR)
detail=F("<r LONG %d UNSUPPORTED>\n");
else
detail=F("<r %d>\n");
}
StringFormatter::send(getAsyncReplyStream(), detail, result);
commitAsyncReplyStream();
} }
void DCCEXParser::callback_Wloco(int16_t result) void DCCEXParser::callback_Wloco(int16_t result)

View File

@ -18,6 +18,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>. * along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "defines.h"
#ifndef DISABLE_EEPROM
#include "EEStore.h" #include "EEStore.h"
#include "DIAG.h" #include "DIAG.h"
@ -103,3 +106,4 @@ void EEStore::dump(int num) {
EEStore *EEStore::eeStore = NULL; EEStore *EEStore::eeStore = NULL;
int EEStore::eeAddress = 0; int EEStore::eeAddress = 0;
#endif

View File

@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>. * along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef DISABLE_EEPROM
#ifndef EEStore_h #ifndef EEStore_h
#define EEStore_h #define EEStore_h
@ -52,3 +53,4 @@ struct EEStore{
}; };
#endif #endif
#endif // DISABLE_EEPROM

View File

@ -1 +1 @@
#define GITHUB_SHA "d4ee215" #define GITHUB_SHA "0f728c1"

View File

@ -47,11 +47,15 @@ void DCCAccessoryDecoder::_begin() {
// Device-specific write function. State 1=closed, 0=thrown. Adjust for RCN-213 compliance // Device-specific write function. State 1=closed, 0=thrown. Adjust for RCN-213 compliance
void DCCAccessoryDecoder::_write(VPIN id, int state) { void DCCAccessoryDecoder::_write(VPIN id, int state) {
int packedAddress = _packedAddress + id - _firstVpin; int packedAddress = _packedAddress + id - _firstVpin;
#ifdef DIAG_IO #if defined(HAL_ACCESSORY_COMMAND_REVERSE)
DIAG(F("DCC Write Linear Address:%d State:%d"), packedAddress, state);
#endif
#if !defined(DCC_ACCESSORY_RCN_213)
state = !state; state = !state;
#ifdef DIAG_IO
DIAG(F("DCC Write Linear Address:%d State:%d (inverted)"), packedAddress, state);
#endif
#else
#ifdef DIAG_IO
DIAG(F("DCC Write Linear Address:%d State:%d"), packedAddress, state);
#endif
#endif #endif
DCC::setAccessory(ADDRESS(packedAddress), SUBADDRESS(packedAddress), state); DCC::setAccessory(ADDRESS(packedAddress), SUBADDRESS(packedAddress), state);
} }

View File

@ -82,7 +82,9 @@ the state of any outputs being monitored or controlled by a separate interface o
**********************************************************************/ **********************************************************************/
#include "Outputs.h" #include "Outputs.h"
#ifndef DISABLE_EEPROM
#include "EEStore.h" #include "EEStore.h"
#endif
#include "StringFormatter.h" #include "StringFormatter.h"
#include "IODevice.h" #include "IODevice.h"
@ -102,10 +104,11 @@ void Output::activate(uint16_t s){
data.active = s; // if s>0, set status to active, else inactive data.active = s; // if s>0, set status to active, else inactive
// set state of output pin to HIGH or LOW depending on whether bit zero of iFlag is set to 0 (ACTIVE=HIGH) or 1 (ACTIVE=LOW) // set state of output pin to HIGH or LOW depending on whether bit zero of iFlag is set to 0 (ACTIVE=HIGH) or 1 (ACTIVE=LOW)
IODevice::write(data.pin, s ^ data.invert); IODevice::write(data.pin, s ^ data.invert);
#ifndef DISABLE_EEPROM
// Update EEPROM if output has been stored. // Update EEPROM if output has been stored.
if(EEStore::eeStore->data.nOutputs > 0 && num > 0) if(EEStore::eeStore->data.nOutputs > 0 && num > 0)
EEPROM.put(num, data.oStatus); EEPROM.put(num, data.oStatus);
#endif
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -141,7 +144,7 @@ bool Output::remove(uint16_t n){
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Static function to load configuration and state of all Outputs from EEPROM // Static function to load configuration and state of all Outputs from EEPROM
#ifndef DISABLE_EEPROM
void Output::load(){ void Output::load(){
struct OutputData data; struct OutputData data;
Output *tt; Output *tt;
@ -176,6 +179,7 @@ void Output::store(){
} }
} }
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Static function to create an Output object // Static function to create an Output object

View File

@ -48,8 +48,10 @@ public:
bool isActive(); bool isActive();
static Output* get(uint16_t); static Output* get(uint16_t);
static bool remove(uint16_t); static bool remove(uint16_t);
#ifndef DISABLE_EEPROM
static void load(); static void load();
static void store(); static void store();
#endif
static Output *create(uint16_t, VPIN, int, int=0); static Output *create(uint16_t, VPIN, int, int=0);
static Output *firstOutput; static Output *firstOutput;
struct OutputData data; struct OutputData data;

View File

@ -69,7 +69,9 @@ decide to ignore the <q ID> return and only react to <Q ID> triggers.
#include "StringFormatter.h" #include "StringFormatter.h"
#include "CommandDistributor.h" #include "CommandDistributor.h"
#include "Sensors.h" #include "Sensors.h"
#ifndef DISABLE_EEPROM
#include "EEStore.h" #include "EEStore.h"
#endif
#include "IODevice.h" #include "IODevice.h"
@ -274,7 +276,7 @@ bool Sensor::remove(int n){
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#ifndef DISABLE_EEPROM
void Sensor::load(){ void Sensor::load(){
struct SensorData data; struct SensorData data;
Sensor *tt; Sensor *tt;
@ -302,7 +304,7 @@ void Sensor::store(){
EEStore::eeStore->data.nSensors++; EEStore::eeStore->data.nSensors++;
} }
} }
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
Sensor *Sensor::firstSensor=NULL; Sensor *Sensor::firstSensor=NULL;

View File

@ -68,8 +68,10 @@ public:
Sensor *nextSensor; Sensor *nextSensor;
void setState(int state); void setState(int state);
#ifndef DISABLE_EEPROM
static void load(); static void load();
static void store(); static void store();
#endif
static Sensor *create(int id, VPIN vpin, int pullUp); static Sensor *create(int id, VPIN vpin, int pullUp);
static Sensor* get(int id); static Sensor* get(int id);
static bool remove(int id); static bool remove(int id);

View File

@ -22,7 +22,9 @@
#include "defines.h" // includes config.h #include "defines.h" // includes config.h
#ifndef DISABLE_EEPROM
#include "EEStore.h" #include "EEStore.h"
#endif
#include "StringFormatter.h" #include "StringFormatter.h"
#include "CommandDistributor.h" #include "CommandDistributor.h"
#include "RMFT2.h" #include "RMFT2.h"
@ -136,10 +138,12 @@
if (ok) { if (ok) {
turnoutlistHash++; // let withrottle know something changed turnoutlistHash++; // let withrottle know something changed
#ifndef DISABLE_EEPROM
// Write byte containing new closed/thrown state to EEPROM if required. Note that eepromAddress // Write byte containing new closed/thrown state to EEPROM if required. Note that eepromAddress
// is always zero for LCN turnouts. // is always zero for LCN turnouts.
if (EEStore::eeStore->data.nTurnouts > 0 && tt->_eepromAddress > 0) if (EEStore::eeStore->data.nTurnouts > 0 && tt->_eepromAddress > 0)
EEPROM.put(tt->_eepromAddress, tt->_turnoutData.flags); EEPROM.put(tt->_eepromAddress, tt->_turnoutData.flags);
#endif
#if defined(RMFT_ACTIVE) #if defined(RMFT_ACTIVE)
RMFT2::turnoutEvent(id, closeFlag); RMFT2::turnoutEvent(id, closeFlag);
@ -151,6 +155,7 @@
return ok; return ok;
} }
#ifndef DISABLE_EEPROM
// Load all turnout objects // Load all turnout objects
/* static */ void Turnout::load() { /* static */ void Turnout::load() {
for (uint16_t i=0; i<EEStore::eeStore->data.nTurnouts; i++) { for (uint16_t i=0; i<EEStore::eeStore->data.nTurnouts; i++) {
@ -204,7 +209,7 @@
#endif #endif
return tt; return tt;
} }
#endif
/************************************************************************************* /*************************************************************************************
* ServoTurnout - Turnout controlled by servo device. * ServoTurnout - Turnout controlled by servo device.
@ -263,6 +268,7 @@
// Load a Servo turnout definition from EEPROM. The common Turnout data has already been read at this point. // Load a Servo turnout definition from EEPROM. The common Turnout data has already been read at this point.
Turnout *ServoTurnout::load(struct TurnoutData *turnoutData) { Turnout *ServoTurnout::load(struct TurnoutData *turnoutData) {
#ifndef DISABLE_EEPROM
ServoTurnoutData servoTurnoutData; ServoTurnoutData servoTurnoutData;
// Read class-specific data from EEPROM // Read class-specific data from EEPROM
EEPROM.get(EEStore::pointer(), servoTurnoutData); EEPROM.get(EEStore::pointer(), servoTurnoutData);
@ -272,6 +278,10 @@
Turnout *tt = ServoTurnout::create(turnoutData->id, servoTurnoutData.vpin, servoTurnoutData.thrownPosition, Turnout *tt = ServoTurnout::create(turnoutData->id, servoTurnoutData.vpin, servoTurnoutData.thrownPosition,
servoTurnoutData.closedPosition, servoTurnoutData.profile, turnoutData->closed); servoTurnoutData.closedPosition, servoTurnoutData.profile, turnoutData->closed);
return tt; return tt;
#else
(void)turnoutData;
return NULL;
#endif
} }
// For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed // For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed
@ -294,6 +304,7 @@
} }
void ServoTurnout::save() { void ServoTurnout::save() {
#ifndef DISABLE_EEPROM
// Write turnout definition and current position to EEPROM // Write turnout definition and current position to EEPROM
// First write common servo data, then // First write common servo data, then
// write the servo-specific data // write the servo-specific data
@ -301,6 +312,7 @@
EEStore::advance(sizeof(_turnoutData)); EEStore::advance(sizeof(_turnoutData));
EEPROM.put(EEStore::pointer(), _servoTurnoutData); EEPROM.put(EEStore::pointer(), _servoTurnoutData);
EEStore::advance(sizeof(_servoTurnoutData)); EEStore::advance(sizeof(_servoTurnoutData));
#endif
} }
/************************************************************************************* /*************************************************************************************
@ -353,6 +365,7 @@
// Load a DCC turnout definition from EEPROM. The common Turnout data has already been read at this point. // Load a DCC turnout definition from EEPROM. The common Turnout data has already been read at this point.
/* static */ Turnout *DCCTurnout::load(struct TurnoutData *turnoutData) { /* static */ Turnout *DCCTurnout::load(struct TurnoutData *turnoutData) {
#ifndef DISABLE_EEPROM
DCCTurnoutData dccTurnoutData; DCCTurnoutData dccTurnoutData;
// Read class-specific data from EEPROM // Read class-specific data from EEPROM
EEPROM.get(EEStore::pointer(), dccTurnoutData); EEPROM.get(EEStore::pointer(), dccTurnoutData);
@ -362,6 +375,10 @@
DCCTurnout *tt = new DCCTurnout(turnoutData->id, dccTurnoutData.address, dccTurnoutData.subAddress); DCCTurnout *tt = new DCCTurnout(turnoutData->id, dccTurnoutData.address, dccTurnoutData.subAddress);
return tt; return tt;
#else
(void)turnoutData;
return NULL;
#endif
} }
void DCCTurnout::print(Print *stream) { void DCCTurnout::print(Print *stream) {
@ -382,6 +399,7 @@
} }
void DCCTurnout::save() { void DCCTurnout::save() {
#ifndef DISABLE_EEPROM
// Write turnout definition and current position to EEPROM // Write turnout definition and current position to EEPROM
// First write common servo data, then // First write common servo data, then
// write the servo-specific data // write the servo-specific data
@ -389,6 +407,7 @@
EEStore::advance(sizeof(_turnoutData)); EEStore::advance(sizeof(_turnoutData));
EEPROM.put(EEStore::pointer(), _dccTurnoutData); EEPROM.put(EEStore::pointer(), _dccTurnoutData);
EEStore::advance(sizeof(_dccTurnoutData)); EEStore::advance(sizeof(_dccTurnoutData));
#endif
} }
@ -427,6 +446,7 @@
// Load a VPIN turnout definition from EEPROM. The common Turnout data has already been read at this point. // Load a VPIN turnout definition from EEPROM. The common Turnout data has already been read at this point.
/* static */ Turnout *VpinTurnout::load(struct TurnoutData *turnoutData) { /* static */ Turnout *VpinTurnout::load(struct TurnoutData *turnoutData) {
#ifndef DISABLE_EEPROM
VpinTurnoutData vpinTurnoutData; VpinTurnoutData vpinTurnoutData;
// Read class-specific data from EEPROM // Read class-specific data from EEPROM
EEPROM.get(EEStore::pointer(), vpinTurnoutData); EEPROM.get(EEStore::pointer(), vpinTurnoutData);
@ -436,6 +456,10 @@
VpinTurnout *tt = new VpinTurnout(turnoutData->id, vpinTurnoutData.vpin, turnoutData->closed); VpinTurnout *tt = new VpinTurnout(turnoutData->id, vpinTurnoutData.vpin, turnoutData->closed);
return tt; return tt;
#else
(void)turnoutData;
return NULL;
#endif
} }
// Report 1 for thrown, 0 for closed. // Report 1 for thrown, 0 for closed.
@ -451,6 +475,7 @@
} }
void VpinTurnout::save() { void VpinTurnout::save() {
#ifndef DISABLE_EEPROM
// Write turnout definition and current position to EEPROM // Write turnout definition and current position to EEPROM
// First write common servo data, then // First write common servo data, then
// write the servo-specific data // write the servo-specific data
@ -458,6 +483,7 @@
EEStore::advance(sizeof(_turnoutData)); EEStore::advance(sizeof(_turnoutData));
EEPROM.put(EEStore::pointer(), _vpinTurnoutData); EEPROM.put(EEStore::pointer(), _vpinTurnoutData);
EEStore::advance(sizeof(_vpinTurnoutData)); EEStore::advance(sizeof(_vpinTurnoutData));
#endif
} }

View File

@ -155,13 +155,14 @@ public:
inline static Turnout *first() { return _firstTurnout; } inline static Turnout *first() { return _firstTurnout; }
#ifndef DISABLE_EEPROM
// Load all turnout definitions. // Load all turnout definitions.
static void load(); static void load();
// Load one turnout definition // Load one turnout definition
static Turnout *loadTurnout(); static Turnout *loadTurnout();
// Save all turnout definitions // Save all turnout definitions
static void store(); static void store();
#endif
static void printAll(Print *stream) { static void printAll(Print *stream) {
for (Turnout *tt = _firstTurnout; tt != 0; tt = tt->_nextTurnout) for (Turnout *tt = _firstTurnout; tt != 0; tt = tt->_nextTurnout)
StringFormatter::send(stream, F("<H %c %c>\n"),tt->getId(), tt->isThrown()); StringFormatter::send(stream, F("<H %c %c>\n"),tt->getId(), tt->isThrown());

View File

@ -51,6 +51,8 @@
#include "version.h" #include "version.h"
#include "RMFT2.h" #include "RMFT2.h"
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define LOOPLOCOS(THROTTLECHAR, CAB) for (int loco=0;loco<MAX_MY_LOCO;loco++) \ #define LOOPLOCOS(THROTTLECHAR, CAB) for (int loco=0;loco<MAX_MY_LOCO;loco++) \
if ((myLocos[loco].throttle==THROTTLECHAR || '*'==THROTTLECHAR) && (CAB<0 || myLocos[loco].cab==CAB)) if ((myLocos[loco].throttle==THROTTLECHAR || '*'==THROTTLECHAR) && (CAB<0 || myLocos[loco].cab==CAB))
@ -409,7 +411,7 @@ void WiThrottle::checkHeartbeat() {
} }
char WiThrottle::LorS(int cab) { char WiThrottle::LorS(int cab) {
return (cab<127)?'S':'L'; return (cab<=HIGHEST_SHORT_ADDR)?'S':'L';
} }
// Drive Away feature. Callback handling // Drive Away feature. Callback handling
@ -421,13 +423,26 @@ char WiThrottle::stashThrottleChar;
void WiThrottle::getLocoCallback(int16_t locoid) { void WiThrottle::getLocoCallback(int16_t locoid) {
stashStream->mark(stashClient); stashStream->mark(stashClient);
if (locoid<0) StringFormatter::send(stashStream,F("HMNo loco found on prog track\n"));
if (locoid<=0)
StringFormatter::send(stashStream,F("HMNo loco found on prog track\n"));
else { else {
char addcmd[20]={'M',stashThrottleChar,'+',LorS(locoid) }; // short or long
itoa(locoid,addcmd+4,10); char addrchar;
stashInstance->multithrottle(stashStream, (byte *)addcmd); if (locoid & LONG_ADDR_MARKER) { // long addr
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON); locoid = locoid ^ LONG_ADDR_MARKER;
DCC::setProgTrackSyncMain(true); // <1 JOIN> so we can drive loco away addrchar = 'L';
} else
addrchar = 'S';
if (addrchar == 'L' && locoid <= HIGHEST_SHORT_ADDR )
StringFormatter::send(stashStream,F("HMLong addr <= " STR(HIGHEST_SHORT_ADDR) " not supported\n"));
else {
char addcmd[20]={'M',stashThrottleChar,'+', addrchar};
itoa(locoid,addcmd+4,10);
stashInstance->multithrottle(stashStream, (byte *)addcmd);
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON);
DCC::setProgTrackSyncMain(true); // <1 JOIN> so we can drive loco away
}
} }
stashStream->commit(); stashStream->commit();
} }

View File

@ -128,6 +128,27 @@ The configuration file for DCC-EX Command Station
// Define scroll mode as 0, 1 or 2 // Define scroll mode as 0, 1 or 2
#define SCROLLMODE 1 #define SCROLLMODE 1
/////////////////////////////////////////////////////////////////////////////////////
// DISABLE EEPROM
//
// If you do not need the EEPROM at all, you can disable all the code that saves
// data in the EEPROM. You might want to do that if you are in a Arduino UNO
// and want to use the EX-RAIL automation. Otherwise you do not have enough RAM
// to do that. Of course, then none of the EEPROM related commands works.
//
// #define DISABLE_EEPROM
/////////////////////////////////////////////////////////////////////////////////////
// REDEFINE WHERE SHORT/LONG ADDR break is. According to NMRA the last short address
// is 127 and the first long address is 128. There are manufacturers which have
// another view. Lenz CS for example have considered addresses long from 100. If
// you want to change to that mode, do
//#define HIGHEST_SHORT_ADDR 99
// If you want to run all your locos addressed long format, you could even do a
//#define HIGHEST_SHORT_ADDR 0
// We do not support to use the same address, for example 100(long) and 100(short)
// at the same time, there must be a border.
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
// //
// DEFINE TURNOUTS/ACCESSORIES FOLLOW NORM RCN-213 // DEFINE TURNOUTS/ACCESSORIES FOLLOW NORM RCN-213
@ -141,7 +162,17 @@ The configuration file for DCC-EX Command Station
// don't add it to your config.h. // don't add it to your config.h.
//#define DCC_TURNOUTS_RCN_213 //#define DCC_TURNOUTS_RCN_213
// The following #define likewise inverts the behaviour of the <a> command // By default, the driver which defines a DCC accessory decoder
// does send out the same state change on the DCC packet as it
// receives. This means a VPIN state=1 sends D=1 (close turnout
// or signal green) in the DCC packet. This can be reversed if
// necessary.
//#define HAL_ACCESSORY_COMMAND_REVERSE
// If you have issues with that the direction of the accessory commands is
// reversed (for example when converting from another CS to DCC-EX) then
// you can use this to revese the sense of all accessory commmands sent
// over DCC++. This #define likewise inverts the behaviour of the <a> command
// for triggering DCC Accessory Decoders, so that <a addr subaddr 0> generates a // for triggering DCC Accessory Decoders, so that <a addr subaddr 0> generates a
// DCC packet with D=1 (close turnout) and <a addr subaddr 1> generates D=0 // DCC packet with D=1 (close turnout) and <a addr subaddr 1> generates D=0
// (throw turnout). // (throw turnout).
@ -155,7 +186,8 @@ The configuration file for DCC-EX Command Station
// To monitor a throttle on one or more serial ports, uncomment the defines below. // To monitor a throttle on one or more serial ports, uncomment the defines below.
// NOTE: do not define here the WiFi shield serial port or your wifi will not work. // NOTE: do not define here the WiFi shield serial port or your wifi will not work.
// //
// #define SERIAL1_COMMAND //#define SERIAL1_COMMAND
// #define SERIAL2_COMMAND //#define SERIAL2_COMMAND
// #define SERIAL3_COMMAND //#define SERIAL3_COMMAND
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////

View File

@ -39,19 +39,29 @@
#if (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO) || defined(TEENSYDUINO)) #if (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO) || defined(TEENSYDUINO))
#define BIG_RAM #define BIG_RAM
#endif #endif
#if ENABLE_WIFI && defined(BIG_RAM) #if ENABLE_WIFI
#define WIFI_ON true #if defined(BIG_RAM)
#ifndef WIFI_CHANNEL #define WIFI_ON true
#define WIFI_CHANNEL 1 #ifndef WIFI_CHANNEL
#endif #define WIFI_CHANNEL 1
#endif
#else
#warning You have defined that you want WIFI but your hardware has not enough memory to do that, so WIFI DISABLED
#define WIFI_ON false
#endif
#else #else
#define WIFI_ON false #define WIFI_ON false
#endif #endif
#if ENABLE_ETHERNET && defined(BIG_RAM) #if ENABLE_ETHERNET
#define ETHERNET_ON true #if defined(BIG_RAM)
#define ETHERNET_ON true
#else
#warning You have defined that you want ETHERNET but your hardware has not enough memory to do that, so ETHERNET DISABLED
#define ETHERNET_ON false
#endif
#else #else
#define ETHERNET_ON false #define ETHERNET_ON false
#endif #endif
#if WIFI_ON && ETHERNET_ON #if WIFI_ON && ETHERNET_ON
@ -65,8 +75,12 @@
// //
#define WIFI_SERIAL_LINK_SPEED 115200 #define WIFI_SERIAL_LINK_SPEED 115200
#if __has_include ( "myAutomation.h") && defined(BIG_RAM) #if __has_include ( "myAutomation.h")
#define RMFT_ACTIVE #if defined(BIG_RAM) || defined(DISABLE_EEPROM)
#define RMFT_ACTIVE
#else
#warning You have myAutomation.h but your hardware has not enough memory to do that, so EX-RAIL DISABLED
#endif
#endif #endif
#endif #endif

View File

@ -3,7 +3,7 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "3.2.0 rc5" #define VERSION "3.2.0 rc7"
// 3.2.0 Major functional and non-functional changes. // 3.2.0 Major functional and non-functional changes.
// New HAL added for I/O (digital and analogue inputs and outputs, servos etc). // New HAL added for I/O (digital and analogue inputs and outputs, servos etc).
// Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules. // Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules.
@ -21,6 +21,9 @@
// Configuration options to globally flip polarity of DCC Accessory states when driven // Configuration options to globally flip polarity of DCC Accessory states when driven
// from <a> command and <T> command. // from <a> command and <T> command.
// Increased use of display for showing loco decoder programming information. // Increased use of display for showing loco decoder programming information.
// Can disable EEPROM code
// Can define border between long and short addresses
// Turnout and accessory states (thrown/closed = 0/1 or 1/0) can be set to match RCN-213
// ... // ...
// 3.1.7 Bugfix: Unknown locos should have speed forward // 3.1.7 Bugfix: Unknown locos should have speed forward
// 3.1.6 Make output ID two bytes and guess format/size of registered outputs found in EEPROM // 3.1.6 Make output ID two bytes and guess format/size of registered outputs found in EEPROM