From e287af83fffad1617e6d4f3205d725be9be97919 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Wed, 22 Sep 2021 10:38:11 +0100 Subject: [PATCH] DCC Turnouts: Store address/subaddress separately. Enable address 0. The range of accessory decoder addresses for the 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. --- DCCEXParser.cpp | 8 +++++--- Turnouts.cpp | 17 ++++++++--------- Turnouts.h | 8 +++++--- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index d09aa1b..b5f472f 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -736,15 +736,17 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) if (!VpinTurnout::create(p[0], p[2])) return false; } else if (params >= 3 && p[1] == HASH_KEYWORD_DCC) { - if (params==4 && p[2]>0 && p[2]<=512 && p[3]>=0 && p[3]<4) { // + // 0<=addr<=511, 0<=subadd<=3 (like command). + if (params==4 && p[2]>=0 && p[2]<512 && p[3]>=0 && p[3]<4) { // if (!DCCTurnout::create(p[0], p[2], p[3])) return false; } else if (params==3 && p[2]>0 && p[2]<=512*4) { // , 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; } else return false; } else - if (params==3) { // legacy for DCC accessory - if (p[1]>0 && p[1]<=512 && p[2]>=0 && p[2]<4) { + if (params==3) { // legacy for DCC accessory + if (p[1]>=0 && p[1]<512 && p[2]>=0 && p[2]<4) { if (!DCCTurnout::create(p[0], p[1], p[2])) return false; } else return false; diff --git a/Turnouts.cpp b/Turnouts.cpp index 6dbc402..dcbff73 100644 --- a/Turnouts.cpp +++ b/Turnouts.cpp @@ -340,7 +340,8 @@ DCCTurnout::DCCTurnout(uint16_t id, uint16_t address, uint8_t subAdd) : Turnout(id, TURNOUT_DCC, false) { - _dccTurnoutData.address = ((address-1) << 2) + subAdd + 1; + _dccTurnoutData.address = address; + _dccTurnoutData.subAddress = subAdd; } // Create function @@ -351,7 +352,8 @@ if (tt->isType(TURNOUT_DCC)) { // Yes, so set parameters 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. return tt; } else { @@ -371,27 +373,24 @@ EEStore::advance(sizeof(dccTurnoutData)); // 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; } void DCCTurnout::print(Print *stream) { StringFormatter::send(stream, F("\n"), _turnoutData.id, - (((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3), - !_turnoutData.closed); + _dccTurnoutData.address, _dccTurnoutData.subAddress, !_turnoutData.closed); // Also report using classic DCC++ syntax for DCC accessory turnouts, since JMRI expects this. StringFormatter::send(stream, F("\n"), _turnoutData.id, - (((_dccTurnoutData.address-1) >> 2)+1), ((_dccTurnoutData.address-1) & 3), - !_turnoutData.closed); + _dccTurnoutData.address, _dccTurnoutData.subAddress, !_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-213 specifies that Throw is 0 and Close is 1. - DCC::setAccessory((((_dccTurnoutData.address-1) >> 2) + 1), - ((_dccTurnoutData.address-1) & 3), close ^ !rcn213Compliant); + DCC::setAccessory(_dccTurnoutData.address, _dccTurnoutData.subAddress, close ^ !rcn213Compliant); _turnoutData.closed = close; return true; } diff --git a/Turnouts.h b/Turnouts.h index 9c14089..6a55c15 100644 --- a/Turnouts.h +++ b/Turnouts.h @@ -213,9 +213,11 @@ private: // DCCTurnoutData contains data specific to this subclass that is // written to EEPROM when the turnout is saved. struct DCCTurnoutData { - // DCC address (Address in bits 15-2, subaddress in bits 1-0 - uint16_t address; // CS currently supports linear address 1-2048 - // That's DCC accessory address 1-512 and subaddress 0-3. + // DCC address (Address in bits 15-2, subaddress in bits 1-0) + struct { + uint16_t address : 14; + uint8_t subAddress : 2; + }; } _dccTurnoutData; // 2 bytes // Constructor