/************************************************************************** * * Copyright (c) 2019-2022 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) Sean Nash * @date (last) 12-Nov-2021 * * @author (original) Sean Nash * @date (original) 07-Nov-2019 * ***************************************************************************/ #include "mibspi.h" #define __ALARM_MGMT_C__ #include "AlarmLamp.h" #include "FPGA.h" #include "InternalADC.h" #include "OperationModes.h" #include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" /** * @addtogroup AlarmManagement * @{ */ // ********** private definitions ********** /// Interval to control lamp and audio and to publish alarm status data. #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 ) #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 LOWEST_ALARM_SUB_RANK 999 ///< Lowest alarm sub-rank that can be set. #define MAX_ALARM_LIST_SIZE 10 ///< Maximum number of active alarms inside alarm list. // *** 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 ) ]; // *** This declaration will cause a compiler error if ALARM_RANK_TABLE does not have same # of alarms as the Alarm_List enumeration. U08 alarmRankTableSizeAssertion[ ( ( sizeof( ALARM_RANK_TABLE ) / sizeof( ALARM_RANK_T ) ) == NUM_OF_ALARM_IDS ? 1 : -1 ) ]; /// A blank alarm data record for alarms that do not include alarm data when triggered. const ALARM_DATA_T BLANK_ALARM_DATA = { ALARM_DATA_TYPE_NONE, 0 }; /// Pin SPI3-CS0 - re-purposed as output GPIO for backup alarm audio enable. #define BACKUP_AUDIO_ENABLE_SPI3_PORT_MASK 0x00000001 // Backup alarm audio enable/disable macros #define SET_BACKUP_AUDIO_ENABLE() {mibspiREG3->PC3 |= BACKUP_AUDIO_ENABLE_SPI3_PORT_MASK;} ///< Macro to enable backup alarm audio. #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.0 ///< 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.0 ///< Minimum audio current (low gain) during test 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 (MAX_ALARM_VOLUME_LEVEL - 1 ) ///< Index for maximum alarm audio volume. #define MIN_ALARM_AUDIO_VOLUME_INDEX 0 ///< Index for minimum alarm audio volume. /// Alarm priority ranking record. typedef struct { ALARM_ID_T alarmID; ///< ID of highest priority alarm in this priority category U32 subRank; ///< Sub-rank of this alarm U32 timeSinceTriggeredMS; ///< Time (in ms) since this alarm was triggered } ALARM_PRIORITY_RANKS_T; /// 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_T; /// Enumeration of alarm audio volume factors. typedef enum Alarm_Audio_Volume_Factors { ALARM_AUDIO_VOLUME_GAIN = 0, ///< Gain setting for alarm audio volume. ALARM_AUDIO_VOLUME_DIVIDER, ///< Divider setting for alarm audio volume. NUM_OF_ALARM_AUDIO_VOLUME_FACTORS ///< Number of alarm audio volume factors. } ALARM_AUDIO_VOLUME_FACTOR_T; /// Lookup table to determine appropriate divider for a given alarm audio volume level. const U08 ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[MAX_ALARM_VOLUME_LEVEL][NUM_OF_ALARM_AUDIO_VOLUME_FACTORS] = { { 1, 0 }, { 1, 1 }, { 3, 1 }, { 3, 2 }, { 4, 2 } }; // ********** private data ********** static BOOL alarmIsActive[ NUM_OF_ALARM_IDS ]; ///< Table - current state of each alarm 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 alarmInfoPublicationTimerCounter = 0; ///< Used to schedule alarm information publication to CAN bus. /// 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 }; /// 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 }; #ifndef ALARM_VOLUME_DEFAULT_LOW /// Set alarm audio volume attenuation level (0..4 - lower level = higher gain). static OVERRIDE_U32_T alarmAudioVolumeLevel = { MIN_ALARM_VOLUME_ATTENUATION, MIN_ALARM_VOLUME_ATTENUATION, MIN_ALARM_VOLUME_ATTENUATION, 0 }; #else static OVERRIDE_U32_T alarmAudioVolumeLevel = { MAX_ALARM_VOLUME_ATTENUATION, MAX_ALARM_VOLUME_ATTENUATION, MAX_ALARM_VOLUME_ATTENUATION, 0 }; #endif /// Alarm audio current (high gain) measured at ADC. static OVERRIDE_F32_T alarmPrimaryAudioCurrentHG = { 0.0, 0.0, 0.0, 0 }; /// Alarm audio current (low gain) measured at ADC. static OVERRIDE_F32_T alarmPrimaryAudioCurrentLG = { 0.0, 0.0, 0.0, 0 }; /// Alarm backup audio current measured at ADC. static OVERRIDE_F32_T alarmBackupAudioCurrent = { 0.0, 0.0, 0.0, 0 }; static COMP_ALARM_STATUS_T alarmStatus; ///< Record for the current composite alarm status. static ALARM_PRIORITY_RANKS_T alarmPriorityFIFO[ NUM_OF_ALARM_PRIORITIES ]; ///< FIFO - first activated or highest sub-rank alarm in each alarm priority category. static BOOL alarmUserRecoveryActionEnabled[ NUMBER_OF_ALARM_USER_ACTIONS ]; ///< Alarm user recovery actions enabled flags. /// Current state of the alarm audio self tests. static ALARM_AUDIO_SELF_TEST_STATE_T alarmAudioSelfTestState; /// Flag indicates whether alarm audio test tone should be output. static BOOL alarmAudioTestToneRequested; // ********** private function prototypes ********** static void activateAlarm( ALARM_ID_T alarm ); static void monitorAlarms( void ); static void updateAlarmsState( void ); static void setAlarmLamp( void ); static void setAlarmAudio( void ); static void updateAlarmsSilenceStatus( void ); static void handleAlarmEscalations( void ); static void updateAlarmsFlags( void ); static void clearAllRecoverableAlarms( void ); static void resetAlarmPriorityFIFO( ALARM_PRIORITY_T priority ); static U32 getAlarmStartTime( ALARM_ID_T alarmID ); static void publishAlarmInfo( void ); /*********************************************************************//** * @brief * The initAlarmMgmt function initializes the AlarmMgmt module. * @details Inputs: none * @details Outputs: AlarmMgmt module initialized. * @return none *************************************************************************/ void initAlarmMgmt( void ) { ALARM_PRIORITY_T p; ALARM_ID_T a; // Disable backup audio CLR_BACKUP_AUDIO_ENABLE(); // Initialize alarm states and start time stamps for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { alarmIsActive[ a ] = FALSE; alarmIsDetected[ 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 ].alarmID = ALARM_ID_NO_ALARM; alarmPriorityFIFO[ p ].subRank = LOWEST_ALARM_SUB_RANK; alarmPriorityFIFO[ p ].timeSinceTriggeredMS = 0; } // 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.topAlarmConditionDetected = FALSE; alarmStatus.systemFault = FALSE; alarmStatus.stop = FALSE; alarmStatus.lampOn = FALSE; alarmStatus.noClear = FALSE; alarmStatus.noResume = FALSE; alarmStatus.noRinseback = FALSE; alarmStatus.noEndTreatment = FALSE; alarmStatus.noNewTreatment = FALSE; alarmStatus.noDialRecirc = FALSE; alarmStatus.usrACKRequired = FALSE; alarmAudioTestToneRequested = FALSE; alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_START; } /*********************************************************************//** * @brief * The execAlarmMgmt function executes the alarm management functions to be * done periodically. The composite alarm state is updated, alarm lamp and * audio patterns are updated, and status is sent out to the rest of the system. * @details Inputs: alarmStatusTable[], ALARM_TABLE[] * @details Outputs: alarmStatus * @return none *************************************************************************/ void execAlarmMgmt( void ) { monitorAlarms(); handleAlarmEscalations(); updateAlarmsState(); updateAlarmsFlags(); updateAlarmsSilenceStatus(); // Publish alarm status at interval if ( ++alarmStatusPublicationTimerCounter >= getU32OverrideValue( &alarmStatusPublishInterval ) ) { // Lamp and audio timing sync'd with broadcast so UI can stay in sync with lamp rhythm setAlarmLamp(); setAlarmAudio(); broadcastAlarmStatus( alarmStatus ); alarmStatusPublicationTimerCounter = 0; } } /*********************************************************************//** * @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 ) ) { // No need to do anything if alarm is already active if ( FALSE == alarmIsActive[ alarm ] ) { // 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 ) { alarmStatus.alarmTop = 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 == ALARM_TABLE[ alarm ].alarmIsFault ) { requestNewOperationMode( MODE_FAUL ); } // Activate alarm 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 ) { clearAlarmCondition( alarm ); } // If alarm has stop property, signal stop now if ( TRUE == ALARM_TABLE[ alarm ].alarmStops ) { initiateAlarmAction( ALARM_ACTION_STOP ); } } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE, alarm ) } } /*********************************************************************//** * @brief * The activateAlarmNoData function activates a given alarm. Also, an alarm * message is broadcast to the rest of the system. This function will * include given data in the broadcast message for logging. * @details Inputs: none * @details 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 ); } /*********************************************************************//** * @brief * The activateAlarm1Data function activates a given alarm. Also, an alarm * message is broadcast to the rest of the system. This function will * include given data in the broadcast message for logging. * @details Inputs: none * @details 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 ) { activateAlarm2Data( alarm, alarmData, BLANK_ALARM_DATA ); } /*********************************************************************//** * @brief * 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 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 ] ) { 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; 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 ); } /*********************************************************************//** * @brief * The clearAlarmCondition function clears a given alarm's condition detected * flag. Also an alarm message is broadcast to the rest of the system. * @details Inputs: none * @details Outputs: alarmIsDetected[] * @param alarm ID of alarm to clear condition for * @return none *************************************************************************/ void clearAlarmCondition( ALARM_ID_T alarm ) { // Verify given alarm if ( ( alarm > ALARM_ID_NO_ALARM ) && ( alarm < NUM_OF_ALARM_IDS ) ) { // Clear alarm condition and broadcast alarm condition clear if not already cleared if ( TRUE == alarmIsDetected[ alarm ] ) { U32 a = (U32)alarm; alarmIsDetected[ alarm ] = FALSE; broadcastData( MSG_ID_ALARM_CONDITION_CLEARED, COMM_BUFFER_OUT_CAN_HD_ALARM, (U08*)&a, sizeof( U32 ) ); } } } /*********************************************************************//** * @brief * The clearAlarm function clears a given alarm if it is recoverable. Also * an alarm message is broadcast to the rest of the system. * @details Inputs: none * @details Outputs: AlarmStatusTable[], alarmIsActive[], alarmStartedAt[], * alarmIsDetected[] * @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 == ALARM_TABLE[ alarm ].alarmNoClear ) { // Clear alarm and broadcast alarm clear if not already cleared if ( TRUE == alarmIsActive[ alarm ] ) { U32 a = (U32)alarm; broadcastData( MSG_ID_ALARM_CLEARED, COMM_BUFFER_OUT_CAN_HD_ALARM, (U08*)&a, sizeof( U32 ) ); alarmIsActive[ alarm ] = FALSE; clearAlarmCondition( alarm ); alarmStartedAt[ alarm ].data = 0; // Clear FIFO if this alarm was in it if ( alarmPriorityFIFO[ ALARM_TABLE[ alarm ].alarmPriority ].alarmID == alarm ) { resetAlarmPriorityFIFO( ALARM_TABLE[ alarm ].alarmPriority ); } } } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_CLEAR, alarm ) } } /*********************************************************************//** * @brief * The setAlarmUserActionEnabled function enables/disables specific alarm * recovery user actions while in specific modes. Ack option is always * potentially enabled - automatically enabled as appropriate by updateAlarmsFlags(). * @details Inputs: none * @details Outputs: * @param action ID of user alarm recovery action to enable/disable * @param enabled set to TRUE to enable action, FALSE to disable * @return none *************************************************************************/ void setAlarmUserActionEnabled( ALARM_USER_ACTION_T action, BOOL enabled ) { if ( action < NUMBER_OF_ALARM_USER_ACTIONS ) { alarmUserRecoveryActionEnabled[ action ] = enabled; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_USER_ACTION, (U32)action ) } } /*********************************************************************//** * @brief * The signalAlarmSilence function handles an alarm silence request from * the user. * @details Inputs: none * @details Outputs: alarm silence status updated * @param cmd ID of user command (1=silence, 0=cancel silence) * @return none *************************************************************************/ void signalAlarmSilence( ALARM_SILENCE_CMD_T cmd ) { if ( ALARM_SILENCE_CMD_START == cmd ) { if ( FALSE == alarmStatus.alarmsSilenced ) { alarmStatus.alarmsSilenced = TRUE; alarmStatus.alarmsSilenceStart = getMSTimerCount(); alarmStatus.alarmsSilenceExpiresIn = ALARM_SILENCE_EXPIRES_IN_SECS; } } else { if ( TRUE == alarmStatus.alarmsSilenced ) { alarmStatus.alarmsSilenced = FALSE; alarmStatus.alarmsSilenceStart = 0; alarmStatus.alarmsSilenceExpiresIn = 0; } } } /*********************************************************************//** * @brief * The signalAlarmUserActionInitiated function clears all non-recoverable alarms * and initiates selected user action. * @details Inputs: none * @details Outputs: * @param action ID of user's selected action to initiate * @return none *************************************************************************/ void signalAlarmUserActionInitiated( ALARM_USER_ACTION_T action ) { // Validate given action if ( action < NUMBER_OF_ALARM_USER_ACTIONS ) { ALARM_ID_T a = alarmStatus.alarmTop; if ( ALARM_USER_ACTION_ACK == action ) { // If user acknowledged top alarm, just clear that alarm if ( TRUE == ALARM_TABLE[ a ].alarmUserAckRequired ) { clearAlarm( a ); } // Otherwise we must be in mode/state where ack was only option - so clear all like other options else { clearAllRecoverableAlarms(); } } else { clearAllRecoverableAlarms(); } } // Initiate user selected action switch ( action ) { case ALARM_USER_ACTION_RESUME: initiateAlarmAction( ALARM_ACTION_RESUME ); break; case ALARM_USER_ACTION_RINSEBACK: initiateAlarmAction( ALARM_ACTION_RINSEBACK ); break; case ALARM_USER_ACTION_END_TREATMENT: initiateAlarmAction( ALARM_ACTION_END_TREATMENT ); break; case ALARM_USER_ACTION_ACK: initiateAlarmAction( ALARM_ACTION_ACK ); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_ALARM_USER_ACTION, action ); break; } } /*********************************************************************//** * @brief * The isAlarmActive function determines whether a given alarm is currently * active. * @details Inputs: alarmIsActive[] * @details Outputs: none * @param alarm 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 * The isAnyAlarmActive function determines whether any alarm is currently * active. * @details Inputs: alarmStatus * @details Outputs: none * @return TRUE if any alarm is active, FALSE if not *************************************************************************/ BOOL isAnyAlarmActive( void ) { BOOL result = ( alarmStatus.alarmTop != ALARM_ID_NO_ALARM ? TRUE : FALSE ); return result; } /*********************************************************************//** * @brief * The isDialysateRecircBlocked function determines whether any currently * active alarm is blocking dialysate re-circulation. * @details Inputs: alarmStatus * @details Outputs: none * @return TRUE if any active alarm prevents dialysate re-circulation, FALSE if not *************************************************************************/ BOOL isDialysateRecircBlocked( void ) { return alarmStatus.noDialRecirc; } /*********************************************************************//** * @brief * The doesAlarmStatusIndicateStop function determines whether any currently * active alarm has stop property. * @details Inputs: alarmStatus * @details Outputs: none * @return TRUE if any active alarm has stop property, FALSE if not *************************************************************************/ BOOL doesAlarmStatusIndicateStop( void ) { return alarmStatus.stop; } /*********************************************************************//** * @brief * The getCurrentAlarmStatePriority function determines the current alarm * state priority (NONE, LOW, MEDIUM, or HIGH). * @details Inputs: alarmStatus * @details Outputs: none * @return current alarm state priority *************************************************************************/ ALARM_PRIORITY_T getCurrentAlarmStatePriority( void ) { return alarmStatus.alarmsState; } /*********************************************************************//** * @brief * The isAlarmRecoverable function determines whether a given alarm is * recoverable. * @details Inputs: ALARM_TABLE[] * @details Outputs: none * @param alarm ID of alarm to check * @return TRUE if given alarm is recoverable, FALSE if not *************************************************************************/ BOOL isAlarmRecoverable( ALARM_ID_T alarm ) { BOOL result = ( TRUE == ALARM_TABLE[ alarm ].alarmNoClear ? FALSE : TRUE ); return result; } /*********************************************************************//** * @brief * The setAlarmAudioVolume function sets the current alarm audio volume level. * @details Inputs: none * @details Outputs: alarmAudioVolumeLevel * @param volumeLevel level of volume requested (1..5) * @return none *************************************************************************/ void setAlarmAudioVolume( U32 volumeLevel ) { BOOL accepted = FALSE; U32 rejReason = REQUEST_REJECT_REASON_NONE; if ( ( volumeLevel > 0 ) && ( volumeLevel <= MAX_ALARM_VOLUME_LEVEL ) ) { // Convert volume level to attenuation level alarmAudioVolumeLevel.data = MAX_ALARM_VOLUME_LEVEL - volumeLevel; accepted = TRUE; } else { rejReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; } // Send response to UI sendAlarmAudioVolumeSetResponse( accepted, rejReason ); } /*********************************************************************//** * @brief * The getNoNewTreatmentStatus function gets the persistent no new * treatment alarm status flag. * @details Inputs: alarmStatus.noNewTreatment * @details Outputs: none * @return TRUE if no new treatment allowed, otherwise FALSE *************************************************************************/ BOOL getNoNewTreatmentStatus( void ) { return alarmStatus.noNewTreatment; } /*********************************************************************//** * @brief * The handleActiveAlarmListRequest function processed the active alarms list * request from UI. * @details Inputs: alarmIsActive[] * @details Outputs: sent active alarms list to UI * @return none *************************************************************************/ void handleActiveAlarmListRequest( void ) { BOOL accepted = TRUE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; U32 activeAlarmList[ MAX_ALARM_LIST_SIZE ]; U32 index; U32 activeAlarmListIndex = 0; for ( index = 0; index < MAX_ALARM_LIST_SIZE; index++ ) { activeAlarmList[ index ] = ALARM_ID_NO_ALARM; } if ( TRUE == isAnyAlarmActive() ) { for ( index = 0; index < NUM_OF_ALARM_IDS; index++ ) { if ( ( TRUE == isAlarmActive( ALARM_RANK_TABLE[ index ].alarmID ) ) && ( activeAlarmListIndex < MAX_ALARM_LIST_SIZE ) ) { activeAlarmList[ activeAlarmListIndex ] = ALARM_RANK_TABLE[ index ].alarmID; activeAlarmListIndex++; } } } sendActiveAlarmsList( accepted, rejReason, activeAlarmList, sizeof( activeAlarmList ) ); } /*********************************************************************//** * @brief * The getAlarmStartTime function gets the active state of a given alarm. * @details Inputs: alarmStartedAt[] * @details Outputs: none * @param alarmID ID of alarm to check * @return The start time stamp of given alarm ID *************************************************************************/ static U32 getAlarmStartTime( ALARM_ID_T alarmID ) { U32 result = 0; if ( alarmID < NUM_OF_ALARM_IDS ) { if ( OVERRIDE_KEY == alarmStartedAt[ alarmID ].override ) { result = alarmStartedAt[ alarmID ].ovData; } else { result = alarmStartedAt[ alarmID ].data; } } else { activateAlarmNoData( ALARM_ID_HD_SOFTWARE_FAULT ); } return result; } /*********************************************************************//** * @brief * The monitorAlarms function monitors alarm audio current. * @details Inputs: alarmStatusTable[] * @details Outputs: alarmPriorityFIFO[], alarmStatus * @return none *************************************************************************/ static void monitorAlarms( void ) { U32 volume = getAlarmAudioVolume(); alarmPrimaryAudioCurrentHG.data = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_HG ); alarmPrimaryAudioCurrentLG.data = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_LG ); alarmBackupAudioCurrent.data = getFPGABackupAlarmAudioCurrent(); // TODO - Check current vs. expected audio output // Publish alarm information at interval publishAlarmInfo(); } /*********************************************************************//** * @brief * The updateAlarmsState function updates the alarms state and alarm to * display. * @details Inputs: alarmStatusTable[] * @details Outputs: alarmPriorityFIFO[], alarmStatus * @return none *************************************************************************/ static void updateAlarmsState( void ) { ALARM_PRIORITY_T highestPriority = ALARM_PRIORITY_NONE; ALARM_ID_T a; BOOL faultsActive = FALSE; BOOL dialysateRecircBlocked = FALSE; // Update FIFOs and sub-ranks per active alarms table - for alarm ranking purposes to determine "top" alarm for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { if ( TRUE == alarmIsActive[ a ] ) { ALARM_PRIORITY_T almPriority = ALARM_TABLE[ a ].alarmPriority; U32 subRank = ALARM_TABLE[ a ].alarmSubRank; U32 msSinceTriggered = calcTimeSince( getAlarmStartTime( a ) ); // See if this alarm is higher rank than highest active alarm in this priority category so far if ( subRank <= alarmPriorityFIFO[ almPriority ].subRank ) { // If sub-rank is a tie, see which alarm was triggered first if ( subRank == alarmPriorityFIFO[ almPriority ].subRank ) { if ( msSinceTriggered > alarmPriorityFIFO[ almPriority ].timeSinceTriggeredMS ) { alarmPriorityFIFO[ almPriority ].alarmID = a; alarmPriorityFIFO[ almPriority ].subRank = subRank; alarmPriorityFIFO[ almPriority ].timeSinceTriggeredMS = msSinceTriggered; } } // Otherwise, this alarm simply outranks current candidate and wins outright else { alarmPriorityFIFO[ almPriority ].alarmID = a; alarmPriorityFIFO[ almPriority ].subRank = subRank; alarmPriorityFIFO[ almPriority ].timeSinceTriggeredMS = msSinceTriggered; } } // Track highest priority alarm found so far of all priority categories highestPriority = MAX( almPriority, highestPriority ); // Track whether any active faults have been found so far if ( TRUE == ALARM_TABLE[ a ].alarmIsFault ) { faultsActive = TRUE; } // Track whether any active alarms prevent dialysate re-circulation so far if ( TRUE == ALARM_TABLE[ a ].alarmNoDialysateRecirc ) { dialysateRecircBlocked = TRUE; } } } // Update alarm to display per highest priority FIFO alarmStatus.alarmsState = highestPriority; alarmStatus.alarmTop = alarmPriorityFIFO[ highestPriority ].alarmID; alarmStatus.topAlarmConditionDetected = alarmIsDetected[ alarmStatus.alarmTop ]; alarmStatus.systemFault = faultsActive; alarmStatus.noDialRecirc = dialysateRecircBlocked; } /*********************************************************************//** * @brief * The setAlarmLamp function sets the alarm lamp pattern according to the * current state of alarms. * @details Inputs: none * @details Outputs: Alarm lamp patter set according to current alarms status. * @return none *************************************************************************/ static void setAlarmLamp( void ) { // Set alarm lamp pattern to appropriate pattern for current alarm state 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 == ALARM_TABLE[ 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_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_LAMP_INVALID_ALARM_STATE, alarmStatus.alarmsState ) break; } } // Execute alarm lamp controller execAlarmLamp(); // Set lamp on flag to match current state of alarm lamp if ( getCurrentAlarmLampPattern() != LAMP_PATTERN_MANUAL ) { alarmStatus.lampOn = getAlarmLampOn(); } else { alarmStatus.lampOn = FALSE; } } /*********************************************************************//** * @brief * The setAlarmAudio function sets the alarm audio pattern according to * the current state of alarms. * @details Inputs: none * @details Outputs: Alarm audio patter set according to current alarms status. * @return none *************************************************************************/ static void setAlarmAudio( void ) { U32 volume = getAlarmAudioVolume(); // If audio test in progress, play test tone. if ( TRUE == alarmAudioTestToneRequested ) { // Play test tone at min volume setAlarmAudioState( ALARM_AUDIO_TEST_TONE, ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[MIN_ALARM_AUDIO_VOLUME_INDEX][ALARM_AUDIO_VOLUME_GAIN], ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[MIN_ALARM_AUDIO_VOLUME_INDEX][ALARM_AUDIO_VOLUME_DIVIDER] ); // If we're in Fault mode, ensure audio test tone request is cancelled. if ( MODE_FAUL == getCurrentOperationMode() ) { alarmAudioTestToneRequested = FALSE; } } // If alarm silenced, play no alarm audio. else if ( TRUE == alarmStatus.alarmsSilenced ) { setAlarmAudioState( ALARM_PRIORITY_NONE, ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_GAIN], ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_DIVIDER] ); } // Otherwise, play alarm audio as appropriate based on current alarm status else { if ( alarmStatus.alarmsState < NUM_OF_ALARM_PRIORITIES ) { #ifndef DISABLE_ALARM_AUDIO setAlarmAudioState( alarmStatus.alarmsState, ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_GAIN], ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_DIVIDER] ); #endif } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_AUDIO_INVALID_ALARM_STATE, alarmStatus.alarmsState ) setAlarmAudioState( ALARM_PRIORITY_HIGH, ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_GAIN], ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_DIVIDER] ); } } } /*********************************************************************//** * @brief * The updateAlarmsSilenceStatus function updates the alarms silence state. * @details Inputs: alarmStatus * @details Outputs: alarmStatus * @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 * The handleAlarmEscalations function handles alarm escalation. * @details Inputs: alarmIsActive[], ALARM_TABLE[] * @details Outputs: alarm(s) escalated when appropriate * @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 != ALARM_TABLE[ a ].alarmEscalatesTo ) { S32 msRemaining = (S32)ALARM_TABLE[ a ].alarmEscalatesAfter - (S32)calcTimeSince( getAlarmStartTime( a ) ); S32 secsRemaining = ( msRemaining / MS_PER_SECOND ) + 1; // Time to escalate? if ( msRemaining <= 0 ) { activateAlarmNoData( ALARM_TABLE[ 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 * The updateAlarmsFlags function updates the alarms flags of the alarms * status record. * @details Inputs: none * @details Outputs: alarmStatus * @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 usrAckReq = FALSE; BOOL noMinimize = TRUE; 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 == ALARM_TABLE[ a ].alarmIsFault ? TRUE : systemFault ); stop = ( TRUE == ALARM_TABLE[ a ].alarmStops ? TRUE : stop ); noClear = ( TRUE == ALARM_TABLE[ a ].alarmNoClear ? TRUE : noClear ); noNewTreatment = ( TRUE == ALARM_TABLE[ a ].alarmNoNewTreatment ? TRUE : noNewTreatment ); // Set user alarm recovery actions allowed flags if ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_RESUME ] ) { noResume = ( TRUE == ALARM_TABLE[ a ].alarmNoResume ? TRUE : noResume ); } else { noResume = TRUE; } if ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_RINSEBACK ] ) { noRinseback = ( TRUE == ALARM_TABLE[ a ].alarmNoRinseback ? TRUE : noRinseback ); } else { noRinseback = TRUE; } if ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_END_TREATMENT ] ) { noEndTreatment = ( TRUE == ALARM_TABLE[ a ].alarmNoEndTreatment ? TRUE : noEndTreatment ); } else { noEndTreatment = TRUE; } } // If alarm active } // Alarm table loop // If top alarm condition not cleared, block resume and rinseback flags if ( TRUE == alarmStatus.topAlarmConditionDetected ) { noResume = TRUE; noRinseback = TRUE; } // If top alarm requires user ack 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 ].alarmUserAckRequired ) || ( ( FALSE == alarmStatus.noClear ) && ( noResume ) && ( noRinseback ) && ( noEndTreatment ) && ( FALSE == alarmStatus.topAlarmConditionDetected ) ) ) { usrAckReq = TRUE; noResume = TRUE; noRinseback = TRUE; noEndTreatment = TRUE; } // If in Treatment-Stop state, allow user to minimize the alarm window if ( ( MODE_TREA == getCurrentOperationMode() ) && ( TREATMENT_STOP_STATE == getTreatmentState() ) ) { noMinimize = 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.usrACKRequired = usrAckReq; alarmStatus.noMinimize = noMinimize; } /*********************************************************************//** * @brief * The clearAllRecoverableAlarms function clears all currently active * recoverable alarms. * @details Inputs: ALARM_TABLE[] * @details Outputs: All currently active recoverable alarms are cleared * @return none *************************************************************************/ static void clearAllRecoverableAlarms( void ) { ALARM_ID_T a = alarmStatus.alarmTop; for ( a = ALARM_ID_HD_SOFTWARE_FAULT; a < NUM_OF_ALARM_IDS; a++ ) { // Is alarm recoverable? if ( FALSE == ALARM_TABLE[ a ].alarmNoClear ) { clearAlarm( a ); } } } /*********************************************************************//** * @brief * The resetAlarmPriorityFIFO function resets a FIFO for a given alarm * priority. * @details Inputs: none * @details 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 ].alarmID = ALARM_ID_NO_ALARM; alarmPriorityFIFO[ priority ].subRank = LOWEST_ALARM_SUB_RANK; alarmPriorityFIFO[ priority ].timeSinceTriggeredMS = 0; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_FIFO_TO_RESET, priority ) } } /*********************************************************************//** * @brief * The publishAlarmInfo function publishes alarm information at the set * interval. * @details Inputs: * @details Outputs: alarm information are published to CAN bus. * @return none *************************************************************************/ static void publishAlarmInfo( void ) { // Publish voltages monitor data on interval if ( ++alarmInfoPublicationTimerCounter >= getU32OverrideValue( &alarmInfoPublishInterval ) ) { ALARM_INFO_PAYLOAD_T data; data.audioVolume = MAX_ALARM_VOLUME_LEVEL - getAlarmAudioVolume(); // convert back to 1..5 volume level for publication data.audioCurrHG = getAlarmAudioPrimaryHighGainCurrent(); data.audioCurrLG = getAlarmAudioPrimaryLowGainCurrent(); data.backupAudioCurr = getAlarmAudioBackupCurrent(); data.safetyShutdown = isSafetyShutdownActivated(); broadcastData( MSG_ID_HD_ALARM_INFORMATION, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( ALARM_INFO_PAYLOAD_T ) ); alarmInfoPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The getAlarmAudioVolume function gets the current alarm audio volume level. * @details Inputs: alarmAudioVolumeLevel * @details Outputs: none * @return the current alarm audio volume level. *************************************************************************/ U32 getAlarmAudioVolume( void ) { U32 result = alarmAudioVolumeLevel.data; if ( OVERRIDE_KEY == alarmAudioVolumeLevel.override ) { result = alarmAudioVolumeLevel.ovData; } return result; } /*********************************************************************//** * @brief * The getAlarmAudioPrimaryHighGainCurrent function gets the current alarm * audio high gain current. * @details Inputs: alarmPrimaryAudioCurrentHG * @details Outputs: none * @return the current alarm audio high gain current (in mA). *************************************************************************/ F32 getAlarmAudioPrimaryHighGainCurrent( void ) { F32 result = alarmPrimaryAudioCurrentHG.data; if ( OVERRIDE_KEY == alarmPrimaryAudioCurrentHG.override ) { result = alarmPrimaryAudioCurrentHG.ovData; } return result; } /*********************************************************************//** * @brief * The getAlarmAudioPrimaryLowGainCurrent function gets the current alarm * audio low gain current. * @details Inputs: alarmPrimaryAudioCurrentLG * @details Outputs: none * @return the current alarm audio low gain current (in mA). *************************************************************************/ F32 getAlarmAudioPrimaryLowGainCurrent( void ) { F32 result = alarmPrimaryAudioCurrentLG.data; if ( OVERRIDE_KEY == alarmPrimaryAudioCurrentLG.override ) { result = alarmPrimaryAudioCurrentLG.ovData; } return result; } /*********************************************************************//** * @brief * The getAlarmAudioBackupCurrent function gets the current backup alarm * audio current. * @details Inputs: alarmBackupAudioCurrent * @details Outputs: none * @return the current backup alarm audio current (in mA). *************************************************************************/ F32 getAlarmAudioBackupCurrent( void ) { F32 result = alarmBackupAudioCurrent.data; if ( OVERRIDE_KEY == alarmBackupAudioCurrent.override ) { result = alarmBackupAudioCurrent.ovData; } return result; } /*********************************************************************//** * @brief * The execAlarmAudioSelfTest function outputs a test audio tone and * measures the audio current level. * @details Inputs: alarmAudioSelfTestState * @details Outputs: none * @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; switch ( alarmAudioSelfTestState ) { case ALARM_AUDIO_SELF_TEST_STATE_START: testStartTime = getMSTimerCount(); // Start test tone alarmAudioTestToneRequested = TRUE; setAlarmAudio(); alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_PRIMARY; break; case ALARM_AUDIO_SELF_TEST_STATE_PRIMARY: { F32 almHGCurrent = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_HG ); F32 almLGCurrent = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_LG ); // 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; } } break; case ALARM_AUDIO_SELF_TEST_STATE_COMPLETE: alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_START; // Should only get here if re-starting self-tests. break; default: // TODO - s/w fault break; } return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetAlarmStateOverride function overrides the state of the * alarm active state for a given alarm with the alarm management with * a given active state. * @details Inputs: none * @details 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 ) { // Verify tester has logged in with HD 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 * state of the active state for a given alarm with the alarm management. * @details Inputs: none * @details 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 ) { // Verify tester has logged in with HD if ( TRUE == isTestingActivated() ) { result = TRUE; clearAlarm( (ALARM_ID_T)alarmID ); } } return result; } /*********************************************************************//** * @brief * The testSetAlarmStartOverride function overrides the start time * for a given alarm with the alarm management with a given start time. * @details Inputs: none * @details 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 ) { // Verify tester has logged in with HD if ( TRUE == isTestingActivated() ) { U32 tim = getMSTimerCount(); if ( tim > value ) { result = TRUE; alarmStartedAt[ alarmID ].ovData = ( tim - value ); alarmStartedAt[ alarmID ].override = OVERRIDE_KEY; } } } return result; } /*********************************************************************//** * @brief * The testResetAlarmStartOverride function resets the override of the * start time for a given alarm with the alarm management. * @details Inputs: none * @details 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 ) { // Verify tester has logged in with HD if ( TRUE == isTestingActivated() ) { result = TRUE; alarmStartedAt[ alarmID ].override = OVERRIDE_RESET; alarmStartedAt[ alarmID ].ovData = alarmStartedAt[ alarmID ].ovInitData; } } return result; } /*********************************************************************//** * @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 HD. * @details Inputs: none * @details Outputs: alarmIsActive[], alarmStartedAt[] * @param key 32-bit supervior 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 == alarmIsActive[ a ] ) { U32 al = (U32)a; broadcastData( MSG_ID_ALARM_CLEARED, COMM_BUFFER_OUT_CAN_HD_ALARM, (U08*)&al, sizeof( U32 ) ); alarmIsActive[ a ] = FALSE; alarmStartedAt[ a ].data = 0; // Clear FIFO if this alarm was in it if ( alarmPriorityFIFO[ ALARM_TABLE[ a ].alarmPriority ].alarmID == a ) { resetAlarmPriorityFIFO( ALARM_TABLE[ a ].alarmPriority ); } } } result = TRUE; } } return result; } /*********************************************************************//** * @brief * The testSetAlarmStatusPublishIntervalOverride function sets the override of the * alarm status publication interval. * @details Inputs: none * @details Outputs: alarmStatusPublishInterval * @param ms milliseconds between alarm status broadcasts * @return TRUE if override set successful, FALSE if not *************************************************************************/ BOOL testSetAlarmStatusPublishIntervalOverride( U32 ms ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = ms / TASK_GENERAL_INTERVAL; result = TRUE; alarmStatusPublishInterval.ovData = intvl; alarmStatusPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetAlarmStatusPublishIntervalOverride function resets the override of the * alarm status publication interval. * @details Inputs: none * @details 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 testSetAlarmInfoPublishIntervalOverride function sets the override of the * alarm information publication interval. * @details Inputs: none * @details 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 Inputs: none * @details 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; } /*********************************************************************//** * @brief * The testSetAlarmAudioVolumeLevelOverride function sets the override of the * alarm audio volume. * @details Inputs: none * @details Outputs: alarmAudioVolumeLevel * @param volume volume level (1..5) of alarm audio * @return TRUE if override set successful, FALSE if not *************************************************************************/ BOOL testSetAlarmAudioVolumeLevelOverride( U32 volume ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmAudioVolumeLevel.ovData = MAX_ALARM_VOLUME_LEVEL - volume; alarmAudioVolumeLevel.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetAlarmAudioVolumeLevelOverride function resets the override of the * alarm audio volume. * @details Inputs: none * @details Outputs: alarmAudioVolumeLevel * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetAlarmAudioVolumeLevelOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmAudioVolumeLevel.override = OVERRIDE_RESET; alarmAudioVolumeLevel.ovData = alarmAudioVolumeLevel.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetPrimaryAlarmAudioCurrentHGOverride function sets the override of the * alarm audio current (high gain) in mA. * @details Inputs: none * @details Outputs: alarmPrimaryAudioCurrentHG * @param mA milliamps measured from high gain channel of primary alarm audio * @return TRUE if override set successful, FALSE if not *************************************************************************/ BOOL testSetPrimaryAlarmAudioCurrentHGOverride( F32 mA ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmPrimaryAudioCurrentHG.ovData = mA; alarmPrimaryAudioCurrentHG.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetPrimaryAlarmAudioCurrentHGOverride function resets the override of the * alarm audio current (high gain). * @details Inputs: none * @details Outputs: alarmPrimaryAudioCurrentHG * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetPrimaryAlarmAudioCurrentHGOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmPrimaryAudioCurrentHG.override = OVERRIDE_RESET; alarmPrimaryAudioCurrentHG.ovData = alarmPrimaryAudioCurrentHG.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetPrimaryAlarmAudioCurrentLGOverride function sets the override of the * alarm audio current (low gain) in mA. * @details Inputs: none * @details Outputs: alarmPrimaryAudioCurrentLG * @param mA milliamps measured from low gain channel of primary alarm audio * @return TRUE if override set successful, FALSE if not *************************************************************************/ BOOL testSetPrimaryAlarmAudioCurrentLGOverride( F32 mA ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmPrimaryAudioCurrentLG.ovData = mA; alarmPrimaryAudioCurrentLG.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetPrimaryAlarmAudioCurrentLGOverride function resets the override of the * alarm audio current (low gain). * @details Inputs: none * @details Outputs: alarmPrimaryAudioCurrentLG * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetPrimaryAlarmAudioCurrentLGOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmPrimaryAudioCurrentLG.override = OVERRIDE_RESET; alarmPrimaryAudioCurrentLG.ovData = alarmPrimaryAudioCurrentLG.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetBackupAlarmAudioCurrentOverride function sets the override of the * alarm audio current (backup) in mA. * @details Inputs: none * @details Outputs: alarmBackupAudioCurrent * @param mA milliamps measured from backup channel of primary alarm audio * @return TRUE if override set successful, FALSE if not *************************************************************************/ BOOL testSetBackupAlarmAudioCurrentOverride( F32 mA ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmBackupAudioCurrent.ovData = mA; alarmBackupAudioCurrent.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetBackupAlarmAudioCurrentOverride function resets the override of the * alarm audio current (backup). * @details Inputs: none * @details Outputs: alarmBackupAudioCurrent * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetBackupAlarmAudioCurrentOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; alarmBackupAudioCurrent.override = OVERRIDE_RESET; alarmBackupAudioCurrent.ovData = alarmBackupAudioCurrent.ovInitData; } return result; } /**@}*/