/************************************************************************** * * Copyright (c) 2024-2025 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 CpldInterface.c * * @author (last) Sean Nash * @date (last) 24-Oct-2024 * * @author (original) Sean Nash * @date (original) 07-Aug-2024 * ***************************************************************************/ #include "gio.h" #include "mibspi.h" #include "CpldInterface.h" #include "GPIO.h" #include "Messaging.h" #include "Timers.h" /** * @addtogroup CPLD_Interface * @{ */ // ********** private definitions ********** #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 initCPLD function initializes the CPLD unit. All outputs to CPLD * (watchdog pet,power off request, alarm lamp LEDs and safety shutdown) * are set to low. * @details \b Inputs: none * @details \b Outputs: CPLD unit signal outputs set to initial states. * @return none *************************************************************************/ void initCPLD( void ) { // Initialize watchdog pet output low (inactive) clrWatchdogPetSignal(); // Initialize power off request output low (inactive) clrPowerOffRequestSignal(); // Initialize alarm lamp color LED outputs low (off) clrAlarmLampGreenSignal(); clrAlarmLampRedSignal(); clrAlarmLampBlueSignal(); // Initialize safety shutdown clrSafetyShutdownSignal(); safetyShutdownActivated = FALSE; safetyShutdownOverrideResetState = FALSE; safetyShutdownSelfTestState = SAFETY_SHUTDOWN_SELF_TEST_STATE_START; safetyShutdownSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; safetyShutdownSelfTestTimerCount = 0; } /*********************************************************************//** * @brief * The toggleCPLDWatchdog function toggles the watchdog pet signal to CPLD. * @details \b Inputs: none * @details \b Outputs: watchdog pet signal toggled. * @return none *************************************************************************/ void toggleCPLDWatchdog( void ) { toggleWatchdogPetSignal(); } /*********************************************************************//** * @brief * The getCPLDSafety function determines the current signal level for the * safety shutdown pin from the CPLD. * @details \b Inputs: Signal from CPLD on safety input pin. * @details \b Outputs: none * @return level of safety line (LOW=active or HIGH=inactive) *************************************************************************/ PIN_SIGNAL_STATE_T getCPLDSafety( void ) { PIN_SIGNAL_STATE_T level = getSafetySignal(); return level; } /*********************************************************************//** * @brief * The getCPLDACPowerLossDetected function determines whether the CPLD is * reporting A/C power has been lost. * @details \b Inputs: Signal from CPLD on A/C presence pin (LOW=AC Power Lost). * @details \b Outputs: none * @return TRUE if A/C power loss is detected, FALSE if not *************************************************************************/ BOOL getCPLDACPowerLossDetected( void ) { PIN_SIGNAL_STATE_T acLevel = getACPowerPresentSignal(); BOOL acLost = ( PIN_SIGNAL_HIGH == acLevel ? FALSE : TRUE ); return acLost; } /*********************************************************************//** * @brief * The setCPLDLampGreen function sets the alarm lamp green signal to CPLD * to given level. * @details \b Inputs: none * @details \b Outputs: alarm lamp green signal set to given level. * @param level LOW (green off) or HIGH (green on) * @return none *************************************************************************/ void setCPLDLampGreen( PIN_SIGNAL_STATE_T level ) { if ( level == PIN_SIGNAL_HIGH ) { setAlarmLampGreenSignal(); } else { clrAlarmLampGreenSignal(); } } /*********************************************************************//** * @brief * The setCPLDLampBlue function sets the alarm lamp blue signal to CPLD * to given level. * @details \b Inputs: none * @details \b Outputs: alarm lamp blue signal set to given level. * @param level LOW (blue off) or HIGH (blue on) * @return none *************************************************************************/ void setCPLDLampBlue( PIN_SIGNAL_STATE_T level ) { if ( level == PIN_SIGNAL_HIGH ) { setAlarmLampBlueSignal(); } else { clrAlarmLampBlueSignal(); } } /*********************************************************************//** * @brief * The setCPLDLampRed function sets the alarm lamp red signal to CPLD * to given level. * @details \b Inputs: none * @details \b Outputs: alarm lamp red signal set to given level. * @param level LOW (red off) or HIGH (red on) * @return none *************************************************************************/ void setCPLDLampRed( PIN_SIGNAL_STATE_T level ) { if ( level == PIN_SIGNAL_HIGH ) { setAlarmLampRedSignal(); } else { clrAlarmLampRedSignal(); } } /*********************************************************************//** * @brief * The toggleCPLDOffRequest function toggles the off request signal to CPLD. * The off request signal must be toggled 4 times, once every 50 ms, in order * for the CPLD to accept the off request sequence and initiate system power * down. * @details \b Inputs: none * @details \b Outputs: off request signal toggled. * @return none *************************************************************************/ void toggleCPLDOffRequest( void ) { togglePowerOffRequestSignal(); } /*********************************************************************//** * @brief * The getCPLDOffButton function determines the current signal level * on the off button pin from the CPLD. * @details \b Inputs: Signal from CPLD on off button pin. * @details \b Outputs: none * @return level (LOW=released or HIGH=depressed) *************************************************************************/ PIN_SIGNAL_STATE_T getCPLDOffButton( void ) { PIN_SIGNAL_STATE_T level = getOffButtonSignal(); return level; } /*********************************************************************//** * @brief * The getCPLDStopButton function determines the current signal level * on the stop button pin from the CPLD. * @details \b Inputs: Signal from CPLD on stop button pin. * @details \b Outputs: none * @return level (LOW=released or HIGH=depressed) *************************************************************************/ PIN_SIGNAL_STATE_T getCPLDStopButton( void ) { PIN_SIGNAL_STATE_T level = getStopButtonSignal(); return level; } /*********************************************************************//** * @brief * The activateSafetyShutdown function activates the safety shutdown signal. * @details \b Message \b Sent: MSG_ID_TD_EVENT for software activated safety * shutdown event. * @details \b Inputs: none * @details \b Outputs: safetyShutdownActivated, Safety Shutdown signal output * set to active state. * @return none *************************************************************************/ void activateSafetyShutdown( void ) { safetyShutdownActivated = TRUE; setSafetyShutdownSignal(); SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SAFETY_LINE, 1, 0 ) } /*********************************************************************//** * @brief * The isSafetyShutdownActivated function returns whether the safety shutdown * signal has been activated by software. * @note The safety shutdown signal can also be activated by other causes * (e.g. watchdog expiration). * @details \b Inputs: safetyShutdownActivated * @details \b Outputs: none * @return TRUE if software has activated safety shutdown, FALSE if not *************************************************************************/ 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 \b Alarm: ALARM_ID_HD_SAFETY_SHUTDOWN_POST_TEST_FAILED if self-test fails. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if self-test state is invalid. * @details \b Inputs: safetyShutdownSelfTestState * @details \b 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(); clrSafetyShutdownSignal(); 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_TD_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 \b Inputs: none * @details \b Outputs: safetyShutdownSelfTestState * @return none *************************************************************************/ void resetSafetyShutdownPOSTState( void ) { safetyShutdownSelfTestState = SAFETY_SHUTDOWN_SELF_TEST_STATE_START; } /*********************************************************************//** * @brief * The testSafetyShutdownOverride function overrides the safety * shutdown. * @details \b Inputs: none * @details \b 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 testSafetyShutdownOverride( MESSAGE_T *message ) { BOOL result = FALSE; TEST_OVERRIDE_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); // Verify tester has logged in with f/w and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { BOOL value = (BOOL)payload.state.u32; // Remember natural state before override so we can reset safetyShutdownOverrideResetState = safetyShutdownActivated; // Override safety shutdown signal if ( value > 0 ) { activateSafetyShutdown(); } else { safetyShutdownActivated = FALSE; clrSafetyShutdownSignal(); } result = TRUE; } return result; } /*********************************************************************//** * @brief * The testResetSafetyShutdownOverride function resets the override of the * safety shutdown. * @details \b Inputs: none * @details \b 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; clrSafetyShutdownSignal(); } result = TRUE; } return result; } /**@}*/