/************************************************************************** * * Copyright (c) 2019-2023 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 SafetyShutdown.c * * @author (last) Sean Nash * @date (last) 02-Feb-2023 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 * ***************************************************************************/ #include #include "gio.h" #include "FPGA.h" #include "InternalADC.h" #include "SystemCommMessages.h" #include "SafetyShutdown.h" #include "Timers.h" /** * @addtogroup SafetyShutdown * @{ */ // ********** private definitions ********** // GIO port A pin assignments for pins connected to CPLD #define SAFETY_GIO_PORT_PIN 3U // CPLD pin I/O macros #define SET_SAFETY_SHUTDOWN() gioSetBit( gioPORTB, SAFETY_GIO_PORT_PIN, PIN_SIGNAL_HIGH ) #define CLR_SAFETY_SHUTDOWN() gioSetBit( gioPORTB, SAFETY_GIO_PORT_PIN, PIN_SIGNAL_LOW ) #define SAFETY_SHUTDOWN_POST_TIMEOUT_MS 500 ///< Safety shutdown POST test timeout (in ms). #define SAFETY_SHUTDOWN_RECOVERY_TIME_MS 500 ///< After safety shutdown POST test, wait this long (in ms) to recover before moving on. #define MAX_24V_LEVEL_ON_SAFETY_SHUTDOWN 5.0F ///< Maximum voltage on 24V line when safety shutdown asserted. #define MIN_24V_LEVEL_ON_SAFETY_RECOVER 22.6F ///< Minimum voltage on 24V line when safety shutdown is recovered. #define MIN_BACKUP_ALARM_CURRENT_MA 200.0F ///< Minimum backup alarm audio current (in mA) detected when safety shutdown asserted. #define MAX_BACKUP_ALARM_CURRENT_MA 10.0F ///< Maximum backup alarm audio current (in mA) detected when safety shutdown is recovered. #define SAFETY_POST_24V_INITIAL 0 ///< Safety shutdown POST failed because 24V was out before safety line pulled. #define SAFETY_POST_24V_NOT_CUT 1 ///< Safety shutdown POST failed because 24V was not cut when safety line pulled. #define SAFETY_POST_NO_24V_RESTORE 2 ///< Safety shutdown POST failed because 24V was not restored when safety line reset. /// Enumeration of safety shutdown self-test states. typedef enum Safety_Shutdown_Self_Test_States { SAFETY_SHUTDOWN_SELF_TEST_STATE_START = 0, ///< Safety shutdown self-test start state SAFETY_SHUTDOWN_SELF_TEST_STATE_IN_PROGRESS, ///< Safety shutdown self-test in progress state SAFETY_SHUTDOWN_SELF_TEST_STATE_RECOVER, ///< Safety shutdown self-test recovery state SAFETY_SHUTDOWN_SELF_TEST_STATE_COMPLETE, ///< Safety shutdown self-test completed state NUM_OF_SAFETY_SHUTDOWN_SELF_TEST_STATES ///< Number of safety shutdown self-test states } SAFETY_SHUTDOWN_SELF_TEST_STATE_T; // ********** private data ********** static BOOL safetyShutdownActivated; ///< Status of safety shutdown signal. static BOOL safetyShutdownOverrideResetState; ///< Natural status of safety shutdown signal. Used to restore state on override reset. static SAFETY_SHUTDOWN_SELF_TEST_STATE_T safetyShutdownSelfTestState; ///< Current safety shutdown self-test state. static SELF_TEST_STATUS_T safetyShutdownSelfTestStatus; ///< Safety shutdown self-test preliminary status. static U32 safetyShutdownSelfTestTimerCount; ///< Safety shutdown self-test state timer counter. /*********************************************************************//** * @brief * The initSafetyShutdown function initializes the Buttons module. * @details Inputs: none * @details Outputs: Safety Shutdown module signal output set to initial state. * @return none *************************************************************************/ void initSafetyShutdown( void ) { safetyShutdownActivated = FALSE; safetyShutdownOverrideResetState = FALSE; safetyShutdownSelfTestState = SAFETY_SHUTDOWN_SELF_TEST_STATE_START; safetyShutdownSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; safetyShutdownSelfTestTimerCount = 0; CLR_SAFETY_SHUTDOWN(); } /*********************************************************************//** * @brief * The activateSafetyShutdown function activates the safety shutdown signal. * @details Inputs: none * @details Outputs: Safety Shutdown signal output set to active state. * @return none *************************************************************************/ void activateSafetyShutdown( void ) { safetyShutdownActivated = TRUE; SET_SAFETY_SHUTDOWN(); SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_SAFETY_LINE, 1, 0 ) } /*********************************************************************//** * @brief * The isSafetyShutdownActivated function returns whether the safety shutdown * signal has been activated. * @details Inputs: none * @details Outputs: none * @return safetyShutdownActivated *************************************************************************/ BOOL isSafetyShutdownActivated( void ) { return safetyShutdownActivated; } /*********************************************************************//** * @brief * The execSafetyShutdownTest function executes the safety shutdown test. * This function should be called periodically until a pass or fail * result is returned. * @details Inputs: safetyShutdownSelfTestState * @details Outputs: safetyShutdownSelfTestState * @return in progress, passed, or failed *************************************************************************/ SELF_TEST_STATUS_T execSafetyShutdownTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; switch ( safetyShutdownSelfTestState ) { case SAFETY_SHUTDOWN_SELF_TEST_STATE_START: { F32 v24 = getIntADCVoltageConverted( INT_ADC_24V_ACTUATORS ); safetyShutdownSelfTestState = SAFETY_SHUTDOWN_SELF_TEST_STATE_IN_PROGRESS; // Verify 24V is up if ( v24 < MIN_24V_LEVEL_ON_SAFETY_RECOVER ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SAFETY_SHUTDOWN_POST_TEST_FAILED, (F32)SAFETY_POST_24V_INITIAL, v24 ) safetyShutdownSelfTestStatus = SELF_TEST_STATUS_FAILED; } safetyShutdownSelfTestTimerCount = getMSTimerCount(); activateSafetyShutdown(); } break; case SAFETY_SHUTDOWN_SELF_TEST_STATE_IN_PROGRESS: if ( TRUE == didTimeout( safetyShutdownSelfTestTimerCount, SAFETY_SHUTDOWN_POST_TIMEOUT_MS ) ) { F32 v24 = getIntADCVoltageConverted( INT_ADC_24V_ACTUATORS ); F32 audioCurrent = getFPGABackupAlarmAudioCurrent(); // Verify 24V is down when w.d. expired if ( v24 > MAX_24V_LEVEL_ON_SAFETY_SHUTDOWN ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SAFETY_SHUTDOWN_POST_TEST_FAILED, (F32)SAFETY_POST_24V_NOT_CUT, v24 ) safetyShutdownSelfTestStatus = SELF_TEST_STATUS_FAILED; } safetyShutdownSelfTestTimerCount = getMSTimerCount(); CLR_SAFETY_SHUTDOWN(); safetyShutdownActivated = FALSE; safetyShutdownSelfTestState = SAFETY_SHUTDOWN_SELF_TEST_STATE_RECOVER; } break; case SAFETY_SHUTDOWN_SELF_TEST_STATE_RECOVER: if ( TRUE == didTimeout( safetyShutdownSelfTestTimerCount, SAFETY_SHUTDOWN_RECOVERY_TIME_MS ) ) { F32 v24 = getIntADCVoltageConverted( INT_ADC_24V_ACTUATORS ); F32 audioCurrent = getFPGABackupAlarmAudioCurrent(); // Verify 24V is down when w.d. recovered if ( v24 < MIN_24V_LEVEL_ON_SAFETY_RECOVER ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SAFETY_SHUTDOWN_POST_TEST_FAILED, (F32)SAFETY_POST_NO_24V_RESTORE, v24 ) safetyShutdownSelfTestStatus = SELF_TEST_STATUS_FAILED; } else { safetyShutdownSelfTestStatus = SELF_TEST_STATUS_PASSED; } safetyShutdownSelfTestState = SAFETY_SHUTDOWN_SELF_TEST_STATE_COMPLETE; result = safetyShutdownSelfTestStatus; } break; case SAFETY_SHUTDOWN_SELF_TEST_STATE_COMPLETE: // If we get called in this state, assume we are doing self-test again result = SELF_TEST_STATUS_IN_PROGRESS; safetyShutdownSelfTestState = SAFETY_SHUTDOWN_SELF_TEST_STATE_START; break; default: result = SELF_TEST_STATUS_FAILED; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_SAFETY_SHUTDOWN_INVALID_SELF_TEST_STATE, safetyShutdownSelfTestState ) break; } return result; } /*********************************************************************//** * @brief * The resetSafetyShutdownPOSTState function resets safety shutdown POST state. * @details Inputs: none * @details Outputs: safetyShutdownSelfTestState * @return none *************************************************************************/ void resetSafetyShutdownPOSTState( void ) { safetyShutdownSelfTestState = SAFETY_SHUTDOWN_SELF_TEST_STATE_START; } /*********************************************************************//** * @brief * The testSetSafetyShutdownOverride function overrides the HD safety * shutdown. * @details Inputs: none * @details Outputs: HD safety shutdown overridden * @param value TRUE to activate safety shutdown, FALSE to de-activate it. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSafetyShutdownOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { // Remember natural state before override so we can reset safetyShutdownOverrideResetState = safetyShutdownActivated; // Override safety shutdown signal if ( value > 0 ) { activateSafetyShutdown(); } else { safetyShutdownActivated = FALSE; CLR_SAFETY_SHUTDOWN(); } result = TRUE; } return result; } /*********************************************************************//** * @brief * The testResetSafetyShutdownOverride function resets the override of the * HD safety shutdown. * @details Inputs: none * @details Outputs: shutdown override reset * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetSafetyShutdownOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { if ( TRUE == safetyShutdownOverrideResetState ) { activateSafetyShutdown(); } else { safetyShutdownActivated = FALSE; CLR_SAFETY_SHUTDOWN(); } result = TRUE; } return result; } /**@}*/