/************************************************************************** * * Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file ModePreTreat.c * * @author (last) Sean Nash * @date (last) 06-Oct-2020 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 * ***************************************************************************/ #include "AlarmMgmt.h" #include "ConsumableSelfTest.h" #include "FPGA.h" #include "ModePreTreat.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" #include "PreTreatmentRecirc.h" #include "Prime.h" #include "SelfTests.h" #include "SampleWater.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" /** * @addtogroup HDPreTreatmentMode * @{ */ // ********** private definitions ********** /// Interval (ms/task time) at which the pre-treatment state data is published on the CAN bus. #define PRE_TREATMENT_DATA_PUB_INTERVAL ( 250 / TASK_GENERAL_INTERVAL ) /// Wait time for ui to transition on completion of a sub-mode (ms/task time). #define SUBMODE_COMPLETE_UI_TRANSITION_TIME_COUNT ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) #define DIP_PATIENT_CONNECTION_FLOW_RATE_ML_MIN 100 ///< Patient connection sub-mode dialysate inlet pump flow rate in mL/min. #define PRE_TREATMENT_FILL_RESERVOIR_ONE_VOLUME_ML 1300 ///< Fill reservoir one to this volume (in mL) during pre-treatment mode. #define PRE_TREATMENT_FILL_RESERVOIR_TWO_VOLUME_ML 700 ///< Fill reservoir two to this volume (in mL) during pre-treatment mode. #define PRIMARY_HEATER_TARGET_TEMP_OFFSET 2.0 ///< Primary heater target temperature offset from trimmer heater temperature. /// States of the pre-treatment reservoir management state machine. typedef enum PreTreatmentReservoirMgmt_States { PRE_TREATMENT_RESERVOIR_MGMT_START_STATE = 0, ///< Wait for signal to start drain and fill reservoirs PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE, ///< Command DG to start draining reservoir PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_RESP_STATE, ///< After sending drain command, process DG drain command response PRE_TREATMENT_RESERVOIR_MGMT_START_FILL_STATE, ///< Command DG to start filling reservoir PRE_TREATMENT_RESERVOIR_MGMT_FILL_CMD_RESP_STATE, ///< After sending fill command, process DG fill command response PRE_TREATMENT_RESERVOIR_MGMT_FILL_COMPLETE_STATE, ///< Reservoir fill has completed PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE, ///< Wait for prime operation to switch reservoir PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE, ///< Pre-treatment reservoir management complete state NUM_OF_PRE_TREATMENT_RESERVOIR_MGMT_STATES ///< Number of pre-treatments reservoir mgmt. states } PRE_TREATMENT_RESERVOIR_MGMT_STATE_T; // ********** private data ********** static BOOL confirmInstallRequested = FALSE; ///< Flag indicates user confirms disposable installation. static BOOL continueToTreatmentRequested = FALSE; ///< Flag indicates user requests to continue to treatment from re-circ. static BOOL setUFVolStatus; ///< The status of set UF volume operation. static BOOL patientConnectionConfirm; ///< Flag indicates user has confirmed patient connection complete. static BOOL treatmentStartRequested = FALSE; ///< Flag indicates user requests treatment begin. static BOOL alarmActionResumeReceived = FALSE; ///< Flag indicates alarm action resume received. static HD_PRE_TREATMENT_MODE_STATE_T currentPreTreatmentState; ///< Current state of pre-treatment mode state machine. static U32 preTreatmentPublishTimerCounter; ///< Pre-treatment data broadcast timer counter used to schedule when to transmit data. static U32 submodeCompleteTransitionTimeCounter; ///< Sub-mode completed transition wait time counter. static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T currentReservoirMgmtState; ///< Current pre-treatment reservoir management state. static BOOL fillReservoirOneStartRequested; ///< Flag indicates fill reservoir one has been requested. static BOOL reservoirFilledStatus[ NUM_OF_DG_RESERVOIRS ]; ///< Flag indicates a reservoir has been filled. // ********** private function prototypes ********** static void publishPreTreatmentState( void ); static void resetSignalFlags( void ); static void transitionToCartridgeInstallation( void ); static void transitionToPatientConnection( void ); static HD_PRE_TREATMENT_MODE_STATE_T handleWaterSampleState( void ); static HD_PRE_TREATMENT_MODE_STATE_T handleSelfTestConsumableState( void ); static HD_PRE_TREATMENT_MODE_STATE_T handleSelfTestNoCartState( void ); static HD_PRE_TREATMENT_MODE_STATE_T handleInstallState( void ); static HD_PRE_TREATMENT_MODE_STATE_T handleSelfTestDryState( void ); static HD_PRE_TREATMENT_MODE_STATE_T handlePrimeState( void ); static HD_PRE_TREATMENT_MODE_STATE_T handleRecirculateState( void ); static HD_PRE_TREATMENT_MODE_STATE_T handlePatientConnectionState( void ); static void execPreTreatmentReservoirMgmt( void ); static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtStartState( void ); static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtDrainCmdState( void ); static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtDrainCmdRespState( void ); static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtFillCmdState( void ); static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtFillCmdRespState( void ); static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtFillCompleteState( void ); static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtWaitReservoirSwitchState( void ); /*********************************************************************//** * @brief * The initPreTreatmentMode function initializes the Pre-Treatment Mode module. * @details Inputs: none * @details Outputs: Pre-Treatment Mode module initialized. * @return none *************************************************************************/ void initPreTreatmentMode( void ) { currentPreTreatmentState = HD_PRE_TREATMENT_START_STATE; currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_START_STATE; setUFVolStatus = FALSE; patientConnectionConfirm = FALSE; fillReservoirOneStartRequested = FALSE; submodeCompleteTransitionTimeCounter = 0; reservoirFilledStatus[ DG_RESERVOIR_1 ] = FALSE; reservoirFilledStatus[ DG_RESERVOIR_2 ] = FALSE; initSampleWater(); initConsumableSelfTest(); initPrime(); initSelfTests(); resetSignalFlags(); } /*********************************************************************//** * @brief * The transitionToPreTreatmentMode function prepares for transition to * pre-treatment mode. * @details Inputs: none * @details Outputs: none * @return none *************************************************************************/ void transitionToPreTreatmentMode( void ) { // Set user alarm recovery actions allowed in this mode setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); initPreTreatmentMode(); cmdStopDGTrimmerHeater(); } /*********************************************************************//** * @brief * The execPreTreatmentMode function executes the Pre-Treatment Mode state machine. * @details Inputs: none * @details Outputs: none * @return current state (sub-mode) *************************************************************************/ U32 execPreTreatmentMode( void ) { BOOL stop = isStopButtonPressed(); if ( TRUE == stop ) { activateAlarmNoData( ALARM_ID_TREATMENT_STOPPED_BY_USER ); } // execute mode state machine switch ( currentPreTreatmentState ) { case HD_PRE_TREATMENT_START_STATE: #ifndef SKIP_SAMPLE_WATER transitionToSampleWater(); #endif currentPreTreatmentState = HD_PRE_TREATMENT_WATER_SAMPLE_STATE; break; case HD_PRE_TREATMENT_WATER_SAMPLE_STATE: currentPreTreatmentState = handleWaterSampleState(); break; case HD_PRE_TREATMENT_SELF_TEST_CONSUMABLE_STATE: currentPreTreatmentState = handleSelfTestConsumableState(); break; case HD_PRE_TREATMENT_SELF_TEST_NO_CART_STATE: currentPreTreatmentState = handleSelfTestNoCartState(); break; case HD_PRE_TREATMENT_CART_INSTALL_STATE: currentPreTreatmentState = handleInstallState(); break; case HD_PRE_TREATMENT_SELF_TEST_DRY_STATE: currentPreTreatmentState = handleSelfTestDryState(); break; case HD_PRE_TREATMENT_PRIME_STATE: currentPreTreatmentState = handlePrimeState(); break; case HD_PRE_TREATMENT_RECIRCULATE_STATE: currentPreTreatmentState = handleRecirculateState(); break; case HD_PRE_TREATMENT_PATIENT_CONNECTION_STATE: currentPreTreatmentState = handlePatientConnectionState(); break; default: currentPreTreatmentState = HD_PRE_TREATMENT_START_STATE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRE_TREATMENT_INVALID_STATE, (U32)currentPreTreatmentState ); break; } // Execute reservoir management for pre-treatment mode execPreTreatmentReservoirMgmt(); // Alarm response request flags should be handled at this point, reset in case not handled in current state resetSignalFlags(); // Broadcast pre-treatment data publishPreTreatmentState(); return (U32)currentPreTreatmentState; } /*********************************************************************//** * @brief * The signalUserConfirmInstallation function handles user confirmation of * disposable installation. * @details Inputs: none * @details Outputs: confirmInstallRequested * @return TRUE if signal accepted, FALSE if not *************************************************************************/ void signalUserConfirmInstallation( void ) { if ( ( MODE_PRET == getCurrentOperationMode() ) && ( HD_PRE_TREATMENT_CART_INSTALL_STATE == currentPreTreatmentState ) ) { confirmInstallRequested = TRUE; } } /*********************************************************************//** * @brief * The signalUserContinueToTreatment function handles user request to continue * to treatment. * @details Inputs: none * @details Outputs: handled and send response to continue to treatment request * @return none *************************************************************************/ void signalUserContinueToTreatment( void ) { BOOL accepted = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; if ( HD_PRE_TREATMENT_RECIRCULATE_STATE == currentPreTreatmentState ) { continueToTreatmentRequested = TRUE; accepted = TRUE; rejReason = REQUEST_REJECT_REASON_NONE; } sendContinueToTreatmentCmdResponse( accepted, rejReason ); } /*********************************************************************//** * @brief * The setUserSetUFVolumeStatus function sets the status for user sets UF * volume operation. * @details Inputs: set UF volume operation status * @details Outputs: setUFVolStatus * @return none *************************************************************************/ void setUserSetUFVolumeStatus( BOOL status ) { setUFVolStatus = status; } /*********************************************************************//** * @brief * The signalUserConfirmPatientConnection function handles user confirms * patient connection message. * @details Inputs: none * @details Outputs: handled and send response to patient connection confirmation * @return none *************************************************************************/ void signalUserConfirmPatientConnection( void ) { BOOL accepted = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_UF_VOLUME_NOT_SET; if ( TRUE == setUFVolStatus ) { if ( HD_PRE_TREATMENT_PATIENT_CONNECTION_STATE == currentPreTreatmentState ) { patientConnectionConfirm = TRUE; accepted = TRUE; rejReason = REQUEST_REJECT_REASON_NONE; } else { rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; } } sendPatientConnectionConfirmCmdResponse( accepted, rejReason ); } /*********************************************************************//** * @brief * The signalUserStartTreatment function handles user requests to start treatment. * @details Inputs: patientConnectionConfirm, currentPreTreatmentState * @details Outputs: handled and send response to treatment start request * @return none *************************************************************************/ void signalUserStartTreatment( void ) { BOOL accepted = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NO_PATIENT_CONNECTION_CONFIRM; #ifndef SKIP_UI_INTERACTION if ( TRUE == patientConnectionConfirm ) #endif { if ( ( MODE_PRET == getCurrentOperationMode() ) && ( HD_PRE_TREATMENT_PATIENT_CONNECTION_STATE == currentPreTreatmentState ) ) { treatmentStartRequested = TRUE; accepted = TRUE; rejReason = REQUEST_REJECT_REASON_NONE; } else { rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; } } sendStartTreatmentResponse( accepted, rejReason ); } /*********************************************************************//** * @brief * The signalAlarmActionToPreTreatmentMode function executes the given alarm action * as appropriate while in PreTreatment Mode. * @details Inputs: none * @details Outputs: given alarm action executed * @param action ID of alarm action to execute * @return none *************************************************************************/ void signalAlarmActionToPreTreatmentMode( ALARM_ACTION_T action ) { switch( action ) { case ALARM_ACTION_STOP: // Stop signal actively polled by mode/sub-mode/state break; case ALARM_ACTION_RESUME: alarmActionResumeReceived = TRUE; break; case ALARM_ACTION_END_TREATMENT: if ( HD_PRE_TREATMENT_PRIME_STATE > currentPreTreatmentState ) { requestNewOperationMode( MODE_STAN ); } else { requestNewOperationMode( MODE_POST ); } break; case ALARM_ACTION_ACK: // Nothing to be done here break; default: // Ignore break; } } /*********************************************************************//** * @brief * The getReservoirFillStatus function returns the fill complete status for * given reservoir. * @details Inputs: reservoirFilledStatus * @details Outputs: none * @return TRUE if reservoir has been filled, otherwise FALSE; *************************************************************************/ BOOL getReservoirFillStatus( DG_RESERVOIR_ID_T reservoirID ) { return reservoirFilledStatus[ reservoirID ]; } /*********************************************************************//** * @brief * The publishPreTreatmentState function broadcasts pre-treatment sub-mode * and current sub-mode state. * @details Inputs: pre-treatment sub-mode, state * @details Outputs: pre-treatment sub-mode, state messages sent on interval * @return none *************************************************************************/ static void publishPreTreatmentState( void ) { // Broadcast treatment time and state data at interval if ( ++preTreatmentPublishTimerCounter >= PRE_TREATMENT_DATA_PUB_INTERVAL ) { PRE_TREATMENT_STATE_DATA_T preTreatmentData; preTreatmentData.preTreatmentSubMode = currentPreTreatmentState; preTreatmentData.sampleWaterState = getSampleWaterState(); preTreatmentData.consumableSelfTestsState = getConsumableSelfTestState(); preTreatmentData.noCartSelfTestsState = getNoCartSelfTestsState(); preTreatmentData.installState = 0; preTreatmentData.drySelfTestsState = getDrySelfTestsState(); preTreatmentData.primeState = getPrimeState(); preTreatmentData.recircState = getPreTreatmentRecircState(); preTreatmentData.patientConnectionState = 0; broadcastPreTreatmentState( &preTreatmentData ); preTreatmentPublishTimerCounter = 0; } } /*********************************************************************//** * @brief * The resetSignalFlags function resets all signal flags. * @details Inputs: none * @details Outputs: signal flags set to FALSE * @return none *************************************************************************/ static void resetSignalFlags( void ) { treatmentStartRequested = FALSE; confirmInstallRequested = FALSE; continueToTreatmentRequested = FALSE; alarmActionResumeReceived = FALSE; } /*********************************************************************//** * @brief * The transitionToCartridgeInstallation function prepares actuators before * transition to pre-treatment install state. * @details Inputs: none * @details Outputs: valves are in insert position * @return none *************************************************************************/ static void transitionToCartridgeInstallation( void ) { VALVE_T valve; for ( valve = VDI; valve < NUM_OF_VALVES; ++valve ) { setValvePosition( valve, VALVE_POSITION_A_INSERT_EJECT ); } setValveAirTrap( STATE_CLOSED ); } /*********************************************************************//** * @brief * The transitionToPatientConnection function prepares actuators before * transition to pre-treatment patient connection state. * @details Inputs: none * @details Outputs: Stopped pumps * @return none *************************************************************************/ static void transitionToPatientConnection( void ) { VALVE_T valve; setUFVolStatus = FALSE; patientConnectionConfirm = FALSE; treatmentStartRequested = FALSE; for ( valve = VDI; valve < NUM_OF_VALVES; ++valve ) { setValvePosition( valve, VALVE_POSITION_C_CLOSE ); } signalBloodPumpHardStop(); signalDialOutPumpHardStop(); setDialInPumpTargetFlowRate( DIP_PATIENT_CONNECTION_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); cmdStartDGTrimmerHeater(); } /*********************************************************************//** * @brief * The handleWaterSampleState function handles sample water state during * pre-treatment mode. * @details Inputs: none * @details Outputs: executed sample water state machine * @return current state (sub-mode) *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handleWaterSampleState( void ) { HD_PRE_TREATMENT_MODE_STATE_T state = HD_PRE_TREATMENT_WATER_SAMPLE_STATE; DG_OP_MODE_T dgOpMode = getDGOpMode(); U32 dgSubMode = getDGSubMode(); execSampleWater(); #ifndef SKIP_SAMPLE_WATER if ( SAMPLE_WATER_COMPLETE_STATE == getSampleWaterState() ) #endif { cmdDGSampleWater( SAMPLE_WATER_CMD_END ); if ( SELF_TEST_STATUS_PASSED == getSampleWaterResult() ) { if ( ( DG_MODE_STAN == dgOpMode ) && ( DG_STANDBY_MODE_STATE_IDLE == dgSubMode ) ) { state = HD_PRE_TREATMENT_SELF_TEST_CONSUMABLE_STATE; F32 const trimmerHeaterTemp = getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ); F32 const primaryHeaterTemp = trimmerHeaterTemp + PRIMARY_HEATER_TARGET_TEMP_OFFSET; cmdStartDG(); cmdSetDGDialysateTargetTemps( primaryHeaterTemp, trimmerHeaterTemp ); transitionToConsumableSelfTest(); } else { cmdStopDG(); } } else { requestNewOperationMode( MODE_STAN ); } } return state; } /*********************************************************************//** * @brief * The handleSelfTestConsumableState function handles consumable self-test state * during pre-treatment mode. * @details Inputs: none * @details Outputs: executed consumable self-test state machine * @return current state (sub-mode) *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handleSelfTestConsumableState( void ) { HD_PRE_TREATMENT_MODE_STATE_T state = HD_PRE_TREATMENT_SELF_TEST_CONSUMABLE_STATE; execConsumableSelfTest(); if ( CONSUMABLE_SELF_TESTS_COMPLETE_STATE == getConsumableSelfTestState() ) { if ( submodeCompleteTransitionTimeCounter++ >= SUBMODE_COMPLETE_UI_TRANSITION_TIME_COUNT ) { submodeCompleteTransitionTimeCounter = 0; state = HD_PRE_TREATMENT_SELF_TEST_NO_CART_STATE; fillReservoirOneStartRequested = TRUE; transitionToNoCartSelfTests(); } } return state; } /*********************************************************************//** * @brief * The handleSelfTestNoCartState function handles self-test with no cartridge. * @details Inputs: none * @details Outputs: home blood pump and dialysate pumps * @return current state (sub-mode) *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handleSelfTestNoCartState( void ) { HD_PRE_TREATMENT_MODE_STATE_T state = HD_PRE_TREATMENT_SELF_TEST_NO_CART_STATE; if ( STATE_OPEN == getFPGADoorState() ) { activateAlarmNoData( ALARM_ID_CARTRIDGE_DOOR_OPENED ); } if ( TRUE == alarmActionResumeReceived ) { alarmActionResumeReceived = FALSE; signalResumeSelfTests(); } execNoCartSelfTests(); if ( NO_CART_SELF_TESTS_COMPLETE_STATE == getNoCartSelfTestsState() ) { if ( submodeCompleteTransitionTimeCounter++ >= SUBMODE_COMPLETE_UI_TRANSITION_TIME_COUNT ) { submodeCompleteTransitionTimeCounter = 0; state = HD_PRE_TREATMENT_CART_INSTALL_STATE; transitionToCartridgeInstallation(); } } return state; } /*********************************************************************//** * @brief * The handleInstallState function handles disposable installation. * @details Inputs: none * @details Outputs: transition to prime sub-mode when blood pump finished * homing * @return current state (sub-mode) *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handleInstallState( void ) { HD_PRE_TREATMENT_MODE_STATE_T state = HD_PRE_TREATMENT_CART_INSTALL_STATE; #ifndef SKIP_UI_INTERACTION if ( TRUE == confirmInstallRequested ) #endif { confirmInstallRequested = FALSE; state = HD_PRE_TREATMENT_SELF_TEST_DRY_STATE; transitionToDrySelfTests(); } return state; } /*********************************************************************//** * @brief * The handleSelfTestDryState function performs dry self-test. * @details Inputs: none * @details Outputs: transition to prime state on user request * @return current state (sub-mode) *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handleSelfTestDryState( void ) { HD_PRE_TREATMENT_MODE_STATE_T state = HD_PRE_TREATMENT_SELF_TEST_DRY_STATE; if ( STATE_OPEN == getFPGADoorState() ) { activateAlarmNoData( ALARM_ID_CARTRIDGE_DOOR_OPENED ); } if ( TRUE == alarmActionResumeReceived ) { alarmActionResumeReceived = FALSE; signalResumeSelfTests(); } execDrySelfTests(); if ( DRY_SELF_TESTS_COMPLETE_STATE == getDrySelfTestsState() ) { if ( submodeCompleteTransitionTimeCounter++ >= SUBMODE_COMPLETE_UI_TRANSITION_TIME_COUNT ) { submodeCompleteTransitionTimeCounter = 0; state = HD_PRE_TREATMENT_PRIME_STATE; transitionToPrime(); } } return state; } /*********************************************************************//** * @brief * The handlePrimeState function handles priming the blood and dialysate * circuits. * @details Inputs: none * @details Outputs: transition to self test wet state after priming passed * @return current state (sub-mode) *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handlePrimeState( void ) { HD_PRE_TREATMENT_MODE_STATE_T state = HD_PRE_TREATMENT_PRIME_STATE; if ( STATE_OPEN == getFPGADoorState() ) { activateAlarmNoData( ALARM_ID_CARTRIDGE_DOOR_OPENED ); } if ( TRUE == alarmActionResumeReceived ) { alarmActionResumeReceived = FALSE; signalResumePrime(); } execPrime(); if ( HD_PRIME_COMPLETE == getPrimeState() ) { if ( submodeCompleteTransitionTimeCounter++ >= SUBMODE_COMPLETE_UI_TRANSITION_TIME_COUNT ) { submodeCompleteTransitionTimeCounter = 0; state = HD_PRE_TREATMENT_RECIRCULATE_STATE; activateAlarmNoData( ALARM_ID_PRIME_COMPLETED_LOW_PRIORITY ); transitionToPreTreatmentRecirc(); } } return state; } /*********************************************************************//** * @brief * The handleRecirculateState function handles blood and dialysate circuits * recirculation state during pre-treatment mode. * @details Inputs: none * @details Outputs: controlled valves and pumps * @return current state (sub-mode) *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handleRecirculateState( void ) { HD_PRE_TREATMENT_MODE_STATE_T state = HD_PRE_TREATMENT_RECIRCULATE_STATE; if ( STATE_OPEN == getFPGADoorState() ) { activateAlarmNoData( ALARM_ID_CARTRIDGE_DOOR_OPENED ); } if ( TRUE == alarmActionResumeReceived ) { alarmActionResumeReceived = FALSE; signalResumePreTreatmentRecirc(); } execPreTreatmentRecirc(); #ifndef SKIP_UI_INTERACTION if ( TRUE == continueToTreatmentRequested ) #endif { continueToTreatmentRequested = FALSE; state = HD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; transitionToPatientConnection(); } return state; } /*********************************************************************//** * @brief * The handlePatientConnectionState function handles patient connection state * during pre-treatment mode. * @details Inputs: none * @details Outputs: requested mode transition to treatment mode * @return current state (sub-mode) *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handlePatientConnectionState( void ) { if ( TRUE == treatmentStartRequested ) { DG_RESERVOIR_ID_T const activeRes = getDGActiveReservoir(); setStartReservoirVolume( activeRes ); requestNewOperationMode( MODE_TREA ); } return HD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; } /*********************************************************************//** * @brief * The execPreTreatmentReservoirMgmt function executes the state machine for * reservoir management during pre-treatment mode. * @details Inputs: currentReservoirMgmtState * @details Outputs: DG reservoirs' fills managed. * @return none *************************************************************************/ static void execPreTreatmentReservoirMgmt( void ) { // treatment reservoir mgmt. state machine switch ( currentReservoirMgmtState ) { case PRE_TREATMENT_RESERVOIR_MGMT_START_STATE: currentReservoirMgmtState = handlePreTreatmentReservoirMgmtStartState(); break; case PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE: currentReservoirMgmtState = handlePreTreatmentReservoirMgmtDrainCmdState(); break; case PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_RESP_STATE: currentReservoirMgmtState = handlePreTreatmentReservoirMgmtDrainCmdRespState(); break; case PRE_TREATMENT_RESERVOIR_MGMT_START_FILL_STATE: currentReservoirMgmtState = handlePreTreatmentReservoirMgmtFillCmdState(); break; case PRE_TREATMENT_RESERVOIR_MGMT_FILL_CMD_RESP_STATE: currentReservoirMgmtState = handlePreTreatmentReservoirMgmtFillCmdRespState(); break; case PRE_TREATMENT_RESERVOIR_MGMT_FILL_COMPLETE_STATE: currentReservoirMgmtState = handlePreTreatmentReservoirMgmtFillCompleteState(); break; case PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE: currentReservoirMgmtState = handlePreTreatmentReservoirMgmtWaitReservoirSwitchState(); break; case PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE: break; default: currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_START_STATE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRIME_RESERVOIR_MGMT_INVALID_STATE, (U32)currentReservoirMgmtState ); break; } } /*********************************************************************//** * @brief * The handlePreTreatmentReservoirMgmtStartState function handles reservoir * management start state for pre-treatment mode. * @details Inputs: fillReservoirOneStartRequested * @details Outputs: processed fill reservoir one request * @return current state of pre-treatment reservoir management *************************************************************************/ static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtStartState( void ) { PRE_TREATMENT_RESERVOIR_MGMT_STATE_T state = PRE_TREATMENT_RESERVOIR_MGMT_START_STATE; if ( TRUE == fillReservoirOneStartRequested ) { fillReservoirOneStartRequested = FALSE; state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; cmdSetDGActiveReservoir( DG_RESERVOIR_2 ); } return state; } /*********************************************************************//** * @brief * The handlePreTreatmentReservoirMgmtDrainCmdState function sends drain * command to DG when DG is in re-circulate mode. * @details Inputs: fillReservoirOneStartRequested * @details Outputs: processed fill reservoir one request * @return current state of pre-treatment reservoir management *************************************************************************/ static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtDrainCmdState( void ) { PRE_TREATMENT_RESERVOIR_MGMT_STATE_T state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; DG_OP_MODE_T dgOpMode = getDGOpMode(); U32 dgSubMode = getDGSubMode(); // If DG has not started yet, start DG if ( DG_MODE_STAN == dgOpMode ) { cmdStartDG(); } if ( TRUE == hasDGCompletedReservoirSwitch() ) { if ( ( DG_MODE_CIRC == dgOpMode ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) ) { state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_RESP_STATE; cmdStartDGDrain( DRAIN_RESERVOIR_TO_VOLUME_ML, TRUE ); } } return state; } /*********************************************************************//** * @brief * The handlePreTreatmentReservoirMgmtDrainCmdRespState function waits * and processes DG drain command response. * @details Inputs: DG drain command response * @details Outputs: processed DG drain command response * @return current state of pre-treatment reservoir management *************************************************************************/ static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtDrainCmdRespState( void ) { PRE_TREATMENT_RESERVOIR_MGMT_STATE_T state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_RESP_STATE; DG_CMD_RESPONSE_T dgCmdResp; DG_OP_MODE_T dgOpMode = getDGOpMode(); if ( ( TRUE == getDGCommandResponse( DG_CMD_START_DRAIN, &dgCmdResp ) ) && ( DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE == dgCmdResp.rejectCode ) ) { state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; } if ( DG_MODE_DRAI == dgOpMode ) { state = PRE_TREATMENT_RESERVOIR_MGMT_START_FILL_STATE; } return state; } /*********************************************************************//** * @brief * The handlePreTreatmentReservoirMgmtFillCmdState function sends fill * command to DG when DG is in re-circulate mode. * @details Inputs: DG operation mode and operation sub-mode * @details Outputs: sent fill command to DG * @return current state of pre-treatment reservoir management *************************************************************************/ static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtFillCmdState( void ) { PRE_TREATMENT_RESERVOIR_MGMT_STATE_T state = PRE_TREATMENT_RESERVOIR_MGMT_START_FILL_STATE; DG_OP_MODE_T dgOpMode = getDGOpMode(); U32 dgSubMode = getDGSubMode(); if ( ( DG_MODE_CIRC == dgOpMode ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) ) { state = PRE_TREATMENT_RESERVOIR_MGMT_FILL_CMD_RESP_STATE; if ( DG_RESERVOIR_1 == getDGInactiveReservoir() ) { cmdStartDGFill( PRE_TREATMENT_FILL_RESERVOIR_ONE_VOLUME_ML ); } else { cmdStartDGFill( PRE_TREATMENT_FILL_RESERVOIR_TWO_VOLUME_ML ); } } return state; } /*********************************************************************//** * @brief * The handlePreTreatmentReservoirMgmtFillCmdRespState function waits * and processes DG fill command response. * @details Inputs: DG fill command response * @details Outputs: processed DG fill command response * @return current state of pre-treatment reservoir management *************************************************************************/ static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtFillCmdRespState( void ) { PRE_TREATMENT_RESERVOIR_MGMT_STATE_T state = PRE_TREATMENT_RESERVOIR_MGMT_FILL_CMD_RESP_STATE; DG_CMD_RESPONSE_T dgCmdResp; DG_OP_MODE_T dgOpMode = getDGOpMode(); if ( ( TRUE == getDGCommandResponse( DG_CMD_START_FILL, &dgCmdResp ) ) && ( DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE == dgCmdResp.rejectCode ) ) { state = PRE_TREATMENT_RESERVOIR_MGMT_START_FILL_STATE; } if ( DG_MODE_FILL == dgOpMode ) { state = PRE_TREATMENT_RESERVOIR_MGMT_FILL_COMPLETE_STATE; } return state; } /*********************************************************************//** * @brief * The handlePreTreatmentReservoirMgmtFillCompleteState function switches * reservoir after the first one fill is complete and restart reservoir management * state machine. * @details Inputs: DG operation mode * @details Outputs: switch active reservoir and signal prime fill complete status * @return current state of pre-treatment reservoir management *************************************************************************/ static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtFillCompleteState( void ) { PRE_TREATMENT_RESERVOIR_MGMT_STATE_T state = PRE_TREATMENT_RESERVOIR_MGMT_FILL_COMPLETE_STATE; DG_OP_MODE_T dgOpMode = getDGOpMode(); U32 dgSubMode = getDGSubMode(); if ( ( DG_MODE_CIRC == dgOpMode ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) ) { if ( FALSE == reservoirFilledStatus[ DG_RESERVOIR_1 ] ) { state = PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE; reservoirFilledStatus[ DG_RESERVOIR_1 ] = TRUE; } else if ( ( TRUE == reservoirFilledStatus[ DG_RESERVOIR_1 ] ) && ( FALSE == reservoirFilledStatus[ DG_RESERVOIR_2 ] ) ) { reservoirFilledStatus[ DG_RESERVOIR_2 ] = TRUE; state = PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE; } } return state; } /*********************************************************************//** * @brief * The handlePreTreatmentReservoirMgmtWaitReservoirSwitchState function waits * until prime operation switches the active reservoir before filling up next reservoir. * @details Inputs: DG intactive reservoir * @details Outputs: start filling next reservoir * @return current state of pre-treatment reservoir management *************************************************************************/ static PRE_TREATMENT_RESERVOIR_MGMT_STATE_T handlePreTreatmentReservoirMgmtWaitReservoirSwitchState( void ) { PRE_TREATMENT_RESERVOIR_MGMT_STATE_T state = PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE; if ( DG_RESERVOIR_2 == getDGInactiveReservoir() ) { state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; } return state; } /**@}*/