Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -r1bff8e530735be63ba557b77557a0bc2ac4b37b2 -re788fc8f7f5b14f26d2973bd31b41858b9856479 --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 1bff8e530735be63ba557b77557a0bc2ac4b37b2) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision e788fc8f7f5b14f26d2973bd31b41858b9856479) @@ -7,8 +7,8 @@ * * @file ModePreTreat.c * -* @author (last) Dara Navaei -* @date (last) 04-May-2023 +* @author (last) Michael Garthwaite +* @date (last) 16-May-2023 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -48,14 +48,17 @@ #define PRE_TREATMENT_FLUSH_FILL_TARGET_TEMP_C 45.0F ///< Pre treatment flush fill target temperature in C. #define PRE_TREATMENT_NORMAL_FILL_TARGET_TEMP_C ( 37.0F + 2.0F ) ///< Pre treatment normal fill target temperature in C. -#define PRE_TREATMENT_MIN_FILL_RESERVOIR_VOLUME_ML 500 ///< Fill reservoir to this volume minimum to prep volume during development. -#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 600 ///< Fill reservoir two to this volume (in mL) during pre-treatment mode. -#define PRE_TREATMENT_FULL_RESERVOIR_VOLUME_ML 1500 ///< Fill reservoir to this volume minimum to prep volume during development. +#define PRE_TREATMENT_MIN_FILL_RESERVOIR_VOLUME_ML 500 ///< Fill reservoir to this volume minimum to prep volume during development. +#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 600 ///< Fill reservoir two to this volume (in mL) during pre-treatment mode. +#define PRE_TREATMENT_FULL_RESERVOIR_VOLUME_ML 1500 ///< Fill reservoir to this volume minimum to prep volume during development. #define PRE_TREATMENT_FLUSH_COUNT 2 ///< Number of flush cycles for each reservoir. +#define PRE_TREATMENT_TEST_CONFIG_MIN_RSRVR_VOL_ML 1400 ///< Pre-treatment test configuration minimum reservoir volume in milliliters. +#define PRE_TREATMENT_TEST_CONFIG_MAX_RSRVR_VOL_ML 1575 ///< Pre-treatment test configuration maximum reservoir volume in milliliters. + typedef struct { BOOL initialDrain; ///< Flags indicate whether a reservoir has been requested to initially drain. @@ -140,6 +143,9 @@ static U32 getPreTreatmentFillVolume( DG_RESERVOIR_ID_T inactiveRes ); static void setPreTreatmentHeatingParams( F32 targetTempC, U32 targetVolML, F32 targetFillFlowLPM, U32 dialysateFlowMLPM ); +// Test configuration test function +static void execPreTreatmentTestConfigReservoirMgmt( void ); + /*********************************************************************//** * @brief * The initPreTreatmentMode function initializes the Pre-Treatment Mode module. @@ -236,8 +242,17 @@ doorClosedRequired( FALSE, FALSE ); - // Start pre-treatment mode in sample water state - transitionToSampleWater(); + if ( getTestConfigStatus( TEST_CONFIG_EXPEDITE_PRE_TREATMENT ) != TRUE ) + { + // Start pre-treatment mode in sample water state + transitionToSampleWater(); + } + else + { + cmdStartDG(); + transitionToPatientConnection(); + currentPreTreatmentState = HD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; + } return currentPreTreatmentState; } @@ -298,8 +313,16 @@ break; } - // Execute reservoir management for pre-treatment mode - execPreTreatmentReservoirMgmt(); + if ( getTestConfigStatus( TEST_CONFIG_EXPEDITE_PRE_TREATMENT ) != TRUE ) + { + // Execute reservoir management for pre-treatment mode + execPreTreatmentReservoirMgmt(); + } + else + { + // If the expedite pre-treatment test configuration is set, the reservoir management is executed differently + execPreTreatmentTestConfigReservoirMgmt(); + } // Alarm response request flags should be handled at this point, reset in case not handled in current state resetSignalFlags(); @@ -424,7 +447,7 @@ if ( HD_PRE_TREATMENT_PATIENT_CONNECTION_STATE == currentPreTreatmentState ) { - if ( PRE_TREATMENT_PAT_CONN_WAIT_FOR_USER_CONFIRM_STATE == currentPreTxPatConnState ) + if ( currentPreTxPatConnState >= PRE_TREATMENT_PAT_CONN_WAIT_FOR_USER_CONFIRM_STATE ) { patientConnectionConfirm = TRUE; accepted = TRUE; @@ -690,6 +713,11 @@ signalDialOutPumpHardStop(); setDialInPumpTargetFlowRate( DIP_PATIENT_CONNECTION_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); cmdStartDGTrimmerHeater(); + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_EXPEDITE_PRE_TREATMENT ) ) + { + setOcclusionInstallLevel(); + } } /*********************************************************************//** @@ -789,6 +817,7 @@ { submodeCompleteTransitionTimeCounter = 0; state = HD_PRE_TREATMENT_CART_INSTALL_STATE; + setCurrentSubState( NO_SUB_STATE ); transitionToCartridgeInstallation(); } } @@ -938,6 +967,8 @@ *************************************************************************/ static HD_PRE_TREATMENT_MODE_STATE_T handlePatientConnectionState( void ) { + HD_PRE_TREATMENT_PAT_CONN_STATE_T priorSubState = currentPreTxPatConnState; + switch ( currentPreTxPatConnState ) { case PRE_TREATMENT_PAT_CONN_WAIT_FOR_UF_VOL_STATE: @@ -961,6 +992,12 @@ break; } + if ( priorSubState != currentPreTxPatConnState ) + { + setCurrentSubState( (U32)currentPreTxPatConnState ); + SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_SUB_STATE_CHANGE, priorSubState, currentPreTxPatConnState ); + } + // handle alarms w/ stop property if ( TRUE == doesAlarmStatusIndicateStop() ) { @@ -982,22 +1019,45 @@ /*********************************************************************//** * @brief + * The handlePatientConnectionDoorOpened function handles the check + * for door opened in pre-treatment patient connection + * sub-mode. + * @details Inputs: none + * @details Outputs: doorOpened + * @return none + *************************************************************************/ +static void handlePatientConnectionDoorOpened( void ) +{ + // Look for cartridge door to open (indicating user inverting dialyzer) + if ( STATE_OPEN == getSwitchStatus( FRONT_DOOR ) ) + { + doorOpened = TRUE; + cmdStopDGTrimmerHeater(); + signalDialInPumpHardStop(); + } + else + { + setDialInPumpTargetFlowRate( DIP_PATIENT_CONNECTION_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + cmdStartDGTrimmerHeater(); + } +} + +/*********************************************************************//** + * @brief * The handlePatientConnectionWait4UFVolState function handles the wait * for ultrafiltration volume setting state of pre-treatment patient connection * sub-mode. * @details Inputs: setUFVolStatus - * @details Outputs: setUFVolStatus, doorOpened + * @details Outputs: setUFVolStatus * @return next patient connection state *************************************************************************/ static HD_PRE_TREATMENT_PAT_CONN_STATE_T handlePatientConnectionWait4UFVolState( void ) { HD_PRE_TREATMENT_PAT_CONN_STATE_T nextState = PRE_TREATMENT_PAT_CONN_WAIT_FOR_UF_VOL_STATE; - // Look for cartridge door to open (indicating user inverting dialyzer) - if ( STATE_OPEN == getSwitchStatus( FRONT_DOOR ) ) - { - doorOpened = TRUE; - } + // Look for cartridge door to open and then close (indicating user inverted dialyzer) + handlePatientConnectionDoorOpened(); + // If UF volume set by user, move on to next state if ( TRUE == setUFVolStatus ) { @@ -1014,20 +1074,19 @@ * for dialyzer invert confirmation state of pre-treatment patient connection * sub-mode. * @details Inputs: doorOpened - * @details Outputs: doorOpened + * @details Outputs: none * @return next patient connection state *************************************************************************/ static HD_PRE_TREATMENT_PAT_CONN_STATE_T handlePatientConnectionWait4DialyzerInvertState( void ) { HD_PRE_TREATMENT_PAT_CONN_STATE_T nextState = PRE_TREATMENT_PAT_CONN_WAIT_FOR_DLZR_INVERT_STATE; // Look for cartridge door to open and then close (indicating user inverted dialyzer) - if ( STATE_OPEN == getSwitchStatus( FRONT_DOOR ) ) - { - doorOpened = TRUE; - } + handlePatientConnectionDoorOpened(); + if ( ( TRUE == doorOpened ) && ( STATE_CLOSED == getSwitchStatus( FRONT_DOOR ) ) ) { + doorClosedRequired( TRUE, TRUE ); nextState = PRE_TREATMENT_PAT_CONN_WAIT_FOR_USER_CONFIRM_STATE; } @@ -1049,7 +1108,6 @@ if ( TRUE == patientConnectionConfirm ) { - doorClosedRequired( TRUE, TRUE ); nextState = PRE_TREATMENT_PAT_CONN_WAIT_FOR_TREATMENT_START_STATE; } @@ -1060,18 +1118,28 @@ * @brief * The handlePatientConnectionWait4TreatmentStartState function handles the wait * for treatment start state of pre-treatment patient connection sub-mode. - * @details Inputs: treatmentStartRequested + * @details Inputs: treatmentStartRequested, currentReservoirMgmtState, + * doorOpened * @details Outputs: none * @return next patient connection state *************************************************************************/ static HD_PRE_TREATMENT_PAT_CONN_STATE_T handlePatientConnectionWait4TreatmentStartState( void ) { HD_PRE_TREATMENT_PAT_CONN_STATE_T nextState = PRE_TREATMENT_PAT_CONN_WAIT_FOR_TREATMENT_START_STATE; + BOOL startTreatment = TRUE; - if ( TRUE == treatmentStartRequested ) + if ( ( TRUE == getTestConfigStatus( TEST_CONFIG_EXPEDITE_PRE_TREATMENT ) ) && + ( currentReservoirMgmtState != PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE ) ) { - DG_RESERVOIR_ID_T const activeRes = getDGActiveReservoir(); + startTreatment = FALSE; + } + if ( ( TRUE == treatmentStartRequested ) && ( TRUE == startTreatment ) ) + { + DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); + + patientConnectionConfirm = FALSE; + doorOpened = FALSE; setStartReservoirVolume( activeRes ); requestNewOperationMode( MODE_TREA ); } @@ -1185,8 +1253,8 @@ { 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 ); + state = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_RESP_STATE; + cmdStartDGDrain( DRAIN_RESERVOIR_TO_VOLUME_ML, TRUE, FALSE, TRUE ); } } @@ -1442,6 +1510,11 @@ if ( ( TRUE == reservoirStatus[ DG_RESERVOIR_1 ].fillComplete ) && ( TRUE == reservoirStatus[ DG_RESERVOIR_2 ].fillComplete ) ) { + F32 targetTempC = getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ); + U32 dialysateFlowMLPM = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ); + + // Set the heating parameters + setPreTreatmentHeatingParams( targetTempC, FILL_RESERVOIR_TO_VOLUME_ML, DEFAULT_TARGET_FILL_FLOW_RATE_LPM, dialysateFlowMLPM ); state = PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE; } else @@ -1539,6 +1612,142 @@ /*********************************************************************//** * @brief + * The execPreTreatmentTestConfigReservoirMgmt function executes the state + * machine for reservoir management during pre-treatment mode when a test + * configuration (expedite pre-treatment test config for now) is enabled. + * @details Inputs: currentReservoirMgmtState + * @details Outputs: currentReservoirMgmtState + * @return none + *************************************************************************/ +static void execPreTreatmentTestConfigReservoirMgmt( void ) +{ + DG_SWITCH_RSRVRS_CMD_T rsrvrCmd; + DG_CMD_RESPONSE_T dgCmdResp; + F32 reservoir1Level = getReservoirWeight( DG_RESERVOIR_1 ); + F32 reservoir2Level = getReservoirWeight( DG_RESERVOIR_2 ); + DG_OP_MODE_T dgOpMode = getDGOpMode(); + U32 dgSubMode = getDGSubMode(); + + switch( currentReservoirMgmtState ) + { + case PRE_TREATMENT_RESERVOIR_MGMT_START_STATE: + rsrvrCmd.useLastTrimmerHeaterDC = FALSE; + + if ( ( reservoir1Level >= PRE_TREATMENT_TEST_CONFIG_MIN_RSRVR_VOL_ML ) && ( reservoir1Level < PRE_TREATMENT_TEST_CONFIG_MAX_RSRVR_VOL_ML ) ) + { + // Assume a reservoir switch is not needed and transition to the complete state because we are done + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE; + + if ( DG_RESERVOIR_2 == getDGActiveReservoir() ) + { + // Reservoir 1 has the right volume, set it to active reservoir and wait for it to be done + rsrvrCmd.reservoirID = (U32)DG_RESERVOIR_1; + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE; + cmdSetDGActiveReservoir( &rsrvrCmd ); + } + } + else if ( reservoir1Level >= PRE_TREATMENT_TEST_CONFIG_MAX_RSRVR_VOL_ML ) + { + // Reservoir 1 needs a partial drain so set it to be inactive so DG can drain it + if ( DG_RESERVOIR_1 == getDGActiveReservoir() ) + { + rsrvrCmd.reservoirID = (U32)DG_RESERVOIR_2; + cmdSetDGActiveReservoir( &rsrvrCmd ); + } + + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; + } + else if ( ( reservoir2Level >= PRE_TREATMENT_TEST_CONFIG_MIN_RSRVR_VOL_ML ) && ( reservoir2Level < PRE_TREATMENT_TEST_CONFIG_MAX_RSRVR_VOL_ML ) ) + { + // Reservoir 2 is in the right level, just make sure it is the active reservoir + // Assume a reservoir switch is not needed and transition to the complete state because we are done + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE; + + if ( DG_RESERVOIR_1 == getDGActiveReservoir() ) + { + rsrvrCmd.reservoirID = (U32)DG_RESERVOIR_2; + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE; + cmdSetDGActiveReservoir( &rsrvrCmd ); + } + } + else if ( reservoir2Level >= PRE_TREATMENT_TEST_CONFIG_MAX_RSRVR_VOL_ML ) + { + if ( DG_RESERVOIR_2 == getDGActiveReservoir() ) + { + rsrvrCmd.reservoirID = (U32)DG_RESERVOIR_1; + cmdSetDGActiveReservoir( &rsrvrCmd ); + } + + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; + } + break; + + case PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE: + // If DG has not started yet, start DG + if ( DG_MODE_STAN == dgOpMode ) + { + cmdStartDG(); + } + + // Ensure any pending reservoir switches are completed before sending drain command + if ( TRUE == hasDGCompletedReservoirSwitch() ) + { + if ( ( DG_MODE_GENE == dgOpMode ) && ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) ) + { + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_RESP_STATE; + cmdStartDGDrain( PRE_TREATMENT_FULL_RESERVOIR_VOLUME_ML, FALSE, FALSE, TRUE ); + } + } + break; + + case PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_RESP_STATE: + // Check DG response to drain command + if ( TRUE == getDGCommandResponse( DG_CMD_START_DRAIN, &dgCmdResp ) ) + { + if ( DG_CMD_REQUEST_REJECT_REASON_NONE == dgCmdResp.rejectCode ) + { + if ( DG_MODE_DRAI == dgOpMode ) + { + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_REQUEST_RESERVOIR_SWITCH_STATE; + } + } + else + { + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_DRAIN_CMD_STATE; + } + } + break; + + case PRE_TREATMENT_RESERVOIR_MGMT_REQUEST_RESERVOIR_SWITCH_STATE: + if ( ( DG_MODE_GENE == dgOpMode ) && ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) ) + { + DG_SWITCH_RSRVRS_CMD_T rsrvrCmd; + DG_RESERVOIR_ID_T inactiveReservoir = getDGInactiveReservoir(); + + rsrvrCmd.reservoirID = ( DG_RESERVOIR_1 == inactiveReservoir ? (U32)DG_RESERVOIR_1 : (U32)DG_RESERVOIR_2 ); + rsrvrCmd.useLastTrimmerHeaterDC = FALSE; + + cmdSetDGActiveReservoir( &rsrvrCmd ); + + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE; + } + break; + + case PRE_TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RESERVOIR_SWITCH_STATE: + if ( TRUE == hasDGCompletedReservoirSwitch() ) + { + currentReservoirMgmtState = PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE; + } + break; + + case PRE_TREATMENT_RESERVOIR_MGMT_COMPLETE_STATE: + // Done with test configuration reservoir management. Do nothing. + break; + } +} + +/*********************************************************************//** + * @brief * The testSetPreTreatmentModePublishIntervalOverride function sets the override of the * pre-treatment mode data publication interval. * @details Inputs: none