/************************************************************************** * * 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 AlarmMgmtDD.c * * @author (last) Vinayakam Mani * @date (last) 05-Aug-2024 * * @author (original) Vinayakam Mani * @date (original) 05-Aug-2024 * ***************************************************************************/ #define __ALARM_MGMT_DD_C__ #include "AlarmMgmtDD.h" #include "Messaging.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SafetyShutdown.h" #include "SystemCommDD.h" #include "TaskGeneral.h" #include "TDDefs.h" #include "Timers.h" /** * @addtogroup AlarmManagement * @{ */ // ********** private definitions ********** #define ALARM_INFO_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) /// Interval (ms/task time) at which the alarm information is published on the CAN bus. #define DATA_PUBLISH_COUNTER_START_COUNT 12 ///< Data publish counter start count. #define SUPERVISOR_ALARM_KEY 0xD2C3B4A5 ///< 32-bit key required for clear all alarms request. const ALARM_DATA_T BLANK_ALARM_DATA = { ALARM_DATA_TYPE_NONE, 0 }; ///< A blank alarm data record for alarms that do not include alarm data when triggered. // ********** private data ********** static U32 alarmInfoPublicationTimerCounter; ///< Used to schedule alarm information publication to CAN bus. static BOOL isAFaultAlarmActive; ///< Boolean flag to indicate whether a DD fault alarm is active. /// Interval (in task intervals) at which to publish alarm information to CAN bus. static OVERRIDE_U32_T alarmInfoPublishInterval = { ALARM_INFO_PUB_INTERVAL, ALARM_INFO_PUB_INTERVAL, ALARM_INFO_PUB_INTERVAL, 0 }; // ********** private function prototypes ********** static void activateAlarmDD( ALARM_ID_T alarm ); static void publishAlarmInfo( void ); static BOOL isTransitionToFaultRequired( void ); /*********************************************************************//** * @brief * The initAlarmMgmtDD function initializes the AlarmMgmt unit. * @details \b Inputs: none * @details \b Outputs: unit variables initialized. * @return none *************************************************************************/ void initAlarmMgmtDD( void ) { alarmInfoPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; isAFaultAlarmActive = FALSE; // Initialize common alarm mgmt unit initAlarmMgmt(); } /*********************************************************************//** * @brief * The execAlarmMgmt function executes periodic alarm management operations. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ void execAlarmMgmt( void ) { // Publish alarm information at interval publishAlarmInfo(); } /*********************************************************************//** * @brief * The activateAlarmDD function activates a given alarm. if the alarm is * DD fault, transition fault operation mode immediately. * @details \b Inputs: none * @details \b Outputs: alarmIsActive[], isAFaultAlarmActive * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when invalid alarm asked to activate. * @param alarm ID of alarm to activate * @return none *************************************************************************/ static void activateAlarmDD( ALARM_ID_T alarm ) { // verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { ALARM_T props = getAlarmProperties( alarm ); // no need to do anything if alarm is already active if ( FALSE == isAlarmActive( alarm ) ) { // activate alarm activateAlarm( alarm ); if ( TRUE == props.alarmIsDDFault ) { // There is a DD fault alarm. isAFaultAlarmActive = TRUE; if ( TRUE == isTransitionToFaultRequired() ) { // If alarm is a DD fault and the alarm manager can transition to fault immediately, go to fault mode //TODO : Testing - remove the comment later // requestNewOperationMode( DD_MODE_FAUL ); } } } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE, alarm ) } } /*********************************************************************//** * @brief * The activateAlarmNoData function activates a given alarm. An alarm message * is broadcast to the rest of the system.it doesn't contain any parameters * associated to alarm. * @details \b Inputs: none * @details \b Outputs: alarm triggered message sent, alarm activated * @param alarm ID of alarm to activate * @return none *************************************************************************/ void activateAlarmNoData( ALARM_ID_T alarm ) { activateAlarm2Data( alarm, BLANK_ALARM_DATA, BLANK_ALARM_DATA, FALSE ); } /*********************************************************************//** * @brief * The activateAlarm1Data function activates a given alarm. An alarm message * is broadcast to the rest of the system. This function will include given * data in the broadcast message for logging. * @details \b Inputs: none * @details \b Outputs: alarm triggered message sent, alarm activated * @param alarm ID of alarm to activate * @param alarmData supporting data to include in alarm message * @return none *************************************************************************/ void activateAlarm1Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData ) { activateAlarm2Data( alarm, alarmData, BLANK_ALARM_DATA, FALSE ); } /*********************************************************************//** * @brief * The activateAlarm2Data function activates a given alarm. An alarm message * is broadcast to the rest of the system. This function will include * two given data in the broadcast message for logging. * @details \b Inputs: none * @details \b Outputs: alarm triggered message sent, alarm activated * @details \b Message \b sent: MSG_ID_ALARM_TRIGGERED to update Alarm * trigerred details along with the supporting data. * @param alarm ID of alarm to activate * @param alarmData1 supporting data to include in alarm message * @param alarmData2 supporting data to include in alarm message * @param outside flag indicates whether alarm is originating from outside HD f/w * @return none *************************************************************************/ void activateAlarm2Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData1, ALARM_DATA_T alarmData2, BOOL outside ) { TD_MODE_SUB_MODE_T tdModes; ALARM_T props = getAlarmProperties( alarm ); getTDOperationMode( &tdModes ); // prevent alarm trigger if property blocks in current mode/state if ( ( ( props.alarmBlockRinseback != TRUE ) || ( tdModes.tdMode != MODE_TREA ) || ( tdModes.tdSubMode != TREATMENT_RINSEBACK_STATE ) ) && ( ( props.alarmBlockEndTx != TRUE ) || ( tdModes.tdMode != MODE_POST ) ) ) { // broadcast alarm and data if alarm not already active if ( ( FALSE == isAlarmActive( alarm ) ) && ( TRUE == isTDCommunicating() ) ) { broadcastAlarmTriggered( alarm, alarmData1, alarmData2 ); } activateAlarmDD( alarm ); } } /*********************************************************************//** * @brief * The clearAlarmDD function clears a given alarm if it is recoverable. * An alarm message is broadcast to the rest of the system. * @details \b Inputs: none * @details \b Outputs: AlarmStatusTable[] * @details \b Message \Sent: MSG_ID_ALARM_CLEARED to update clearance of * the alarm. * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when invalid alarm needs * to be cleared. * @param alarm ID of alarm to clear * @return none *************************************************************************/ void clearAlarmDD( ALARM_ID_T alarm ) { ALARM_T props = getAlarmProperties( alarm ); // verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { // clear alarm and broadcast alarm clear if not already cleared (and not a DD fault which should not be cleared) if ( ( TRUE == isAlarmActive( alarm ) ) && ( props.alarmIsDDFault != TRUE ) ) { if ( TRUE == isTDCommunicating() ) { broadcastAlarmCleared( alarm ); } setAlarmActive( alarm, FALSE ); clearAlarmConditionDD( alarm ); } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_CLEAR, alarm ) } } /*********************************************************************//** * @brief * The clearAlarmConditionDD function clears a given alarm's condition detected * flag. Also an alarm message is broadcast to the rest of the system. * @details \b Inputs: none * @details \b Outputs: alarmIsDetected[] * @details \b Message \b Sent: MSG_ID_ALARM_CONDITION_CLEARED to update * alarm condition clearance. * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when invalid alarm conditioned * needs to be cleared * @param alarm ID of alarm to clear condition for * @return none *************************************************************************/ void clearAlarmConditionDD( ALARM_ID_T alarm ) { // verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { // clear alarm and broadcast alarm clear if not already cleared if ( TRUE == isAlarmConditionDetected( alarm ) ) { if ( TRUE == isTDCommunicating() ) { broadcastAlarmConditionCleared( alarm ); } setAlarmConditionDetected( alarm, FALSE ); } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_ID, alarm ) } } /*********************************************************************//** * @brief * The isDDFaultAlarmActive function determines whether a fault alarm is currently * active. * @details \b Inputs: alarmStatus * @details \b Outputs: none * @return TRUE if any alarm is active, FALSE if not *************************************************************************/ BOOL isDDFaultAlarmActive( void ) { return isAFaultAlarmActive; } /*********************************************************************//** * @brief * The publishAlarmInfo function publishes alarm information at the set * interval. * @details \b Inputs: * @details \b Outputs: alarm information are published to CAN bus. * @details \b Message \b Sent: MSG_ID_DD_ALARM_INFO_DATA to puslish saftey * shutdown activation details. * @return none *************************************************************************/ static void publishAlarmInfo( void ) { // Publish voltages monitor data on interval if ( ++alarmInfoPublicationTimerCounter >= getU32OverrideValue( &alarmInfoPublishInterval ) ) { SAFETY_SHUTDOWN_ACTIVATION_DATA_T data; data.safetyShutdownStatus = (U32)isSafetyShutdownActivated(); broadcastData( MSG_ID_DD_ALARM_INFO_DATA, COMM_BUFFER_OUT_CAN_DD_ALARM, (U08*)&data, sizeof( SAFETY_SHUTDOWN_ACTIVATION_DATA_T ) ); alarmInfoPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The handleResendActiveAlarmsRequest function processes the request to re-send * all active alarms. * @details \b Inputs: alarmIsActive[] * @details \b Outputs: re-send active alarms to UI * @details \b Message \b Sent: MSG_ID_ALARM_TRIGGERED to resend all active alarms. * @return none *************************************************************************/ void handleResendActiveAlarmsRequest( void ) { U32 index; for ( index = 0; index < NUM_OF_ALARM_IDS; index++ ) { if ( TRUE == isAlarmActive( (ALARM_ID_T)index ) ) { broadcastAlarmTriggered( index, BLANK_ALARM_DATA, BLANK_ALARM_DATA ); } } } /*********************************************************************//** * @brief * The isAnyCleaningModeInletWaterConditionActive function returns the status * of any of the inlet water conditions is active or not in a cleaning mode * @details \b Inputs: none * @details \b Outputs: none * @return TRUE if any of the inlet water conditions is active otherwise, FALSE *************************************************************************/ BOOL isAnyCleaningModeInletWaterConditionActive( void ) { BOOL status = FALSE; // Check all the inlet water conditions // status |= isAlarmActive( ALARM_ID_DD_CLEANING_MODE_INLET_WATER_TEMP_TOO_HIGH ); // status |= isAlarmActive( ALARM_ID_DD_CLEANING_MODE_INLET_WATER_TEMP_TOO_LOW ); // status |= isAlarmActive( ALARM_ID_DD_CLEANING_MODE_INLET_WATER_COND_TOO_HIGH ); // status |= isAlarmActive( ALARM_ID_DD_CLEANING_MODE_INLET_WATER_COND_TOO_LOW ); // status |= isAlarmActive( ALARM_ID_DD_CLEANING_MODE_INLET_WATER_PRESSURE_TOO_HIGH ); // status |= isAlarmActive( ALARM_ID_DD_CLEANING_MODE_INLET_WATER_PRESSURE_TOO_LOW ); return status; } /*********************************************************************//** * @brief * The isTransitionToFaultRequired function checks whether the alarm management * should request a transition to fault mode immediately or it should be deferred * @details \b Inputs: none * @details \b Outputs: none * @return TRUE if transition to fault is required otherwise, FALSE *************************************************************************/ static BOOL isTransitionToFaultRequired( void ) { BOOL status = TRUE; DD_OP_MODE_T opMode = getCurrentOperationMode(); switch( opMode ) { //case DD_MODE_FLUS: case DD_MODE_HEAT: case DD_MODE_SERV: case DD_MODE_HCOL: case DD_MODE_ROPS: status = FALSE; break; default: // NOTE: Do nothing for the other modes break; } return status; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testClearAllAlarms function clears all active alarms, even if they * are non-recoverable or faults. The caller of this function must provide * the correct 32-bit key. A Dialin user must also be logged into DD. * @details \b Inputs: none * @details \b Outputs: alarmIsActive[], alarmStartedAt[] * @details \b Message \b Sent: MSG_ID_ALARM_CLEARED to clear all alarms. * @param key 32-bit supervisor alarm key required to perform this function * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testClearAllAlarms( U32 key ) { BOOL result = FALSE; // Verify key if ( SUPERVISOR_ALARM_KEY == key ) { // Verify tester has logged in with HD if ( TRUE == isTestingActivated() ) { ALARM_ID_T a; // Clear all active alarms for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { if ( TRUE == isAlarmActive( a ) ) { ALARM_NAME_DATA_T data; data.alarmName = (U32)a; broadcastData( MSG_ID_ALARM_CLEARED, COMM_BUFFER_OUT_CAN_DD_ALARM, (U08*)&data, sizeof( ALARM_NAME_DATA_T ) ); setAlarmActive( a, FALSE ); } } result = TRUE; } } return result; } /*********************************************************************//** * @brief * The testSetAlarmInfoPublishIntervalOverride function sets the override of the * alarm information publication interval. * @details \b Inputs: none * @details \b Outputs: alarmInfoPublishInterval * @param ms milliseconds between alarm info broadcasts * @return TRUE if override set successful, FALSE if not *************************************************************************/ BOOL testSetAlarmInfoPublishIntervalOverride( U32 ms ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = ms / TASK_GENERAL_INTERVAL; result = TRUE; alarmInfoPublishInterval.ovData = intvl; alarmInfoPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetAlarmInfoPublishIntervalOverride function resets the override of the * alarm information publication interval. * @details \b Inputs: none * @details \b Outputs: alarmInfoPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetAlarmInfoPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmInfoPublishInterval.override = OVERRIDE_RESET; alarmInfoPublishInterval.ovData = alarmInfoPublishInterval.ovInitData; } return result; } /**@}*/