Skip to content

Commit 8d356ba

Browse files
committed
Railcom Update
1 parent a5484fa commit 8d356ba

File tree

6 files changed

+42
-76
lines changed

6 files changed

+42
-76
lines changed

DCC.cpp

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,47 +1239,3 @@ void DCC::displayCabList(Print * stream) {
12391239
StringFormatter::send(stream,F("<* Default momentum=%d/%d *>\n"),
12401240
DCC::defaultMomentumA,DCC::defaultMomentumD);
12411241
}
1242-
1243-
void DCC::setLocoInBlock(uint16_t loco, uint16_t blockid, bool exclusive) {
1244-
// avoid unused warnings when EXRAIL not active
1245-
(void)loco; (void)blockid; (void)exclusive;
1246-
1247-
// update block loco is in, tell exrail leaving old block, and entering new.
1248-
1249-
// NOTE: The loco table scanning is really inefficient and needs rewriting
1250-
// This was done once in the momentum poc.
1251-
#ifdef EXRAIL_ACTIVE
1252-
auto slot=LocoSlot::getSlot(loco,true);
1253-
if (!slot) return; // loco not known, nothing to do
1254-
1255-
auto oldBlock=slot->getBlockOccupied();
1256-
if (oldBlock==blockid) return;
1257-
if (oldBlock) RMFT2::blockEvent(oldBlock,loco,false);
1258-
slot->setBlockOccupied(blockid);
1259-
if (blockid) RMFT2::blockEvent(blockid,loco,true);
1260-
1261-
if (exclusive) {
1262-
SLOTLOOP {
1263-
if (slot->getLoco()!=loco && slot->getBlockOccupied()==blockid) {
1264-
RMFT2::blockEvent(blockid,slot->getLoco(),false);
1265-
slot->setBlockOccupied(0);
1266-
}
1267-
}
1268-
}
1269-
1270-
#endif
1271-
}
1272-
1273-
void DCC::clearBlock(uint16_t blockid) {
1274-
(void)blockid; // avoid unused warning when EXRAIL not active
1275-
// clear block occupied by loco, tell exrail about all leavers
1276-
#ifdef EXRAIL_ACTIVE
1277-
SLOTLOOP {
1278-
1279-
if (slot->getBlockOccupied()==blockid) {
1280-
RMFT2::blockEvent(blockid,slot->getLoco(),false);
1281-
slot->setBlockOccupied(0);
1282-
}
1283-
}
1284-
#endif
1285-
}

DCC.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ class DCC
8383
static void verifyCVByte(int16_t cv, byte byteValue, ACK_CALLBACK callback);
8484
static void verifyCVBit(int16_t cv, byte bitNum, bool bitValue, ACK_CALLBACK callback);
8585
static bool setTime(uint16_t minutes,uint8_t speed, bool suddenChange);
86-
static void setLocoInBlock(uint16_t loco, uint16_t blockid, bool exclusive);
87-
static void clearBlock(uint16_t blockid);
8886
static void getDriveawayLocoId(ACK_CALLBACK callback);
8987
static void getLocoId(ACK_CALLBACK callback);
9088
static void getConsistId(ACK_CALLBACK callback);

DCCTimerAVR.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,44 +72,44 @@ void DCCTimer::startRailcomTimer(byte brakePin) {
7272
- Sets the Railcom pin high at first tick and subsequent ticks
7373
until its reset to setting pin 9 low at next tick.
7474
75-
- Cycles at 436uS so the second tick is the
75+
- Cycles at cutoutDuration so the second tick is the
7676
correct distance from the cutout.
7777
7878
- Waveform code is responsible for resetting
7979
any time between the first and second tick.
8080
(there will be 7 DCC timer1 ticks in which to do this.)
8181
8282
*/
83-
const int cutoutDuration = 430; // Desired interval in microseconds
84-
const int cycle=cutoutDuration/2;
83+
const int Tcs=(26+32)/2; // half way spec Desired time from idealised setup call (at previous DCC timer interrupt) to the cutout.
84+
const int Tce=(454+488)/2; // half way spec (460..480uS) Time from start of cutout to end of cutout.
85+
const int cutoutDuration = Tce-Tcs; // Desired interval in microseconds
86+
const int cycle=(cutoutDuration+1)/2; //
8587

86-
const byte RailcomFudge0=58+58+29;
88+
const byte delayBeforeCutout=58+58+Tcs; // Expected time from idealised setup call (at previous DCC timer interrupt) to the cutout. This is the time we need to wait before we can set pin 9 high. We will then set pin 9 low at the next tick which is cutoutDuration later. This value should be reduced to reflect the Timer1 value measuring the time since the previous hardware interrupt.
8789

8890
// Set Timer2 to CTC mode with set on compare match
8991
TCCR2A = (1 << WGM21) | (1 << COM2B0) | (1 << COM2B1);
9092
// Prescaler of 32
9193
TCCR2B = (1 << CS21) | (1 << CS20);
92-
OCR2A = cycle-1; // Compare match value for 430 uS
94+
OCR2A = cycle; // Compare match value for cutout duration
9395
// Enable Timer2 output on pin 9 (OC2B)
9496
DDRB |= (1 << DDB1);
9597

96-
// RailcomFudge2 is the expected time from idealised
98+
// timeSlip is the expected time from idealised
9799
// setup call (at previous DCC timer interrupt) to the cutout.
98100
// This value should be reduced to reflect the Timer1 value
99101
// measuring the time since the previous hardware interrupt
100-
byte tcfudge=TCNT1/16;
101-
TCNT2=cycle-RailcomFudge0/2+tcfudge/2;
102102

103-
104-
// Previous TIMER1 Tick was at rising end-of-packet bit
105-
// Cutout starts half way through first preamble
106-
// that is 2.5 * 58uS later.
107-
}
103+
// tcnt1 = prescaler 64, tcnt2 prescaler=32
104+
noInterrupts();
105+
uint16_t timeSlip=(TCNT1/64)*32;
106+
TCNT2=cycle-timeSlip/2-delayBeforeCutout/2;
107+
interrupts();
108+
}
108109

109110
void DCCTimer::ackRailcomTimer() {
110111
// Change Timer2 to CTC mode with RESET pin 9 on next compare match
111112
TCCR2A = (1 << WGM21) | (1 << COM2B1);
112-
// diagnostic digitalWrite(4,LOW);
113113
}
114114

115115

LocoSlot.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ void LocoSlot::prepare(uint16_t locoId) {
3131
momentumA=MOMENTUM_USE_DEFAULT;
3232
momentumD=MOMENTUM_USE_DEFAULT;
3333
targetSpeed=128;
34-
blockOccupied=0;
3534
savedSpeedCode=0;
3635

3736
snifferSpeedCode=128; // default direction forward

LocoSlot.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ class LocoSlot {
4343
LocoSlot* consistNext;
4444

4545
// DCC data for this loco
46-
uint16_t loco; // DCC loco id
47-
uint16_t blockOccupied; // railcom detected block
48-
46+
uint16_t loco; // DCC loco id
4947
byte targetSpeed; // speed set by throttle
5048
byte speedCode; // current DCC speed and direction
5149
byte snifferSpeedCode; // sniffer speed and direction
@@ -93,8 +91,6 @@ class LocoSlot {
9391
void setGroupFlags(byte v) { groupFlags=v; }
9492
uint32_t getFunctions() { return functions; }
9593
void setFunctions(uint32_t v) { functions=v; }
96-
uint16_t getBlockOccupied() { return blockOccupied; }
97-
void setBlockOccupied(uint16_t v) { blockOccupied=v; }
9894
void forget();
9995
void saveSpeed();
10096
byte getSavedSpeedCode() ;

Railcom.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,31 @@
1818
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
1919
*/
2020

21+
22+
/*
23+
This class acts as a 3 way coordinator between
24+
- the DCC waveform cutout generator,
25+
- the incoming railcom collector notifications
26+
- and the EXRAIL2 block enter/exit system
27+
*/
2128
#include "Railcom.h"
2229
#include "DCC.h"
2330
#include "DCCWaveform.h"
31+
#include "EXRAIL2.h"
2432

2533
uint16_t Railcom::expectLoco=0;
2634
uint16_t Railcom::expectCV=0;
2735
unsigned long Railcom::expectWait=0;
2836
ACK_CALLBACK Railcom::expectCallback=0;
2937

38+
enum ResponseType: byte {
39+
ENTER_BLOCK=0x00, // loco entering block, block id and loco id follow
40+
EXIT_BLOCK=0x80, // loco exiting block, block id and loco id follow
41+
CV_VALUE=0x40, // cv value read from a POM, cv value follow
42+
CV_VALUE_LIST=0xC0, // list of cv values read from a POM, cv id and 4 values follow
43+
};
44+
45+
3046
// anticipate is used when waiting for a CV read from a railcom loco
3147
void Railcom::anticipate(uint16_t loco, uint16_t cv, ACK_CALLBACK callback) {
3248
expectLoco=loco;
@@ -42,31 +58,32 @@ void Railcom::process(int16_t firstVpin,byte * buffer, byte length) {
4258
byte i=0;
4359
while (i<length) {
4460
byte block=buffer[i] & 0x3f;
45-
byte type=buffer[i]>>6;
46-
61+
(void)block; // avoid compiler warning if not using EXRAIL
62+
byte type=buffer[i] & 0xc0;
63+
4764
switch (type) {
4865
// a type=0 record has block,locohi,locolow
49-
case 0: {
66+
case ENTER_BLOCK:
67+
case EXIT_BLOCK:
68+
{
69+
#ifdef EXRAIL_ACTIVE
5070
uint16_t locoid= ((uint16_t)buffer[i+1])<<8 | ((uint16_t)buffer[i+2]);
51-
DIAG(F("RC3 b=%d l=%d"),block,locoid);
52-
53-
if (locoid==0) DCC::clearBlock(firstVpin+block);
54-
else DCC::setLocoInBlock(locoid,firstVpin+block,true);
71+
RMFT2::blockEvent(firstVpin+block,locoid,type==ENTER_BLOCK);
72+
#endif
5573
i+=3;
5674
}
5775
break;
58-
case 2: { // csv value from POM read
76+
case CV_VALUE: { // csv value from POM read
5977
byte value=buffer[i+1];
6078
if (expectCV && DCCWaveform::getRailcomLastLocoAddress()==expectLoco) {
61-
DCC::setLocoInBlock(expectLoco,firstVpin+block,false);
6279
if (expectCallback) expectCallback(value);
6380
expectCV=0;
6481
}
6582
i+=2;
6683
}
6784
break;
6885
default:
69-
DIAG(F("Unknown RC Collector code %d"),type);
86+
DIAG(F("Unknown RC Collector code 0x%x"),type);
7087
return;
7188
}
7289
}

0 commit comments

Comments
 (0)