Skip to content

Commit

Permalink
Channel2 support
Browse files Browse the repository at this point in the history
  • Loading branch information
Asbelos committed Oct 22, 2024
1 parent dd42390 commit 9ccf1fe
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 34 deletions.
36 changes: 36 additions & 0 deletions DCC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand Down
4 changes: 3 additions & 1 deletion DCC.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions DCCEXParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,10 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[])
Diag::CMD = onOff;
return true;

case "RAILCOM"_hk: // <D RAILCOM ON/OFF>
Diag::RAILCOM = onOff;
return true;

#ifdef HAS_ENOUGH_MEMORY
case "WIFI"_hk: // <D WIFI ON/OFF>
Diag::WIFI = onOff;
Expand Down
66 changes: 36 additions & 30 deletions Railcom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<length;i++) {
if (i==2) Serial.write(' ');
Serial.write(hexchars[inbound[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);
Expand All @@ -188,35 +191,38 @@ 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;
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;
lastChannel1Loco=0;
// Previous locos (if any) is exiting block
DCC::clearBlock(vpin);
}
packetsWithNoData++;
}
5 changes: 2 additions & 3 deletions Railcom.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down
2 changes: 2 additions & 0 deletions StringFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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...) {
Expand Down
1 change: 1 addition & 0 deletions StringFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Diag {
static bool WITHROTTLE;
static bool ETHERNET;
static bool LCN;
static bool RAILCOM;

};

Expand Down

0 comments on commit 9ccf1fe

Please sign in to comment.