1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-02-19 23:46:02 +01:00

Compare commits

..

No commits in common. "fae713eae7967028943dc8649edd0c1201541144" and "7bd790dfbfcf853c7fcf56da4735979fd119f48f" have entirely different histories.

6 changed files with 57 additions and 85 deletions

View File

@ -77,7 +77,6 @@ void DCCWaveform::interruptHandler() {
if (cutoutNextTime) { if (cutoutNextTime) {
cutoutNextTime=false; cutoutNextTime=false;
railcomSampleWindow=false; // about to cutout, stop reading railcom data. railcomSampleWindow=false; // about to cutout, stop reading railcom data.
railcomCutoutCounter++;
DCCTimer::startRailcomTimer(9); DCCTimer::startRailcomTimer(9);
} }
byte sigMain=signalTransform[mainTrack.state]; byte sigMain=signalTransform[mainTrack.state];
@ -126,7 +125,6 @@ bool DCCWaveform::railcomPossible=false; // High accuracy only
volatile bool DCCWaveform::railcomActive=false; // switched on by user volatile bool DCCWaveform::railcomActive=false; // switched on by user
volatile bool DCCWaveform::railcomDebug=false; // switched on by user volatile bool DCCWaveform::railcomDebug=false; // switched on by user
volatile bool DCCWaveform::railcomSampleWindow=false; // true during packet transmit volatile bool DCCWaveform::railcomSampleWindow=false; // true during packet transmit
volatile byte DCCWaveform::railcomCutoutCounter=0; // cyclic cutout
bool DCCWaveform::setRailcom(bool on, bool debug) { bool DCCWaveform::setRailcom(bool on, bool debug) {
if (on && railcomPossible) { if (on && railcomPossible) {

View File

@ -87,9 +87,6 @@ class DCCWaveform {
inline static bool isRailcom() { inline static bool isRailcom() {
return railcomActive; return railcomActive;
}; };
inline static byte getRailcomCutoutCounter() {
return railcomCutoutCounter;
};
inline static bool isRailcomSampleWindow() { inline static bool isRailcomSampleWindow() {
return railcomSampleWindow; return railcomSampleWindow;
}; };
@ -128,7 +125,6 @@ class DCCWaveform {
static volatile bool railcomActive; // switched on by user static volatile bool railcomActive; // switched on by user
static volatile bool railcomDebug; // switched on by user static volatile bool railcomDebug; // switched on by user
static volatile bool railcomSampleWindow; // when safe to sample static volatile bool railcomSampleWindow; // when safe to sample
static volatile byte railcomCutoutCounter; // incremented for each cutout
static bool cutoutNextTime; // railcom static bool cutoutNextTime; // railcom
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
static RMTChannel *rmtMainChannel; static RMTChannel *rmtMainChannel;

View File

@ -1,6 +1,5 @@
// file exists to break #include dependency loop // file exists to break #include dependency loop
#include "EXRAIL2.h" #include "EXRAIL2.h"
#include "EXRAIL3.h"
void RMFT3::blockEvent(int16_t block, int16_t loco, bool entering) { void RMFT3::blockEvent(int16_t block, int16_t loco, bool entering) {
RMFT2::blockEvent(block,loco,entering); RMFT2::blockEvent(block,loco,entering);
}; };

View File

@ -45,6 +45,7 @@
#ifndef IO_I2CRailcom_h #ifndef IO_I2CRailcom_h
#define IO_I2CRailcom_h #define IO_I2CRailcom_h
#include "EXRAIL3.h"
#include "IODevice.h" #include "IODevice.h"
#include "I2CManager.h" #include "I2CManager.h"
#include "DIAG.h" #include "DIAG.h"
@ -53,23 +54,22 @@
// Debug and diagnostic defines, enable too many will result in slowing the driver // Debug and diagnostic defines, enable too many will result in slowing the driver
#define DIAG_I2CRailcom #define DIAG_I2CRailcom
#define DIAG_I2CRailcom_data
class I2CRailcom : public IODevice { class I2CRailcom : public IODevice {
private: private:
// SC16IS752 defines // SC16IS752 defines
uint8_t _UART_CH=0x00; // channel 0 or 1 flips each loop if npins>1 uint8_t _UART_CH=0x00; // channel 0 or 1 flips each loop if npins>1
byte _inbuf[65]; byte _inbuf[65];
byte _outbuf[2]; byte _outbuf[2];
byte cutoutCounter[2]; Railcom _channelMonitors[2];
Railcom * _channelMonitors[2]; int16_t _locoInBlock[2];
public: public:
// Constructor // Constructor
I2CRailcom(VPIN firstVpin, int nPins, I2CAddress i2cAddress){ I2CRailcom(VPIN firstVpin, int nPins, I2CAddress i2cAddress){
_firstVpin = firstVpin; _firstVpin = firstVpin;
_nPins = nPins; _nPins = nPins;
_I2CAddress = i2cAddress; _I2CAddress = i2cAddress;
_channelMonitors[0]=new Railcom(firstVpin);
if (nPins>1) _channelMonitors[1]=new Railcom(firstVpin+1);
addDevice(this); addDevice(this);
} }
@ -87,7 +87,7 @@ public:
DIAG(F("I2CRailcom: %s UART%S detected"), DIAG(F("I2CRailcom: %s UART%S detected"),
_I2CAddress.toString(), exists?F(""):F(" NOT")); _I2CAddress.toString(), exists?F(""):F(" NOT"));
if (!exists) return; if (!exists) return;
_UART_CH=0; _UART_CH=0;
Init_SC16IS752(); // Initialize UART0 Init_SC16IS752(); // Initialize UART0
if (_nPins>1) { if (_nPins>1) {
@ -106,31 +106,50 @@ public:
// return if in cutout or cutout very soon. // return if in cutout or cutout very soon.
if (!DCCWaveform::isRailcomSampleWindow()) return; if (!DCCWaveform::isRailcomSampleWindow()) return;
// IF we have 2 channels, flip channels each loop // IF we have 2 channels, flip channels each loop
if (_nPins>1) _UART_CH=_UART_CH?0:1; if (_nPins>1) _UART_CH=_UART_CH?0:1;
// have we read this cutout already?
auto cut=DCCWaveform::getRailcomCutoutCounter();
if (cutoutCounter[_UART_CH]==cut) return;
cutoutCounter[_UART_CH]=cut;
// Read incoming raw Railcom data, and process accordingly // Read incoming raw Railcom data, and process accordingly
auto inlength = UART_ReadRegister(REG_RXLV); auto inlength = UART_ReadRegister(REG_RXLV);
if (inlength==0) return; if (inlength==0) return;
if (inlength> sizeof(_inbuf)) inlength=sizeof(_inbuf);
_inbuf[0]=0; #ifdef DIAG_I2CRailcom
if (inlength>0) { DIAG(F("Railcom: %s/%d RX Fifo length: %d"),_I2CAddress.toString(), _UART_CH, inlength);
// Read data buffer from UART #endif
_outbuf[0]=(byte)(REG_RHR << 3 | _UART_CH << 1);
I2CManager.read(_I2CAddress, _inbuf, inlength, _outbuf, 1); // Read data buffer from UART
} _outbuf[0]=(byte)(REG_RHR << 3 | _UART_CH << 1);
I2CManager.read(_I2CAddress, _inbuf, inlength, _outbuf, 1);
// HK: Reset FIFO at end of read cycle // HK: Reset FIFO at end of read cycle
UART_WriteRegister(REG_FCR, 0x07,false); UART_WriteRegister(REG_FCR, 0x07,false);
#ifdef DIAG_I2CRailcom_data
DIAG(F("Railcom %s/%d RX FIFO Data"), _I2CAddress.toString(), _UART_CH);
for (int i = 0; i < inlength; i++){
DIAG(F("[0x%x]: 0x%x"), i, _inbuf[i]);
}
#endif
// Ask Railcom to interpret the raw data // Ask Railcom to interpret the channel1 loco
_channelMonitors[_UART_CH]->process(_inbuf,inlength); auto locoid=_channelMonitors[_UART_CH].getChannel1Loco(_inbuf);
#ifdef DIAG_I2CRailcom
DIAG(F("Railcom Channel1=%d"), locoid);
#endif
if (locoid<0) return; // -1 indicates Railcom needs another packet
// determine if loco in this block has changed
auto prevLoco=_locoInBlock[_UART_CH];
if (locoid==prevLoco) return;
// Previous loco (if any) is exiting block
if (prevLoco) RMFT3::blockEvent(_firstVpin+_UART_CH,prevLoco,false);
// new loco, if any, is entering block
_locoInBlock[_UART_CH]=locoid;
if (locoid) RMFT3::blockEvent(_firstVpin+_UART_CH,locoid,true);
} }

View File

@ -49,13 +49,7 @@
**/ **/
#include "Railcom.h" #include "Railcom.h"
#include "defines.h"
#include "FSH.h" #include "FSH.h"
#include "EXRAIL3.h"
#include "DIAG.h"
//#define DIAG_I2CRailcom_data
/** Table for 8-to-6 decoding of railcom data. This table can be indexed by the /** Table for 8-to-6 decoding of railcom data. This table can be indexed by the
* 8-bit value read from the railcom channel, and the return value will be * 8-bit value read from the railcom channel, and the return value will be
@ -135,70 +129,41 @@ const uint8_t HIGHFLASH decode[256] =
RMOB_LOGON_ENABLE_FEEDBACK = 15, RMOB_LOGON_ENABLE_FEEDBACK = 15,
}; };
Railcom::Railcom(uint16_t blockvpin) {
Railcom::Railcom() {
haveHigh=false; haveHigh=false;
haveLow=false; haveLow=false;
packetsWithNoData=0;
locoOnTrack=0;
vpin=blockvpin;
} }
/* returns -1: Call again next packet /* returns -1: Call again next packet
0: No loco on track 0: No loco on track
>0: loco id >0: loco id
*/ */
void Railcom::process(uint8_t * inbound, uint8_t length) { int16_t Railcom::getChannel1Loco(uint8_t * inbound) {
#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]);
}
#endif
auto v1=GETHIGHFLASH(decode,inbound[0]); auto v1=GETHIGHFLASH(decode,inbound[0]);
auto v2=(length>2) ? GETHIGHFLASH(decode,inbound[1]):0x0; if (v1>MAX_VALID) return -1;
uint16_t packet=(v1<<6) | (v2 & 0x3f); auto v2=GETHIGHFLASH(decode,inbound[1]);
if (v2>MAX_VALID) return -1;
auto packet=(v1<<6) | v2;
// packet is 12 bits TTTTDDDDDDDD // packet is 12 bits TTTTDDDDDDDD
auto type=packet>>8; auto type=packet>>8;
auto data= packet & 0xFF; auto data= packet & 0xFF;
if (type==RMOB_ADRHIGH) { if (type==RMOB_ADRHIGH) {
holdoverHigh=data; holdoverHigh=data;
haveHigh=true; haveHigh=true;
packetsWithNoData=0;
} }
else if (type==RMOB_ADRLOW) { else if (type==RMOB_ADRLOW) {
holdoverLow=data; holdoverLow=data;
haveLow=true; haveLow=true;
packetsWithNoData=0;
} }
else if (type==RMOB_EXT) { else if (type==RMOB_EXT) {
return; /* ignore*/ return -1; /* ignore*/
} }
else { else {
if (packetsWithNoData>MAX_WAIT_FOR_GLITCH) { haveHigh=false;
// treat as no loco haveLow=false;
haveHigh=false; return 0; // treat as no loco
haveLow=false;
// Previous loco (if any) is exiting block
blockEvent(false);
locoOnTrack=0;
return ;
}
packetsWithNoData++;
return; // need more data
} }
if (haveHigh && haveLow) { if (haveHigh && haveLow) return ((holdoverHigh<<8)| holdoverLow);
uint16_t thisLoco=((holdoverHigh<<8)| holdoverLow); return -1; // call again, need next packet
if (locoOnTrack!=thisLoco) {
// Previous loco (if any) is exiting block
blockEvent(false);
locoOnTrack=thisLoco;
blockEvent(true);
}
}
}
void Railcom::blockEvent(bool entering) {
#ifdef EXRAIL_ACTIVE
if (locoOnTrack) RMFT3::blockEvent(vpin,locoOnTrack,entering);
#endif
} }

View File

@ -24,22 +24,17 @@
class Railcom { class Railcom {
public: public:
Railcom(uint16_t vpin); Railcom();
/* returns -1: Call again next packet /* returns -1: Call again next packet
0: No loco on track 0: No loco on track
>0: loco id >0: loco id
*/ */
void process(uint8_t * inbound,uint8_t length); int16_t getChannel1Loco(uint8_t * inbound);
private: private:
void blockEvent(bool entering);
uint16_t locoOnTrack;
uint16_t vpin;
uint8_t holdoverHigh,holdoverLow; uint8_t holdoverHigh,holdoverLow;
bool haveHigh,haveLow; bool haveHigh,haveLow;
uint8_t packetsWithNoData;
static const byte MAX_WAIT_FOR_GLITCH=20; // number of dead or empty packets before assuming loco=0
}; };
#endif #endif