/************************************************************************** * * Copyright (c) 2019-2019 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 Buttons.c * * @date 20-Sep-2019 * @author S. Nash * * @brief Monitor/Controller for the off and stop buttons. * **************************************************************************/ #include "Common.h" #include "CPLD.h" #include "TaskPriority.h" #include "Timers.h" #include "OperationModes.h" #include "Buttons.h" // ********** private definitions ********** typedef enum Button_States { BUTTON_STATE_RELEASED = 0, BUTTON_STATE_PRESSED, NUM_OF_BUTTON_STATES } BUTTON_STATE_T; typedef enum Button_Self_Test_States { BUTTON_SELF_TEST_STATE_START = 0, BUTTON_SELF_TEST_STATE_IN_PROGRESS, BUTTON_SELF_TEST_STATE_COMPLETE, NUM_OF_BUTTON_SELF_TEST_STATES } BUTTON_SELF_TEST_STATE_T; #define OFF_REQUEST_PULSE_COUNT 4 #define OFF_REQUEST_PULSE_INTVL 50 // ms #define STOP_BUTTON_PENDING_TIMEOUT 500 // ms #define STUCK_BUTTON_TIMEOUT 1000 // ms // ********** private data ********** static BUTTON_STATE_T offButtonState = BUTTON_STATE_RELEASED; static BUTTON_STATE_T prevOffButtonState = BUTTON_STATE_RELEASED; static BOOL offButtonPressPending = FALSE; static BUTTON_STATE_T stopButtonState = BUTTON_STATE_RELEASED; static BUTTON_STATE_T prevStopButtonState = BUTTON_STATE_RELEASED; static BOOL stopButtonPressPending = FALSE; static U32 stopButtonPendingTimer = 0; static U32 offRequestPulseCount = 0; static U32 offRequestPulseTimer = 0; static BUTTON_SELF_TEST_STATE_T buttonSelfTestState = BUTTON_SELF_TEST_STATE_START; static U32 buttonSelfTestTimerCount = 0; // ********** private function prototypes ********** static void handleOffButtonProcessing( void ); static void handleStopButtonProcessing( void ); static BOOL isCurrentOpModeOkToTurnOff( void ); /************************************************************************* * @brief initButtons * The initButtons function initializes the Buttons module. * @details * Inputs : none * Outputs : Buttons module initialized. * @param none * @return none *************************************************************************/ void initButtons( void ) { offButtonState = BUTTON_STATE_RELEASED; prevOffButtonState = BUTTON_STATE_RELEASED; offButtonPressPending = FALSE; stopButtonState = BUTTON_STATE_RELEASED; prevStopButtonState = BUTTON_STATE_RELEASED; stopButtonPressPending = FALSE; stopButtonPendingTimer = 0; offRequestPulseCount = 0; offRequestPulseTimer = 0; buttonSelfTestState = BUTTON_SELF_TEST_STATE_START; buttonSelfTestTimerCount = 0; } /************************************************************************* * @brief execButtons * The execButtons function executes the Buttons monitor. * @details * Inputs : none * Outputs : offButtonState, stopButtonState, prevOffButtonState, prevStopButtonState * @param none * @return none *************************************************************************/ void execButtons( void ) { PIN_SIGNAL_STATE_T off = getCPLDOffButton(); PIN_SIGNAL_STATE_T stop = getCPLDStopButton(); // set current button states read from CPLD offButtonState = ( off == PIN_SIGNAL_HIGH ? BUTTON_STATE_PRESSED : BUTTON_STATE_RELEASED ); stopButtonState = ( stop == PIN_SIGNAL_HIGH ? BUTTON_STATE_PRESSED : BUTTON_STATE_RELEASED ); // handle button state transitions for stop button handleStopButtonProcessing(); // handle button state transitions for off button handleOffButtonProcessing(); } /************************************************************************* * @brief isStopButtonPressed * The isStopButtonPressed function determines whether the stop button has been \n * pressed. Once the stop button has transitioned from released to pressed, a \n * press for the stop button will be pending until this function is called. \n * @details * Inputs : stopButtonPressPending * Outputs : stopButtonPressPending * @param button * @return true if the stop button is pressed, false if not *************************************************************************/ BOOL isStopButtonPressed( void ) { BOOL result = stopButtonPressPending; stopButtonPressPending = FALSE; return result; } /************************************************************************* * @brief isButtonPressedRaw * The isButtonPressedRaw function determines whether a given button is currently \n * pressed. * @details * Inputs : offButtonState, prevOffButtonState, stopButtonState, prevStopButtonState * Outputs : none * @param button * @return true if given button is pressed, false if not *************************************************************************/ BOOL isButtonPressedRaw( BUTTON_T button ) { BOOL result = FALSE; switch ( button ) { case BUTTON_OFF: if ( offButtonState == BUTTON_STATE_PRESSED ) { result = TRUE; } break; case BUTTON_STOP: if ( stopButtonState == BUTTON_STATE_PRESSED ) { result = TRUE; } break; default: // TODO - s/w fault break; } return result; } /************************************************************************* * @brief userConfirmOffButton * The userConfirmOffButton function handles user confirmation of the off \n * button. The off request will be initiated here. * @details * Inputs : stopButtonState, prevStopButtonState * Outputs : stopButtonPressPending * @param none * @return none *************************************************************************/ void userConfirmOffButton( void ) { if ( TRUE == isCurrentOpModeOkToTurnOff() ) { offButtonPressPending = TRUE; offRequestPulseCount = OFF_REQUEST_PULSE_COUNT; offRequestPulseTimer = 0; } } /************************************************************************* * @brief execStuckButtonTest * The execStuckButtonTest function executes the stuck button test. \n * This function should be called periodically until a pass or fail \n * result is returned. * @details * Inputs : * Outputs : * @param none * @return in progress, passed, or failed *************************************************************************/ SELF_TEST_STATUS_T execStuckButtonTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; switch ( buttonSelfTestState ) { case BUTTON_SELF_TEST_STATE_START: buttonSelfTestState = BUTTON_SELF_TEST_STATE_IN_PROGRESS; buttonSelfTestTimerCount = getMSTimerCount(); // no break here so we pass through directly to in progress processing case BUTTON_SELF_TEST_STATE_IN_PROGRESS: if ( ( offButtonState == BUTTON_STATE_RELEASED ) && ( stopButtonState == BUTTON_STATE_RELEASED ) ) { result = SELF_TEST_STATUS_PASSED; buttonSelfTestState = BUTTON_SELF_TEST_STATE_COMPLETE; } else if ( TRUE == didTimeout( buttonSelfTestTimerCount, STUCK_BUTTON_TIMEOUT ) ) { result = SELF_TEST_STATUS_FAILED; // TODO - trigger stuck button POST failure buttonSelfTestState = BUTTON_SELF_TEST_STATE_COMPLETE; } // else just stay in progress and wait for next call break; case BUTTON_SELF_TEST_STATE_COMPLETE: // if we get called in this state, assume we're doing self test again buttonSelfTestState = BUTTON_SELF_TEST_STATE_START; break; default: result = SELF_TEST_STATUS_FAILED; // TODO - s/w fault break; } return result; } /************************************************************************* * @brief isCurrentOpModeOkToTurnOff * The isCurrentOpModeOkToTurnOff function determines whether the system can \n * be turned off in current operation mode. * @details * Inputs : Current operation mode. * Outputs : none * @param none * @return true if can turn system off in current mode, false if not *************************************************************************/ static BOOL isCurrentOpModeOkToTurnOff( void ) { OP_MODE opMode = getCurrentOperationMode(); BOOL result = FALSE; if ( ( opMode == MODE_STAN ) || ( opMode == MODE_SERV ) || ( opMode == MODE_FAUL ) ) { result = TRUE; } return result; } /************************************************************************* * @brief handleOffButtonProcessing * The handleOffButtonProcessing function checks for and processes off button \n * activity. * @details * Inputs : offButtonState, prevOffButtonState * Outputs : offButtonPressPending, offRequestPulseCount, offRequestPulseTimer * @param none * @return none *************************************************************************/ static void handleOffButtonProcessing( void ) { // handle button state transitions for off button if ( offButtonState != prevOffButtonState ) { if ( offButtonState == BUTTON_STATE_PRESSED ) { // if off request in a valid mode, send to UI for user confirmation if ( TRUE == isCurrentOpModeOkToTurnOff() ) { // TODO - send off button to UI for user confirmation // TODO - remove later (just pretend user confirmed for now) userConfirmOffButton(); } } prevOffButtonState = offButtonState; } if ( TRUE == offButtonPressPending ) { offRequestPulseTimer += TASK_PRIORITY_INTERVAL; if ( offRequestPulseTimer >= OFF_REQUEST_PULSE_INTVL ) { offRequestPulseTimer = 0; offRequestPulseCount--; if ( offRequestPulseCount == 0 ) { offButtonPressPending = false; } toggleCPLDOffRequest(); } } } /************************************************************************* * @brief handleStopButtonProcessing * The handleStopButtonProcessing function checks for and processes stop button \n * activity. * @details * Inputs : stopButtonState, prevStopButtonState * Outputs : stopButtonPressPending * @param none * @return none *************************************************************************/ static void handleStopButtonProcessing( void ) { // handle button state transitions for stop button if ( stopButtonState != prevStopButtonState ) { if ( stopButtonState == BUTTON_STATE_PRESSED ) { stopButtonPressPending = TRUE; stopButtonPendingTimer = getMSTimerCount(); } prevStopButtonState = stopButtonState; } // handle when a stop button press is pending if ( TRUE == stopButtonPressPending ) { // if stop button not consumed within a reasonable time, s/w fault if ( TRUE == didTimeout( stopButtonPendingTimer, STOP_BUTTON_PENDING_TIMEOUT ) ) { // TODO - s/w fault } } }