Index: firmware/App/Modes/ModePostTreat.c =================================================================== diff -u -rebf844fc2607388dfade1ffa599c0b17ee58a438 -ra226711bd50ef8cc3c60e7de813b67cc8d02e5f6 --- firmware/App/Modes/ModePostTreat.c (.../ModePostTreat.c) (revision ebf844fc2607388dfade1ffa599c0b17ee58a438) +++ firmware/App/Modes/ModePostTreat.c (.../ModePostTreat.c) (revision a226711bd50ef8cc3c60e7de813b67cc8d02e5f6) @@ -24,6 +24,7 @@ #include "FPGA.h" #include "OperationModes.h" #include "ModePostTreat.h" +#include "Timers.h" #include "Valves.h" /** @@ -33,9 +34,12 @@ // ********** private definitions ********** -#define EMPTY_RESERVOIR_VOLUME_ML 0 ///< Empty reservoir volume in ml. -#define DIP_FLUSH_FLOW_RATE_ML_MIN 300 ///< Dialysate inlet pump flow rate during flush in mL/min. +#define EMPTY_RESERVOIR_VOLUME_ML 0 ///< Empty reservoir volume in ml. +#define DIP_FLUSH_FLOW_RATE_ML_MIN 300 ///< Dialysate inlet pump flow rate during flush in mL/min. +#define LOAD_CELL_VOLUME_NOISE_TOLERANCE 0.05 ///< Allow 5% tolerance on load cell readings. +#define LOAD_CELL_STEADY_VOLUME_TIME ( 10 * MS_PER_SECOND ) ///< Time load cell reading need to remain steady in ms. + /// Post-Treatmen de-prime state machine. typedef enum De_Prime_States { @@ -51,6 +55,10 @@ static BOOL patientDisconnectionConfirmed = FALSE; ///< Flag indicates user confirms patient disconnection. static BOOL disposableRemovalConfirmed = FALSE; ///< Flag indicates user confirms disposable removal. +static BOOL isDrainStarted = FALSE; ///< Flag indicates a drain operation has been started. +static U32 previousLoadCellReading; ///< Previous load cell reading. +static U32 loadcellSteadyVolumeStartTime; ///< Load cell steady volume starting time. + static HD_POST_TREATMENT_STATE_T currentPostTreatmentState; ///< Current state of post-treatment mode state machine. static DE_PRIME_STATE_T currentDePrimeState; ///< Current de-prime sub-mode state. @@ -62,6 +70,8 @@ static HD_POST_TREATMENT_STATE_T handlePostTreatmentVerifyState( void ); static void execDePrime( void ); +static BOOL switchReservoirCompleted( DG_RESERVOIR_ID_T activeRes ); +static BOOL startDrainCompleted( void ); static DE_PRIME_STATE_T handleDePrimeFirstDrainState( void ); static DE_PRIME_STATE_T handleDePrimeFlushBypassState( void ); static DE_PRIME_STATE_T handleDePrimeDrainBypassState( void ); @@ -77,6 +87,9 @@ { patientDisconnectionConfirmed = FALSE; disposableRemovalConfirmed = FALSE; + isDrainStarted = FALSE; + previousLoadCellReading = 0; + loadcellSteadyVolumeStartTime = 0; currentPostTreatmentState = HD_POST_TREATMENT_PATIENT_DISCONNECTION_STATE; currentDePrimeState = DE_PRIME_FIRST_DRAIN_STATE; } @@ -174,9 +187,7 @@ if ( TRUE == patientDisconnectionConfirmed ) { - setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); - cmdStartDGDrain( EMPTY_RESERVOIR_VOLUME_ML, FALSE ); - + patientDisconnectionConfirmed = FALSE; state = HD_POST_TREATMENT_DE_PRIME_STATE; } @@ -271,6 +282,90 @@ /*********************************************************************//** * @brief + * The switchReservoirCompleted function waits for switch reservoir response + * from DG and re-send switch reservoir command if DG rejected previous one. + * @details Inputs: none + * @details Outputs: processed DG switch reservoir command response + * @return TRUE if switch reservoir completed, otherwise FALSE + *************************************************************************/ +static BOOL switchReservoirCompleted( DG_RESERVOIR_ID_T activeRes ) +{ + BOOL result = FALSE; + DG_CMD_RESPONSE_T dgCmdResp; + + if ( TRUE == getDGCommandResponse( DG_CMD_SWITCH_RESERVOIR, &dgCmdResp ) ) + { + if ( TRUE == dgCmdResp.rejected ) + { + cmdSetDGActiveReservoir( activeRes ); + } + else + { + result = TRUE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The startDrainCompleted function waits for drain command response from DG + * and re-send drain command if DG rejected previous one. + * @details Inputs: none + * @details Outputs: processed DG drain command response + * @return TRUE if start reservoir drain completed, otherwise FALSE + *************************************************************************/ +static BOOL startDrainCompleted( void ) +{ + BOOL result = FALSE; + DG_CMD_RESPONSE_T dgCmdResp; + + if ( TRUE == getDGCommandResponse( DG_CMD_START_DRAIN, &dgCmdResp ) ) + { + if ( TRUE == dgCmdResp.rejected ) + { + cmdStartDGDrain( EMPTY_RESERVOIR_VOLUME_ML, FALSE ); + } + else + { + result = TRUE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The isBypassCircuitFlushed function checks load cell steady reading as an + * indicator for flushed bypass circuit. + * @details Inputs: previousLoadCellReading + * @details Outputs: processed DG drain command response + * @return TRUE if start reservoir drain completed, otherwise FALSE + *************************************************************************/ +static BOOL isBypassCircuitFlushed( void ) +{ + BOOL result = FALSE; + DG_RESERVOIR_ID_T const activeRes = getDGActiveReservoir(); + F32 const loadcellWeight = getReservoirWeightSmallFilter( activeRes ); + F32 const weightChange = fabs( 1.0 - ( previousLoadCellReading / loadcellWeight ) ); + + if ( weightChange < LOAD_CELL_VOLUME_NOISE_TOLERANCE ) + { + result = didTimeout( loadcellSteadyVolumeStartTime, LOAD_CELL_STEADY_VOLUME_TIME ); + } + else + { + previousLoadCellReading = loadcellWeight; + loadcellSteadyVolumeStartTime = getMSTimerCount(); + } + + return result; +} + +/*********************************************************************//** + * @brief * The handleDePrimeFirstDrainState function sends command to DG to drain * reservoir one. * @details Inputs: none @@ -283,11 +378,23 @@ if ( ( DG_MODE_CIRC == getDGOpMode() ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == getDGSubMode() ) ) { - cmdSetDGActiveReservoir( DG_RESERVOIR_1 ); - setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); + cmdSetDGActiveReservoir( DG_RESERVOIR_2 ); + } + + if ( TRUE == switchReservoirCompleted( DG_RESERVOIR_2 ) ) + { cmdStartDGDrain( EMPTY_RESERVOIR_VOLUME_ML, FALSE ); - setDialInPumpTargetFlowRate( DIP_FLUSH_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + } + if ( TRUE == startDrainCompleted() ) + { + isDrainStarted = TRUE; + } + + // Drain has started and DG goes to re-circ mode means drain completed + if ( ( TRUE == isDrainStarted ) && ( DG_MODE_CIRC == getDGOpMode() ) ) + { + isDrainStarted = FALSE; state = DE_PRIME_FLUSH_BYPASS_STATE; } @@ -308,9 +415,26 @@ if ( ( DG_MODE_CIRC == getDGOpMode() ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == getDGSubMode() ) ) { - cmdSetDGActiveReservoir( DG_RESERVOIR_2 ); + cmdSetDGActiveReservoir( DG_RESERVOIR_1 ); + } + + if ( TRUE == switchReservoirCompleted( DG_RESERVOIR_1 ) ) + { + loadcellSteadyVolumeStartTime = getMSTimerCount(); + setDialInPumpTargetFlowRate( DIP_FLUSH_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); cmdStartDGDrain( EMPTY_RESERVOIR_VOLUME_ML, FALSE ); + } + if ( TRUE == startDrainCompleted() ) + { + isDrainStarted = TRUE; + } + + // Drain has started and DG goes to re-circ mode means drain completed + if ( ( TRUE == isBypassCircuitFlushed() ) && ( TRUE == isDrainStarted ) && ( DG_MODE_CIRC == getDGOpMode() ) ) + { + signalDialInPumpHardStop(); + isDrainStarted = FALSE; state = DE_PRIME_DRAIN_BYPASS_STATE; } @@ -331,6 +455,23 @@ if ( ( DG_MODE_CIRC == getDGOpMode() ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == getDGSubMode() ) ) { + cmdSetDGActiveReservoir( DG_RESERVOIR_2 ); + } + + if ( TRUE == switchReservoirCompleted( DG_RESERVOIR_2 ) ) + { + cmdStartDGDrain( EMPTY_RESERVOIR_VOLUME_ML, FALSE ); + } + + if ( TRUE == startDrainCompleted() ) + { + isDrainStarted = TRUE; + } + + // Drain has started and DG goes to re-circ mode means drain completed + if ( ( TRUE == isDrainStarted ) && ( DG_MODE_CIRC == getDGOpMode() ) ) + { + isDrainStarted = FALSE; state = DE_PRIME_COMPLETE_STATE; }