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.
fae713eae7
...
7bd790dfbf
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
61
Railcom.cpp
61
Railcom.cpp
@ -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
|
|
||||||
}
|
}
|
||||||
|
13
Railcom.h
13
Railcom.h
@ -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
|
Loading…
Reference in New Issue
Block a user