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