DCCpp
This is the library version of a program for Arduino to control railroading DCC devices.
SignalGenerator_esp32.cpp
1 /**********************************************************************
2 DCC++ BASE STATION FOR ESP32
3 
4 COPYRIGHT (c) 2017 Mike Dunston
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14  You should have received a copy of the GNU General Public License
15  along with this program. If not, see http://www.gnu.org/licenses
16 **********************************************************************/
17 
18 #ifdef ESP32
19 
20 #include "DCCppESP32.h"
21 #include <esp32-hal-timer.h>
22 #include <driver/adc.h>
23 #include <esp_adc_cal.h>
24 
25 #include "SignalGenerator_esp32.h"
26 #include "MotorBoard.h"
27 
28 // Define constants for DCC Signal pattern
29 
30 // this controls the timer tick frequency
31 #define DCC_TIMER_PRESCALE 80
32 
33 // number of microseconds for sending a zero via the DCC encoding
34 #define DCC_ZERO_BIT_TOTAL_DURATION 196
35 // number of microseconds for each half of the DCC signal for a zero
36 #define DCC_ZERO_BIT_PULSE_DURATION 98
37 
38 // number of microseconds for sending a one via the DCC encoding
39 #define DCC_ONE_BIT_TOTAL_DURATION 116
40 // number of microseconds for each half of the DCC signal for a one
41 #define DCC_ONE_BIT_PULSE_DURATION 58
42 
43 SignalGenerator dccSignalGenerators[2];
44 
45 uint8_t idlePacket[] = {0xFF, 0x00};
46 uint8_t resetPacket[] = {0x00, 0x00};
47 
48 void startDCCSignalGenerators() {
49  dccSignalGenerators[SIGNAL_GENERATOR_MAIN].configureSignal<SIGNAL_GENERATOR_MAIN>("OPERATIONS", DIRECTION_MOTOR_CHANNEL_PIN_MAIN, 512);
50  dccSignalGenerators[SIGNAL_GENERATOR_PROG].configureSignal<SIGNAL_GENERATOR_PROG>("PROGRAMMING", DIRECTION_MOTOR_CHANNEL_PIN_PROG, 64);
51 }
52 
53 void loadBytePacket(SignalGenerator &signalGenerator, uint8_t *data, uint8_t length, uint8_t repeatCount) {
54  std::vector<uint8_t> packet;
55  for(int i = 0; i < length; i++) {
56  packet.push_back(data[i]);
57  }
58  signalGenerator.loadPacket(packet, repeatCount);
59 }
60 
61 bool IRAM_ATTR SignalGenerator::getNextBitToSend() {
62  const uint8_t bitMask[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
63  bool result = false;
64  // if we are processing a packet, check if we have sent all bits or repeats
65  if(_currentPacket != NULL) {
66  if(_currentPacket->currentBit == _currentPacket->numberOfBits) {
67  if(_currentPacket->numberOfRepeats > 0) {
68  _currentPacket->numberOfRepeats--;
69  _currentPacket->currentBit = 0;
70  } else {
71  // if the current packet is not the idle pack get rid of it
72  if(_currentPacket != &_idlePacket) {
73  _availablePackets.push(_currentPacket);
74  }
75  _currentPacket = NULL;
76  }
77  }
78  }
79  // if we don't have a packet, check if we have any to send otherwise
80  // queue up an idle packet
81  if (_currentPacket == NULL) {
82  if(!_toSend.empty()) {
83  _currentPacket = _toSend.front();
84  _toSend.pop();
85  } else {
86  _currentPacket = &_idlePacket;
87  _currentPacket->currentBit = 0;
88  }
89  }
90  // if we have a packet to send, get the next bit from the packet
91  if(_currentPacket != NULL) {
92  result = _currentPacket->buffer[_currentPacket->currentBit / 8] & bitMask[_currentPacket->currentBit % 8];
93  _currentPacket->currentBit++;
94  }
95  return result;
96 }
97 
98 void SignalGenerator::loadPacket(std::vector<uint8_t> data, int numberOfRepeats) {
99  #if DEBUG_SIGNAL_GENERATOR
100  log_v("[%s] Preparing DCC Packet containing %d bytes, %d repeats [%d in queue]", _name.c_str(), data.size(), numberOfRepeats, _toSend.size());
101  #endif
102  while(_availablePackets.empty()) {
103  delay(2);
104  }
105  Packet *packet = _availablePackets.front();
106  _availablePackets.pop();
107 
108  packet->numberOfRepeats = numberOfRepeats;
109  packet->currentBit = 0;
110 
111  // calculate checksum (XOR)
112  // add first byte as checksum byte
113  uint8_t checksum = data[0];
114  for(int i = 1; i < data.size(); i++)
115  checksum ^= data[i];
116  data.push_back(checksum);
117 
118  // standard DCC preamble
119  packet->buffer[0] = 0xFF;
120  packet->buffer[1] = 0xFF;
121  // first bit of actual data at the end of the preamble
122  packet->buffer[2] = 0xFC + bitRead(data[0], 7);
123  packet->buffer[3] = data[0] << 1;
124  packet->buffer[4] = data[1];
125  packet->buffer[5] = data[2] >> 1;
126  packet->buffer[6] = data[2] << 7;
127 
128  if(data.size() == 3){
129  packet->numberOfBits = 49;
130  } else{
131  packet->buffer[6] += data[3] >> 2;
132  packet->buffer[7] = data[3] << 6;
133  if(data.size() == 4){
134  packet->numberOfBits = 58;
135  } else{
136  packet->buffer[7] += data[4] >> 3;
137  packet->buffer[8] = data[4] << 5;
138  if(data.size() == 5){
139  packet->numberOfBits = 67;
140  } else{
141  packet->buffer[8] += data[5] >> 4;
142  packet->buffer[9] = data[5] << 4;
143  packet->numberOfBits = 76;
144  } // >5 bytes
145  } // >4 bytes
146  } // >3 bytes
147 
148 #if SHOW_DCC_PACKETS
149  String packetHex = "";
150  for(int i = 0; i < data.size() + 1; i++) {
151  packetHex += String(packet->buffer[i], HEX) + " ";
152  }
153  log_v("[%s] <* %s / %d / %d>n", _name.c_str(), packetHex.c_str(),
154  packet->numberOfBits, packet->numberOfRepeats);
155 #endif
156  _toSend.push(packet);
157 }
158 
159 template<int timerIndex>
160 void IRAM_ATTR signalGeneratorPulseTimer(void)
161 {
162  auto& signalGenerator = dccSignalGenerators[timerIndex];
163  if(signalGenerator.getNextBitToSend()) {
164  timerAlarmWrite(signalGenerator._pulseTimer, DCC_ONE_BIT_PULSE_DURATION, false);
165  timerAlarmWrite(signalGenerator._fullCycleTimer, DCC_ONE_BIT_TOTAL_DURATION, true);
166  } else {
167  timerAlarmWrite(signalGenerator._pulseTimer, DCC_ZERO_BIT_PULSE_DURATION, false);
168  timerAlarmWrite(signalGenerator._fullCycleTimer, DCC_ZERO_BIT_TOTAL_DURATION, true);
169  }
170  timerWrite(signalGenerator._pulseTimer, 0);
171  timerAlarmEnable(signalGenerator._pulseTimer);
172  digitalWrite(signalGenerator._directionPin, HIGH);
173 }
174 
175 template<int timerIndex>
176 void IRAM_ATTR signalGeneratorDirectionTimer()
177 {
178  auto& signalGenerator = dccSignalGenerators[timerIndex];
179  digitalWrite(signalGenerator._directionPin, LOW);
180 }
181 
182 template<int timerIndex>
183 void SignalGenerator::configureSignal(String name, uint8_t directionPin, uint16_t maxPackets) {
184  _name = name;
185  _directionPin = directionPin;
186  _currentPacket = NULL;
187 
188  // create packets for this signal generator up front, they will be reused until
189  // the base station is shutdown
190  for(int index = 0; index < maxPackets; index++) {
191  _availablePackets.push(new Packet());
192  }
193 
194  // force the directionPin to low since it will be controlled by the DCC timer
195  pinMode(_directionPin, INPUT);
196  digitalWrite(_directionPin, LOW);
197  pinMode(_directionPin, OUTPUT);
198 
199  // inject the required reset and idle packets into the queue
200  // this is required as part of S-9.2.4 section A
201  // at least 20 reset packets and 10 idle packets must be sent upon initialization
202  // of the base station to force decoders to exit service mode.
203  log_i("[%s] Adding reset packet to packet queue", _name.c_str());
204  loadBytePacket(dccSignalGenerators[timerIndex], resetPacket, 2, 20);
205  log_i("[%s] Adding idle packet to packet queue", _name.c_str());
206  loadBytePacket(dccSignalGenerators[timerIndex], idlePacket, 2, 10);
207 
208  log_i("[%s] Starting Timer(%d) for generating DCC Signal (Full Wave)", _name.c_str(), 2 * timerIndex);
209  _fullCycleTimer = timerBegin(2 * timerIndex, DCC_TIMER_PRESCALE, true);
210  log_i("[%s] Attaching interrupt handler to Timer(%d)", _name.c_str(), 2 * timerIndex);
211  timerAttachInterrupt(_fullCycleTimer, &signalGeneratorPulseTimer<timerIndex>, true);
212  log_i("[%s] Configuring alarm on Timer(%d) to %dus", _name.c_str(), 2 * timerIndex, DCC_ONE_BIT_TOTAL_DURATION);
213  timerAlarmWrite(_fullCycleTimer, DCC_ONE_BIT_TOTAL_DURATION, true);
214  log_i("[%s] Setting load on Timer(%d) to zero", _name.c_str(), 2 * timerIndex);
215  timerWrite(_fullCycleTimer, 0);
216 
217  log_i("[%s] Starting Timer(%d) for generating DCC Signal (Half Wave)", _name.c_str(), 2 * timerIndex + 1);
218  _pulseTimer = timerBegin(2*timerIndex + 1, DCC_TIMER_PRESCALE, true);
219  log_i("[%s] Attaching interrupt handler to Timer(%d)", _name.c_str(), 2 * timerIndex + 1);
220  timerAttachInterrupt(_pulseTimer, &signalGeneratorDirectionTimer<timerIndex>, true);
221  log_i("[%s] Configuring alarm on Timer(%d) to %dus", _name.c_str(), 2 * timerIndex + 1, DCC_ONE_BIT_TOTAL_DURATION / 2);
222  timerAlarmWrite(_pulseTimer, DCC_ONE_BIT_PULSE_DURATION, false);
223  log_i("[%s] Setting load on Timer(%d) to zero", _name.c_str(), 2 * timerIndex + 1);
224  timerWrite(_pulseTimer, 0);
225 
226  log_i("[%s] Enabling alarm on Timer(%d)", _name.c_str(), 2 * timerIndex);
227  timerAlarmEnable(_fullCycleTimer);
228  log_i("[%s] Enabling alarm on Timer(%d)", _name.c_str(), 2 * timerIndex + 1);
229  timerAlarmEnable(_pulseTimer);
230 }
231 
232 void SignalGenerator::waitForQueueEmpty() {
233  while(!_toSend.empty()) {
234  log_i("[%s] Waiting for %d packets to send...", _name.c_str(), _toSend.size());
235  delay(10);
236  }
237 }
238 
239 bool SignalGenerator::isQueueEmpty() {
240  return _toSend.empty();
241 }
242 
243 uint64_t sampleADCChannel(adc1_channel_t channel, uint8_t sampleCount) {
244  uint64_t current = 0;
245  int successfulReads = 0;
246  for(uint8_t sampleReadCount = 0; sampleReadCount < sampleCount; sampleReadCount++) {
247  int reading = adc1_get_raw(channel);
248  if(reading > 0) {
249  current += reading;
250  successfulReads++;
251  }
252  delay(2);
253  }
254  if(successfulReads) {
255  current /= successfulReads;
256  }
257  return current;
258 }
259 
260 // number of analogRead samples to take when monitoring current after a CV verify (bit or byte) has been sent
261 const uint8_t CVSampleCount = 250;
262 
263 int16_t readCV(const uint16_t cv) {
264  const adc1_channel_t adcChannel = MotorBoardManager::getBoardByName("PROG")->getADC1Channel();
265  const uint16_t milliAmpAck = (4096 / MotorBoardManager::getBoardByName("PROG")->getMaxMilliAmps()) * 60;
266  uint8_t readCVBitPacket[4] = { (uint8_t)(0x78 + (highByte(cv - 1) & 0x03)), lowByte(cv - 1), 0x00, 0x00};
267  uint8_t verifyCVBitPacket[4] = { (uint8_t)(0x74 + (highByte(cv - 1) & 0x03)), lowByte(cv - 1), 0x00, 0x00};
268  int16_t cvValue = 0;
269  log_d("[PROG] Attempting to read CV %d, samples: %d, ack value: %d", cv, CVSampleCount, milliAmpAck);
270 
271  for(uint8_t bit = 0; bit < 8; bit++) {
272  log_d("[PROG] CV %d, bit [%d/7]", cv, bit);
273  readCVBitPacket[2] = 0xE8 + bit;
274  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 3);
275  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], readCVBitPacket, 3, 5);
276  dccSignalGenerators[SIGNAL_GENERATOR_PROG].waitForQueueEmpty();
277  if(sampleADCChannel(adcChannel, CVSampleCount) > milliAmpAck) {
278  log_d("[PROG] CV %d, bit [%d/7] ON", cv, bit);
279  bitWrite(cvValue, bit, 1);
280  } else {
281  log_d("[PROG] CV %d, bit [%d/7] OFF", cv, bit);
282  }
283  }
284 
285  // verify the byte we received
286  verifyCVBitPacket[2] = cvValue & 0xFF;
287  log_d("[PROG] CV %d, read value %d, verifying", cv, cvValue);
288  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 3);
289  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], verifyCVBitPacket, 3, 5);
290  dccSignalGenerators[SIGNAL_GENERATOR_PROG].waitForQueueEmpty();
291  bool verified = false;
292  if(sampleADCChannel(adcChannel, CVSampleCount) > milliAmpAck) {
293  verified = true;
294  log_d("[PROG] CV %d, verified", cv);
295  }
296  if(!verified) {
297  log_w("[PROG] CV %d, could not be verified", cv);
298  cvValue = -1;
299  }
300  return cvValue;
301 }
302 
303 bool writeProgCVByte(const uint16_t cv, const uint8_t cvValue) {
304  const adc1_channel_t adcChannel = MotorBoardManager::getBoardByName("PROG")->getADC1Channel();
305  const uint16_t milliAmpAck = (4096 / MotorBoardManager::getBoardByName("PROG")->getMaxMilliAmps()) * 60;
306  const uint8_t maxWriteAttempts = 5;
307  uint8_t writeCVBytePacket[4] = { (uint8_t)(0x7C + (highByte(cv - 1) & 0x03)), lowByte(cv - 1), cvValue, 0x00};
308  uint8_t verifyCVBytePacket[4] = { (uint8_t)(0x74 + (highByte(cv - 1) & 0x03)), lowByte(cv - 1), cvValue, 0x00};
309  bool writeVerified = false;
310 
311  for(uint8_t attempt = 1; attempt <= maxWriteAttempts && !writeVerified; attempt++) {
312  log_d("[PROG %d/%d] Attempting to write CV %d as %d", attempt, maxWriteAttempts, cv, cvValue);
313  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 1);
314  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], writeCVBytePacket, 3, 4);
315  dccSignalGenerators[SIGNAL_GENERATOR_PROG].waitForQueueEmpty();
316  // verify that the decoder received the write byte packet and sent an ACK
317  if(sampleADCChannel(adcChannel, CVSampleCount) > milliAmpAck) {
318  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 3);
319  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], verifyCVBytePacket, 3, 5);
320  dccSignalGenerators[SIGNAL_GENERATOR_PROG].waitForQueueEmpty();
321  // check that decoder sends an ACK for the verify operation
322  if(sampleADCChannel(adcChannel, CVSampleCount) > milliAmpAck) {
323  writeVerified = true;
324  log_d("[PROG] CV %d write value %d verified.", cv, cvValue);
325  }
326  } else {
327  log_w("[PROG] CV %d write value %d could not be verified.", cv, cvValue);
328  }
329  log_i("[PROG] Sending decoder reset packet");
330  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 3);
331  }
332  return writeVerified;
333 }
334 
335 bool writeProgCVBit(const uint16_t cv, const uint8_t bit, const bool value) {
336  const adc1_channel_t adcChannel = MotorBoardManager::getBoardByName("PROG")->getADC1Channel();
337  const uint16_t milliAmpAck = (4096 / MotorBoardManager::getBoardByName("PROG")->getMaxMilliAmps()) * 60;
338  const uint8_t maxWriteAttempts = 5;
339  uint8_t writeCVBitPacket[4] = { (uint8_t)(0x78 + (highByte(cv - 1) & 0x03)), lowByte(cv - 1), (uint8_t)(0xF0 + bit + value * 8), 0x00};
340  uint8_t verifyCVBitPacket[4] = { (uint8_t)(0x74 + (highByte(cv - 1) & 0x03)), lowByte(cv - 1), (uint8_t)(0xB0 + bit + value * 8), 0x00};
341  bool writeVerified = false;
342 
343  for(uint8_t attempt = 1; attempt <= maxWriteAttempts && !writeVerified; attempt++) {
344  log_d("[PROG %d/%d] Attempting to write CV %d bit %d as %d", attempt, maxWriteAttempts, cv, bit, value);
345  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 1);
346  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], writeCVBitPacket, 3, 4);
347  dccSignalGenerators[SIGNAL_GENERATOR_PROG].waitForQueueEmpty();
348  // verify that the decoder received the write byte packet and sent an ACK
349  if(sampleADCChannel(adcChannel, CVSampleCount) > milliAmpAck) {
350  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 3);
351  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], verifyCVBitPacket, 3, 5);
352  dccSignalGenerators[SIGNAL_GENERATOR_PROG].waitForQueueEmpty();
353  // check that decoder sends an ACK for the verify operation
354  if(sampleADCChannel(adcChannel, CVSampleCount) > milliAmpAck) {
355  writeVerified = true;
356  log_d("[PROG %d/%d] CV %d write bit %d verified.", attempt, maxWriteAttempts, cv, bit);
357  }
358  } else {
359  log_w("[PROG %d/%d] CV %d write bit %d could not be verified.", attempt, maxWriteAttempts, cv, bit);
360  }
361  log_i("[PROG] Sending decoder reset packet");
362  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 3);
363  }
364  return writeVerified;
365 }
366 
367 void writeOpsCVByte(const uint16_t locoNumber, const uint16_t cv, const uint8_t cvValue) {
368  if(locoNumber > 127) {
369  uint8_t writeCVBytePacket[] = {
370  (uint8_t)(0xC0 | highByte(locoNumber)),
371  lowByte(locoNumber),
372  (uint8_t)(0xEC + (highByte(cv - 1) & 0x03)),
373  lowByte(cv - 1),
374  cvValue,
375  0x00};
376  log_d("[OPS] Updating CV %d to %d for loco %d", cv, cvValue, locoNumber);
377  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_MAIN], writeCVBytePacket, 5, 4);
378  } else {
379  uint8_t writeCVBytePacket[] = {
380  lowByte(locoNumber),
381  (uint8_t)(0xEC + (highByte(cv - 1) & 0x03)),
382  lowByte(cv - 1),
383  cvValue,
384  0x00};
385  log_d("[OPS] Updating CV %d to %d for loco %d", cv, cvValue, locoNumber);
386  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_MAIN], writeCVBytePacket, 4, 4);
387  }
388 }
389 
390 void writeOpsCVBit(const uint16_t locoNumber, const uint16_t cv, const uint8_t bit, const bool value) {
391  if(locoNumber > 127) {
392  uint8_t writeCVBitPacket[] = {
393  (uint8_t)(0xC0 | highByte(locoNumber)),
394  lowByte(locoNumber),
395  (uint8_t)(0xE8 + (highByte(cv - 1) & 0x03)),
396  lowByte(cv - 1),
397  (uint8_t)(0xF0 + bit + value * 8),
398  0x00};
399  log_d("[OPS] Updating CV %d bit %d to %d for loco %d", cv, bit, value, locoNumber);
400  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_MAIN], writeCVBitPacket, 5, 4);
401  } else {
402  uint8_t writeCVBitPacket[] = {
403  lowByte(locoNumber),
404  (uint8_t)(0xE8 + (highByte(cv - 1) & 0x03)),
405  lowByte(cv - 1),
406  (uint8_t)(0xF0 + bit + value * 8),
407  0x00};
408  log_d("[OPS] Updating CV %d bit %d to %d for loco %d", cv, bit, value, locoNumber);
409  loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_MAIN], writeCVBitPacket, 4, 4);
410  }
411 }
412 #endif