/************************************************************************** * * Copyright (c) 2021-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 Bubble.c * * @author (last) Dara Navaei * @date (last) 22-Jun-2023 * * @author (original) Peman Montazemi * @date (original) 06-May-2021 * ***************************************************************************/ #include "AlarmMgmt.h" #include "Bubble.h" #include "FPGA.h" #include "OperationModes.h" #include "Switches.h" #include "SystemCommMessages.h" #include "TaskPriority.h" #include "Timers.h" /** * @addtogroup Bubble * @{ */ // ********** private definitions ********** #define BUBBLE_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the air bubble detector data is published on the CAN bus. #define BUBBLE_TIMEOUT_MS 500 ///< Air bubble detector timeout for self-test (15 ms extended edge detection) #define DATA_PUBLISH_COUNTER_START_COUNT 70 ///< Data publish counter start count. /// Defined states for the air bubble detectors state machine. typedef enum BubbleStates { BUBBLE_NORMAL_STATE = 0, ///< Normal state BUBBLE_SELF_TEST_STATE, ///< Self-test state NUM_OF_BUBBLE_STATES ///< Number of bubble detector states } BUBBLE_STATES_T; // ********** private data ********** static BUBBLE_STATES_T bubblesState[ NUM_OF_BUBBLES ]; ///< Current state of air bubble detectors state machines. static OVERRIDE_U32_T bubblesStatus[ NUM_OF_BUBBLES ]; ///< Detected air bubble status for air bubble detectors. static SELF_TEST_STATUS_T bubblesSelfTestStatus[ NUM_OF_BUBBLES ]; ///< Current status of air bubble detectors self-tests. static U32 bubblesSelfTestStartTime[ NUM_OF_BUBBLES ]; ///< Air bubble detectors self-test start times. static BOOL bubblesSelfTestRequested[ NUM_OF_BUBBLES ]; ///< Air bubble detectors self-test requested flags. static BOOL bubbleDetectionEnabled[ NUM_OF_BUBBLES ]; ///< Flag indicates whether air bubble alarm detection is enabled. /// Interval (in ms) at which to publish air bubble detectors data on CAN bus. static OVERRIDE_U32_T bubblesDataPublishInterval = { BUBBLE_PUB_INTERVAL, BUBBLE_PUB_INTERVAL, 0, 0 }; static U32 bubblesDataPublicationTimerCounter; ///< Timer counter used to schedule air bubble detectors data publication to CAN bus. // ********** private function prototypes ********** static BUBBLE_STATES_T handleBubbleNormalState( BUBBLES_T ); static BUBBLE_STATES_T handleBubbleSelfTestState( BUBBLES_T ); static void publishBubblesData( void ); /*********************************************************************//** * @brief * The initBubbles function initializes the air bubble detectors module. * @details Inputs: none * @details Outputs: Air bubble detectors module initialized. * @return none *************************************************************************/ void initBubbles( void ) { BUBBLES_T bubble; for ( bubble = ADV; bubble < NUM_OF_BUBBLES; bubble++ ) { bubblesState[ bubble ] = BUBBLE_NORMAL_STATE; bubblesStatus[ bubble ].data = BUBBLE_NOT_DETECTED; bubblesStatus[ bubble ].ovInitData = BUBBLE_NOT_DETECTED; bubblesStatus[ bubble ].ovData = BUBBLE_NOT_DETECTED; bubblesStatus[ bubble ].override = OVERRIDE_RESET; bubblesSelfTestStatus[ bubble ] = SELF_TEST_STATUS_IN_PROGRESS; bubblesSelfTestRequested[ bubble ] = FALSE; bubblesSelfTestStartTime[ bubble ] = 0; } bubblesDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; } /*********************************************************************//** * @brief * The execBubbles function executes the air bubble detectors driver. * @details Inputs: FPGA air bubble detectors status GPIO pin state * @details Outputs: bubblesStatus * @return none *************************************************************************/ void execBubbles( void ) { BUBBLES_T bubble; if ( getCurrentOperationMode() != MODE_INIT ) { // Loop through all of the air bubble detectors for ( bubble = ADV; bubble < NUM_OF_BUBBLES; bubble++ ) { // Execute the air bubble detector state machine switch( bubblesState[ bubble ] ) { case BUBBLE_NORMAL_STATE: bubblesState[ bubble ] = handleBubbleNormalState( bubble ); break; case BUBBLE_SELF_TEST_STATE: bubblesState[ bubble ] = handleBubbleSelfTestState( bubble ); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_BUBBLE_STATE, bubblesState[ bubble ] ) break; } } } // Publish air bubble detectors data if due publishBubblesData(); } /*********************************************************************//** * @brief * The selfTestBubble function requests that a specified air bubble detector * be self-tested. * @details Inputs: none * @details Outputs: Air bubble detector module self-testing * @return Boolean as success or failure *************************************************************************/ void selfTestBubble( BUBBLES_T bubble ) { bubblesSelfTestRequested[ bubble ] = TRUE; } /*********************************************************************//** * @brief * The setVenousBubbleDetectionEnabled function enabled or disables venous * bubble detection. * @details Inputs: none * @details Outputs: bubbleDetectionEnabled[] * @param enabled flag indicates whether venous bubble detection is enabled * @return none *************************************************************************/ void setVenousBubbleDetectionEnabled( BOOL enabled ) { bubbleDetectionEnabled[ ADV ] = enabled; } /*********************************************************************//** * @brief * The getVenousBubbleDetectionEnabled function returns the state of the * venous bubble detection enable flag. * @details Inputs: bubbleDetectionEnabled[] * @details Outputs: none * @return bubbleDetectionEnabled[] *************************************************************************/ BOOL getVenousBubbleDetectionEnabled( void ) { return bubbleDetectionEnabled[ ADV ]; } /*********************************************************************//** * @brief * The getBubbleStatus function gets the current reading for a given air bubble * detector. * @details Inputs: bubblesStatus * @details Outputs: none * @return the current air bubble status. *************************************************************************/ BUBBLE_STATUS_T getBubbleStatus( BUBBLES_T bubble ) { BUBBLE_STATUS_T result = (BUBBLE_STATUS_T)bubblesStatus[ bubble ].data; if ( OVERRIDE_KEY == bubblesStatus[ bubble ].override ) { result = (BUBBLE_STATUS_T)bubblesStatus[ bubble ].ovData; } return result; } /*********************************************************************//** * @brief * The getBubbleSelfTestStatus function gets the status for a given air bubble * detector self-test. * @details Inputs: bubblesSelfTestStatus * @details Outputs: none * @return status of air bubble detector self-test. *************************************************************************/ SELF_TEST_STATUS_T getBubbleSelfTestStatus( BUBBLES_T bubble ) { return bubblesSelfTestStatus[ bubble ]; } /*********************************************************************//** * @brief * The handleBubbleNormalState function handles a given air bubble module * in normal state. * @details Inputs: none * @details Outputs: Bubble module normal. * @return next state *************************************************************************/ static BUBBLE_STATES_T handleBubbleNormalState( BUBBLES_T bubble ) { BUBBLE_STATES_T state = BUBBLE_NORMAL_STATE; TREATMENT_STATE_T treatmentState = getTreatmentState(); if ( bubble < NUM_OF_BUBBLES ) { if ( TRUE == noFPGABubbleDetected( bubble ) ) { bubblesStatus[ bubble ].data = BUBBLE_NOT_DETECTED; } else { bubblesStatus[ bubble ].data = BUBBLE_DETECTED; } #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BUBBLE_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif { // Check for venous bubble alarm if enabled and pump track closed. if ( ( BUBBLE_DETECTED == getBubbleStatus( bubble ) ) && ( STATE_CLOSED == getSwitchStatus( PUMP_TRACK_SWITCH ) ) && ( bubbleDetectionEnabled[ ADV ] != FALSE ) ) { activateAlarmNoData( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED ); } } if ( TRUE == bubblesSelfTestRequested[ bubble ] ) { state = BUBBLE_SELF_TEST_STATE; bubblesSelfTestRequested[ bubble ] = FALSE; bubblesSelfTestStatus[ bubble ] = SELF_TEST_STATUS_IN_PROGRESS; setFPGABubbleSelfTest( bubble ); bubblesSelfTestStartTime[ bubble ] = getMSTimerCount(); } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_BUBBLE_ID, bubble ) } return state; } /*********************************************************************//** * @brief * The handleBubbleSelfTestState function handles a given air bubble detector * in self-test state. * @details Inputs: none * @details Outputs: Air bubble detector module self-test. * @return next state *************************************************************************/ static BUBBLE_STATES_T handleBubbleSelfTestState( BUBBLES_T bubble ) { BUBBLE_STATES_T state = BUBBLE_SELF_TEST_STATE; if ( bubble < NUM_OF_BUBBLES ) { if ( TRUE == noFPGABubbleDetected( bubble ) ) { bubblesStatus[ bubble ].data = BUBBLE_NOT_DETECTED; } else { bubblesStatus[ bubble ].data = BUBBLE_DETECTED; } if ( SELF_TEST_STATUS_IN_PROGRESS == bubblesSelfTestStatus[ bubble ] ) { if ( BUBBLE_DETECTED == getBubbleStatus( bubble ) ) // Faked air bubble caused { bubblesSelfTestStatus[ bubble ] = SELF_TEST_STATUS_PASSED; clearFPGABubbleSelfTest( bubble ); } else if ( TRUE == didTimeout( bubblesSelfTestStartTime[ bubble ], BUBBLE_TIMEOUT_MS ) ) { bubblesSelfTestStatus[ bubble ] = SELF_TEST_STATUS_FAILED; activateAlarmNoData( ALARM_ID_HD_VENOUS_BUBBLE_SELF_TEST_FAILURE ); } } else { // Air bubble self-test finished, wait for self-test faked air bubble detector clear if ( BUBBLE_NOT_DETECTED == getBubbleStatus( bubble ) ) { state = BUBBLE_NORMAL_STATE; } } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_BUBBLE_ID, bubble ) } return state; } /*********************************************************************//** * @brief * The publishBubblesData function publishes air bubble detectors data at * the set interval. * @details Inputs: status, bubblesState * @details Outputs: if broadcast is due, send air bubble detectors data * @return none *************************************************************************/ static void publishBubblesData( void ) { // Publish air bubble detectors data on interval if ( ++bubblesDataPublicationTimerCounter >= getU32OverrideValue( &bubblesDataPublishInterval ) ) { BUBBLES_DATA_T bubbleData; bubbleData.statusADV = (U32)getBubbleStatus( ADV ); bubbleData.stateADV = (U32)bubblesState[ ADV ]; broadcastData( MSG_ID_HD_BUBBLES_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&bubbleData, sizeof( BUBBLES_DATA_T ) ); bubblesDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetBubblesDataPublishIntervalOverride function overrides the * air bubbles data publish interval. * @details Inputs: none * @details Outputs: bubblesDataPublishInterval * @param value override air bubbles data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBubblesDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_PRIORITY_INTERVAL; result = TRUE; bubblesDataPublishInterval.ovData = intvl; bubblesDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetBubblesDataPublishIntervalOverride function resets the override * of the air bubbles data publish interval. * @details Inputs: none * @details Outputs: bubblesDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetBubblesDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bubblesDataPublishInterval.override = OVERRIDE_RESET; bubblesDataPublishInterval.ovData = bubblesDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetBubbleStatusOverride function overrides the status * of a given air bubble detector. * @details Inputs: none * @details Outputs: bubblesStatus * @param none * @param status override air bubble detector with this * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBubbleStatusOverride( BUBBLE_STATUS_T status, BUBBLES_T bubble ) { BOOL result = FALSE; if ( ( status < NUM_OF_BUBBLE_STATUS ) && ( bubble < NUM_OF_BUBBLES ) ) { if ( TRUE == isTestingActivated() ) { result = TRUE; bubblesStatus[ bubble ].ovData = (U32)status; bubblesStatus[ bubble ].override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetBubbleStatusOverride function resets the override of a * given air bubble detector status. * @details Inputs: none * @details Outputs: bubblesStatus * @param none * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetBubbleStatusOverride( BUBBLES_T bubble ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bubblesStatus[ bubble ].override = OVERRIDE_RESET; bubblesStatus[ bubble ].ovData = bubblesStatus[ bubble ].ovInitData; } return result; } /**@}*/