20 #include "DCCppESP32.h" 21 #include <esp32-hal-timer.h> 22 #include <driver/adc.h> 23 #include <esp_adc_cal.h> 25 #include "SignalGenerator_esp32.h" 26 #include "MotorBoard.h" 31 #define DCC_TIMER_PRESCALE 80 34 #define DCC_ZERO_BIT_TOTAL_DURATION 196 36 #define DCC_ZERO_BIT_PULSE_DURATION 98 39 #define DCC_ONE_BIT_TOTAL_DURATION 116 41 #define DCC_ONE_BIT_PULSE_DURATION 58 43 SignalGenerator dccSignalGenerators[2];
45 uint8_t idlePacket[] = {0xFF, 0x00};
46 uint8_t resetPacket[] = {0x00, 0x00};
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);
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]);
58 signalGenerator.loadPacket(packet, repeatCount);
61 bool IRAM_ATTR SignalGenerator::getNextBitToSend() {
62 const uint8_t bitMask[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
65 if(_currentPacket != NULL) {
66 if(_currentPacket->currentBit == _currentPacket->numberOfBits) {
67 if(_currentPacket->numberOfRepeats > 0) {
68 _currentPacket->numberOfRepeats--;
69 _currentPacket->currentBit = 0;
72 if(_currentPacket != &_idlePacket) {
73 _availablePackets.push(_currentPacket);
75 _currentPacket = NULL;
81 if (_currentPacket == NULL) {
82 if(!_toSend.empty()) {
83 _currentPacket = _toSend.front();
86 _currentPacket = &_idlePacket;
87 _currentPacket->currentBit = 0;
91 if(_currentPacket != NULL) {
92 result = _currentPacket->buffer[_currentPacket->currentBit / 8] & bitMask[_currentPacket->currentBit % 8];
93 _currentPacket->currentBit++;
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());
102 while(_availablePackets.empty()) {
105 Packet *packet = _availablePackets.front();
106 _availablePackets.pop();
108 packet->numberOfRepeats = numberOfRepeats;
109 packet->currentBit = 0;
113 uint8_t checksum = data[0];
114 for(
int i = 1; i < data.size(); i++)
116 data.push_back(checksum);
119 packet->buffer[0] = 0xFF;
120 packet->buffer[1] = 0xFF;
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;
128 if(data.size() == 3){
129 packet->numberOfBits = 49;
131 packet->buffer[6] += data[3] >> 2;
132 packet->buffer[7] = data[3] << 6;
133 if(data.size() == 4){
134 packet->numberOfBits = 58;
136 packet->buffer[7] += data[4] >> 3;
137 packet->buffer[8] = data[4] << 5;
138 if(data.size() == 5){
139 packet->numberOfBits = 67;
141 packet->buffer[8] += data[5] >> 4;
142 packet->buffer[9] = data[5] << 4;
143 packet->numberOfBits = 76;
149 String packetHex =
"";
150 for(
int i = 0; i < data.size() + 1; i++) {
151 packetHex += String(packet->buffer[i], HEX) +
" ";
153 log_v(
"[%s] <* %s / %d / %d>n", _name.c_str(), packetHex.c_str(),
154 packet->numberOfBits, packet->numberOfRepeats);
156 _toSend.push(packet);
159 template<
int timerIndex>
160 void IRAM_ATTR signalGeneratorPulseTimer(
void)
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);
167 timerAlarmWrite(signalGenerator._pulseTimer, DCC_ZERO_BIT_PULSE_DURATION,
false);
168 timerAlarmWrite(signalGenerator._fullCycleTimer, DCC_ZERO_BIT_TOTAL_DURATION,
true);
170 timerWrite(signalGenerator._pulseTimer, 0);
171 timerAlarmEnable(signalGenerator._pulseTimer);
172 digitalWrite(signalGenerator._directionPin, HIGH);
175 template<
int timerIndex>
176 void IRAM_ATTR signalGeneratorDirectionTimer()
178 auto& signalGenerator = dccSignalGenerators[timerIndex];
179 digitalWrite(signalGenerator._directionPin, LOW);
182 template<
int timerIndex>
183 void SignalGenerator::configureSignal(String name, uint8_t directionPin, uint16_t maxPackets) {
185 _directionPin = directionPin;
186 _currentPacket = NULL;
190 for(
int index = 0; index < maxPackets; index++) {
191 _availablePackets.push(
new Packet());
195 pinMode(_directionPin, INPUT);
196 digitalWrite(_directionPin, LOW);
197 pinMode(_directionPin, OUTPUT);
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);
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);
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);
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);
232 void SignalGenerator::waitForQueueEmpty() {
233 while(!_toSend.empty()) {
234 log_i(
"[%s] Waiting for %d packets to send...", _name.c_str(), _toSend.size());
239 bool SignalGenerator::isQueueEmpty() {
240 return _toSend.empty();
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);
254 if(successfulReads) {
255 current /= successfulReads;
261 const uint8_t CVSampleCount = 250;
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};
269 log_d(
"[PROG] Attempting to read CV %d, samples: %d, ack value: %d", cv, CVSampleCount, milliAmpAck);
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);
281 log_d(
"[PROG] CV %d, bit [%d/7] OFF", cv, bit);
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) {
294 log_d(
"[PROG] CV %d, verified", cv);
297 log_w(
"[PROG] CV %d, could not be verified", cv);
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;
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();
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();
322 if(sampleADCChannel(adcChannel, CVSampleCount) > milliAmpAck) {
323 writeVerified =
true;
324 log_d(
"[PROG] CV %d write value %d verified.", cv, cvValue);
327 log_w(
"[PROG] CV %d write value %d could not be verified.", cv, cvValue);
329 log_i(
"[PROG] Sending decoder reset packet");
330 loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 3);
332 return writeVerified;
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;
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();
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();
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);
359 log_w(
"[PROG %d/%d] CV %d write bit %d could not be verified.", attempt, maxWriteAttempts, cv, bit);
361 log_i(
"[PROG] Sending decoder reset packet");
362 loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_PROG], resetPacket, 2, 3);
364 return writeVerified;
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)),
372 (uint8_t)(0xEC + (highByte(cv - 1) & 0x03)),
376 log_d(
"[OPS] Updating CV %d to %d for loco %d", cv, cvValue, locoNumber);
377 loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_MAIN], writeCVBytePacket, 5, 4);
379 uint8_t writeCVBytePacket[] = {
381 (uint8_t)(0xEC + (highByte(cv - 1) & 0x03)),
385 log_d(
"[OPS] Updating CV %d to %d for loco %d", cv, cvValue, locoNumber);
386 loadBytePacket(dccSignalGenerators[SIGNAL_GENERATOR_MAIN], writeCVBytePacket, 4, 4);
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)),
395 (uint8_t)(0xE8 + (highByte(cv - 1) & 0x03)),
397 (uint8_t)(0xF0 + bit + value * 8),
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);
402 uint8_t writeCVBitPacket[] = {
404 (uint8_t)(0xE8 + (highByte(cv - 1) & 0x03)),
406 (uint8_t)(0xF0 + bit + value * 8),
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);