diff --git a/DCC.cpp b/DCC.cpp index e60cf25b..fb961d57 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -897,6 +897,42 @@ DCC::LOCO DCC::speedTable[MAX_LOCOS]; int DCC::lastLocoReminder = 0; int DCC::highestUsedReg = 0; +void DCC::setLocoInBlock(int loco, uint16_t blockid, bool exclusive) { + // update block loco is in, tell exrail leaving old block, and entering new. + + // NOTE: The loco table scanning is really inefficient and needs rewriting + // This was done once in the momentum poc. + #ifdef EXRAIL_ACTIVE + int reg=lookupSpeedTable(loco,true); + if (reg<0) return; + auto oldBlock=speedTable[reg].blockOccupied; + if (oldBlock==blockid) return; + if (oldBlock) RMFT2::blockEvent(oldBlock,loco,false); + speedTable[reg].blockOccupied=blockid; + if (blockid) RMFT2::blockEvent(blockid,loco,true); + + if (exclusive) { + for (int reg = 0; reg <= highestUsedReg; reg++) { + if (speedTable[reg].loco!=loco && speedTable[reg].blockOccupied==blockid) { + RMFT2::blockEvent(blockid,speedTable[reg].loco,false); + speedTable[reg].blockOccupied=0; + } + } + } + #endif +} + +void DCC::clearBlock(uint16_t blockid) { + // Railcom reports block empty... tell Exrail about all leavers + #ifdef EXRAIL_ACTIVE + for (int reg = 0; reg <= highestUsedReg; reg++) { + if (speedTable[reg].blockOccupied==blockid) { + RMFT2::blockEvent(blockid,speedTable[reg].loco,false); + speedTable[reg].blockOccupied=0; + } + } + #endif +} void DCC::displayCabList(Print * stream) { diff --git a/DCC.h b/DCC.h index 38c1952f..7993847e 100644 --- a/DCC.h +++ b/DCC.h @@ -102,12 +102,14 @@ class DCC byte speedCode; byte groupFlags; uint32_t functions; + uint16_t blockOccupied; // railcom detected block }; static LOCO speedTable[MAX_LOCOS]; static int lookupSpeedTable(int locoId, bool autoCreate=true); static byte cv1(byte opcode, int cv); static byte cv2(int cv); - + static void setLocoInBlock(int locoid, uint16_t blockid, bool exclusive); + static void clearBlock(uint16_t blockid); private: static byte loopStatus; static void setThrottle2(uint16_t cab, uint8_t speedCode); diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 85005c59..0bd0ecb6 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -1205,6 +1205,10 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[]) Diag::CMD = onOff; return true; + case "RAILCOM"_hk: // + Diag::RAILCOM = onOff; + return true; + #ifdef HAS_ENOUGH_MEMORY case "WIFI"_hk: // Diag::WIFI = onOff; diff --git a/Railcom.cpp b/Railcom.cpp index dc880a9b..7ccd74c2 100644 --- a/Railcom.cpp +++ b/Railcom.cpp @@ -51,10 +51,9 @@ #include "Railcom.h" #include "defines.h" #include "FSH.h" -#include "EXRAIL3.h" +#include "DCC.h" #include "DIAG.h" -#define DIAG_I2CRailcom_data /** Table for 8-to-6 decoding of railcom data. This table can be indexed by the @@ -143,31 +142,35 @@ Railcom::Railcom(uint16_t blockvpin) { haveHigh=false; haveLow=false; packetsWithNoData=0; - locoOnTrack=0; + lastChannel1Loco=0; vpin=blockvpin; } + +// Process is called by a raw data collector. void Railcom::process(uint8_t * inbound, uint8_t length) { + + if (length<2 || (inbound[0]==0 && inbound[1]==0)) { + noData(); + return; + } + - #ifdef DIAG_I2CRailcom_data - static const char hexchars[]="0123456789ABCDEF"; - if (length>2) { - Serial.print("R "); + if (Diag::RAILCOM) { + static const char hexchars[]="0123456789ABCDEF"; + if (length>2) { + USB_SERIAL.print(F("<*R ")); for (byte i=0;i>4]); - Serial.write(hexchars[inbound[i]& 0x0F ]); + USB_SERIAL.write(hexchars[inbound[i]>>4]); + USB_SERIAL.write(hexchars[inbound[i]& 0x0F ]); } - Serial.println(); - } - - #endif - if (length<2 || (inbound[0]==0 && inbound[1]==0)) { - noData(); - return; + USB_SERIAL.print(F(" *>\n")); + } } + auto v1=GETHIGHFLASH(decode,inbound[0]); auto v2=(length>1) ? GETHIGHFLASH(decode,inbound[1]):INV; uint16_t packet=(v1<<6) | (v2 & 0x3f); @@ -188,25 +191,28 @@ void Railcom::process(uint8_t * inbound, uint8_t length) { return; /* ignore*/ } else { + // channel1 is unreadable so maybe multiple locos in block + if (length>2 && GETHIGHFLASH(decode,inbound[0])!=INV) { + // it looks like we have channel2 data + auto thisLoco=DCCWaveform::getRailcomLastLocoAddress(); + if (Diag::RAILCOM) DIAG(F("c2=%d"),thisLoco); + if (thisLoco) DCC::setLocoInBlock(thisLoco,vpin,false); // this loco is in block, but not exclusive + return; + } + // channel1 no good and no channel2 noData(); - return; // need more data + return; } if (haveHigh && haveLow) { uint16_t thisLoco=((holdoverHigh<<8)| holdoverLow); - if (locoOnTrack!=thisLoco) { - // Previous loco (if any) is exiting block - blockEvent(false); - locoOnTrack=thisLoco; - blockEvent(true); + if (thisLoco!=lastChannel1Loco) { + // the exclusive DCC call is quite expensive, we dont want to call it every packet + DCC::setLocoInBlock(thisLoco,vpin,true); // only this loco is in block + lastChannel1Loco=thisLoco; } } } -void Railcom::blockEvent(bool entering) { - #ifdef EXRAIL_ACTIVE - if (locoOnTrack) RMFT3::blockEvent(vpin,locoOnTrack,entering); - #endif -} void Railcom::noData() { if (packetsWithNoData>MAX_WAIT_FOR_GLITCH) return; @@ -214,9 +220,9 @@ void Railcom::noData() { // treat as no loco haveHigh=false; haveLow=false; - // Previous loco (if any) is exiting block - blockEvent(false); - locoOnTrack=0; + lastChannel1Loco=0; + // Previous locos (if any) is exiting block + DCC::clearBlock(vpin); } packetsWithNoData++; } diff --git a/Railcom.h b/Railcom.h index c84d55bf..1207b297 100644 --- a/Railcom.h +++ b/Railcom.h @@ -33,13 +33,12 @@ class Railcom { void process(uint8_t * inbound,uint8_t length); private: - void blockEvent(bool entering); void noData(); - uint16_t locoOnTrack; uint16_t vpin; uint8_t holdoverHigh,holdoverLow; bool haveHigh,haveLow; - uint8_t packetsWithNoData; + uint8_t packetsWithNoData; + uint16_t lastChannel1Loco; static const byte MAX_WAIT_FOR_GLITCH=20; // number of dead or empty packets before assuming loco=0 }; diff --git a/StringFormatter.cpp b/StringFormatter.cpp index 192e1ccb..912f53a4 100644 --- a/StringFormatter.cpp +++ b/StringFormatter.cpp @@ -27,6 +27,8 @@ bool Diag::WIFI=false; bool Diag::WITHROTTLE=false; bool Diag::ETHERNET=false; bool Diag::LCN=false; +bool Diag::RAILCOM=false; + void StringFormatter::diag( const FSH* input...) { diff --git a/StringFormatter.h b/StringFormatter.h index 25d15e23..74cfd70e 100644 --- a/StringFormatter.h +++ b/StringFormatter.h @@ -30,6 +30,7 @@ class Diag { static bool WITHROTTLE; static bool ETHERNET; static bool LCN; + static bool RAILCOM; };