/************************************************************************** * * Copyright (c) 2019-2021 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) Peman Montazemi * @date (last) 30-Apr-2021 * * @author (original) Peman Montazemi * @date (original) 30-Apr-2021 * ***************************************************************************/ #include "AlarmMgmt.h" #include "Bubble.h" #include "FPGA.h" #include "OperationModes.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) /// Defined states for the air bubble detectors state machine. typedef enum BubbleStates { BUBBLE_INIT_STATE = 0, ///< Initial state BUBBLE_SELF_TEST_STATE, ///< Self-test state BUBBLE_NORMAL_STATE, ///< Normal 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 = [ 0, 0 ]; ///< Air bubble detectors self-test start times. static BOOL bubblesSelfTestRequested = [ FALSE, FALSE ]; ///< Air bubble detectors self-test requested flags. /// 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 = 0; ///< Timer counter used to schedule air bubble detectors data publication to CAN bus. // ********** private function prototypes ********** static BUBBLE_STATES_T handleBubbleInitState( BUBBLES_T ); static BUBBLE_STATES_T handleBubbleSelfTestState( BUBBLES_T ); static BUBBLE_STATES_T handleBubbleNormalState( BUBBLES_T ); static void publishBubblesData( void ); static U32 getPublishBubblesDataInterval( 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 = ADA; bubble < NUM_OF_BUBBLES; bubble++) { bubblesState[ bubble ] = BUBBLE_INIT_STATE; bubblesStatus[ bubble ].data = BUBBLE_NOT_DETECTED; bubblesSelfTestStatus[ bubble ] = SELF_TEST_STATUS_IN_PROGRESS; bubblesSelfTestRequested[ bubble ] = FALSE; bubblesSelfTestStartTime[ bubble ] = 0; } } /*********************************************************************//** * @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 execBubble( void ) { BUBBLES_T bubble; if ( getCurrentOperationMode() != MODE_INIT ) { // Loop through all of the air bubble detectors for ( bubble = ADA; bubble < NUM_OF_BUBBLES; bubble++ ) { // Execute the air bubble detector state machine switch( bubblesState[ bubble ] ) { case BUBBLE_INIT_STATE: bubblesState[ bubble ] = handleBubbleInitState( bubble ); break; case BUBBLE_SELF_TEST_STATE: bubblesState[ bubble ] = handleBubbleSelfTestState( bubble ); break; case BUBBLE_NORMAL_STATE: bubblesState[ bubble ] = handleBubbleNormalState( bubble ); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_BUBBLE_STATE, bubblesState[ bubble ] ) bubblesState[ bubble ] = BUBBLE_INIT_STATE; 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 ) { bubbleSelfTestRequested[ bubble ] = TRUE; } /*********************************************************************//** * @brief * The handleBubbleInitState function handles a given air bubble detector * module in init state. * @details Inputs: none * @details Outputs: Air bubble detector module init. * @return next state *************************************************************************/ static BUBBLE_STATES_T handleBubbleInitState( BUBBLES_T bubble ) { BUBBLE_STATES_T state[ bubble ] = BUBBLE_INIT_STATE; if ( TRUE == bubblesSelfTestRequested[ bubble ] ) { state[ bubble ] = BUBBLE_SELF_TEST_STATE; bubblesSelfTestRequested[ bubble ] = FALSE; setFPGABubbleSelfTest( bubble ); bubblesSelfTestStartTime[ bubble ] = getMSTimerCount(); } return state[ bubble ]; } /*********************************************************************//** * @brief * The handleBubbleSelfTestState function handles a given air bubble detector * module 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 ] = BUBBLE_SELF_TEST_STATE; if ( TRUE == FPGABubbleSelfTestDetected( bubble ) ) { state[ bubble ] = BUBBLE_SELF_TEST_STATE; bubblesSelfTestStatus[ bubble ] = SELF_TEST_STATUS_IN_PROGRESS; clearFPGABubbleSelfTest( bubble ); bubblesSelfTestStartTime[ bubble ] = getMSTimerCount(); } else { if ( TRUE == didTimeout( bubblesSelfTestStartTime[ bubble ], BUBBLE_TIMEOUT_MS ) ) { if ( bubble == ADA ) { activateAlarmNoData( ALARM_ID_HD_ARTERIAL_BUBBLE_FAULT ); } else if ( bubble == ADV ) { activateAlarmNoData( ALARM_ID_HD_VENOUS_BUBBLE_FAULT ); } else { // TODO: Should never get here, alarm as appropriate } } } return state[ bubble ]; } /*********************************************************************//** * @brief * The handleBloodLeakSelfTestState function handles the Blood Leak module * in self-test state. * @details Inputs: none * @details Outputs: Blood Leak module self test. * @return next state *************************************************************************/ static BLOOD_LEAK_STATES_T handleBloodLeakSelfTestState( void ) { BLOOD_LEAK_STATES_T state = BLOOD_LEAK_SELF_TEST_STATE; if ( SELF_TEST_STATUS_IN_PROGRESS == bloodLeakSelfTestStatus ) { if ( FALSE == noFPGABloodLeakDetected() ) // Faked blood leak caused by independent MCU board { bloodLeakSelfTestStatus = SELF_TEST_STATUS_PASSED; clearFPGABloodLeakSelfTest(); } else if ( TRUE == didTimeout( bloodLeakSelfTestStartTime, BLOOD_LEAK_TIMEOUT_MS ) ) { bloodLeakSelfTestStatus = SELF_TEST_STATUS_FAILED; activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_SELF_TEST_FAILURE ); } } else { // Blood leak self-test finished, wait for self-test faked blood leak clear if ( TRUE == noFPGABloodLeakDetected() ) { state = BLOOD_LEAK_NORMAL_STATE; } } return state; } /*********************************************************************//** * @brief * The handleBloodLeakNormalState function handles the Blood Leak module * in normal state. * @details Inputs: none * @details Outputs: Blood Leak module normal. * @return next state *************************************************************************/ static BLOOD_LEAK_STATES_T handleBloodLeakNormalState( void ) { BLOOD_LEAK_STATES_T state = BLOOD_LEAK_NORMAL_STATE; if ( TRUE == noFPGABloodLeakDetected() ) { bloodLeakStatus.data = BLOOD_LEAK_NOT_DETECTED; } else { bloodLeakStatus.data = BLOOD_LEAK_DETECTED; } // Check status reading and act upon if ( BLOOD_LEAK_DETECTED == getBloodLeakStatus() ) { if ( getCurrentOperationMode() == MODE_TREA ) { activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); } else { activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_FAULT ); } } else // Blood leak not detected { clearAlarmCondition( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); } if ( TRUE == bloodLeakZeroRequested ) { state = BLOOD_LEAK_ZERO_STATE; bloodLeakZeroRequested = FALSE; setFPGABloodLeakZero(); bloodLeakZeroStartTime = getMSTimerCount(); } return state; } /*********************************************************************//** * @brief * The getBloodLeakStatus function gets the current reading for the blood * leak detector. * @details Inputs: bloodLeakStatus * @details Outputs: none * @return the current blood leak status. *************************************************************************/ BLOOD_LEAK_STATUS_T getBloodLeakStatus( void ) { BLOOD_LEAK_STATUS_T result = (BLOOD_LEAK_STATUS_T)bloodLeakStatus.data; if ( OVERRIDE_KEY == bloodLeakStatus.override ) { result = (BLOOD_LEAK_STATUS_T)bloodLeakStatus.ovData; } return result; } /*********************************************************************//** * @brief * The getBloodLeakSelfTestStatus function gets the status for the blood * leak detector self-test. * @details Inputs: bloodLeakSelfTestStatus * @details Outputs: none * @return status of blood leak detector self-test. *************************************************************************/ SELF_TEST_STATUS_T getBloodLeakSelfTestStatus( void ) { return bloodLeakSelfTestStatus; } /*********************************************************************//** * @brief * The getPublishBloodLeakDataInterval function gets the blood leak data * publication interval. * @details Inputs: bloodLeakDataPublishInterval * @details Outputs: none * @return the current blood leak data publication interval (in task intervals). *************************************************************************/ static U32 getPublishBloodLeakDataInterval( void ) { U32 result = bloodLeakDataPublishInterval.data; if ( OVERRIDE_KEY == bloodLeakDataPublishInterval.override ) { result = bloodLeakDataPublishInterval.ovData; } return result; } /*********************************************************************//** * @brief * The publishBubblesData function publishes air bubble detectors data at * the set interval. * @details Inputs: bloodLeakStatus, bloodLeakState * @details Outputs: if broadcast is due, send air bubble detectors data * @return none *************************************************************************/ static void publishBubblesData( void ) { BUBBLE_T bubble; // Publish air bubble detectors data on interval if ( ++bubblesDataPublicationTimerCounter >= getPublishBubblesDataInterval() ) { BUBBLES_STATUS_T status = getBubblesStatus(); broadcastBloodLeakData( status, (U32)bloodLeakState ); bloodLeakDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetBloodLeakDataPublishIntervalOverride function overrides the * blood leak data publish interval. * @details Inputs: none * @details Outputs: bloodLeakDataPublishInterval * @param value override blood leak data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBloodLeakDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_PRIORITY_INTERVAL; result = TRUE; bloodLeakDataPublishInterval.ovData = intvl; bloodLeakDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetBloodLeakDataPublishIntervalOverride function resets the override * of the blood leak data publish interval. * @details Inputs: none * @details Outputs: bloodLeakDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetBloodLeakDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bloodLeakDataPublishInterval.override = OVERRIDE_RESET; bloodLeakDataPublishInterval.ovData = bloodLeakDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetBloodLeakStatusOverride function overrides the status * of the blood leak detector. * @details Inputs: none * @details Outputs: bloodLeakStatus * @param none * @param status override blood leak detector with this * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBloodLeakStatusOverride( BLOOD_LEAK_STATUS_T status ) { BOOL result = FALSE; if ( status < NUM_OF_BLOOD_LEAK_STATUS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; bloodLeakStatus.ovData = (U32)status; bloodLeakStatus.override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetBloodLeakStatusOverride function resets the override of the * blood leak detector status. * @details Inputs: none * @details Outputs: bloodLeakStatus * @param none * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetBloodLeakStatusOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bloodLeakStatus.override = OVERRIDE_RESET; bloodLeakStatus.ovData = bloodLeakStatus.ovInitData; } return result; } /**@}*/