/************************************************************************** * * Copyright (c) 2019-2020 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 WatchdogMgmt.c * * @author (last) Quang Nguyen * @date (last) 14-Sep-2020 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 * ***************************************************************************/ #include "CPLD.h" #include "InternalADC.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "Timers.h" #include "WatchdogMgmt.h" /** * @addtogroup WatchdogMgmt * @{ */ // ********** private definitions ********** #define MIN_WATCHDOG_PET_INTERVAL_MS 45 ///< Minimum watchdog pet interval. #define WATCHDOG_POST_TIMEOUT_MS 500 ///< Watchdog POST timeout in ms. #define WATCHDOG_RECOVERY_TIME_MS 750 ///< Watchdog recovery time in ms. #define MAX_24V_LEVEL_ON_WATCHDOG_EXPIRED 5.0 ///< Maximum voltage on 24V line when watchdog is expired. // TODO - check w/ Systems. Takes time for V to bleed off. Had to raise to 5V. #define MIN_24V_LEVEL_ON_WATCHDOG_RECOVER 22.6 ///< Minimum voltage on 24V line when watchdog is recovered. /// List of watchdog states. typedef enum Button_Self_Test_States { WATCHDOG_SELF_TEST_STATE_START = 0, ///< Watchdog self-test state start WATCHDOG_SELF_TEST_STATE_IN_PROGRESS, ///< watchdog self-test state in progress WATCHDOG_SELF_TEST_STATE_RECOVER, ///< Watchdog self-test state recover WATCHDOG_SELF_TEST_STATE_COMPLETE, ///< Watchdog self-test state complete NUM_OF_WATCHDOG_SELF_TEST_STATES ///< Number of watchdog self-test states } WATCHDOG_SELF_TEST_STATE_T; // ********** private data ********** static U32 lastWatchdogPetTime = 0; ///< Previous watchdog pet timestamp (in ms). static OVERRIDE_U32_T watchdogTaskCheckedIn[ NUM_OF_TASKS ]; ///< Array of flags indicating whether individual tasks have checked in with watchdog manager. static WATCHDOG_SELF_TEST_STATE_T watchdogSelfTestState; ///< Watchdog self-test current state. static SELF_TEST_STATUS_T watchdogSelfTestStatus; ///< Watchdog self-test status. static U32 watchdogSelfTestTimerCount = 0; ///< Watchdog self-test timer count. // ********** private function prototypes ********** static void resetWDTaskCheckIns( void ); static BOOL haveAllTasksCheckedIn( void ); static void petWatchdog( void ); static BOOL hasTaskGeneralCheckedIn( U32 task ); /*********************************************************************//** * @brief * The initWatchdogMgmt function initializes the WatchdogMgmt module. * @details Inputs: none * @details Outputs: WatchdogMgmt module initialized. * @return none *************************************************************************/ void initWatchdogMgmt( void ) { U32 i; lastWatchdogPetTime = 0; watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_START; watchdogSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; watchdogSelfTestTimerCount = 0; // initialize task check-ins to false for ( i = 0; i < NUM_OF_TASKS; i++ ) { watchdogTaskCheckedIn[ i ].data = FALSE; watchdogTaskCheckedIn[ i ].ovData = FALSE; watchdogTaskCheckedIn[ i ].ovInitData = FALSE; watchdogTaskCheckedIn[ i ].override = OVERRIDE_RESET; } } /*********************************************************************//** * @brief * The execWatchdogMgmt function executes the watchdog management service. * @details Inputs: watchdogTaskCheckedIn[] * @details Outputs: Pets watchdog when all tasks checked in * @return none *************************************************************************/ void execWatchdogMgmt( void ) { BOOL allTasksCheckedIn; // called by background task, so give bg task credit for checking in checkInWithWatchdogMgmt( TASK_BG ); // check to see if all monitored tasks have checked in allTasksCheckedIn = haveAllTasksCheckedIn(); // if all monitored tasks checked in, pet watchdog and clear the slate if ( ( TRUE == allTasksCheckedIn ) && ( didTimeout( lastWatchdogPetTime, MIN_WATCHDOG_PET_INTERVAL_MS ) ) ) { petWatchdog(); resetWDTaskCheckIns(); } // check to see if watchdog has expired if ( PIN_SIGNAL_LOW == getCPLDWatchdogExpired() ) { // ignore expired watchdog until after watchdog POST if ( ( WATCHDOG_SELF_TEST_STATE_COMPLETE == watchdogSelfTestState ) || ( getCurrentOperationMode() != DG_MODE_INIT ) ) { #ifndef DEBUG_ENABLED activateAlarmNoData( ALARM_ID_WATCHDOG_EXPIRED ); #endif } } } /*********************************************************************//** * @brief * The checkInWithWatchdogMgmt function checks a given task in with the * watchdog management service. * @details Inputs: none * @details Outputs: task is checked in with the watchdog management * @param task the task that is checking in with the watchdog management * @return none *************************************************************************/ void checkInWithWatchdogMgmt( TASK_T task ) { if ( task < NUM_OF_TASKS ) { watchdogTaskCheckedIn[ task ].data = TRUE; } } /*********************************************************************//** * @brief * The execWatchdogTest function executes the watchdog test. This function * should be called periodically until a pass or fail result is returned. * @details Inputs: watchdogSelfTestState * @details Outputs: Executed watchdog self-test * @return in progress, passed, or failed *************************************************************************/ SELF_TEST_STATUS_T execWatchdogTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; switch ( watchdogSelfTestState ) { case WATCHDOG_SELF_TEST_STATE_START: watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_IN_PROGRESS; watchdogSelfTestTimerCount = getMSTimerCount(); // no break here so we pass through directly to in progress processing case WATCHDOG_SELF_TEST_STATE_IN_PROGRESS: while ( FALSE == didTimeout( watchdogSelfTestTimerCount, WATCHDOG_POST_TIMEOUT_MS ) ) { // waiting here for w.d. test period to prevent this task from checking in - watchdog should expire } if ( PIN_SIGNAL_LOW == getCPLDWatchdogExpired() ) { F32 v24 = getIntADCVoltageConverted( INT_ADC_PRIMARY_HEATER_24_VOLTS ); // Verify 24V is down when w.d. expired if ( v24 > MAX_24V_LEVEL_ON_WATCHDOG_EXPIRED ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_WATCHDOG_POST_TEST_FAILED, 2.0, v24 ); watchdogSelfTestStatus = SELF_TEST_STATUS_FAILED; } } else { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_WATCHDOG_POST_TEST_FAILED, 1 ); watchdogSelfTestStatus = SELF_TEST_STATUS_FAILED; } watchdogSelfTestTimerCount = getMSTimerCount(); watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_RECOVER; break; case WATCHDOG_SELF_TEST_STATE_RECOVER: if ( TRUE == didTimeout( watchdogSelfTestTimerCount, WATCHDOG_RECOVERY_TIME_MS ) ) { if ( getCPLDWatchdogExpired() == PIN_SIGNAL_HIGH ) { F32 v24 = getIntADCVoltageConverted( INT_ADC_PRIMARY_HEATER_24_VOLTS ); // Verify 24V is down when w.d. recovered TODO - ask EE team why 24V does not quite recover all the way to 22.6V even after 750 ms. How long should it take? // if ( v24 < MIN_24V_LEVEL_ON_WATCHDOG_RECOVER ) // { // SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_WATCHDOG_POST_TEST_FAILED, 3.0, v24 ); // watchdogSelfTestStatus = SELF_TEST_STATUS_FAILED; // } // else { watchdogSelfTestStatus = SELF_TEST_STATUS_PASSED; } } result = watchdogSelfTestStatus; watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_COMPLETE; } break; case WATCHDOG_SELF_TEST_STATE_COMPLETE: // if we get called in this state, assume we're doing self-test again watchdogSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_START; break; default: result = SELF_TEST_STATUS_FAILED; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_WATCHDOG_INVALID_SELF_TEST_STATE, watchdogSelfTestState ) break; } return result; } /*********************************************************************//** * @brief * The resetWDTaskCheckIns function resets the task check-ins with the watchdog. * @details Inputs: none * @details Outputs: watchdogTaskCheckedIn[] array reset to all false. * @return none *************************************************************************/ static void resetWDTaskCheckIns( void ) { U32 i; // initialize task check-ins to false for ( i = 0; i < NUM_OF_TASKS; i++ ) { watchdogTaskCheckedIn[ i ].data = FALSE; } } /*********************************************************************//** * @brief * The haveAllTasksCheckedIn function determines whether all tasks have * checked in with watchdog mgmt. * @details Inputs: watchdogTaskCheckedIn[] * @details Outputs: none * @return TRUE if all tasks have checked in since last watchdog pet, FALSE if not. *************************************************************************/ static BOOL haveAllTasksCheckedIn( void ) { BOOL result = TRUE; U32 i; // check that each task has checked in for ( i = 0; i < NUM_OF_TASKS; i++ ) { if ( FALSE == hasTaskGeneralCheckedIn( i ) ) { result = FALSE; break; } } return result; } /*********************************************************************//** * @brief * The hasTaskGeneralCheckedIn function gets the check-in state of a given task. * @details Inputs: watchdogTaskCheckedIn[] * @details Outputs: none * @param task ID of task to check * @return TRUE if given task has checked in, FALSE if not *************************************************************************/ static BOOL hasTaskGeneralCheckedIn( U32 task ) { BOOL result = FALSE; if ( task < NUM_OF_TASKS ) { result = (BOOL)getU32OverrideValue( &watchdogTaskCheckedIn[ task ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_TASK, task ); } return result; } /*********************************************************************//** * @brief * The petWatchdog function pets the watchdog by pulsing the CPLD WD pet signal. * @details Inputs: none * @details Outputs: CPLD WD pet signal is pulsed * @return none *************************************************************************/ static void petWatchdog( void ) { // pulse the watchdog signal toggleCPLDWatchdog(); // remember when we last pet the watchdog lastWatchdogPetTime = getMSTimerCount(); } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetWatchdogTaskCheckInOverride function overrides the state of the * task check-in with the watchdog management with a given check-in state. * @details Inputs: none * @details Outputs: watchdogTaskCheckedIn[] * @param task ID of task to override check-in state for * @param value override state for the given task ID * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetWatchdogTaskCheckInOverride( U32 task, BOOL value ) { BOOL result = FALSE; if ( task < NUM_OF_TASKS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; watchdogTaskCheckedIn[ task ].ovData = value; watchdogTaskCheckedIn[ task ].override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetWatchdogTaskCheckInOverride function resets the override of the * state of the check-in with the watchdog management. * @details Inputs: none * @details Outputs: watchdogTaskCheckedIn[] * @param task ID of task to override check-in state for * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetWatchdogTaskCheckInOverride( U32 task ) { BOOL result = FALSE; if ( task < NUM_OF_TASKS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; watchdogTaskCheckedIn[ task ].override = OVERRIDE_RESET; watchdogTaskCheckedIn[ task ].ovData = watchdogTaskCheckedIn[ task ].ovInitData; } } return result; } /**@}*/