Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r87acb1655edbf974497e4300f2c18eea62f8acba -rdf70610b0fd07ef4757da8ab504ecc856e178fe1 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 87acb1655edbf974497e4300f2c18eea62f8acba) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision df70610b0fd07ef4757da8ab504ecc856e178fe1) @@ -39,68 +39,80 @@ // ********** private definitions ********** // General defines -#define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. -#define HEAT_DISINFECT_DATA_PUB_INTERVAL ( MS_PER_SECOND / \ - TASK_GENERAL_INTERVAL ) ///< Mode Heat Disinfect data publish interval in counts. +#define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. +#define HEAT_DISINFECT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode Heat Disinfect data publish interval in counts. // Start state defines -#define MIN_INLET_PRESSURE_PSI 30.0 ///< Minimum water inlet pressure in psi. -#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 1.0 ///< Max start state TDi and TRo difference tolerance in C. +#define MIN_INLET_PRESSURE_PSI 30.0 ///< Minimum water inlet pressure in psi. +#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 1.0 ///< Max start state TDi and TRo difference tolerance in C. // Drain R1 & R2 states defines -#define DRAIN_PUMP_TARGET_RPM 1800 ///< Drain pump target RPM during drain. -#define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. -#define RSRVRS_EMPTY_VOL_ML 50.0 ///< Reservoirs 1 & 2 empty volume in mL. //TODO Change this value to actual value -#define DRAIN_WEIGH_UNCHANGE_TIMEOUT ( 2 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. +#define DRAIN_PUMP_TARGET_RPM 1800 ///< Drain pump target RPM during drain. +#define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. +#define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 2 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. // Flush drain path state defines -#define FLUSH_DRAIN_WAIT_TIME_MS ( 1 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. TODo original time was 60 seconds -#define MIN_INLET_TEMPERATURE_C 15.0 ///< Minimum water inlet temperature in C. TODO original temperature was 25 C -#define MIN_INLET_CONDUCTIVITY_US_PER_CM 0.0 ///< Minimum water inlet conductivity in uS/cm -#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0 ///< Maximum water inlet conductivity in us/cm +#define FLUSH_DRAIN_WAIT_TIME_MS ( 1 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. TODo original time was 60 seconds +#define MIN_INLET_TEMPERATURE_C 15.0 ///< Minimum water inlet temperature in C. TODO original temperature was 25 C +#define MIN_INLET_CONDUCTIVITY_US_PER_CM 0.0 ///< Minimum water inlet conductivity in uS/cm +#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0 ///< Maximum water inlet conductivity in us/cm // Flush circulation path state defines -#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.6 ///< RO pump target flow rate during flush/fill in L/min. TODO original flow was 0.8 -#define MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. -#define FLUSH_CICRCULATION_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush/rinse circulation path wait time in milliseconds. TODO original time was 30 seconds -#define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 3.0 ///< Maximum flush circulation temperature difference tolerance in C. +#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.8 ///< RO pump target flow rate during flush/fill in L/min. TODO original flow was 0.8 +#define MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. +#define FLUSH_CICRCULATION_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush/rinse circulation path wait time in milliseconds. TODO original time was 30 seconds +#define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 3.0 ///< Maximum flush circulation temperature difference tolerance in C. // Flush and drain R1 and R2 -#define RSRVRS_FULL_VOL_ML 1900.0 ///< Reservoirs 1 & 2 full volume in mL. -#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< Reservoirs 1 & 2 partial volume in mL. -#define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. -#define RSRVRS_500ML_FILL_UP_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. -#define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. +#define RSRVRS_FULL_VOL_ML 1900.0 ///< Reservoirs 1 & 2 full volume in mL. +#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< Reservoirs 1 & 2 partial volume in mL. +#define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. +#define RSRVRS_500ML_FILL_UP_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. +#define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. // Fill and heat water -#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 35.0 ///< Heat disinfect target water temperature in C. TODO original temperature was 88.0 +#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 55.0 ///< Heat disinfect target water temperature in C. TODO original temperature was 85.0 +#define HEAT_DISINFECT_START_TEMPERATURE_C 50.0 ///< Heat disinfect minimum acceptable temperature in C. TODO original temperature was 81.0 // R1 to R2 & R2 to R1 heat disinfect circulation -#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 0.6 ///< Heat disinfect target RO flow rate in L/min. -#define HEAT_DISINFECT_MAX_RO_PRESSURE_PSI 30 ///< Heat disinfect maximum RO pressure in psi. -#define HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI 1.0 ///< Heat disinfect target drain outlet pressure in psi. -#define HEAT_DISINFECT_START_TEMPERATURE_C 31.0 ///< Heat disinfect minimum acceptable temperature in C. TODO original temperature was 81.0 -#define HEAT_DISINFECT_TIME_MS ( 0.5 * 60 * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. TODO original time was 10 minutes -#define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 30 * 60 * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. -#define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disnfect. -#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 100.0 ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. -#define POST_HEAT_DISINFECT_WAIT_TIME_MS ( 1 * 60 * MS_PER_SECOND ) ///< Heat disinfect final wait time before flushing the system in milliseconds. +#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 0.8 ///< Heat disinfect target RO flow rate in L/min. TODO original value was 0.8 +#define HEAT_DISINFECT_MAX_RO_PRESSURE_PSI 30 ///< Heat disinfect maximum RO pressure in psi. +#define HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI 1.0 ///< Heat disinfect target drain outlet pressure in psi. +#define HEAT_DISINFECT_TIME_MS ( 0.5 * 60 * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. TODO original time was 10 minutes +#define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 30 * 60 * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. +#define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disnfect. +#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 100.0 ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. +#define POST_HEAT_DISINFECT_WAIT_TIME_MS ( 1 * 60 * MS_PER_SECOND ) ///< Heat disinfect final wait time before flushing the system in milliseconds. // Rinse R1 to R2 -#define ROF_MIN_LOW_PRESSURE_TEMPERATURE_C 30.0 ///< RO filter minimum temperature that the pressure must be no more than 30psi in C. TODO the actual value is 45.0 +#define ROF_MIN_LOW_PRESSURE_TEMPERATURE_C 45.0 ///< RO filter minimum temperature that the pressure must be no more than 30psi in C. TODO the actual value is 45.0 -/// TODO remove? -typedef enum rsvrs_status +// Cancellation paths +#define MIX_DRAIN_TEMPERATURE_THRESHOLD_C 60.0 ///< Temperature threshold for performing mix drain or normal drain. + +/// Cancellation paths +typedef enum Cancellation_modes { - RSRVR_EMPTY = 0, - RSRVR_PARTIALLY_FULL, - RSVR_FULL, - NUM_OF_RSRVRS_STATUS -} RSRVRS_STATUS_T; + CANCELLATION_MODE_NONE = 0, ///< Cancellation mode none. + CANCELLATION_MODE_BASIC, ///< Cancellation mode basic. + CANCELLATION_MODE_HOT, ///< Cancellation mode hot. + CANCELLATION_MODE_COLD, ///< Cancellation mode cold. + NUM_OF_CANCELLATION_MODES ///< Number of cancellation modes. +} CANCELLATION_MODES_T; +/// Reservoirs status +typedef enum Reservoirs_status +{ + RESERVOIR_EMPTY = 0, + RESERVOIR_FULL, + RESERVOIR_TIMEOUT, + NUM_OF_RESERVOIR_STATES +} TYPE_T ; + // ********** private data ********** -static DG_HEAT_DISINFECT_STATE_T heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Currently active heat disinfect state. +static DG_HEAT_DISINFECT_STATE_T heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Current active heat disinfect state. +static DG_HEAT_DISINFECT_STATE_T prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Previous active heat disinfect state before alarm. static U32 overallHeatDisinfectTimer = 0; ///< Heat disinfect cycle total timer. static U32 stateTimer = 0; ///< Heat disinfect state timer to be used in different states. static U32 stateTrialCounter = 0; ///< Heat disinfect state trial counter to be used for retries in different states. @@ -117,6 +129,7 @@ static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during heat disinfect. static BOOL hasPostHeatDisinfectWaitStarted = FALSE; ///< Final delay at the end of heat disinfect and before flush flag. static U32 dataPublishCounter = 0; ///< Heat Disinfect data publish counter. +static CANCELLATION_MODES_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. // ********** private function prototypes ********** @@ -140,13 +153,12 @@ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR2ToR1AndDrainR1State( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseCirculationState( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeBasicPath( void ); -static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeColdWaterPath( void ); -static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeHotWaterPath( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeWaterPath( void ); static void resetActuators( void ); static void setModeToFailed( DG_HEAT_DISINFECT_STATE_T state ); -static BOOL isRsrvrFull( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout, DG_HEAT_DISINFECT_STATE_T state ); -static BOOL isRsrvrEmpty( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, DG_HEAT_DISINFECT_STATE_T failedState ); +static BOOL isRsrvrFull( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout, DG_HEAT_DISINFECT_STATE_T cancellationState ); +static BOOL isRsrvrEmpty( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, DG_HEAT_DISINFECT_STATE_T cancellationState ); static BOOL isStateHeatDisinfectComplete( DG_HEAT_DISINFECT_STATE_T state ); static void publishHeatDisinfectData( void ); @@ -164,6 +176,7 @@ void initHeatDisinfectMode( void ) { heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; stateTimer = 0; isThisLastDrain = FALSE; stateTrialCounter = 0; @@ -174,6 +187,7 @@ R2HeatDisinfectVol = 0; hasPostHeatDisinfectWaitStarted = FALSE; overallHeatDisinfectTimer = 0; + cancellationMode = CANCELLATION_MODE_NONE; } /*********************************************************************//** @@ -279,15 +293,14 @@ heatDisinfectState = handleHeatDisinfectRinseCirculationState(); break; - case DG_HEAT_DISINFECT_STATE_CANCEL_MODE_BASIC_PATH: + case DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH: + heatDisinfectState = handleHeatDisinfectCancelModeBasicPath(); break; - case DG_HEAT_DISINFECT_STATE_CANCEL_MODE_COLD_WATER_PATH: + case DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH: + heatDisinfectState = handleHeatDisinfectCancelModeWaterPath(); break; - case DG_HEAT_DISINFECT_STATE_CANCEL_MODE_HOT_WATER_PATH: - break; - case DG_HEAT_DISINFECT_STATE_COMPLETE: // Done with heat disinfect cycle, failed or not break; @@ -326,8 +339,11 @@ void stopDGHeatDisinfect( void ) { heatDisinfectState = DG_HEAT_DISINFECT_STATE_COMPLETE; + + // Reset all the actuators resetActuators(); + // Transition to mode standby requestNewOperationMode( DG_MODE_STAN ); } @@ -359,7 +375,8 @@ // should be canceled if ( ppiPressure < MIN_INLET_PRESSURE_PSI && fabs( TDiTemp - TRoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) { - setModeToFailed( state ); + prevHeatDisinfectState = state; + state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } else { @@ -388,14 +405,21 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; - if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH ) ) { isR1Full = FALSE; if ( isThisLastDrain ) { + // Done with draining + signalDrainPumpHardStop(); + + // Set the valves to flush the recirculation line setValveState( VPI, VALVE_STATE_OPEN ); setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); //TODO turn on the concentrate pumps @@ -404,7 +428,6 @@ // Done with final draining isThisLastDrain = FALSE; - stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_RINSE_CIRCULATION; } else @@ -414,9 +437,11 @@ tareReservoir(); // NOTE: Drain pump is already on and VDr is already on drain state setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); - stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; } + + // Start the timer + stateTimer = getMSTimerCount(); } return state; @@ -434,7 +459,7 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; - if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH ) ) { isR2Full = FALSE; @@ -472,8 +497,8 @@ if ( didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) { // If the inlet temperature and conductivity are in range, move onto the next state - if ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MIN_INLET_TEMPERATURE_C /*&& TODO bring the code back - getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) > MIN_INLET_CONDUCTIVITY_US_PER_CM*/ ) + if ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MIN_INLET_TEMPERATURE_C && + getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) > MIN_INLET_CONDUCTIVITY_US_PER_CM ) { setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); @@ -489,7 +514,8 @@ // Couldn't get a good water sample after a couple of trials and the disinfect cycle failed else { - setModeToFailed( state ); + prevHeatDisinfectState = state; + state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } } @@ -511,20 +537,20 @@ // Check if the flush circulation time has elapsed and the temperature sensors are not in range yet if ( didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) && FALSE == areTempSensorsInRange ) { - // TODO add TPm later. This is the new temp sensor of the coldest spot. It is temporarily TDi. - F32 TPmTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + + F32 ThdTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); // TODO add TPm later. This is the new temp sensor of the coldest spot. It is temporarily TDi. F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); F32 TD1Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_1 ); F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); - F32 avgTemp = ( /*TPmTemp +*/ TPoTemp + TD1Temp + TD2Temp ) / 3.0; //TODO add TPm once we have the sensor in change the average count to 4.0 + F32 avgTemp = ( ThdTemp + TPoTemp + TD1Temp + TD2Temp ) / 4.0; - BOOL isTPmOut = FALSE; //fabs( TPmTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; TODO uncomment this when + BOOL isThdOut = fabs( ThdTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; BOOL isTPoOut = fabs( TPoTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; BOOL isTD1Out = fabs( TD1Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; BOOL isTD2Out = fabs( TD2Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; // Check if any of the temperature sensors are out of tolerance - if( isTPmOut || isTPoOut || isTD1Out || isTD2Out ) + if( isThdOut || isTPoOut || isTD1Out || isTD2Out ) { // Check if we have exceeded the number of trials. If not, try another time if ( ++stateTrialCounter < MAX_ALLOWED_STATE_TRIALS ) @@ -534,7 +560,8 @@ // State failed. Cancel heat disinfect mode else { - setModeToFailed( state ); + prevHeatDisinfectState = state; + state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } } else @@ -552,6 +579,8 @@ //if ( didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) if ( TRUE ) { + isR1Full = FALSE; + isR2Full = FALSE; setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); @@ -578,12 +607,12 @@ // If R1 is not full, keep monitoring for R1 level and timeout if ( isR1Full != TRUE ) { - isR1Full = isRsrvrFull( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + isR1Full = isRsrvrFull( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); } // Once R1 is full, keep monitoring for R2 level and timeout if( isR1Full ) { - isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); // Once R2 is full (to 500mL in this case), transition to the next state if ( isR2Full ) @@ -618,21 +647,22 @@ DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1; // If reservoir 1 is empty, turn off the drain pump - if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ) ) { + isR1Full = FALSE; // Done with draining R1 signalDrainPumpHardStop(); } // First reservoir 2 must be completely full if ( isR2Full != TRUE ) { - isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); } // Once R2 is full, R1 must be partially full if( isR2Full ) { - isR1Full = isRsrvrFull( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + isR1Full = isRsrvrFull( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); // Once R1 is partially full, transition to the next state if ( isR1Full ) @@ -669,7 +699,7 @@ DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R2; // If reservoir 2 is empty, set the drain valve to drain R1 - if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ) ) { setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); // Start the timer for drain timeout @@ -693,7 +723,7 @@ DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R1; // If reservoir 1 is empty, set the state to fill water state - if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ) ) { // Done with draining the reservoirs signalDrainPumpHardStop(); @@ -734,14 +764,14 @@ DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER; // First reservoir 1 must be full - if ( isRsrvrFull( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ) ) + if ( isRsrvrFull( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ) ) { isR1Full = TRUE; } // Once reservoir 1 is full, check the status of reservoir 2 since the water overflows to reservoir 2 if ( isR1Full ) { - isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); // Once reservoir 2 is full, set the actuators for recirculation if ( isR2Full ) @@ -825,7 +855,7 @@ BOOL isR1PartiallyFull = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - RSRVRS_PARTIAL_FILL_VOL_ML ) < RSRVRS_MAX_TARGET_VOL_CHANGE_ML; - if ( isRsrvrFull( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ) && isR1PartiallyFull ) + if ( isRsrvrFull( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ) && isR1PartiallyFull ) { // Get the current volumes to be monitored during R2 to R1 heat disinfect state R1HeatDisinfectVol = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); @@ -903,7 +933,7 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; - if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ) ) { isR1Full = FALSE; @@ -929,7 +959,7 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R2; - if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ) ) { isR2Full = FALSE; @@ -995,17 +1025,17 @@ if ( isR1Full != TRUE ) { - isR1Full = isRsrvrFull( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + isR1Full = isRsrvrFull( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); } if ( isR1Full ) { - isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); if ( isR2Full ) { - // Set the valves to rinses R2 to R1 and drain R1 + // Set the valves to rinse R2 to R1 and drain R1 setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); @@ -1033,7 +1063,7 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1; - if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ) ) { // Done with draining R1 signalDrainPumpHardStop(); @@ -1042,19 +1072,19 @@ // First reservoir 2 must be completely full if ( isR2Full != TRUE ) { - isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + isR2Full = isRsrvrFull( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); } // Once reservoir 2 is completely full, monitor reservoir 1 if ( isR2Full ) { - isR1Full = isRsrvrFull( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + isR1Full = isRsrvrFull( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH ); if ( isR1Full ) { // Done with filling, turn off the RO pump signalROPumpHardStop(); - // Deenergize all the valves and set the VDr to drain R2 + // De-energize all the valves and set the VDr to drain R2 setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); @@ -1101,8 +1131,99 @@ /*********************************************************************//** * @brief + * The handleHeatDisinfectCancelModeBasicPath function handles the + * heat disinfect cancel mode basic path state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeBasicPath( void ) +{ + // Go to state complete, we are done + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_COMPLETE; + + // Set the cancellation mode + cancellationMode = CANCELLATION_MODE_BASIC; + + // Pass the previous heat disinfect state for alarm report + setModeToFailed( prevHeatDisinfectState ); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectCancelModeWaterPath function handles the + * heat disinfect cancel mode cold water path state. + * @details Inputs: none TODO fill up + * @details Outputs: none TODO fill up + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeWaterPath( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + + // Stop all the actuators first then decide who should run next + resetActuators(); + + if ( cancellationMode == CANCELLATION_MODE_NONE ) + { + // Check inlet dialysate and redundant outlet temperature sensors + F32 TDi = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + F32 TRo = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); + + // The two sensors must be less than a threshold to decide if mix drain is needed to normal drain + if ( TDi < MIX_DRAIN_TEMPERATURE_THRESHOLD_C && TRo < MIX_DRAIN_TEMPERATURE_THRESHOLD_C ) + { + // Set the reservoirs status to FALSE + isR1Full = FALSE; + isR2Full = FALSE; + cancellationMode = CANCELLATION_MODE_COLD; + } + else + { + // Set the reservoirs status to FALSE + isR1Full = FALSE; + isR2Full = FALSE; + // The fluid is hot so this is a mix drain. Set the VPd to direct the cold inlet fluid to drain + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); + cancellationMode = CANCELLATION_MODE_HOT; + } + + // The drain is set to start from reservoir 2 since all the actuators have been de-energized + // Start the drain pump + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Start the timer for drain timeout + stateTimer = getMSTimerCount(); + } + + // If reservoir 2 is empty, set to drain reservoir 1 + if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + { + // Set the drain valve to reservoir 1 + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + isR2Full = FALSE; + } + + // If reservoir 2 has already been drained and reservoir 1 is empty, reset and switch to complete + if ( ( isR2Full != TRUE ) && isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + { + // Done with heat disinfect mode + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + + // Pass the previous heat disinfect state for alarm report + setModeToFailed( prevHeatDisinfectState ); + } + + return state; +} + +/*********************************************************************//** + * @brief * The resetActuators function sets all the actuators to reset and - * deenergized state. + * de-energized state. * @details Inputs: none * @details Outputs: none * @return none @@ -1114,7 +1235,7 @@ turnOffUVReactor( INLET_UV_REACTOR ); turnOffUVReactor( OUTLET_UV_REACTOR ); - // Deenergize all the valves + // De-energize all the valves setValveState( VPI, VALVE_STATE_OPEN ); setValveState( VBF, VALVE_STATE_CLOSED ); setValveState( VSP, VALVE_STATE_CLOSED ); @@ -1145,8 +1266,6 @@ *************************************************************************/ static void setModeToFailed( DG_HEAT_DISINFECT_STATE_T failedState ) { - heatDisinfectState = DG_HEAT_DISINFECT_STATE_COMPLETE; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_HEAT_DISINFECT_CYCLE_FAILED, failedState ) } @@ -1160,10 +1279,11 @@ * @param r is either R1 or R2 * @param targetVol is the target fill volume * @param timeout is the fill up timeout - * @param state is the state that called this function + * @param cancellationState is the cancellation state to be called in case + * the operation timed out. * @return none *************************************************************************/ -static BOOL isRsrvrFull( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout, DG_HEAT_DISINFECT_STATE_T state ) +static BOOL isRsrvrFull( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout, DG_HEAT_DISINFECT_STATE_T cancellationState ) { BOOL rsrvrStatus = FALSE; F32 volume = 0.0; @@ -1186,8 +1306,9 @@ } else if ( didTimeout( stateTimer, timeout ) ) { - // Fill timed out - //setModeToFailed( state ); //TODO un-comment + // Failed to fill ontime. Update the previous heat disinfect state and transition to basic cancellation + prevHeatDisinfectState = heatDisinfectState; + heatDisinfectState = cancellationState; } return rsrvrStatus; @@ -1201,10 +1322,11 @@ * @details Inputs: none * @details Outputs: none * @param r is R1 or R2 - * @param state is the state that called this function + * @param cancellationState is the cancellation state to be called in case + * the operation timed out. * @return none *************************************************************************/ -static BOOL isRsrvrEmpty( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, DG_HEAT_DISINFECT_STATE_T failedState ) +static BOOL isRsrvrEmpty( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, DG_HEAT_DISINFECT_STATE_T cancellationState ) { BOOL isDrainComplete = FALSE; @@ -1217,7 +1339,9 @@ } else if ( didTimeout( stateTimer, RSRVRS_DRAIN_TIMEOUT_MS ) ) { - setModeToFailed( failedState ); + // Failed to drain ontime. Update the previous heat disinfect state and transition to basic cancellation + prevHeatDisinfectState = heatDisinfectState; + heatDisinfectState = cancellationState; } return isDrainComplete; @@ -1237,7 +1361,7 @@ BOOL heatDisinfectStatus = FALSE; F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 TPmTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); //TODO change this to actual TPm sensor later + F32 ThdTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); //TODO change this to actual TPm sensor later BOOL isR1OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; BOOL isR2OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) - R2HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; @@ -1266,20 +1390,22 @@ // If the coldest spot which is TPm is less than minimum heat disinfect temperature, // reset the heat disinfect timers and check whether heating up has timed out - if ( TPmTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) + if ( ThdTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) { + // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfection truly starts + heatDisinfectTimer = getMSTimerCount(); hasHeatDisinfectStarted = FALSE; if ( didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) { // Heating up to minimum temperature for heat disinfect failed - //setModeToFailed( state ); TODO un-comment - BOOL test = FALSE; + // TODO we need to know how long it takes to reach to temperature before turning on the timeout + //setModeToFailed( state ); } } - else if ( hasHeatDisinfectStarted != TRUE && TPmTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) + else if ( hasHeatDisinfectStarted != TRUE && ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) { - // The temperature of the coldest spot is in range start. Start the timer for heat disinfect cycle + // The temperature of the coldest spot is in range to start the disinfect timer heatDisinfectTimer = getMSTimerCount(); hasHeatDisinfectStarted = TRUE; } @@ -1312,9 +1438,10 @@ { MODE_HEAT_DISINFECT_DATA_T data; - data.heatDisinfectState = (U32)heatDisinfectState; // TODO remove + data.heatDisinfectState = (U32)heatDisinfectState; data.overallElapsedTime = calcTimeSince( overallHeatDisinfectTimer ); data.stateElapsedTime = calcTimeSince( stateTimer ); + data.cancellationMode = (U32)cancellationMode; // If the mode is in the actual heat disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion if ( heatDisinfectState == DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 || heatDisinfectState == DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1 )