// // DCC_Decoder.cpp - Arduino library for NMRA DCC Decoding. // Written by Kevin Snow, MynaBay.com, November, 2011. // Questions: dcc@mynabay.com // Released into the public domain. // #include "Arduino.h" #include "DCC_Decoder.h" ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Global Decoder object // DCC_Decoder DCC; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // NMRA DCC Definitions // // Microsecond 0 & 1 timings #define kONE_Min 52 #define kONE_Max 64 #define kZERO_Min 90 #define kZERO_Max 10000 // Minimum preamble length #define kPREAMBLE_MIN 10 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Interrupt handling // unsigned long DCC_Decoder::gInterruptMicros = 0; byte DCC_Decoder::gInterruptTimeIndex = 0; volatile unsigned int DCC_Decoder::gInterruptTime[2]; volatile unsigned int DCC_Decoder::gInterruptChaos; /////////////////////////////////////////////////// void DCC_Decoder::DCC_Interrupt() { unsigned long ms = micros(); gInterruptTime[gInterruptTimeIndex] = ms - gInterruptMicros; gInterruptMicros = ms; gInterruptChaos += gInterruptTimeIndex; gInterruptTimeIndex ^= 0x01; } /////////////////////////////////////////////////// void DCC_Decoder::ShiftInterruptAlignment() { noInterrupts(); gInterruptTime[0] = gInterruptTime[1]; gInterruptTimeIndex = 1; interrupts(); } /////////////////////////////////////////////////// void DCC_Decoder::StartInterrupt(byte interrupt) { gInterruptTimeIndex = 0; gInterruptTime[0] = gInterruptTime[1] = 0; gInterruptChaos = 0; gInterruptMicros = micros(); attachInterrupt( interrupt, DCC_Interrupt, CHANGE ); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Globals // typedef void(*StateFunc)(); // Current state function pointer StateFunc DCC_Decoder::gState; // Current state function pointer // Timing data from last interrupt unsigned int DCC_Decoder::gLastChaos; // Interrupt chaos count we processed // Preamble bit count int DCC_Decoder::gPreambleCount; // Bit count for reading preamble // Reset reason byte DCC_Decoder::gResetReason; // Result code of last reason decoder was reset boolean DCC_Decoder::gHandledAsRawPacket; // Packet data byte DCC_Decoder::gPacket[kPACKET_LEN_MAX]; // The packet data. byte DCC_Decoder::gPacketIndex; // Byte index to write to. byte DCC_Decoder::gPacketMask; // Bit index to write to. 0x80,0x40,0x20,...0x01 boolean DCC_Decoder::gPacketEndedWith1; // Set true if packet ended on 1. Spec requires that the // packet end bit can count as a bit in next preamble. // CV Storage byte DCC_Decoder::gCV[kCV_MAX]; // CV Storage (TODO - Move to PROGMEM) // Packet arrival timing unsigned long DCC_Decoder::gThisPacketMS; // Milliseconds of this packet being parsed boolean DCC_Decoder::gLastPacketToThisAddress; // Was last pack processed to this decoder's address? unsigned long DCC_Decoder::gLastValidPacketMS; // Milliseconds of last valid packet unsigned long DCC_Decoder::gLastValidPacketToAddressMS; // Milliseconds of last valid packet to this decoder unsigned long DCC_Decoder::gLastValidIdlePacketMS; // Milliseconds of last valid idle packet unsigned long DCC_Decoder::gLastValidResetPacketMS; // Milliseconds of last valid reset packet ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Packet Timing Support // unsigned long DCC_Decoder::MillisecondsSinceLastValidPacket() { return millis() - gLastValidPacketMS; } unsigned long DCC_Decoder::MillisecondsSinceLastPacketToThisDecoder() { return millis() - gLastValidPacketToAddressMS; } unsigned long DCC_Decoder::MillisecondsSinceLastIdlePacket() { return millis() - gLastValidIdlePacketMS; } unsigned long DCC_Decoder::MillisecondsSinceLastResetPacket() { return millis() - gLastValidResetPacketMS; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // CV Support // byte DCC_Decoder::ReadCV(int cv) { if( cv>=kCV_PrimaryAddress && cv=kCV_PrimaryAddress && cv 3 ) errorDectection ^= gPacket[2]; if( gPacketIndex > 4 ) errorDectection ^= gPacket[3]; if( gPacketIndex > 5 ) errorDectection ^= gPacket[4]; if( errorDectection != gPacket[gPacketIndex-1] ) { GOTO_DecoderReset( kDCC_ERR_DETECTION_FAILED ); } // Save off milliseconds of this valid packet gThisPacketMS = millis(); gLastPacketToThisAddress = false; /////////////////////////////////////////////////////////// // Dispatch to RawPacketHandler - All packets go to raw (except idle and reset above) // // gHandledAsRawPacket cleared in Reset. If packet is handled here this flag avoids // sending to another dispatch routine. We don't just return here because we need to // figure out packet type and update time fields. if( func_RawPacket ) { gHandledAsRawPacket = (func_RawPacket)(gPacketIndex,gPacket); } /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Handle 3 byte packets if( gPacketIndex == 3 ) { /////////////////////////////////////////////////////////// // Decoder idle & reset packets as defined in 9.2. if( gPacket[1]==0x00 ) { // Broadcast idle packet if( gPacket[0]==0xFF ) { if( !gHandledAsRawPacket && func_IdlePacket ) { (func_IdlePacket)(gPacketIndex,gPacket); } GOTO_DecoderReset( kDCC_OK_IDLE ); }else{ // Broadcast reset packet if( gPacket[0]==0x00 ) { if( !gHandledAsRawPacket && func_ResetPacket ) { (func_ResetPacket)(gPacketIndex,gPacket); } GOTO_DecoderReset( kDCC_OK_RESET ); } } } /////////////////////////////////////////////////////////// // Handle as a basic accessory decoder packet if( ((gPacket[0] & 0xC0) == 0x80) && ((gPacket[1] & 0x80) == 0x80) ) { address = ~gPacket[1] & 0x70; address = (address<<2) + (gPacket[0] & 0x3F); gLastPacketToThisAddress = (address==DCC.Address()); if( gLastPacketToThisAddress || address == 0x003F || func_BasicAccPacket_All_Packets ) // 0x003F is broadcast packet { if( !gHandledAsRawPacket && func_BasicAccPacket ) { // Call BasicAccHandler Activate bit data bits (func_BasicAccPacket)( address, ((gPacket[1] & 0x08) ? true : false), (gPacket[1] & 0x07)); } } GOTO_DecoderReset( kDCC_OK_BASIC_ACCESSORY ); } /////////////////////////////////////////////////////////// // Handle as a baseline packet // What decoder is this addressed to? if( gPacket[0] & 0x80 ) { GOTO_DecoderReset( kDCC_ERR_BASELINE_ADDR ); } // Baseline instruction packet? if( (gPacket[1] & 0xC0) != 0x40 ) { GOTO_DecoderReset( kDCC_ERR_BASELINE_INSTR ); } // bits as defined in 9.2 byte addressByte = gPacket[0] & 0x7F; byte directionBit = gPacket[1] & 0x20; byte cBit = gPacket[1] & 0x10; byte speedBits = gPacket[1] & 0x0F; // Stop or estop?? if( speedBits==0 ) { speedBits = kDCC_STOP_SPEED; }else{ if( speedBits== 1 ) { speedBits = kDCC_ESTOP_SPEED; }else{ if( gCV[kCV_ConfigurationData1] & 0x02 ) // Bit 1 of CV29: 0=14speeds, 1=28Speeds { speedBits = ((speedBits << 1 ) & (cBit ? 1 : 0)) - 3; // speedBits = 1..28 }else{ speedBits -= 1; // speedBits = 1..14 } } } // Make callback gLastPacketToThisAddress = (addressByte==DCC.ReadCV(kCV_PrimaryAddress)); if( func_BaselineControlPacket_All_Packets || gLastPacketToThisAddress ) { if( !gHandledAsRawPacket && func_BaselineControlPacket ) { (*func_BaselineControlPacket)(addressByte,speedBits,directionBit); } } GOTO_DecoderReset( kDCC_OK_BASELINE ); } /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Handle 4 byte packets if( gPacketIndex == 4 ) { /////////////////////////////////////////////////////////// // Handle as a extd accessory decoder packet (4 bytes) if( ((gPacket[0] & 0xC0) == 0x80) && ((gPacket[1] & 0x85) == 0x01) ) { int msb = (gPacket[1] & 0x06); address = (gPacket[1] & 0x70); address = (msb<<8) + (address<<2) + (gPacket[0] & 0x3F); gLastPacketToThisAddress = (address==DCC.Address()); if( gLastPacketToThisAddress || address == 0x033F || func_ExtdAccPacket_All_Packets ) // 0x033F is broadcast packet { if( !gHandledAsRawPacket && func_ExtdAccPacket ) { // Call ExtAccHandler data bits (*func_ExtdAccPacket)( address, gPacket[2] & 0x1F); } } GOTO_DecoderReset( kDCC_OK_EXTENDED_ACCESSORY ); } } /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Handle 5 byte packets if( gPacketIndex == 5 ) { // TODO - Implement } /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Handle 6 byte packets if( gPacketIndex == 6 ) { // TODO - Implement } /////////////////////////////////////////////////////////// // Done! GOTO_DecoderReset( kDCC_OK ); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Standard interrupt reader - If a complete bit has been read it places timing in periodA & periodB and flows out bottom. // #define StandardInterruptHeader(behalfOf) \ noInterrupts(); \ if( gInterruptChaos == gLastChaos ) \ { \ interrupts(); \ return; \ } \ if( gInterruptChaos-gLastChaos > 1 ) \ { \ interrupts(); \ GOTO_DecoderReset( kDCC_ERR_MISSED_BITS ); \ } \ unsigned int periodA = gInterruptTime[0]; \ unsigned int periodB = gInterruptTime[1]; \ gLastChaos = gInterruptChaos; \ interrupts(); \ boolean aIs1 = ( periodA >= kONE_Min && periodA <= kONE_Max ); \ if( !aIs1 && (periodA < kZERO_Min || periodA > kZERO_Max) ) \ { \ GOTO_DecoderReset( kDCC_ERR_NOT_0_OR_1 ); \ } \ boolean bIs1 = ( periodB >= kONE_Min && periodB <= kONE_Max ); \ if( !bIs1 && (periodB < kZERO_Min || periodB > kZERO_Max) ) \ { \ GOTO_DecoderReset( kDCC_ERR_NOT_0_OR_1 ); \ } \ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Read packet bytes // void DCC_Decoder::State_ReadPacket() { // Interrupt header StandardInterruptHeader(); // Normally the two halves match. If not, reset if( aIs1 == bIs1 ) { // 8 out of 9 times through we'll have a mask and be writing bits if( gPacketMask ) { // Write the bit. if( aIs1 ) { gPacket[gPacketIndex] |= gPacketMask; } // advance the bit mask gPacketMask = gPacketMask >> 1; }else{ // Getting here is the 9th time and the it's the data start bit between bytes. // Zero indicates more data, 1 indicates end of packet // Advance index and reset mask gPacketIndex++; gPacketMask = 0x80; // Data start bit is a 1, that's the end of packet! Execute. if( aIs1 ) { gPacketEndedWith1 = true; if( gPacketIndex>=kPACKET_LEN_MIN && gPacketIndex<=kPACKET_LEN_MAX ) { GOTO_ExecutePacket(); } GOTO_DecoderReset( kDCC_ERR_INVALID_LENGTH ); }else{ // Data start bit is a 0. Do we have room for more data? if( gPacketIndex >= kPACKET_LEN_MAX ) { GOTO_DecoderReset( kDCC_ERR_MISSING_END_BIT ); } } } }else{ GOTO_DecoderReset( kDCC_ERR_NOT_0_OR_1 ); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Watch for Preamble // void DCC_Decoder::State_ReadPreamble() { // Interrupt header StandardInterruptHeader(); // If we get here, booleans aIs1 and bIs1 are set to the two halves of the next bit. // If both are 1, it's a 1 bit. if( aIs1 && bIs1 ) { // Increment preamble bit count ++gPreambleCount; }else{ // If they equal it's a 0. if( aIs1 == bIs1 ) { if( gPreambleCount >= kPREAMBLE_MIN ) { // BANG! Read preamble plus trailing 0. Go read the packet. GOTO_ReadPacketState(); } }else{ // One is 0 the other 1. Shift alignment. ShiftInterruptAlignment(); } // Not enough bits in preamble or shifted alignment. Start over at zero preamble. gPreambleCount = 0; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Reset handling (Part 2) // void DCC_Decoder::State_Reset() { // EngineReset Handler (Debugging) if( func_DecodingEngineCompletion ) { (func_DecodingEngineCompletion)(gHandledAsRawPacket ? kDCC_OK_MAX : gResetReason); } gHandledAsRawPacket = false; // If reset with an OK code, this was a valid packet. Save off times if( gResetReason < kDCC_OK_MAX ) { // Save MS of last valid packet gLastValidPacketMS = gThisPacketMS; // Save off other times switch( gResetReason ) { case kDCC_OK_IDLE: gLastValidIdlePacketMS = gThisPacketMS; break; case kDCC_OK_RESET: gLastValidResetPacketMS = gThisPacketMS; break; case kDCC_OK_BASELINE: case kDCC_OK_BASIC_ACCESSORY: case kDCC_OK_EXTENDED_ACCESSORY: if(gLastPacketToThisAddress) { gLastValidPacketToAddressMS = gThisPacketMS; } break; default: break; } } // Reset packet data gPacket[0] = gPacket[1] = gPacket[2] = gPacket[3] = gPacket[4] = gPacket[5] = 0; gPacketIndex = 0; gPacketMask = 0x80; // Copy last time and reset chaos noInterrupts(); gPreambleCount = (gPacketEndedWith1 && gLastChaos==gInterruptChaos) ? 1 : 0; gLastChaos = gInterruptChaos = 0; interrupts(); // Clear packet ended 1 flag gPacketEndedWith1 = false; // Go find preamble GOTO_PreambleState(); } void DCC_Decoder::State_Boot() { } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // SetupDecoder // void DCC_Decoder::SetupDecoder(byte mfgID, byte mfgVers, byte interrupt) { if( gInterruptMicros == 0 ) { // Save mfg info gCV[kCV_ManufacturerVersionNo] = mfgID; gCV[kCV_ManufacturedID] = mfgVers; // Attach the DCC interrupt StartInterrupt(interrupt); // Start decoder in reset state GOTO_DecoderReset( kDCC_OK_BOOT ); } } void DCC_Decoder::SetupMonitor(byte interrupt) { if( gInterruptMicros == 0 ) { // Attach the DCC interrupt StartInterrupt(interrupt); // Start decoder in reset state GOTO_DecoderReset( kDCC_OK_BOOT ); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Hearbeat function. Dispatch the dcc_decoder library state machine. // void DCC_Decoder::loop() { (gState)(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Constructor (Not really). // DCC_Decoder::DCC_Decoder() { gState = DCC_Decoder::State_Boot; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Human readable error strings // const char PROGMEM* DCC_Decoder::ResultString(byte resultCode) { static const char PROGMEM* const gResults[] = { "OK", "OK - Unhandled", "OK - Boot", "OK - Idle packet", "OK - Reset packet", "OK - Handled raw", "OK - Handled baseline", "OK - Handled basic accessory", "OK - Handled extended accessory", }; static const char PROGMEM* const gErrors[] = { "ERROR - Detection failed", "ERROR - Baseline address", "ERROR - Baseline instruction", "ERROR - Missed bits", "ERROR - Not 0 or 1", "ERROR - Invalid packet length", "ERROR - Missing packet end bits", }; static const char PROGMEM* const gErrorsBadCode = "ERROR - Bad result code"; if( resultCode>=0 && resultCode<(sizeof(gResults)/sizeof(gResults[0])) ) { return gResults[resultCode]; } if( resultCode>=100 && (resultCode-100)<(byte)(sizeof(gErrors)/sizeof(gErrors[0])) ) { return gErrors[resultCode-100]; } return gErrorsBadCode; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Helper to make packet strings // char* DCC_Decoder::MakePacketString(char* buffer60Bytes, byte byteCount, byte* packet) { buffer60Bytes[0] = 0; if( byteCount>=kPACKET_LEN_MIN && byteCount<=kPACKET_LEN_MAX ) { int i = 0; for(byte byt=0; byt>1; } buffer60Bytes[i++] = ' '; } buffer60Bytes[--i] = 0; } return buffer60Bytes; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Helper to return preamble length // int DCC_Decoder::LastPreambleBitCount() { return gPreambleCount; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////