/************************************************************************** * * Copyright (c) 2019-2019 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 Timers.c * * @date 07-Nov-2019 * @author S. Nash * * @brief Alarm Management service module. Provides general alarm management \n * functionality including support functions for triggering and clearing \n * specific alarms. * **************************************************************************/ #include "Common.h" #include "AlarmLamp.h" #include "SystemCommMessages.h" #include "Timers.h" // ********** private definitions ********** #pragma pack(push,1) typedef struct { ALARM_PRIORITY_T alarmsState; // current alarm priority level BOOL alarmsSilenced; // alarms are currently silenced? U32 alarmsSilenceStart; // time stamp for when alarms were silenced (ms) U32 alarmsSilenceExpiresIn; // time until alarm silence expires (seconds) U32 alarmsEscalatesIn; // time until alarm will escalate (seconds) ALARM_ID_T alarmTop; // ID of current top alarm that will drive lamp/audio and UI should be displaying right now BOOL systemFault; // a system fault is active? BOOL stop; // we should be in controlled stop right now BOOL noClear; // no recovery will be possible BOOL noResume; // treatment may not be resumed at this time BOOL noRinseback; // rinseback may not be initiated at this time BOOL noEndTreatment; // ending the treatment is not an option at this time BOOL noNewTreatment; // no new treatments may be started even if current treatment is ended BOOL bypassDialyzer; // the dialyzer should be bypassed at this time } COMP_ALARM_STATUS_T; typedef struct { ALARM_PRIORITY_T alarmPriority; // priority of alarm U32 alarmEscalatesAfter; // time (s) after start when alarm will escalate if not cleared (zero indicates no escalation) ALARM_ID_T alarmEscalatesTo; // ID of alarm that this alarm will escalate to (ALARM_ID_NO_ALARM indicates no esclation) BOOL alarmIsFault; // alarm is a system fault? BOOL alarmStops; // alarm activation should cause a controlled stop BOOL alarmNoClear; // alarm cannot be cleared (unrecoverable)? BOOL alarmNoResume; // alarm prevents treatment resume BOOL alarmNoRinseback; // alarm prevents rinseback BOOL alarmNoEndTreatment; // alarm prevents ending treatment BOOL alarmNoNewTreatment; // alarm prevents any new treatments BOOL alarmDialyzerBypass; // alarm activation should cause dialyzer bypass until cleared } ALARM_T; #pragma pack(pop) const ALARM_T alarmTable[NUM_OF_ALARM_IDS] = { { ALARM_PRIORITY_NONE, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_NO_ALARM { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE } // ALARM_ID_SOFTWARE_FAULT }; // ********** private data ********** DATA_ARRAY_DECL( BOOL, AlarmStates, NUM_OF_ALARM_IDS, alarmIsActive ); DATA_ARRAY_DECL( U32, AlarmStarts, NUM_OF_ALARM_IDS, alarmStartedAt ); static COMP_ALARM_STATUS_T alarmStatus; static ALARM_ID_T alarmPriorityFIFO[NUM_OF_ALARM_PRIORITIES]; // ********** private function prototypes ********** static void updateAlarmsState( void ); static void setAlarmLampAndAudio( void ); static void updateAlarmsSilenceStatus( void ); static void handleAlarmEscalations( void ); static void updateAlarmsFlags( void ); static void resetAlarmPriorityFIFO( ALARM_PRIORITY_T priority ); static DATA_ARRAY_GET_PROTOTYPE( BOOL, getAlarmActive, alarmID ); static DATA_ARRAY_GET_PROTOTYPE( U32, getAlarmStartTime, alarmID ); /************************************************************************* * @brief initAlarmMgmt * The initAlarmMgmt function initializes the AlarmMgmt module. * @details * Inputs : none * Outputs : AlarmMgmt module initialized. * @param none * @return none *************************************************************************/ void initAlarmMgmt( void ) { ALARM_PRIORITY_T p; ALARM_ID_T a; // initialize alarm states and start time stamps for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { alarmIsActive[a].data = FALSE; alarmIsActive[a].ovData = FALSE; alarmIsActive[a].ovInitData = TRUE; alarmIsActive[a].override = OVERRIDE_RESET; alarmStartedAt[a].data = 0; alarmStartedAt[a].ovData = 0; alarmStartedAt[a].ovInitData = 0; alarmStartedAt[a].override = OVERRIDE_RESET; } // initialize alarm FIFOs for ( p = ALARM_PRIORITY_NONE; p < NUM_OF_ALARM_PRIORITIES; p++ ) { alarmPriorityFIFO[p] = ALARM_ID_NO_ALARM; } // initialize composite alarm state alarmStatus.alarmsState = ALARM_PRIORITY_NONE; alarmStatus.alarmsSilenced = FALSE; alarmStatus.alarmsSilenceStart = 0; alarmStatus.alarmsSilenceExpiresIn = 0; alarmStatus.alarmsEscalatesIn = 0; alarmStatus.alarmTop = ALARM_ID_NO_ALARM; alarmStatus.systemFault = FALSE; alarmStatus.stop = FALSE; alarmStatus.noClear = FALSE; alarmStatus.noResume = FALSE; alarmStatus.noRinseback = FALSE; alarmStatus.noEndTreatment = FALSE; alarmStatus.noNewTreatment = FALSE; alarmStatus.bypassDialyzer = FALSE; } /************************************************************************* * @brief execAlarmMgmt * The execAlarmMgmt function executes the alarm management functions to be \n * done periodically. The composite alarm state is updated, alarm lamp and \n * audio patterns are updated, and status is sent out to the rest of the system. * @details * Inputs : larmStatusTable[], alarmTable[] * Outputs : larmStatus * @param none * @return none *************************************************************************/ void execAlarmMgmt( void ) { handleAlarmEscalations(); updateAlarmsState(); updateAlarmsFlags(); updateAlarmsSilenceStatus(); setAlarmLampAndAudio(); // TODO - publish alarms status record to rest of system } /************************************************************************* * @brief activateAlarm * The activateAlarm function activates a given alarm. Also, an alarm \n * message is broadcast to the rest of the system. * @details * Inputs : none * Outputs : AlarmStatusTable[] * @param alarm : ID of alarm to activate * @return none *************************************************************************/ void activateAlarm( ALARM_ID_T alarm ) { // verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { alarmIsActive[alarm].data = TRUE; alarmStartedAt[alarm].data = getMSTimerCount(); // TODO - send alarm broadcast msg } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE, alarm ) } } /************************************************************************* * @brief activateAlarm1Data * The activateAlarm function activates a given alarm. Also, an alarm \n * message is broadcast to the rest of the system. This function will \n * include given data in the broadcast message for logging. * @details * Inputs : none * Outputs : AlarmStatusTable[] * @param alarm : ID of alarm to activate * @param alarmData : supporting data to include in alarm msg * @return none *************************************************************************/ void activateAlarm1Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData ) { // verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { alarmIsActive[alarm].data = TRUE; alarmStartedAt[alarm].data = getMSTimerCount(); // TODO - send alarm broadcast msg w/ alarm data } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE1, alarm ) } } /************************************************************************* * @brief activateAlarm1Data * The activateAlarm function activates a given alarm. Also, an alarm \n * message is broadcast to the rest of the system. This function will \n * include two given data in the broadcast message for logging. * @details * Inputs : none * Outputs : AlarmStatusTable[] * @param alarm : ID of alarm to activate * @param alarmData1 : supporting data to include in alarm msg * @param alarmData2 : supporting data to include in alarm msg * @return none *************************************************************************/ void activateAlarm2Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData1, ALARM_DATA_T alarmData2 ) { // verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { alarmIsActive[alarm].data = TRUE; alarmStartedAt[alarm].data = getMSTimerCount(); // TODO - send alarm broadcast msg w/ alarm data } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE2, alarm ) } } /************************************************************************* * @brief clearAlarm * The clearAlarm function clears a given alarm if it is recoverable. Also \n * an alarm message is broadcast to the rest of the system. * @details * Inputs : none * Outputs : AlarmStatusTable[] * @param alarm : ID of alarm to clear * @return none *************************************************************************/ void clearAlarm( ALARM_ID_T alarm ) { // verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { // verify alarm can be cleared if ( FALSE == alarmTable[alarm].alarmNoClear ) { alarmIsActive[alarm].data = FALSE; alarmStartedAt[alarm].data = 0; // clear FIFO if this alarm was in it if ( alarmPriorityFIFO[alarmTable[alarm].alarmPriority] == alarm ) { resetAlarmPriorityFIFO( alarmTable[alarm].alarmPriority ); } // TODO - send alarm broadcast msg w/ alarm data } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_CLEAR, alarm ) } } /************************************************************************* * @brief isAlarmActive * The isAlarmActive function determines whether a given alarm is currently \n * active. * @details * Inputs : alarmIsActive[] * Outputs : none * @param alarmID : ID of alarm to check * @return TRUE if given alarm is active, FALSE if not *************************************************************************/ BOOL isAlarmActive( ALARM_ID_T alarm ) { BOOL result = getAlarmActive( alarm ); return result; } /************************************************************************* * @brief getAlarmActive * The getAlarmActive function gets the active state of a given alarm. * @details * Inputs : alarmIsActive[] * Outputs : none * @param alarmID : ID of alarm to check * @return TRUE if given alarm is active, FALSE if not *************************************************************************/ static DATA_ARRAY_GET( BOOL, getAlarmActive, alarmID, NUM_OF_ALARM_IDS-1, alarmIsActive, TRUE ) /************************************************************************* * @brief getAlarmStartTime * The getAlarmStartTime function gets the active state of a given alarm. * @details * Inputs : alarmStartedAt[] * Outputs : none * @param alarmID : ID of alarm to check * @return The start time stamp of given alarm ID *************************************************************************/ static DATA_ARRAY_GET( U32, getAlarmStartTime, alarmID, NUM_OF_ALARM_IDS-1, alarmStartedAt, 0 ) /************************************************************************* * @brief updateAlarmsState * The updateAlarmsState function updates the alarms state and alarm to \n * display. * @details * Inputs : alarmStatusTable[] * Outputs : alarmPriorityFIFO[], alarmStatus * @param none * @return none *************************************************************************/ static void updateAlarmsState( void ) { ALARM_ID_T tempDisp = ALARM_ID_NO_ALARM; ALARM_PRIORITY_T tempState = ALARM_PRIORITY_NONE; ALARM_ID_T a; ALARM_PRIORITY_T p; // update FIFOs per alarm status table for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { if ( TRUE == getAlarmActive(a) ) { if ( ALARM_ID_NO_ALARM == alarmPriorityFIFO[alarmTable[a].alarmPriority] ) { alarmPriorityFIFO[alarmTable[a].alarmPriority] = a; } } } // update alarms status and alarm to display per highest priority FIFO for ( p = ALARM_PRIORITY_LOW; p < NUM_OF_ALARM_PRIORITIES; p++ ) { tempState = p; tempDisp = alarmPriorityFIFO[p]; } alarmStatus.alarmsState = tempState; alarmStatus.alarmTop = tempDisp; } /************************************************************************* * @brief setAlarmLampAndAudio * The setAlarmLampAndAudio function sets the alarm lamp and audio patterns \n * according to the current state of alarms. * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void setAlarmLampAndAudio( void ) { switch ( alarmStatus.alarmsState ) { case ALARM_PRIORITY_NONE: requestAlarmLampPattern( LAMP_PATTERN_OK ); // TODO - no audio break; case ALARM_PRIORITY_LOW: requestAlarmLampPattern( LAMP_PATTERN_LOW_ALARM ); // TODO - low priority audio break; case ALARM_PRIORITY_MEDIUM: requestAlarmLampPattern( LAMP_PATTERN_MED_ALARM ); // TODO - medium priority audio break; case ALARM_PRIORITY_HIGH: if ( TRUE == alarmTable[alarmStatus.alarmTop].alarmIsFault ) { requestAlarmLampPattern( LAMP_PATTERN_FAULT ); } else { requestAlarmLampPattern( LAMP_PATTERN_HIGH_ALARM ); } // TODO - high priority audio break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_LAMP_INVALID_ALARM_STATE, alarmStatus.alarmsState ) break; } } /************************************************************************* * @brief updateAlarmsSilenceStatus * The updateAlarmsSilenceStatus function updates the alarms silence state. * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void updateAlarmsSilenceStatus( void ) { } /************************************************************************* * @brief handleAlarmEscalations * The handleAlarmEscalations function handles alarm escalation. * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void handleAlarmEscalations( void ) { } /************************************************************************* * @brief updateAlarmsFlags * The updateAlarmsFlags function updates the alarms flags of the alarms \n * status record. * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void updateAlarmsFlags( void ) { } /************************************************************************* * @brief resetAlarmPriorityFIFO * The resetAlarmPriorityFIFO function resets a FIFO for a given alarm \n * priority. * @details * Inputs : none * Outputs : alarmPriorityFIFO[] * @param priority : priority of FIFO to reset * @return none *************************************************************************/ static void resetAlarmPriorityFIFO( ALARM_PRIORITY_T priority ) { // verify priority if ( priority < NUM_OF_ALARM_PRIORITIES ) { alarmPriorityFIFO[priority] = ALARM_ID_NO_ALARM; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /************************************************************************* * @brief testSetAlarmStateOverride and testResetAlarmStateOverride * The testSetAlarmStateOverride function overrides the state of the \n * alarm active state for a given alarm with the alarm management with \n * a given active state. * The testResetAlarmStateOverride function resets the override of the \n * state of the active state for a given alarm with the alarm management. * @details * Inputs : none * Outputs : alarmIsActive[] * @param alarmID : ID of alarm to override active state for * @param value : override state for the given alarm ID * @return TRUE if override successful, FALSE if not *************************************************************************/ DATA_ARRAY_OVERRIDE_FUNC( BOOL, testSetAlarmStateOverride, testResetAlarmStateOverride, alarmIsActive, alarmID, NUM_OF_ALARM_IDS-1 ) /************************************************************************* * @brief testSetAlarmStartOverride and testResetAlarmStartOverride * The testSetAlarmStartOverride function overrides the start time \n * for a given alarm with the alarm management with a given start time. \n * The testResetAlarmStartOverride function resets the override of the \n * start time for a given alarm with the alarm management. * @details * Inputs : none * Outputs : alarmStartedAt[] * @param alarmID : ID of alarm to override start time for * @param value : override start time for the given alarm ID * @return TRUE if override successful, FALSE if not *************************************************************************/ DATA_ARRAY_OVERRIDE_FUNC( U32, testSetAlarmStartOverride, testResetAlarmStartOverride, alarmStartedAt, alarmID, NUM_OF_ALARM_IDS-1 )