/************************************************************************** * * Copyright (c) 2024-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 AlarmAudio.c * * @author (last) Sean * @date (last) 30-Jul-2024 * * @author (original) Sean * @date (original) 30-Jul-2024 * ***************************************************************************/ #include "AlarmAudio.h" #include "AlarmMgmtTD.h" #include "CpldInterface.h" #include "FpgaTD.h" #include "GPIO.h" #include "InternalADC.h" #include "Messaging.h" #include "OperationModes.h" #include "TaskGeneral.h" #include "Timers.h" /** * @addtogroup AlarmAudio * @{ */ // ********** private definitions ********** #define ALARM_AUDIO_TEST_TONE 4 ///< Alarm audio state for continuous test tone. #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. /// Enumeration of alarm audio self-test states. typedef enum Alarm_Audio_Self_Test_States { 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. 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 OVERRIDE_U32_T alarmAudioVolumeLevel; ///< Alarm audio attenuation level (0..4 where 0 = max volume and 4 = min volume). static OVERRIDE_F32_T alarmPrimaryAudioCurrentHG; ///< Alarm audio current (high gain) measured at ADC. static OVERRIDE_F32_T alarmPrimaryAudioCurrentLG; ///< Alarm audio current (low gain) measured at ADC. static OVERRIDE_F32_T alarmBackupAudioCurrent; ///< Alarm backup audio current measured at ADC. static ALARM_AUDIO_SELF_TEST_STATE_T alarmAudioSelfTestState; ///< Current state of the alarm audio self tests. static U32 audioTestStartTime; ///< Start time of audio alarm current self-test. static BOOL alarmAudioTestToneRequested; ///< Flag indicates whether alarm audio test tone should be output. // ********** private function prototypes ********** /*********************************************************************//** * @brief * The initAlarmAudio function initializes the Alarm Audio unit. * @details \b Inputs: none * @details \b Outputs: Alarm Audio unit initialized. * @return none *************************************************************************/ void initAlarmAudio( void ) { // Disable backup audio clrAlarmBuzzerSignal(); alarmAudioVolumeLevel.data = MAX_ALARM_VOLUME_ATTENUATION; alarmAudioVolumeLevel.ovData = MAX_ALARM_VOLUME_ATTENUATION; alarmAudioVolumeLevel.ovInitData = MAX_ALARM_VOLUME_ATTENUATION; alarmAudioVolumeLevel.override = OVERRIDE_RESET; alarmPrimaryAudioCurrentHG.data = 0.0; alarmPrimaryAudioCurrentHG.ovData = 0.0; alarmPrimaryAudioCurrentHG.ovInitData = 0.0; alarmPrimaryAudioCurrentHG.override = OVERRIDE_RESET; alarmPrimaryAudioCurrentLG.data = 0.0; alarmPrimaryAudioCurrentLG.ovData = 0.0; alarmPrimaryAudioCurrentLG.ovInitData = 0.0; alarmPrimaryAudioCurrentLG.override = OVERRIDE_RESET; alarmBackupAudioCurrent.data = 0.0; alarmBackupAudioCurrent.ovData = 0.0; alarmBackupAudioCurrent.ovInitData = 0.0; alarmBackupAudioCurrent.override = OVERRIDE_RESET; alarmAudioTestToneRequested = FALSE; alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_START; audioTestStartTime = 0; } /*********************************************************************//** * @brief * The execAlarmAudio function executes the alarm audio service to update * audio current measurements. * @details \b Inputs: none * @details \b Outputs: alarmPrimaryAudioCurrentHG, alarmPrimaryAudioCurrentLG, * alarmBackupAudioCurrent * @return none *************************************************************************/ void execAlarmAudio( void ) { alarmPrimaryAudioCurrentHG.data = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_HG ); alarmPrimaryAudioCurrentLG.data = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_LG ); alarmBackupAudioCurrent.data = getFPGABackupAlarmAudioCurrent(); } /*********************************************************************//** * @brief * The setAlarmAudio function sets the alarm audio pattern according to * the current state of the alarm system. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if alarm state is invalid. * @details \b Inputs: alarmAudioTestToneRequested * @details \b Outputs: appropriate alarm pattern set for reported alarm state. * @return none *************************************************************************/ void setAlarmAudio( void ) { U32 volume = getAlarmAudioVolume(); ALARM_PRIORITY_T almState = getCurrentAlarmStatePriority(); // 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[MAX_ALARM_AUDIO_VOLUME_INDEX][ALARM_AUDIO_VOLUME_GAIN], ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[MAX_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 ( ( ALARM_PRIORITY_NONE == almState ) || ( TRUE == areAlarmsSilenced() ) ) { 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 ( almState < NUM_OF_ALARM_PRIORITIES ) { #ifndef _RELEASE_ // if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ALARM_AUDIO ) != SW_CONFIG_ENABLE_VALUE ) #endif { setAlarmAudioState( almState, ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_GAIN], ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_DIVIDER] ); } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_AUDIO_INVALID_ALARM_STATE, almState ) 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 setAlarmAudioVolume function sets the current alarm audio volume level. * @note This function is called by the set alarm volume message handler. * @details \b Message \b Sent: Response to alarm volume set message. * @details \b Inputs: none * @details \b 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 getAlarmAudioVolume function gets the current alarm audio volume level. * @details \b Inputs: alarmAudioVolumeLevel * @details \b Outputs: none * @return The current alarm audio volume level. *************************************************************************/ U32 getAlarmAudioVolume( void ) { U32 result = alarmAudioVolumeLevel.data; #ifndef _RELEASE_ // Check the software configurations // if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_ALARM_VOLUME_DEFAULT_LOW ) ) // { // result = MIN_ALARM_VOLUME_ATTENUATION; // } #endif if ( OVERRIDE_KEY == alarmAudioVolumeLevel.override ) { result = alarmAudioVolumeLevel.ovData; } return result; } /*********************************************************************//** * @brief * The getAlarmAudioPrimaryHighGainCurrent function gets the measured alarm * audio high gain current. * @details \b Inputs: alarmPrimaryAudioCurrentHG * @details \b Outputs: none * @return The measured 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 measured alarm * audio low gain current. * @details \b Inputs: alarmPrimaryAudioCurrentLG * @details \b Outputs: none * @return The measured 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 measured backup alarm * audio current. * @details \b Inputs: alarmBackupAudioCurrent * @details \b Outputs: none * @return The measured 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 * verifies the audio current levels. * @note This function should be called periodically until a pass or fail * is returned. * @details \b Alarm: ALARM_ID_TD_ALARM_AUDIO_SELF_TEST_FAILURE if audio * currents are out of range. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if self-test state is invalid. * @details \b Inputs: alarmAudioSelfTestState, audioTestStartTime * @details \b Outputs: audioTestStartTime, alarmAudioTestToneRequested * @return pass, fail, or in progress *************************************************************************/ SELF_TEST_STATUS_T execAlarmAudioSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; F32 almLGCurrent = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_LG ); switch ( alarmAudioSelfTestState ) { case ALARM_AUDIO_SELF_TEST_STATE_START: 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_TD_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 ) { 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_TD_ALARM_AUDIO_SELF_TEST_FAILURE, almLGCurrent, ALARM_AUDIO_CURRENT_LG_MIN_MA ); alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_COMPLETE; } break; 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_TD_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: alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_START; // Should only get here if re-starting self-tests. break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_ALARM_AUDIO_STATE, (U32)alarmAudioSelfTestState ) break; } return result; } /*********************************************************************//** * @brief * The resetAlarmAudioPOSTState function resets the alarm audio POST state. * @details \b Inputs: none * @details \b Outputs: alarmAudioSelfTestState * @return none *************************************************************************/ void resetAlarmAudioPOSTState( void ) { alarmAudioSelfTestState = ALARM_AUDIO_SELF_TEST_STATE_START; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testAlarmAudioVolumeLevelOverride function sets the override for the * alarm audio volume. * @details \b Inputs: none * @details \b Outputs: alarmAudioVolumeLevel * @param message Override message from Dialin which includes the alarm * audio volume level to override to. * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL testAlarmAudioVolumeLevelOverride( MESSAGE_T *message ) { BOOL result = u32Override( message, &alarmAudioVolumeLevel, 0, MAX_ALARM_VOLUME_LEVEL - 1 ); return result; } /*********************************************************************//** * @brief * The testPrimaryAlarmAudioCurrentHGOverride function sets the override * for the alarm audio current (high gain) in mA. * @details \b Inputs: none * @details \b Outputs: alarmPrimaryAudioCurrentHG * @param message Override message from Dialin which includes the primary * alarm audio current hgih gain (in mA) to override to. * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL testPrimaryAlarmAudioCurrentHGOverride( MESSAGE_T *message ) { BOOL result = f32Override( message, &alarmPrimaryAudioCurrentHG ); return result; } /*********************************************************************//** * @brief * The testPrimaryAlarmAudioCurrentLGOverride function sets the override * for the alarm audio current (low gain) in mA. * @details \b Inputs: none * @details \b Outputs: alarmPrimaryAudioCurrentLG * @param message Override message from Dialin which includes the primary * alarm audio current low gain (in mA) to override to. * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL testPrimaryAlarmAudioCurrentLGOverride( MESSAGE_T *message ) { BOOL result = f32Override( message, &alarmPrimaryAudioCurrentLG ); return result; } /*********************************************************************//** * @brief * The testBackupAlarmAudioCurrentOverride function sets the override for * the alarm audio current (backup) in mA. * @details \b Inputs: none * @details \b Outputs: alarmBackupAudioCurrent * @param message Override message from Dialin which includes the backup * alarm audio current (in mA) to override to. * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL testBackupAlarmAudioCurrentOverride( MESSAGE_T *message ) { BOOL result = f32Override( message, &alarmBackupAudioCurrent ); return result; } /**@}*/