Index: firmware/App/Services/AlarmMgmt.c =================================================================== diff -u -rcbca82ba088d63f6d53579f97728d4ad5d668bf3 -rf3ea910aef69d3abf485d97ac9a63af6304ca0c2 --- firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision cbca82ba088d63f6d53579f97728d4ad5d668bf3) +++ firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision f3ea910aef69d3abf485d97ac9a63af6304ca0c2) @@ -8,7 +8,7 @@ * @file AlarmMgmt.c * * @author (last) Sean Nash -* @date (last) 31-Mar-2023 +* @date (last) 21-Apr-2023 * * @author (original) Sean Nash * @date (original) 07-Nov-2019 @@ -20,6 +20,7 @@ #define __ALARM_MGMT_C__ #include "AlarmLamp.h" +#include "CPLD.h" #include "FPGA.h" #include "InternalADC.h" #include "OperationModes.h" @@ -39,12 +40,16 @@ #define ALARM_STATUS_PUBLISH_INTERVAL ( ALARM_LAMP_AND_AUDIO_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) /// Interval (ms/task time) at which the alarm information is published on the CAN bus. #define ALARM_INFO_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) + +/// Interval (ms/task time) Alarms are blocked after the return of AC power. +#define ALARM_BLOCKED_COUNT_AFTER_AC_RETURN ( 10*MS_PER_SECOND / TASK_GENERAL_INTERVAL ) -#define ALARM_SILENCE_EXPIRES_IN_SECS (60) ///< Alarm silence expiration time in seconds. +#define ALARM_SILENCE_EXPIRES_IN_SECS (60) ///< Alarm silence expiration time in seconds. -#define SUPERVISOR_ALARM_KEY 0xD2C3B4A5 ///< 32-bit key required for clear all alarms request. +#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 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 // *** 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 ) ]; @@ -62,8 +67,8 @@ #define CLR_BACKUP_AUDIO_ENABLE() {mibspiREG3->PC3 &= ~BACKUP_AUDIO_ENABLE_SPI3_PORT_MASK;} ///< Macro to disable backup alarm audio. #define ALARM_AUDIO_TEST_TONE 4 ///< Alarm audio state for continuous test tone. -#define ALARM_AUDIO_CURRENT_HG_MIN_MA 20.0F ///< Minimum audio current (high gain) during test tone self-test (in mA). // TODO - Why is HG so low? S/B same as LG I think. -#define ALARM_AUDIO_CURRENT_LG_MIN_MA 60.0F ///< Minimum audio current (low gain) during test tone self-test (in mA). +#define ALARM_AUDIO_CURRENT_LG_MIN_MA 50.0F ///< Minimum audio current (low gain) during test tone self-test (in mA). +#define ALARM_AUDIO_CURRENT_LG_MAX_MA 20.0F ///< Maximum audio current (low gain) during no tone self-test (in mA). #define ALARM_AUDIO_MAX_TEST_TIME_MS 1000 ///< Maximum time for audio current to reach threshold in test. #define MAX_ALARM_AUDIO_VOLUME_INDEX 0 ///< Index for maximum alarm audio volume. #define MIN_ALARM_AUDIO_VOLUME_INDEX (MAX_ALARM_VOLUME_LEVEL - 1 ) ///< Index for minimum alarm audio volume. @@ -79,10 +84,11 @@ /// Enumeration of alarm audio self-test states. typedef enum Alarm_Lamp_Self_Test_States { - ALARM_AUDIO_SELF_TEST_STATE_START = 0, ///< Start state of alarm lamp self-test. - ALARM_AUDIO_SELF_TEST_STATE_PRIMARY, ///< Red state of alarm lamp self-test. - ALARM_AUDIO_SELF_TEST_STATE_COMPLETE, ///< Completed state of alarm lamp self-test. - NUM_OF_ALARM_AUDIO_SELF_TEST_STATES ///< Number of states in alarm lamp self-test. + ALARM_AUDIO_SELF_TEST_STATE_START = 0, ///< Start state of alarm audio self-test. + ALARM_AUDIO_SELF_TEST_STATE_PRIMARY, ///< Test tone state of alarm audio self-test. + ALARM_AUDIO_SELF_TEST_STATE_NO_TONE, ///< No tone state of alarm audio self-test. + ALARM_AUDIO_SELF_TEST_STATE_COMPLETE, ///< Completed state of alarm audio self-test. + NUM_OF_ALARM_AUDIO_SELF_TEST_STATES ///< Number of states in alarm audio self-test. } ALARM_AUDIO_SELF_TEST_STATE_T; /// Enumeration of alarm audio volume factors. @@ -108,6 +114,8 @@ static BOOL alarmIsDetected[ NUM_OF_ALARM_IDS ]; ///< Table - current state of each alarm condition (detected or cleared) static OVERRIDE_U32_T alarmStartedAt[ NUM_OF_ALARM_IDS ]; ///< Table - when alarm became active for each alarm (if active) or zero (if inactive) static U32 alarmStatusPublicationTimerCounter = 0; ///< Used to schedule alarm status publication to CAN bus. +static U32 alarmsBlockedTimer = 0; ///< Countdown timer used to temporarily block new alarms from being initiated +static U32 audioTestStartTime; ///< Start time of audio alarm current self-test. static U32 alarmInfoPublicationTimerCounter = 0; ///< Used to schedule alarm information publication to CAN bus. /// Interval (in task intervals) at which to publish alarm status to CAN bus. @@ -195,7 +203,7 @@ alarmStatus.alarmsState = ALARM_PRIORITY_NONE; alarmStatus.alarmsSilenced = FALSE; alarmStatus.alarmsSilenceStart = 0; - alarmStatus.alarmsSilenceExpiresIn = 0; + alarmStatus.alarmsSilenceExpiresIn = 0; alarmStatus.alarmsEscalatesIn = 0; alarmStatus.alarmsToEscalate = FALSE; alarmStatus.alarmTop = ALARM_ID_NO_ALARM; @@ -211,6 +219,7 @@ alarmStatus.noDialRecirc = FALSE; alarmStatus.ok = FALSE; + alarmsBlockedTimer = 0; alarmAudioTestToneRequested = FALSE; resumeBlockedByAlarmProperty = FALSE; alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_START; @@ -233,24 +242,30 @@ updateAlarmsSilenceStatus(); // Publish alarm status and information at interval publishAlarmInfo(); + + // Block new machine alarms during power fail recovery + if ( alarmsBlockedTimer > 0 ) + { + alarmsBlockedTimer--; + } } - -/*********************************************************************//** - * @brief - * The activateAlarm function activates a given alarm. - * @details Inputs: none - * @details 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 ) ) - { + +/*********************************************************************//** + * @brief + * The activateAlarm function activates a given alarm. + * @details Inputs: none + * @details Outputs: alarmIsActive[], alarmStartedAt[], alarmStatus is updated + * @param alarm ID of alarm to activate + * @return none + *************************************************************************/ +static void activateAlarm( ALARM_ID_T alarm ) +{ + // Verify valid alarm index + if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) + { // No need to do anything if alarm is already active, but if condition was cleared then re-trigger alarm if ( ( FALSE == alarmIsActive[ alarm ] ) || - ( ( FALSE == alarmIsDetected[ alarm ] ) && ( FALSE == ALARM_TABLE[ alarm ].alarmConditionClearImmed ) ) ) + ( ( FALSE == alarmIsDetected[ alarm ] ) && ( FALSE == ALARM_TABLE[ alarm ].alarmConditionClearImmed ) ) ) { // If alarm status was that no alarms currently active, set this alarm as top alarm until status formally updated later if ( ALARM_ID_NO_ALARM == alarmStatus.alarmTop ) @@ -273,6 +288,7 @@ alarmIsActive[ alarm ] = TRUE; alarmStartedAt[ alarm ].data = getMSTimerCount(); alarmIsDetected[ alarm ] = TRUE; + // If alarm has clear condition immediately property, clear condition now if ( TRUE == ALARM_TABLE[ alarm ].alarmConditionClearImmed ) { @@ -288,7 +304,7 @@ else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE, alarm ) - } + } } /*********************************************************************//** @@ -327,7 +343,7 @@ * The activateAlarm2Data function activates a given alarm. Also, 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 Inputs: none + * @details Inputs: alarmsBlockedTimer, determines blocked alarm conditions * @details Outputs: alarm triggered message sent, alarm activated * @param alarm ID of alarm to activate * @param alarmData1 supporting data to include in alarm msg @@ -336,28 +352,47 @@ *************************************************************************/ 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 ] ) + // Block if new alarms are occur during loss of AC power + if ( ( TRUE == getCPLDACPowerLossDetected() ) ) { - ALARM_TRIGGERED_PAYLOAD_T data; + alarmsBlockedTimer = ALARM_BLOCKED_COUNT_AFTER_AC_RETURN; + } + // Sanity check, verify valid alarm index + if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) + { + // if the block timer is 0 OR we have an unblockable alarm + if ( ( ALARM_NOT_BLOCKED == alarmsBlockedTimer ) + || ( ALARM_ID_HD_AC_POWER_LOST == alarm ) + || ( ALARM_ID_HD_AC_POWER_LOST_IN_TREATMENT == alarm ) ) + { + // Broadcast alarm and data if alarm not already active + if ( FALSE == alarmIsActive[ alarm ] ) + { + ALARM_TRIGGERED_PAYLOAD_T data; - data.alarm = (U32)alarm; - data.almDataType1 = (U32)alarmData1.dataType; - data.almData1 = alarmData1.data.uInt.data; - data.almDataType2 = (U32)alarmData2.dataType; - data.almData2 = alarmData2.data.uInt.data; - data.almPriority = ALARM_TABLE[ alarm ].alarmPriority; - data.almRank = ALARM_TABLE[ alarm ].alarmSubRank; - data.almClrTopOnly = ALARM_TABLE[ alarm ].alarmClearOnly; + data.alarm = (U32)alarm; + data.almDataType1 = (U32)alarmData1.dataType; + data.almData1 = alarmData1.data.uInt.data; + data.almDataType2 = (U32)alarmData2.dataType; + data.almData2 = alarmData2.data.uInt.data; + data.almPriority = ALARM_TABLE[ alarm ].alarmPriority; + data.almRank = ALARM_TABLE[ alarm ].alarmSubRank; + data.almClrTopOnly = ALARM_TABLE[ alarm ].alarmClearOnly; - broadcastData( MSG_ID_ALARM_TRIGGERED, COMM_BUFFER_OUT_CAN_HD_ALARM, (U08*)&data, sizeof( ALARM_TRIGGERED_PAYLOAD_T ) ); - // Send information for UI to log to treatment log - if ( ( TRUE == ALARM_TABLE[ alarm ].alarmTreatmentLog ) && ( MODE_TREA == getCurrentOperationMode() ) ) - { - sendTreatmentLogAlarmEventData( alarm, alarmData1, alarmData2 ); - } + broadcastData( MSG_ID_ALARM_TRIGGERED, COMM_BUFFER_OUT_CAN_HD_ALARM, (U08*)&data, sizeof( ALARM_TRIGGERED_PAYLOAD_T ) ); + // Send information for UI to log to treatment log + if ( ( TRUE == ALARM_TABLE[ alarm ].alarmTreatmentLog ) && ( MODE_TREA == getCurrentOperationMode() ) ) + { + sendTreatmentLogAlarmEventData( alarm, alarmData1, alarmData2 ); + } + } + activateAlarm( alarm ); + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE, alarm ) } - activateAlarm( alarm ); } /*********************************************************************//** @@ -491,7 +526,7 @@ void signalAlarmUserActionInitiated( ALARM_USER_ACTION_T action ) { // Validate given action - if ( action < NUMBER_OF_ALARM_USER_ACTIONS ) + 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; @@ -841,6 +876,7 @@ // Check for user confirmation of end treatment alarm response if ( CONFIRMATION_REQUEST_STATUS_ACCEPTED == getConfirmationRequestStatus( GENERIC_CONFIRM_ID_TREATMENT_END ) ) { + clearAllRecoverableAlarms(); initiateAlarmAction( ALARM_ACTION_END_TREATMENT ); } @@ -1149,16 +1185,15 @@ } // If alarm active } // Alarm table loop - // If top alarm condition not cleared, block resume and rinseback flags + // If top alarm condition not cleared, block resume if ( TRUE == alarmStatus.topAlarmConditionDetected ) { noResume = TRUE; - noRinseback = TRUE; } // If top alarm has clear only property or no other user options enabled for recoverable alarm and condition cleared, set user ack flag and block other flags if ( ( TRUE == ALARM_TABLE[ alarmStatus.alarmTop ].alarmClearOnly ) || - ( ( FALSE == alarmStatus.noClear ) && ( noResume ) && ( noRinseback ) && ( noEndTreatment ) && + ( ( FALSE == alarmStatus.noClear ) && ( TRUE == noResume ) && ( TRUE == noRinseback ) && ( TRUE == noEndTreatment ) && ( FALSE == alarmStatus.topAlarmConditionDetected ) ) ) { usrAckReq = TRUE; @@ -1167,6 +1202,15 @@ noEndTreatment = TRUE; } + // If AC power is out, block all user options + if ( TRUE == getCPLDACPowerLossDetected() ) + { + usrAckReq = FALSE; + noResume = TRUE; + noRinseback = TRUE; + noEndTreatment = TRUE; + } + // If in Treatment-Stop state or Fault/Service/Standby Mode, allow user to minimize the alarm window if ( ( MODE_FAUL == currentMode ) || ( MODE_SERV == currentMode ) || ( MODE_STAN == currentMode ) || ( ( MODE_TREA == currentMode ) && ( TREATMENT_STOP_STATE == getTreatmentState() ) ) ) @@ -1367,46 +1411,63 @@ * @brief * The execAlarmAudioSelfTest function outputs a test audio tone and * measures the audio current level. - * @details Inputs: alarmAudioSelfTestState - * @details Outputs: none + * @details Inputs: alarmAudioSelfTestState, audioTestStartTime + * @details Outputs: audioTestStartTime, alarmAudioTestToneRequested * @return the current backup alarm audio current (in mA). *************************************************************************/ SELF_TEST_STATUS_T execAlarmAudioSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; - static U32 testStartTime; + F32 almLGCurrent = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_LG ); switch ( alarmAudioSelfTestState ) { case ALARM_AUDIO_SELF_TEST_STATE_START: - testStartTime = getMSTimerCount(); - // Start test tone - alarmAudioTestToneRequested = TRUE; - setAlarmAudio(); - alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_PRIMARY; + if ( almLGCurrent < ALARM_AUDIO_CURRENT_LG_MAX_MA ) + { + audioTestStartTime = getMSTimerCount(); + // Start test tone + alarmAudioTestToneRequested = TRUE; + setAlarmAudio(); + alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_PRIMARY; + } + else + { + result = SELF_TEST_STATUS_FAILED; + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_ALARM_AUDIO_SELF_TEST_FAILURE, almLGCurrent, ALARM_AUDIO_CURRENT_LG_MAX_MA ); + alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_COMPLETE; + } break; case ALARM_AUDIO_SELF_TEST_STATE_PRIMARY: + // Check if alarm audio current is sufficiently high indicating alarm tone is being output + if ( almLGCurrent > ALARM_AUDIO_CURRENT_LG_MIN_MA ) { - F32 almHGCurrent = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_HG ); - F32 almLGCurrent = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_LG ); + alarmAudioTestToneRequested = FALSE; + audioTestStartTime = getMSTimerCount(); + alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_NO_TONE; + } + else if ( TRUE == didTimeout( audioTestStartTime, ALARM_AUDIO_MAX_TEST_TIME_MS ) ) + { + alarmAudioTestToneRequested = FALSE; + result = SELF_TEST_STATUS_FAILED; + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_ALARM_AUDIO_SELF_TEST_FAILURE, almLGCurrent, ALARM_AUDIO_CURRENT_LG_MIN_MA ); + alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_COMPLETE; + } + break; - // Check if alarm audio current is sufficiently high indicating alarm tone is being output - if ( ( almHGCurrent > ALARM_AUDIO_CURRENT_HG_MIN_MA ) && - ( almLGCurrent > ALARM_AUDIO_CURRENT_LG_MIN_MA ) ) - { - alarmAudioTestToneRequested = FALSE; - result = SELF_TEST_STATUS_PASSED; - alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_COMPLETE; - } - else if ( TRUE == didTimeout( testStartTime, ALARM_AUDIO_MAX_TEST_TIME_MS ) ) - { - alarmAudioTestToneRequested = FALSE; - result = SELF_TEST_STATUS_FAILED; - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_ALARM_AUDIO_SELF_TEST_FAILURE, almHGCurrent, almLGCurrent ); - alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_COMPLETE; - } + case ALARM_AUDIO_SELF_TEST_STATE_NO_TONE: + if ( almLGCurrent < ALARM_AUDIO_CURRENT_LG_MAX_MA ) + { + result = SELF_TEST_STATUS_PASSED; + alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_COMPLETE; } + else if ( TRUE == didTimeout( audioTestStartTime, ALARM_AUDIO_MAX_TEST_TIME_MS ) ) + { + result = SELF_TEST_STATUS_FAILED; + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_ALARM_AUDIO_SELF_TEST_FAILURE, almLGCurrent, ALARM_AUDIO_CURRENT_LG_MAX_MA ); + alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_COMPLETE; + } break; case ALARM_AUDIO_SELF_TEST_STATE_COMPLETE: