/************************************************************************** * * 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 Switches.c * * @author (last) Sean * @date (last) 17-Sep-2024 * * @author (original) Sean * @date (original) 17-Sep-2024 * ***************************************************************************/ #include "FpgaTD.h" #include "Messaging.h" //#include "NVDataMgmt.h" #include "Switches.h" #include "TaskGeneral.h" #include "Timers.h" /** * @addtogroup Switches * @{ */ // ********** private definitions ********** #define SWITCHES_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the switches data is published on the CAN bus. #define SWITCHES_DEBOUNCE_TIME_MS ( MS_PER_SECOND / 4 ) ///< Switches FPGA status check interval. #define DATA_PUBLISH_COUNTER_START_COUNT 90 ///< Data publish counter start count. // ********** private data ********** static U32 switchesDataPublicationCounter; ///< Switches data publication counter. static OVERRIDE_U32_T switchesDataPublishInterval; ///< Interval (in ms) at which to publish switches data to CAN bus. static OVERRIDE_U32_T switchesStatus[ NUM_OF_SWITCHES ]; ///< Debounced switch states. static U32 switchDebounceStartTimes[ NUM_OF_SWITCHES ]; ///< Switch debounce start times. static BOOL requireDoorClosed; ///< Flag indicates whether door is required to be closed in current state. // ********** private function prototypes ********** static void publishSwitchesData( void ); static void handleSwitchAlarms( void ); /*********************************************************************//** * @brief * The initSwitches function initializes the switches unit. * @details \b Inputs: none * @details \b Outputs: Switches monitor unit initialized * @return none *************************************************************************/ void initSwitches( void ) { U32 i; switchesDataPublicationCounter = DATA_PUBLISH_COUNTER_START_COUNT; requireDoorClosed = FALSE; switchesDataPublishInterval.data = SWITCHES_DATA_PUB_INTERVAL; switchesDataPublishInterval.ovData = SWITCHES_DATA_PUB_INTERVAL; switchesDataPublishInterval.ovInitData = 0; switchesDataPublishInterval.override = OVERRIDE_RESET; // Initialize all the switches for ( i = 0; i < NUM_OF_SWITCHES; i++ ) { switchesStatus[ i ].data = (U32)STATE_CLOSED; switchesStatus[ i ].ovData = (U32)STATE_CLOSED; switchesStatus[ i ].ovInitData = (U32)STATE_CLOSED; switchesStatus[ i ].override = OVERRIDE_RESET; switchDebounceStartTimes[ i ] = 0; } } /*********************************************************************//** * @brief * The execSwitches function executes the switches monitor executive. * @details \b Inputs: switchesStatus * @details \b Outputs: switchesStatus * @return none *************************************************************************/ void execSwitches( void ) { U32 i; OPN_CLS_STATE_T currentSwitchStates[ NUM_OF_SWITCHES ]; // Get current state of each switch currentSwitchStates[ H9_SWCH ] = ( FALSE == getFPGAFrontDoorClosedStatus() ? STATE_OPEN : STATE_CLOSED ); // Debounce each switch for ( i = 0; i < NUM_OF_SWITCHES; i++ ) { #ifndef _RELEASE_ // if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_SWITCHES_MONITOR ) ) // { // switchesStatus[ i ].status.data = STATE_CLOSED; // } // else #endif { // Check if the current switch status is not the same as the recorded data if ( (U32)currentSwitchStates[ i ] != switchesStatus[ i ].data ) { // If the debounce time is 0, start the timer if ( 0 == switchDebounceStartTimes[ i ] ) { switchDebounceStartTimes[ i ] = getMSTimerCount(); } // If the debounce time has been elapsed, update the switch status to the new status else if ( TRUE == didTimeout( switchDebounceStartTimes[ i ], SWITCHES_DEBOUNCE_TIME_MS ) ) { // If the bit is 0, the door switch is open, because it is normally open switch switchDebounceStartTimes[ i ] = 0; switchesStatus[ i ].data = currentSwitchStates[ i ]; } } else { switchDebounceStartTimes[ i ] = 0; } } } // Check for switch alarms handleSwitchAlarms(); // Handle publishing switches data publishSwitchesData(); } /*********************************************************************//** * @brief * The handleSwitchAlarms function checks for switch related alarms. * @details \b Alarm: ALARM_ID_TD_CARTRIDGE_DOOR_OPENED if door is open when * it should be closed. * @details \b Inputs: requireDoorClosed, switchesStatus * @details \b Outputs: switchesStatus * @return none *************************************************************************/ static void handleSwitchAlarms( void ) { #ifndef _RELEASE_ // if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SWITCHES_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) #endif { // Check for door closed alarm if ( TRUE == requireDoorClosed ) { if ( getSwitchState( H9_SWCH ) != STATE_CLOSED ) { activateAlarmNoData( ALARM_ID_TD_CARTRIDGE_DOOR_OPENED ); } } // Handle clearing alarm conditions if ( STATE_CLOSED == getSwitchState( H9_SWCH ) ) { clearAlarmCondition( ALARM_ID_TD_CARTRIDGE_DOOR_OPENED ); } } } /*********************************************************************//** * @brief * The getSwitchState function returns the state of a given switch. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given switch ID is invalid. * @details \b Inputs: switchesStatus * @details \b Outputs: switchesStatus * @param switchId ID of switch to get state for * @return switch state of given switch *************************************************************************/ OPN_CLS_STATE_T getSwitchState( SWITCH_T switchId ) { U32 state = 0; if ( switchId < NUM_OF_SWITCHES ) { state = switchesStatus[ switchId ].data; if ( OVERRIDE_KEY == switchesStatus[ switchId ].override ) { state = switchesStatus[ switchId ].ovData; } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_INVALID_SWITCH_ID, (U32)switchId ) } return (OPN_CLS_STATE_T)state; } /*********************************************************************//** * @brief * The doorClosedRequired function sets flags that determine whether door * and pump tracks should be closed/locked in current state. Associated * alarms will be triggered if switches not in required state. * @details \b Inputs: none * @details \b Outputs: requireDoorClosed * @param door is door required to be closed in current state? * @return none *************************************************************************/ void doorClosedRequired( BOOL door ) { requireDoorClosed = door; } /*********************************************************************//** * @brief * The publishSwitchesData function broadcasts the switches data at the * publication interval. * @details \b Message \b Sent: MSG_ID_TD_SWITCHES_DATA * @details \b Inputs: switchesDataPublicationCounter * @details \b Outputs: switchesDataPublicationCounter * @return none *************************************************************************/ static void publishSwitchesData( void ) { if ( ++switchesDataPublicationCounter >= getU32OverrideValue( &switchesDataPublishInterval ) ) { SWITCHES_DATA_T data; switchesDataPublicationCounter = 0; data.h9Door = (U32)getSwitchState( H9_SWCH ); broadcastData( MSG_ID_TD_SWITCHES_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( SWITCHES_DATA_T ) ); } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSwitchesDataPublishIntervalOverride function overrides the interval * at which the TD switches data is published. * @details \b Inputs: none * @details \b Outputs: switchesDataPublishInterval * @param message Override message from Dialin which includes the interval * (in ms) to override the switches broadcast interval to. * @return TRUE if override request is successful, FALSE if not *************************************************************************/ BOOL testSwitchesDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &switchesDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testSwitchOverride function overrides the state for a given switch. * @details \b Inputs: none * @details \b Outputs: switchesStatus[] * @param message Override message from Dialin which includes an ID of * the switch to override and the state to override the switch to. * @return TRUE if override request is successful, FALSE if not *************************************************************************/ BOOL testSwitchOverride( MESSAGE_T *message ) { BOOL result = u32ArrayOverride( message, &switchesStatus[0], NUM_OF_SWITCHES - 1, 0, NUM_OF_OPN_CLS_STATES - 1 ); return result; } /**@}*/