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