/************************************************************************** * * Copyright (c) 2024-2025 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 SystemCommDD.c * * @author (last) Michael Garthwaite * @date (last) 08-Sep-2025 * * @author (original) Vinayakam Mani * @date (original) 07-Aug-2024 * ***************************************************************************/ #include // for memcpy() #include "can.h" #include "sci.h" #include "sys_dma.h" #include "Comm.h" #include "Interrupts.h" #include "OperationModes.h" #include "Messaging.h" #include "SystemCommDD.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup SystemCommDD * @{ */ // ********** private definitions ********** #define TD_COMM_TIMEOUT_IN_MS 2000 ///< TD has not sent any broadcast messages for this much time #define FP_COMM_TIMEOUT_IN_MS 2000 ///< FP has not sent any broadcast messages 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_DD_ALARM, COMM_BUFFER_OUT_CAN_FP_ALARM, COMM_BUFFER_OUT_CAN_DD_2_TD, COMM_BUFFER_OUT_CAN_DD_BROADCAST, COMM_BUFFER_OUT_CAN_FP_BROADCAST, COMM_BUFFER_OUT_DD_CAN_PC, COMM_BUFFER_OUT_FP_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_UI_ALARM, COMM_BUFFER_IN_CAN_TD_2_DD, COMM_BUFFER_IN_CAN_TD_BROADCAST, COMM_BUFFER_IN_CAN_UI_BROADCAST, COMM_BUFFER_IN_DD_CAN_PC, COMM_BUFFER_IN_FP_CAN_PC, }; static volatile BOOL ddIsOnlyCANNode = TRUE; ///< flag indicating whether DG is alone on CAN bus. static OVERRIDE_U32_T tdCommunicationStatus = {0, 0, 0, 0}; ///< has TD sent a message since last check static volatile U32 timeOfLastTDCheckIn = 0; ///< last time we received an TD broadcast static OVERRIDE_U32_T fpCommunicationStatus = {0, 0, 0, 0}; ///< has FP sent a message since last check static volatile U32 timeOfLastFPCheckIn = 0; ///< last time we received an FP broadcast // ********** private function prototypes ********** /*********************************************************************//** * @brief * The initSystemCommDD function initializes the DD SystemComm unit. * @details \b Inputs: none * @details \b Outputs: SystemComm unit initialized. * @return none *************************************************************************/ void initSystemCommDD( 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 checkInFromTD function checks in the TD with the DD - indicating that * the TD is communicating. * @details \b Inputs: none * @details \b Outputs: tdCommunicationStatus, timeOfLastTDCheckIn * @return none *************************************************************************/ void checkInFromTD( void ) { tdCommunicationStatus.data = TRUE; timeOfLastTDCheckIn = getMSTimerCount(); // if ( TRUE == isAlarmActive( ALARM_ID_DD_TD_COMM_TIMEOUT ) ) // { // clearAlarmCondition( ALARM_ID_DD_TD_COMM_TIMEOUT ); // } } /*********************************************************************//** * @brief * The checkInFromFP function checks in the FP with the DD - indicating that * the FP is communicating. * @details \b Inputs: none * @details \b Outputs: fpCommunicationStatus, timeOfLastFPCheckIn * @return none *************************************************************************/ void checkInFromFP( void ) { fpCommunicationStatus.data = TRUE; timeOfLastFPCheckIn = getMSTimerCount(); // if ( TRUE == isAlarmActive( ALARM_ID_DD_FP_COMM_TIMEOUT ) ) // { // clearAlarmCondition( ALARM_ID_DD_FP_COMM_TIMEOUT ); // } } /*********************************************************************//** * @brief * The isTDCommunicating function determines whether the TD is communicating * with the DD. * @details \b Inputs: tdCommunicationStatus * @details \b Outputs: none * @return TRUE if TD has broadcast since last call, FALSE if not *************************************************************************/ BOOL isTDCommunicating( void ) { return getU32OverrideValue( &tdCommunicationStatus ); } /*********************************************************************//** * @brief * The isFPCommunicating function determines whether the FP is communicating * with the DD. * @details \b Inputs: fpCommunicationStatus * @details \b Outputs: none * @return TRUE if FP has broadcast since last call, FALSE if not *************************************************************************/ BOOL isFPCommunicating( void ) { return getU32OverrideValue( &fpCommunicationStatus ); } /*********************************************************************//** * @brief * The isOnlyCANNode function determines whether the DD is the only node * currently on the CAN bus. * @details \b Inputs: ddIsOnlyCANNode * @details \b Outputs: none * @return TRUE if DD is only node on CAN bus, FALSE if not *************************************************************************/ BOOL isOnlyCANNode( void ) { return ddIsOnlyCANNode; } /*********************************************************************//** * @brief * The setOnlyCANNode function sets whether the DD is the only node * currently on the CAN bus. * @details \b Inputs: none * @details \b Outputs: ddIsOnlyCANNode * @return only TRUE if TD is only node on CAN bus, FALSE if not *************************************************************************/ void setOnlyCANNode( BOOL only ) { ddIsOnlyCANNode = 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 Inputs: timeOfLastTDCheckIn, timeOfLastFPCheckIn * @details \b Outputs: possibly a comm t/o alarm * @return none *************************************************************************/ void checkForCommTimeouts( void ) { if ( TRUE == didTimeout( timeOfLastTDCheckIn, TD_COMM_TIMEOUT_IN_MS ) ) { tdCommunicationStatus.data = FALSE; setTDOperationMode( 0, 0 ); // If TD off or not connected, consider TD mode is fault. //stopHeater( DG_TRIMMER_HEATER ); // If TD off or not connected, ensure trimmer heater is off. } if ( TRUE == didTimeout( timeOfLastFPCheckIn, FP_COMM_TIMEOUT_IN_MS ) ) { fpCommunicationStatus.data = FALSE; //setFPOperationMode( 0, 0 ); // If FP off or not connected, consider FP mode is fault. } } /*********************************************************************//** * @brief * The getInBufferID function gets the buffer ID for a given buffer index. * @details \b Inputs: CAN_IN_BUFFERS[] * @details \b Outputs: none * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when invalid CAN Input * buffer is seen. * @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 { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CAN_IN_INVALID_BUFFER ) } return result; } /*********************************************************************//** * @brief * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs * within a set period of time. Assumed function is being called when a new * bad CRC is detected so a new bad CRC will be added to the list. * @details \b Inputs: badCRCTimeStamps[], badCRCListIdx, badCRCListCount * @details \b Outputs: possibly a "too many bad CRCs" alarm * @details \b Alarm: ALARM_ID_DD_COMM_TOO_MANY_BAD_CRCS when too many bad * message CRC seen. * @return none *************************************************************************/ void checkTooManyBadMsgCRCs( void ) { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_COMM_TOO_MANY_BAD_CRCS, 2 ); // 2 for DD } } /*********************************************************************//** * @brief * The getOutBufferID function gets the buffer ID for a given buffer index. * @details \b Inputs: CAN_OUT_BUFFERS[] * @details \b Outputs: none * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when invalid CAN Output * buffer is seen. * @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 { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CAN_OUT_INVALID_BUFFER ) } return result; } /*********************************************************************//** * @brief * The processReceivedMessage function processes a given message. * @details \b Inputs: none * @details \b 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 *************************************************************************/ /*********************************************************************//** * @brief * The testTDCommunicationStatusOverride function sets the override * of the TD communication status. * @details \b Inputs: none * @details \b Outputs: tdCommunicationStatus * @param message Override message from Dialin which includes the flag * value to override for the Td communication status. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testTDCommunicationStatusOverride( MESSAGE_T *message ) { BOOL result = u32Override( message, &tdCommunicationStatus, FALSE, TRUE ); return result; } /*********************************************************************//** * @brief * The testFPCommunicationStatusOverride function sets the override * of the FP communication status. * @details \b Inputs: none * @details \b Outputs: fpCommunicationStatus * @param message Override message from Dialin which includes the flag * value to override for the FP communication status. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testFPCommunicationStatusOverride( MESSAGE_T *message ) { BOOL result = u32Override( message, &fpCommunicationStatus, FALSE, TRUE ); return result; } /**@}*/