├── library.properties ├── keywords.txt ├── readme.md ├── readme.txt ├── examples ├── DCC_Monitor │ └── DCC_Monitor.pde └── DCC_Basic_Acc_Decoder │ └── DCC_Basic_Acc_Decoder.pde ├── DCC_Decoder.h └── DCC_Decoder.cpp /library.properties: -------------------------------------------------------------------------------- 1 | name=DCC Decoder 2 | author=MynaBay 3 | maintainer=MynaBay 4 | sentence=An Arduino library for creating NMRA DCC decoding devices. 5 | paragraph=Use this library to decode model railroad DCC signals. 6 | category=Communication 7 | url=https://github.com/MynaBay/DCC_Decoder 8 | architectures=* 9 | version=1.6 10 | core-dependencies=arduino (>=1.6.0) 11 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Matrix 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | DCC_Decoder KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | SetupDecoder KEYWORD2 16 | SetupMonitor KEYWORD2 17 | SetIdlePacketHandler KEYWORD2 18 | SetResetPacketHandler KEYWORD2 19 | SetRawPacketHandler KEYWORD2 20 | SetBasicAccessoryDecoderPacketHandler KEYWORD2 21 | SetExtendedAccessoryDecoderPacketHandler KEYWORD2 22 | SetBaselineControlPacketHandler KEYWORD2 23 | SetDecodingEngineCompletionStatusHandler KEYWORD2 24 | ReadCV KEYWORD2 25 | WriteCV KEYWORD2 26 | MakePacketString KEYWORD2 27 | ResultString KEYWORD2 28 | loop KEYWORD2 29 | Address KEYWORD2 30 | 31 | ####################################### 32 | # Constants (LITERAL1) 33 | ####################################### 34 | 35 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | This is a library for Arduino for decoding dcc signals. 2 | Uses Arduino 1.6 IDE. 3 | 4 | Installation 5 | -------------------------------------------------------------------------------- 6 | 7 | To install this library, just place this entire folder as a subfolder in your 8 | Arduino/lib/targets/libraries folder. 9 | 10 | When installed, this library should look like: 11 | 12 | libraries/DCC_Decoder (this library's folder) 13 | libraries/DCC_Decoder/DCC_Decoder.cpp (the library implementation file) 14 | libraries/DCC_Decoder/DCC_Decoder.h (the library header file) 15 | libraries/DCC_Decoder/keywords.txt (the syntax coloring file) 16 | libraries/DCC_Decoder/examples (the examples in the "open" menu) 17 | libraries/DCC_Decoder/readme.txt (this file) 18 | 19 | Building 20 | -------------------------------------------------------------------------------- 21 | 22 | After this library is installed, you just have to start the Arduino application. 23 | 24 | To use this library in a sketch, go to the Sketch | Import Library menu and 25 | select DCC_Decoder. This will add a corresponding line to the top of your sketch: 26 | 27 | #include 28 | 29 | To stop using this library, delete that line from your sketch. 30 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | This is a library for Arduino for decoding dcc signals. 2 | Uses Arduino 1.6 IDE. 3 | 4 | Installation 5 | -------------------------------------------------------------------------------- 6 | 7 | To install this library, just place this entire folder as a subfolder in your 8 | Arduino/lib/targets/libraries folder. 9 | 10 | When installed, this library should look like: 11 | 12 | libraries/DCC_Decoder (this library's folder) 13 | libraries/DCC_Decoder/DCC_Decoder.cpp (the library implementation file) 14 | libraries/DCC_Decoder/DCC_Decoder.h (the library header file) 15 | libraries/DCC_Decoder/keywords.txt (the syntax coloring file) 16 | libraries/DCC_Decoder/examples (the examples in the "open" menu) 17 | libraries/DCC_Decoder/readme.txt (this file) 18 | 19 | Building 20 | -------------------------------------------------------------------------------- 21 | 22 | After this library is installed, you just have to start the Arduino application. 23 | 24 | To use this library in a sketch, go to the Sketch | Import Library menu and 25 | select DCC_Decoder. This will add a corresponding line to the top of your sketch: 26 | 27 | #include 28 | 29 | To stop using this library, delete that line from your sketch. 30 | -------------------------------------------------------------------------------- /examples/DCC_Monitor/DCC_Monitor.pde: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 5 | // 6 | // Defines and structures 7 | // 8 | #define kDCC_INTERRUPT 0 9 | 10 | typedef struct 11 | { 12 | int count; 13 | byte validBytes; 14 | byte data[6]; 15 | } DCCPacket; 16 | 17 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 18 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // The dcc decoder object and global data 21 | // 22 | int gPacketCount = 0; 23 | int gIdlePacketCount = 0; 24 | int gLongestPreamble = 0; 25 | 26 | DCCPacket gPackets[25]; 27 | 28 | static unsigned long lastMillis = millis(); 29 | 30 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 31 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 32 | // 33 | // Packet handlers 34 | // 35 | 36 | // ALL packets are sent to the RawPacket handler. Returning true indicates that packet was handled. DCC library starts watching for 37 | // next preamble. Returning false and library continue parsing packet and finds another handler to call. 38 | boolean RawPacket_Handler(byte byteCount, byte* packetBytes) 39 | { 40 | // Bump global packet count 41 | ++gPacketCount; 42 | 43 | int thisPreamble = DCC.LastPreambleBitCount(); 44 | if( thisPreamble > gLongestPreamble ) 45 | { 46 | gLongestPreamble = thisPreamble; 47 | } 48 | 49 | // Walk table and look for a matching packet 50 | for( int i=0; i<(int)(sizeof(gPackets)/sizeof(gPackets[0])); ++i ) 51 | { 52 | if( gPackets[i].validBytes ) 53 | { 54 | // Not an empty slot. Does this slot match this packet? If so, bump count. 55 | if( gPackets[i].validBytes==byteCount ) 56 | { 57 | char isPacket = true; 58 | for( int j=0; j 0 ) 128 | { 129 | Serial.print(gPackets[i].count, DEC); 130 | if( gPackets[i].count < 10 ) 131 | { 132 | Serial.print(" "); 133 | }else{ 134 | if( gPackets[i].count < 100 ) 135 | { 136 | Serial.print(" "); 137 | }else{ 138 | Serial.print(" "); 139 | } 140 | } 141 | Serial.println( DCC.MakePacketString(buffer60Bytes, gPackets[i].validBytes, &gPackets[i].data[0]) ); 142 | } 143 | gPackets[i].validBytes = 0; 144 | gPackets[i].count = 0; 145 | } 146 | Serial.println("============================================"); 147 | 148 | gPacketCount = 0; 149 | gIdlePacketCount = 0; 150 | gLongestPreamble = 0; 151 | } 152 | 153 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 154 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 155 | // 156 | // Main loop 157 | // 158 | void loop() 159 | { 160 | DCC.loop(); 161 | 162 | if( millis()-lastMillis > 2000 ) 163 | { 164 | DumpAndResetTable(); 165 | lastMillis = millis(); 166 | } 167 | } 168 | 169 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 170 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 171 | 172 | -------------------------------------------------------------------------------- /examples/DCC_Basic_Acc_Decoder/DCC_Basic_Acc_Decoder.pde: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 5 | // 6 | // Defines and structures 7 | // 8 | #define kDCC_INTERRUPT 0 9 | 10 | typedef struct 11 | { 12 | int address; // Address to respond to 13 | byte output; // State of output 1=on, 0=off 14 | int outputPin; // Arduino output pin to drive 15 | boolean isDigital; // true=digital, false=analog. If analog must also set analogValue field 16 | boolean isFlasher; // true=flash output, false=no time, no flash. 17 | byte analogValue; // Value to use with analog type. 18 | int durationMilli; // Milliseconds to leave output on for. 0 means don't auto off 19 | 20 | unsigned long onMilli; // Used internally for timing 21 | unsigned long offMilli; // 22 | } DCCAccessoryAddress; 23 | 24 | DCCAccessoryAddress gAddresses[8]; 25 | 26 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 27 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 28 | // 29 | // Decoder Init 30 | // 31 | void ConfigureDecoder() 32 | { 33 | gAddresses[0].address = 714; 34 | gAddresses[0].output = 0; 35 | gAddresses[0].outputPin = 5; 36 | gAddresses[0].isDigital = false; 37 | gAddresses[0].isFlasher = false; 38 | gAddresses[0].analogValue = 250; 39 | gAddresses[0].durationMilli = 500; 40 | 41 | gAddresses[1].address = 715; 42 | gAddresses[1].output = 0; 43 | gAddresses[1].outputPin = 6; 44 | gAddresses[1].isDigital = true; 45 | gAddresses[1].isFlasher = false; 46 | gAddresses[1].analogValue = 0; 47 | gAddresses[1].durationMilli = 500; 48 | 49 | gAddresses[2].address = 814; 50 | gAddresses[2].output = 0; 51 | gAddresses[2].outputPin = 5; 52 | gAddresses[2].isDigital = false; 53 | gAddresses[2].isFlasher = true; 54 | gAddresses[2].analogValue = 250; 55 | gAddresses[2].durationMilli = 500; 56 | 57 | gAddresses[3].address = 815; 58 | gAddresses[3].output = 0; 59 | gAddresses[3].outputPin = 6; 60 | gAddresses[3].isDigital = true; 61 | gAddresses[3].isFlasher = true; 62 | gAddresses[3].analogValue = 0; 63 | gAddresses[3].durationMilli = 500; 64 | 65 | gAddresses[4].address = 914; 66 | gAddresses[4].output = 0; 67 | gAddresses[4].outputPin = 5; 68 | gAddresses[4].isDigital = false; 69 | gAddresses[4].isFlasher = false; 70 | gAddresses[4].analogValue = 250; 71 | gAddresses[4].durationMilli = 0; 72 | 73 | gAddresses[5].address = 915; 74 | gAddresses[5].output = 0; 75 | gAddresses[5].outputPin = 6; 76 | gAddresses[5].isDigital = true; 77 | gAddresses[5].isFlasher = false; 78 | gAddresses[5].analogValue = 0; 79 | gAddresses[5].durationMilli = 0; 80 | 81 | gAddresses[6].address = 0; 82 | gAddresses[6].output = 0; 83 | gAddresses[6].outputPin = 0; 84 | gAddresses[6].isDigital = false; 85 | gAddresses[6].isFlasher = false; 86 | gAddresses[6].analogValue = 0; 87 | gAddresses[6].durationMilli = 0; 88 | 89 | gAddresses[7].address = 0; 90 | gAddresses[7].output = 0; 91 | gAddresses[7].outputPin = 0; 92 | gAddresses[7].isDigital = false; 93 | gAddresses[7].isFlasher = false; 94 | gAddresses[7].analogValue = 0; 95 | gAddresses[7].durationMilli = 0; 96 | 97 | // Setup output pins 98 | for(int i=0; i<(int)(sizeof(gAddresses)/sizeof(gAddresses[0])); i++) 99 | { 100 | if( gAddresses[i].outputPin ) 101 | { 102 | pinMode( gAddresses[i].outputPin, OUTPUT ); 103 | } 104 | gAddresses[i].onMilli = 0; 105 | gAddresses[i].offMilli = 0; 106 | } 107 | } 108 | 109 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 110 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 111 | // 112 | // Basic accessory packet handler 113 | // 114 | void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data) 115 | { 116 | // Convert NMRA packet address format to human address 117 | address -= 1; 118 | address *= 4; 119 | address += 1; 120 | address += (data & 0x06) >> 1; 121 | 122 | boolean enable = (data & 0x01) ? 1 : 0; 123 | 124 | for(int i=0; i<(int)(sizeof(gAddresses)/sizeof(gAddresses[0])); i++) 125 | { 126 | if( address == gAddresses[i].address ) 127 | { 128 | Serial.print("Basic addr: "); 129 | Serial.print(address,DEC); 130 | Serial.print(" activate: "); 131 | Serial.println(enable,DEC); 132 | 133 | if( enable ) 134 | { 135 | gAddresses[i].output = 1; 136 | gAddresses[i].onMilli = millis(); 137 | gAddresses[i].offMilli = 0; 138 | }else{ 139 | gAddresses[i].output = 0; 140 | gAddresses[i].onMilli = 0; 141 | gAddresses[i].offMilli = millis(); 142 | } 143 | } 144 | } 145 | 146 | } 147 | 148 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 149 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 150 | // 151 | // Setup 152 | // 153 | void setup() 154 | { 155 | Serial.begin(9600); 156 | DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true); 157 | ConfigureDecoder(); 158 | DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT ); 159 | } 160 | 161 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 162 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 163 | // 164 | // Main loop 165 | // 166 | void loop() 167 | { 168 | static int addr = 0; 169 | 170 | //////////////////////////////////////////////////////////////// 171 | // Loop DCC library 172 | DCC.loop(); 173 | 174 | //////////////////////////////////////////////////////////////// 175 | // Bump to next address to test 176 | if( ++addr >= (int)(sizeof(gAddresses)/sizeof(gAddresses[0])) ) 177 | { 178 | addr = 0; 179 | } 180 | 181 | //////////////////////////////////////////////////////////////// 182 | // Turn off output? 183 | if( gAddresses[addr].offMilli && gAddresses[addr].offMilli=kCV_PrimaryAddress && cv=kCV_PrimaryAddress && cv 3 ) errorDectection ^= gPacket[2]; 278 | if( gPacketIndex > 4 ) errorDectection ^= gPacket[3]; 279 | if( gPacketIndex > 5 ) errorDectection ^= gPacket[4]; 280 | if( errorDectection != gPacket[gPacketIndex-1] ) 281 | { 282 | GOTO_DecoderReset( kDCC_ERR_DETECTION_FAILED ); 283 | } 284 | 285 | // Save off milliseconds of this valid packet 286 | gThisPacketMS = millis(); 287 | gLastPacketToThisAddress = false; 288 | 289 | /////////////////////////////////////////////////////////// 290 | // Dispatch to RawPacketHandler - All packets go to raw (except idle and reset above) 291 | // 292 | // gHandledAsRawPacket cleared in Reset. If packet is handled here this flag avoids 293 | // sending to another dispatch routine. We don't just return here because we need to 294 | // figure out packet type and update time fields. 295 | if( func_RawPacket ) 296 | { 297 | gHandledAsRawPacket = (func_RawPacket)(gPacketIndex,gPacket); 298 | } 299 | 300 | /////////////////////////////////////////////////////////// 301 | /////////////////////////////////////////////////////////// 302 | // Handle 3 byte packets 303 | if( gPacketIndex == 3 ) 304 | { 305 | /////////////////////////////////////////////////////////// 306 | // Decoder idle & reset packets as defined in 9.2. 307 | if( gPacket[1]==0x00 ) 308 | { 309 | // Broadcast idle packet 310 | if( gPacket[0]==0xFF ) 311 | { 312 | if( !gHandledAsRawPacket && func_IdlePacket ) 313 | { 314 | (func_IdlePacket)(gPacketIndex,gPacket); 315 | } 316 | GOTO_DecoderReset( kDCC_OK_IDLE ); 317 | }else{ 318 | // Broadcast reset packet 319 | if( gPacket[0]==0x00 ) 320 | { 321 | if( !gHandledAsRawPacket && func_ResetPacket ) 322 | { 323 | (func_ResetPacket)(gPacketIndex,gPacket); 324 | } 325 | GOTO_DecoderReset( kDCC_OK_RESET ); 326 | } 327 | } 328 | } 329 | 330 | /////////////////////////////////////////////////////////// 331 | // Handle as a basic accessory decoder packet 332 | if( ((gPacket[0] & 0xC0) == 0x80) && ((gPacket[1] & 0x80) == 0x80) ) 333 | { 334 | address = ~gPacket[1] & 0x70; 335 | address = (address<<2) + (gPacket[0] & 0x3F); 336 | gLastPacketToThisAddress = (address==DCC.Address()); 337 | if( gLastPacketToThisAddress || address == 0x003F || func_BasicAccPacket_All_Packets ) // 0x003F is broadcast packet 338 | { 339 | if( !gHandledAsRawPacket && func_BasicAccPacket ) 340 | { 341 | // Call BasicAccHandler Activate bit data bits 342 | (func_BasicAccPacket)( address, ((gPacket[1] & 0x08) ? true : false), (gPacket[1] & 0x07)); 343 | } 344 | } 345 | GOTO_DecoderReset( kDCC_OK_BASIC_ACCESSORY ); 346 | } 347 | 348 | /////////////////////////////////////////////////////////// 349 | // Handle as a baseline packet 350 | 351 | // What decoder is this addressed to? 352 | if( gPacket[0] & 0x80 ) 353 | { 354 | GOTO_DecoderReset( kDCC_ERR_BASELINE_ADDR ); 355 | } 356 | 357 | // Baseline instruction packet? 358 | if( (gPacket[1] & 0xC0) != 0x40 ) 359 | { 360 | GOTO_DecoderReset( kDCC_ERR_BASELINE_INSTR ); 361 | } 362 | 363 | // bits as defined in 9.2 364 | byte addressByte = gPacket[0] & 0x7F; 365 | byte directionBit = gPacket[1] & 0x20; 366 | byte cBit = gPacket[1] & 0x10; 367 | byte speedBits = gPacket[1] & 0x0F; 368 | 369 | // Stop or estop?? 370 | if( speedBits==0 ) 371 | { 372 | speedBits = kDCC_STOP_SPEED; 373 | }else{ 374 | if( speedBits== 1 ) 375 | { 376 | speedBits = kDCC_ESTOP_SPEED; 377 | }else{ 378 | if( gCV[kCV_ConfigurationData1] & 0x02 ) // Bit 1 of CV29: 0=14speeds, 1=28Speeds 379 | { 380 | speedBits = ((speedBits << 1 ) & (cBit ? 1 : 0)) - 3; // speedBits = 1..28 381 | }else{ 382 | speedBits -= 1; // speedBits = 1..14 383 | } 384 | } 385 | } 386 | 387 | // Make callback 388 | gLastPacketToThisAddress = (addressByte==DCC.ReadCV(kCV_PrimaryAddress)); 389 | if( func_BaselineControlPacket_All_Packets || gLastPacketToThisAddress ) 390 | { 391 | if( !gHandledAsRawPacket && func_BaselineControlPacket ) 392 | { 393 | (*func_BaselineControlPacket)(addressByte,speedBits,directionBit); 394 | } 395 | } 396 | GOTO_DecoderReset( kDCC_OK_BASELINE ); 397 | } 398 | 399 | /////////////////////////////////////////////////////////// 400 | /////////////////////////////////////////////////////////// 401 | // Handle 4 byte packets 402 | if( gPacketIndex == 4 ) 403 | { 404 | /////////////////////////////////////////////////////////// 405 | // Handle as a extd accessory decoder packet (4 bytes) 406 | if( ((gPacket[0] & 0xC0) == 0x80) && ((gPacket[1] & 0x85) == 0x01) ) 407 | { 408 | int msb = (gPacket[1] & 0x06); 409 | address = (gPacket[1] & 0x70); 410 | address = (msb<<8) + (address<<2) + (gPacket[0] & 0x3F); 411 | gLastPacketToThisAddress = (address==DCC.Address()); 412 | if( gLastPacketToThisAddress || address == 0x033F || func_ExtdAccPacket_All_Packets ) // 0x033F is broadcast packet 413 | { 414 | if( !gHandledAsRawPacket && func_ExtdAccPacket ) 415 | { 416 | // Call ExtAccHandler data bits 417 | (*func_ExtdAccPacket)( address, gPacket[2] & 0x1F); 418 | } 419 | } 420 | GOTO_DecoderReset( kDCC_OK_EXTENDED_ACCESSORY ); 421 | } 422 | } 423 | 424 | /////////////////////////////////////////////////////////// 425 | /////////////////////////////////////////////////////////// 426 | // Handle 5 byte packets 427 | if( gPacketIndex == 5 ) 428 | { 429 | // TODO - Implement 430 | } 431 | 432 | /////////////////////////////////////////////////////////// 433 | /////////////////////////////////////////////////////////// 434 | // Handle 6 byte packets 435 | if( gPacketIndex == 6 ) 436 | { 437 | // TODO - Implement 438 | } 439 | 440 | /////////////////////////////////////////////////////////// 441 | // Done! 442 | GOTO_DecoderReset( kDCC_OK ); 443 | } 444 | 445 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 446 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 447 | // 448 | // Standard interrupt reader - If a complete bit has been read it places timing in periodA & periodB and flows out bottom. 449 | // 450 | #define StandardInterruptHeader(behalfOf) \ 451 | noInterrupts(); \ 452 | if( gInterruptChaos == gLastChaos ) \ 453 | { \ 454 | interrupts(); \ 455 | return; \ 456 | } \ 457 | if( gInterruptChaos-gLastChaos > 1 ) \ 458 | { \ 459 | interrupts(); \ 460 | GOTO_DecoderReset( kDCC_ERR_MISSED_BITS ); \ 461 | } \ 462 | unsigned int periodA = gInterruptTime[0]; \ 463 | unsigned int periodB = gInterruptTime[1]; \ 464 | gLastChaos = gInterruptChaos; \ 465 | interrupts(); \ 466 | boolean aIs1 = ( periodA >= kONE_Min && periodA <= kONE_Max ); \ 467 | if( !aIs1 && (periodA < kZERO_Min || periodA > kZERO_Max) ) \ 468 | { \ 469 | GOTO_DecoderReset( kDCC_ERR_NOT_0_OR_1 ); \ 470 | } \ 471 | boolean bIs1 = ( periodB >= kONE_Min && periodB <= kONE_Max ); \ 472 | if( !bIs1 && (periodB < kZERO_Min || periodB > kZERO_Max) ) \ 473 | { \ 474 | GOTO_DecoderReset( kDCC_ERR_NOT_0_OR_1 ); \ 475 | } \ 476 | 477 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 478 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 479 | // 480 | // Read packet bytes 481 | // 482 | void DCC_Decoder::State_ReadPacket() 483 | { 484 | // Interrupt header 485 | StandardInterruptHeader(); 486 | 487 | // Normally the two halves match. If not, reset 488 | if( aIs1 == bIs1 ) 489 | { 490 | // 8 out of 9 times through we'll have a mask and be writing bits 491 | if( gPacketMask ) 492 | { 493 | // Write the bit. 494 | if( aIs1 ) 495 | { 496 | gPacket[gPacketIndex] |= gPacketMask; 497 | } 498 | // advance the bit mask 499 | gPacketMask = gPacketMask >> 1; 500 | 501 | }else{ 502 | // Getting here is the 9th time and the it's the data start bit between bytes. 503 | // Zero indicates more data, 1 indicates end of packet 504 | 505 | // Advance index and reset mask 506 | gPacketIndex++; 507 | gPacketMask = 0x80; 508 | 509 | // Data start bit is a 1, that's the end of packet! Execute. 510 | if( aIs1 ) 511 | { 512 | gPacketEndedWith1 = true; 513 | if( gPacketIndex>=kPACKET_LEN_MIN && gPacketIndex<=kPACKET_LEN_MAX ) 514 | { 515 | GOTO_ExecutePacket(); 516 | } 517 | GOTO_DecoderReset( kDCC_ERR_INVALID_LENGTH ); 518 | }else{ 519 | // Data start bit is a 0. Do we have room for more data? 520 | if( gPacketIndex >= kPACKET_LEN_MAX ) 521 | { 522 | GOTO_DecoderReset( kDCC_ERR_MISSING_END_BIT ); 523 | } 524 | } 525 | } 526 | }else{ 527 | GOTO_DecoderReset( kDCC_ERR_NOT_0_OR_1 ); 528 | } 529 | } 530 | 531 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 532 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 533 | // 534 | // Watch for Preamble 535 | // 536 | void DCC_Decoder::State_ReadPreamble() 537 | { 538 | // Interrupt header 539 | StandardInterruptHeader(); 540 | 541 | // If we get here, booleans aIs1 and bIs1 are set to the two halves of the next bit. 542 | 543 | // If both are 1, it's a 1 bit. 544 | if( aIs1 && bIs1 ) 545 | { 546 | // Increment preamble bit count 547 | ++gPreambleCount; 548 | }else{ 549 | // If they equal it's a 0. 550 | if( aIs1 == bIs1 ) 551 | { 552 | if( gPreambleCount >= kPREAMBLE_MIN ) 553 | { 554 | // BANG! Read preamble plus trailing 0. Go read the packet. 555 | GOTO_ReadPacketState(); 556 | } 557 | }else{ 558 | // One is 0 the other 1. Shift alignment. 559 | ShiftInterruptAlignment(); 560 | } 561 | // Not enough bits in preamble or shifted alignment. Start over at zero preamble. 562 | gPreambleCount = 0; 563 | } 564 | } 565 | 566 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 567 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 568 | // 569 | // Reset handling (Part 2) 570 | // 571 | void DCC_Decoder::State_Reset() 572 | { 573 | // EngineReset Handler (Debugging) 574 | if( func_DecodingEngineCompletion ) 575 | { 576 | (func_DecodingEngineCompletion)(gHandledAsRawPacket ? kDCC_OK_MAX : gResetReason); 577 | } 578 | gHandledAsRawPacket = false; 579 | 580 | // If reset with an OK code, this was a valid packet. Save off times 581 | if( gResetReason < kDCC_OK_MAX ) 582 | { 583 | // Save MS of last valid packet 584 | gLastValidPacketMS = gThisPacketMS; 585 | 586 | // Save off other times 587 | switch( gResetReason ) 588 | { 589 | case kDCC_OK_IDLE: 590 | gLastValidIdlePacketMS = gThisPacketMS; 591 | break; 592 | case kDCC_OK_RESET: 593 | gLastValidResetPacketMS = gThisPacketMS; 594 | break; 595 | case kDCC_OK_BASELINE: 596 | case kDCC_OK_BASIC_ACCESSORY: 597 | case kDCC_OK_EXTENDED_ACCESSORY: 598 | if(gLastPacketToThisAddress) 599 | { 600 | gLastValidPacketToAddressMS = gThisPacketMS; 601 | } 602 | break; 603 | default: 604 | break; 605 | } 606 | } 607 | 608 | // Reset packet data 609 | gPacket[0] = gPacket[1] = gPacket[2] = gPacket[3] = gPacket[4] = gPacket[5] = 0; 610 | gPacketIndex = 0; 611 | gPacketMask = 0x80; 612 | 613 | // Copy last time and reset chaos 614 | noInterrupts(); 615 | gPreambleCount = (gPacketEndedWith1 && gLastChaos==gInterruptChaos) ? 1 : 0; 616 | gLastChaos = gInterruptChaos = 0; 617 | interrupts(); 618 | 619 | // Clear packet ended 1 flag 620 | gPacketEndedWith1 = false; 621 | 622 | // Go find preamble 623 | GOTO_PreambleState(); 624 | } 625 | 626 | void DCC_Decoder::State_Boot() 627 | { 628 | } 629 | 630 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 631 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 632 | // 633 | // SetupDecoder 634 | // 635 | void DCC_Decoder::SetupDecoder(byte mfgID, byte mfgVers, byte interrupt) 636 | { 637 | if( gInterruptMicros == 0 ) 638 | { 639 | // Save mfg info 640 | gCV[kCV_ManufacturerVersionNo] = mfgID; 641 | gCV[kCV_ManufacturedID] = mfgVers; 642 | 643 | // Attach the DCC interrupt 644 | StartInterrupt(interrupt); 645 | 646 | // Start decoder in reset state 647 | GOTO_DecoderReset( kDCC_OK_BOOT ); 648 | } 649 | } 650 | 651 | void DCC_Decoder::SetupMonitor(byte interrupt) 652 | { 653 | if( gInterruptMicros == 0 ) 654 | { 655 | // Attach the DCC interrupt 656 | StartInterrupt(interrupt); 657 | 658 | // Start decoder in reset state 659 | GOTO_DecoderReset( kDCC_OK_BOOT ); 660 | } 661 | } 662 | 663 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 664 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 665 | // 666 | // Hearbeat function. Dispatch the dcc_decoder library state machine. 667 | // 668 | void DCC_Decoder::loop() 669 | { 670 | (gState)(); 671 | } 672 | 673 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 674 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 675 | // 676 | // Constructor (Not really). 677 | // 678 | DCC_Decoder::DCC_Decoder() 679 | { 680 | gState = DCC_Decoder::State_Boot; 681 | } 682 | 683 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 684 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 685 | // 686 | // Human readable error strings 687 | // 688 | 689 | const char PROGMEM* 690 | DCC_Decoder::ResultString(byte resultCode) 691 | { 692 | static const char PROGMEM* const gResults[] = 693 | { 694 | "OK", 695 | "OK - Unhandled", 696 | "OK - Boot", 697 | "OK - Idle packet", 698 | "OK - Reset packet", 699 | "OK - Handled raw", 700 | "OK - Handled baseline", 701 | "OK - Handled basic accessory", 702 | "OK - Handled extended accessory", 703 | }; 704 | 705 | static const char PROGMEM* const gErrors[] = 706 | { 707 | "ERROR - Detection failed", 708 | "ERROR - Baseline address", 709 | "ERROR - Baseline instruction", 710 | "ERROR - Missed bits", 711 | "ERROR - Not 0 or 1", 712 | "ERROR - Invalid packet length", 713 | "ERROR - Missing packet end bits", 714 | }; 715 | 716 | static const char PROGMEM* const gErrorsBadCode = "ERROR - Bad result code"; 717 | 718 | if( resultCode>=0 && resultCode<(sizeof(gResults)/sizeof(gResults[0])) ) 719 | { 720 | return gResults[resultCode]; 721 | } 722 | if( resultCode>=100 && (resultCode-100)<(byte)(sizeof(gErrors)/sizeof(gErrors[0])) ) 723 | { 724 | return gErrors[resultCode-100]; 725 | } 726 | return gErrorsBadCode; 727 | } 728 | 729 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 730 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 731 | // 732 | // Helper to make packet strings 733 | // 734 | char* DCC_Decoder::MakePacketString(char* buffer60Bytes, byte byteCount, byte* packet) 735 | { 736 | buffer60Bytes[0] = 0; 737 | if( byteCount>=kPACKET_LEN_MIN && byteCount<=kPACKET_LEN_MAX ) 738 | { 739 | int i = 0; 740 | for(byte byt=0; byt>1; 747 | } 748 | buffer60Bytes[i++] = ' '; 749 | } 750 | buffer60Bytes[--i] = 0; 751 | } 752 | return buffer60Bytes; 753 | } 754 | 755 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 756 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 757 | // 758 | // Helper to return preamble length 759 | // 760 | int DCC_Decoder::LastPreambleBitCount() 761 | { 762 | return gPreambleCount; 763 | } 764 | 765 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 766 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 767 | --------------------------------------------------------------------------------