#include // For memcpy() #include "can.h" #include "sci.h" #include "sys_dma.h" #include "Comm.h" #include "Interrupts.h" #include "Messaging.h" #include "OperationModes.h" #include "SystemCommRO.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup SystemCommRO * @{ */ // ********** private definitions ********** #define DD_COMM_TIMEOUT_IN_MS 1000 ///< DD has not checked in for this much time #define MAX_COMM_CRC_FAILURES 5 ///< Maximum number of CRC errors within window period before alarm #define MAX_COMM_CRC_FAILURE_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< CRC error window #define MAX_FPGA_CLOCK_SPEED_ERRORS 3 ///< maximum number of FPGA clock speed errors within window period before alarm #define MAX_FPGA_CLOCK_SPEED_ERROR_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< FPGA clock speed error window /// Array of out-going CAN buffers. const COMM_BUFFER_T CAN_OUT_BUFFERS[ NUM_OF_CAN_OUT_BUFFERS ] = { COMM_BUFFER_OUT_CAN_RO_ALARM, COMM_BUFFER_OUT_CAN_RO_2_DD, COMM_BUFFER_OUT_CAN_RO_BROADCAST, COMM_BUFFER_OUT_CAN_PC }; /// Array of in-coming CAN buffers. const COMM_BUFFER_T CAN_IN_BUFFERS[ NUM_OF_CAN_IN_BUFFERS ] = { COMM_BUFFER_IN_CAN_TD_ALARM, COMM_BUFFER_IN_CAN_DD_ALARM, COMM_BUFFER_IN_CAN_UI_ALARM, COMM_BUFFER_IN_CAN_DD_2_RO, COMM_BUFFER_IN_CAN_TD_BROADCAST, COMM_BUFFER_IN_CAN_DD_BROADCAST, COMM_BUFFER_IN_CAN_UI_BROADCAST, COMM_BUFFER_IN_CAN_PC, }; // ********** private data ********** static volatile BOOL roIsOnlyCANNode = TRUE; ///< Flag indicating whether RO is alone on CAN bus. static volatile BOOL ddIsCommunicating = FALSE; ///< Has DD sent a message since last check static U32 timeOfLastDDCheckIn = 0; ///< Last time DD checked in static volatile BOOL uiIsCommunicating = FALSE; ///< Has UI sent a message since last check static U32 timeOfLastUICheckIn = 0; ///< Last time UI checked in static volatile BOOL uiDidCommunicate = FALSE; ///< Has UI every sent a message // ********** private function prototypes ********** /*********************************************************************//** * @brief * The initSystemCommRO function initializes the system communication unit * for the RO firmware. * @details \b Inputs: none * @details \b Outputs: SystemComm unit initialized. * @return none *************************************************************************/ void initSystemCommRO( void ) { // Initialize common system comm unit initSystemComm(); // Initialize bad message CRC time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC, MAX_COMM_CRC_FAILURES, MAX_COMM_CRC_FAILURE_WINDOW_MS ); // Initialize FPGA clock speed error time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CLOCK_SPEED_ERROR, MAX_FPGA_CLOCK_SPEED_ERRORS, MAX_FPGA_CLOCK_SPEED_ERROR_WINDOW_MS); } /*********************************************************************//** * @brief * The checkInFromDD function checks in the DD with the TD - indicating that * the DD is communicating. * @details \b Inputs: none * @details \b Outputs: ddIsCommunicating, timeOfLastDDCheckIn * @return none *************************************************************************/ void checkInFromDD( void ) { ddIsCommunicating = TRUE; timeOfLastDDCheckIn = getMSTimerCount(); if ( TRUE == isAlarmActive( ALARM_ID_TD_DD_COMM_TIMEOUT ) ) { clearAlarmCondition( ALARM_ID_TD_DD_COMM_TIMEOUT ); } } /*********************************************************************//** * @brief * The checkInFromUI function checks in the UI with the TD - indicating that * the UI is communicating. * @details \b Inputs: none * @details \b Outputs: uiIsCommunicating, timeOfLastUICheckIn, uiDidCommunicate * @return none *************************************************************************/ void checkInFromUI( void ) { if ( FALSE == uiDidCommunicate ) { // Start DD check-in timer when UI first communicates timeOfLastDDCheckIn = getMSTimerCount(); } uiIsCommunicating = TRUE; timeOfLastUICheckIn = getMSTimerCount(); uiDidCommunicate = TRUE; } /*********************************************************************//** * @brief * The isDDCommunicating function determines whether the DD is communicating * with the TD. * @details \b Inputs: ddIsCommunicating * @details \b Outputs: none * @return TRUE if DD is communicating, FALSE if not *************************************************************************/ BOOL isDDCommunicating( void ) { return ddIsCommunicating; } /*********************************************************************//** * @brief * The isOnlyCANNode function determines whether the TD is the only node * currently on the CAN bus. * @details \b Inputs: tdIsOnlyCANNode * @details \b Outputs: none * @return TRUE if TD is only node on CAN bus, FALSE if not *************************************************************************/ BOOL isOnlyCANNode( void ) { return roIsOnlyCANNode; } /*********************************************************************//** * @brief * The setOnlyCANNode function sets whether the TD is the only node * currently on the CAN bus. * @details \b Inputs: none * @details \b Outputs: tdIsOnlyCANNode * @param only Flag indicating whether the TD is the only node on the CAN bus. * @return none *************************************************************************/ void setOnlyCANNode( BOOL only ) { roIsOnlyCANNode = only; } /*********************************************************************//** * @brief * The clearCANXmitBuffers function clears all CAN transmit buffers. * @details \b Inputs: CAN_OUT_BUFFERS[] * @details \b Outputs: CAN transmit buffers cleared. * @return none *************************************************************************/ void clearCANXmitBuffers( void ) { U32 i; for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) { clearBuffer( getOutBufferID( i ) ); } } /*********************************************************************//** * @brief * The checkForCommTimeouts function checks for sub-system communication * timeout errors. * @details \b Alarm: ALARM_ID_TD_UI_COMM_TIMEOUT if UI no longer communicating. * @details \b Alarm: ALARM_ID_TD_DD_COMM_TIMEOUT if DD no longer communicating. * @details \b Inputs: timeOfLastDDCheckIn, timeOfLastUICheckIn * @details \b Outputs: none * @return none *************************************************************************/ void checkForCommTimeouts( void ) { if ( TRUE == uiDidCommunicate ) { RO_OP_MODE_T opMode = getCurrentOperationMode(); if ( TRUE == didTimeout( timeOfLastDDCheckIn, DD_COMM_TIMEOUT_IN_MS ) ) { #ifndef RUN_WITHOUT_DD // Only alarm on DG comm loss while in the treatment workflow /*if ( RO_MODE_PRET == opMode || RO_MODE_TREA == opMode || RO_MODE_POST == opMode ) { activateAlarmNoData( ALARM_ID_TD_DD_COMM_TIMEOUT ); // we don't want to keep thinking DG is in a useful mode - set it to fault mode until DG is able to report its' true mode status // setDGOpMode( DG_MODE_FAUL, 0 ); } else // Otherwise clear the alarm { clearAlarmCondition( ALARM_ID_TD_DD_COMM_TIMEOUT ); } ddIsCommunicating = FALSE; */ #endif } } } /*********************************************************************//** * @brief * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs * within a set period of time. * @note Assumed function is being called when a new bad CRC is detected. * @details \b Alarm: ALARM_ID_TD_COMM_TOO_MANY_BAD_CRCS if too many (5) bad * CRCs detected in the last 10 minutes. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ void checkTooManyBadMsgCRCs( void ) { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_FP_COMM_TOO_MANY_BAD_CRCS, (U32)ALARM_SOURCE_RO ); } } /*********************************************************************//** * @brief * The getInBufferID function gets the incoming communication buffer ID for * a given buffer index. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given buffer index is invalid. * @details \b Inputs: CAN_IN_BUFFERS[] * @details \b Outputs: none * @param idx incoming buffer index (e.g. 0 indicates first incoming buffer) * @return ID of buffer associated with given incoming buffer index *************************************************************************/ COMM_BUFFER_T getInBufferID( U32 idx ) { COMM_BUFFER_T result = COMM_BUFFER_NOT_USED; // validate given index if ( idx < NUM_OF_CAN_IN_BUFFERS ) { result = CAN_IN_BUFFERS[ idx ]; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, SW_FAULT_ID_SYSTEM_COMM_INVALID_BUFFER_INDEX1, idx ) } return result; } /*********************************************************************//** * @brief * The getOutBufferID function gets the outgoing communication buffer ID for * a given buffer index. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given buffer index is invalid. * @details \b Inputs: CAN_OUT_BUFFERS[] * @details \b Outputs: none * @param idx outgoing buffer index (e.g. 0 indicates first outgoing buffer) * @return ID of buffer associated with given outgoing buffer index *************************************************************************/ COMM_BUFFER_T getOutBufferID( U32 idx ) { COMM_BUFFER_T result = COMM_BUFFER_NOT_USED; // validate given index if ( idx < NUM_OF_CAN_OUT_BUFFERS ) { result = CAN_OUT_BUFFERS[ idx ]; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_SYSTEM_COMM_INVALID_BUFFER_INDEX2, idx ) } return result; } /*********************************************************************//** * @brief * The processReceivedMessage function processes a given message. * @details \b Inputs: none * @details \b Outputs: message processed * @param message Pointer to the message to process. * @return none *************************************************************************/ void processReceivedMessage( MESSAGE_T *message ) { // Handle any messages from other sub-systems handleIncomingMessage( message ); } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /**@}*/