/************************************************************************** * * 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 SelfTests.c * * @author (last) Dara Navaei * @date (last) 20-Mar-2024 * * @author (original) Quang Nguyen * @date (original) 28-Jan-2021 * ***************************************************************************/ #include "AirPump.h" #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 "Switches.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 BLOOD_PUMP_PRESSURE_SELF_TEST_FLOW 100 ///< Pressure self-test BP flow rate in mL/min. #define DIAL_IN_PUMP_PRESSURE_SELF_TEST_FLOW 400 ///< Pressure self-test DPi 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 PRE_NORMAL_PRESSURE_SELF_TEST_DELAY_MS ( 5 * MS_PER_SECOND ) ///< Delay 5 second prior to getting initial normal baseline pressures. #define BLOOD_PUMP_RUN_TIME_PRESSURE_SELF_TEST ( 30 * MS_PER_SECOND ) ///< Pressure self-test time to run blood pump in ms. #define VENOUS_PRESSURE_SELF_TEST_MAX_TEST_TIME ( 60 * MS_PER_SECOND ) ///< Pressure self-test time to run venous self test in ms. #define DECAY_PRESSURE_SELF_TEST_TIME ( 4 * MS_PER_SECOND ) ///< time to wait for pressure to decay in ms. #define STABILTY_PRESSURE_SELF_TEST_TIME ( 5 * MS_PER_SECOND ) ///< Time to wait for pressure to stabilize in ms. #define NORMALIZED_PRESSURE_SELF_TEST_TIME ( 20 * MS_PER_SECOND ) ///< Time to wait for pressure to normalize in ms. #define NORMALIZED_PRESSURE_SELF_TEST_VBT_TIMER ( 1 * MS_PER_SECOND ) ///< Time to wait until we open VBT during normal pressure tests. #define NORMALIZED_PRESSURE_SELF_TEST_VDI_TIMER ( 5 * MS_PER_SECOND ) ///< Time to wait until we open VDI during normal pressure tests. #define ARTERIAL_DECAY_PRESSURE_DIFF_TOLERANCE_MMHG 5.0F ///< Difference in arterial pressure readings after the pump stops (in mmHg). #define VENOUS_DECAY_PRESSURE_DIFF_TOLERANCE_MMHG 5.0F ///< Difference in venous pressure readings after the pump stops (in mmHg). #define ARTERIAL_STABILITY_PRESSURE_DIFF_TOLERANCE_MMHG 5.0F ///< Difference in arterial pressure readings while in a stable pressured state (in mmHg). #define VENOUS_STABILITY_PRESSURE_DIFF_TOLERANCE_MMHG 5.0F ///< Difference in venous pressure readings while in a stable pressured state (in mmHg). #define ARTERIAL_PRESSURE_SELF_TEST_LOW_LIMIT_MMHG -200.0F ///< Arterial pressure low limit after running blood pump. #define VENOUS_PRESSURE_SELF_TEST_HIGH_LIMIT_MMHG 200.0F ///< Venous pressure high limit after running blood pump. #define VENOUS_PRESSURE_SELF_TEST_FIRST_PASS_LIMIT_MMHG 250.0F ///< Venous pressure high limit after running air pump in first test. #define NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG 20.0F ///< 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_FIRST_DISPLACEMENT_TARGET_VOLUME_ML 100.0F ///< Target of first displacement volume in ml. #define WET_SELF_TEST_SECOND_DISPLACEMENT_TARGET_VOLUME_ML 600.0F ///< Target of second displacement volume in ml. #define WET_SELF_TEST_INTEGRATED_VOLUME_PCT_TOLERANCE 0.10F ///< Tolerance on integrated volume as a percentage (10%). #define WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE 20.0F ///< Tolerance on integrated volume in grams. #define WET_SELF_TEST_INTEGRATED_VOLUME_WIDER_TOLERANCE 100.0F ///< Wider tolerance on integrated volume in grams, during debug. #define WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G 20.0F ///< Tolerance in the load cell readings of the displacement in grams. #define WET_SELF_TEST_FIRST_DISPLACEMENT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Time to displace dialysate in wet self-test in ms (first). #define WET_SELF_TEST_SECOND_DISPLACEMENT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Time to displace dialysate in wet self-test in ms (second). #define RESERVOIR_SETTLE_TIME_MS ( 5 * 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 ( 12 * SEC_PER_MIN ) ///< Maximum dry self-test time (in seconds). #define CARTRIDGE_INSERT_PRESSURE_SETTLE_TIME_MS ( 10 * MS_PER_SECOND ) ///< Time (in ms) required to wait for occlusion pressure to settle after cartridge insertion. #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. #define BLOOD_LEAK_DETECTOR_DEBUBBLE_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Blood leak detector debubble timeout in milliseconds. // ********** 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 havePumpsStartedForNCST; ///< Flag indicates pumps have started running for no cartridge pumps self-test. static BOOL pumpHomingRequestedForNCST; ///< Flag indicates pumps should be homed after running no cartridge pumps self-test. static DRY_SELF_TESTS_STATE_T currentDrySelfTestsState; ///< Current state of the dry self-tests state machine. static U32 pressureSelfTestPreNormalStartTime; ///< Pressure dry self-test pre-normal start time. static U32 pressureSelfTestBloodPumpRunStartTime; ///< Pressure dry self-test blood pump runs start time. static U32 pressureSelfTestVenousTestStartTime; ///< Pressure dry self-test dip runs start time. static U32 pressureSelfTestNormalizedStartTime; ///< Normalized pressure dry self-test start time. static U32 pressureSelfTestDecayStartTime; ///< Decay pressure dry self-test start time. static U32 pressureSelfTestStabilityStartTime; ///< Stability 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 F32 peakArterialPressure; ///< Holds the peak arterial pressure reading. static F32 peakVenousPressure; ///< Holds the peak normal venous pressure reading. static F32 decayedArterialPressure; ///< Holds the decayed arterial pressure reading after blood pump is stopped. static F32 decayedVenousPressure; ///< Holds the decayed venous pressure reading after blood pump is stopped. static BOOL dryPressureTestsCompleted; ///< Flag indicates dry cartridge pressure leak testing has been completed. 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 WET_SELF_TESTS_STATE_T checkpointWetSelfTestsState; ///< Checkpoint 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 BOOL isValvesSettingSent; ///< Flag indicates valve setting change has been sent to DG. static U32 selfTestCartridgeSettleTime; ///< Cartridge settle start time. 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 U32 bloodLeakDebubbleStartTimeMS; ///< Blood leak detector debubble start time in milliseconds. static BOOL useHeparin; ///< Flag indicates the user of heparin. static BOOL heparinOcclusionTestRun; ///< Flag indicates whether the heparin occlusion test has been run. static BOOL selfTestsResumeRequested; ///< Flag indicates user requesting self-tests resume. static BOOL cartridgeUsedTestRun; ///< Flag indicates whether the used cartridge test has been run. static BOOL occlusionBaselineWasSet; ///< Flag indicates whether the blood pump occlusion baseline for installed cartridge has been set. static BOOL doorStateAfterCartridgeInstall; ///< Flag indicates state of front door for saline clamp check after cartridge installed. // ********** private function prototypes ********** static void resetSelfTestsFlags( void ); static void setupForSelfTestsStop( void ); static void setAlarmResumePerDoorAndLatch( 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 handleDrySelfTestStartState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestWaitForDoorCloseState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestUsedCartridgeCheckState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestCartridgeLoadedCheckState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestSyringePumpSeekState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsNormalSetupState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsVenousSetupState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsVenousState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsArterialSetupState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsArterialState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsDecayState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsStabilityState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsNormalState( void ); 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( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestBloodLeakDetectorDebubbleState( void ); 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( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementSetupState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementVerifyState( void ); 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; doorStateAfterCartridgeInstall = TRUE; } /*********************************************************************//** * @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: dryPressureTestsCompleted, PreTreatmentSubState * @details Outputs: All pumps stopped * @return none *************************************************************************/ static void setupForSelfTestsStop( void ) { signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); cmdStopDGTrimmerHeater(); if ( TRUE == isAlarmActive( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM ) ) { retractSyringePump(); } else { stopSyringePump(); } setValvePosition( VDI, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VDO, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VBV, VALVE_POSITION_A_INSERT_EJECT ); // If the HD has finished no cart s.t. but not dry pressure tests, Open VBT to vent pressure // to prevent air going to the Saline bag. if ( ( HD_PRE_TREATMENT_SELF_TEST_DRY_STATE == getPreTreatmentSubState() ) && ( FALSE == dryPressureTestsCompleted ) ) { setValvePosition( VBA, VALVE_POSITION_B_OPEN ); setValveAirTrap( STATE_OPEN ); } else { setValvePosition( VBA, VALVE_POSITION_A_INSERT_EJECT ); setValveAirTrap( STATE_CLOSED ); } } /*********************************************************************//** * @brief * The setAlarmResumePerDoorAndLatch function sets alarm resume enable for * stop states based on whether door and pump track are closed. * @details Inputs: state of front door and pump track * @details Outputs: resume alarm enabled/disabled * @return none *************************************************************************/ static void setAlarmResumePerDoorAndLatch( void ) { BOOL doorClosed = ( STATE_CLOSED == getSwitchStatus( FRONT_DOOR ) ? TRUE : FALSE ); BOOL latchClosed = ( STATE_CLOSED == getSwitchStatus( PUMP_TRACK_SWITCH ) ? TRUE : FALSE ); // require front door and pump track to be closed before allowing resume if ( ( TRUE == doorClosed ) && ( TRUE == latchClosed ) ) { setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); } else { setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); } } /*********************************************************************//** * @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 ); #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP ) ) { useHeparin = FALSE; } else #endif { useHeparin = ( ( bolusVol > 0.0 ) || ( hepRate > 0.0 ) ? TRUE : FALSE ); } currentNoCartSelfTestsState = NO_CART_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; runPumpStartTime = 0; havePumpsStartedForNCST = FALSE; pumpHomingRequestedForNCST = FALSE; selfTestStartTime = getMSTimerCount(); selfTestPreviousPublishDataTime = getMSTimerCount(); setCurrentSubState( (U32)currentNoCartSelfTestsState ); doorClosedRequired( TRUE, TRUE ); // Pumps should be off signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); stopSyringePump(); // Set valves to default positions setValveAirTrap( STATE_CLOSED ); 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 ); resetSelfTestsFlags(); } /*********************************************************************//** * @brief * The execNoCartSelfTests function executes the no cartridge self-tests * state machine. * @details Inputs: currentNoCartSelfTestsState * @details Outputs: currentNoCartSelfTestsState * @return none *************************************************************************/ void execNoCartSelfTests( void ) { NO_CART_SELF_TESTS_STATE_T priorSubState = currentNoCartSelfTestsState; // execute no cartridge self-tests state machine switch ( currentNoCartSelfTestsState ) { case NO_CART_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE: currentNoCartSelfTestsState = handleNoCartSelfTestsWaitForClosedDoor(); break; case NO_CART_SELF_TESTS_PRESSURE_CHECKS_STATE: execPresOcclTest(); 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(); if ( priorSubState != currentNoCartSelfTestsState ) { setCurrentSubState( (U32)currentNoCartSelfTestsState ); SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_SUB_STATE_CHANGE, priorSubState, currentNoCartSelfTestsState ); } // Publish current self-test time data if ( calcTimeSince( selfTestPreviousPublishDataTime ) >= SELF_TEST_TIME_DATA_PUB_INTERVAL ) { U32 const elapsedSelfTestTimeInSecs = calcTimeSince( selfTestStartTime ) / MS_PER_SECOND; SELF_TEST_NO_CARTRIDGE_PAYLOAD_T data; selfTestPreviousPublishDataTime = getMSTimerCount(); data.timeout = MAX_NO_CARTRIDGE_SELF_TEST_TIME; data.countdown = ( elapsedSelfTestTimeInSecs <= MAX_NO_CARTRIDGE_SELF_TEST_TIME ? MAX_NO_CARTRIDGE_SELF_TEST_TIME - elapsedSelfTestTimeInSecs : 0 ); broadcastData( MSG_ID_HD_NO_CART_SELF_TEST_PROGRESS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( SELF_TEST_NO_CARTRIDGE_PAYLOAD_T ) ); } } /*********************************************************************//** * @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: front door state * @details Outputs: Dry self-tests re-initialized, VBA state changed depending * on front door state * @return none *************************************************************************/ void transitionToDrySelfTests() { currentDrySelfTestsState = DRY_SELF_TESTS_START_STATE; pressureSelfTestBloodPumpRunStartTime = 0; pressureSelfTestNormalizedStartTime = 0; previousNormalArterialPressure = 0.0; previousNormalVenousPressure = 0.0; dryPressureTestsCompleted = FALSE; cartridgeUsedTestRun = FALSE; occlusionBaselineWasSet = FALSE; heparinOcclusionTestRun = FALSE; selfTestStartTime = getMSTimerCount(); selfTestPreviousPublishDataTime = getMSTimerCount(); selfTestCartridgeSettleTime = getMSTimerCount(); doorClosedRequired( FALSE, TRUE ); setCurrentSubState( (U32)currentDrySelfTestsState ); // Pumps should be off signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); stopSyringePump(); // Set valves to default positions setValveAirTrap( STATE_CLOSED ); setValvePosition( VDI, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VDO, VALVE_POSITION_A_INSERT_EJECT ); if ( STATE_CLOSED == getSwitchStatus( FRONT_DOOR ) ) { setValvePosition( VBA, VALVE_POSITION_B_OPEN ); } else { setValvePosition( VBA, VALVE_POSITION_A_INSERT_EJECT ); } setValvePosition( VBV, VALVE_POSITION_A_INSERT_EJECT ); resetSelfTestsFlags(); } /*********************************************************************//** * @brief * The execDrySelfTests function executes the dry self-tests state machine. * @details Inputs: currentDrySelfTestsState * @details Outputs: currentDrySelfTestsState, pressureSelfTestPreNormalStartTime * @return none *************************************************************************/ void execDrySelfTests( void ) { DRY_SELF_TESTS_STATE_T priorSubState = currentDrySelfTestsState; // execute dry self-tests state machine switch ( currentDrySelfTestsState ) { case DRY_SELF_TESTS_START_STATE: currentDrySelfTestsState = handleDrySelfTestStartState(); 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_CARTRIDGE_LOADED_CHECK_STATE: currentDrySelfTestsState = handleDrySelfTestCartridgeLoadedCheckState(); break; case DRY_SELF_TESTS_SYRINGE_PUMP_SEEK_STATE: currentDrySelfTestsState = handleDrySelfTestSyringePumpSeekState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_SETUP_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsNormalSetupState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_VENOUS_SETUP_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsVenousSetupState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_VENOUS: currentDrySelfTestsState = handleDrySelfTestPressureSensorsVenousState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_ARTERIAL_SETUP_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsArterialSetupState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_ARTERIAL: currentDrySelfTestsState = handleDrySelfTestPressureSensorsArterialState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_DECAY_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsDecayState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_STABILITY_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsStabilityState(); break; case DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsNormalState(); 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 ( priorSubState != currentDrySelfTestsState ) { setCurrentSubState( (U32)currentDrySelfTestsState ); SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_SUB_STATE_CHANGE, priorSubState, currentDrySelfTestsState ); } // Publish current self-test time data if ( calcTimeSince( selfTestPreviousPublishDataTime ) >= SELF_TEST_TIME_DATA_PUB_INTERVAL ) { U32 const elapsedSelfTestTimeInSecs = calcTimeSince( selfTestStartTime ) / MS_PER_SECOND; SELF_TEST_DRY_PAYLOAD_T data; selfTestPreviousPublishDataTime = getMSTimerCount(); data.timeout = MAX_DRY_SELF_TEST_TIME; data.countdown = ( elapsedSelfTestTimeInSecs <= MAX_DRY_SELF_TEST_TIME ? ( MAX_DRY_SELF_TEST_TIME - elapsedSelfTestTimeInSecs ) : 0 ); broadcastData( MSG_ID_HD_DRY_SELF_TEST_PROGRESS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( SELF_TEST_DRY_PAYLOAD_T ) ); } } /*********************************************************************//** * @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() { wetSelfTestsResult = FALSE; currentWetSelfTestsState = WET_SELF_TESTS_START_STATE; checkpointWetSelfTestsState = WET_SELF_TESTS_START_STATE; settleStartTime = 0; displacementStartTime = 0; fmdIntegratedVolume = 0.0; isValvesSettingSent = FALSE; selfTestStartTime = getMSTimerCount(); selfTestPreviousPublishDataTime = getMSTimerCount(); bloodLeakDebubbleStartTimeMS = getMSTimerCount(); // Pumps should be off signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); stopSyringePump(); // Set valves to default positions setValveAirTrap( STATE_CLOSED ); setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); setCurrent4thLevelState( currentWetSelfTestsState ); resetSelfTestsFlags(); } /*********************************************************************//** * @brief * The execWetSelfTests function executes the wet self-tests state machine. * @details Inputs: currentWetSelfTestsState * @details Outputs: currentWetSelfTestsState, wetSelfTestsResult * @return none *************************************************************************/ void execWetSelfTests( void ) { WET_SELF_TESTS_STATE_T priorSubState = currentWetSelfTestsState; #ifndef _RELEASE_ if ( ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRIMING ) ) || ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_WET_SELF_TEST ) ) ) { currentWetSelfTestsState = WET_SELF_TESTS_COMPLETE_STATE; } #endif // execute wet self-tests state machine switch ( currentWetSelfTestsState ) { case WET_SELF_TESTS_START_STATE: currentWetSelfTestsState = handleWetSelfTestStartState(); break; case WET_SELF_TESTS_BUBBLE_CHECK_SETUP_STATE: currentWetSelfTestsState = handleWetSelfTestSetupState(); break; case WET_SELF_TESTS_BUBBLE_CHECK_STATE: currentWetSelfTestsState = handleWetSelfTestBubblesState(); break; case WET_SELF_TESTS_PRIME_CHECK_STATE: currentWetSelfTestsState = handleWetSelfTestPrimeCheckState(); break; case WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_DEBUBBLE_STATE: currentWetSelfTestsState = handleWetSelfTestBloodLeakDetectorDebubbleState(); 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(); 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(); 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 ( priorSubState != currentWetSelfTestsState ) { setCurrent4thLevelState( currentWetSelfTestsState ); SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_SUB_STATE_CHANGE, priorSubState, 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 getWetSelfTestState function returns the state of wet self-tests. * @details Inputs: none * @details Outputs: none * @return state of the wet self test *************************************************************************/ U32 getWetSelfTestState( void ) { return (U32)currentWetSelfTestsState; } /*********************************************************************//** * @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: selfTestStartTime * @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; OPN_CLS_STATE_T frontDoor = getSwitchStatus( FRONT_DOOR ); signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); selfTestStartTime = getMSTimerCount(); if ( STATE_CLOSED == frontDoor ) { state = NO_CART_SELF_TESTS_PRESSURE_CHECKS_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, VALVE_FORCE_HOME, VALVE_NO_CARTRIDGE_PRESENT ); } 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; BOOL syringeHome = isSyringePumpHome(); BOOL syringeStopped = isSyringePumpStopped(); BOOL syringePreloaded = isSyringePumpPreLoaded(); if ( TRUE == useHeparin ) { if ( ( TRUE != syringeHome ) && ( TRUE == syringeStopped ) && ( FALSE == syringePreloaded ) ) { retractSyringePump(); } else if ( ( TRUE == syringeHome ) && ( TRUE == syringeStopped ) && ( FALSE == syringePreloaded ) ) { // Is syringe loaded? if ( TRUE == isSyringeDetected() ) { activateAlarmNoData( ALARM_ID_HD_SYRINGE_DETECTED ); } else { preloadSyringePlunger(); } } else if ( TRUE == syringePreloaded ) { state = NO_CART_SELF_TESTS_PUMPS_STATE; } } else { 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: havePumpsStartedForNCST * @details Outputs: pumpHomingRequestedForNCST, * 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 == havePumpsStartedForNCST ) { havePumpsStartedForNCST = 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 == pumpHomingRequestedForNCST ) { // Home pumps for cartridge installation homeBloodPump(); homeDialInPump(); homeDialOutPump(); state = NO_CART_SELF_TESTS_HOME_IDLE_STATE; } else if ( TRUE == didTimeout( runPumpStartTime, PUMP_RUN_SELF_TEST_TIME_MS ) ) { // Request homing of pumps for cartridge installation signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); pumpHomingRequestedForNCST = TRUE; } 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: selfTestsResumeRequested * @details Outputs: selfTestStartTime, selfTestsResumeRequested, * havePumpsStartedForNCST, pumpHomingRequestedForNCST * @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; setAlarmResumePerDoorAndLatch(); doorClosedRequired( FALSE, FALSE ); // Restart self-test start time selfTestStartTime = getMSTimerCount(); if ( TRUE == selfTestsResumeRequested ) { selfTestsResumeRequested = FALSE; havePumpsStartedForNCST = FALSE; pumpHomingRequestedForNCST = FALSE; doorClosedRequired( TRUE, TRUE ); state = NO_CART_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestStartState 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 handleDrySelfTestStartState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_START_STATE; OPN_CLS_STATE_T pumpTrack = getSwitchStatus( PUMP_TRACK_SWITCH ); handleDoorCloseAfterCartridgeInsertion(); // want to pinch off saline once door closed after cartridge install if ( STATE_CLOSED == pumpTrack ) { // Ensure occlusion sensor has time to settle after cartridge insertion before starting dry self-tests if ( TRUE == didTimeout( selfTestCartridgeSettleTime, CARTRIDGE_INSERT_PRESSURE_SETTLE_TIME_MS ) ) { setOcclusionInstallLevel(); // Record occlusion pressure level after a new cartridge is installed occlusionBaselineWasSet = TRUE; doorClosedRequired( TRUE, TRUE ); state = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestWaitForDoorCloseState function makes sure door is * closed before starting self-tests. * @details Inputs: none * @details Outputs: selfTestStartTime * @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; OPN_CLS_STATE_T frontDoor = getSwitchStatus( FRONT_DOOR ); OPN_CLS_STATE_T pumpTrack = getSwitchStatus( PUMP_TRACK_SWITCH ); // Restart self-test start time selfTestStartTime = getMSTimerCount(); if ( ( STATE_CLOSED == frontDoor ) && ( STATE_CLOSED == pumpTrack ) ) { state = DRY_SELF_TESTS_USED_CARTRIDGE_CHECK_STATE; setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_B_OPEN ); setValvePosition( VBV, VALVE_POSITION_A_INSERT_EJECT ); } 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: cartridgeUsedTestRun * @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 ADVBubbleStatus = getBubbleStatus( ADV ); SEND_EVENT_WITH_2_U32_DATA(HD_EVENT_DRY_SELF_TEST_CARTRIDGE_RESULT,(U32)ADVBubbleStatus,(U32)BUBBLE_DETECTED) if ( ( BUBBLE_DETECTED == ADVBubbleStatus ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) ) { resetArtVenPressureOffsets(); state = DRY_SELF_TESTS_CARTRIDGE_LOADED_CHECK_STATE; } else { if ( TRUE == getTestConfigStatus( TEST_CONFIG_USE_WET_CARTRIDGE ) ) { // If either of the test configurations are set go to loaded check state = DRY_SELF_TESTS_CARTRIDGE_LOADED_CHECK_STATE; cartridgeUsedTestRun = TRUE; } else { // If we are using the worn cartridge or wet cartridge, it is not needed to alarm the user to install the new cartridge activateAlarmNoData( ALARM_ID_HD_INSTALL_NEW_CARTRIDGE ); } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestCartridgeLoadedCheckState function verifies a cartridge * is installed by checking sufficient pressure at OB sensor. * @details Inputs: none * @details Outputs: occlusionBaselineWasSet * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestCartridgeLoadedCheckState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_CARTRIDGE_LOADED_CHECK_STATE; if ( SELF_TEST_STATUS_PASSED == execPresOcclDryTest() ) { state = DRY_SELF_TESTS_SYRINGE_PUMP_SEEK_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { if ( TRUE == isAlarmActive( ALARM_ID_HD_NO_CARTRIDGE_LOADED ) ) { occlusionBaselineWasSet = FALSE; // need to get baseline again after cartridge installed properly } state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestSyringePumpSeekState function handles the syringe * pump seek dry self-test state. * @details Inputs: useHeparin * @details Outputs: pressureSelfTestPreNormalStartTime * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestSyringePumpSeekState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_SYRINGE_PUMP_SEEK_STATE; BOOL done = FALSE; if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } else { // using Heparin? if ( TRUE == useHeparin ) { // syringe pump is not busy? if ( FALSE == isSyringePumpRunning() ) { // seek completed? if ( TRUE == isSyringePlungerFound() ) { // move on when seek completed done = TRUE; } else { // pre-load completed? if ( TRUE == isSyringePumpPreLoaded() ) { // initiate seek plunger operation seekSyringePlunger(); } else { // pre-load syringe preloadSyringePlunger(); } } } } else { // not using Heparin, so move on done = TRUE; } } // setup for pressure tests when done if ( TRUE == done ) { setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_B_OPEN ); // need open path from PBA to VBT setValvePosition( VBV, VALVE_POSITION_A_INSERT_EJECT ); // need open path from PBA to VBT setValveAirTrap( STATE_OPEN ); pressureSelfTestPreNormalStartTime = getMSTimerCount(); state = DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_SETUP_STATE; if ( TRUE == getTestConfigStatus( TEST_CONFIG_USE_WET_CARTRIDGE ) ) { // skip pressure tests if using wet cartridge dryPressureTestsCompleted = TRUE; state = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; } } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsSetupState function handles the setup * for pressure sensors dry self-test. * @details Inputs: pressureSelfTestPreNormalStartTime * @details Outputs: previousNormalArterialPressure, previousNormalVenousPressure * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsNormalSetupState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_SETUP_STATE; if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } else { // wait for pressure to equalize w/ atmosphere and tare arterial and venous pressures if ( TRUE == didTimeout( pressureSelfTestPreNormalStartTime, PRE_NORMAL_PRESSURE_SELF_TEST_DELAY_MS ) ) { setArtVenPressureOffsets(); state = DRY_SELF_TESTS_PRESSURE_SENSORS_VENOUS_SETUP_STATE; } } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsVenousSetupState function handles the setup * for the venous pressure sensor dry self-test. * @details Inputs: none * @details Outputs: pressureSelfTestVenousTestStartTime * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsVenousSetupState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_VENOUS; if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } else { 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 ); setAirPumpState( AIR_PUMP_STATE_ON ); pressureSelfTestVenousTestStartTime = getMSTimerCount(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsVenousState function tests the readings of * the venous pressure sensor and verify they are in correct range. * @details Inputs: pressureSelfTestVenousTestStartTime * @details Outputs: none * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsVenousState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_VENOUS; F32 venousPressure = getFilteredVenousPressure(); // End the test when reaching target pressure or time out if ( VENOUS_PRESSURE_SELF_TEST_FIRST_PASS_LIMIT_MMHG <= venousPressure ) { setAirPumpState( AIR_PUMP_STATE_OFF ); state = DRY_SELF_TESTS_PRESSURE_SENSORS_ARTERIAL_SETUP_STATE; } if ( TRUE == didTimeout( pressureSelfTestVenousTestStartTime, VENOUS_PRESSURE_SELF_TEST_MAX_TEST_TIME ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, venousPressure, VENOUS_PRESSURE_SELF_TEST_FIRST_PASS_LIMIT_MMHG ); setAirPumpState( AIR_PUMP_STATE_OFF ); } if ( TRUE == doesAlarmStatusIndicateStop() ) { setAirPumpState( AIR_PUMP_STATE_OFF ); state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsArterialSetupState function handles the setup * for the arterial pressure sensor dry self-test. * @details Inputs: * @details Outputs: pressureSelfTestBloodPumpRunStartTime * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsArterialSetupState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_ARTERIAL; if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } else { 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( BLOOD_PUMP_PRESSURE_SELF_TEST_FLOW, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); pressureSelfTestBloodPumpRunStartTime = getMSTimerCount(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsArterialState function tests the readings of * the arterial pressure sensor and verify they are in correct range. * @details Inputs: pressureSelfTestBloodPumpRunStartTime * @details Outputs: peakVenousPressure, peakArterialPressure, * pressureSelfTestDecayStartTime * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsArterialState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_ARTERIAL; F32 arterialPressure = getFilteredArterialPressure(); F32 venousPressure = getFilteredVenousPressure(); // End the test when reaching target pressure or time out // Test pass when reading positive arterial pressure and negative venous pressure if ( ( ARTERIAL_PRESSURE_SELF_TEST_LOW_LIMIT_MMHG >= arterialPressure ) && ( VENOUS_PRESSURE_SELF_TEST_HIGH_LIMIT_MMHG <= venousPressure ) ) { peakVenousPressure = venousPressure; peakArterialPressure = arterialPressure; signalBloodPumpHardStop(); pressureSelfTestDecayStartTime = getMSTimerCount(); state = DRY_SELF_TESTS_PRESSURE_SENSORS_DECAY_STATE; } if ( TRUE == didTimeout( pressureSelfTestBloodPumpRunStartTime, BLOOD_PUMP_RUN_TIME_PRESSURE_SELF_TEST ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, venousPressure, arterialPressure ); } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsDecayState function verifies * the readings of pressure sensors after we have verified the sensors * are in the correct range by observing the loss in pressure once * the pump has stopped. * @details Inputs: pressureSelfTestDecayStartTime, peakArterialPressure, * peakVenousPressure * @details Outputs: decayedArterialPressure, decayedVenousPressure * pressureSelfTestStabilityStartTime * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsDecayState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_DECAY_STATE; F32 arterialPressure = getFilteredArterialPressure(); F32 venousPressure = getFilteredVenousPressure(); F32 arterialDecayDiff = 0.0F; F32 venousDecayDiff = 0.0F; // update peak pressure value from pressurized state // if pressure continues to increase due to filter lag. // Arterial goes negative while Venous goes positive. if ( arterialPressure < peakArterialPressure ) { peakArterialPressure = arterialPressure; } if ( venousPressure > peakVenousPressure ) { peakVenousPressure = venousPressure; } if ( TRUE == didTimeout( pressureSelfTestDecayStartTime, DECAY_PRESSURE_SELF_TEST_TIME ) ) { arterialDecayDiff = fabs( arterialPressure - peakArterialPressure ); venousDecayDiff = fabs( venousPressure - peakVenousPressure ); SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_DRY_SELF_TEST_PRESSURE_DECAY_WAIT_PERIOD, arterialDecayDiff, venousDecayDiff ) if ( ( arterialDecayDiff < ARTERIAL_DECAY_PRESSURE_DIFF_TOLERANCE_MMHG ) && ( venousDecayDiff < VENOUS_DECAY_PRESSURE_DIFF_TOLERANCE_MMHG ) ) { decayedArterialPressure = arterialPressure; decayedVenousPressure = venousPressure; pressureSelfTestStabilityStartTime = getMSTimerCount(); state = DRY_SELF_TESTS_PRESSURE_SENSORS_STABILITY_STATE; } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, arterialDecayDiff, venousDecayDiff ); } } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = DRY_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleDrySelfTestPressureSensorsStabilityState function verifies the readings of * pressure sensors in a stable, pressurized state after decay has been observed. * @details Inputs: pressureSelfTestNormalizedStartTime, decayedArterialPressure * decayedVenousPressure * @details Outputs: pressureSelfTestNormalizedStartTime * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsStabilityState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_STABILITY_STATE; F32 arterialStabilityDiff = 0.0F; F32 venousStabilityDiff = 0.0F; if ( ( TRUE == didTimeout( pressureSelfTestStabilityStartTime, STABILTY_PRESSURE_SELF_TEST_TIME ) ) ) { arterialStabilityDiff = fabs( getFilteredArterialPressure() - decayedArterialPressure ); venousStabilityDiff = fabs( getFilteredVenousPressure() - decayedVenousPressure ); SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_DRY_SELF_TEST_PRESSURE_RESULT, arterialStabilityDiff, venousStabilityDiff ) if ( ( arterialStabilityDiff < ARTERIAL_STABILITY_PRESSURE_DIFF_TOLERANCE_MMHG ) && ( venousStabilityDiff < VENOUS_STABILITY_PRESSURE_DIFF_TOLERANCE_MMHG ) ) { pressureSelfTestNormalizedStartTime = getMSTimerCount(); setValvePosition( VBV, VALVE_POSITION_B_OPEN ); state = DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_STATE; } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, arterialStabilityDiff, venousStabilityDiff ); } } 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: pressureSelfTestNormalizedStartTime * @details Outputs: none * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsNormalState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_STATE; F32 arterialPressureDiff = fabs( getFilteredArterialPressure() - previousNormalArterialPressure ); F32 venousPressureDiff = fabs( getFilteredVenousPressure() - previousNormalVenousPressure ); // open air trap after time threshold. if ( TRUE == didTimeout( pressureSelfTestNormalizedStartTime, NORMALIZED_PRESSURE_SELF_TEST_VBT_TIMER ) ) { setValveAirTrap( STATE_OPEN ); } // After VBT opened, start looking to see if pressures normalize if ( ( STATE_OPEN == getValveAirTrapStatus() ) && ( arterialPressureDiff <= NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG ) && ( venousPressureDiff <= NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG ) ) { dryPressureTestsCompleted = TRUE; state = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; } // If pressures do not normalize within max t/o, alarm if ( TRUE == didTimeout( pressureSelfTestNormalizedStartTime, NORMALIZED_PRESSURE_SELF_TEST_TIME ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_DRY_PRESSURE_NORMAL_TEST_FAILURE, arterialPressureDiff, venousPressureDiff ); } 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 3 seconds has elapsed } else { primeSyringePump(); } } else { if ( TRUE == isSyringePumpPreLoaded() ) { seekSyringePlunger(); } else { preloadSyringePlunger(); } } } } 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: syringeOcclusionDelayStartTime * @details Outputs: heparinOcclusionTestRun * @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 ) ) { if ( FALSE == checkForSyringeOcclusion( FALSE ) ) // transition to complete state only when occlusion is removed { state = DRY_SELF_TESTS_COMPLETE_STATE; } heparinOcclusionTestRun = TRUE; } 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: selfTestsResumeRequested, occlusionBaselineWasSet, * dryPressureTestsCompleted, cartridgeUsedTestRun, heparinOcclusionTestRun * @details Outputs: selfTestsResumeRequested, selfTestStartTime, selfTestCartridgeSettleTime * @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; setAlarmResumePerDoorAndLatch(); doorClosedRequired( FALSE, FALSE ); // if not enough heparin alarm, pre-load pusher after retract completes if ( TRUE == isAlarmActive( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM ) ) { // prevent resume until syringe is retracted and pre-loaded setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); if ( isSyringePumpRunning() != TRUE ) { if ( TRUE == isSyringePumpHome() ) { preloadSyringePlunger(); } else if ( TRUE == isSyringePumpPreLoaded() ) { setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); } } } // if heparin occlusin alarm, keep calling check function so alarm condition will clear when resolved if ( TRUE == isAlarmActive( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION ) ) { checkForSyringeOcclusion( FALSE ); } // Set VBA to Pos A and close VBT after we have // depressurized the line from failed pressure self tests. if ( FALSE == dryPressureTestsCompleted ) { if ( getFilteredVenousPressure() <= NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG ) { setValvePosition( VBA, VALVE_POSITION_A_INSERT_EJECT ); setValveAirTrap( STATE_CLOSED ); } } // if resume request, resume dry self-tests if ( TRUE == selfTestsResumeRequested ) { // Restart self-test start time selfTestStartTime = getMSTimerCount(); selfTestsResumeRequested = FALSE; selfTestCartridgeSettleTime = getMSTimerCount(); doorClosedRequired( TRUE, TRUE ); if ( TRUE == heparinOcclusionTestRun ) { state = DRY_SELF_TESTS_COMPLETE_STATE; } else if ( TRUE == dryPressureTestsCompleted ) { state = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; } else { doorClosedRequired( FALSE, TRUE ); setValvePosition( VBA, VALVE_POSITION_B_OPEN ); if ( TRUE == cartridgeUsedTestRun ) { doorClosedRequired( TRUE, TRUE ); resetArtVenPressureOffsets(); state = DRY_SELF_TESTS_CARTRIDGE_LOADED_CHECK_STATE; } else if ( occlusionBaselineWasSet != TRUE ) { selfTestCartridgeSettleTime = getMSTimerCount(); state = DRY_SELF_TESTS_START_STATE; } else { state = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; } } } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestStartState function handles setup state for wet * self-tests sub-mode. * @details Inputs: heparin bolus volume setting * @details Outputs: setup valves * @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_BUBBLE_CHECK_SETUP_STATE; F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); // if user set a Heparin bolus volume, request bolus to be initiated now if ( bolusVol > 0.0F ) { startHeparinBolus(); // Function will only start bolus if necessary } if ( TRUE == doesAlarmStatusIndicateStop() ) { state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestSetupState function setup for bubble self-test * check. * @details Inputs: none * @details Outputs: bubble detector self-test requested, checkpointWetSelfTestsState * @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_BUBBLE_CHECK_STATE; selfTestBubble( ADV ); if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_BUBBLE_CHECK_STATE; 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: checkpointWetSelfTestsState * @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_BUBBLE_CHECK_STATE; if ( SELF_TEST_STATUS_PASSED == getBubbleSelfTestStatus( ADV ) ) { state = WET_SELF_TESTS_PRIME_CHECK_STATE; } if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_BUBBLE_CHECK_STATE; 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, checkpointWetSelfTestsState * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestPrimeCheckState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_PRIME_CHECK_STATE; BUBBLE_STATUS_T ADVBubbleStatus = getBubbleStatus( ADV ); if ( BUBBLE_NOT_DETECTED == ADVBubbleStatus ) { if ( FALSE == isAlarmActive( ALARM_ID_HD_PRE_TREATMENT_WET_PRIME_TEST_FAILURE ) ) { if ( TRUE == zeroBloodLeak() ) { state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; // all is good to go to the next state } } else { // Stick in this state, until bubbles no longer detected/Alarm cleared if ( STATE_CLOSED == getSwitchStatus( PUMP_TRACK_SWITCH ) ) // Spurious bubble alarms occur when the cartridge is disturbed (unlatched) { clearAlarmCondition( ALARM_ID_HD_PRE_TREATMENT_WET_PRIME_TEST_FAILURE ); } } } else { if ( STATE_CLOSED == getSwitchStatus( PUMP_TRACK_SWITCH ) ) { activateAlarmNoData( ALARM_ID_HD_PRE_TREATMENT_WET_PRIME_TEST_FAILURE ); } } if ( TRUE == doesAlarmStatusIndicateStop() ) // WET_PRIME_TEST_FAILURE will force the self-tests to stop { checkpointWetSelfTestsState = WET_SELF_TESTS_PRIME_CHECK_STATE; state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestBloodLeakDetectorDebubbleState function runs the * dialin pump in bypass mode to remove the potential bubbles from the * blood leak detector prior to command another zero sequence. * @details Inputs: bloodLeakDebubbleStartTimeMS * @details Outputs: none * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestBloodLeakDetectorDebubbleState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_DEBUBBLE_STATE; if ( TRUE == didTimeout( bloodLeakDebubbleStartTimeMS, BLOOD_LEAK_DETECTOR_DEBUBBLE_TIMEOUT_MS ) ) { signalDialInPumpHardStop(); if ( getMeasuredDialInPumpSpeed() <= NEARLY_ZERO ) { if ( TRUE == zeroBloodLeak() ) { state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; } } } 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: bloodLeakDebubbleStartTimeMS, settleStartTime, * isValvesSettingSent, checkpointWetSelfTestsState * @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; SELF_TEST_STATUS_T status = getBloodLeakSelfTestStatus(); if ( SELF_TEST_STATUS_PASSED == status ) { settleStartTime = getMSTimerCount(); isValvesSettingSent = FALSE; state = WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE; } else if ( SELF_TEST_STATUS_FAILED == status ) { if ( TRUE == hasBloodLeakZeroSequenceFailed() ) { zeroBloodLeakReset(); #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif { activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_SENSOR_ZERO_SEQUENCE_FAILED ); } } else { setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setDialInPumpTargetFlowRate( DIALYSATE_FLOW_RATE_FOR_RECIRC, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); bloodLeakDebubbleStartTimeMS = getMSTimerCount(); state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_DEBUBBLE_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; 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, isValvesSettingSent * @details Outputs: isValvesSettingSent, checkpointWetSelfTestsState * @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 ) { setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); cmdChangeDGValveSetting( DG_VALVE_SETTING_R1_TO_R2 ); isValvesSettingSent = TRUE; settleStartTime = 0; } if ( ( TRUE == isValvesSettingSent ) && ( TRUE == getDGCommandResponse( DG_CMD_VALVE_SETTING, &cmdResp ) ) ) { isValvesSettingSent = FALSE; // Re-send command if DG rejects if ( DG_CMD_REQUEST_REJECT_REASON_NONE == cmdResp.rejectCode ) { setDialInPumpTargetFlowRate( DIP_FLOW_RATE_FIRST_DISPLACEMENT_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); cmdStartDGTrimmerHeater(); settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_FIRST_DISPLACEMENT_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE; 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: displacementStartTime, fmdIntegratedVolume, settleStartTime * @details Outputs: settleStartTime, displacementStartTime, checkpointWetSelfTestsState * @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; // Once we've settled (5 sec), integrate flow to volume over duration of fluid transfer if ( 0 == settleStartTime ) { fmdIntegratedVolume += ( getMeasuredDialInFlowRate() / (F32)( ( SEC_PER_MIN * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ); if ( TRUE == didTimeout( displacementStartTime, WET_SELF_TEST_FIRST_DISPLACEMENT_TIME_MS ) ) { signalDialInPumpHardStop(); cmdStopDGTrimmerHeater(); settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE; } } // Wait for settle time, then initiate transfer test if ( ( TRUE == didTimeout( settleStartTime, RESERVOIR_SETTLE_TIME_MS ) ) && ( settleStartTime != 0 ) ) { reservoirVolume[ DG_RESERVOIR_1 ] = getReservoirWeight( DG_RESERVOIR_1 ); reservoirVolume[ DG_RESERVOIR_2 ] = getReservoirWeight( DG_RESERVOIR_2 ); displacementStartTime = getMSTimerCount(); fmdIntegratedVolume = 0.0F; settleStartTime = 0; } if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_FIRST_DISPLACEMENT_STATE; 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, fmdIntegratedVolume * @details Outputs: checkpointWetSelfTestsState * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestFirstDisplacementVerifyState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE; F32 resOneDiffAfterDisplacement = reservoirVolume[ DG_RESERVOIR_1 ] - getReservoirWeight( DG_RESERVOIR_1 ); F32 resTwoDiffAfterDisplacement = getReservoirWeight( DG_RESERVOIR_2 ) - reservoirVolume[ DG_RESERVOIR_2 ]; F32 averageDisp = ( resOneDiffAfterDisplacement + resTwoDiffAfterDisplacement ) / 2.0F; F32 integratedVolumeDiff = fabs( fmdIntegratedVolume - averageDisp ); F32 integratedVolumeToTargetPercent = fabs( 1.0F - ( fmdIntegratedVolume / averageDisp ) ); F32 integrateVolumeToleranceG = WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE; #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_WET_SELF_TEST_WIDER_VOLUME_TOL ) ) { integrateVolumeToleranceG = WET_SELF_TEST_INTEGRATED_VOLUME_WIDER_TOLERANCE; } #endif SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT, resOneDiffAfterDisplacement, resTwoDiffAfterDisplacement ) SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT, averageDisp, fmdIntegratedVolume ) if ( ( fabs( resOneDiffAfterDisplacement - resTwoDiffAfterDisplacement ) <= WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G ) && ( ( integratedVolumeDiff <= integrateVolumeToleranceG ) || ( integratedVolumeToTargetPercent <= WET_SELF_TEST_INTEGRATED_VOLUME_PCT_TOLERANCE ) ) ) { state = WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE; } else { if ( getTestConfigStatus( TEST_CONFIG_DISABLE_WET_SELFTEST_DISPLACEMENT_ALARM ) != TRUE ) { if ( fabs( resOneDiffAfterDisplacement - resTwoDiffAfterDisplacement) > WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_WET_LC_TEST_FAILURE, resOneDiffAfterDisplacement, resTwoDiffAfterDisplacement ); } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_WET_FLOW_TEST_FAILURE, averageDisp, fmdIntegratedVolume ); } } else { state = WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE; 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, isValvesSettingSent * @details Outputs: isValvesSettingSent, checkpointWetSelfTestsState * @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 ) { setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); cmdChangeDGValveSetting( DG_VALVE_SETTING_R2_TO_R1 ); isValvesSettingSent = TRUE; settleStartTime = 0; } if ( ( TRUE == isValvesSettingSent ) && ( TRUE == getDGCommandResponse( DG_CMD_VALVE_SETTING, &cmdResp ) ) ) { isValvesSettingSent = FALSE; // Re-send command if DG rejects if ( DG_CMD_REQUEST_REJECT_REASON_NONE == cmdResp.rejectCode ) { setDialInPumpTargetFlowRate( DIP_FLOW_RATE_SECOND_DISPLACEMENT_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); cmdStartDGTrimmerHeater(); settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_SECOND_DISPLACEMENT_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE; 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: displacementStartTime, fmdIntegratedVolume, settleStartTime * @details Outputs: displacementStartTime, checkpointWetSelfTestsState * @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; if ( ( TRUE == didTimeout( settleStartTime, RESERVOIR_SETTLE_TIME_MS ) ) && ( settleStartTime != 0 ) ) { reservoirVolume[ DG_RESERVOIR_1 ] = getReservoirWeight( DG_RESERVOIR_1 ); reservoirVolume[ DG_RESERVOIR_2 ] = getReservoirWeight( DG_RESERVOIR_2 ); displacementStartTime = getMSTimerCount(); fmdIntegratedVolume = 0.0F; settleStartTime = 0; } if ( 0 == settleStartTime ) { fmdIntegratedVolume += ( getMeasuredDialInFlowRate() / (F32)( ( SEC_PER_MIN * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ); if ( TRUE == didTimeout( displacementStartTime, WET_SELF_TEST_SECOND_DISPLACEMENT_TIME_MS ) ) { signalDialInPumpHardStop(); cmdStopDGTrimmerHeater(); settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_SECOND_DISPLACEMENT_STATE; 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, checkpointWetSelfTestsState * @return the next state of wet self-tests state machine *************************************************************************/ static WET_SELF_TESTS_STATE_T handleWetSelfTestSecondDisplacementVerifyState( void ) { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE; F32 resOneDiffAfterDisplacement = getReservoirWeight( DG_RESERVOIR_1 ) - reservoirVolume[ DG_RESERVOIR_1 ]; F32 resTwoDiffAfterDisplacement = reservoirVolume[ DG_RESERVOIR_2 ] - getReservoirWeight( DG_RESERVOIR_2 ); F32 avgDisp = ( resOneDiffAfterDisplacement + resTwoDiffAfterDisplacement ) / 2.0F; F32 integratedVolumeDiff = fabs( fmdIntegratedVolume - avgDisp ); F32 integratedVolumeToTargetPercent = fabs( 1.0F - ( fmdIntegratedVolume / avgDisp ) ); F32 integrateVolumeToleranceG = WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE; #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_WET_SELF_TEST_WIDER_VOLUME_TOL ) ) { integrateVolumeToleranceG = WET_SELF_TEST_INTEGRATED_VOLUME_WIDER_TOLERANCE; } #endif SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT, resOneDiffAfterDisplacement, resTwoDiffAfterDisplacement ) SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT, avgDisp, fmdIntegratedVolume ) if ( ( fabs( resOneDiffAfterDisplacement - resTwoDiffAfterDisplacement ) <= WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G ) && ( ( integratedVolumeDiff <= integrateVolumeToleranceG ) || ( integratedVolumeToTargetPercent <= WET_SELF_TEST_INTEGRATED_VOLUME_PCT_TOLERANCE ) ) ) { state = WET_SELF_TESTS_COMPLETE_STATE; } else { if ( getTestConfigStatus( TEST_CONFIG_DISABLE_WET_SELFTEST_DISPLACEMENT_ALARM ) != TRUE ) { if ( fabs( resOneDiffAfterDisplacement - resTwoDiffAfterDisplacement) > WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_WET_LC_TEST_FAILURE, resOneDiffAfterDisplacement, resTwoDiffAfterDisplacement ); } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_WET_FLOW_TEST_FAILURE, avgDisp, fmdIntegratedVolume ); } } else { state = WET_SELF_TESTS_COMPLETE_STATE; } } if ( TRUE == doesAlarmStatusIndicateStop() ) { checkpointWetSelfTestsState = WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE; state = WET_SELF_TESTS_STOPPED_STATE; setupForSelfTestsStop(); } return state; } /*********************************************************************//** * @brief * The handleWetSelfTestStoppedState function handles the stopped wet self-tests * operation. * @details Inputs: selfTestsResumeRequested, checkpointWetSelfTestsState * @details Outputs: selfTestsResumeRequested, selfTestStartTime * @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; F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); setAlarmResumePerDoorAndLatch(); doorClosedRequired( FALSE, FALSE ); if ( TRUE == selfTestsResumeRequested ) { if ( BUBBLE_NOT_DETECTED == getBubbleStatus( ADV ) ) { if ( STATE_CLOSED == getSwitchStatus( PUMP_TRACK_SWITCH ) ) // Spurious bubble alarms occur when the cartridge is disturbed (unlatched) { clearAlarmCondition( ALARM_ID_HD_PRE_TREATMENT_WET_PRIME_TEST_FAILURE ); } } // Restart self-test start time selfTestStartTime = getMSTimerCount(); doorClosedRequired( TRUE, TRUE ); selfTestsResumeRequested = FALSE; // if user set a Heparin bolus volume, request bolus to be initiated now if ( bolusVol > 0.0F ) { startHeparinBolus(); // Function will only start bolus if necessary } switch( checkpointWetSelfTestsState ) { case WET_SELF_TESTS_BUBBLE_CHECK_SETUP_STATE: case WET_SELF_TESTS_BUBBLE_CHECK_STATE: case WET_SELF_TESTS_PRIME_CHECK_STATE: case WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_DEBUBBLE_STATE: case WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE: state = WET_SELF_TESTS_START_STATE; break; case WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE: case WET_SELF_TESTS_FIRST_DISPLACEMENT_STATE: state = WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE; break; case WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE: state = WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE; break; case WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE: case WET_SELF_TESTS_SECOND_DISPLACEMENT_STATE: state = WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE; break; case WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE: case WET_SELF_TESTS_COMPLETE_STATE: state = WET_SELF_TESTS_COMPLETE_STATE; break; default: state = WET_SELF_TESTS_START_STATE; break; } } return state; } /*********************************************************************//** * @brief * The handleDoorCloseAfterCartridgeInsertion function handles the check * for door close after cartridge install so that saline line can be pinched. * @details Inputs: door and latch states, doorStateAfterCartridgeInstall * @details Outputs: doorStateAfterCartridgeInstall * @return none *************************************************************************/ void handleDoorCloseAfterCartridgeInsertion( void ) { OPN_CLS_STATE_T frontDoor = getSwitchStatus( FRONT_DOOR ); OPN_CLS_STATE_T pumpTrack = getSwitchStatus( PUMP_TRACK_SWITCH ); if ( ( STATE_OPEN == frontDoor ) && ( TRUE == doorStateAfterCartridgeInstall ) ) { doorStateAfterCartridgeInstall = FALSE; } // when transitioning from door open to door closed, pinch off saline bag to prevent saline from running up the line if ( ( STATE_CLOSED == frontDoor ) && ( STATE_CLOSED == pumpTrack ) && ( FALSE == doorStateAfterCartridgeInstall ) ) { setValvePosition( VBA, VALVE_POSITION_B_OPEN ); doorStateAfterCartridgeInstall = TRUE; } } /**@}*/