/************************************************************************** * * Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file SystemComm.c * * @author (last) Sean * @date (last) 30-Jul-2024 * * @author (original) Sean * @date (original) 30-Jul-2024 * ***************************************************************************/ #include #include // For memcpy() #include "can.h" #include "sci.h" #include "sys_dma.h" #include "Comm.h" #include "Interrupts.h" #include "OperationModes.h" #include "SystemCommTD.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup SystemCommTD * @{ */ // ********** private definitions ********** #define UI_COMM_TIMEOUT_IN_MS 7500 ///< Maximum time (in ms) that UI is allowed to wait before checking in with HD. #define UI_COMM_SERVICE_MODE_TIMEOUT_IN_MS (2 * SEC_PER_MIN * MS_PER_SECOND) ///< Maximum time (in ms) that UI is allowed to wait before checking in with HD when in service mode. #define DG_COMM_TIMEOUT_IN_MS 1000 ///< DG 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 // ********** private data ********** /// Array of out-going CAN buffers. const COMM_BUFFER_T CAN_OUT_BUFFERS[ NUM_OF_CAN_OUT_BUFFERS ] = { COMM_BUFFER_OUT_CAN_TD_ALARM, COMM_BUFFER_OUT_CAN_TD_2_DD, COMM_BUFFER_OUT_CAN_TD_2_UI, COMM_BUFFER_OUT_CAN_TD_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_DD_ALARM, COMM_BUFFER_IN_CAN_RO_ALARM, COMM_BUFFER_IN_CAN_UI_ALARM, COMM_BUFFER_IN_CAN_DD_2_TD, COMM_BUFFER_IN_CAN_UI_2_TD, COMM_BUFFER_IN_CAN_DD_BROADCAST, COMM_BUFFER_IN_CAN_RO_BROADCAST, COMM_BUFFER_IN_CAN_UI_BROADCAST, COMM_BUFFER_IN_CAN_PC, }; static volatile BOOL tdIsOnlyCANNode = TRUE; ///< Flag indicating whether HD is alone on CAN bus. static volatile BOOL ddIsCommunicating = FALSE; ///< Has DD sent a message since last check static U32 timeOfLastDGCheckIn = 0; ///< Last time DG 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 initSystemCommTD function initializes the SystemComm module. * @details Inputs: none * @details Outputs: SystemComm module initialized. * @return none *************************************************************************/ void initSystemCommTD( 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 checkInFromDG function checks in the DG with the HD - indicating that * the DG is communicating. * @details Inputs: none * @details Outputs: ddIsCommunicating * @return none *************************************************************************/ void checkInFromDG( void ) { ddIsCommunicating = TRUE; timeOfLastDGCheckIn = 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 HD - indicating that * the UI is communicating. * @details Inputs: none * @details Outputs: uiIsCommunicating * @return none *************************************************************************/ void checkInFromUI( void ) { if ( FALSE == uiDidCommunicate ) { // Start DG check-in timer when UI first communicates timeOfLastDGCheckIn = getMSTimerCount(); } uiIsCommunicating = TRUE; timeOfLastUICheckIn = getMSTimerCount(); uiDidCommunicate = TRUE; } /*********************************************************************//** * @brief * The isDDCommunicating function determines whether the DD is communicating * with the TD. * @details Inputs: ddIsCommunicating * @details Outputs: none * @return TRUE if DG has checked in since last call, FALSE if not *************************************************************************/ BOOL isDDCommunicating( void ) { return ddIsCommunicating; } /*********************************************************************//** * @brief * The isUICommunicating function determines whether the UI is communicating * with the HD. * @details Inputs: uiIsCommunicating * @details Outputs: none * @return TRUE if UI has checked in since last call, FALSE if not *************************************************************************/ BOOL isUICommunicating( void ) { BOOL result = uiIsCommunicating; uiIsCommunicating = FALSE; return result; } /*********************************************************************//** * @brief * The uiCommunicated function determines whether the UI has communicated. * @details Inputs: none * @details Outputs: none * @return TRUE if UI has communicated since power up, FALSE if not *************************************************************************/ BOOL uiCommunicated( void ) { #ifdef SIMULATE_UI uiDidCommunicate = TRUE; #endif return uiDidCommunicate; } /*********************************************************************//** * @brief * The isOnlyCANNode function determines whether the HD is the only node * currently on the CAN bus. * @details Inputs: tdIsOnlyCANNode * @details Outputs: none * @return TRUE if HD is only node on CAN bus, FALSE if not *************************************************************************/ BOOL isOnlyCANNode( void ) { return tdIsOnlyCANNode; } /*********************************************************************//** * @brief * The setOnlyCANNode function sets whether the HD is the only node * currently on the CAN bus. * @details Inputs: none * @details Outputs: tdIsOnlyCANNode * @return only TRUE if HD is only node on CAN bus, FALSE if not *************************************************************************/ void setOnlyCANNode( BOOL only ) { tdIsOnlyCANNode = only; } /*********************************************************************//** * @brief * The clearCANXmitBuffers function clears all CAN transmit buffers. * @details Inputs: CAN_OUT_BUFFERS[] * @details 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 ) ); } } /************************************************************************* ********************** TRANSMIT SUPPORT FUNCTIONS ************************ *************************************************************************/ /************************************************************************* ********************** RECEIVE SUPPORT FUNCTIONS ************************* *************************************************************************/ /*********************************************************************//** * @brief * The checkForCommTimeouts function checks for sub-system communication * timeout errors. * @details Inputs: timeOfLastDGCheckIn, timeOfLastUICheckIn * @details Outputs: possibly a comm t/o alarm * @return none *************************************************************************/ void checkForCommTimeouts( void ) { if ( TRUE == uiDidCommunicate ) { TD_OP_MODE_T opMode = getCurrentOperationMode(); U32 uiTO_MS = UI_COMM_TIMEOUT_IN_MS; // in service mode, allow up to 2 minutes for UI to check-in (for lock-down) if ( MODE_SERV == opMode ) { uiTO_MS = UI_COMM_SERVICE_MODE_TIMEOUT_IN_MS; } if ( TRUE == didTimeout( timeOfLastUICheckIn, uiTO_MS ) ) { #ifndef _RELEASE_ // if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_COMM_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif { activateAlarmNoData( ALARM_ID_TD_UI_COMM_TIMEOUT ); } } if ( TRUE == didTimeout( timeOfLastDGCheckIn, DG_COMM_TIMEOUT_IN_MS ) ) { #ifndef RUN_WITHOUT_DG // Only alarm on DG comm loss while in the treatment workflow if ( MODE_PRET == opMode || MODE_TREA == opMode || 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 getInBufferID function gets the buffer ID for a given buffer index. * @details Inputs: CAN_IN_BUFFERS[] * @details Outputs: none * @param idx incoming buffer index (e.g. 0 indicates first incoming buffer) * @return buffer id 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 { // TODO - s/w fault } return result; } /*********************************************************************//** * @brief * The getOutBufferID function gets the buffer ID for a given buffer index. * @details Inputs: CAN_OUT_BUFFERS[] * @details Outputs: none * @param idx outgoing buffer index (e.g. 0 indicates first outgoing buffer) * @return buffer id 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 { // TODO - s/w fault } return result; } /*********************************************************************//** * @brief * The processReceivedMessage function processes a given message. * @details Inputs: none * @details Outputs: message processed * @param message pointer to message to process * @return none *************************************************************************/ void processReceivedMessage( MESSAGE_T *message ) { // Handle any messages from other sub-systems handleIncomingMessage( message ); } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /**@}*/