Index: firmware/App/Services/AlarmMgmt.c =================================================================== diff -u -re2cf7feff54dad3fc5be72619fa64b5421fc6f9f -rcd5be724d5a3ba7457e761191d82f278654d7f5c --- firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision e2cf7feff54dad3fc5be72619fa64b5421fc6f9f) +++ firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision cd5be724d5a3ba7457e761191d82f278654d7f5c) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2019-2023 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-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 AlarmMgmt.c * -* @author (last) Vinayakam Mani -* @date (last) 11-Sep-2023 +* @author (last) Sean Nash +* @date (last) 31-Oct-2023 * * @author (original) Sean Nash * @date (original) 07-Nov-2019 @@ -49,7 +49,9 @@ #define SUPERVISOR_ALARM_KEY 0xD2C3B4A5 ///< 32-bit key required for clear all alarms request. #define LOWEST_ALARM_SUB_RANK 999 ///< Lowest alarm sub-rank that can be set. -#define ALARM_NOT_BLOCKED 0 ///< Alarm blocked timer value that indicates no alarm block +#define ALARM_NOT_BLOCKED 0 ///< Alarm blocked timer value that indicates no alarm block + +#define MIN_TIME_BETWEEN_ALARM_ACTIONS_MS MS_PER_SECOND ///< Minimum time between user alarm actions (in ms). // *** This declaration will cause a compiler error if ALARM_TABLE does not have same # of alarms as the Alarm_List enumeration. U08 alarmTableSizeAssertion[ ( ( sizeof( ALARM_TABLE ) / sizeof( ALARM_T ) ) == NUM_OF_ALARM_IDS ? 1 : -1 ) ]; @@ -117,6 +119,7 @@ static U32 alarmInfoPublicationTimerCounter = 0; ///< Used to schedule alarm information publication to CAN bus. static U32 audioTestStartTime; ///< Start time of audio alarm current self-test. static U32 alarmsBlockedTimer = 0; ///< Countdown timer used to temporarily block new alarms from being initiated +static U32 lastUserAlarmActionReceivedTime = 0; ///< Time of last alarm action by user received from the UI (ms timestamp). /// Interval (in task intervals) at which to publish alarm status to CAN bus. static OVERRIDE_U32_T alarmStatusPublishInterval = { ALARM_STATUS_PUBLISH_INTERVAL, ALARM_STATUS_PUBLISH_INTERVAL, ALARM_STATUS_PUBLISH_INTERVAL, 0 }; @@ -223,6 +226,7 @@ alarmStatus.ok = FALSE; alarmsBlockedTimer = 0; + lastUserAlarmActionReceivedTime = 0; alarmAudioTestToneRequested = FALSE; resumeBlockedByAlarmProperty = FALSE; alarmNoRetrigger = FALSE; @@ -563,67 +567,117 @@ /*********************************************************************//** * @brief * The signalAlarmUserActionInitiated function clears all non-recoverable alarms - * and initiates selected user action. - * @details Inputs: none - * @details Outputs: + * and initiates selected user action. User actions are debounced (must come + * at least 1 second after last). And user actions must be appropriate for current + * alarm state. + * @details Inputs: ALARM_TABLE[], alarmStatus, lastUserAlarmActionReceivedTime + * @details Outputs: alarmIsActive[], lastUserAlarmActionReceivedTime * @param action ID of user's selected action to initiate * @return none *************************************************************************/ void signalAlarmUserActionInitiated( ALARM_USER_ACTION_T action ) { - BOOL allRecAlarmsCleared = TRUE; + BOOL alarmActionIsValid = FALSE; - // Clear recoverable alarms on user action - if ( ( action < NUMBER_OF_ALARM_USER_ACTIONS ) && ( action != ALARM_USER_ACTION_END_TREATMENT ) ) // end tx action must be confirmed first - { - ALARM_ID_T a = alarmStatus.alarmTop; - - if ( ALARM_USER_ACTION_ACK == action ) - { - // If user acknowledged alarm w/ clear only property, just clear that alarm - if ( TRUE == ALARM_TABLE[ a ].alarmClearOnly ) - { - clearAlarm( a ); - } - // Otherwise we must be in mode/state where ack was only option - so clear all like other options - else - { - allRecAlarmsCleared = clearAllRecoverableAlarms( action ); - } - } - else - { - allRecAlarmsCleared = clearAllRecoverableAlarms( action ); - } - } - - // Initiate user selected action + // Validate user selected action is appropriate per current alarm system status switch ( action ) { case ALARM_USER_ACTION_RESUME: - if ( TRUE == allRecAlarmsCleared ) - { // only resume if we've cleared all recoverable alarms - initiateAlarmAction( ALARM_ACTION_RESUME ); + if ( alarmStatus.noResume != TRUE ) + { + alarmActionIsValid = TRUE; } break; case ALARM_USER_ACTION_RINSEBACK: - initiateAlarmAction( ALARM_ACTION_RINSEBACK ); + if ( alarmStatus.noRinseback != TRUE ) + { + alarmActionIsValid = TRUE; + } break; case ALARM_USER_ACTION_END_TREATMENT: - // Send message to UI to get user confirmation to end treatment - action initiated only upon receipt of user confirmation from UI - addConfirmationRequest( GENERIC_CONFIRM_ID_TREATMENT_END, GENERIC_CONFIRM_CMD_REQUEST_OPEN, 0 ); + if ( alarmStatus.noEndTreatment != TRUE ) + { + alarmActionIsValid = TRUE; + } break; case ALARM_USER_ACTION_ACK: - initiateAlarmAction( ALARM_ACTION_ACK ); + if ( TRUE == alarmStatus.ok ) + { + alarmActionIsValid = TRUE; + } break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_ALARM_USER_ACTION, action ); break; } + + // Ignore alarm action if invalid or too soon after last one (essentially a debounce in case user double tapped a button) + if ( ( TRUE == alarmActionIsValid ) && ( calcTimeSince( lastUserAlarmActionReceivedTime ) >= MIN_TIME_BETWEEN_ALARM_ACTIONS_MS ) ) + { + BOOL allRecAlarmsCleared = TRUE; + + // Clear recoverable alarms on user action + if ( action != ALARM_USER_ACTION_END_TREATMENT ) // end tx action must be confirmed first + { + ALARM_ID_T a = alarmStatus.alarmTop; + + if ( ALARM_USER_ACTION_ACK == action ) + { + // If user acknowledged alarm w/ clear only property, just clear that alarm + if ( TRUE == ALARM_TABLE[ a ].alarmClearOnly ) + { + clearAlarm( a ); + } + // Otherwise we must be in mode/state where ack was only option - so clear all like other options + else + { + allRecAlarmsCleared = clearAllRecoverableAlarms( action ); + } + } + else + { + allRecAlarmsCleared = clearAllRecoverableAlarms( action ); + } + } + + // Initiate user selected action + switch ( action ) + { + case ALARM_USER_ACTION_RESUME: + if ( TRUE == allRecAlarmsCleared ) + { // only resume if we've cleared all recoverable alarms + initiateAlarmAction( ALARM_ACTION_RESUME ); + } + break; + + case ALARM_USER_ACTION_RINSEBACK: + initiateAlarmAction( ALARM_ACTION_RINSEBACK ); + break; + + case ALARM_USER_ACTION_END_TREATMENT: + // Send message to UI to get user confirmation to end treatment - action initiated only upon receipt of user confirmation from UI + addConfirmationRequest( GENERIC_CONFIRM_ID_TREATMENT_END, GENERIC_CONFIRM_CMD_REQUEST_OPEN, 0 ); + break; + + case ALARM_USER_ACTION_ACK: + initiateAlarmAction( ALARM_ACTION_ACK ); + break; + +// This default cannot be reached in VectorCAST due to check above for alarmActionIsValid +#ifndef _VECTORCAST_ + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_ALARM_USER_ACTION, action ); + break; +#endif + } + } + + // Remember last time user selected an alarm action + lastUserAlarmActionReceivedTime = getMSTimerCount(); } /*********************************************************************//**