/************************************************************************** * * Copyright (c) 2019-2022 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 SelfTests.c * * @author (last) Dara Navaei * @date (last) 04-Jan-2022 * * @author (original) Quang Nguyen * @date (original) 28-Jan-2021 * ***************************************************************************/ #include "AirTrap.h" #include "BloodFlow.h" #include "BloodLeak.h" #include "Bubble.h" #include "DGInterface.h" #include "DialInFlow.h" #include "DialOutFlow.h" #include "FPGA.h" #include "ModeTreatmentParams.h" #include "PresOccl.h" #include "SelfTests.h" #include "SyringePump.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" #include "Valves.h" /** * @addtogroup SelfTests * @{ */ // ********** private definitions ********** #define PUMP_RUN_SELF_TEST_TIME_MS ( 15 * MS_PER_SECOND ) ///< Self-test time to run pumps in ms. #define PUMP_SELF_TEST_FLOW_RATE_ML_MIN 100 ///< Self-test pump flow rate in mL/min. #define SYRINGE_PUMP_OCCLUSION_CHECK_DELAY ( 1 * MS_PER_SECOND ) ///< Delay 1 second then check for syringe pump prime occlusion. #define BLOOD_PUMP_RUN_TIME_PRESSURE_SELF_TEST ( 5 * MS_PER_SECOND ) ///< Pressure self-test time to run blood pump in ms. #define NORMALIZED_PRESSURE_SELF_TEST_TIME ( 4 * MS_PER_SECOND ) ///< Time to wait for pressure to normalize in ms. #define ARTERIAL_PRESSURE_SELF_TEST_LOW_LIMIT_MMHG -50.0 ///< Arterial pressure low limit after running blood pump. #define VENOUS_PRESSURE_SELF_TEST_HIGH_LIMIT_MMHG 400 ///< Venous pressure high limit after running blood pump. #define NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG 10.0 ///< Difference in pressure readings after return to normal state tolerance (in mmHg). #define DIP_FLOW_RATE_SETUP_ML_MIN 150 ///< Dialysate inlet pump flow rate during the setup for wet self-test. #define DIP_FLOW_RATE_FIRST_DISPLACEMENT_ML_MIN 100 ///< Dialysate inlet pump flow rate during the first displacement in wet self-test. #define DIP_FLOW_RATE_SECOND_DISPLACEMENT_ML_MIN 600 ///< Dialysate inlet pump flow rate during the second displacement in wet self-test. #define WET_SELF_TEST_RESERVOIR_ONE_SETUP_VOLUME_ML 1200.0 ///< Setup volume for reservoir one before wet self-test in ml. #define WET_SELF_TEST_FIRST_DISPLACEMENT_TARGET_VOLUME_ML 100.0 ///< Target of first displacement volume in ml. #define WET_SELF_TEST_SECOND_DISPLACEMENT_TARGET_VOLUME_ML 600.0 ///< Target of second displacement volume in ml. #define WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE 5.0 ///< Tolerance on integrated volume in percentage. #define WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G 25.0 ///< Tolerance in the load cell readings of the displacement in grams (2%). #define WET_SELF_TEST_DISPLACEMENT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Time to displace dialysate in wet self-test in ms. #define RESERVOIR_SETTLE_TIME_MS ( 4 * MS_PER_SECOND ) ///< Time allotted for reservoir to settle in ms. #define MAX_NO_CARTRIDGE_SELF_TEST_TIME 30 ///< Maximum no cartridge self-test time (in seconds). #define MAX_DRY_SELF_TEST_TIME ( 3 * SEC_PER_MIN ) ///< Maximum dry self-test time (in seconds). #define SELF_TEST_TIME_DATA_PUB_INTERVAL ( MS_PER_SECOND ) ///< Interval (ms/task time) at which self-test time data is published on the CAN bus. /// Multiplier to conver flow (mL/min) into volume (mL) for period of general task interval. static const F32 SELF_TEST_FLOW_INTEGRATOR = ( ( 1.0 * TASK_GENERAL_INTERVAL ) / ( SEC_PER_MIN * MS_PER_SECOND ) ); /// Wet self-tests state machine. typedef enum Wet_Self_Tests_State { WET_SELF_TESTS_START_STATE = 0, ///< Wet self-tests starting state. WET_SELF_TESTS_SETUP_STATE, ///< Setup reservoirs for wet self-tests. WET_SELF_TESTS_BUBBLES_STATE, ///< Wet self-test air bubble detectors state. WET_SELF_TESTS_PRIME_CHECK_STATE, ///< Prime check wet self-tests state, checks for primed patient lines. WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE, ///< Blood leak detector self-test state. WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE, ///< Setup valve and start dialysate pump for first displacement. WET_SELF_TESTS_FIRST_DISPLACEMENT_STATE, ///< Fill reservoir 2 with 100 mL of dialysate from reservoir 1 state. WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE, ///< After first displacement completed verify state. WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE, ///< Setup valve and start dialysate pump for second displacement. WET_SELF_TESTS_SECOND_DISPLACEMENT_STATE, ///< Fill reservoir 1 with 300 mL of dialysate from reservoir 2 state. WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE, ///< After first displacement completed verify state. WET_SELF_TESTS_STOPPED_STATE, ///< Wet self-test stopped state. WET_SELF_TESTS_COMPLETE_STATE, ///< Wet self-test complete state. NUM_OF_WET_SELF_TESTS_STATES ///< Number of wet self-tests states. } WET_SELF_TESTS_STATE_T; // ********** private data ********** static NO_CART_SELF_TESTS_STATE_T currentNoCartSelfTestsState; ///< Current state of the no cartridge self-tests state machine. static U32 runPumpStartTime; ///< Beginning time when pumps start running static BOOL havePumpsStarted; ///< Flag indicates pumps have started running for self-test. static DRY_SELF_TESTS_STATE_T currentDrySelfTestsState; ///< Current state of the dry self-tests state machine. static U32 pressureSelfTestBloodPumpRunStartTime; ///< Pressure dry self-test blood pump runs start time. static U32 pressureSelfTestNormalizedStartTime; ///< Normalized pressure dry self-test start time. static F32 previousNormalArterialPressure; ///< Holds the previous normal arterial pressure reading. static F32 previousNormalVenousPressure; ///< Holds the previous normal venous pressure reading. static BOOL wetSelfTestsResult; ///< Result of wet self-tests. static WET_SELF_TESTS_STATE_T currentWetSelfTestsState; ///< Current state of the wet self-tests state machine. static U32 settleStartTime; ///< Wait for reservoir to settle start time. static U32 displacementStartTime; ///< Dialysate displacement starting time. static F32 fmdIntegratedVolume; ///< FMD integrated volume over displacement time. static F32 reservoirVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Hold the current volume of all reservoirs. static F32 setupDisplacementVolume; ///< Hold the setup displacement volume to get reservoir one to target volume. static BOOL isValvesSettingSent; ///< Flag indicates valve setting change has been send to DG. static U32 selfTestStartTime; ///< Starting time of self-test (in ms). static U32 selfTestPreviousPublishDataTime; ///< Last time self-test time data is being published (in ms). static U32 syringeOcclusionDelayStartTime; ///< Used to calculate the 1 second delay time before check for prime occlusion. static BOOL useHeparin; ///< Flag indicates the user of heparin. static BOOL selfTestsResumeRequested; ///< Flag indicates user requesting self-tests resume. // ********** private function prototypes ********** static void resetSelfTestsFlags( void ); static void setupForSelfTestsStop( void ); static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestsWaitForClosedDoor( void ); static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestHomeValvesState( void ); static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestHomeSyringePumpState( void ); static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestPumpsState( void ); static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestHomeIdleState( void ); static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestStoppedState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestWaitForDoorCloseState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestUsedCartridgeCheckState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsSetupState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsState( SELF_TEST_STATUS_T *result ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsNormalState( SELF_TEST_STATUS_T *result ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestSyringePumpPrimeState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestSyringePumpOcclusionDetectionState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestStoppedState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestStartState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestSetupState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestBubblesState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestPrimeCheckState( SELF_TEST_STATUS_T *result ); static WET_SELF_TESTS_STATE_T handleWetSelfTestBloodLeakDetectorState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestFirstDisplacementSetupState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestFirstDisplacementState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestFirstDisplacementVerifyState( SELF_TEST_STATUS_T *result ); static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementSetupState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementVerifyState( SELF_TEST_STATUS_T *result ); static WET_SELF_TESTS_STATE_T handleWetSelfTestStoppedState( void ); /*********************************************************************//** * @brief * The initSelfTests function initializes the SelfTests module. * @details Inputs: none * @details Outputs: SelfTests module initialized. * @return none *************************************************************************/ void initSelfTests( void ) { selfTestStartTime = 0; selfTestPreviousPublishDataTime = 0; syringeOcclusionDelayStartTime = 0; } /*********************************************************************//** * @brief * The signalResumeSelfTests function signals the self-tests to resume * previous operation. * @details Inputs: none * @details Outputs: primeResumeRequested * @return none *************************************************************************/ void signalResumeSelfTests( void ) { selfTestsResumeRequested = TRUE; } /*********************************************************************//** * @brief * The resetSelfTestsFlags function resets all self-tests signal flags. * @details Inputs: none * @details Outputs: signal flags set to FALSE * @return none *************************************************************************/ static void resetSelfTestsFlags( void ) { selfTestsResumeRequested = FALSE; } /*********************************************************************//** * @brief * The setupForSelfTestsStop function sets actuators appropriately for self-tests * states. * @details Inputs: none * @details Outputs: All pumps stopped * @return none *************************************************************************/ static void setupForSelfTestsStop( void ) { signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); stopSyringePump(); setValvePosition( VDI, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VDO, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VBA, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VBV, VALVE_POSITION_A_INSERT_EJECT ); } /*********************************************************************//** * @brief * The transitionToNoCartSelfTests function resets anything required before * the start of no cartridge self-tests. * @details Inputs: none * @details Outputs: No cartridge self-tests re-initialized. * @return none *************************************************************************/ void transitionToNoCartSelfTests( void ) { F32 const bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); F32 const hepRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ); if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP ) != SW_CONFIG_ENABLE_VALUE ) { useHeparin = ( ( bolusVol > 0.0 ) || ( hepRate > 0.0 ) ? TRUE : FALSE ); } else { useHeparin = FALSE; } currentNoCartSelfTestsState = NO_CART_SELF_TESTS_START_STATE; runPumpStartTime = 0; havePumpsStarted = FALSE; selfTestStartTime = getMSTimerCount(); selfTestPreviousPublishDataTime = getMSTimerCount(); resetSelfTestsFlags(); } /*********************************************************************//** * @brief * The execNoCartSelfTests function executes the no cartridge self-tests * state machine. * @details Inputs: currentNoCartSelfTestsState * @details Outputs: currentNoCartSelfTestsState * @return none *************************************************************************/ void execNoCartSelfTests( void ) { // execute no cartridge self-tests state machine switch ( currentNoCartSelfTestsState ) { case NO_CART_SELF_TESTS_START_STATE: currentNoCartSelfTestsState = NO_CART_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; break; case NO_CART_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE: currentNoCartSelfTestsState = handleNoCartSelfTestsWaitForClosedDoor(); break; case NO_CART_SELF_TESTS_OCCLUSION_SENSORS_STATE: execPresOcclTest(); currentNoCartSelfTestsState = NO_CART_SELF_TESTS_BLOOD_FLOW_METERS_STATE; break; case NO_CART_SELF_TESTS_BLOOD_FLOW_METERS_STATE: execBloodFlowTest(); currentNoCartSelfTestsState = NO_CART_SELF_TESTS_DIALYSATE_FLOW_METERS_STATE; break; case NO_CART_SELF_TESTS_DIALYSATE_FLOW_METERS_STATE: // TODO as of now, the dialysate flow self test only gets the calibration record so it is only called in POST currentNoCartSelfTestsState = NO_CART_SELF_TESTS_BOARD_TEMPERATURE_STATE; break; case NO_CART_SELF_TESTS_BOARD_TEMPERATURE_STATE: // TODO: Implement self tests currentNoCartSelfTestsState = NO_CART_SELF_TESTS_HOME_VALVES_STATE; break; case NO_CART_SELF_TESTS_HOME_VALVES_STATE: currentNoCartSelfTestsState = handleNoCartSelfTestHomeValvesState(); break; case NO_CART_SELF_TESTS_HOME_SYRINGE_PUMP_STATE: currentNoCartSelfTestsState = handleNoCartSelfTestHomeSyringePumpState(); break; case NO_CART_SELF_TESTS_PUMPS_STATE: currentNoCartSelfTestsState = handleNoCartSelfTestPumpsState(); break; case NO_CART_SELF_TESTS_HOME_IDLE_STATE: currentNoCartSelfTestsState = handleNoCartSelfTestHomeIdleState(); break; case NO_CART_SELF_TESTS_STOPPED_STATE: currentNoCartSelfTestsState = handleNoCartSelfTestStoppedState(); break; case NO_CART_SELF_TESTS_COMPLETE_STATE: break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_NO_CARTRIDGE_SELF_TEST_STATE, currentNoCartSelfTestsState ); break; } // Self-tests flags should be handled by now, reset if flags not handled with current state resetSelfTestsFlags(); // Publish current self-test time data if ( calcTimeSince( selfTestPreviousPublishDataTime ) >= SELF_TEST_TIME_DATA_PUB_INTERVAL ) { U32 const elapsedSelfTestTimeInSecs = calcTimeSince( selfTestStartTime ) / MS_PER_SECOND; selfTestPreviousPublishDataTime = getMSTimerCount(); if ( elapsedSelfTestTimeInSecs <= MAX_NO_CARTRIDGE_SELF_TEST_TIME ) { SELF_TEST_NO_CARTRIDGE_PAYLOAD_T data; data.timeout = MAX_NO_CARTRIDGE_SELF_TEST_TIME; data.countdown = ( MAX_NO_CARTRIDGE_SELF_TEST_TIME - elapsedSelfTestTimeInSecs ); broadcastData( MSG_ID_HD_NO_CART_SELF_TEST_PROGRESS, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( SELF_TEST_NO_CARTRIDGE_PAYLOAD_T ) ); } else { // SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_NO_CART_SELF_TEST_TIMEOUT, currentNoCartSelfTestsState ); } } } /*********************************************************************//** * @brief * The getNoCartSelfTestsState function returns the current state of no * cartridge self-tests sub-mode. * @details Inputs: currentNoCartSelfTestsState * @details Outputs: none * @return current no cartridge self-tests state *************************************************************************/ U32 getNoCartSelfTestsState( void ) { return (U32)currentNoCartSelfTestsState; } /*********************************************************************//** * @brief * The transitionToDrySelfTests function resets anything required before * the start of dry self-tests. * @details Inputs: none * @details Outputs: Dry self-tests re-initialized. * @return none *************************************************************************/ void transitionToDrySelfTests() { currentDrySelfTestsState = DRY_SELF_TESTS_START_STATE; pressureSelfTestBloodPumpRunStartTime = 0; pressureSelfTestNormalizedStartTime = 0; previousNormalArterialPressure = 0.0; previousNormalVenousPressure = 0.0; selfTestStartTime = getMSTimerCount(); selfTestPreviousPublishDataTime = getMSTimerCount(); resetSelfTestsFlags(); } /*********************************************************************//** * @brief * The execDrySelfTests function executes the dry self-tests state machine. * @details Inputs: currentDrySelfTestsState * @details Outputs: currentDrySelfTestsState * @return none *************************************************************************/ void execDrySelfTests( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; // execute dry self-tests state machine switch ( currentDrySelfTestsState ) { case DRY_SELF_TESTS_START_STATE: if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DRY_SELF_TESTS ) ) { // TODO: Remove once dry self-test is ready to use currentDrySelfTestsState = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; } else { currentDrySelfTestsState = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; } break; case DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE: currentDrySelfTestsState = handleDrySelfTestWaitForDoorCloseState(); break; case DRY_SELF_TESTS_USED_CARTRIDGE_CHECK_STATE: currentDrySelfTestsState = handleDrySelfTestUsedCartridgeCheckState(); break; case DRY_SELF_TESTS_OCCLUSION_SENSORS_STATE: if ( SELF_TEST_STATUS_PASSED == execPresOcclDryTest() ) { setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); setValveAirTrap( STATE_OPEN ); currentDrySelfTestsState = DRY_SELF_TESTS_PRESSURE_SENSORS_SETUP_STATE; } break; case DRY_SELF_TESTS_PRESSURE_SENSORS_SETUP_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsSetupState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsState( &result ); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsNormalState( &result ); break; case DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE: currentDrySelfTestsState = handleDrySelfTestSyringePumpPrimeState(); break; case DRY_SELF_TESTS_SYRINGE_PUMP_OCCLUSION_DETECTION_STATE: currentDrySelfTestsState = handleDrySelfTestSyringePumpOcclusionDetectionState(); break; case DRY_SELF_TESTS_STOPPED_STATE: currentDrySelfTestsState = handleDrySelfTestStoppedState(); break; case DRY_SELF_TESTS_COMPLETE_STATE: break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_DRY_SELF_TEST_STATE, currentDrySelfTestsState ); break; } // Self-tests flags should be handled by now, reset if flags not handled with current state resetSelfTestsFlags(); if ( SELF_TEST_STATUS_FAILED == result ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRE_TREATMENT_DRY_SELF_TEST_FAILURE, currentDrySelfTestsState ); } // Publish current self-test time data if ( calcTimeSince( selfTestPreviousPublishDataTime ) >= SELF_TEST_TIME_DATA_PUB_INTERVAL ) { U32 const elapsedSelfTestTimeInSecs = calcTimeSince( selfTestStartTime ) / MS_PER_SECOND; selfTestPreviousPublishDataTime = getMSTimerCount(); if ( elapsedSelfTestTimeInSecs <= MAX_DRY_SELF_TEST_TIME ) { SELF_TEST_DRY_PAYLOAD_T data; data.timeout = MAX_DRY_SELF_TEST_TIME; data.countdown = ( MAX_DRY_SELF_TEST_TIME - elapsedSelfTestTimeInSecs ); broadcastData( MSG_ID_HD_DRY_SELF_TEST_PROGRESS, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( SELF_TEST_DRY_PAYLOAD_T ) ); } else { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DRY_SELF_TEST_TIMEOUT, currentDrySelfTestsState ); } } } /*********************************************************************//** * @brief * The getDrySelfTestsState function returns the current state of dry self-tests sub-mode. * @details Inputs: currentDrySelfTestsState * @details Outputs: none * @return current dry self-tests state *************************************************************************/ U32 getDrySelfTestsState( void ) { return (U32)currentDrySelfTestsState; } /*********************************************************************//** * @brief * The transitionToWetSelfTests function resets anything required before * the start of wet self-tests. * @details Inputs: none * @details Outputs: Wet self-tests re-initialized. * @return none *************************************************************************/ void transitionToWetSelfTests() { signalDialInPumpHardStop(); // turn off DPi that was on in previous dialysate bypass state wetSelfTestsResult = FALSE; currentWetSelfTestsState = WET_SELF_TESTS_START_STATE; settleStartTime = 0; displacementStartTime = 0; fmdIntegratedVolume = 0.0; isValvesSettingSent = FALSE; selfTestStartTime = getMSTimerCount(); selfTestPreviousPublishDataTime = getMSTimerCount(); resetSelfTestsFlags(); } /*********************************************************************//** * @brief * The execWetSelfTests function executes the wet self-tests state machine. * @details Inputs: currentWetSelfTestsState * @details Outputs: currentWetSelfTestsState, wetSelfTestsResult * @return none *************************************************************************/ void execWetSelfTests( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; // execute wet self-tests state machine switch ( currentWetSelfTestsState ) { case WET_SELF_TESTS_START_STATE: currentWetSelfTestsState = handleWetSelfTestStartState(); break; case WET_SELF_TESTS_SETUP_STATE: currentWetSelfTestsState = handleWetSelfTestSetupState(); break; case WET_SELF_TESTS_BUBBLES_STATE: currentWetSelfTestsState = handleWetSelfTestBubblesState(); break; case WET_SELF_TESTS_PRIME_CHECK_STATE: currentWetSelfTestsState = handleWetSelfTestPrimeCheckState( &result ); break; case WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE: currentWetSelfTestsState = handleWetSelfTestBloodLeakDetectorState(); break; case WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE: currentWetSelfTestsState = handleWetSelfTestFirstDisplacementSetupState(); break; case WET_SELF_TESTS_FIRST_DISPLACEMENT_STATE: currentWetSelfTestsState = handleWetSelfTestFirstDisplacementState(); break; case WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE: currentWetSelfTestsState = handleWetSelfTestFirstDisplacementVerifyState( &result ); break; case WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE: currentWetSelfTestsState = handleWetSelfTestSecondDisplacementSetupState(); break; case WET_SELF_TESTS_SECOND_DISPLACEMENT_STATE: currentWetSelfTestsState = handleWetSelfTestSecondDisplacementState(); break; case WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE: currentWetSelfTestsState = handleWetSelfTestSecondDisplacementVerifyState( &result ); break; case WET_SELF_TESTS_STOPPED_STATE: currentWetSelfTestsState = handleWetSelfTestStoppedState(); break; case WET_SELF_TESTS_COMPLETE_STATE: wetSelfTestsResult = TRUE; break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_WET_SELF_TEST_STATE, currentWetSelfTestsState ); break; } // Self-tests flags should be handled by now, reset if flags not handled with current state resetSelfTestsFlags(); if ( SELF_TEST_STATUS_FAILED == result ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRE_TREATMENT_WET_SELF_TEST_FAILURE, currentWetSelfTestsState ); } } /*********************************************************************//** * @brief * The isDrySelfTestsPassed function returns the status of wet self-tests. * @details Inputs: none * @details Outputs: none * @return TRUE if wet self-tests passed, otherwise FALSE *************************************************************************/ BOOL isWetSelfTestsPassed( void ) { return wetSelfTestsResult; } /*********************************************************************//** * @brief * The handleNoCartridgeWaitForClosedDoor function executes the wait for * door to be closed state of no cartridge self-tests state machine. * @details Inputs: none * @details Outputs: none * @return the next state of no cartridge self-tests state machine *************************************************************************/ static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestsWaitForClosedDoor( void ) { NO_CART_SELF_TESTS_STATE_T state = NO_CART_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); selfTestStartTime = getMSTimerCount(); // TODO: Use appropriate sensor driver if ( STATE_CLOSED == getFPGADoorState() ) { state = NO_CART_SELF_TESTS_OCCLUSION_SENSORS_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { setupForSelfTestsStop(); state = NO_CART_SELF_TESTS_STOPPED_STATE; } return state; } /*********************************************************************//** * @brief * The handleNoCartSelfTestHomeValvesState function starts homing process for * all the valves. * @details Inputs: none * @details Outputs: Home all valves * @return the next state of no cartridge self-tests state machine *************************************************************************/ static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestHomeValvesState( void ) { NO_CART_SELF_TESTS_STATE_T state = NO_CART_SELF_TESTS_HOME_SYRINGE_PUMP_STATE; VALVE_T valve; for ( valve = VDI; valve < NUM_OF_VALVES; ++valve ) { homeValve( valve ); } if ( TRUE == doesAlarmStatusIndicateStop() ) { setupForSelfTestsStop(); state = NO_CART_SELF_TESTS_STOPPED_STATE; } return state; } /*********************************************************************//** * @brief * The handleNoCartSelfTestHomeSyringePumpState function homes syringe pump. * @details Inputs: useHeparin * @details Outputs: Home syringe pump * @return the next state of no cartridge self-tests state machine *************************************************************************/ static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestHomeSyringePumpState( void ) { NO_CART_SELF_TESTS_STATE_T state = NO_CART_SELF_TESTS_HOME_SYRINGE_PUMP_STATE; if ( TRUE == useHeparin ) { if ( TRUE == isSyringePumpStopped() ) { retractSyringePump(); } } if ( ( TRUE != useHeparin ) || ( TRUE == isSyringePumpHome() ) ) { state = NO_CART_SELF_TESTS_PUMPS_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { setupForSelfTestsStop(); state = NO_CART_SELF_TESTS_STOPPED_STATE; } return state; } /*********************************************************************//** * @brief * The handleNoCartSelfTestPumpsState function runs blood, dialysate inlet, * dialysate outlet pumps for certain time to make sure no alarms occur. * @details Inputs: none * @details Outputs: Ran self-test for blood, dialysate in, dialysate out pumps * @return the next state of no cartridge self-tests state machine *************************************************************************/ static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestPumpsState( void ) { NO_CART_SELF_TESTS_STATE_T state = NO_CART_SELF_TESTS_PUMPS_STATE; if ( FALSE == havePumpsStarted ) { havePumpsStarted = TRUE; setBloodPumpTargetFlowRate( PUMP_SELF_TEST_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); setDialInPumpTargetFlowRate( PUMP_SELF_TEST_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); setDialOutPumpTargetRate( PUMP_SELF_TEST_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); runPumpStartTime = getMSTimerCount(); } if ( TRUE == didTimeout( runPumpStartTime, PUMP_RUN_SELF_TEST_TIME_MS ) ) { signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); // Home pumps for cartridge installation homeBloodPump(); homeDialInPump(); homeDialOutPump(); state = NO_CART_SELF_TESTS_HOME_IDLE_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { setupForSelfTestsStop(); state = NO_CART_SELF_TESTS_STOPPED_STATE; } return state; } /*********************************************************************//** * @brief * The handleNoCartSelfTestHomeIdleState function waits for all pumps finish homing. * @details Inputs: none * @details Outputs: All pumps finished homing * @return the next state of no cartridge self-tests state machine *************************************************************************/ static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestHomeIdleState( void ) { NO_CART_SELF_TESTS_STATE_T state = NO_CART_SELF_TESTS_HOME_IDLE_STATE; if ( ( FALSE == isDialInPumpRunning() ) && ( FALSE == isDialOutPumpRunning() ) && ( FALSE == isBloodPumpRunning() ) ) { state = NO_CART_SELF_TESTS_COMPLETE_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { setupForSelfTestsStop(); state = NO_CART_SELF_TESTS_STOPPED_STATE; } return state; } /*********************************************************************//** * @brief * The handleNoCartSelfTestStoppedState function handles the stopped no * cartridge self-tests operation. * @details Inputs: none * @details Outputs: none * @return the next state of no cart self-tests state machine *************************************************************************/ static NO_CART_SELF_TESTS_STATE_T handleNoCartSelfTestStoppedState( void ) { NO_CART_SELF_TESTS_STATE_T state = NO_CART_SELF_TESTS_STOPPED_STATE; // Restart self-test start time selfTestStartTime = getMSTimerCount(); if ( TRUE == selfTestsResumeRequested ) { selfTestsResumeRequested = FALSE; havePumpsStarted = FALSE; state = NO_CART_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestWaitForDoorCloseState function makes sure door is * closed before starting self-tests. * @details Inputs: none * @details Outputs: none * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestWaitForDoorCloseState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; // Restart self-test start time selfTestStartTime = getMSTimerCount(); // TODO: Use appropriate sensor driver if ( STATE_CLOSED == getFPGADoorState() ) { state = DRY_SELF_TESTS_USED_CARTRIDGE_CHECK_STATE; setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestUsedCartridgeCheckState function verify no fluid is * detected by bubble detectors to ensure the cartridge is new. * @details Inputs: none * @details Outputs: none * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestUsedCartridgeCheckState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_USED_CARTRIDGE_CHECK_STATE; BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); if ( ( BUBBLE_DETECTED == ADVBubbleStatus ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) ) { state = DRY_SELF_TESTS_OCCLUSION_SENSORS_STATE; } // else // { // activateAlarmNoData( ALARM_ID_INSTALL_NEW_CARTRIDGE ); // } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsSetupState function handles the setup * for pressure sensors dry self-test. * @details Inputs: none * @details Outputs: none * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsSetupState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_STATE; if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } else { previousNormalArterialPressure = getFilteredArterialPressure(); previousNormalVenousPressure = getFilteredVenousPressure(); setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_B_OPEN ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); setValveAirTrap( STATE_CLOSED ); setBloodPumpTargetFlowRate( PUMP_SELF_TEST_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); pressureSelfTestBloodPumpRunStartTime = getMSTimerCount(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsState function tests the readings of * pressure sensors and verify they are in correct range. * @details Inputs: none * @details Outputs: none * @param result self-test result * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsState( SELF_TEST_STATUS_T *result ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_STATE; F32 const arterialPressure = getFilteredArterialPressure(); F32 const venousPressure = getFilteredVenousPressure(); // End the test when reaching target pressure or time out if ( ( TRUE == didTimeout( pressureSelfTestBloodPumpRunStartTime, BLOOD_PUMP_RUN_TIME_PRESSURE_SELF_TEST ) ) || ( ARTERIAL_PRESSURE_SELF_TEST_LOW_LIMIT_MMHG >= arterialPressure ) || ( VENOUS_PRESSURE_SELF_TEST_HIGH_LIMIT_MMHG <= venousPressure ) ) { // Test pass when reading positive arterial pressure and negative venous pressure if ( ( arterialPressure < 0) && ( venousPressure > 0 ) ) { signalBloodPumpHardStop(); setValvePosition( VBV, VALVE_POSITION_B_OPEN ); setValveAirTrap( STATE_OPEN ); pressureSelfTestNormalizedStartTime = getMSTimerCount(); state = DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_STATE; } else { *result = SELF_TEST_STATUS_FAILED; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsNormalState function verify the readings of * pressure sensors after returning to normal state. * @details Inputs: none * @details Outputs: none * @param result self-test result * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsNormalState( SELF_TEST_STATUS_T *result ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_STATE; F32 const arterialPressureDiff = fabs( getFilteredArterialPressure() - previousNormalArterialPressure ); F32 const venousPressureDiff = fabs( getFilteredVenousPressure() - previousNormalVenousPressure ); if ( TRUE == didTimeout( pressureSelfTestNormalizedStartTime, NORMALIZED_PRESSURE_SELF_TEST_TIME ) ) { if ( ( arterialPressureDiff <= NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG ) && ( venousPressureDiff <= NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG ) ) { state = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; } else { *result = SELF_TEST_STATUS_FAILED; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestSyringePumpPrimeState function handles the prime * operation for syringe pump. * @details Inputs: none * @details Outputs: none * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestSyringePumpPrimeState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; if ( TRUE == useHeparin ) { if ( FALSE == isSyringePumpRunning() ) { if ( TRUE == isSyringePlungerFound() ) { if ( TRUE == isSyringePumpPrimed() ) { state = DRY_SELF_TESTS_SYRINGE_PUMP_OCCLUSION_DETECTION_STATE; syringeOcclusionDelayStartTime = getMSTimerCount(); // Get the current time to check for occlusion after 1 second has elapsed } else { primeSyringePump(); } } else { if ( TRUE == isAlarmActive( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM ) ) { retractSyringePump(); } else if ( TRUE == isSyringePumpHome() ) { seekSyringePlunger(); } } } } else { state = DRY_SELF_TESTS_COMPLETE_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestSyringePumpOcclusionDetectionState function handles * occlusion detection after prime has completed. * @details Inputs: none * @details Outputs: none * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestSyringePumpOcclusionDetectionState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_SYRINGE_PUMP_OCCLUSION_DETECTION_STATE; if ( TRUE == didTimeout( syringeOcclusionDelayStartTime, SYRINGE_PUMP_OCCLUSION_CHECK_DELAY ) ) { checkForPrimeOcclusion(); state = DRY_SELF_TESTS_COMPLETE_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestStoppedState function handles the stopped dry self-tests * operation. * @details Inputs: none * @details Outputs: none * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestStoppedState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_STOPPED_STATE; // Restart self-test start time selfTestStartTime = getMSTimerCount(); if ( TRUE == selfTestsResumeRequested ) { selfTestsResumeRequested = FALSE; if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_DRY_SELF_TESTS ) != SW_CONFIG_ENABLE_VALUE ) { state = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; } else { state = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; } } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestStartState function handles setup state for wet * self-tests sub-mode. * @details Inputs: reservoir one weight * @details Outputs: setup valves and dialysate inlet pump * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestStartState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_START_STATE; DG_CMD_RESPONSE_T cmdResp; F32 const resOneWeight = getReservoirWeightLargeFilter( DG_RESERVOIR_1 ); setupDisplacementVolume = fabs( resOneWeight - WET_SELF_TEST_RESERVOIR_ONE_SETUP_VOLUME_ML ); if ( FALSE == isValvesSettingSent ) { isValvesSettingSent = TRUE; setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); if ( resOneWeight > WET_SELF_TEST_RESERVOIR_ONE_SETUP_VOLUME_ML ) { cmdChangeDGValveSetting( DG_VALVE_SETTING_R1_TO_R2 ); } else { cmdChangeDGValveSetting( DG_VALVE_SETTING_R2_TO_R1 ); } } if ( ( TRUE == isValvesSettingSent ) && ( TRUE == getDGCommandResponse( DG_CMD_VALVE_SETTING, &cmdResp ) ) ) { // Re-send command if DG rejects isValvesSettingSent = FALSE; if ( FALSE == cmdResp.rejected ) { if ( ( TRUE == isValvesSettingSent ) && ( TRUE == getDGCommandResponse( DG_CMD_VALVE_SETTING, &cmdResp ) ) ) { // Re-send command if DG rejects isValvesSettingSent = FALSE; if ( FALSE == cmdResp.rejected ) { F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); setDialInPumpTargetFlowRate( DIP_FLOW_RATE_SETUP_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); fmdIntegratedVolume = 0.0; if ( ( bolusVol > 0.0 ) && ( getSyringePumpVolumeDelivered() < bolusVol ) ) { startHeparinBolus(); // moved here from startHeparinPump() in Dialysis.c } state = WET_SELF_TESTS_SETUP_STATE; } } state = WET_SELF_TESTS_SETUP_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestSetupState function setup reservoir one before * the start of wet self-tests. * @details Inputs: dialysate inlet flow rate * @details Outputs: stop dialysate inlet pump * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestSetupState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_SETUP_STATE; setupDisplacementVolume -= ( SELF_TEST_FLOW_INTEGRATOR * getMeasuredDialInFlowRate() ); if ( setupDisplacementVolume <= 0 ) { signalDialInPumpHardStop(); selfTestBubble( ADV ); state = WET_SELF_TESTS_BUBBLES_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestBubblesState function waiting for air bubble detectors * self-tests to finish. * @details Inputs: bubbleSelfTestStatus * @details Outputs: none * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestBubblesState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_BUBBLES_STATE; if ( SELF_TEST_STATUS_PASSED == getBubbleSelfTestStatus( ADV ) ) { state = WET_SELF_TESTS_PRIME_CHECK_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestPrimeCheckState function checks arterial and venous * lines to make sure they are primed. * @details Inputs: Arterial and venous bubble detectors status * @details Outputs: Test pass/fail * @param result self-test result * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestPrimeCheckState( SELF_TEST_STATUS_T *result ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_PRIME_CHECK_STATE; *result = SELF_TEST_STATUS_FAILED; BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); if ( BUBBLE_NOT_DETECTED == ADVBubbleStatus ) { #ifndef _RELEASE_ // TODO do we need both of these? if ( ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_SELF_TEST ) != SW_CONFIG_ENABLE_VALUE ) && ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SELF_TESTS_AIR_BUBBLE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) ) #endif { zeroBloodLeak(); } state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; *result = SELF_TEST_STATUS_PASSED; } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestBloodLeakDetectorState function handles zeroing and * self-test for blood leak detector. * @details Inputs: none * @details Outputs: next self-test state * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestBloodLeakDetectorState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; #ifndef IGNORE_BLOOD_LEAK_SELF_TEST if ( /*( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_SELF_TEST ) != SW_CONFIG_ENABLE_VALUE ) || */ ( SELF_TEST_STATUS_PASSED == getBloodLeakSelfTestStatus() ) ) #endif { settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestStartFirstDisplacementState function setups the valves * and pumps to start first dialysate displacement. * @details Inputs: settleStartTime * @details Outputs: setup valves and pump, reservoirVolume[] * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestFirstDisplacementSetupState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE; DG_CMD_RESPONSE_T cmdResp; if ( ( FALSE == isValvesSettingSent ) && ( TRUE == didTimeout( settleStartTime, RESERVOIR_SETTLE_TIME_MS ) ) ) { reservoirVolume[ DG_RESERVOIR_1 ] = getReservoirWeightLargeFilter( DG_RESERVOIR_1 ); reservoirVolume[ DG_RESERVOIR_2 ] = getReservoirWeightLargeFilter( DG_RESERVOIR_2 ); setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); cmdChangeDGValveSetting( DG_VALVE_SETTING_R1_TO_R2 ); isValvesSettingSent = TRUE; } if ( ( TRUE == isValvesSettingSent ) && ( TRUE == getDGCommandResponse( DG_CMD_VALVE_SETTING, &cmdResp ) ) ) { // Re-send command if DG rejects isValvesSettingSent = FALSE; if ( FALSE == cmdResp.rejected ) { setDialInPumpTargetFlowRate( DIP_FLOW_RATE_FIRST_DISPLACEMENT_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); displacementStartTime = getMSTimerCount(); fmdIntegratedVolume = 0.0; state = WET_SELF_TESTS_FIRST_DISPLACEMENT_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestFirstDisplacementState function handles the first * dialysate displacement from reservoir 1 to reservoir 2. * @details Inputs: firstDisplacementStartTime, measured dialysate flow rate * @details Outputs: integrated volume * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestFirstDisplacementState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_FIRST_DISPLACEMENT_STATE; fmdIntegratedVolume += getMeasuredDialInFlowRate(); if ( TRUE == didTimeout( displacementStartTime, WET_SELF_TEST_DISPLACEMENT_TIME_MS ) ) { signalDialInPumpHardStop(); fmdIntegratedVolume = ( ( fmdIntegratedVolume * TASK_GENERAL_INTERVAL ) / ( SEC_PER_MIN * MS_PER_SECOND ) ); settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestFirstDisplacementVerifyState function checks the load cell * readings and FMD integrated volume after the first dialysate displacement. * @details Inputs: settleStartTime, reservoirVolume[], reservoirs' weights * @details Outputs: verify correctness of dialysate flow meter and load cell * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestFirstDisplacementVerifyState( SELF_TEST_STATUS_T *result ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE; if ( TRUE == didTimeout( settleStartTime, RESERVOIR_SETTLE_TIME_MS ) ) { F32 const resOneDiffAfterDisplacement = reservoirVolume[ DG_RESERVOIR_1 ] - getReservoirWeightLargeFilter( DG_RESERVOIR_1 ); F32 const resTwoDiffAfterDisplacement = getReservoirWeightLargeFilter( DG_RESERVOIR_2 ) - reservoirVolume[ DG_RESERVOIR_2 ]; F32 const integratedVolumeToTargetPercent = fabs( 1.0 - ( fmdIntegratedVolume / WET_SELF_TEST_FIRST_DISPLACEMENT_TARGET_VOLUME_ML ) ); if ( ( fabs( resOneDiffAfterDisplacement - resTwoDiffAfterDisplacement) <= WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G ) && ( integratedVolumeToTargetPercent <= WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE ) ) { state = WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE; } else { *result = SELF_TEST_STATUS_FAILED; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestSecondDisplacementSetupState function setups the valves * and pumps to start second dialysate displacement. * @details Inputs: settleStartTime * @details Outputs: setup valves and pump, reservoirVolume[] * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementSetupState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE; DG_CMD_RESPONSE_T cmdResp; if ( FALSE == isValvesSettingSent ) { reservoirVolume[ DG_RESERVOIR_1 ] = getReservoirWeightLargeFilter( DG_RESERVOIR_1 ); reservoirVolume[ DG_RESERVOIR_2 ] = getReservoirWeightLargeFilter( DG_RESERVOIR_2 ); setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); cmdChangeDGValveSetting( DG_VALVE_SETTING_R1_TO_R2 ); isValvesSettingSent = TRUE; } if ( ( TRUE == isValvesSettingSent ) && ( TRUE == getDGCommandResponse( DG_CMD_VALVE_SETTING, &cmdResp ) ) ) { // Re-send command if DG rejects isValvesSettingSent = FALSE; if ( FALSE == cmdResp.rejected ) { setDialInPumpTargetFlowRate( DIP_FLOW_RATE_SECOND_DISPLACEMENT_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); displacementStartTime = getMSTimerCount(); fmdIntegratedVolume = 0.0; state = WET_SELF_TESTS_SECOND_DISPLACEMENT_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestSecondDisplacementState function handles the first * dialysate displacement from reservoir 2 to reservoir 1. * @details Inputs: firstDisplacementStartTime, measured dialysate flow rate * @details Outputs: integrated volume * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_SECOND_DISPLACEMENT_STATE; fmdIntegratedVolume += getMeasuredDialInFlowRate(); if ( TRUE == didTimeout( displacementStartTime, WET_SELF_TEST_DISPLACEMENT_TIME_MS ) ) { signalDialInPumpHardStop(); // Convert flow into volume for period of general task interval fmdIntegratedVolume = ( ( fmdIntegratedVolume * TASK_GENERAL_INTERVAL ) / ( SEC_PER_MIN * MS_PER_SECOND ) ); settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestSecondDisplacementVerifyState function checks the load cell * readings and FMD integrated volume after the second dialysate displacement. * @details Inputs: settleStartTime, reservoirVolume[], reservoirs' weights * @details Outputs: verify correctness of dialysate flow meter and load cell * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementVerifyState( SELF_TEST_STATUS_T *result ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE; if ( TRUE == didTimeout( settleStartTime, RESERVOIR_SETTLE_TIME_MS ) ) { F32 const resOneDiffAfterDisplacement = getReservoirWeightLargeFilter( DG_RESERVOIR_1 ) - reservoirVolume[ DG_RESERVOIR_1 ]; F32 const resTwoDiffAfterDisplacement = reservoirVolume[ DG_RESERVOIR_2 ] - getReservoirWeightLargeFilter( DG_RESERVOIR_2 ); F32 const integratedVolumeToTargetPercent = fabs( 1.0 - ( fmdIntegratedVolume / WET_SELF_TEST_SECOND_DISPLACEMENT_TARGET_VOLUME_ML ) ); if ( ( fabs( resOneDiffAfterDisplacement - resTwoDiffAfterDisplacement) <= WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G ) && ( integratedVolumeToTargetPercent <= WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE ) ) { state = WET_SELF_TESTS_COMPLETE_STATE; } else { *result = SELF_TEST_STATUS_FAILED; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestStoppedState function handles the stopped wet self-tests * operation. * @details Inputs: none * @details Outputs: none * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestStoppedState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_STOPPED_STATE; if ( TRUE == selfTestsResumeRequested ) { selfTestsResumeRequested = FALSE; state = WET_SELF_TESTS_START_STATE; } return state; } /**@}*/