Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -rf6888c7e4e05cb84b11fceb4340458d8af543ce8 -r6255a679626d6f02fa30841ce626a08842725334 --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision f6888c7e4e05cb84b11fceb4340458d8af543ce8) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 6255a679626d6f02fa30841ce626a08842725334) @@ -1,46 +1,124 @@ /************************************************************************** * -* Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * -* @file ModePreTreat.c +* @file ModePreTreat.c * -* @author (last) Sean Nash -* @date (last) 06-Oct-2020 +* @author (last) Dara Navaei +* @date (last) 04-Jan-2022 * -* @author (original) Dara Navaei -* @date (original) 05-Nov-2019 +* @author (original) Dara Navaei +* @date (original) 05-Nov-2019 * ***************************************************************************/ -#include "AirTrap.h" -#include "AlarmLamp.h" -#include "BloodFlow.h" -#include "DialInFlow.h" -#include "DialOutFlow.h" +#include "AlarmMgmt.h" #include "Buttons.h" +#include "ConsumableSelfTest.h" +#include "FPGA.h" +#include "ModePreTreat.h" +#include "ModeTreatmentParams.h" #include "OperationModes.h" +#include "PresOccl.h" +#include "PreTreatmentRecirc.h" +#include "Prime.h" +#include "Reservoirs.h" +#include "SelfTests.h" +#include "SampleWater.h" #include "SystemCommMessages.h" -#include "ModePreTreat.h" -#include "SystemCommMessages.h" -#ifdef RM46_EVAL_BOARD_TARGET - #include "Timers.h" - static U32 start; -#endif +#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. + +#ifndef SKIP_PRIMING +#define PRE_TREATMENT_FLUSH_RESERVOIR_VOLUME_ML 500 ///< Fill reservoir to this volume (in mL) to flush filter and lines. +#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. +#else +#define PRE_TREATMENT_FLUSH_RESERVOIR_VOLUME_ML FILL_RESERVOIR_TO_VOLUME_ML +#define PRE_TREATMENT_FILL_RESERVOIR_ONE_VOLUME_ML FILL_RESERVOIR_TO_VOLUME_ML +#define PRE_TREATMENT_FILL_RESERVOIR_TWO_VOLUME_ML FILL_RESERVOIR_TO_VOLUME_ML +#endif + +#define PRIMARY_HEATER_TARGET_TEMP_OFFSET 2.0 //TODO remove ///< 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 treatStartReqReceived = FALSE; ///< Flag indicates user requests treatment begin. +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. +/// Interval (in task intervals) at which to publish pre-treatment mode data to CAN bus. +static OVERRIDE_U32_T preTreatmentModePublishInterval = { PRE_TREATMENT_DATA_PUB_INTERVAL, PRE_TREATMENT_DATA_PUB_INTERVAL, PRE_TREATMENT_DATA_PUB_INTERVAL, 0 }; +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. +static BOOL reservoirFlushedStatus[ NUM_OF_DG_RESERVOIRS ]; ///< Flag indicates a reservoir has been flushed. + // ********** 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. @@ -50,6 +128,27 @@ *************************************************************************/ 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(); + // Reservoirs state machine is not used in Pre-treatment but the + // init function is called here to initialize all the variables in + // the reservoirs driver since an API from the reservoirs is used + // to setup the DG heaters. + initReservoirs(); + + resetSignalFlags(); } /*********************************************************************//** @@ -58,15 +157,25 @@ * pre-treatment mode. * @details Inputs: none * @details Outputs: none - * @return none + * @return initial state *************************************************************************/ -void transitionToPreTreatmentMode( void ) +U32 transitionToPreTreatmentMode( void ) { - treatStartReqReceived = FALSE; + F32 trimmerHeaterTemp = getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ); -#ifdef RM46_EVAL_BOARD_TARGET - start = getMSTimerCount(); -#endif + initPreTreatmentMode(); + + // Set the heaters specs to start heating up the water + setDialysateHeatingParams(); + + cmdStopDGTrimmerHeater(); + + // 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 ); + + return currentPreTreatmentState; } /*********************************************************************//** @@ -80,46 +189,194 @@ { BOOL stop = isStopButtonPressed(); -#ifndef DISABLE_UI_TREATMENT_WORKFLOW - if ( TRUE == treatStartReqReceived ) + 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: + 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 none + *************************************************************************/ +void signalUserConfirmInstallation( void ) +{ + F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); + F32 hepRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ); + + // Accept installation confirmation if we are in install state of pre-treatment mode and syringe is detected or Heparin not being used in this treatment. + if ( ( MODE_PRET == getCurrentOperationMode() ) && + ( HD_PRE_TREATMENT_CART_INSTALL_STATE == currentPreTreatmentState ) && + ( ( TRUE == isSyringeDetected() ) || ( ( bolusVol < NEARLY_ZERO ) && ( hepRate < NEARLY_ZERO ) ) ) ) { - requestNewOperationMode( MODE_TREA ); + confirmInstallRequested = TRUE; } -#ifdef RM46_EVAL_BOARD_TARGET - if ( TRUE == didTimeout( start, 5000U ) ) + // TODO - send a reject reason if not accepting confirmation +} + +/*********************************************************************//** + * @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 ) { - requestNewOperationMode( MODE_TREA ); + continueToTreatmentRequested = TRUE; + accepted = TRUE; + rejReason = REQUEST_REJECT_REASON_NONE; } -#endif - return 0; // TODO - return current state + sendContinueToTreatmentCmdResponse( accepted, rejReason ); } /*********************************************************************//** * @brief - * The signalUserBeginningTreatment function handles user start of a - * treatment. + * 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: requested mode transition to treatment mode - * @return TRUE if signal accepted, FALSE if not + * @details Outputs: handled and send response to patient connection confirmation + * @return none *************************************************************************/ -BOOL signalUserBeginningTreatment( void ) +void signalUserConfirmPatientConnection( void ) { - BOOL result = FALSE; + BOOL accepted = FALSE; + REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_UF_VOLUME_NOT_SET; - if ( MODE_PRET == getCurrentOperationMode() ) + if ( TRUE == setUFVolStatus ) { - treatStartReqReceived = TRUE; - result = TRUE; + 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; + } } - sendTreatmentStartResponseMsg( result, 0 ); // TODO - provide reason code if rejected - return result; + 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; + +#ifdef SKIP_UI_INTERACTION + patientConnectionConfirm = TRUE; +#endif + + if ( TRUE == patientConnectionConfirm ) + { + 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 @@ -129,7 +386,754 @@ *************************************************************************/ 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 ) + { + if ( HD_PRE_TREATMENT_WATER_SAMPLE_STATE == currentPreTreatmentState ) + { + cmdDGSampleWater( SAMPLE_WATER_CMD_END ); + } + 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 >= getU32OverrideValue( &preTreatmentModePublishInterval ) ) + { + 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; + + broadcastData( MSG_ID_PRE_TREATMENT_STATE, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&preTreatmentData, sizeof( PRE_TREATMENT_STATE_DATA_T ) ); + 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; + cmdStartDG(); + 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; + +#ifdef SKIP_UI_INTERACTION + confirmInstallRequested = TRUE; +#endif + + if ( TRUE == confirmInstallRequested ) + { + 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 ) + { + setOcclusionInstallLevel(); // Record occlusion pressure level after a new cartridge is installed. + 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(); + +#ifdef SKIP_UI_INTERACTION + continueToTreatmentRequested = TRUE; +#endif + + if ( TRUE == continueToTreatmentRequested ) + { + 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 ); + resetHeparinVolumeDelivered(); // get clean starting volume/position before we start treatment + 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_PRE_TREATMENT_RESERVOIR_MGMT_INVALID_STATE, 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_GENE == dgOpMode ) && ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) ) + { + state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_RESP_STATE; + cmdStartDGDrain( DRAIN_RESERVOIR_TO_VOLUME_ML, TRUE, FALSE, 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 ) ) + { + if ( DG_CMD_REQUEST_REJECT_REASON_NONE == dgCmdResp.rejectCode ) + { + state = PRE_TREATMENT_RESERVOIR_MGMT_START_FILL_STATE; + } + else + { + state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_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_GENE == dgOpMode ) && ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) ) + { + state = PRE_TREATMENT_RESERVOIR_MGMT_FILL_CMD_RESP_STATE; + + if ( ( TRUE == reservoirFlushedStatus[ DG_RESERVOIR_1 ] ) && ( TRUE == reservoirFlushedStatus[ DG_RESERVOIR_2 ] ) ) + { + if ( DG_RESERVOIR_1 == getDGInactiveReservoir() ) + { + cmdStartDGFill( PRE_TREATMENT_FILL_RESERVOIR_ONE_VOLUME_ML, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); + } + else + { + cmdStartDGFill( PRE_TREATMENT_FILL_RESERVOIR_TWO_VOLUME_ML, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); + } + } + else + { + cmdStartDGFill( PRE_TREATMENT_FLUSH_RESERVOIR_VOLUME_ML, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); + } + } + + 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_GENE == dgOpMode ) && ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) ) + { + if ( ( TRUE == reservoirFlushedStatus[ DG_RESERVOIR_1 ] ) && ( TRUE == reservoirFlushedStatus[ DG_RESERVOIR_2 ] ) ) + { + 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; + } + } + else + { + state = PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE; + + if ( FALSE == reservoirFlushedStatus[ DG_RESERVOIR_1 ] ) + { +#ifdef SKIP_PRIMING + reservoirFilledStatus[ DG_RESERVOIR_1 ] = TRUE; +#else + reservoirFlushedStatus[ DG_RESERVOIR_1 ] = TRUE; + cmdSetDGActiveReservoir( DG_RESERVOIR_1 ); +#endif + } + else if ( ( TRUE == reservoirFlushedStatus[ DG_RESERVOIR_1 ] ) && ( FALSE == reservoirFlushedStatus[ DG_RESERVOIR_2 ] ) ) + { + reservoirFlushedStatus[ DG_RESERVOIR_2 ] = TRUE; + cmdSetDGActiveReservoir( DG_RESERVOIR_2 ); + } + } + } + + 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 ( ( TRUE == reservoirFilledStatus[ DG_RESERVOIR_1 ] ) && ( FALSE == reservoirFilledStatus[ DG_RESERVOIR_2 ] ) ) + { + if ( DG_RESERVOIR_2 == getDGInactiveReservoir() ) + { + state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; + } + } + else + { + if ( TRUE == hasDGCompletedReservoirSwitch() ) + { + state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; + } + } + + return state; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetPreTreatmentModePublishIntervalOverride function sets the override of the + * pre-treatment mode data publication interval. + * @details Inputs: none + * @details Outputs: preTreatmentModePublishInterval + * @param ms milliseconds between pre-treatment mode broadcasts + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetPreTreatmentModePublishIntervalOverride( U32 ms ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = ms / TASK_GENERAL_INTERVAL; + + result = TRUE; + preTreatmentModePublishInterval.ovData = intvl; + preTreatmentModePublishInterval.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetPreTreatmentModePublishIntervalOverride function resets the override of the + * pre-treatment mode data publication interval. + * @details Inputs: none + * @details Outputs: preTreatmentModePublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetPreTreatmentModePublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + preTreatmentModePublishInterval.override = OVERRIDE_RESET; + preTreatmentModePublishInterval.ovData = preTreatmentModePublishInterval.ovInitData; + } + + return result; +} + /**@}*/