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  if(printFlag) // for debugging purposes
129  printPacket(nReg,b,nBytes,nRepeat);
130 #endif
131 
132 } // RegisterList::loadPacket
133 
135 
136 void RegisterList::setThrottle(int nReg, int cab, int tSpeed, int tDirection) volatile
137 {
138  byte b[5]; // save space for checksum byte
139  byte nB = 0;
140 
141  if (cab>127)
142  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
143 
144  b[nB++] = lowByte(cab);
145  b[nB++] = 0x3F; // 128-step speed control byte
146  if (tSpeed >= 0)
147  b[nB++] = tSpeed + (tSpeed>0) + tDirection * 128; // max speed is 126, but speed codes range from 2-127 (0=stop, 1=emergency stop)
148  else {
149  b[nB++] = 1;
150  tSpeed = 0;
151  }
152 
153  loadPacket(nReg, b, nB, 0, 1);
154 
155 #if defined(USE_TEXTCOMMAND)
156  DCCPP_INTERFACE.print("<T");
157  DCCPP_INTERFACE.print(nReg); DCCPP_INTERFACE.print(" ");
158  DCCPP_INTERFACE.print(cab); DCCPP_INTERFACE.print(" ");
159  DCCPP_INTERFACE.print(tSpeed); DCCPP_INTERFACE.print(" ");
160  DCCPP_INTERFACE.print(tDirection);
161  DCCPP_INTERFACE.print(">");
162 #if !defined(USE_ETHERNET)
163  DCCPP_INTERFACE.println("");
164 #endif
165 #endif
166  speedTable[nReg] = tDirection == 1 ? tSpeed : -tSpeed;
167 
168 } // RegisterList::setThrottle(ints)
169 
170 #ifdef USE_TEXTCOMMAND
171 void RegisterList::setThrottle(char *s) volatile
172 {
173  int nReg;
174  int cab;
175  int tSpeed;
176  int tDirection;
177 
178  if (sscanf(s, "%d %d %d %d", &nReg, &cab, &tSpeed, &tDirection) != 4)
179  {
180 #ifdef DCCPP_DEBUG_MODE
181  Serial.println(F("t Syntax error"));
182 #endif
183  return;
184  }
185 
186  this->setThrottle(nReg, cab, tSpeed, tDirection);
187 } // RegisterList::setThrottle(string)
188 #endif
189 
191 
192 void RegisterList::setFunction(int nReg, int cab, int fByte, int eByte) volatile
193 {
194  byte b[5]; // save space for checksum byte
195  byte nB = 0;
196 
197  if (cab>127)
198  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
199 
200  b[nB++] = lowByte(cab);
201 
202  if (eByte < 0) { // this is a request for functions FL,F1-F12
203  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
204  }
205  else { // this is a request for functions F13-F28
206  b[nB++] = (fByte | 0xDE) & 0xDF; // for safety this guarantees that first byte will either be 0xDE (for F13-F20) or 0xDF (for F21-F28)
207  b[nB++] = eByte;
208  }
209 
210 #if defined(USE_TEXTCOMMAND)
211  DCCPP_INTERFACE.print("<F");
212  DCCPP_INTERFACE.print(nReg); DCCPP_INTERFACE.print(" ");
213  DCCPP_INTERFACE.print(cab); DCCPP_INTERFACE.print(" ");
214  DCCPP_INTERFACE.print(fByte); DCCPP_INTERFACE.print(" ");
215  DCCPP_INTERFACE.print(eByte);
216  DCCPP_INTERFACE.print(">");
217 #if !defined(USE_ETHERNET)
218  DCCPP_INTERFACE.println("");
219 #endif
220 #endif
221  /* NMRA DCC norm ask for two DCC packets instead of only one:
222  "Command Stations that generate these packets, and which are not periodically refreshing these functions,
223  must send at least two repetitions of these commands when any function state is changed."
224  https://www.nmra.org/sites/default/files/s-9.2.1_2012_07.pdf
225  */
226  loadPacket(nReg, b, nB, 4, 1);
227 } // RegisterList::setFunction(ints)
228 
229 #ifdef USE_TEXTCOMMAND
230 void RegisterList::setFunction(char *s) volatile
231 {
232  int reg, cab;
233  int fByte, eByte;
234 
235  int a, b, c, d, e;
236 
237  switch (sscanf(s, "%d %d %d %d %d", &a, &b, &c, &d, &e))
238  {
239  case 2:
240  reg = 0;
241  cab = a;
242  fByte = b;
243  eByte = -1;
244  break;
245 
246  case 3:
247  reg = 0;
248  cab = a;
249  fByte = b;
250  eByte = c;
251  break;
252  case 4:
253  reg = b;
254  cab = c;
255  fByte = d;
256  eByte = -1;
257  break;
258  case 5:
259  reg = b;
260  cab = c;
261  fByte = d;
262  eByte = e;
263  break;
264 
265  default:
266 #ifdef DCCPP_DEBUG_MODE
267  Serial.println(F("f Syntax error"));
268 #endif
269  return;
270  }
271 
272  this->setFunction(reg, cab, fByte, eByte);
273 
274 } // RegisterList::setFunction(string)
275 #endif
276 
278 
279 void RegisterList::setAccessory(int aAdd, int aNum, int activate) volatile
280 {
281  byte b[3]; // save space for checksum byte
282 
283  b[0] = aAdd % 64 + 128; // first byte is of the form 10AAAAAA, where AAAAAA represent 6 least significant bits of accessory address
284  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
285 
286  loadPacket(0, b, 2, 4, 1);
287 
288 } // RegisterList::setAccessory(ints)
289 
290 #ifdef USE_TEXTCOMMAND
291 void RegisterList::setAccessory(char *s) volatile
292 {
293  int aAdd; // the accessory address (0-511 = 9 bits)
294  int aNum; // the accessory number within that address (0-3)
295  int activate; // flag indicated whether accessory should be activated (1) or deactivated (0) following NMRA recommended convention
296 
297  if (sscanf(s, "%d %d %d", &aAdd, &aNum, &activate) != 3)
298  {
299 #ifdef DCCPP_DEBUG_MODE
300  Serial.println(F("a Syntax error"));
301 #endif
302  return;
303  }
304 
305  this->setAccessory(aAdd, aNum, activate);
306 
307 } // RegisterList::setAccessory(string)
308 #endif
309 
311 
312 void RegisterList::writeTextPacket(int nReg, byte *b, int nBytes) volatile
313 {
314 
315  if (nBytes<2 || nBytes>5) { // invalid valid packet
316  DCCPP_INTERFACE.print("<mInvalid Packet>");
317 #if !defined(USE_ETHERNET)
318  DCCPP_INTERFACE.println("");
319 #endif
320  return;
321  }
322 
323  loadPacket(nReg, b, nBytes, 0, 1);
324 
325 } // RegisterList::writeTextPacket(bytes)
326 
327 #ifdef USE_TEXTCOMMAND
328 void RegisterList::writeTextPacket(char *s) volatile
329 {
330  int nReg;
331  byte b[6];
332  int nBytes;
333 
334  nBytes = sscanf(s, "%d %hhx %hhx %hhx %hhx %hhx", &nReg, b, b + 1, b + 2, b + 3, b + 4) - 1;
335 
336  this->writeTextPacket(nReg, b, nBytes);
337 
338 } // RegisterList::writeTextPacket(string)
339 #endif
340 
342 
343 int RegisterList::buildBaseAcknowlegde(int inMonitorPin) volatile
344 {
345  int base = 0;
346  for (int j = 0; j < ACK_BASE_COUNT; j++)
347  {
348  int val = (int)analogRead(inMonitorPin);
349  base += val;
350  }
351 
352  return base / ACK_BASE_COUNT;
353 }
354 
355 int RegisterList::checkAcknowlegde(int inMonitorPin, int inBase) volatile
356 {
357  int c = 0;
358 #ifdef DCCPP_DEBUG_MODE
359  int max = 0;
360 #endif
361 
362  for (int j = 0; j < ACK_SAMPLE_COUNT; j++)
363  {
364  int val = (int)analogRead(inMonitorPin);
365  c = (int)((val - inBase) * ACK_SAMPLE_SMOOTHING + c * (1.0 - ACK_SAMPLE_SMOOTHING));
366 #ifdef DCCPP_DEBUG_MODE
367  if (c > max)
368  max = c;
369 #endif
370  if (c > ACK_SAMPLE_THRESHOLD)
371  return 1;
372  }
373 
374 #ifdef DCCPP_DEBUG_MODE
375  if (max > ACK_SAMPLE_THRESHOLD / 2)
376  {
377  // Only show closest values...
378  Serial.print(F("Max acknowledge value : "));
379  Serial.println(max);
380  }
381 #endif
382  return 0;
383 }
384 
385 int RegisterList::readCVraw(int cv, int callBack, int callBackSub) volatile
386 {
387  byte bRead[4];
388  int bValue;
389  int ret, base;
390 
391  cv--; // actual CV addresses are cv-1 (0-1023)
392 
393  byte MonitorPin = DCCppConfig::CurrentMonitorProg;
394  if (DCCpp::IsMainTrack(this))
395  MonitorPin = DCCppConfig::CurrentMonitorMain;
396 
397  // A read cannot be done if a monitor pin is not defined !
398  if (MonitorPin == UNDEFINED_PIN)
399  return -1;
400 
401 #ifdef DCCPP_DEBUG_MODE
402  Serial.print(F("readCVraw : start reading cv "));
403  Serial.println(cv);
404 #endif
405 
406  bRead[0] = 0x78 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
407  bRead[1] = lowByte(cv);
408 
409  bValue = 0;
410 
411  for (int i = 0; i<8; i++) {
412 
413  base = RegisterList::buildBaseAcknowlegde(MonitorPin);
414 
415  bRead[2] = 0xE8 + i;
416 
417  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
418  loadPacket(0, bRead, 3, 5); // NMRA recommends 5 verify packets
419  loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
420 
421  ret = RegisterList::checkAcknowlegde(MonitorPin, base);
422 
423  bitWrite(bValue, i, ret);
424  }
425 
426  base = RegisterList::buildBaseAcknowlegde(MonitorPin);
427 
428  bRead[0] = 0x74 + (highByte(cv) & 0x03); // set-up to re-verify entire byte
429  bRead[2] = bValue;
430 
431  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
432  loadPacket(0, bRead, 3, 5); // NMRA recommends 5 verify packets
433  loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
434 
435  ret = RegisterList::checkAcknowlegde(MonitorPin, base);
436 
437  if (ret == 0) // verify unsuccessful
438  bValue = -1;
439 
440 #if defined(USE_TEXTCOMMAND)
441  DCCPP_INTERFACE.print("<r");
442  DCCPP_INTERFACE.print(callBack);
443  DCCPP_INTERFACE.print("|");
444  DCCPP_INTERFACE.print(callBackSub);
445  DCCPP_INTERFACE.print("|");
446  DCCPP_INTERFACE.print(cv + 1);
447  DCCPP_INTERFACE.print(" ");
448  DCCPP_INTERFACE.print(bValue);
449  DCCPP_INTERFACE.print(">");
450 #if !defined(USE_ETHERNET)
451  DCCPP_INTERFACE.println("");
452 #endif
453 #endif
454 
455 #ifdef DCCPP_DEBUG_MODE
456  Serial.println(F("end reading"));
457 #endif
458  return bValue;
459 }
460 
461 int RegisterList::readCV(int cv, int callBack, int callBackSub) volatile
462 {
463  return RegisterList::readCVraw(cv, callBack, callBackSub);
464 } // RegisterList::readCV(ints)
465 
466 #ifdef USE_TEXTCOMMAND
467 int RegisterList::readCV(char *s) volatile
468 {
469  int cv, callBack, callBackSub;
470 
471  if (sscanf(s, "%d %d %d", &cv, &callBack, &callBackSub) != 3) // cv = 1-1024
472  {
473 #ifdef DCCPP_DEBUG_MODE
474  Serial.println(F("R Syntax error"));
475 #endif
476  return -1;
477  }
478 
479  return this->readCV(cv, callBack, callBackSub);
480 } // RegisterList::readCV(string)
481 #endif
482 
483 int RegisterList::readCVmain(int cv, int callBack, int callBackSub) volatile
484 {
485  return RegisterList::readCVraw(cv, callBack, callBackSub);
486 
487 } // RegisterList::readCV_Main()
488 
489 #ifdef USE_TEXTCOMMAND
490 int RegisterList::readCVmain(char *s) volatile
491 {
492  int cv, callBack, callBackSub;
493 
494  if (sscanf(s, "%d %d %d", &cv, &callBack, &callBackSub) != 3) // cv = 1-1024
495  {
496 #ifdef DCCPP_DEBUG_MODE
497  Serial.println(F("r Syntax error"));
498 #endif
499  return -1;
500  }
501 
502  return this->readCVmain(cv, callBack, callBackSub);
503 } // RegisterList::readCVmain(string)
504 #endif
505 
507 
508 void RegisterList::writeCVByte(int cv, int bValue, int callBack, int callBackSub) volatile
509 {
510  byte bWrite[4];
511  int ret, base;
512 
513  cv--; // actual CV addresses are cv-1 (0-1023)
514 
515  bWrite[0] = 0x7C + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
516  bWrite[1] = lowByte(cv);
517  bWrite[2] = bValue;
518 
519  loadPacket(0, resetPacket, 2, 1);
520  loadPacket(0, bWrite, 3, 4);
521  loadPacket(0, resetPacket, 2, 1);
522  loadPacket(0, idlePacket, 2, 10);
523 
524  // If monitor pin undefined, write cv without any confirmation...
525  if (DCCppConfig::CurrentMonitorProg != UNDEFINED_PIN)
526  {
527  base = RegisterList::buildBaseAcknowlegde(DCCppConfig::CurrentMonitorProg);
528 
529  bWrite[0] = 0x74 + (highByte(cv) & 0x03); // set-up to re-verify entire byte
530 
531  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
532  loadPacket(0, bWrite, 3, 5); // NMRA recommends 5 verify packets
533  loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
534 
535  ret = RegisterList::checkAcknowlegde(DCCppConfig::CurrentMonitorProg, base);
536 
537  if (ret == 0) // verify unsuccessful
538  bValue = -1;
539  }
540 
541 #if defined(USE_TEXTCOMMAND)
542  DCCPP_INTERFACE.print("<r");
543  DCCPP_INTERFACE.print(callBack);
544  DCCPP_INTERFACE.print("|");
545  DCCPP_INTERFACE.print(callBackSub);
546  DCCPP_INTERFACE.print("|");
547  DCCPP_INTERFACE.print(cv + 1);
548  DCCPP_INTERFACE.print(" ");
549  DCCPP_INTERFACE.print(bValue);
550  DCCPP_INTERFACE.print(">");
551 #if !defined(USE_ETHERNET)
552  DCCPP_INTERFACE.println("");
553 #endif
554 #endif
555 } // RegisterList::writeCVByte(ints)
556 
557 #ifdef USE_TEXTCOMMAND
558 void RegisterList::writeCVByte(char *s) volatile
559 {
560  int bValue, cv, callBack, callBackSub;
561 
562  if (sscanf(s, "%d %d %d %d", &cv, &bValue, &callBack, &callBackSub) != 4) // cv = 1-1024
563  {
564 #ifdef DCCPP_DEBUG_MODE
565  Serial.println(F("W Syntax error"));
566 #endif
567  return;
568  }
569 
570  this->writeCVByte(cv, bValue, callBack, callBackSub);
571 } // RegisterList::writeCVByte(string)
572 #endif
573 
575 
576 void RegisterList::writeCVBit(int cv, int bNum, int bValue, int callBack, int callBackSub) volatile
577 {
578  byte bWrite[4];
579  int ret, base;
580 
581  cv--; // actual CV addresses are cv-1 (0-1023)
582  bValue = bValue % 2;
583  bNum = bNum % 8;
584 
585  bWrite[0] = 0x78 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
586  bWrite[1] = lowByte(cv);
587  bWrite[2] = 0xF0 + bValue * 8 + bNum;
588 
589  loadPacket(0, resetPacket, 2, 1);
590  loadPacket(0, bWrite, 3, 4);
591  loadPacket(0, resetPacket, 2, 1);
592  loadPacket(0, idlePacket, 2, 10);
593 
594  // If monitor pin undefined, write cv without any confirmation...
595  if (DCCppConfig::CurrentMonitorProg != UNDEFINED_PIN)
596  {
597  base = RegisterList::buildBaseAcknowlegde(DCCppConfig::CurrentMonitorProg);
598 
599  bitClear(bWrite[2], 4); // change instruction code from Write Bit to Verify Bit
600 
601  loadPacket(0, resetPacket, 2, 3); // NMRA recommends starting with 3 reset packets
602  loadPacket(0, bWrite, 3, 5); // NMRA recommends 5 verfy packets
603  loadPacket(0, resetPacket, 2, 1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
604 
605  ret = RegisterList::checkAcknowlegde(DCCppConfig::CurrentMonitorProg, base);
606 
607  if (ret == 0) // verify unsuccessful
608  bValue = -1;
609  }
610 
611 #if defined(USE_TEXTCOMMAND)
612  DCCPP_INTERFACE.print("<r");
613  DCCPP_INTERFACE.print(callBack);
614  DCCPP_INTERFACE.print("|");
615  DCCPP_INTERFACE.print(callBackSub);
616  DCCPP_INTERFACE.print("|");
617  DCCPP_INTERFACE.print(cv + 1);
618  DCCPP_INTERFACE.print(" ");
619  DCCPP_INTERFACE.print(bNum);
620  DCCPP_INTERFACE.print(" ");
621  DCCPP_INTERFACE.print(bValue);
622  DCCPP_INTERFACE.print(">");
623 #if !defined(USE_ETHERNET)
624  DCCPP_INTERFACE.println("");
625 #endif
626 #endif
627 } // RegisterList::writeCVBit(ints)
628 
629 #ifdef USE_TEXTCOMMAND
630 void RegisterList::writeCVBit(char *s) volatile
631 {
632  int bNum, bValue, cv, callBack, callBackSub;
633 
634  if(sscanf(s,"%d %d %d %d %d",&cv,&bNum,&bValue,&callBack,&callBackSub) != 5) // cv = 1-1024
635  {
636 #ifdef DCCPP_DEBUG_MODE
637  Serial.println(F("W Syntax error"));
638 #endif
639  return;
640  }
641 
642  this->writeCVBit(cv, bNum, bValue, callBack, callBackSub);
643 } // RegisterList::writeCVBit(string)
644 #endif
645 
647 
648 void RegisterList::writeCVByteMain(int cab, int cv, int bValue) volatile
649 {
650  byte b[6]; // save space for checksum byte
651  byte nB = 0;
652 
653  cv--;
654 
655  if (cab>127)
656  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
657 
658  b[nB++] = lowByte(cab);
659  b[nB++] = 0xEC + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
660  b[nB++] = lowByte(cv);
661  b[nB++] = bValue;
662 
663  loadPacket(0, b, nB, 4);
664 
665 } // RegisterList::writeCVByteMain(ints)
666 
667 #ifdef USE_TEXTCOMMAND
668 void RegisterList::writeCVByteMain(char *s) volatile
669 {
670  int cab;
671  int cv;
672  int bValue;
673 
674  if (sscanf(s, "%d %d %d", &cab, &cv, &bValue) != 3)
675  {
676 #ifdef DCCPP_DEBUG_MODE
677  Serial.println(F("w Syntax error"));
678 #endif
679  return;
680  }
681 
682  this->writeCVByteMain(cab, cv, bValue);
683 } // RegisterList::writeCVByteMain(string)
684 #endif
685 
687 
688 void RegisterList::writeCVBitMain(int cab, int cv, int bNum, int bValue) volatile
689 {
690  byte b[6]; // save space for checksum byte
691  byte nB = 0;
692 
693  cv--;
694 
695  bValue = bValue % 2;
696  bNum = bNum % 8;
697 
698  if (cab>127)
699  b[nB++] = highByte(cab) | 0xC0; // convert train number into a two-byte address
700 
701  b[nB++] = lowByte(cab);
702  b[nB++] = 0xE8 + (highByte(cv) & 0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
703  b[nB++] = lowByte(cv);
704  b[nB++] = 0xF0 + bValue * 8 + bNum;
705 
706  loadPacket(0, b, nB, 4);
707 
708 } // RegisterList::writeCVBitMain(ints)
709 
710 #ifdef USE_TEXTCOMMAND
711 void RegisterList::writeCVBitMain(char *s) volatile
712 {
713  int cab;
714  int cv;
715  int bNum;
716  int bValue;
717 
718  if (sscanf(s, "%d %d %d %d", &cab, &cv, &bNum, &bValue) != 4)
719  {
720 #ifdef DCCPP_DEBUG_MODE
721  Serial.println(F("w Syntax error"));
722 #endif
723  return;
724  }
725 
726  this->writeCVBitMain(cab, cv, bNum, bValue);
727 } // RegisterList::writeCVBitMain(string)
728 #endif
729 
731 
732 #ifdef DCCPP_DEBUG_MODE
733 void RegisterList::printPacket(int nReg, byte *b, int nBytes, int nRepeat) volatile
734 {
735  DCCPP_INTERFACE.print("<*");
736  DCCPP_INTERFACE.print(nReg);
737  DCCPP_INTERFACE.print(":");
738  for(int i=0;i<nBytes;i++){
739  DCCPP_INTERFACE.print(" ");
740  DCCPP_INTERFACE.print(b[i],HEX);
741  }
742  DCCPP_INTERFACE.print(" / ");
743  DCCPP_INTERFACE.print(nRepeat);
744  DCCPP_INTERFACE.print(">");
745 #if !defined(USE_ETHERNET)
746  DCCPP_INTERFACE.println("");
747 #endif
748 } // RegisterList::printPacket()
749 #endif
750 
752 
753 byte RegisterList::idlePacket[3]={0xFF,0x00,0}; // always leave extra byte for checksum computation
754 byte RegisterList::resetPacket[3]={0x00,0x00,0};
755 
756 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:186