diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 211aac3..5c4d6d2 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -127,10 +127,11 @@ volatile bool DCCWaveform::railcomActive=false; // switched on by user volatile bool DCCWaveform::railcomDebug=false; // switched on by user volatile bool DCCWaveform::railcomSampleWindow=false; // true during packet transmit volatile byte DCCWaveform::railcomCutoutCounter=0; // cyclic cutout +volatile byte DCCWaveform::railcomLastAddressHigh=0; +volatile byte DCCWaveform::railcomLastAddressLow=0; bool DCCWaveform::setRailcom(bool on, bool debug) { if (on && railcomPossible) { - // TODO check possible railcomActive=true; railcomDebug=debug; } @@ -233,6 +234,12 @@ void DCCWaveform::promotePendingPacket() { return; } + // Remember address bytes of last sent packet so that Railcom can + // work out where the channel2 data came from. + railcomLastAddressHigh=transmitPacket[0]; + railcomLastAddressLow =transmitPacket[1]; + + if (packetPending) { // Copy pending packet to transmit packet // a fixed length memcpy is faster than a variable length loop for these small lengths diff --git a/DCCWaveform.h b/DCCWaveform.h index 97cf94b..8979c28 100644 --- a/DCCWaveform.h +++ b/DCCWaveform.h @@ -100,6 +100,14 @@ class DCCWaveform { railcomPossible=yes; if (!yes) setRailcom(false,false); }; + inline static uint16_t getRailcomLastLocoAddress() { + // first 2 bits 00=short loco, 11=long loco , 01/10 = accessory + byte addressType=railcomLastAddressHigh & 0xC0; + if (addressType==0xC0) return ((railcomLastAddressHigh & 0x3f)<<8) | railcomLastAddressLow; + if (addressType==0x00) return railcomLastAddressHigh & 0x3F; + return 0; + } + private: #ifndef ARDUINO_ARCH_ESP32 volatile bool packetPending; @@ -129,6 +137,7 @@ class DCCWaveform { static volatile bool railcomDebug; // switched on by user static volatile bool railcomSampleWindow; // when safe to sample static volatile byte railcomCutoutCounter; // incremented for each cutout + static volatile byte railcomLastAddressHigh,railcomLastAddressLow; static bool cutoutNextTime; // railcom #ifdef ARDUINO_ARCH_ESP32 static RMTChannel *rmtMainChannel; diff --git a/IO_I2CRailcom.h b/IO_I2CRailcom.h index 0daa368..9dcccdf 100644 --- a/IO_I2CRailcom.h +++ b/IO_I2CRailcom.h @@ -58,7 +58,7 @@ class I2CRailcom : public IODevice { private: // SC16IS752 defines uint8_t _UART_CH=0x00; // channel 0 or 1 flips each loop if npins>1 - byte _inbuf[65]; + byte _inbuf[12]; byte _outbuf[2]; byte cutoutCounter[2]; Railcom * _channelMonitors[2]; @@ -118,7 +118,7 @@ public: // Read incoming raw Railcom data, and process accordingly auto inlength = UART_ReadRegister(REG_RXLV); - if (inlength==0) return; + if (inlength> sizeof(_inbuf)) inlength=sizeof(_inbuf); _inbuf[0]=0; if (inlength>0) { diff --git a/Railcom.cpp b/Railcom.cpp index ef7b7f1..dc880a9 100644 --- a/Railcom.cpp +++ b/Railcom.cpp @@ -54,7 +54,7 @@ #include "EXRAIL3.h" #include "DIAG.h" -//#define DIAG_I2CRailcom_data +#define DIAG_I2CRailcom_data /** Table for 8-to-6 decoding of railcom data. This table can be indexed by the @@ -135,6 +135,10 @@ const uint8_t HIGHFLASH decode[256] = RMOB_LOGON_ENABLE_FEEDBACK = 15, }; +// each railcom block is represented by an instance of this class. +// The blockvpin is the vpin associated with this block for the purposes of +// a HAL driver for the railcom detection and the EXRAIL ONBLOCKENTER/ONBLOCKEXIT + Railcom::Railcom(uint16_t blockvpin) { haveHigh=false; haveLow=false; @@ -143,23 +147,33 @@ Railcom::Railcom(uint16_t blockvpin) { vpin=blockvpin; } - /* returns -1: Call again next packet - 0: No loco on track - >0: loco id - */ void Railcom::process(uint8_t * inbound, uint8_t length) { + + #ifdef DIAG_I2CRailcom_data - DIAG(F("Railcom %d RX FIFO Data, %d"), vpin,length); - for (int i = 0; i < 2; i++){ - if (inbound[i]) DIAG(F("[0x%x]: 0x%x"), i, inbound[i]); - } + static const char hexchars[]="0123456789ABCDEF"; + if (length>2) { + Serial.print("R "); + for (byte i=0;i>4]); + Serial.write(hexchars[inbound[i]& 0x0F ]); + } + Serial.println(); + } + #endif + if (length<2 || (inbound[0]==0 && inbound[1]==0)) { + noData(); + return; + } + auto v1=GETHIGHFLASH(decode,inbound[0]); - auto v2=(length>2) ? GETHIGHFLASH(decode,inbound[1]):0x0; + auto v2=(length>1) ? GETHIGHFLASH(decode,inbound[1]):INV; uint16_t packet=(v1<<6) | (v2 & 0x3f); // packet is 12 bits TTTTDDDDDDDD - auto type=packet>>8; - auto data= packet & 0xFF; + byte type=(packet>>8) & 0x0F; + byte data= packet & 0xFF; if (type==RMOB_ADRHIGH) { holdoverHigh=data; haveHigh=true; @@ -174,16 +188,7 @@ void Railcom::process(uint8_t * inbound, uint8_t length) { return; /* ignore*/ } else { - if (packetsWithNoData>MAX_WAIT_FOR_GLITCH) { - // treat as no loco - haveHigh=false; - haveLow=false; - // Previous loco (if any) is exiting block - blockEvent(false); - locoOnTrack=0; - return ; - } - packetsWithNoData++; + noData(); return; // need more data } if (haveHigh && haveLow) { @@ -202,3 +207,16 @@ void Railcom::blockEvent(bool entering) { if (locoOnTrack) RMFT3::blockEvent(vpin,locoOnTrack,entering); #endif } + +void Railcom::noData() { + if (packetsWithNoData>MAX_WAIT_FOR_GLITCH) return; + if (packetsWithNoData==MAX_WAIT_FOR_GLITCH) { + // treat as no loco + haveHigh=false; + haveLow=false; + // Previous loco (if any) is exiting block + blockEvent(false); + locoOnTrack=0; + } + packetsWithNoData++; +} diff --git a/Railcom.h b/Railcom.h index b16945e..c84d55b 100644 --- a/Railcom.h +++ b/Railcom.h @@ -34,6 +34,7 @@ class Railcom { private: void blockEvent(bool entering); + void noData(); uint16_t locoOnTrack; uint16_t vpin; uint8_t holdoverHigh,holdoverLow;