Advertisement
Guest User

Untitled

a guest
Jul 2nd, 2020
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.97 KB | None | 0 0
  1. /**********************************************************************
  2.  
  3. PacketRegister.cpp
  4. COPYRIGHT (c) 2013-2016 Gregg E. Berman
  5.  
  6. Part of DCC++ EX BASE STATION for the Arduino
  7.  
  8. **********************************************************************/
  9.  
  10. #include "DCCppEX.h"
  11. #include "PacketRegister.h"
  12. #include "CommInterface.h"
  13.  
  14. ///////////////////////////////////////////////////////////////////////////////
  15.  
  16. void Register::initPackets(){
  17. activePacket=packet;
  18. updatePacket=packet+1;
  19. } // Register::initPackets
  20.  
  21. ///////////////////////////////////////////////////////////////////////////////
  22.  
  23. RegisterList::RegisterList(int maxNumRegs){
  24. this->maxNumRegs=maxNumRegs;
  25. reg=(Register *)calloc((maxNumRegs+1),sizeof(Register));
  26. for(int i=0;i<=maxNumRegs;i++)
  27. reg[i].initPackets();
  28. regMap=(Register **)calloc((maxNumRegs+1),sizeof(Register *));
  29. speedTable=(int *)calloc((maxNumRegs+1),sizeof(int *));
  30. currentReg=reg;
  31. regMap[0]=reg;
  32. maxLoadedReg=reg;
  33. nextReg=NULL;
  34. currentBit=0;
  35. nRepeat=0;
  36. } // RegisterList::RegisterList
  37.  
  38. ///////////////////////////////////////////////////////////////////////////////
  39.  
  40. // LOAD DCC PACKET INTO TEMPORARY REGISTER 0, OR PERMANENT REGISTERS 1 THROUGH DCC_PACKET_QUEUE_MAX (INCLUSIVE)
  41. // CONVERTS 2, 3, 4, OR 5 BYTES INTO A DCC BIT STREAM WITH PREAMBLE, CHECKSUM, AND PROPER BYTE SEPARATORS
  42. // BITSTREAM IS STORED IN UP TO A 10-BYTE ARRAY (USING AT MOST 76 OF 80 BITS)
  43.  
  44. void RegisterList::loadPacket(int nReg, byte *b, int nBytes, int nRepeat, int printFlag) volatile {
  45.  
  46. nReg=nReg%((maxNumRegs+1)); // force nReg to be between 0 and maxNumRegs, inclusive
  47.  
  48. 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
  49.  
  50. if(regMap[nReg]==NULL) // first time this Register Number has been called
  51. regMap[nReg]=maxLoadedReg+1; // set Register Pointer for this Register Number to next available Register
  52.  
  53. Register *r=regMap[nReg]; // set Register to be updated
  54. Packet *p=r->updatePacket; // set Packet in the Register to be updated
  55. byte *buf=p->buf; // set byte buffer in the Packet to be updated
  56.  
  57. b[nBytes]=b[0]; // copy first byte into what will become the checksum byte
  58. for(int i=1;i<nBytes;i++) // XOR remaining bytes into checksum byte
  59. b[nBytes]^=b[i];
  60. nBytes++; // increment number of bytes in packet to include checksum byte
  61.  
  62. buf[0]=0xFF; // first 8 bytes of 22-byte preamble
  63. buf[1]=0xFF; // second 8 bytes of 22-byte preamble
  64. buf[2]=0xFC + bitRead(b[0],7); // last 6 bytes of 22-byte preamble + data start bit + b[0], bit 7
  65. buf[3]=b[0]<<1; // b[0], bits 6-0 + data start bit
  66. buf[4]=b[1]; // b[1], all bits
  67. buf[5]=b[2]>>1; // b[2], bits 7-1
  68. buf[6]=b[2]<<7; // b[2], bit 0
  69.  
  70. if(nBytes==3){
  71. p->nBits=49;
  72. } else{
  73. buf[6]+=b[3]>>2; // b[3], bits 7-2
  74. buf[7]=b[3]<<6; // b[3], bit 1-0
  75. if(nBytes==4){
  76. p->nBits=58;
  77. } else{
  78. buf[7]+=b[4]>>3; // b[4], bits 7-3
  79. buf[8]=b[4]<<5; // b[4], bits 2-0
  80. if(nBytes==5){
  81. p->nBits=67;
  82. } else{
  83. buf[8]+=b[5]>>4; // b[5], bits 7-4
  84. buf[9]=b[5]<<4; // b[5], bits 3-0
  85. p->nBits=76;
  86. } // >5 bytes
  87. } // >4 bytes
  88. } // >3 bytes
  89.  
  90. nextReg=r;
  91. this->nRepeat=nRepeat;
  92. maxLoadedReg=max(maxLoadedReg,nextReg);
  93.  
  94. if(printFlag && SHOW_PACKETS) // for debugging purposes
  95. printPacket(nReg,b,nBytes,nRepeat);
  96.  
  97. } // RegisterList::loadPacket
  98.  
  99. ///////////////////////////////////////////////////////////////////////////////
  100.  
  101. void RegisterList::setThrottle(const char *s) volatile{
  102. byte b[5]; // save space for checksum byte
  103. int nReg;
  104. int cab;
  105. int tSpeed;
  106. int tDirection;
  107. byte nB=0;
  108.  
  109. if(sscanf(s,"%d %d %d %d",&nReg,&cab,&tSpeed,&tDirection)!=4)
  110. return;
  111.  
  112. if(nReg<1 || nReg>maxNumRegs)
  113. return;
  114.  
  115. if(cab>127)
  116. b[nB++]=highByte(cab) | 0xC0; // convert train number into a two-byte address
  117.  
  118. b[nB++]=lowByte(cab);
  119. b[nB++]=0x3F; // 128-step speed control byte
  120. if(tSpeed>=0)
  121. b[nB++]=tSpeed+(tSpeed>0)+tDirection*128; // max speed is 126, but speed codes range from 2-127 (0=stop, 1=emergency stop)
  122. else{
  123. b[nB++]=1;
  124. tSpeed=0;
  125. }
  126.  
  127. loadPacket(nReg,b,nB,0,1);
  128.  
  129. CommManager::printf("<T %d %d %d>", nReg, tSpeed, tDirection);
  130.  
  131. speedTable[nReg]=tDirection==1?tSpeed:-tSpeed;
  132.  
  133. } // RegisterList::setThrottle()
  134.  
  135. ///////////////////////////////////////////////////////////////////////////////
  136.  
  137. void RegisterList::setFunction(const char *s) volatile{
  138. byte b[5]; // save space for checksum byte
  139. int cab;
  140. int fByte, eByte;
  141. int nParams;
  142. byte nB=0;
  143.  
  144. nParams=sscanf(s,"%d %d %d",&cab,&fByte,&eByte);
  145.  
  146. if(nParams<2)
  147. return;
  148.  
  149. if(cab>127)
  150. b[nB++]=highByte(cab) | 0xC0; // convert train number into a two-byte address
  151.  
  152. b[nB++]=lowByte(cab);
  153.  
  154. if(nParams==2){ // this is a request for functions FL,F1-F12
  155. 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
  156. } else { // this is a request for functions F13-F28
  157. b[nB++]=(fByte | 0xDE) & 0xDF; // for safety this guarantees that first byte will either be 0xDE (for F13-F20) or 0xDF (for F21-F28)
  158. b[nB++]=eByte;
  159. }
  160.  
  161. loadPacket(0,b,nB,4,1);
  162.  
  163. } // RegisterList::setFunction()
  164.  
  165. ///////////////////////////////////////////////////////////////////////////////
  166.  
  167. void RegisterList::setAccessory(const char *s) volatile{
  168. byte b[3]; // save space for checksum byte
  169. int aAdd; // the accessory address (0-511 = 9 bits)
  170. int aNum; // the accessory number within that address (0-3)
  171. int activate; // flag indicated whether accessory should be activated (1) or deactivated (0) following NMRA recommended convention
  172.  
  173. if(sscanf(s,"%d %d %d",&aAdd,&aNum,&activate)!=3)
  174. return;
  175.  
  176. b[0]=aAdd%64+128; // first byte is of the form 10AAAAAA, where AAAAAA represent 6 least signifcant bits of accessory address
  177. 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
  178.  
  179. loadPacket(0,b,2,4,1);
  180.  
  181. } // RegisterList::setAccessory()
  182.  
  183. ///////////////////////////////////////////////////////////////////////////////
  184.  
  185. void RegisterList::writeTextPacket(const char *s) volatile{
  186.  
  187. int nReg;
  188. byte b[6];
  189. int nBytes;
  190. nBytes=sscanf(s,"%d %x %x %x %x %x",&nReg,b,b+1,b+2,b+3,b+4)-1;
  191.  
  192. if(nBytes<2 || nBytes>5){ // invalid valid packet
  193. CommManager::printf("<mInvalid Packet>");
  194. return;
  195. }
  196. loadPacket(nReg,b,nBytes,0,1);
  197. } // RegisterList::writeTextPacket()
  198.  
  199. ///////////////////////////////////////////////////////////////////////////////
  200. //byte RegisterList::ackDetect(unsigned int base) volatile{ TODO work in progress. Factoring this routine to this function breaks the code
  201. // int c=0;
  202. // byte count=0;
  203. // byte d=0;
  204. // for(int j=0;j<ACK_SAMPLE_COUNT;j++){ // TODO remove old code when tested
  205. // // c=(analogRead(CURRENT_MONITOR_PIN_PROG)-base)*ACK_SAMPLE_SMOOTHING+c*(1.0-ACK_SAMPLE_SMOOTHING);
  206. // //c=(unsigned int)((((analogRead(CURRENT_MONITOR_PIN_PROG))-base)*(unsigned long int)CURRENT_CONVERSION_FACTOR)/100);
  207. // // c=(unsigned int)(((analogRead(CURRENT_MONITOR_PIN_PROG) * (unsigned long int)CURRENT_CONVERSION_FACTOR)/100) - base);
  208. // c=((analogRead(CURRENT_MONITOR_PIN_PROG)*CURRENT_CONVERSION_FACTOR)/100) - base;
  209. // //CommManager::printf("%d,",c);
  210. // //if (c < base) {
  211. // // c=base;
  212. // //}
  213. // if(c > ACK_SAMPLE_THRESHOLD) {
  214. // count++;
  215. // if (count==2){
  216. // CommManager::printf("%d,", c);
  217. // d=1; //TODO Issue a reset packet here?
  218. // //break;
  219. // }
  220. // }
  221. // // if (d==1){
  222. // // printf("XX");
  223. // // break;
  224. //// }
  225. // }
  226. // return d;
  227. //}
  228.  
  229. ///////////////////////////////////////////////////////////////////////////////
  230.  
  231. unsigned int RegisterList::readBaseCurrent() volatile {
  232. unsigned int base=0;
  233. for(int j=0;j<ACK_BASE_COUNT;j++)
  234. base+=analogRead(CURRENT_MONITOR_PIN_PROG);
  235. base/=ACK_BASE_COUNT;
  236. return base;
  237. } // RegisterList::readBaseCurrent()
  238.  
  239. ///////////////////////////////////////////////////////////////////////////////
  240.  
  241. void RegisterList::readCV(const char *s) volatile{
  242. byte bRead[4];
  243. int bValue;
  244. int cv, callBack, callBackSub;
  245. int current;
  246. unsigned int base;
  247. byte count=0;
  248. byte d=0;
  249. int ackThreshold;
  250.  
  251. ackThreshold = ACK_SAMPLE_THRESHOLD/((CURRENT_CONVERSION_FACTOR)/100);
  252.  
  253. if(sscanf(s,"%d %d %d",&cv,&callBack,&callBackSub) != 3) { // cv = 1-1024
  254. return;
  255. }
  256. cv--; // actual CV addresses are cv-1 (0-1023)
  257.  
  258. bRead[0]=0x78+(highByte(cv)&0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
  259. bRead[1]=lowByte(cv);
  260.  
  261. bValue=0;
  262.  
  263. for(int i=0;i<8;i++) {
  264. base=0;
  265. current=0;
  266. d=0;
  267. count=0;
  268.  
  269. base=readBaseCurrent();
  270.  
  271. bRead[2]=0xE8+i;
  272.  
  273. loadPacket(0,resetPacket,2,3); // NMRA recommends starting with 3 reset packets
  274. loadPacket(0,bRead,3,5); // NMRA recommends 5 verify packets
  275. loadPacket(0,bRead,3,1); // Line for D&H decoders
  276. loadPacket(0,idlePacket,2,6); // NMRA recommends 6 idle or reset packets for decoder recovery time
  277.  
  278. for(int j=0;j<ACK_SAMPLE_COUNT;j++){
  279. current=analogRead(CURRENT_MONITOR_PIN_PROG) - base;
  280. if(current > ackThreshold) {
  281. count++;
  282. if (count==2){
  283. d=1;
  284. //break; // TODO see if we can break out of this once we get an ACK
  285. }
  286. }
  287. }
  288. bitWrite(bValue,i,d);
  289. }
  290.  
  291. base=0;
  292. current=0;
  293. d=0;
  294. count=0;
  295.  
  296. base=readBaseCurrent();
  297.  
  298. bRead[0]=0x74+(highByte(cv)&0x03); // set-up to re-verify entire byte
  299. bRead[2]=bValue;
  300.  
  301. loadPacket(0,resetPacket,2,3); // NMRA recommends starting with 3 reset packets
  302. loadPacket(0,bRead,3,5); // NMRA recommends 5 verify packets
  303. loadPacket(0,bRead,3,1); // forces code to wait until all repeats of bRead are completed (and decoder begins to respond)
  304. loadPacket(0,idlePacket,2,6); // NMRA recommends 6 idle or reset packets for decoder recovery time
  305.  
  306. for(int j=0;j<ACK_SAMPLE_COUNT;j++){
  307. current=analogRead(CURRENT_MONITOR_PIN_PROG) - base;
  308. if(current > ackThreshold) {
  309. count++;
  310. if (count==2){
  311. d=1;
  312. //break; TODO see if we can break out of here once we get an ACK
  313. }
  314. }
  315. }
  316.  
  317. if(d==0) { // verify unsuccessful
  318. bValue=-1;
  319. }else {
  320. loadPacket(0,resetPacket,2,1); // Final reset packet completed (and decoder begines to respond)
  321. }
  322.  
  323. CommManager::printf("<r%d|%d|%d %d>", callBack, callBackSub, cv+1, bValue);
  324. } // RegisterList::readCV()
  325.  
  326. ///////////////////////////////////////////////////////////////////////////////
  327.  
  328. void RegisterList::writeCVByte(const char *s) volatile{
  329. byte bWrite[4];
  330. int bValue;
  331. int cv, callBack, callBackSub;
  332. int current;
  333. unsigned int base;
  334. byte count=0;
  335. byte d=0;
  336. int ackThreshold;
  337.  
  338. ackThreshold = ACK_SAMPLE_THRESHOLD/((CURRENT_CONVERSION_FACTOR)/100);
  339.  
  340. if(sscanf(s,"%d %d %d %d",&cv,&bValue,&callBack,&callBackSub)!=4) // cv = 1-1024
  341. return;
  342. cv--; // actual CV addresses are cv-1 (0-1023)
  343.  
  344. bWrite[0]=0x7C+(highByte(cv)&0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
  345. bWrite[1]=lowByte(cv);
  346. bWrite[2]=bValue;
  347.  
  348. //loadPacket(0,resetPacket,2,1); // NMRA recommends starting with 3 reset packets
  349. //loadPacket(0,bWrite,3,4); // NMRA recommends 5 write packets
  350. //loadPacket(0,bWrite,2,6); // NMRA recommends 6 write or reset packets for decoder recovery time
  351. //loadPacket(0,idlePacket,2,10);
  352.  
  353. loadPacket(0,resetPacket,2,1);
  354. loadPacket(0,bWrite,3,4);
  355. // loadPacket(0,resetPacket,2,1);
  356. loadPacket(0,idlePacket,2,10);
  357.  
  358. base=0;
  359. current=0;
  360. d=0;
  361. count=0;
  362.  
  363. base=readBaseCurrent();
  364.  
  365. bWrite[0]=0x74+(highByte(cv)&0x03); // set-up to re-verify entire byte
  366.  
  367. // TODO NMRA says reset, write then reset IF we got a verify
  368. loadPacket(0,resetPacket,2,3); // NMRA recommends starting with 3 reset packets
  369. loadPacket(0,bWrite,3,5); // NMRA recommends 5 verify packets
  370. loadPacket(0,bWrite,3,1); // NMRA recommends 6 write or reset packets for decoder recovery time
  371.  
  372. for(int j=0;j<ACK_SAMPLE_COUNT;j++){
  373. current=analogRead(CURRENT_MONITOR_PIN_PROG) - base;
  374. if(current > ackThreshold) {
  375. count++;
  376. if (count==2){
  377. // CommManager::printf("%d,", c); TODO remove after testing
  378. d=1;
  379. //break; TODO see if we can break out of here once we get an ACK
  380. }
  381. }
  382. }
  383.  
  384. if(d==0) { // verify unsuccessful
  385. bValue=-1;
  386. }else {
  387. loadPacket(0,resetPacket,2,1); // Final reset packet (and decoder begins to respond)
  388. }
  389.  
  390. CommManager::printf("<r%d|%d|%d %d>", callBack, callBackSub, cv+1, bValue);
  391. } // RegisterList::writeCVByte()
  392.  
  393. ///////////////////////////////////////////////////////////////////////////////
  394.  
  395. void RegisterList::writeCVBit(const char *s) volatile{
  396. byte bWrite[4];
  397. int bNum,bValue;
  398. int cv, callBack, callBackSub;
  399. int current=0;
  400. unsigned int base;
  401. byte count=0;
  402. byte d=0;
  403. int ackThreshold;
  404.  
  405. if(sscanf(s,"%d %d %d %d %d",&cv,&bNum,&bValue,&callBack,&callBackSub)!=5) // cv = 1-1024
  406. return;
  407. cv--; // actual CV addresses are cv-1 (0-1023)
  408.  
  409. bValue=bValue%2;
  410. bNum=bNum%8;
  411.  
  412. bWrite[0]=0x78+(highByte(cv)&0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
  413. bWrite[1]=lowByte(cv);
  414. bWrite[2]=0xF0+bValue*8+bNum;
  415.  
  416. loadPacket(0,resetPacket,2,1); // NMRA recommends starting with 3 reset packets
  417. loadPacket(0,bWrite,3,4); // NMRA recommends 5 verify packets
  418. //loadPacket(0,bWrite,3,6); // NMRA recommends 6 write or reset packets for decoder recovery time
  419. loadPacket(0,idlePacket,2,10); // TODO remove old line after testing
  420.  
  421. current=0;
  422. d=0;
  423. base=0;
  424. count=0;
  425.  
  426. base=readBaseCurrent();
  427.  
  428. bitClear(bWrite[2],4); // change instruction code from Write Bit to Verify Bit
  429.  
  430. loadPacket(0,resetPacket,2,3); // NMRA recommends starting with 3 reset packets
  431. loadPacket(0,bWrite,3,5); // NMRA recommends 5 verify packets
  432. loadPacket(0,bWrite,3,1); // NMRA recommends 6 write or reset packets for decoder recovery time
  433.  
  434. for(int j=0;j<ACK_SAMPLE_COUNT;j++){
  435. current=analogRead(CURRENT_MONITOR_PIN_PROG) - base;
  436. if(current > ackThreshold) {
  437. count++;
  438. if (count==2){
  439. // CommManager::printf("%d,", c); TODO remove after testing
  440. d=1;
  441. //break; TODO see if we can break out of here once we get an ACK
  442. }
  443. }
  444. }
  445.  
  446. if(d==0) { // verify unsuccessful
  447. bValue=-1;
  448. }else {
  449. loadPacket(0,resetPacket,2,1);
  450. }
  451. CommManager::printf("<r%d|%d|%d %d %d>", callBack, callBackSub, cv+1, bNum, bValue);
  452. } // RegisterList::writeCVBit()
  453.  
  454. ///////////////////////////////////////////////////////////////////////////////
  455.  
  456. void RegisterList::writeCVByteMain(const char *s) volatile{
  457. byte b[6]; // save space for checksum byte
  458. int cab;
  459. int cv;
  460. int bValue;
  461. byte nB=0;
  462.  
  463. if(sscanf(s,"%d %d %d",&cab,&cv,&bValue)!=3)
  464. return;
  465. cv--;
  466.  
  467. if(cab>127)
  468. b[nB++]=highByte(cab) | 0xC0; // convert train number into a two-byte address
  469.  
  470. b[nB++]=lowByte(cab);
  471. b[nB++]=0xEC+(highByte(cv)&0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
  472. b[nB++]=lowByte(cv);
  473. b[nB++]=bValue;
  474.  
  475. loadPacket(0,b,nB,4);
  476.  
  477. } // RegisterList::writeCVByteMain()
  478.  
  479. ///////////////////////////////////////////////////////////////////////////////
  480.  
  481. void RegisterList::writeCVBitMain(const char *s) volatile{
  482. byte b[6]; // save space for checksum byte
  483. int cab;
  484. int cv;
  485. int bNum;
  486. int bValue;
  487. byte nB=0;
  488.  
  489. if(sscanf(s,"%d %d %d %d",&cab,&cv,&bNum,&bValue)!=4)
  490. return;
  491. cv--;
  492.  
  493. bValue=bValue%2;
  494. bNum=bNum%8;
  495.  
  496. if(cab>127)
  497. b[nB++]=highByte(cab) | 0xC0; // convert train number into a two-byte address
  498.  
  499. b[nB++]=lowByte(cab);
  500. b[nB++]=0xE8+(highByte(cv)&0x03); // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
  501. b[nB++]=lowByte(cv);
  502. b[nB++]=0xF0+bValue*8+bNum;
  503.  
  504. loadPacket(0,b,nB,4);
  505.  
  506. } // RegisterList::writeCVBitMain()
  507.  
  508. ///////////////////////////////////////////////////////////////////////////////
  509.  
  510. void RegisterList::printPacket(int nReg, byte *b, int nBytes, int nRepeat) volatile {
  511. CommManager::printf("<*%d:", nReg);
  512. for(int i=0;i<nBytes;i++){
  513. CommManager::printf(" %02x", b[i]);
  514. }
  515. CommManager::printf(" / %d>", nRepeat);
  516. } // RegisterList::printPacket()
  517.  
  518. ///////////////////////////////////////////////////////////////////////////////
  519.  
  520. byte RegisterList::idlePacket[3]={0xFF,0x00,0}; // always leave extra byte for checksum computation
  521. byte RegisterList::resetPacket[3]={0x00,0x00,0};
  522.  
  523. 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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement