1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-30 03:26:13 +01:00

DCC Turnouts: Store address/subaddress separately. Enable address 0.

The range of accessory decoder addresses for the <a> command is 0-511 in line with the DCC packet contents.  The turnout command previously rejected address 0; this has been changed to the same range of addresses can be used by both commands, i.e. address 0-511 and subaddress 0-3.  The linear address mapping remains so that linear address 1 is addr/subaddr 1/0; i.e. the first decoder address is not accessible by linear address.
This commit is contained in:
Neil McKechnie 2021-09-22 10:38:11 +01:00
parent e59e07b971
commit e287af83ff
3 changed files with 18 additions and 15 deletions

View File

@ -736,15 +736,17 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[])
if (!VpinTurnout::create(p[0], p[2])) return false; if (!VpinTurnout::create(p[0], p[2])) return false;
} else } else
if (params >= 3 && p[1] == HASH_KEYWORD_DCC) { if (params >= 3 && p[1] == HASH_KEYWORD_DCC) {
if (params==4 && p[2]>0 && p[2]<=512 && p[3]>=0 && p[3]<4) { // <T id DCC n m> // <T id DCC addr subadd> 0<=addr<=511, 0<=subadd<=3 (like <a> command).<T>
if (params==4 && p[2]>=0 && p[2]<512 && p[3]>=0 && p[3]<4) { // <T id DCC n m>
if (!DCCTurnout::create(p[0], p[2], p[3])) return false; if (!DCCTurnout::create(p[0], p[2], p[3])) return false;
} else if (params==3 && p[2]>0 && p[2]<=512*4) { // <T id DCC nn>, 1<=nn<=2048 } else if (params==3 && p[2]>0 && p[2]<=512*4) { // <T id DCC nn>, 1<=nn<=2048
// Linearaddress 1 maps onto decoder address 1/0 (not 0/0!).
if (!DCCTurnout::create(p[0], (p[2]-1)/4+1, (p[2]-1)%4)) return false; if (!DCCTurnout::create(p[0], (p[2]-1)/4+1, (p[2]-1)%4)) return false;
} else } else
return false; return false;
} else } else
if (params==3) { // legacy <T id n n> for DCC accessory if (params==3) { // legacy <T id addr subadd> for DCC accessory
if (p[1]>0 && p[1]<=512 && p[2]>=0 && p[2]<4) { if (p[1]>=0 && p[1]<512 && p[2]>=0 && p[2]<4) {
if (!DCCTurnout::create(p[0], p[1], p[2])) return false; if (!DCCTurnout::create(p[0], p[1], p[2])) return false;
} else } else
return false; return false;

View File

@ -340,7 +340,8 @@
DCCTurnout::DCCTurnout(uint16_t id, uint16_t address, uint8_t subAdd) : DCCTurnout::DCCTurnout(uint16_t id, uint16_t address, uint8_t subAdd) :
Turnout(id, TURNOUT_DCC, false) Turnout(id, TURNOUT_DCC, false)
{ {
_dccTurnoutData.address = ((address-1) << 2) + subAdd + 1; _dccTurnoutData.address = address;
_dccTurnoutData.subAddress = subAdd;
} }
// Create function // Create function
@ -351,7 +352,8 @@
if (tt->isType(TURNOUT_DCC)) { if (tt->isType(TURNOUT_DCC)) {
// Yes, so set parameters<T> // Yes, so set parameters<T>
DCCTurnout *dt = (DCCTurnout *)tt; DCCTurnout *dt = (DCCTurnout *)tt;
dt->_dccTurnoutData.address = ((add-1) << 2) + subAdd + 1; dt->_dccTurnoutData.address = add;
dt->_dccTurnoutData.subAddress = subAdd;
// Don't touch the _closed parameter, retain the original value. // Don't touch the _closed parameter, retain the original value.
return tt; return tt;
} else { } else {
@ -371,27 +373,24 @@
EEStore::advance(sizeof(dccTurnoutData)); EEStore::advance(sizeof(dccTurnoutData));
// Create new object // Create new object
DCCTurnout *tt = new DCCTurnout(turnoutData->id, (((dccTurnoutData.address-1) >> 2)+1), ((dccTurnoutData.address-1) & 3)); DCCTurnout *tt = new DCCTurnout(turnoutData->id, dccTurnoutData.address, dccTurnoutData.subAddress);
return tt; return tt;
} }
void DCCTurnout::print(Print *stream) { void DCCTurnout::print(Print *stream) {
StringFormatter::send(stream, F("<H %d DCC %d %d %d>\n"), _turnoutData.id, StringFormatter::send(stream, F("<H %d DCC %d %d %d>\n"), _turnoutData.id,
(((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3), _dccTurnoutData.address, _dccTurnoutData.subAddress, !_turnoutData.closed);
!_turnoutData.closed);
// Also report using classic DCC++ syntax for DCC accessory turnouts, since JMRI expects this. // 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, StringFormatter::send(stream, F("<H %d %d %d %d>\n"), _turnoutData.id,
(((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3), _dccTurnoutData.address, _dccTurnoutData.subAddress, !_turnoutData.closed);
!_turnoutData.closed);
} }
bool DCCTurnout::setClosedInternal(bool close) { bool DCCTurnout::setClosedInternal(bool close) {
// DCC++ Classic behaviour is that Throw writes a 1 in the packet, // DCC++ Classic behaviour is that Throw writes a 1 in the packet,
// and Close writes a 0. // and Close writes a 0.
// RCN-213 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), DCC::setAccessory(_dccTurnoutData.address, _dccTurnoutData.subAddress, close ^ !rcn213Compliant);
((_dccTurnoutData.address-1) & 3), close ^ !rcn213Compliant);
_turnoutData.closed = close; _turnoutData.closed = close;
return true; return true;
} }

View File

@ -213,9 +213,11 @@ private:
// DCCTurnoutData contains data specific to this subclass that is // DCCTurnoutData contains data specific to this subclass that is
// written to EEPROM when the turnout is saved. // written to EEPROM when the turnout is saved.
struct DCCTurnoutData { struct DCCTurnoutData {
// DCC address (Address in bits 15-2, subaddress in bits 1-0 // DCC address (Address in bits 15-2, subaddress in bits 1-0)
uint16_t address; // CS currently supports linear address 1-2048 struct {
// That's DCC accessory address 1-512 and subaddress 0-3. uint16_t address : 14;
uint8_t subAddress : 2;
};
} _dccTurnoutData; // 2 bytes } _dccTurnoutData; // 2 bytes
// Constructor // Constructor