/************************************************************************** * * 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 AirTrap.c * * @author (last) Sean Nash * @date (last) 16-Sep-2020 * * @author (original) Sean * @date (original) 16-Sep-2020 * ***************************************************************************/ #include "AirTrap.h" #include "AlarmMgmt.h" #include "FPGA.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TaskPriority.h" #include "Timers.h" /** * @addtogroup AirTrap * @{ */ // ********** private definitions ********** #define AIR_TRAP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< interval (ms/task time) at which the air trap data is published on the CAN bus. /// Defined states for the air trap controller state machine. typedef enum AirTrap_States { AIR_TRAP_INIT_STATE = 0, ///< Initialization state AIR_TRAP_MANUAL_CONTROL_STATE, ///< Manually control air trap valve state AIR_TRAP_VALVE_CLOSED_STATE, ///< Valve closed state - until air detected at lower level AIR_TRAP_VALVE_OPEN_STATE, ///< Valve open state - until fluid detected at upper level NUM_OF_AIR_TRAP_STATES ///< Number of air trap controller states } AIR_TRAP_STATE_T; /// Defined states for the air trap self-test state machine. typedef enum AirTrap_Self_Test_States { AIR_TRAP_SELF_TEST_STATE_START = 0, ///< Self-test start state AIR_TRAP_SELF_TEST_STATE_IN_PROGRESS, ///< Self-test in progress state AIR_TRAP_SELF_TEST_STATE_COMPLETE, ///< Self-test completed state NUM_OF_AIR_TRAP_SELF_TEST_STATES ///< Number of air trap self-test states } AIR_TRAP_SELF_TEST_STATE_T; // ********** private data ********** static AIR_TRAP_STATE_T airTrapControllerState; ///< current state of air trap controller state machine. static U32 airTrapDataPublicationTimerCounter = 0; ///< used to schedule air trap data publication to CAN bus. /// interval (in ms) at which to publish air trap data to CAN bus. static OVERRIDE_U32_T airTrapDataPublishInterval = { AIR_TRAP_DATA_PUB_INTERVAL, AIR_TRAP_DATA_PUB_INTERVAL, 0, 0 }; static OVERRIDE_U32_T airTrapLevels[ NUM_OF_AIR_TRAP_LEVEL_SENSORS ]; ///< detected air trap level for each level sensor. static AIR_TRAP_SELF_TEST_STATE_T airTrapSelfTestState; ///< current air trap self-test state. static U32 airTrapSelfTestTimerCount = 0; ///< timer counter for air trap self-test. static BOOL pendingStartAirTrapController = FALSE; ///< flag indicates an air trap controller start request is pending. static BOOL pendingStopAirTrapController = FALSE; ///< flag indicates an air trap controller stop request is pending. // ********** private function prototypes ********** static AIR_TRAP_STATE_T handleAirTrapManualControlState( void ); static AIR_TRAP_STATE_T handleAirTrapValveClosedState( void ); static AIR_TRAP_STATE_T handleAirTrapValveOpenState( void ); static void publishAirTrapData( void ); static U32 getPublishAirTrapDataInterval( void ); /*********************************************************************//** * @brief * The initAirTrap function initializes the Air Trap module. * @details * Inputs : none * Outputs : Air Trap module initialized. * @return none *************************************************************************/ void initAirTrap( void ) { resetAirTrap(); airTrapSelfTestState = AIR_TRAP_SELF_TEST_STATE_START; } /*********************************************************************//** * @brief * The resetAirTrap function resets certain parts of the air trap module * between treatments. * @details * Inputs : none * Outputs : Air Trap module reset. * @return none *************************************************************************/ void resetAirTrap( void ) { airTrapControllerState = AIR_TRAP_INIT_STATE; pendingStartAirTrapController = FALSE; pendingStopAirTrapController = FALSE; } /*********************************************************************//** * @brief * The startAirTrapControl function requests a start to air trap control. * @details * Inputs : airTrapControllerState * Outputs : pendingStartAirTrapController * @return none *************************************************************************/ void startAirTrapControl( void ) { if ( FALSE == isAirTrapControlling() ) { pendingStartAirTrapController = TRUE; } } /*********************************************************************//** * @brief * The endAirTrapControl function requests a stop to air trap control. * @details * Inputs : airTrapControllerState * Outputs : pendingStopAirTrapController * @return none *************************************************************************/ void endAirTrapControl( void ) { if ( TRUE == isAirTrapControlling() ) { pendingStopAirTrapController = TRUE; setValveAirTrap( STATE_CLOSED ); // always exit air trap valve control w/ valve closed. } } /*********************************************************************//** * @brief * The isAirTrapControlling function determines whether the air trap is * currently controlling. * @details * Inputs : airTrapControllerState * Outputs : none * @return TRUE if air trap is currently controlling, FALSE if not. *************************************************************************/ BOOL isAirTrapControlling( void ) { BOOL result = FALSE; if ( airTrapControllerState >= AIR_TRAP_VALVE_CLOSED_STATE ) { result = TRUE; } return result; } /*********************************************************************//** * @brief * The execAirTrapMonitor function executes the air trap monitor. * @details * Inputs : TBD * Outputs : airTrapLevels[] * @return none *************************************************************************/ void execAirTrapMonitor( void ) { BOOL lower, upper; // get latest level readings getFPGAAirTrapLevels( &lower, &upper ); airTrapLevels[ AIR_TRAP_LEVEL_SENSOR_LOWER ].data = (U32)( TRUE == lower ? AIR_TRAP_LEVEL_AIR : AIR_TRAP_LEVEL_FLUID ); airTrapLevels[ AIR_TRAP_LEVEL_SENSOR_UPPER ].data = (U32)( TRUE == upper ? AIR_TRAP_LEVEL_AIR : AIR_TRAP_LEVEL_FLUID ); // check level readings are valid if ( ( TRUE == lower ) && ( FALSE == upper ) ) { // TODO - fault if illegal level readings persist // TODO - close valve and end valve control } } /*********************************************************************//** * @brief * The execAirTrapController function executes the air trap control state machine. * @details * Inputs : airTrapControllerState * Outputs : airTrapControllerState * @return none *************************************************************************/ void execAirTrapController( void ) { // execute air trap state machine switch( airTrapControllerState ) { case AIR_TRAP_INIT_STATE: airTrapControllerState = AIR_TRAP_MANUAL_CONTROL_STATE; break; case AIR_TRAP_MANUAL_CONTROL_STATE: airTrapControllerState = handleAirTrapManualControlState(); break; case AIR_TRAP_VALVE_CLOSED_STATE: airTrapControllerState = handleAirTrapValveClosedState(); break; case AIR_TRAP_VALVE_OPEN_STATE: airTrapControllerState = handleAirTrapValveOpenState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (U32)SW_FAULT_ID_AIR_TRAP_INVALID_STATE, (U32)airTrapControllerState ) airTrapControllerState = AIR_TRAP_INIT_STATE; break; } // publish air trap data if due publishAirTrapData(); } /*********************************************************************//** * @brief * The handleAirTrapManualControlState function handles the manual control * state of the air trap. * @details * Inputs : pendingStartAirTrapController * Outputs : none * @return next state *************************************************************************/ static AIR_TRAP_STATE_T handleAirTrapManualControlState( void ) { AIR_TRAP_STATE_T result = AIR_TRAP_MANUAL_CONTROL_STATE; // transition to valve control states when requested if ( TRUE == pendingStartAirTrapController ) { pendingStartAirTrapController = FALSE; setValveAirTrap( STATE_CLOSED ); result = AIR_TRAP_VALVE_CLOSED_STATE; } return result; } /*********************************************************************//** * @brief * The handleAirTrapValveClosedState function handles the valve closed state * of the air trap. * @details * Inputs : pendingStopAirTrapController, airTrapLevels[] * Outputs : none * @return next state *************************************************************************/ static AIR_TRAP_STATE_T handleAirTrapValveClosedState( void ) { AIR_TRAP_STATE_T result = AIR_TRAP_VALVE_CLOSED_STATE; // transition to manual valve control state when requested if ( TRUE == pendingStopAirTrapController ) { pendingStopAirTrapController = FALSE; result = AIR_TRAP_MANUAL_CONTROL_STATE; } // transition to open valve state when air detected at lower level else if ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) { setValveAirTrap( STATE_OPEN ); result = AIR_TRAP_VALVE_OPEN_STATE; } return result; } /*********************************************************************//** * @brief * The handleAirTrapValveOpenState function handles the valve open state of * the air trap. * @details * Inputs : pendingStopAirTrapController, airTrapLevels[] * Outputs : none * @return next state *************************************************************************/ static AIR_TRAP_STATE_T handleAirTrapValveOpenState( void ) { AIR_TRAP_STATE_T result = AIR_TRAP_VALVE_OPEN_STATE; // transition to manual valve control state when requested if ( TRUE == pendingStopAirTrapController ) { pendingStopAirTrapController = FALSE; result = AIR_TRAP_MANUAL_CONTROL_STATE; } // transition to closed valve state when fluid detected at upper level else if ( AIR_TRAP_LEVEL_FLUID == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) { setValveAirTrap( STATE_CLOSED ); result = AIR_TRAP_VALVE_CLOSED_STATE; } return result; } /*********************************************************************//** * @brief * The getAirTrapLevel function gets the current reading for the given * level sensor. * @details * Inputs : airTrapLevels[] * Outputs : none * @param sensor ID of level sensor to get reading for * @return the current level sensor reading for the given sensor (air or fluid). *************************************************************************/ AIR_TRAP_LEVELS_T getAirTrapLevel( AIR_TRAP_LEVEL_SENSORS_T sensor ) { AIR_TRAP_LEVELS_T result; if ( sensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS ) { result = (AIR_TRAP_LEVELS_T)airTrapLevels[ sensor ].data; if ( OVERRIDE_KEY == airTrapLevels[ sensor ].override ) { result = (AIR_TRAP_LEVELS_T)airTrapLevels[ sensor ].ovData; } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (U32)SW_FAULT_ID_AIR_TRAP_INVALID_LEVEL_SENSOR, (U32)sensor ) result = AIR_TRAP_LEVEL_AIR; } return result; } /*********************************************************************//** * @brief * The getPublishAirTrapDataInterval function gets the air trap data * publication interval. * @details * Inputs : airTrapDataPublishInterval * Outputs : none * @return the current air trap data publication interval (in task intervals). *************************************************************************/ static U32 getPublishAirTrapDataInterval( void ) { U32 result = airTrapDataPublishInterval.data; if ( OVERRIDE_KEY == airTrapDataPublishInterval.override ) { result = airTrapDataPublishInterval.ovData; } return result; } /*********************************************************************//** * @brief * The publishAirTrapData function publishes air trap data at the set interval. * @details * Inputs : airTrapLevels[] * Outputs : if broadcast is due, send air trap data * @return none *************************************************************************/ static void publishAirTrapData( void ) { // publish air trap data on interval if ( ++airTrapDataPublicationTimerCounter >= getPublishAirTrapDataInterval() ) { AIR_TRAP_LEVELS_T lowLevel = getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ); AIR_TRAP_LEVELS_T highLevel = getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ); broadcastAirTrapData( lowLevel, highLevel ); airTrapDataPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The execAirTrapTest function executes the state machine for the air trap * self-test. * @details * Inputs : none * Outputs : none * @return the current state of the PresOccl self-test. *************************************************************************/ SELF_TEST_STATUS_T execAirTrapTest( void ) { SELF_TEST_STATUS_T status = SELF_TEST_STATUS_PASSED; // TODO - implement POST return status; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetAirTrapDataPublishIntervalOverride function overrides the * air trap data publish interval. * @details * Inputs : none * Outputs : airTrapDataPublishInterval * @param value override air trap data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetAirTrapDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_GENERAL_INTERVAL; result = TRUE; airTrapDataPublishInterval.ovData = intvl; airTrapDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetAirTrapDataPublishIntervalOverride function resets the override * of the air trap data publish interval. * @details * Inputs : none * Outputs : airTrapDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetAirTrapDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; airTrapDataPublishInterval.override = OVERRIDE_RESET; airTrapDataPublishInterval.ovData = airTrapDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetAirTrapLevelOverride function overrides the measured level * for a given level sensor. * @details * Inputs : none * Outputs : airTrapLevels[] * @param sensor ID of level sensor to override * @param level override level sensor with this * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetAirTrapLevelOverride( AIR_TRAP_LEVEL_SENSORS_T sensor, AIR_TRAP_LEVELS_T level ) { BOOL result = FALSE; if ( sensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; airTrapLevels[ sensor ].ovData = (U32)level; airTrapLevels[ sensor ].override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetAirTrapLevelOverride function resets the override of the * level sensor. * @details * Inputs : none * Outputs : airTrapLevels[] * @param sensor ID of level sensor to reset override * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetAirTrapLevelOverride( AIR_TRAP_LEVEL_SENSORS_T sensor ) { BOOL result = FALSE; if ( sensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; airTrapLevels[ sensor ].override = OVERRIDE_RESET; airTrapLevels[ sensor ].ovData = airTrapLevels[ sensor ].ovInitData; } } return result; } /**@}*/