/************************************************************************** * * 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 DDInterface.c * * @author (last) Sean * @date (last) 30-Jul-2024 * * @author (original) Sean * @date (original) 30-Jul-2024 * ***************************************************************************/ #include // To check for NaN #include "DDDefs.h" #include "DDInterface.h" #include "Messaging.h" #include "ModeInitPOST.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SystemCommTD.h" #include "TaskGeneral.h" #include "Timers.h" /** * @addtogroup DDInterface * @{ */ // ********** private definitions ********** #define DD_DATA_FRESHNESS_TIMEOUT_MS ( 3 * MS_PER_SECOND ) ///< DD data freshness timeout (in ms). // ********** private data ********** // DG status static DD_OP_MODE_T ddCurrentOpMode; ///< Current DD operation mode. static U32 ddSubMode; ///< Current state (sub-mode) of current DG operation mode. static BOOL ddStartCommandSent; ///< Flag indicates command to start DG has been sent. static BOOL ddStarted; ///< Flag indicates whether we have commanded the DD to start or stop. static BOOL ddOpModeDataFreshFlag = FALSE; ///< Flag to signal the handleDDOpMode() to process fresh dd op mode data // DG command response static DD_CMD_RESPONSE_T ddCmdResp[ NUM_OF_DD_COMMANDS ]; ///< Keep the latest DD command response for each command. // ********** private function prototypes ********** static void checkDDRestart( void ); static void checkDDDataFreshness( ALARM_ID_T alarmID, BOOL *ddFreshDataFlag ); /*********************************************************************//** * @brief * The initDDInterface function initializes the DDInterface module. * @details Inputs: none * @details Outputs: DDInterface module initialized. * @return none *************************************************************************/ void initDDInterface( void ) { U32 i; // NOTE: the active reservoir is set to reservoir 1 since DG will send active reservoir 1 as active on power up ddStarted = FALSE; ddCurrentOpMode = DD_MODE_INIT; ddSubMode = 0; ddStartCommandSent = FALSE; // initialize DD command response for ( i = 0; i < NUM_OF_DD_COMMANDS; i++ ) { ddCmdResp[ i ].commandID = DD_CMD_NONE; ddCmdResp[ i ].rejected = TRUE; ddCmdResp[ i ].rejectCode = DD_CMD_REQUEST_REJECT_REASON_NONE; } // initPersistentAlarm( ALARM_ID_TD_DD_NEW_OPERATION_MODE_MESSAGE_NOT_RECEIVE, DD_DATA_FRESHNESS_TIMEOUT_MS, DD_DATA_FRESHNESS_TIMEOUT_MS ); } /**********************************************************************//** * @brief * The checkDGDataFreshness function checks the condition * for triggering an alarm if the DG fresh data is not received for 2 seconds. * @details Inputs: none * @details Outputs: an alarm is triggered or an alarm condition is cleared * @param alarm ID of alarm to check * @param flag to signal the fresh data processing * @return None *************************************************************************/ static void checkDGDataFreshness( ALARM_ID_T alarmID, BOOL *dgFreshDataFlag ) { if ( TRUE == *dgFreshDataFlag ) { *dgFreshDataFlag = FALSE; checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); } else { // Alarm if not receiving DG fresh data message in timely manner if ( TRUE == isDDCommunicating() ) { checkPersistentAlarm( alarmID, TRUE, 0.0, 0.0 ); } else { checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); } } } /*********************************************************************//** * @brief * The execDGInterfaceMonitor function executes the DG Interface monitoring * function. Ensures DG is sending fresh data in a timely manner. * @details Inputs: dgLoadCellDataFreshFlag, dgDialysateTemperatureDataFreshFlag, * dgReservoirsDataFreshFlag, dgOpModeDataFreshFlag * @details Outputs: dgLoadCellDataFreshFlag, dgDialysateTemperatureDataFreshFlag, * dgReservoirsDataFreshFlag, dgOpModeDataFreshFlag * @return none *************************************************************************/ void execDDInterfaceMonitor( void ) { // if ( getCPLDACPowerLossDetected() != TRUE ) { // Trigger alarm if not receiving new dialysate temperature data message in timely manner // checkDGDataFreshness( ALARM_ID_HD_NEW_DIALYSATE_TEMP_DATA_MESSAGE_NOT_RECEIVE, &dgDialysateTemperatureDataFreshFlag ); // Trigger alarm if not receiving new DG op mode message in timely manner // checkDGDataFreshness( ALARM_ID_HD_DG_NEW_OPERATION_MODE_MESSAGE_NOT_RECEIVE, &dgOpModeDataFreshFlag ); // if ( TRUE == isAlarmActive( ALARM_ID_HD_DG_NEW_OPERATION_MODE_MESSAGE_NOT_RECEIVE ) ) // { // // 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 ); // } // Check to see if DD has restarted checkDDRestart(); } } /*********************************************************************//** * @brief * The getDDOpMode function gets the current DD operating mode. * @details Inputs: ddCurrentOpMode * @details Outputs: none * @return Current DD operating mode. *************************************************************************/ DD_OP_MODE_T getDDOpMode( void ) { return ddCurrentOpMode; } /*********************************************************************//** * @brief * The getDGSubMode function gets the current DG operating sub-mode. * @details Inputs: dgSubMode * @details Outputs: none * @return Current DG operating sub-mode. *************************************************************************/ U32 getDDSubMode( void ) { return ddSubMode; } /*********************************************************************//** * @brief * The setDGOpMode function sets the latest DG operating mode reported by * the DG. * @details Inputs: none * @details Outputs: dgCurrentOpMode, dgSubMode, dgOpModeDataFreshFlag * @param opMode operating mode reported by DG * @param subMode sub-mode (current state) of operating mode reported by DG * @return none *************************************************************************/ void setDDOpMode( U32 opMode, U32 subMode ) { if ( opMode < NUM_OF_DD_MODES ) { // reset POST passed flag if DG restarted or faulted or went to service mode if ( ( opMode < DD_MODE_STAN ) && ( ddCurrentOpMode >= DD_MODE_STAN ) ) { signalDDPOSTFinalResult( FALSE ); } // update DG op mode and sub-mode ddCurrentOpMode = (DD_OP_MODE_T)opMode; ddSubMode = subMode; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DD_OPERATING_MODE, opMode ); } ddOpModeDataFreshFlag = TRUE; } /*********************************************************************//** * @brief * The handleDDCommandResponse function processes the latest DD command response. * @details Inputs: none * @details Outputs: process command response from DD * @param ddCmdRespPtr pointer to DD command response data record * @return none *************************************************************************/ void handleDDCommandResponse( DD_CMD_RESPONSE_T *ddCmdRespPtr ) { if ( ddCmdRespPtr->commandID < NUM_OF_DD_COMMANDS ) { if ( DD_CMD_NONE != ddCmdRespPtr->commandID ) { memcpy( &ddCmdResp[ ddCmdRespPtr->commandID ], ddCmdRespPtr, sizeof( DD_CMD_RESPONSE_T ) ); } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_DD_INVALID_COMMAND_RESPONSE_ID, ddCmdRespPtr->commandID ); } if ( TRUE == ddCmdRespPtr->rejected ) { switch ( ddCmdRespPtr->rejectCode ) { case DD_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER: // SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DG_COMMAND_INVALID_PARAMETER_FAULT, ddCmdRespPtr->commandID ); break; case DD_CMD_REQUEST_REJECT_REASON_NONE: case DD_CMD_REQUEST_REJECT_REASON_INVALID_MODE: default: // Our state machines will detect and handle DG mode out of sync // TODO Consider a generic handler for all state machine break; } } } /*********************************************************************//** * @brief * The getDDCommandResponse function gets the latest command response from DD. * @details Inputs: ddCmdResp * @details Outputs: none * @param commandID id of specific interested command response * @param cmdRespPtr pointer to data record to copy DD command response to * @return TRUE if a specific command response has been received, otherwise FALSE *************************************************************************/ BOOL getDDCommandResponse( U32 commandID, DD_CMD_RESPONSE_T *cmdRespPtr ) { BOOL hasCommandResp = FALSE; if ( commandID == ddCmdResp[ commandID ].commandID ) { hasCommandResp = TRUE; memcpy( cmdRespPtr, &ddCmdResp[ commandID ], sizeof( DD_CMD_RESPONSE_T ) ); } return hasCommandResp; } /*********************************************************************//** * @brief * The checkDDRestart function checks to see if DD has restarted after started * by TD and triggers appropriate alarm. * @details Inputs: ddStartCommandSent, ddStarted, ddCurrentOpMode * @details Outputs: ddStartCommandSent, ddStarted, triggers a fault alarm if DD restarted * @return none *************************************************************************/ static void checkDDRestart( void ) { if ( ( ddStartCommandSent == TRUE ) && ( DD_MODE_GEND == ddCurrentOpMode ) ) { ddStartCommandSent = FALSE; ddStarted = TRUE; } // if ( TRUE == ddStarted ) // { // if ( ( DG_MODE_FAUL != ddCurrentOpMode ) && ( DG_MODE_GEND != ddCurrentOpMode ) && // ( DG_MODE_FILL != ddCurrentOpMode ) && ( DG_MODE_DRAI != ddCurrentOpMode ) ) // { // activateAlarmNoData( ALARM_ID_HD_DG_RESTARTED_FAULT ); // ddStarted = FALSE; // do not want to re-trigger alarm after alarm is cleared // } // } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /**@}*/