/**********************************************************************//** * * Copyright (c) 2019-2020 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 "AlarmLamp.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" /** * @addtogroup AlarmManagement * @{ */ // ********** private definitions ********** #define ALARM_STATUS_PUBLISH_INTERVAL (500/TASK_GENERAL_INTERVAL) ///< Default interval to publish alarm status data. #define ALARM_SILENCE_EXPIRES_IN_SECS (60) ///< Alarm silence expiration time in seconds. #define ALM_ESC_1_MIN (1 * SEC_PER_MIN * MS_PER_SECOND) ///< Number of ms in 1 minute. #define ALM_ESC_4_MIN (4 * SEC_PER_MIN * MS_PER_SECOND) ///< Number of ms in 4 minutes. #define ALM_ESC_5_MIN (5 * SEC_PER_MIN * MS_PER_SECOND) ///< Number of ms in 5 minutes. #define ALM_ESC_10_MIN (10 * SEC_PER_MIN * MS_PER_SECOND) ///< Number of ms in 10 minutes. #pragma pack(push,1) /// Record defining the properties of each individual alarm. 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) /// Table of alarms and their static properties. const ALARM_T alarmTable[ NUM_OF_ALARM_IDS ] = { // Priority Escalate In Escalate To Fault Stops NoClr NoRes NoRin NoEnd NoNew Bypass { 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 { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_STUCK_BUTTON_TEST_FAILED { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_FPGA_POST_TEST_FAILED { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_WATCHDOG_POST_TEST_FAILED { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_UI_COMM_POST_FAILED { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_OFF_CHECK { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_OFF_CHECK { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MC_DIRECTION_CHECK { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_ROTOR_SPEED_CHECK { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_OFF_CHECK { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_ROTOR_SPEED_CHECK { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_WATCHDOG_EXPIRED { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_RTC_COMM_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_RTC_CONFIG_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_DG_COMM_TIMEOUT { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_UI_COMM_TIMEOUT { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_COMM_TOO_MANY_BAD_CRCS { ALARM_PRIORITY_LOW, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_TREATMENT_STOPPED_BY_USER { ALARM_PRIORITY_MEDIUM, ALM_ESC_1_MIN, ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RESUME, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_SITTING_WARNING { ALARM_PRIORITY_MEDIUM, ALM_ESC_5_MIN, ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RINSEBACK, FALSE, TRUE , FALSE, TRUE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RESUME { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, TRUE, TRUE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RINSEBACK { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_CAN_MESSAGE_NOT_ACKED { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_OCCLUSION_BLOOD_PUMP { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_OCCLUSION_DIAL_IN_PUMP { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_OCCLUSION_DIAL_OUT_PUMP { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_ARTERIAL_PRESSURE_LOW { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_ARTERIAL_PRESSURE_HIGH { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_VENOUS_PRESSURE_LOW { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_VENOUS_PRESSURE_HIGH { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_UF_RATE_TOO_HIGH_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_UF_VOLUME_ACCURACY_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_RTC_BATTERY_LOW { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_RTC_OR_TIMER_ACCURACY_FAILURE { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_RTC_RAM_OPS_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_NVDATA_EEPROM_OPS_FAILURE { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_NVDATA_MFG_RECORD_CRC_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_NVDATA_SRVC_RECORD_CRC_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_NVDATA_CAL_RECORD_CRC_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_NVDATA_HW_USAGE_DATA_CRC_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // AlARM_ID_NVDATA_DISINFECTION_DATE_CRC_ERROR { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_RO_PUMP_OUT_PRESSURE_OUT_OF_RANGE { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_TEMPERATURE_SENSORS_OUT_OF_RANGE { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_TEMPERATURE_SENSORS_INCONSISTENT { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_HD_COMM_TIMEOUT { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_FLOW_VS_MOTOR_SPEED_CHECK { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_FLOW_VS_MOTOR_SPEED_CHECK { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MOTOR_SPEED_CHECK { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MOTOR_SPEED_CHECK }; /// A blank alarm data record for alarms that do not include alarm data when triggered. const ALARM_DATA_T blankAlarmData = { ALARM_DATA_TYPE_NONE, 0 }; // ********** private data ********** /// interval (in ms) at which to publish alarm status to CAN bus DATA_DECL( U32, AlarmStatusPub, alarmStatusPublishInterval, ALARM_STATUS_PUBLISH_INTERVAL, ALARM_STATUS_PUBLISH_INTERVAL ); static U32 alarmStatusPublicationTimerCounter = 0; ///< Used to schedule alarm status publication to CAN bus. /// table - current state of each alarm static BOOL alarmIsActive[ NUM_OF_ALARM_IDS ]; /// table - when alarm became active for each alarm (if active) or zero (if inactive) DATA_ARRAY_DECL( U32, AlarmStarts, NUM_OF_ALARM_IDS, alarmStartedAt ); static COMP_ALARM_STATUS_T alarmStatus; ///< Record for the current composite alarm status. static ALARM_ID_T alarmPriorityFIFO[ NUM_OF_ALARM_PRIORITIES ]; // ********** private function prototypes ********** static void activateAlarm( ALARM_ID_T alarm ); 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( U32, getAlarmStartTime, alarmID ); static DATA_GET_PROTOTYPE( U32, getPublishAlarmStatusInterval ); /************************************************************************* * @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 ] = FALSE; 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(); // publish alarm status at interval if ( ++alarmStatusPublicationTimerCounter >= getPublishAlarmStatusInterval() ) { broadcastAlarmStatus( alarmStatus ); alarmStatusPublicationTimerCounter = 0; } } /************************************************************************* * @brief activateAlarm * The activateAlarm function activates a given alarm. * @details * Inputs : none * Outputs : alarmIsActive[], alarmStartedAt[] * @param alarm : ID of alarm to activate * @return none *************************************************************************/ static void activateAlarm( ALARM_ID_T alarm ) { // verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { // no need to do anything if alarm is already active if ( FALSE == alarmIsActive[ alarm ] ) { // if alarms silenced, end silence due to new alarm alarmStatus.alarmsSilenced = FALSE; // if alarm is a fault, request transition to fault mode if ( TRUE == alarmTable[ alarm ].alarmIsFault ) { #ifndef RM46_EVAL_BOARD_TARGET requestNewOperationMode( MODE_FAUL ); #endif } // activate alarm alarmIsActive[ alarm ] = TRUE; alarmStartedAt[ alarm ].data = getMSTimerCount(); #ifdef DEBUG_ENABLED { // TODO - temporary debug code - remove later char debugStr[ 256 ]; sprintf( debugStr, "ALARM triggered:%5d \n", alarm ); sendDebugData( (U08*)debugStr, strlen(debugStr) ); } #endif } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE, alarm ) } } /************************************************************************* * @brief activateAlarmNoData * The activateAlarmNoData 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 : alarm triggered message sent, alarm activated * @param alarm : ID of alarm to activate * @param alarmData : supporting data to include in alarm msg * @return none *************************************************************************/ void activateAlarmNoData( ALARM_ID_T alarm ) { // broadcast alarm and data if alarm not already active if ( FALSE == alarmIsActive[ alarm ] ) { broadcastAlarmTriggered( (U16)alarm, blankAlarmData, blankAlarmData ); } activateAlarm( alarm ); } /************************************************************************* * @brief activateAlarm1Data * The activateAlarm1Data 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 : alarm triggered message sent, alarm activated * @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 ) { // broadcast alarm and data if alarm not already active if ( FALSE == alarmIsActive[ alarm ] ) { broadcastAlarmTriggered( (U16)alarm, alarmData, blankAlarmData ); } activateAlarm( alarm ); } /************************************************************************* * @brief activateAlarm1Data * The activateAlarm2Data 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 : alarm triggered message sent, alarm activated * @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 ) { // broadcast alarm and data if alarm not already active if ( FALSE == alarmIsActive[ alarm ] ) { broadcastAlarmTriggered( (U16)alarm, alarmData1, alarmData2 ); } activateAlarm( 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 ) { // clear alarm and broadcast alarm clear if not already cleared if ( TRUE == alarmIsActive[ alarm ] ) { broadcastAlarmCleared( alarm ); alarmIsActive[ alarm ] = FALSE; alarmStartedAt[ alarm ].data = 0; // clear FIFO if this alarm was in it if ( alarmPriorityFIFO[ alarmTable[ alarm ].alarmPriority ] == alarm ) { resetAlarmPriorityFIFO( alarmTable[ alarm ].alarmPriority ); } } } } 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 = alarmIsActive[ alarm ]; return result; } /************************************************************************* * @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_PRIORITY_T highestPriority = ALARM_PRIORITY_NONE; ALARM_ID_T a; BOOL faultsActive = FALSE; // update FIFOs per active alarms table for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { if ( TRUE == alarmIsActive[a] ) { ALARM_PRIORITY_T almPriority = alarmTable[ a ].alarmPriority; if ( ALARM_ID_NO_ALARM == alarmPriorityFIFO[ almPriority ] ) { alarmPriorityFIFO[ almPriority ] = a; } highestPriority = MAX( almPriority, highestPriority ); if ( TRUE == alarmTable[ a ].alarmIsFault ) { faultsActive = TRUE; } } } // update alarm to display per highest priority FIFO alarmStatus.alarmsState = highestPriority; alarmStatus.alarmTop = alarmPriorityFIFO[ highestPriority ]; alarmStatus.systemFault = faultsActive; } /************************************************************************* * @brief setAlarmLampAndAudio * The setAlarmLampAndAudio function sets the alarm lamp and audio patterns \n * according to the current state of alarms. * @details * Inputs : none * Outputs : Alarm lamp patter set according to current alarms status. * @param none * @return none *************************************************************************/ static void setAlarmLampAndAudio( void ) { if ( getCurrentAlarmLampPattern() != LAMP_PATTERN_MANUAL ) { switch ( alarmStatus.alarmsState ) { case ALARM_PRIORITY_NONE: requestAlarmLampPattern( LAMP_PATTERN_OK ); break; case ALARM_PRIORITY_LOW: requestAlarmLampPattern( LAMP_PATTERN_LOW_ALARM ); break; case ALARM_PRIORITY_MEDIUM: requestAlarmLampPattern( LAMP_PATTERN_MED_ALARM ); break; case ALARM_PRIORITY_HIGH: if ( TRUE == alarmTable[ alarmStatus.alarmTop ].alarmIsFault ) { requestAlarmLampPattern( LAMP_PATTERN_FAULT ); } else { requestAlarmLampPattern( LAMP_PATTERN_HIGH_ALARM ); } break; default: requestAlarmLampPattern( LAMP_PATTERN_FAULT ); SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_LAMP_INVALID_ALARM_STATE, alarmStatus.alarmsState ) break; } } if ( TRUE == alarmStatus.alarmsSilenced ) { // TODO - no audio } else // alarms not silenced { switch ( alarmStatus.alarmsState ) { case ALARM_PRIORITY_NONE: // TODO - no audio break; case ALARM_PRIORITY_LOW: // TODO - low priority audio break; case ALARM_PRIORITY_MEDIUM: // TODO - medium priority audio break; case ALARM_PRIORITY_HIGH: // TODO - high priority audio break; default: // TODO - high priority audio 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 : alarmStatus * Outputs : alarmStatus * @param none * @return none *************************************************************************/ static void updateAlarmsSilenceStatus( void ) { // if alarms not silenced, reset alarms silence related properties if ( TRUE != alarmStatus.alarmsSilenced ) { alarmStatus.alarmsSilenceExpiresIn = 0; alarmStatus.alarmsSilenceStart = 0; } else { U32 timeSinceAlarmSilenceStart = calcTimeSince( alarmStatus.alarmsSilenceStart ) / MS_PER_SECOND; if ( timeSinceAlarmSilenceStart >= ALARM_SILENCE_EXPIRES_IN_SECS ) { alarmStatus.alarmsSilenceExpiresIn = 0; } else { alarmStatus.alarmsSilenceExpiresIn = ALARM_SILENCE_EXPIRES_IN_SECS - timeSinceAlarmSilenceStart; } // if alarms silence expires, end it if ( 0 == alarmStatus.alarmsSilenceExpiresIn ) { alarmStatus.alarmsSilenced = FALSE; } } } /************************************************************************* * @brief handleAlarmEscalations * The handleAlarmEscalations function handles alarm escalation. * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void handleAlarmEscalations( void ) { U32 secsToEscalate = 0; ALARM_ID_T nextAlarmToEscalate = ALARM_ID_NO_ALARM; ALARM_ID_T a; // update escalations for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { if ( TRUE == alarmIsActive[ a ] ) { // does active alarm escalate? if ( ALARM_ID_NO_ALARM != alarmTable[ a ].alarmEscalatesTo ) { S32 msRemaining = (S32)alarmTable[ a ].alarmEscalatesAfter - (S32)calcTimeSince( getAlarmStartTime( a ) ); S32 secsRemaining = ( msRemaining / MS_PER_SECOND ) + 1; // time to escalate? if ( msRemaining <= 0 ) { activateAlarmNoData( alarmTable[ a ].alarmEscalatesTo ); clearAlarm( a ); } else { // no candidates for alarm escalation yet? if ( ALARM_ID_NO_ALARM == nextAlarmToEscalate ) { secsToEscalate = secsRemaining; nextAlarmToEscalate = a; } // sooner candidate for alarm escalation? else if ( secsRemaining < secsToEscalate ) { secsToEscalate = secsRemaining; nextAlarmToEscalate = a; } } } // if alarm escalates } // if alarm active } // alarm table loop // update alarm escalation properties if ( TRUE == alarmStatus.systemFault || ALARM_ID_NO_ALARM == nextAlarmToEscalate ) { alarmStatus.alarmsToEscalate = FALSE; alarmStatus.alarmsEscalatesIn = 0; } else { alarmStatus.alarmsToEscalate = TRUE; alarmStatus.alarmsEscalatesIn = secsToEscalate; } } /************************************************************************* * @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 ) { BOOL systemFault = FALSE; BOOL stop = FALSE; BOOL noClear = FALSE; BOOL noResume = FALSE; BOOL noRinseback = FALSE; BOOL noEndTreatment = FALSE; BOOL noNewTreatment = FALSE; BOOL bypassDialyzer = FALSE; ALARM_ID_T a; // determine alarm flags for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { if ( TRUE == alarmIsActive[ a ] ) { systemFault = ( TRUE == alarmTable[ a ].alarmIsFault ? TRUE : systemFault ); stop = ( TRUE == alarmTable[ a ].alarmStops ? TRUE : stop ); noClear = ( TRUE == alarmTable[ a ].alarmNoClear ? TRUE : noClear ); noResume = ( TRUE == alarmTable[ a ].alarmNoResume ? TRUE : noResume ); noRinseback = ( TRUE == alarmTable[ a ].alarmNoRinseback ? TRUE : noRinseback ); noEndTreatment = ( TRUE == alarmTable[ a ].alarmNoEndTreatment ? TRUE : noEndTreatment ); noNewTreatment = ( TRUE == alarmTable[ a ].alarmNoNewTreatment ? TRUE : noNewTreatment ); bypassDialyzer = ( TRUE == alarmTable[ a ].alarmDialyzerBypass ? TRUE : bypassDialyzer ); } // if alarm active } // alarm table loop // do not bypass dialyzer if stop or fault flag set if ( ( TRUE == systemFault ) || ( TRUE == stop ) ) { bypassDialyzer = FALSE; } // set updated alarm flags alarmStatus.systemFault = systemFault; alarmStatus.stop = stop; alarmStatus.noClear = noClear; alarmStatus.noResume = noResume; alarmStatus.noRinseback = noRinseback; alarmStatus.noEndTreatment = noEndTreatment; alarmStatus.noNewTreatment = noNewTreatment; alarmStatus.bypassDialyzer = bypassDialyzer; } /************************************************************************* * @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; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_FIFO_TO_RESET, priority ) } } /************************************************************************* * @brief getPublishAlarmStatusInterval * The getPublishAlarmStatusInterval function gets the alarm status \n * publication interval. * @details * Inputs : alarmStatusPublishInterval * Outputs : none * @param none * @return the current alarm status publication interval (in ms). *************************************************************************/ DATA_GET( U32, getPublishAlarmStatusInterval, alarmStatusPublishInterval ) /**@}*/ /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /************************************************************************* * @brief testSetAlarmStatusPublishIntervalOverride * The testSetAlarmStatusPublishIntervalOverride function overrides the \n * alarm status publish interval. * @details * Inputs : none * Outputs : alarmStatusPublishInterval * @param value : override blood flow data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetAlarmStatusPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_GENERAL_INTERVAL; result = TRUE; alarmStatusPublishInterval.ovData = intvl; alarmStatusPublishInterval.override = OVERRIDE_KEY; } return result; } /************************************************************************* * @brief testResetAlarmStatusPublishIntervalOverride * The testResetAlarmStatusPublishIntervalOverride function resets the override \n * of the alarm status publish interval. * @details * Inputs : none * Outputs : alarmStatusPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetAlarmStatusPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmStatusPublishInterval.override = OVERRIDE_RESET; alarmStatusPublishInterval.ovData = alarmStatusPublishInterval.ovInitData; } return result; } /************************************************************************* * @brief * 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. * @details * Inputs : none * Outputs : alarm activated or cleared * @param alarmID : ID of alarm to activate or clear * @param value : override state for the given alarm ID (1=activate, 0=clear) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetAlarmStateOverride( U32 alarmID, U32 state ) { BOOL result = FALSE; if ( alarmID < NUM_OF_ALARM_IDS ) { if ( TRUE == isTestingActivated() ) { if ( TRUE == state ) { activateAlarmNoData( (ALARM_ID_T)alarmID ); } else { clearAlarm( (ALARM_ID_T)alarmID ); } result = TRUE; } } return result; } /************************************************************************* * @brief * 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 : alarm cleared * @param alarmID : ID of alarm to clear * @return TRUE if alarm clear successful, FALSE if not *************************************************************************/ BOOL testResetAlarmStateOverride( U32 alarmID ) { BOOL result = FALSE; if ( alarmID < NUM_OF_ALARM_IDS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; clearAlarm( (ALARM_ID_T)alarmID ); } } return result; } /************************************************************************* * @brief testSetAlarmStartOverride * The testSetAlarmStartOverride function overrides the start time \n * for a given alarm with the alarm management with a given start time. \n * @details * Inputs : none * Outputs : alarmStartedAt[] * @param alarmID : ID of alarm to override start time for * @param value : override time since start (in ms) for the given alarm ID * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetAlarmStartOverride( U32 alarmID, U32 value ) { BOOL result = FALSE; if ( alarmID < NUM_OF_ALARM_IDS ) { if ( TRUE == isTestingActivated() ) { U32 tim = getMSTimerCount(); if ( tim > value ) { result = TRUE; alarmStartedAt[ alarmID ].ovData = ( tim - value ); alarmStartedAt[ alarmID ].override = OVERRIDE_KEY; } } } return result; } /************************************************************************* * @brief testResetAlarmStartOverride * 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 reset override of start time for * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetAlarmStartOverride( U32 alarmID ) { BOOL result = FALSE; if ( alarmID < NUM_OF_ALARM_IDS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; alarmStartedAt[ alarmID ].override = OVERRIDE_RESET; alarmStartedAt[ alarmID ].ovData = alarmStartedAt[ alarmID ].ovInitData; } } return result; }