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 "DCCpp.h"
11 //#include "DCCpp_Uno.h"
12 //#include "PacketRegister.h"
13 //#include "Comm.h"
14 
15 #ifdef USE_ETHERNET
16 uint8_t DCCppConfig::EthernetIp[4];
17 uint8_t DCCppConfig::EthernetMac[6];
18 int DCCppConfig::EthernetPort = 0;
19 #endif
20 
21 byte DCCppConfig::SignalEnablePinMain = 255;
22 byte DCCppConfig::CurrentMonitorMain = 255;
23 
24 byte DCCppConfig::SignalEnablePinProg = 255;
25 byte DCCppConfig::CurrentMonitorProg = 255;
26 
27 byte DCCppConfig::DirectionMotorA = 255;
28 byte DCCppConfig::DirectionMotorB = 255;
29 
31 
32 void Register::initPackets(){
33  activePacket=packet;
34  updatePacket=packet+1;
35 } // Register::initPackets
36 
38 
39 RegisterList::RegisterList(int maxNumRegs){
40  this->maxNumRegs=maxNumRegs;
41  reg=(Register *)calloc((maxNumRegs+1),sizeof(Register));
42  for(int i=0;i<=maxNumRegs;i++)
43  reg[i].initPackets();
44  regMap=(Register **)calloc((maxNumRegs+1),sizeof(Register *));
45  speedTable=(int *)calloc((maxNumRegs+1),sizeof(int *));
46  currentReg=reg;
47  regMap[0]=reg;
48  maxLoadedReg=reg;
49  nextReg=NULL;
50  currentBit=0;
51  nRepeat=0;
52 } // RegisterList::RegisterList
53 
55 
56 // LOAD DCC PACKET INTO TEMPORARY REGISTER 0, OR PERMANENT REGISTERS 1 THROUGH DCC_PACKET_QUEUE_MAX (INCLUSIVE)
57 // CONVERTS 2, 3, 4, OR 5 BYTES INTO A DCC BIT STREAM WITH PREAMBLE, CHECKSUM, AND PROPER BYTE SEPARATORS
58 // BITSTREAM IS STORED IN UP TO A 10-BYTE ARRAY (USING AT MOST 76 OF 80 BITS)
59 
60 void RegisterList::loadPacket(int nReg, byte *b, int nBytes, int nRepeat, int printFlag) volatile
61 {
62 #ifdef VISUALSTUDIO
63  return;
64 #endif
65  nReg=nReg%((maxNumRegs+1)); // force nReg to be between 0 and maxNumRegs, inclusive
66 
67  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
68 
69  if(regMap[nReg]==NULL) // first time this Register Number has been called
70  regMap[nReg]=maxLoadedReg+1; // set Register Pointer for this Register Number to next available Register
71 
72  Register *r=regMap[nReg]; // set Register to be updated
73  Packet *p=r->updatePacket; // set Packet in the Register to be updated
74  byte *buf=p->buf; // set byte buffer in the Packet to be updated
75 
76  b[nBytes]=b[0]; // copy first byte into what will become the checksum byte
77  for(int i=1;i<nBytes;i++) // XOR remaining bytes into checksum byte
78  b[nBytes]^=b[i];
79  nBytes++; // increment number of bytes in packet to include checksum byte
80 
81  buf[0]=0xFF; // first 8 bytes of 22-byte preamble
82  buf[1]=0xFF; // second 8 bytes of 22-byte preamble
83  buf[2]=0xFC + bitRead(b[0],7); // last 6 bytes of 22-byte preamble + data start bit + b[0], bit 7
84  buf[3]=b[0]<<1; // b[0], bits 6-0 + data start bit
85  buf[4]=b[1]; // b[1], all bits
86  buf[5]=b[2]>>1; // b[2], bits 7-1
87  buf[6]=b[2]<<7; // b[2], bit 0
88 
89  if(nBytes==3){
90  p->nBits=49;
91  } else{
92  buf[6]+=b[3]>>2; // b[3], bits 7-2
93  buf[7]=b[3]<<6; // b[3], bit 1-0
94  if(nBytes==4){
95  p->nBits=58;
96  } else{
97  buf[7]+=b[4]>>3; // b[4], bits 7-3
98  buf[8]=b[4]<<5; // b[4], bits 2-0
99  if(nBytes==5){
100  p->nBits=67;
101  } else{
102  buf[8]+=b[5]>>4; // b[5], bits 7-4
103  buf[9]=b[5]<<4; // b[5], bits 3-0
104  p->nBits=76;
105  } // >5 bytes
106  } // >4 bytes
107  } // >3 bytes
108 
109  nextReg=r;
110  this->nRepeat=nRepeat;
111  maxLoadedReg=max(maxLoadedReg,nextReg);
112 
113 #ifdef DCCPP_DEBUG_MODE
114  if(printFlag) // for debugging purposes
115  printPacket(nReg,b,nBytes,nRepeat);
116 #endif
117 
118 } // RegisterList::loadPacket
119 
121 
122 void RegisterList::setThrottle(int nReg, int cab, int tSpeed, int tDirection) volatile
123 {
124  byte b[5]; // save space for checksum byte
125  byte nB = 0;
126 
127  if (cab>127)
128  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
129 
130  b[nB++] = lowByte(cab);
131  b[nB++] = 0x3F; // 128-step speed control byte
132  if (tSpeed >= 0)
133  b[nB++] = tSpeed + (tSpeed>0) + tDirection * 128; // max speed is 126, but speed codes range from 2-127 (0=stop, 1=emergency stop)
134  else {
135  b[nB++] = 1;
136  tSpeed = 0;
137  }
138 
139  loadPacket(nReg, b, nB, 0, 1);
140 
141 #ifdef DCCPP_DEBUG_MODE
142  INTERFACE.print("<T");
143  INTERFACE.print(nReg); INTERFACE.print(" ");
144  INTERFACE.print(cab); INTERFACE.print(" ");
145  INTERFACE.print(tSpeed); INTERFACE.print(" ");
146  INTERFACE.print(tDirection);
147  INTERFACE.println(">");
148 #endif
149  speedTable[nReg] = tDirection == 1 ? tSpeed : -tSpeed;
150 
151 } // RegisterList::setThrottle(ints)
152 
153 void RegisterList::setThrottle(char *s) volatile
154 {
155  int nReg;
156  int cab;
157  int tSpeed;
158  int tDirection;
159 
160  if (sscanf(s, "%d %d %d %d", &nReg, &cab, &tSpeed, &tDirection) != 4)
161  {
162 #ifdef DCCPP_DEBUG_MODE
163  Serial.println(F("t Syntax error"));
164 #endif
165  return;
166  }
167 
168  this->setThrottle(nReg, cab, tSpeed, tDirection);
169 } // RegisterList::setThrottle(string)
170 
172 
173 void RegisterList::setFunction(int nReg, int cab, int fByte, int eByte) volatile
174 {
175  byte b[5]; // save space for checksum byte
176  byte nB = 0;
177 
178  if (cab>127)
179  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
180 
181  b[nB++] = lowByte(cab);
182 
183  if (eByte < 0) { // this is a request for functions FL,F1-F12
184  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
185  }
186  else { // this is a request for functions F13-F28
187  b[nB++] = (fByte | 0xDE) & 0xDF; // for safety this guarantees that first byte will either be 0xDE (for F13-F20) or 0xDF (for F21-F28)
188  b[nB++] = eByte;
189  }
190 
191 #ifdef DCCPP_DEBUG_MODE
192  INTERFACE.print("<F");
193  INTERFACE.print(nReg); INTERFACE.print(" ");
194  INTERFACE.print(cab); INTERFACE.print(" ");
195  INTERFACE.print(fByte); INTERFACE.print(" ");
196  INTERFACE.print(eByte);
197  INTERFACE.println(">");
198 #endif
199  loadPacket(nReg, b, nB, 4, 1);
200 } // RegisterList::setFunction(ints)
201 
202 void RegisterList::setFunction(char *s) volatile
203 {
204  int cab;
205  int fByte, eByte;
206  int nParams;
207 
208  nParams = sscanf(s, "%d %d %d", &cab, &fByte, &eByte);
209  if (nParams<2)
210  {
211 #ifdef DCCPP_DEBUG_MODE
212  Serial.println(F("f Syntax error"));
213 #endif
214  return;
215  }
216 
217  if (nParams == 2) // this is a request for functions FL,F1-F12
218  eByte = -1;
219 
220  this->setFunction(0, cab, fByte, eByte); // TODO : nReg 0 is not valid !
221 
222 } // RegisterList::setFunction(string)
223 
225 
226 void RegisterList::setAccessory(int aAdd, int aNum, int activate) volatile
227 {
228  byte b[3]; // save space for checksum byte
229 
230  b[0] = aAdd % 64 + 128; // first byte is of the form 10AAAAAA, where AAAAAA represent 6 least signifcant bits of accessory address
231  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
232 
233  loadPacket(0, b, 2, 4, 1);
234 
235 } // RegisterList::setAccessory(ints)
236 
237 void RegisterList::setAccessory(char *s) volatile
238 {
239  int aAdd; // the accessory address (0-511 = 9 bits)
240  int aNum; // the accessory number within that address (0-3)
241  int activate; // flag indicated whether accessory should be activated (1) or deactivated (0) following NMRA recommended convention
242 
243  if (sscanf(s, "%d %d %d", &aAdd, &aNum, &activate) != 3)
244  {
245 #ifdef DCCPP_DEBUG_MODE
246  Serial.println(F("a Syntax error"));
247 #endif
248  return;
249  }
250 
251  this->setAccessory(aAdd, aNum, activate);
252 
253 } // RegisterList::setAccessory(string)
254 
256 
257 void RegisterList::writeTextPacket(int nReg, byte *b, int nBytes) volatile
258 {
259 
260  if (nBytes<2 || nBytes>5) { // invalid valid packet
261  INTERFACE.println("<mInvalid Packet>");
262  return;
263  }
264 
265  loadPacket(nReg, b, nBytes, 0, 1);
266 
267 } // RegisterList::writeTextPacket(bytes)
268 
269 void RegisterList::writeTextPacket(char *s) volatile
270 {
271  int nReg;
272  byte b[6];
273  int nBytes;
274 
275  nBytes = sscanf(s, "%d %hhx %hhx %hhx %hhx %hhx", &nReg, b, b + 1, b + 2, b + 3, b + 4) - 1;
276 
277  this->writeTextPacket(nReg, b, nBytes);
278 
279 } // RegisterList::writeTextPacket(string)
280 
282 
283 int RegisterList::readCVraw(int cv, int callBack, int callBackSub, bool FromProg) volatile
284 {
285  byte bRead[4];
286  int bValue;
287  int c, d, base;
288  cv--; // actual CV addresses are cv-1 (0-1023)
289 
290  byte MonitorPin = DCCppConfig::CurrentMonitorProg;
291  if (!FromProg)
292  MonitorPin = DCCppConfig::CurrentMonitorMain;
293 
294  if (MonitorPin == 255)
295  return -1;
296 
297  bRead[0] = 0x78 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
298  bRead[1] = lowByte(cv);
299 
300  bValue = 0;
301 
302  for (int i = 0; i<8; i++) {
303 
304  c = 0;
305  d = 0;
306  base = 0;
307 
308  for (int j = 0; j < ACK_BASE_COUNT; j++)
309  {
310  int val = (int)analogRead(MonitorPin);
311  base += val;
312  }
313  base /= ACK_BASE_COUNT;
314 
315  bRead[2] = 0xE8 + i;
316 
317  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
318  loadPacket(0, bRead, 3, 5); // NMRA recommends 5 verfy packets
319  loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
320 
321  for (int j = 0; j<ACK_SAMPLE_COUNT; j++)
322  {
323  int val = (int)analogRead(MonitorPin);
324  c = (int)((val - base)*ACK_SAMPLE_SMOOTHING + c*(1.0 - ACK_SAMPLE_SMOOTHING));
325  if (c>ACK_SAMPLE_THRESHOLD)
326  d = 1;
327  }
328 
329  bitWrite(bValue, i, d);
330  }
331 
332  c = 0;
333  d = 0;
334  base = 0;
335 
336  for (int j = 0; j<ACK_BASE_COUNT; j++)
337  base += analogRead(MonitorPin);
338  base /= ACK_BASE_COUNT;
339 
340  bRead[0] = 0x74 + (highByte(cv) & 0x03); // set-up to re-verify entire byte
341  bRead[2] = bValue;
342 
343  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
344  loadPacket(0, bRead, 3, 5); // NMRA recommends 5 verfy packets
345  loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
346 
347  for (int j = 0; j<ACK_SAMPLE_COUNT; j++) {
348  c = (int)((analogRead(MonitorPin) - base)*ACK_SAMPLE_SMOOTHING + c*(1.0 - ACK_SAMPLE_SMOOTHING));
349  if (c>ACK_SAMPLE_THRESHOLD)
350  d = 1;
351  }
352 
353  if (d == 0) // verify unsuccessful
354  bValue = -1;
355 
356 #ifdef DCCPP_DEBUG_MODE
357  INTERFACE.print("<r");
358  INTERFACE.print(callBack);
359  INTERFACE.print("|");
360  INTERFACE.print(callBackSub);
361  INTERFACE.print("|");
362  INTERFACE.print(cv + 1);
363  INTERFACE.print(" ");
364  INTERFACE.print(bValue);
365  INTERFACE.println(">");
366 #endif
367 
368  return bValue;
369 }
370 
371 void RegisterList::readCV(int cv, int callBack, int callBackSub) volatile
372 {
373  /*int bValue = */RegisterList::readCVraw(cv, callBack, callBackSub, true);
374 
375 } // RegisterList::readCV(ints)
376 
377 void RegisterList::readCV(char *s) volatile
378 {
379  int cv, callBack, callBackSub;
380 
381  if (sscanf(s, "%d %d %d", &cv, &callBack, &callBackSub) != 3) // cv = 1-1024
382  {
383 #ifdef DCCPP_DEBUG_MODE
384  Serial.println(F("R Syntax error"));
385 #endif
386  return;
387  }
388 
389  this->readCV(cv, callBack, callBackSub);
390 } // RegisterList::readCV(string)
391 
392 int RegisterList::readCVmain(int cv, int callBack, int callBackSub) volatile
393 {
394  return RegisterList::readCVraw(cv, callBack, callBackSub, false);
395 
396 } // RegisterList::readCV_Main()
397 
398 int RegisterList::readCVmain(char *s) volatile
399 {
400  int cv, callBack, callBackSub;
401 
402  if (sscanf(s, "%d %d %d", &cv, &callBack, &callBackSub) != 3) // cv = 1-1024
403  {
404 #ifdef DCCPP_DEBUG_MODE
405  Serial.println(F("r Syntax error"));
406 #endif
407  return -1;
408  }
409 
410  return this->readCVmain(cv, callBack, callBackSub);
411 } // RegisterList::readCVmain(string)
412 
414 
415 void RegisterList::writeCVByte(int cv, int bValue, int callBack, int callBackSub) volatile
416 {
417  byte bWrite[4];
418  int c, d, base;
419 
420  cv--; // actual CV addresses are cv-1 (0-1023)
421 
422  bWrite[0] = 0x7C + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
423  bWrite[1] = lowByte(cv);
424  bWrite[2] = bValue;
425 
426  loadPacket(0, resetPacket, 2, 1);
427  loadPacket(0, bWrite, 3, 4);
428  loadPacket(0, resetPacket, 2, 1);
429  loadPacket(0, idlePacket, 2, 10);
430 
431  // If monitor pin undefined, write cv without any confirmation...
432  if (DCCppConfig::CurrentMonitorProg != 255)
433  {
434  c = 0;
435  d = 0;
436  base = 0;
437 
438  for (int j = 0; j < ACK_BASE_COUNT; j++)
439  base += analogRead(DCCppConfig::CurrentMonitorProg);
440  base /= ACK_BASE_COUNT;
441 
442  bWrite[0] = 0x74 + (highByte(cv) & 0x03); // set-up to re-verify entire byte
443 
444  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
445  loadPacket(0, bWrite, 3, 5); // NMRA recommends 5 verfy packets
446  loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
447 
448  for (int j = 0; j < ACK_SAMPLE_COUNT; j++) {
449  c = (int)((analogRead(DCCppConfig::CurrentMonitorProg) - base)*ACK_SAMPLE_SMOOTHING + c*(1.0 - ACK_SAMPLE_SMOOTHING));
450  if (c > ACK_SAMPLE_THRESHOLD)
451  d = 1;
452  }
453 
454  if (d == 0) // verify unsuccessful
455  bValue = -1;
456 
457 #ifdef DCCPP_DEBUG_MODE
458  INTERFACE.print("<r");
459  INTERFACE.print(callBack);
460  INTERFACE.print("|");
461  INTERFACE.print(callBackSub);
462  INTERFACE.print("|");
463  INTERFACE.print(cv + 1);
464  INTERFACE.print(" ");
465  INTERFACE.print(bValue);
466  INTERFACE.println(">");
467 #endif
468  }
469 } // RegisterList::writeCVByte(ints)
470 
471 void RegisterList::writeCVByte(char *s) volatile
472 {
473  int bValue, cv, callBack, callBackSub;
474 
475  if (sscanf(s, "%d %d %d %d", &cv, &bValue, &callBack, &callBackSub) != 4) // cv = 1-1024
476  {
477 #ifdef DCCPP_DEBUG_MODE
478  Serial.println(F("W Syntax error"));
479 #endif
480  return;
481  }
482 
483  this->writeCVByte(cv, bValue, callBack, callBackSub);
484 } // RegisterList::writeCVByte(string)
485 
487 
488 void RegisterList::writeCVBit(int cv, int bNum, int bValue, int callBack, int callBackSub) volatile
489 {
490  byte bWrite[4];
491  int c, d, base;
492 
493  cv--; // actual CV addresses are cv-1 (0-1023)
494  bValue = bValue % 2;
495  bNum = bNum % 8;
496 
497  bWrite[0] = 0x78 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
498  bWrite[1] = lowByte(cv);
499  bWrite[2] = 0xF0 + bValue * 8 + bNum;
500 
501  loadPacket(0, resetPacket, 2, 1);
502  loadPacket(0, bWrite, 3, 4);
503  loadPacket(0, resetPacket, 2, 1);
504  loadPacket(0, idlePacket, 2, 10);
505 
506  // If monitor pin undefined, write cv without any confirmation...
507  if (DCCppConfig::CurrentMonitorProg != 255)
508  {
509  c = 0;
510  d = 0;
511  base = 0;
512 
513  for (int j = 0; j < ACK_BASE_COUNT; j++)
514  base += analogRead(DCCppConfig::CurrentMonitorProg);
515  base /= ACK_BASE_COUNT;
516 
517  bitClear(bWrite[2], 4); // change instruction code from Write Bit to Verify Bit
518 
519  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
520  loadPacket(0, bWrite, 3, 5); // NMRA recommends 5 verfy packets
521  loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
522 
523  for (int j = 0; j < ACK_SAMPLE_COUNT; j++) {
524  c = (int)((analogRead(DCCppConfig::CurrentMonitorProg) - base)*ACK_SAMPLE_SMOOTHING + c*(1.0 - ACK_SAMPLE_SMOOTHING));
525  if (c > ACK_SAMPLE_THRESHOLD)
526  d = 1;
527  }
528 
529  if (d == 0) // verify unsuccessful
530  bValue = -1;
531 
532 #ifdef DCCPP_DEBUG_MODE
533  INTERFACE.print("<r");
534  INTERFACE.print(callBack);
535  INTERFACE.print("|");
536  INTERFACE.print(callBackSub);
537  INTERFACE.print("|");
538  INTERFACE.print(cv + 1);
539  INTERFACE.print(" ");
540  INTERFACE.print(bNum);
541  INTERFACE.print(" ");
542  INTERFACE.print(bValue);
543  INTERFACE.println(">");
544 #endif
545  }
546 } // RegisterList::writeCVBit(ints)
547 
548 void RegisterList::writeCVBit(char *s) volatile
549 {
550  int bNum, bValue, cv, callBack, callBackSub;
551 
552  if(sscanf(s,"%d %d %d %d %d",&cv,&bNum,&bValue,&callBack,&callBackSub) != 5) // cv = 1-1024
553  {
554 #ifdef DCCPP_DEBUG_MODE
555  Serial.println(F("W Syntax error"));
556 #endif
557  return;
558  }
559 
560  this->writeCVBit(cv, bNum, bValue, callBack, callBackSub);
561 } // RegisterList::writeCVBit(string)
562 
564 
565 void RegisterList::writeCVByteMain(int cab, int cv, int bValue) volatile
566 {
567  byte b[6]; // save space for checksum byte
568  byte nB = 0;
569 
570  cv--;
571 
572  if (cab>127)
573  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
574 
575  b[nB++] = lowByte(cab);
576  b[nB++] = 0xEC + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
577  b[nB++] = lowByte(cv);
578  b[nB++] = bValue;
579 
580  loadPacket(0, b, nB, 4);
581 
582 } // RegisterList::writeCVByteMain(ints)
583 
584 void RegisterList::writeCVByteMain(char *s) volatile
585 {
586  int cab;
587  int cv;
588  int bValue;
589 
590  if (sscanf(s, "%d %d %d", &cab, &cv, &bValue) != 3)
591  {
592 #ifdef DCCPP_DEBUG_MODE
593  Serial.println(F("w Syntax error"));
594 #endif
595  return;
596  }
597 
598  this->writeCVByteMain(cab, cv, bValue);
599 } // RegisterList::writeCVByteMain(string)
600 
602 
603 void RegisterList::writeCVBitMain(int cab, int cv, int bNum, int bValue) volatile
604 {
605  byte b[6]; // save space for checksum byte
606  byte nB = 0;
607 
608  cv--;
609 
610  bValue = bValue % 2;
611  bNum = bNum % 8;
612 
613  if (cab>127)
614  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
615 
616  b[nB++] = lowByte(cab);
617  b[nB++] = 0xE8 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
618  b[nB++] = lowByte(cv);
619  b[nB++] = 0xF0 + bValue * 8 + bNum;
620 
621  loadPacket(0, b, nB, 4);
622 
623 } // RegisterList::writeCVBitMain(ints)
624 
625 void RegisterList::writeCVBitMain(char *s) volatile
626 {
627  int cab;
628  int cv;
629  int bNum;
630  int bValue;
631 
632  if (sscanf(s, "%d %d %d %d", &cab, &cv, &bNum, &bValue) != 4)
633  {
634 #ifdef DCCPP_DEBUG_MODE
635  Serial.println(F("w Syntax error"));
636 #endif
637  return;
638  }
639 
640  this->writeCVBitMain(cab, cv, bNum, bValue);
641 } // RegisterList::writeCVBitMain(string)
642 
644 
645 #ifdef DCCPP_DEBUG_MODE
646 void RegisterList::printPacket(int nReg, byte *b, int nBytes, int nRepeat) volatile
647 {
648 
649  INTERFACE.print("<*");
650  INTERFACE.print(nReg);
651  INTERFACE.print(":");
652  for(int i=0;i<nBytes;i++){
653  INTERFACE.print(" ");
654  INTERFACE.print(b[i],HEX);
655  }
656  INTERFACE.print(" / ");
657  INTERFACE.print(nRepeat);
658  INTERFACE.println(">");
659 } // RegisterList::printPacket()
660 #endif
661 
663 
664 byte RegisterList::idlePacket[3]={0xFF,0x00,0}; // always leave extra byte for checksum computation
665 byte RegisterList::resetPacket[3]={0x00,0x00,0};
666 
667 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