diff --git a/NmraDcc.cpp b/NmraDcc.cpp index 9df1429..29ab28d 100644 --- a/NmraDcc.cpp +++ b/NmraDcc.cpp @@ -39,7 +39,7 @@ #endif // Uncomment to print DEBUG messages -// #define DEBUG_PRINT +//#define DEBUG_PRINT //------------------------------------------------------------------------ // DCC Receive Routine @@ -581,11 +581,14 @@ uint8_t writeCV( unsigned int CV, uint8_t Value) { switch( CV ) { + case CV_29_CONFIG: + // copy addressmode Bit to Flags + DccProcState.Flags = ( DccProcState.Flags & ~FLAGS_OUTPUT_ADDRESS_MODE) | (Value & FLAGS_OUTPUT_ADDRESS_MODE); + // no break, because myDccAdress must also be reset case CV_ACCESSORY_DECODER_ADDRESS_LSB: // Also same CV for CV_MULTIFUNCTION_PRIMARY_ADDRESS case CV_ACCESSORY_DECODER_ADDRESS_MSB: case CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB: case CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB: - case CV_29_CONFIG: DccProcState.myDccAddress = -1; // Assume any CV Write Operation might change the Address } @@ -598,6 +601,10 @@ uint8_t writeCV( unsigned int CV, uint8_t Value) if( notifyCVChange ) notifyCVChange( CV, Value) ; + if( notifyDccCVChange && !(DccProcState.Flags & FLAGS_SETCV_CALLED) ) + notifyDccCVChange( CV, Value ); + + DccProcState.Flags &= ~FLAGS_SETCV_CALLED; } return readEEPROM( CV ) ; } @@ -882,11 +889,10 @@ void processServiceModeOperation( DCC_MSG * pDccMsg ) { uint16_t CVAddr ; uint8_t Value ; - if( pDccMsg->Size == 3) // 3 Byte Packets are for Address Only, Register and Paged Mode { uint8_t RegisterAddr ; - + DB_PRINT("3-BytePkt"); RegisterAddr = pDccMsg->Data[0] & 0x07 ; Value = pDccMsg->Data[1] ; @@ -928,7 +934,7 @@ void processServiceModeOperation( DCC_MSG * pDccMsg ) } else if( pDccMsg->Size == 4) // 4 Byte Packets are for Direct Byte & Bit Mode - { + { DB_PRINT("BB-Mode"); CVAddr = ( ( ( pDccMsg->Data[0] & 0x03 ) << 8 ) | pDccMsg->Data[1] ) + 1 ; Value = pDccMsg->Data[2] ; @@ -1048,46 +1054,48 @@ void execDccProcessor( DCC_MSG * pDccMsg ) { if( DccProcState.Flags & FLAGS_DCC_ACCESSORY_DECODER ) { - uint16_t BoardAddress ; - uint16_t OutputAddress ; + int16_t BoardAddress ; + int16_t OutputAddress ; uint8_t TurnoutPairIndex ; #ifdef DEBUG_PRINT - SerialPrintPacketHex(F( "execDccProcessor: Accessory Decoder Command: "), pDccMsg); + SerialPrintPacketHex(F( "eDP: AccCmd: "), pDccMsg); #endif BoardAddress = ( ( (~pDccMsg->Data[1]) & 0b01110000 ) << 2 ) | ( pDccMsg->Data[0] & 0b00111111 ) ; - DB_PRINT("execDccProcessor: Board Addr: %d", BoardAddress); + TurnoutPairIndex = (pDccMsg->Data[1] & 0b00000110) >> 1; + DB_PRINT("eDP: BAddr:%d, Index:%d", BoardAddress, TurnoutPairIndex); + // First check for Legacy Accessory Decoder Configuration Variable Access Instruction // as it's got a different format to the others if((pDccMsg->Size == 5) && ((pDccMsg->Data[1] & 0b10001100) == 0b00001100)) { - DB_PRINT( "execDccProcessor: Legacy Accessory Decoder CV Access Command"); + DB_PRINT( "eDP: Legacy Accessory Decoder CV Access Command"); // Check if this command is for our address or the broadcast address if((BoardAddress != getMyAddr()) && ( BoardAddress < 511 )) { - DB_PRINT("execDccProcessor: Board Address Not Matched"); + DB_PRINT("eDP: Board Address Not Matched"); return; } uint16_t cvAddress = ((pDccMsg->Data[1] & 0b00000011) << 8) + pDccMsg->Data[2] + 1; uint8_t cvValue = pDccMsg->Data[3]; - DB_PRINT("execDccProcessor: CV: %d Value: %d", cvAddress, cvValue ); + DB_PRINT("eDP: CV:%d Value:%d", cvAddress, cvValue ); if(validCV( cvAddress, 1 )) writeCV(cvAddress, cvValue); return; } - TurnoutPairIndex = (pDccMsg->Data[1] & 0b00000110) >> 1; OutputAddress = (((BoardAddress - 1) << 2 ) | TurnoutPairIndex) + 1 ; //decoder output addresses start with 1, packet address range starts with 0 // ( according to NMRA 9.2.2 ) + DB_PRINT("eDP: OAddr:%d", OutputAddress); if( DccProcState.inAccDecDCCAddrNextReceivedMode) { if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE ) { - DB_PRINT("execDccProcessor: Set Output Addr: %d", OutputAddress); + DB_PRINT("eDP: Set OAddr:%d", OutputAddress); //uint16_t storedOutputAddress = OutputAddress + 1; // The value stored in CV1 & 9 for Output Addressing Mode is + 1 writeCV(CV_ACCESSORY_DECODER_ADDRESS_LSB, (uint8_t)(OutputAddress % 256)); writeCV(CV_ACCESSORY_DECODER_ADDRESS_MSB, (uint8_t)(OutputAddress / 256)); @@ -1097,7 +1105,7 @@ void execDccProcessor( DCC_MSG * pDccMsg ) } else { - DB_PRINT("execDccProcessor: Set Board Addr: %d", BoardAddress); + DB_PRINT("eDP: Set BAddr:%d", BoardAddress); writeCV(CV_ACCESSORY_DECODER_ADDRESS_LSB, (uint8_t)(BoardAddress % 64)); writeCV(CV_ACCESSORY_DECODER_ADDRESS_MSB, (uint8_t)(BoardAddress / 64)); @@ -1111,21 +1119,32 @@ void execDccProcessor( DCC_MSG * pDccMsg ) // If we're filtering addresses, does the address match our address or is it a broadcast address? If NOT then return if( DccProcState.Flags & FLAGS_MY_ADDRESS_ONLY ) { - if( ( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE ) && ( OutputAddress != getMyAddr() ) && ( OutputAddress < 2045 ) ) - return; - - else if( ( BoardAddress != getMyAddr() ) && ( BoardAddress < 511 ) ) - return; - - DB_PRINT("execDccProcessor: Address Matched"); + if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE ) { + DB_PRINT(" AddrChk: OAddr:%d, BAddr:%d, myAddr:%d Chk=%d", OutputAddress, BoardAddress, getMyAddr(), OutputAddress != getMyAddr() ); + if ( OutputAddress != getMyAddr() && OutputAddress < 2045 ) { + DB_PRINT(" eDP: OAddr:%d, myAddr:%d - no match", OutputAddress, getMyAddr() ); + return; + } + } else { + if( ( BoardAddress != getMyAddr() ) && ( BoardAddress < 511 ) ) { + DB_PRINT(" eDP: BAddr:%d, myAddr:%d - no match", BoardAddress, getMyAddr() ); + return; + } + } + DB_PRINT("eDP: Address Matched"); } + if((pDccMsg->Size == 4) && ((pDccMsg->Data[1] & 0b10001001) == 1)) // Extended Accessory Decoder Control Packet Format { uint8_t state = pDccMsg->Data[2] ;// & 0b00011111; - DB_PRINT("execDccProcessor: Output Addr: %d Extended State: %0X", OutputAddress, state); + DB_PRINT("eDP: OAddr:%d Extended State:%0X", OutputAddress, state); if( notifyDccSigOutputState ) notifyDccSigOutputState(OutputAddress, state); + + // old callback ( for compatibility with 1.4.2, not to be used in new designs ) + if( notifyDccSigState ) + notifyDccSigState( OutputAddress, TurnoutPairIndex, pDccMsg->Data[2] ) ; } else if(pDccMsg->Size == 3) // Basic Accessory Decoder Packet Format @@ -1133,49 +1152,49 @@ void execDccProcessor( DCC_MSG * pDccMsg ) uint8_t direction = pDccMsg->Data[1] & 0b00000001; uint8_t outputPower = (pDccMsg->Data[1] & 0b00001000) >> 3; - // for compatibility with 1.4.2 + // old callback ( for compatibility with 1.4.2, not to be used in new designs ) if ( notifyDccAccState ) notifyDccAccState( OutputAddress, BoardAddress, pDccMsg->Data[1] & 0b00000111, outputPower ); if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE ) { - DB_PRINT("execDccProcessor: Output Addr: %d Turnout Dir: %d Output Power: %d", OutputAddress, direction, outputPower); + DB_PRINT("eDP: OAddr:%d Turnout Dir:%d Output Power:%d", OutputAddress, direction, outputPower); if( notifyDccAccTurnoutOutput ) notifyDccAccTurnoutOutput( OutputAddress, direction, outputPower ); } else { - DB_PRINT("execDccProcessor: Turnout Pair Index: %d Dir: %d Output Power: ", TurnoutPairIndex, direction, outputPower); + DB_PRINT("eDP: Turnout Pair Index:%d Dir:%d Output Power: ", TurnoutPairIndex, direction, outputPower); if( notifyDccAccTurnoutBoard ) notifyDccAccTurnoutBoard( BoardAddress, TurnoutPairIndex, direction, outputPower ); } } else if(pDccMsg->Size == 6) // Accessory Decoder OPS Mode Programming { - DB_PRINT("execDccProcessor: OPS Mode CV Programming Command"); + DB_PRINT("eDP: OPS Mode CV Programming Command"); // Check for unsupported OPS Mode Addressing mode if(((pDccMsg->Data[1] & 0b10001001) != 1) && ((pDccMsg->Data[1] & 0b10001111) != 0x80)) { - DB_PRINT("execDccProcessor: Unsupported OPS Mode CV Addressing Mode"); + DB_PRINT("eDP: Unsupported OPS Mode CV Addressing Mode"); return; } // Check if this command is for our address or the broadcast address if(DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE) { - DB_PRINT("execDccProcessor: Check Output Address: %d", OutputAddress); + DB_PRINT("eDP: Check Output Address:%d", OutputAddress); if((OutputAddress != getMyAddr()) && ( OutputAddress < 2045 )) { - DB_PRINT("execDccProcessor: Output Address Not Matched"); + DB_PRINT("eDP: Output Address Not Matched"); return; } } else { - DB_PRINT("execDccProcessor: Check Board Address: %d", BoardAddress); + DB_PRINT("eDP: Check Board Address:%d", BoardAddress); if((BoardAddress != getMyAddr()) && ( BoardAddress < 511 )) { - DB_PRINT("execDccProcessor: Board Address Not Matched"); + DB_PRINT("eDP: Board Address Not Matched"); return; } } @@ -1185,16 +1204,16 @@ void execDccProcessor( DCC_MSG * pDccMsg ) OpsInstructionType insType = (OpsInstructionType)((pDccMsg->Data[2] & 0b00001100) >> 2) ; - DB_PRINT("execDccProcessor: OPS Mode Instruction: %d", insType); + DB_PRINT("eDP: OPS Mode Instruction:%d", insType); switch(insType) { case OPS_INS_RESERVED: case OPS_INS_VERIFY_BYTE: - DB_PRINT("execDccProcessor: Unsupported OPS Mode Instruction: %d", insType); + DB_PRINT("eDP: Unsupported OPS Mode Instruction:%d", insType); break; // We only support Write Byte or Bit Manipulation case OPS_INS_WRITE_BYTE: - DB_PRINT("execDccProcessor: CV: %d Value: %d", cvAddress, cvValue); + DB_PRINT("eDP: CV:%d Value:%d", cvAddress, cvValue); if(validCV( cvAddress, 1 )) writeCV(cvAddress, cvValue); break; @@ -1314,6 +1333,7 @@ uint8_t NmraDcc::getCV( uint16_t CV ) //////////////////////////////////////////////////////////////////////// uint8_t NmraDcc::setCV( uint16_t CV, uint8_t Value) { + DccProcState.Flags |= FLAGS_SETCV_CALLED; return writeCV(CV,Value); } @@ -1398,6 +1418,7 @@ uint8_t NmraDcc::process() xorValue ^= DccRx.PacketCopy.Data[i]; if(xorValue) { #ifdef DCC_DBGVAR + DB_PRINT("Cerr"); countOf.Err++; #endif return 0 ; diff --git a/NmraDcc.h b/NmraDcc.h index 3f74178..ed2191d 100644 --- a/NmraDcc.h +++ b/NmraDcc.h @@ -202,6 +202,7 @@ class NmraDcc // Flag values to be logically ORed together and passed into the init() method #define FLAGS_MY_ADDRESS_ONLY 0x01 // Only process DCC Packets with My Address #define FLAGS_AUTO_FACTORY_DEFAULT 0x02 // Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255 +#define FLAGS_SETCV_CALLED 0x10 // only used internally !! #define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6 #define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7 @@ -630,6 +631,8 @@ extern uint8_t notifyIsSetCVReady(void) __attribute__ ((weak)); /*+ * notifyCVChange() Called when a CV value is changed. * This is called whenever a CV's value is changed. + * notifyDccCVChange() Called only when a CV value is changed by a Dcc packet or a internal lib function. + * it is NOT called if the CV is chaged by means of the setCV() method. * Note: It is not called if notifyCVWrite() is defined * or if the value in the EEPROM is the same as the value * in the write command. @@ -642,6 +645,7 @@ extern uint8_t notifyIsSetCVReady(void) __attribute__ ((weak)); * None */ extern void notifyCVChange( uint16_t CV, uint8_t Value) __attribute__ ((weak)); +extern void notifyDccCVChange( uint16_t CV, uint8_t Value) __attribute__ ((weak)); /*+ * notifyCVResetFactoryDefault() Called when CVs must be reset. @@ -654,7 +658,7 @@ extern void notifyCVChange( uint16_t CV, uint8_t Value) __attribute__ ((weak) * * Inputs: * None - * * + * * * Returns: * None */ @@ -667,15 +671,26 @@ extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak)); * * Inputs: * None - * * + * * * Returns: * None */ extern void notifyCVAck(void) __attribute__ ((weak)); +/*+ + * notifyServiceMode(bool) Called when state of 'inServiceMode' changes + * + * Inputs: + * bool state of inServiceMode + * * + * Returns: + * None + */ extern void notifyServiceMode(bool) __attribute__ ((weak)); -// Deprecated, only for backward compatibility with version 1.4.2. Don't use in new designs +// Deprecated, only for backward compatibility with version 1.4.2. +// Don't use in new designs. These functions may be dropped in future versions extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State ) __attribute__ ((weak)); +extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State) __attribute__ ((weak)); #if defined (__cplusplus) }