/************************************************************************** * * 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 BloodLeak.c * * @author (last) Sean Nash * @date (last) 12-Nov-2021 * * @author (original) Peman Montazemi * @date (original) 18-Mar-2021 * ***************************************************************************/ #include "AlarmMgmt.h" #include "BloodLeak.h" #include "FPGA.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "TaskPriority.h" #include "Timers.h" /** * @addtogroup BloodLeak * @{ */ // ********** private definitions ********** #define BLOOD_LEAK_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the blood leak data is published on the CAN bus. #define BLOOD_LEAK_TIMEOUT_MS 500 ///< Blood leak detector timeout for zeroing and self-test (15 ms extended edge detection) #define BLOOD_LEAK_PERSISTENCE ( 5 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Persistence for blood leak detected alarm. /// Defined states for the blood leak detector state machine. typedef enum BloodLeakStates { BLOOD_LEAK_CHECK_SET_POINT_STATE = 0, ///< Check set point state. BLOOD_LEAK_SET_SET_POINT_STATE, ///< Set set point state. BLOOD_LEAK_INIT_STATE, ///< Init state. BLOOD_LEAK_ZERO_STATE, ///< Zero state. BLOOD_LEAK_SELF_TEST_STATE, ///< Self-test state. BLOOD_LEAK_NORMAL_STATE, ///< Normal state. NUM_OF_BLOOD_LEAK_STATES ///< Number of blood leak detector states. } BLOOD_LEAK_STATES_T; // ********** private data ********** static BLOOD_LEAK_STATES_T bloodLeakState; ///< Current state of blood leak state machine. static OVERRIDE_U32_T bloodLeakStatus; ///< Detected blood leak status for blood leak detector. static SELF_TEST_STATUS_T bloodLeakSelfTestStatus; ///< Current status of blood leak self-test. static BOOL bloodLeakZeroRequested = FALSE; ///< Blood leak zero requested flag static U32 bloodLeakZeroStartTime = 0; ///< Blood leak zeroing start time. static U32 bloodLeakSelfTestStartTime = 0; ///< Blood leak self-test start time. static U32 bloodLeakPersistenceCtr = 0; ///< Blood leak alarm persistence timer counter. static OVERRIDE_U32_T bloodLeakDataPublishInterval = { BLOOD_LEAK_PUB_INTERVAL, BLOOD_LEAK_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish blood leak data to CAN bus. static U32 bloodLeakDataPublicationTimerCounter = 0; ///< Timer counter used to schedule blood leak data publication to CAN bus. // ********** private function prototypes ********** static BLOOD_LEAK_STATES_T handleBloodLeakCheckSetPointState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakSetSetPointState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakInitState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakZeroState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakSelfTestState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakNormalState( void ); static void publishBloodLeakData( void ); /*********************************************************************//** * @brief * The initBloodLeak function initializes the Blood Leak module. * @details Inputs: none * @details Outputs: Blood Leak module initialized. * @return none *************************************************************************/ void initBloodLeak( void ) { bloodLeakState = BLOOD_LEAK_CHECK_SET_POINT_STATE; bloodLeakStatus.data = BLOOD_LEAK_NOT_DETECTED; bloodLeakStatus.ovInitData = BLOOD_LEAK_NOT_DETECTED; bloodLeakStatus.ovData = BLOOD_LEAK_NOT_DETECTED; bloodLeakStatus.override = OVERRIDE_RESET; bloodLeakSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; bloodLeakZeroRequested = FALSE; bloodLeakZeroStartTime = 0; bloodLeakSelfTestStartTime = 0; } /*********************************************************************//** * @brief * The execBloodLeak function executes the blood leak detector driver. * @details Inputs: FPGA blood leak status GPIO pin state * @details Outputs: bloodLeakStatus * @return none *************************************************************************/ void execBloodLeak( void ) { if ( getCurrentOperationMode() != MODE_INIT ) { // Execute blood leak state machine switch( bloodLeakState ) { case BLOOD_LEAK_CHECK_SET_POINT_STATE: bloodLeakState = handleBloodLeakCheckSetPointState(); break; case BLOOD_LEAK_SET_SET_POINT_STATE: bloodLeakState = handleBloodLeakSetSetPointState(); break; case BLOOD_LEAK_INIT_STATE: bloodLeakState = handleBloodLeakInitState(); break; case BLOOD_LEAK_ZERO_STATE: bloodLeakState = handleBloodLeakZeroState(); break; case BLOOD_LEAK_SELF_TEST_STATE: bloodLeakState = handleBloodLeakSelfTestState(); break; case BLOOD_LEAK_NORMAL_STATE: bloodLeakState = handleBloodLeakNormalState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_BLOOD_LEAK_STATE, bloodLeakState ) bloodLeakState = BLOOD_LEAK_INIT_STATE; break; } } // Publish blood leak data if due publishBloodLeakData(); } /*********************************************************************//** * @brief * The zeroBloodLeak function requests that the Blood Leak Detector be * zeroed. * @details Inputs: none * @details Outputs: Blood Leak module zeroing. * @return Boolean as success or failure *************************************************************************/ void zeroBloodLeak( void ) { bloodLeakZeroRequested = TRUE; } /*********************************************************************//** * @brief * The handleBloodLeakCheckSetPointState function handles the check set point * state to ensure the set point is set correctly. * @details Inputs: none * @details Outputs: Blood Leak module init. * @return next state *************************************************************************/ static BLOOD_LEAK_STATES_T handleBloodLeakCheckSetPointState( void ) { BLOOD_LEAK_STATES_T state = BLOOD_LEAK_CHECK_SET_POINT_STATE; // TODO remove state = BLOOD_LEAK_SET_SET_POINT_STATE; // TODO remove for testing only return state; } /*********************************************************************//** * @brief * The handleBloodLeakSetSetPointState function handles the set set point state. * @details Inputs: none * @details Outputs: Blood Leak module init. * @return next state *************************************************************************/ static BLOOD_LEAK_STATES_T handleBloodLeakSetSetPointState( void ) { BLOOD_LEAK_STATES_T state = BLOOD_LEAK_SET_SET_POINT_STATE; state = BLOOD_LEAK_INIT_STATE; return state; } /*********************************************************************//** * @brief * The handleBloodLeakInitState function handles the Blood Leak module in init * state. * @details Inputs: none * @details Outputs: Blood Leak module init. * @return next state *************************************************************************/ static BLOOD_LEAK_STATES_T handleBloodLeakInitState( void ) { BLOOD_LEAK_STATES_T state = BLOOD_LEAK_INIT_STATE; if ( TRUE == bloodLeakZeroRequested ) { state = BLOOD_LEAK_ZERO_STATE; bloodLeakZeroRequested = FALSE; setFPGABloodLeakZero(); bloodLeakZeroStartTime = getMSTimerCount(); } return state; } /*********************************************************************//** * @brief * The handleBloodLeakZeroState function handles the Blood Leak module in zeroing * state. * @details Inputs: none * @details Outputs: Blood Leak module zeroing. * @return next state *************************************************************************/ static BLOOD_LEAK_STATES_T handleBloodLeakZeroState( void ) { BLOOD_LEAK_STATES_T state = BLOOD_LEAK_ZERO_STATE; if ( TRUE == FPGABloodLeakZeroDetected() ) { state = BLOOD_LEAK_SELF_TEST_STATE; bloodLeakSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; clearFPGABloodLeakZero(); setFPGABloodLeakSelfTest(); bloodLeakSelfTestStartTime = getMSTimerCount(); } else { if ( TRUE == didTimeout( bloodLeakZeroStartTime, BLOOD_LEAK_TIMEOUT_MS ) ) { activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_FAULT ); } } return state; } /*********************************************************************//** * @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() ) && ( getCurrentOperationMode() == MODE_TREA ) ) { if ( ++bloodLeakPersistenceCtr > BLOOD_LEAK_PERSISTENCE ) { bloodLeakPersistenceCtr = BLOOD_LEAK_PERSISTENCE; activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); } } else // Blood leak not detected { if ( bloodLeakPersistenceCtr > 0 ) { bloodLeakPersistenceCtr--; } else { 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 publishBloodLeakData function publishes blood leak data at the set interval. * @details Inputs: bloodLeakStatus, bloodLeakState * @details Outputs: if broadcast is due, send blood leak data * @return none *************************************************************************/ static void publishBloodLeakData( void ) { // Publish blood leak data on interval if ( ++bloodLeakDataPublicationTimerCounter >= getU32OverrideValue( &bloodLeakDataPublishInterval ) ) { BLOOD_LEAK_DATA_T data; data.bloodLeakStatus = (U32)getBloodLeakStatus(); data.bloodLeakState = (U32)bloodLeakState; data.bloodLeakZeroStatusCounter = (U32)getFPGABloodLeakZeroStatusCounter(); data.bloodLeakCounter = (U32)getFPGABloodLeakCounter(); data.bloodLeakZeroedStatus = (U32)getFPGABloodLeakZeroedStatus(); data.bloodLeakDetectSetPoint = (U32)getFPGABloodLeakDetectSetPoint(); data.bloodLeakDetectLevel = (U32)getFPGABloodLeakDetectLevel(); data.bloodLeakStCount = (U32)getFPGABloodLeakStCount(); data.bloodLeakLEDIntesity = (U32)getFPGABloodLeakLEDIntensity(); data.bloodLeakRegisterCounter = (U32)getFPGABloodLeakRegisterCounter(); broadcastData( MSG_ID_HD_BLOOD_LEAK_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( BLOOD_LEAK_DATA_T ) ); 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; } /**@}*/