-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTPLDCC2.cppxxx
More file actions
144 lines (127 loc) · 3.96 KB
/
Copy pathTPLDCC2.cppxxx
File metadata and controls
144 lines (127 loc) · 3.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <Arduino.h>
#include <DIO2.h>
#include "DIAG.h"
#include "TPLDCC2.h"
#include "TPLDCC.h"
// An instance of this class handles the DCC transmissions for one track. (main or prog)
// Interrupts are marshalled via the statics.
// A track has a current transmit buffer, and a pending buffer.
// When the current buffer is exhausted, either the pending buffer (if there is one waiting) or an idle buffer.
const byte bitMask[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
TPLDCC1::TPLDCC1(byte powerPinNo, byte directionPinNo, byte sensePinNo, bool isMain) {
// establish appropriate pins
powerPin=Arduino_to_GPIO_pin(powerPinNo);
directionPin=Arduino_to_GPIO_pin(directionPinNo);
sensePin=sensePinNo;
isMainTrack=isMain;
packetPending=false;
transmitPacket=TPLDCC::idlePacket;
state=0;
bits_sent=0;
nextSampleDue=0;
}
void TPLDCC2::begin2() {
pinMode2f(powerPin,OUTPUT);
pinMode2f(directionPin,OUTPUT);
pinMode(sensePin,INPUT);
setPowerMode(POWERMODE::ON);
DIAG(F("\nTrack started sensePin=%d\n"),sensePin);
}
POWERMODE TPLDCC2::getPowerMode() {
return powerMode;
}
void TPLDCC2::setPowerMode(POWERMODE mode) {
powerMode=mode;
digitalWrite2f(powerPin, mode==POWERMODE::ON ? HIGH:LOW);
}
void TPLDCC2:: mirror(TPLDCC2 otherTrack) {
digitalWrite2f(directionPin,digitalRead2f(otherTrack.directionPin));
}
void TPLDCC2::checkPowerOverload() {
if (millis()<nextSampleDue) return;
int current;
switch (powerMode) {
case POWERMODE::OFF:
nextSampleDue=millis()+POWER_SAMPLE_OFF_WAIT;
break;
case POWERMODE::ON:
// Check current
current=analogRead(sensePin);
if (current < POWER_SAMPLE_MAX) nextSampleDue=millis()+POWER_SAMPLE_ON_WAIT;
else {
setPowerMode(POWERMODE::OVERLOAD);
DIAG(F("\n*** %s TRACK POWER OVERLOAD pin=%d current=%d max=%d ***\n"),isMainTrack?"MAIN":"PROG",sensePin,current,POWER_SAMPLE_MAX);
nextSampleDue=millis()+POWER_SAMPLE_OVERLOAD_WAIT;
}
break;
case POWERMODE::OVERLOAD:
// Try setting it back on after the OVERLOAD_WAIT
setPowerMode(POWERMODE::ON);
break;
}
}
bool TPLDCC2::startAckProcess() {
if (sensePin==0) return false;
int baxse=0;
for (int j = 0; j < ACK_BASE_COUNT; j++)
{
base+= (int)analogRead(sensePin);
}
ackBaseCurrent=base / ACK_BASE_COUNT;
return true;
}
bool TPLDCC2::getAck()
{
int threshold=ackBaseCurrent+ACK_SAMPLE_THRESHOLD;
for (int j = 0; j < ACK_SAMPLE_COUNT; j++)
{
if (analogRead(sensePin) > threshold) return true;
}
return false;
}
// process time-edge sensitive part of interrupt
// return true if second level required
bool TPLDCC2::interrupt1() {
// NOTE: this must consume transmission buffers even if the power is off
// otherwise can cause hangs in main loop waiting for the pendingBuffer.
switch (state) {
case 0: // start of bit transmission
digitalWrite2f(directionPin, HIGH);
state = 1;
return true; // must call interrupt2
case 1: // 58Ms after case 0
if (currentBit) {
digitalWrite2f(directionPin, LOW);
state = 0;
}
else state = 2;
break;
case 2: digitalWrite2f(directionPin, LOW);
state = 3;
break;
case 3: state = 0;
break;
}
return false;
}
void TPLDCC2::interrupt2() {
currentBit = transmitPacket.data[bits_sent / 8] & bitMask[ bits_sent % 8 ];
bits_sent++;
if (bits_sent >= transmitPacket.bits) {
bits_sent = 0;
// end of transmission buffer... repeat or switch to next message
if (transmitPacket.repeats > 0) {
transmitPacket.repeats--;
}
else {
transmitPacket= packetPending ? pendingPacket : TPLDCC::idlePacket;
packetPending=false;
}
}
}
// Wait until there is no packet pending, then make this pending
void TPLDCC2::schedulePacket(DCCPacket& newpacket) {
while(packetPending) delay(1);
pendingPacket=newpacket;
packetPending=true;
}