mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-23 08:06:13 +01:00
Merge branch 'master' into EXRAILPlus
This commit is contained in:
commit
bb2c85d973
18
DCC.cpp
18
DCC.cpp
|
@ -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"
|
||||||
|
@ -57,9 +59,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);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +89,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);
|
||||||
|
|
||||||
|
@ -125,7 +129,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;
|
||||||
|
@ -154,7 +158,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) {
|
||||||
|
@ -266,7 +270,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);
|
||||||
|
@ -287,7 +291,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);
|
||||||
|
@ -552,7 +556,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);
|
||||||
|
@ -910,7 +914,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
10
DCC.h
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -278,7 +280,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];
|
||||||
|
@ -368,7 +372,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);
|
||||||
|
@ -540,6 +544,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);
|
||||||
|
@ -549,7 +554,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;
|
||||||
|
@ -865,10 +870,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);
|
||||||
|
@ -958,10 +965,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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#define GITHUB_SHA "a2f8a8e"
|
#define GITHUB_SHA "0f728c1"
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -17,7 +17,7 @@ Both CommandStation-EX and BaseStation-Classic support much of the NMRA Digital
|
||||||
* Control of all cab functions F0-F28 and F29-F68
|
* 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)
|
* 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
|
* Programming Track: Same as the main track with the addition of reading configuration variable bytes
|
||||||
* And manu more custom features. see [What's new in CommandStation-EX?](#whats-new-in-commandstation-ex)
|
* And many more custom features. see [What's new in CommandStation-EX?](#whats-new-in-commandstation-ex)
|
||||||
|
|
||||||
|
|
||||||
# What’s in this Repository?
|
# What’s in this Repository?
|
||||||
|
|
|
@ -68,7 +68,9 @@ decide to ignore the <q ID> return and only react to <Q ID> triggers.
|
||||||
|
|
||||||
#include "StringFormatter.h"
|
#include "StringFormatter.h"
|
||||||
#include "Sensors.h"
|
#include "Sensors.h"
|
||||||
|
#ifndef DISABLE_EEPROM
|
||||||
#include "EEStore.h"
|
#include "EEStore.h"
|
||||||
|
#endif
|
||||||
#include "IODevice.h"
|
#include "IODevice.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,7 +277,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;
|
||||||
|
@ -303,7 +305,7 @@ void Sensor::store(){
|
||||||
EEStore::eeStore->data.nSensors++;
|
EEStore::eeStore->data.nSensors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Sensor *Sensor::firstSensor=NULL;
|
Sensor *Sensor::firstSensor=NULL;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
28
Turnouts.cpp
28
Turnouts.cpp
|
@ -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 "RMFT2.h"
|
#include "RMFT2.h"
|
||||||
#include "Turnouts.h"
|
#include "Turnouts.h"
|
||||||
|
@ -142,10 +144,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);
|
||||||
|
@ -159,6 +163,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++) {
|
||||||
|
@ -212,7 +217,7 @@
|
||||||
#endif
|
#endif
|
||||||
return tt;
|
return tt;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
// Display, on the specified stream, the current state of the turnout (1=thrown or 0=closed).
|
// Display, on the specified stream, the current state of the turnout (1=thrown or 0=closed).
|
||||||
/* static */ void Turnout::printState(uint16_t id, Print *stream) {
|
/* static */ void Turnout::printState(uint16_t id, Print *stream) {
|
||||||
Turnout *tt = get(id);
|
Turnout *tt = get(id);
|
||||||
|
@ -277,6 +282,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);
|
||||||
|
@ -286,6 +292,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
|
||||||
|
@ -308,6 +318,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
|
||||||
|
@ -315,6 +326,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
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************************
|
/*************************************************************************************
|
||||||
|
@ -367,6 +379,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);
|
||||||
|
@ -376,6 +389,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) {
|
||||||
|
@ -396,6 +413,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
|
||||||
|
@ -403,6 +421,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -441,6 +460,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);
|
||||||
|
@ -450,6 +470,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.
|
||||||
|
@ -465,6 +489,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
|
||||||
|
@ -472,6 +497,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
tt->printState(stream);
|
tt->printState(stream);
|
||||||
|
|
|
@ -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))
|
||||||
|
@ -415,7 +417,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
|
||||||
|
@ -427,13 +429,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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,10 +162,20 @@ 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).
|
||||||
//#define DCC_ACCESSORY_RCN_213
|
//#define DCC_ACCESSORY_COMMAND_REVERSE
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
36
defines.h
36
defines.h
|
@ -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
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user