DCCpp
This is the library version of a program for Arduino to control railroading DCC devices.
PacketRegister.cpp
1 /**********************************************************************
2 
3 PacketRegister.cpp
4 COPYRIGHT (c) 2013-2016 Gregg E. Berman
5 Adapted by Thierry PARIS
6 
7 Part of DCC++ BASE STATION for the Arduino
8 **********************************************************************/
9 
10 #include "Arduino.h"
11 
12 //static byte ackThreshold = 30;
13 
14 #include "DCCpp.h"
15 //#include "DCCpp_Uno.h"
16 //#include "PacketRegister.h"
17 //#include "Comm.h"
18 
19 #ifdef USE_ETHERNET
20 uint8_t DCCppConfig::EthernetIp[4];
21 uint8_t DCCppConfig::EthernetMac[6];
22 int DCCppConfig::EthernetPort = 0;
23 
24 EthernetProtocol DCCppConfig::Protocol = EthernetProtocol::TCP;
25 #endif
26 
27 byte DCCppConfig::SignalEnablePinMain = UNDEFINED_PIN;
28 byte DCCppConfig::CurrentMonitorMain = UNDEFINED_PIN;
29 
30 byte DCCppConfig::SignalEnablePinProg = UNDEFINED_PIN;
31 byte DCCppConfig::CurrentMonitorProg = UNDEFINED_PIN;
32 
33 #ifndef USE_ONLY1_INTERRUPT
34 byte DCCppConfig::DirectionMotorA = UNDEFINED_PIN;
35 byte DCCppConfig::DirectionMotorB = UNDEFINED_PIN;
36 #else
37 uint8_t DCCppConfig::SignalPortMaskMain = 0;
38 uint8_t DCCppConfig::SignalPortMaskProg = 0;
39 
40 volatile uint8_t *DCCppConfig::SignalPortInMain = 0;
41 volatile uint8_t *DCCppConfig::SignalPortInProg = 0;
42 #endif
43 
45 
46 void Register::initPackets(){
47  activePacket=packet;
48  updatePacket=packet+1;
49 } // Register::initPackets
50 
52 
53 RegisterList::RegisterList(int maxNumRegs){
54  this->maxNumRegs=maxNumRegs;
55  reg=(Register *)calloc((maxNumRegs+1),sizeof(Register));
56  for(int i=0;i<=maxNumRegs;i++)
57  reg[i].initPackets();
58  regMap=(Register **)calloc((maxNumRegs+1),sizeof(Register *));
59  speedTable=(int *)calloc((maxNumRegs+1),sizeof(int *));
60  currentReg=reg;
61  regMap[0]=reg;
62  maxLoadedReg=reg;
63  nextReg=NULL;
64  currentBit=0;
65  nRepeat=0;
66 } // RegisterList::RegisterList
67 
69 
70 // LOAD DCC PACKET INTO TEMPORARY REGISTER 0, OR PERMANENT REGISTERS 1 THROUGH DCC_PACKET_QUEUE_MAX (INCLUSIVE)
71 // CONVERTS 2, 3, 4, OR 5 BYTES INTO A DCC BIT STREAM WITH PREAMBLE, CHECKSUM, AND PROPER BYTE SEPARATORS
72 // BITSTREAM IS STORED IN UP TO A 10-BYTE ARRAY (USING AT MOST 76 OF 80 BITS)
73 
74 void RegisterList::loadPacket(int nReg, byte *b, int nBytes, int nRepeat, int printFlag) volatile
75 {
76 #ifdef VISUALSTUDIO
77  return;
78 #endif
79  nReg=nReg%((maxNumRegs+1)); // force nReg to be between 0 and maxNumRegs, inclusive
80 
81  while(nextReg!=NULL); // pause while there is a Register already waiting to be updated -- nextReg will be reset to NULL by interrupt when prior Register updated fully processed
82 
83  if(regMap[nReg]==NULL) // first time this Register Number has been called
84  regMap[nReg]=maxLoadedReg+1; // set Register Pointer for this Register Number to next available Register
85 
86  Register *r=regMap[nReg]; // set Register to be updated
87  Packet *p=r->updatePacket; // set Packet in the Register to be updated
88  byte *buf=p->buf; // set byte buffer in the Packet to be updated
89 
90  b[nBytes]=b[0]; // copy first byte into what will become the checksum byte
91  for(int i=1;i<nBytes;i++) // XOR remaining bytes into checksum byte
92  b[nBytes]^=b[i];
93  nBytes++; // increment number of bytes in packet to include checksum byte
94 
95  buf[0]=0xFF; // first 8 bytes of 22-byte preamble
96  buf[1]=0xFF; // second 8 bytes of 22-byte preamble
97  buf[2]=0xFC + bitRead(b[0],7); // last 6 bytes of 22-byte preamble + data start bit + b[0], bit 7
98  buf[3]=b[0]<<1; // b[0], bits 6-0 + data start bit
99  buf[4]=b[1]; // b[1], all bits
100  buf[5]=b[2]>>1; // b[2], bits 7-1
101  buf[6]=b[2]<<7; // b[2], bit 0
102 
103  if(nBytes==3){
104  p->nBits=49;
105  } else{
106  buf[6]+=b[3]>>2; // b[3], bits 7-2
107  buf[7]=b[3]<<6; // b[3], bit 1-0
108  if(nBytes==4){
109  p->nBits=58;
110  } else{
111  buf[7]+=b[4]>>3; // b[4], bits 7-3
112  buf[8]=b[4]<<5; // b[4], bits 2-0
113  if(nBytes==5){
114  p->nBits=67;
115  } else{
116  buf[8]+=b[5]>>4; // b[5], bits 7-4
117  buf[9]=b[5]<<4; // b[5], bits 3-0
118  p->nBits=76;
119  } // >5 bytes
120  } // >4 bytes
121  } // >3 bytes
122 
123  nextReg=r;
124  this->nRepeat=nRepeat;
125  maxLoadedReg=max(maxLoadedReg,nextReg);
126 
127 #ifdef DCCPP_DEBUG_MODE
128 #ifdef DCCPP_DEBUG_VERBOSE_MODE
129  if(printFlag) // for debugging purposes
130  printPacket(nReg,b,nBytes,nRepeat);
131 #endif
132 #endif
133 
134 } // RegisterList::loadPacket
135 
137 
138 void RegisterList::setThrottle(int nReg, int cab, int tSpeed, int tDirection) volatile
139 {
140  byte b[5]; // save space for checksum byte
141  byte nB = 0;
142 
143  if (cab>127)
144  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
145 
146  b[nB++] = lowByte(cab);
147  b[nB++] = 0x3F; // 128-step speed control byte
148  if (tSpeed >= 0)
149  b[nB++] = tSpeed + (tSpeed>0) + tDirection * 128; // max speed is 126, but speed codes range from 2-127 (0=stop, 1=emergency stop)
150  else {
151  b[nB++] = 1;
152  tSpeed = 0;
153  }
154 
155  loadPacket(nReg, b, nB, 0, 1);
156 
157 #if defined(USE_TEXTCOMMAND)
158  DCCPP_INTERFACE.print("<T");
159  DCCPP_INTERFACE.print(nReg); DCCPP_INTERFACE.print(" ");
160  DCCPP_INTERFACE.print(cab); DCCPP_INTERFACE.print(" ");
161  DCCPP_INTERFACE.print(tSpeed); DCCPP_INTERFACE.print(" ");
162  DCCPP_INTERFACE.print(tDirection);
163  DCCPP_INTERFACE.print(">");
164 #if !defined(USE_ETHERNET)
165  DCCPP_INTERFACE.println("");
166 #endif
167 #endif
168  speedTable[nReg] = tDirection == 1 ? tSpeed : -tSpeed;
169 
170 } // RegisterList::setThrottle(ints)
171 
172 #ifdef USE_TEXTCOMMAND
173 void RegisterList::setThrottle(const char *s) volatile
174 {
175  int nReg;
176  int cab;
177  int tSpeed;
178  int tDirection;
179 
180  if (sscanf(s, "%d %d %d %d", &nReg, &cab, &tSpeed, &tDirection) != 4)
181  {
182 #ifdef DCCPP_DEBUG_MODE
183  Serial.println(F("t Syntax error"));
184 #endif
185  return;
186  }
187 
188  this->setThrottle(nReg, cab, tSpeed, tDirection);
189 } // RegisterList::setThrottle(string)
190 #endif
191 
193 
194 void RegisterList::setFunction(int nReg, int cab, int fByte, int eByte) volatile
195 {
196  byte b[5]; // save space for checksum byte
197  byte nB = 0;
198 
199  if (cab>127)
200  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
201 
202  b[nB++] = lowByte(cab);
203 
204  if (eByte < 0) { // this is a request for functions FL,F1-F12
205  b[nB++] = (fByte | 0x80) & 0xBF; // for safety this guarantees that first nibble of function byte will always be of binary form 10XX which should always be the case for FL,F1-F12
206  }
207  else { // this is a request for functions F13-F28
208  b[nB++] = (fByte | 0xDE) & 0xDF; // for safety this guarantees that first byte will either be 0xDE (for F13-F20) or 0xDF (for F21-F28)
209  b[nB++] = eByte;
210  }
211 
212 #if defined(USE_TEXTCOMMAND)
213  DCCPP_INTERFACE.print("<F");
214  DCCPP_INTERFACE.print(nReg); DCCPP_INTERFACE.print(" ");
215  DCCPP_INTERFACE.print(cab); DCCPP_INTERFACE.print(" ");
216  DCCPP_INTERFACE.print(fByte); DCCPP_INTERFACE.print(" ");
217  DCCPP_INTERFACE.print(eByte);
218  DCCPP_INTERFACE.print(">");
219 #if !defined(USE_ETHERNET)
220  DCCPP_INTERFACE.println("");
221 #endif
222 #endif
223  /* NMRA DCC norm ask for two DCC packets instead of only one:
224  "Command Stations that generate these packets, and which are not periodically refreshing these functions,
225  must send at least two repetitions of these commands when any function state is changed."
226  https://www.nmra.org/sites/default/files/s-9.2.1_2012_07.pdf
227  */
228  loadPacket(nReg, b, nB, 4, 1);
229 } // RegisterList::setFunction(ints)
230 
231 #ifdef USE_TEXTCOMMAND
232 void RegisterList::setFunction(const char *s) volatile
233 {
234  int reg, cab;
235  int fByte, eByte;
236 
237  int a, b, c, d, e;
238 
239  switch (sscanf(s, "%d %d %d %d %d", &a, &b, &c, &d, &e))
240  {
241  case 2:
242  reg = 0;
243  cab = a;
244  fByte = b;
245  eByte = -1;
246  break;
247 
248  case 3:
249  reg = 0;
250  cab = a;
251  fByte = b;
252  eByte = c;
253  break;
254  case 4:
255  reg = b;
256  cab = c;
257  fByte = d;
258  eByte = -1;
259  break;
260  case 5:
261  reg = b;
262  cab = c;
263  fByte = d;
264  eByte = e;
265  break;
266 
267  default:
268 #ifdef DCCPP_DEBUG_MODE
269  Serial.println(F("f Syntax error"));
270 #endif
271  return;
272  }
273 
274  this->setFunction(reg, cab, fByte, eByte);
275 
276 } // RegisterList::setFunction(string)
277 #endif
278 
280 
281 void RegisterList::setAccessory(int aAdd, int aNum, int activate) volatile
282 {
283  byte b[3]; // save space for checksum byte
284 
285  b[0] = aAdd % 64 + 128; // first byte is of the form 10AAAAAA, where AAAAAA represent 6 least significant bits of accessory address
286  b[1] = ((((aAdd / 64) % 8) << 4) + (aNum % 4 << 1) + activate % 2) ^ 0xF8; // second byte is of the form 1AAACDDD, where C should be 1, and the least significant D represent activate/deactivate
287 
288  loadPacket(0, b, 2, 4, 1);
289 
290 } // RegisterList::setAccessory(ints)
291 
292 #ifdef USE_TEXTCOMMAND
293 void RegisterList::setAccessory(const char *s) volatile
294 {
295  int aAdd; // the accessory address (0-511 = 9 bits)
296  int aNum; // the accessory number within that address (0-3)
297  int activate; // flag indicated whether accessory should be activated (1) or deactivated (0) following NMRA recommended convention
298 
299  if (sscanf(s, "%d %d %d", &aAdd, &aNum, &activate) != 3)
300  {
301 #ifdef DCCPP_DEBUG_MODE
302  Serial.println(F("a Syntax error"));
303 #endif
304  return;
305  }
306 
307  this->setAccessory(aAdd, aNum, activate);
308 
309 } // RegisterList::setAccessory(string)
310 #endif
311 
313 
314 void RegisterList::writeTextPacket(int nReg, byte *b, int nBytes) volatile
315 {
316 
317  if (nBytes<2 || nBytes>5) { // invalid valid packet
318  DCCPP_INTERFACE.print("<mInvalid Packet>");
319 #if !defined(USE_ETHERNET)
320  DCCPP_INTERFACE.println("");
321 #endif
322  return;
323  }
324 
325  loadPacket(nReg, b, nBytes, 0, 1);
326 
327 } // RegisterList::writeTextPacket(bytes)
328 
329 #ifdef USE_TEXTCOMMAND
330 void RegisterList::writeTextPacket(const char *s) volatile
331 {
332  int nReg;
333  byte b[6];
334  int nBytes;
335 
336  nBytes = sscanf(s, "%d %hhx %hhx %hhx %hhx %hhx", &nReg, b, b + 1, b + 2, b + 3, b + 4) - 1;
337 
338  this->writeTextPacket(nReg, b, nBytes);
339 
340 } // RegisterList::writeTextPacket(string)
341 #endif
342 
344 
345 int RegisterList::buildBaseAcknowlegde(int inMonitorPin) volatile
346 {
347  int base = 0;
348  for (int j = 0; j < ACK_BASE_COUNT; j++)
349  {
350  int val = (int)analogRead(inMonitorPin);
351  base += val;
352  }
353 
354  return base / ACK_BASE_COUNT;
355 }
356 
357 bool RegisterList::checkAcknowlegde(int inMonitorPin, int inBase) volatile
358 {
359  int c = 0;
360  int max = 0;
361 
362 #if defined(ARDUINO_ARCH_ESP32)
363  int loopMax = 20;
364 #else
365  int loopMax = 1;
366 #endif
367 
368 #ifdef DCCPP_DEBUG_MODE
369  int loop = 0;
370 #endif
371  for (int a = 0; a < loopMax; a++)
372  {
373  c = 0;
374  for (int j = 0; j < ACK_SAMPLE_COUNT; j++)
375  {
376  int val = (int)analogRead(inMonitorPin);
377  c = (int)((val - inBase) * ACK_SAMPLE_SMOOTHING + c * (1.0 - ACK_SAMPLE_SMOOTHING));
378  if (c > max)
379  {
380  max = c;
381 #ifdef DCCPP_DEBUG_MODE
382  loop = a;
383 #endif
384  }
385  }
386  }
387 
388 #ifdef DCCPP_DEBUG_MODE
389  Serial.print(F(" iter : "));
390  Serial.print(loop);
391  Serial.print(", max : ");
392  Serial.println(max);
393 #endif
394 
395  return (max > ACK_SAMPLE_THRESHOLD);
396 }
397 
398 int RegisterList::readCVraw(int cv, int callBack, int callBackSub) volatile
399 {
400  byte bRead[4];
401  int bValue;
402  int ret, base;
403 
404  cv--; // actual CV addresses are cv-1 (0-1023)
405 
406  byte MonitorPin = DCCppConfig::CurrentMonitorProg;
407  if (DCCpp::IsMainTrack(this))
408  MonitorPin = DCCppConfig::CurrentMonitorMain;
409 
410  // A read cannot be done if a monitor pin is not defined !
411  if (MonitorPin == UNDEFINED_PIN)
412  return -1;
413 
414 #ifdef DCCPP_DEBUG_MODE
415  Serial.print(F("readCVraw : start reading cv "));
416  Serial.println(cv+1);
417 #endif
418 
419  bRead[0] = 0x78 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
420  bRead[1] = lowByte(cv);
421 
422  bValue = 0;
423 
424  for (int i = 0; i<8; i++) {
425 
426  base = RegisterList::buildBaseAcknowlegde(MonitorPin);
427 
428 #if defined(ARDUINO_ARCH_ESP32)
429  delay(10);
430 #endif
431 
432  bRead[2] = 0xE8 + i;
433 
434  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
435  loadPacket(0, bRead, 3, 5); // NMRA recommends 5 verify packets
436 // loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
437  loadPacket(0, idlePacket, 2, 6); // NMRA recommends 6 idle or reset packets for decoder recovery time
438 
439 #if defined(ARDUINO_ARCH_ESP32)
440  delay(2);
441 #endif
442 
443  ret = RegisterList::checkAcknowlegde(MonitorPin, base);
444 
445  bitWrite(bValue, i, ret);
446  }
447 
448 #if defined(ARDUINO_ARCH_ESP32)
449  delay(10);
450 #endif
451 
452  base = RegisterList::buildBaseAcknowlegde(MonitorPin);
453 
454 #if defined(ARDUINO_ARCH_ESP32)
455  delay(10);
456 #endif
457 
458  bRead[0] = 0x74 + (highByte(cv) & 0x03); // set-up to re-verify entire byte
459  bRead[2] = bValue;
460 
461  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
462  loadPacket(0, bRead, 3, 5); // NMRA recommends 5 verify packets
463  //loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
464  loadPacket(0, idlePacket, 2, 6); // NMRA recommends 6 idle or reset packets for decoder recovery time
465 
466 #if defined(ARDUINO_ARCH_ESP32)
467  delay(2);
468 #endif
469 
470  ret = RegisterList::checkAcknowlegde(MonitorPin, base);
471 
472  if (ret == 0) // verify unsuccessful
473  bValue = -1;
474 
475 #if defined(USE_TEXTCOMMAND)
476  DCCPP_INTERFACE.print("<r");
477  DCCPP_INTERFACE.print(callBack);
478  DCCPP_INTERFACE.print("|");
479  DCCPP_INTERFACE.print(callBackSub);
480  DCCPP_INTERFACE.print("|");
481  DCCPP_INTERFACE.print(cv + 1);
482  DCCPP_INTERFACE.print(" ");
483  DCCPP_INTERFACE.print(bValue);
484  DCCPP_INTERFACE.print(">");
485 #if !defined(USE_ETHERNET)
486  DCCPP_INTERFACE.println("");
487 #endif
488 #endif
489 
490 #ifdef DCCPP_DEBUG_MODE
491  Serial.println(F("end reading"));
492 #endif
493  return bValue;
494 }
495 
496 int RegisterList::readCV(int cv, int callBack, int callBackSub) volatile
497 {
498  return RegisterList::readCVraw(cv, callBack, callBackSub);
499 } // RegisterList::readCV(ints)
500 
501 #ifdef USE_TEXTCOMMAND
502 int RegisterList::readCV(const char *s) volatile
503 {
504  int cv, callBack, callBackSub;
505 
506  if (sscanf(s, "%d %d %d", &cv, &callBack, &callBackSub) != 3) // cv = 1-1024
507  {
508 #ifdef DCCPP_DEBUG_MODE
509  Serial.println(F("R Syntax error"));
510 #endif
511  return -1;
512  }
513 
514  return this->readCV(cv, callBack, callBackSub);
515 } // RegisterList::readCV(string)
516 #endif
517 
518 int RegisterList::readCVmain(int cv, int callBack, int callBackSub) volatile
519 {
520  return RegisterList::readCVraw(cv, callBack, callBackSub);
521 
522 } // RegisterList::readCV_Main()
523 
524 #ifdef USE_TEXTCOMMAND
525 int RegisterList::readCVmain(const char *s) volatile
526 {
527  int cv, callBack, callBackSub;
528 
529  if (sscanf(s, "%d %d %d", &cv, &callBack, &callBackSub) != 3) // cv = 1-1024
530  {
531 #ifdef DCCPP_DEBUG_MODE
532  Serial.println(F("r Syntax error"));
533 #endif
534  return -1;
535  }
536 
537  return this->readCVmain(cv, callBack, callBackSub);
538 } // RegisterList::readCVmain(string)
539 #endif
540 
542 
543 bool RegisterList::writeCVByte(int cv, int bValue, int callBack, int callBackSub) volatile
544 {
545  byte bWrite[4];
546  bool ok = false;
547  int ret, base;
548 
549  cv--; // actual CV addresses are cv-1 (0-1023)
550 
551  bWrite[0] = 0x7C + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
552  bWrite[1] = lowByte(cv);
553  bWrite[2] = bValue;
554 
555  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
556  loadPacket(0, bWrite, 3, 5); // NMRA recommends 5 verify packets
557  loadPacket(0, bWrite, 3, 6); // NMRA recommends 6 write or reset packets for decoder recovery time
558 
559  /*loadPacket(0, resetPacket, 2, 1);
560  loadPacket(0, bWrite, 3, 4);
561  loadPacket(0, resetPacket, 2, 1);
562  loadPacket(0, idlePacket, 2, 10);*/
563 
564  // If monitor pin undefined, write cv without any confirmation...
565  if (DCCppConfig::CurrentMonitorProg != UNDEFINED_PIN)
566  {
567  base = RegisterList::buildBaseAcknowlegde(DCCppConfig::CurrentMonitorProg);
568 
569  bWrite[0] = 0x74 + (highByte(cv) & 0x03); // set-up to re-verify entire byte
570 
571  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
572  loadPacket(0, bWrite, 3, 5); // NMRA recommends 5 verify packets
573  //loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
574  loadPacket(0, bWrite, 3, 6); // NMRA recommends 6 write or reset packets for decoder recovery time
575 
576  ret = RegisterList::checkAcknowlegde(DCCppConfig::CurrentMonitorProg, base);
577 
578  loadPacket(0, resetPacket, 2, 1); // Final reset packet (and decoder begins to respond)
579 
580  if (ret != 0) // verify successful
581  ok = true;
582  }
583 
584 #if defined(USE_TEXTCOMMAND)
585  DCCPP_INTERFACE.print("<r");
586  DCCPP_INTERFACE.print(callBack);
587  DCCPP_INTERFACE.print("|");
588  DCCPP_INTERFACE.print(callBackSub);
589  DCCPP_INTERFACE.print("|");
590  DCCPP_INTERFACE.print(cv + 1);
591  DCCPP_INTERFACE.print(" ");
592  DCCPP_INTERFACE.print(bValue);
593  DCCPP_INTERFACE.print(">");
594 #if !defined(USE_ETHERNET)
595  DCCPP_INTERFACE.println("");
596 #endif
597 #endif
598  return ok;
599 } // RegisterList::writeCVByte(ints)
600 
601 #ifdef USE_TEXTCOMMAND
602 bool RegisterList::writeCVByte(const char *s) volatile
603 {
604  int bValue, cv, callBack, callBackSub;
605 
606  if (sscanf(s, "%d %d %d %d", &cv, &bValue, &callBack, &callBackSub) != 4) // cv = 1-1024
607  {
608 #ifdef DCCPP_DEBUG_MODE
609  Serial.println(F("W Syntax error"));
610 #endif
611  return false;
612  }
613 
614  return this->writeCVByte(cv, bValue, callBack, callBackSub);
615 } // RegisterList::writeCVByte(string)
616 #endif
617 
619 
620 bool RegisterList::writeCVBit(int cv, int bNum, int bValue, int callBack, int callBackSub) volatile
621 {
622  byte bWrite[4];
623  bool ok = false;
624  int ret, base;
625 
626  cv--; // actual CV addresses are cv-1 (0-1023)
627  bValue = bValue % 2;
628  bNum = bNum % 8;
629 
630  bWrite[0] = 0x78 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
631  bWrite[1] = lowByte(cv);
632  bWrite[2] = 0xF0 + bValue * 8 + bNum;
633 
634  /*loadPacket(0, resetPacket, 2, 1);
635  loadPacket(0, bWrite, 3, 4);
636  loadPacket(0, resetPacket, 2, 1);
637  loadPacket(0, idlePacket, 2, 10);*/
638 
639  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
640  loadPacket(0, bWrite, 3, 5); // NMRA recommends 5 verify packets
641  loadPacket(0, bWrite, 3, 6); // NMRA recommends 6 write or reset packets for decoder recovery time
642 
643  // If monitor pin undefined, write cv without any confirmation...
644  if (DCCppConfig::CurrentMonitorProg != UNDEFINED_PIN)
645  {
646  base = RegisterList::buildBaseAcknowlegde(DCCppConfig::CurrentMonitorProg);
647 
648  bitClear(bWrite[2], 4); // change instruction code from Write Bit to Verify Bit
649 
650  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
651  loadPacket(0, bWrite, 3, 5); // NMRA recommends 5 verfy packets
652  //loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
653  loadPacket(0, bWrite, 3, 6); // NMRA recommends 6 write or reset packets for decoder recovery time
654 
655  ret = RegisterList::checkAcknowlegde(DCCppConfig::CurrentMonitorProg, base);
656 
657  loadPacket(0, resetPacket, 2, 1); // Final reset packetcompleted (and decoder begins to respond)
658 
659  if (ret != 0) // verify successful
660  ok = true;
661  }
662 
663 #if defined(USE_TEXTCOMMAND)
664  DCCPP_INTERFACE.print("<r");
665  DCCPP_INTERFACE.print(callBack);
666  DCCPP_INTERFACE.print("|");
667  DCCPP_INTERFACE.print(callBackSub);
668  DCCPP_INTERFACE.print("|");
669  DCCPP_INTERFACE.print(cv + 1);
670  DCCPP_INTERFACE.print(" ");
671  DCCPP_INTERFACE.print(bNum);
672  DCCPP_INTERFACE.print(" ");
673  DCCPP_INTERFACE.print(bValue);
674  DCCPP_INTERFACE.print(">");
675 #if !defined(USE_ETHERNET)
676  DCCPP_INTERFACE.println("");
677 #endif
678 #endif
679  return ok;
680 } // RegisterList::writeCVBit(ints)
681 
682 #ifdef USE_TEXTCOMMAND
683 bool RegisterList::writeCVBit(const char *s) volatile
684 {
685  int bNum, bValue, cv, callBack, callBackSub;
686 
687  if(sscanf(s,"%d %d %d %d %d",&cv,&bNum,&bValue,&callBack,&callBackSub) != 5) // cv = 1-1024
688  {
689 #ifdef DCCPP_DEBUG_MODE
690  Serial.println(F("W Syntax error"));
691 #endif
692  return false;
693  }
694 
695  return this->writeCVBit(cv, bNum, bValue, callBack, callBackSub);
696 } // RegisterList::writeCVBit(string)
697 #endif
698 
700 
701 void RegisterList::writeCVByteMain(int cab, int cv, int bValue) volatile
702 {
703  byte b[6]; // save space for checksum byte
704  byte nB = 0;
705 
706  cv--;
707 
708  if (cab>127)
709  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
710 
711  b[nB++] = lowByte(cab);
712  b[nB++] = 0xEC + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
713  b[nB++] = lowByte(cv);
714  b[nB++] = bValue;
715 
716  loadPacket(0, b, nB, 4);
717 
718 } // RegisterList::writeCVByteMain(ints)
719 
720 #ifdef USE_TEXTCOMMAND
721 void RegisterList::writeCVByteMain(const char *s) volatile
722 {
723  int cab;
724  int cv;
725  int bValue;
726 
727  if (sscanf(s, "%d %d %d", &cab, &cv, &bValue) != 3)
728  {
729 #ifdef DCCPP_DEBUG_MODE
730  Serial.println(F("w Syntax error"));
731 #endif
732  return;
733  }
734 
735  this->writeCVByteMain(cab, cv, bValue);
736 } // RegisterList::writeCVByteMain(string)
737 #endif
738 
740 
741 void RegisterList::writeCVBitMain(int cab, int cv, int bNum, int bValue) volatile
742 {
743  byte b[6]; // save space for checksum byte
744  byte nB = 0;
745 
746  cv--;
747 
748  bValue = bValue % 2;
749  bNum = bNum % 8;
750 
751  if (cab>127)
752  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
753 
754  b[nB++] = lowByte(cab);
755  b[nB++] = 0xE8 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
756  b[nB++] = lowByte(cv);
757  b[nB++] = 0xF0 + bValue * 8 + bNum;
758 
759  loadPacket(0, b, nB, 4);
760 
761 } // RegisterList::writeCVBitMain(ints)
762 
763 #ifdef USE_TEXTCOMMAND
764 void RegisterList::writeCVBitMain(const char *s) volatile
765 {
766  int cab;
767  int cv;
768  int bNum;
769  int bValue;
770 
771  if (sscanf(s, "%d %d %d %d", &cab, &cv, &bNum, &bValue) != 4)
772  {
773 #ifdef DCCPP_DEBUG_MODE
774  Serial.println(F("w Syntax error"));
775 #endif
776  return;
777  }
778 
779  this->writeCVBitMain(cab, cv, bNum, bValue);
780 } // RegisterList::writeCVBitMain(string)
781 #endif
782 
784 
785 #ifdef DCCPP_DEBUG_MODE
786 void RegisterList::printPacket(int nReg, byte *b, int nBytes, int nRepeat) volatile
787 {
788  DCCPP_INTERFACE.print("<*");
789  DCCPP_INTERFACE.print(nReg);
790  DCCPP_INTERFACE.print(":");
791  for(int i=0;i<nBytes;i++){
792  DCCPP_INTERFACE.print(" ");
793  DCCPP_INTERFACE.print(b[i],HEX);
794  }
795  DCCPP_INTERFACE.print(" / ");
796  DCCPP_INTERFACE.print(nRepeat);
797  DCCPP_INTERFACE.print(">");
798 #if !defined(USE_ETHERNET)
799  DCCPP_INTERFACE.println("");
800 #endif
801 } // RegisterList::printPacket()
802 #endif
803 
805 
806 byte RegisterList::idlePacket[3]={0xFF,0x00,0}; // always leave extra byte for checksum computation
807 byte RegisterList::resetPacket[3]={0x00,0x00,0};
808 
809 byte RegisterList::bitMask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; // masks used in interrupt routine to speed the query of a single bit in a Packet
static bool IsMainTrack(volatile RegisterList *apRegs)
Definition: DCCpp.hpp:188