Index: RTC.c =================================================================== diff -u -r1b618d2334c95066f413b46e9e3c399c699f2da3 -rafd5cc2609acbf8ccf9194da1e88461196c35968 --- RTC.c (.../RTC.c) (revision 1b618d2334c95066f413b46e9e3c399c699f2da3) +++ RTC.c (.../RTC.c) (revision afd5cc2609acbf8ccf9194da1e88461196c35968) @@ -7,8 +7,8 @@ * * @file RTC.c * -* @author (last) Bill Bracken -* @date (last) 19-Sep-2023 +* @author (last) Michael Garthwaite +* @date (last) 01-Mar-2023 * * @author (original) Dara Navaei * @date (original) 11-Jan-2020 @@ -137,6 +137,8 @@ /// Number of seconds in 2 years. Assumes no leap year in 2 year period. static const U32 SECONDS_IN_2_YEARS = SECONDS_IN_NORMAL_YEAR * 2; +#define MIN_EPOCH_DATE ( 1689958503 ) ///< Epoch dates must be greater than 8/11/2023 + /// RTC self-test state enumeration. typedef enum RTC_Self_Test_States { @@ -168,6 +170,7 @@ RTC_EXEC_STATE_READ_FROM_RAM, ///< Exec state read from RAM RTC_EXEC_STATE_READ, ///< Exec state read RTC_EXEC_STATE_WRITE, ///< Exec state write + RTC_EXEC_STATE_VERIFY_WRITE, ///< Exec state verify RTC write NUM_OF_RTC_EXEC_STATES ///< Total number of exec states } RTC_EXEC_STATE_T; @@ -214,6 +217,12 @@ static U16 previousFPGATimerCount; ///< Previous FPGA timer count; static OVERRIDE_U32_T rtcControlRegister1 = { 0, 0, 0, 0 }; ///< RTC control register 1. static OVERRIDE_U32_T rtcControlRegister3 = { 0, 0, 0, 0 }; ///< RTC control register 3. + + +// DEN-15979 testing +static U08 debugEventBuffer[ DEBUG_EVENT_FIXED_BUFFER_SIZE ]; ///< debug event buffer +static U16 writeSaveBuffer[ MIBSPI_MAX_BUFFER_LENGTH + 1 ]; ///< Buffer to store data written to RTC. + #ifdef _DG_ static BOOL syncDG2HDDateTimeFlag; ///< Flag indicating whether DG RTC should be sync'd to HD RTC. #endif @@ -224,6 +233,7 @@ // ********** Private function prototypes ********* static BOOL serviceRTC( U16* bufferTransmit, U16* bufferReceive, U16 bufferLength ); +static void logSPIFailure( void ); static BOOL isRTCFunctional( void ); static U08 convertBCD2Decimal( U08 bcd ); static U08 convertDecimal2BCD( U08 decimal ); @@ -247,7 +257,9 @@ static RTC_EXEC_STATE_T handleExecWriteToRAMState( void ); static RTC_EXEC_STATE_T handleExecReadFromRAMState( void ); static RTC_EXEC_STATE_T handleExecWriteState( void ); +static RTC_EXEC_STATE_T handleExecVerifyWriteState( void ); + /*********************************************************************//** * @brief * The initRTC initializes the RTC module. @@ -273,7 +285,7 @@ hasWriteToRTCRequested = FALSE; hasWriteToRAMRequested = FALSE; hasReadFromRAMRequested = FALSE; - isRTCServiceOnEntry = FALSE; + isRTCServiceOnEntry = TRUE; isTimestampBufferReady = FALSE; previousFPGATimerCount = 0; #ifdef _DG_ @@ -443,6 +455,10 @@ RTCExecState = handleExecWriteState(); break; + case RTC_EXEC_STATE_VERIFY_WRITE: + RTCExecState = handleExecVerifyWriteState(); + break; + case RTC_EXEC_STATE_READ: RTCExecState = handleExecReadState(); break; @@ -701,6 +717,9 @@ * @details Outputs: isRTCServiceOnEntry, RTCServiceState, numberOfFailedRTCTransfers, * previousTransferLength * @return TRUE if RTC operation was successful + * + * @NOTE If function returns false and RTCServiceOnEntry is RTC_SERVICE_COMPLETE + * indicates that the function failed. *************************************************************************/ static BOOL serviceRTC( U16* bufferTransmit, U16* bufferReceive, U16 bufferLength ) { @@ -728,41 +747,53 @@ { mibspiSetData( mibspiREG3, MIBSPI_GROUP_ZERO, bufferTransmit ); mibspiTransfer( mibspiREG3, MIBSPI_GROUP_ZERO ); - numberOfFailedRTCTransfers = 0; previousTransferLength = bufferLength; + isRTCServiceOnEntry = FALSE; RTCServiceState = RTC_WAIT_FOR_TRANSFER_AND_READ; } else { - RTCServiceState = RTC_SERVICE_COMPLETE; + isRTCServiceOnEntry = TRUE; + numberOfFailedRTCTransfers++; + logSPIFailure(); + + if ( numberOfFailedRTCTransfers >= MAX_ALLOWED_FAILED_RTC_TRANSFERS ) + { + numberOfFailedRTCTransfers = 0; + RTCServiceState = RTC_SERVICE_COMPLETE; + } } - isRTCServiceOnEntry = FALSE; break; case RTC_WAIT_FOR_TRANSFER_AND_READ: if ( mibspiIsTransferComplete( mibspiREG3, MIBSPI_GROUP_ZERO ) ) { mibspiGetData( mibspiREG3, MIBSPI_GROUP_ZERO, bufferReceive ); RTCServiceState = RTC_SERVICE_COMPLETE; + numberOfFailedRTCTransfers = 0; result = TRUE; } - else if ( numberOfFailedRTCTransfers >= MAX_ALLOWED_FAILED_RTC_TRANSFERS ) - { - RTCServiceState = RTC_SERVICE_COMPLETE; - } else { - // Transfer to RTC failed. This transfer - // should be done in 50ms + // Transfer to RTC failed. This transfer should be done in 50ms numberOfFailedRTCTransfers++; + logSPIFailure( ); + + if ( numberOfFailedRTCTransfers >= MAX_ALLOWED_FAILED_RTC_TRANSFERS ) + { + numberOfFailedRTCTransfers = 0; + RTCServiceState = RTC_SERVICE_COMPLETE; + } } - // Done with read (successful of failed) + // Done with read (successful or failed) // get ready for another call isRTCServiceOnEntry = TRUE; break; case RTC_SERVICE_COMPLETE: // Done with reading and transfer + numberOfFailedRTCTransfers = 0; + isRTCServiceOnEntry = TRUE; break; default: @@ -775,6 +806,21 @@ /*********************************************************************//** * @brief + * The logSPIFailur logs an occurrence of an SPI failure. + * @details Inputs: none + * @details Outputs: debugEventBuffer, RTCServiceState, + * numberOfFaileRTCTransfers + * @return None + *************************************************************************/ +static void logSPIFailure( void ) +{ + memset( debugEventBuffer, 0x00, sizeof(debugEventBuffer) ); + snprintf( ( char * ) debugEventBuffer, sizeof( debugEventBuffer ), "$RTC SPI: %d, %d", RTCServiceState, numberOfFailedRTCTransfers ); + broadcastData( DEBUG_EVENT_MSG_ID, COMM_BUFFER_OUT_CAN_BROADCAST, debugEventBuffer, sizeof( debugEventBuffer ) ); +} + +/*********************************************************************//** + * @brief * The isRTCFunctional checks whether the RTC is still functional by checking * the bits in the first 3 control registers. The function ignore the clear * flags. @@ -1185,12 +1231,15 @@ if ( RTCServiceState == RTC_SERVICE_COMPLETE && isStatusOk ) { + memcpy(writeSaveBuffer, txBuffer, ( RTC_GENERAL_BUFFER_LENGTH * 2 ) ); + releaseSemaphore( SEMAPHORE_RTC ); // Reset the counter to start with the new read timeCounter = 1; hasWriteToRTCRequested = FALSE; - result = RTC_EXEC_STATE_IDLE; + prepBufferForReadCommand(RTC_GENERAL_BUFFER_LENGTH); + result = RTC_EXEC_STATE_VERIFY_WRITE; } else if ( RTCServiceState == RTC_SERVICE_COMPLETE ) { @@ -1199,7 +1248,7 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif #ifdef _HD_ - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif result = RTC_EXEC_STATE_IDLE; hasWriteToRTCRequested = FALSE; @@ -1239,7 +1288,7 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif #ifdef _HD_ - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif result = RTC_EXEC_STATE_IDLE; } @@ -1318,7 +1367,7 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif #ifdef _HD_ - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif result = RTC_EXEC_STATE_IDLE; hasReadFromRAMRequested = FALSE; @@ -1353,12 +1402,62 @@ timeCounter = 1; data.epochTime = lastEpochTime; + broadcastData( EPOCH_DATA_MSG_ID, COMM_BUFFER_OUT_CAN_BROADCAST, (U08*)&data, sizeof( RTC_DATA_T ) ); + } + + releaseSemaphore( SEMAPHORE_RTC ); + + result = RTC_EXEC_STATE_IDLE; + } + else if ( RTC_SERVICE_COMPLETE == RTCServiceState ) + { + releaseSemaphore( SEMAPHORE_RTC ); #ifdef _DG_ - broadcastData( MSG_ID_DG_RTC_EPOCH_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( RTC_DATA_T ) ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif #ifdef _HD_ - broadcastData( MSG_ID_RTC_EPOCH_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( RTC_DATA_T ) ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif + result = RTC_EXEC_STATE_IDLE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleExecVerifyWriteState reads timestamp from RT to verify the + * RTC write was successful. + * @details Inputs: RTCServiceState, lastEpochTime, timeCounter, txBuffer, rxBuffer + * @details Outputs: lastEpochTime, timeCounter, alarm if any RTC operations error + * occurred + * @return next state + *************************************************************************/ +static RTC_EXEC_STATE_T handleExecVerifyWriteState( void ) +{ + RTC_EXEC_STATE_T result = RTC_EXEC_STATE_VERIFY_WRITE; + BOOL isStatusOk = serviceRTC( txBuffer, rxBuffer, RTC_GENERAL_BUFFER_LENGTH ); + + if ( ( RTC_SERVICE_COMPLETE == RTCServiceState ) && ( TRUE == isStatusOk ) ) + { + // Compare received buffer with what was transmitted + if ( 0 != memcmp( &writeSaveBuffer[1], &rxBuffer[1], ( RTC_GENERAL_BUFFER_LENGTH - 1 )* 2 ) ) + { + memset( debugEventBuffer, 0x00, sizeof( debugEventBuffer ) ); + snprintf( ( char * ) debugEventBuffer, sizeof( debugEventBuffer ), "$RTC Verify: %02X:%02X, %02X:%02X, %02X:%02X, %02X:%02X", + rxBuffer[0], writeSaveBuffer[0], rxBuffer[1], writeSaveBuffer[1], rxBuffer[2], writeSaveBuffer[2], rxBuffer[3], writeSaveBuffer[3] ); + broadcastData( DEBUG_EVENT_MSG_ID, COMM_BUFFER_OUT_CAN_BROADCAST, debugEventBuffer, sizeof( debugEventBuffer ) ); + + memset( debugEventBuffer, 0x00, sizeof( debugEventBuffer ) ); + snprintf( ( char * ) debugEventBuffer, sizeof( debugEventBuffer ), "$RTC Verify: %02X:%02X, %02X:%02X, %02X:%02X, %02X:%02X", + rxBuffer[4], writeSaveBuffer[4], rxBuffer[5], writeSaveBuffer[5], rxBuffer[6], writeSaveBuffer[6], rxBuffer[7], writeSaveBuffer[7] ); + broadcastData( DEBUG_EVENT_MSG_ID, COMM_BUFFER_OUT_CAN_BROADCAST, debugEventBuffer, sizeof( debugEventBuffer ) ); + + memset( debugEventBuffer, 0x00, sizeof( debugEventBuffer ) ); + snprintf( ( char * ) debugEventBuffer, sizeof( debugEventBuffer ), "$RTC Verify: %02X:%02X, %02X:%02X, %02X:%02X", + rxBuffer[8], writeSaveBuffer[8], rxBuffer[9], writeSaveBuffer[9], rxBuffer[10], writeSaveBuffer[10] ); + broadcastData( DEBUG_EVENT_MSG_ID, COMM_BUFFER_OUT_CAN_BROADCAST, debugEventBuffer, sizeof( debugEventBuffer ) ); + } releaseSemaphore( SEMAPHORE_RTC ); @@ -1371,9 +1470,6 @@ #ifdef _DG_ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) #endif -#ifdef _HD_ - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_RTC_RAM_OPS_FAILURE, result ) -#endif result = RTC_EXEC_STATE_IDLE; } @@ -1598,7 +1694,33 @@ return getU16OverrideValue(&rtcControlRegister3); } +/*********************************************************************//** + * @brief + * The isEpochValid check if epoch is valid + * @details Inputs: epoch time + * @details Outputs: None + * @return TRUE if epoch is valid, else false + *************************************************************************/ +BOOL isEpochValid( U32 epoch ) +{ + BOOL result = TRUE; + memset( debugEventBuffer, 0x00, sizeof( debugEventBuffer ) ); + snprintf( ( char * ) debugEventBuffer, sizeof( debugEventBuffer ), "$RTC epoch check" ); + broadcastData( DEBUG_EVENT_MSG_ID, COMM_BUFFER_OUT_CAN_BROADCAST, debugEventBuffer, sizeof( debugEventBuffer ) ); + + if ( epoch < MIN_EPOCH_DATE ) + { + result = FALSE; + + memset( debugEventBuffer, 0x00, sizeof( debugEventBuffer ) ); + snprintf( ( char * ) debugEventBuffer, sizeof( debugEventBuffer ), "$RTC epoch: %d", epoch ); + broadcastData( DEBUG_EVENT_MSG_ID, COMM_BUFFER_OUT_CAN_BROADCAST, debugEventBuffer, sizeof( debugEventBuffer ) ); + } + + return result; +} + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -1715,7 +1837,7 @@ * The testResetRTCCtlReg3Status function resets the override * of RTC control register 3. * @details Inputs: none - * @details Outputs: rtcControlRegister1 + * @details Outputs: rtcControlRegister3 * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetRTCCtlReg3Status( void ) @@ -1726,7 +1848,7 @@ { result = TRUE; rtcControlRegister3.override = OVERRIDE_RESET; - rtcControlRegister3.ovData = rtcControlRegister1.ovInitData; + rtcControlRegister3.ovData = rtcControlRegister3.ovInitData; } return result;