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