Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 -r1a5efe97f5f39594b45797fded52cafce92afe80 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 1a5efe97f5f39594b45797fded52cafce92afe80) @@ -41,19 +41,19 @@ // 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 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 MAX_START_STATE_TEMP_SENSORS_DIFF_C 3.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 DRAIN_PUMP_TARGET_RPM 2200 ///< Drain pump target RPM during drain. #define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 2* SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. #define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. // Flush drain path state defines -#define FLUSH_DRAIN_WAIT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. TODo original time was 60 seconds +#define FLUSH_DRAIN_WAIT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. #define MIN_INLET_TEMPERATURE_C 15.0 ///< Minimum water inlet temperature in C. TODO original temperature was 25 C #define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0 ///< Maximum water inlet conductivity in us/cm @@ -73,29 +73,33 @@ #define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. // Fill and heat water -#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 85.0 ///< Heat disinfect target water temperature in C. TODO original temperature was 85.0 -#define HEAT_DISINFECT_START_TEMPERATURE_C 81.0 ///< Heat disinfect minimum acceptable temperature in C. TODO original temperature was 81.0 +#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 83.0 ///< Heat disinfect target water temperature in C. +#define HEAT_DISINFECT_START_TEMPERATURE_C 81.0 ///< Heat disinfect minimum acceptable temperature in C. // R1 to R2 & R2 to R1 heat disinfect circulation -#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 0.9 ///< Heat disinfect target RO flow rate in L/min. TODO original value was 0.8 +#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 1.2 ///< 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 10.0 ///< Heat disinfect target drain outlet pressure in psi. -#define HEAT_DISINFECT_TIME_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. TODO original time was 10 minutes +#define HEAT_DISINFECT_TIME_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. #define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. TODO figure out this timeout #define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 0.5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disinfect. TODO change this to 5 seconds #define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 600.0 ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. TODO original value is 100 mL #define POST_HEAT_DISINFECT_WAIT_TIME_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect final wait time before flushing the system in milliseconds. +// Cool down RO filter +#define MIN_NUM_OF_ROF_CIRCULATIONS_FOR_COOLING 2 ///< Number of circulations that are needed to make the RO filter is below 45 C. +#define ROF_COOL_DOWN_TARGET_FLOW_LPM 0.3 ///< RO filter cool down target flow in L/min. +#define ROF_COOL_DOWN_CIRCULATION_TIME_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< RO filter cool down circulation timer in milliseconds. + // Mix drain R1 and R2 #define RSRVRS_MIX_DRAIN_TIMEOUT_MS ( 20 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 mix drain timeout in ms. #define DRAIN_PUMP_START_TIME_IN_MIX_DRAIN_MS ( 5 * MS_PER_SECOND ) ///< Time to start the drain pump at mix drain after directing the flow to drain in ms. #define DRAIN_PUMP_RPM_IN_MIX_DRAIN 600 ///< The RPM that the drain pump should be run during mix drain. #define MIX_DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 15 * MS_PER_SECOND ) ///< Time period of unchanged weight during mix draining before timeout. // Rinse R1 to R2 -#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 +#define ROF_MIN_LOW_PRESSURE_TEMPERATURE_C 45.0 ///< RO filter minimum temperature that the pressure must be no more than 30psi in C. -// Cancellation paths #define MIX_DRAIN_TEMPERATURE_THRESHOLD_C 60.0 ///< Temperature threshold for performing mix drain or normal drain. /// Cancellation paths @@ -106,7 +110,7 @@ CANCELLATION_MODE_HOT, ///< Cancellation mode hot. CANCELLATION_MODE_COLD, ///< Cancellation mode cold. NUM_OF_CANCELLATION_MODES ///< Number of cancellation modes. -} CANCELLATION_MODES_T; +} CANCELLATION_MODE_T; /// Heat disinfect status typedef enum Heat_disinfect_status @@ -120,27 +124,31 @@ // ********** private data ********** -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. -static BOOL areTempSensorsInRange = FALSE; ///< Heat disinfect temperature sensors in/out range flag. +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 DG_HEAT_DISINFECT_UI_STATE_T heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_NOT_RUNNING; ///< Current active heat disinfect UI state. +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. +static BOOL areTempSensorsInRange = FALSE; ///< Heat disinfect temperature sensors in/out range flag. /// Boolean flag to check whether draining R1 and R2 is at the end of the heat disinfect cycle or in the beginning. So the drain states can be reused. static BOOL isThisLastDrain = FALSE; -static DG_RESERVOIR_STATUS_T rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 1 status. -static DG_RESERVOIR_STATUS_T rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 2 status. -static F32 R1HeatDisinfectVol = 0.0; ///< Reservoir 1 full volume during heat disinfect. -static F32 R2HeatDisinfectVol = 0.0; ///< Reservoir 2 full volume during heat disinfect. -static U32 heatDisinfectTimer = 0; ///< Heat disinfect timer. -static BOOL isPartialDisinfectInProgress = FALSE; ///< Heat disinfect partial complete/in progess flag. -static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during heat disinfect. -static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during heat disinfect. -static U32 dataPublishCounter = 0; ///< Heat Disinfect data publish counter. -static CANCELLATION_MODES_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. -static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. -static ALARM_ID_T alarmDetectedPendingTrigger; ///< Heat disinfect alarm to raise. -static BOOL isDrainPumpInMixDrainOn = FALSE; ///< Flag to show the drain pump is on during mix drain. +static DG_RESERVOIR_STATUS_T rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 1 status. +static DG_RESERVOIR_STATUS_T rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 2 status. +static F32 R1HeatDisinfectVol = 0.0; ///< Reservoir 1 full volume during heat disinfect. +static F32 R2HeatDisinfectVol = 0.0; ///< Reservoir 2 full volume during heat disinfect. +static U32 heatDisinfectTimer = 0; ///< Heat disinfect timer. +static BOOL isPartialDisinfectInProgress = FALSE; ///< Heat disinfect partial complete/in progess flag. +static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during heat disinfect. +static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during heat disinfect. +static U32 dataPublishCounter = 0; ///< Heat Disinfect data publish counter. +static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. +static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. +static ALARM_ID_T alarmDetectedPendingTrigger; ///< Heat disinfect alarm to raise. +static BOOL isDrainPumpInMixDrainOn = FALSE; ///< Flag to indicate the drain pump is on during mix drain. +static BOOL hasROFCirculationBeenStarted = FALSE; ///< Flag to indicate the water in RO filter has been recirculated. +static U32 ROFCirculationTimer = 0; ///< RO filter circulation timer. +static U32 ROFCirculationCoolingCounter = 0; ///< RO filter circulation cooling counter. // ********** private function prototypes ********** @@ -182,14 +190,17 @@ * @details Outputs: heatDisinfectState, stateTimer, isThisLastDrain, * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, * R1HeatDisinfectVol, R2HeatDisinfectVol, overallHeatDisinfectTimer, - * cancellationMode, rsrvrFillStableTimeCounter, isPartialDisinfectInProgress, - * isDrainPumpOnInMixDrain + * cancellationMode, rsrvrFillStableTimeCounter, prevHeatDisinfectState + * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain, + * hasROFCirculationBeenStarted, ROFCirculationTimer, + * ROFCirculationCoolingCounter * @return none *************************************************************************/ void initHeatDisinfectMode( void ) { heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_NOT_RUNNING; stateTimer = 0; isThisLastDrain = FALSE; stateTrialCounter = 0; @@ -203,6 +214,9 @@ rsrvrFillStableTimeCounter = 0; isPartialDisinfectInProgress = FALSE; isDrainPumpInMixDrainOn = FALSE; + hasROFCirculationBeenStarted = FALSE; + ROFCirculationTimer = 0; + ROFCirculationCoolingCounter = 0; } /*********************************************************************//** @@ -406,7 +420,7 @@ F32 TDiTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODo change to TDi F32 TRoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); - // If the inlet pressure is less than the threshold and TDi and TRo difference is greater than 1 C, the cycle + // If the inlet pressure is less than the threshold and TDi and TRo difference is greater than 3 C, the cycle // should be canceled if ( ( ppiPressure < MIN_INLET_PRESSURE_PSI ) && ( fabs( TDiTemp - TRoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) ) { @@ -416,6 +430,9 @@ } else { + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT; + // Close VPi to prevent wasting water setValveState( VPI, VALVE_STATE_CLOSED ); // Request a tare for reservoir 1 @@ -490,6 +507,7 @@ rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; // Request a tare for reservoir 2 tareReservoir(); + #ifndef V_2_SYSTEM // Done with draining R1, close it setValveState( VRD1, VALVE_STATE_CLOSED ); @@ -551,6 +569,7 @@ else { signalDrainPumpHardStop(); + #ifndef V_2_SYSTEM // Done with draining R2, close it setValveState( VRD2, VALVE_STATE_CLOSED ); @@ -574,7 +593,7 @@ * @brief * The handleHeatDisinfectFlushDrainState function handles the heat disinfect * flush drain state. The state flushes the drain line for a period of time - * and then measure the temperature and conductivity of water. If they are + * and then measures the temperature and conductivity of water. If they are * not within the range, it transitions to basic cancellation path, otherwise * it transitions to the next state. * @details Inputs: stateTimer, stateTrialCounter, alarm, @@ -640,7 +659,7 @@ DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; // Check if the flush circulation time has elapsed and the temperature sensors are not in range yet - if ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) && ( FALSE == areTempSensorsInRange ) ) + if ( ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) && ( FALSE == areTempSensorsInRange ) ) { F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); // TODO add THd later. This is the new temp sensor of the coldest spot. F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); @@ -721,7 +740,7 @@ { rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - // Keep monitoring the status of reservoir 2 as the same time + // Keep monitoring the status of reservoir 2 at the same time rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue @@ -964,7 +983,7 @@ // Turn on the RO pump setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); - // Start heating the water while we are filling up the rsrvrs + // Start heating the water while we are filling up the reservoirs setPrimaryHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); startPrimaryHeater(); @@ -1002,6 +1021,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_HEAT_UP_WATER; + // First reservoir 1 must be full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { @@ -1029,17 +1051,17 @@ // Set the drain pump to control mode setDrainPumpTargetOutletPressure( HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI ); - // Set the RO flow to maximum pressure of 25psi since it is the maximum pressure on the RO filter + // Set the RO flow to maximum pressure of 30psi since it is the maximum pressure on the RO filter // at inlet temperature > 45 C setROPumpTargetFlowRate( HEAT_DISINFECT_TARGET_RO_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); - // Start the trimmer heater since we are recirculating water - //setTrimmerHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); - //startTrimmerHeater(); TODO turn the trimmer heater on when THD is implemented + // Start the trimmer heater since we are recirculating water and there is flow in the shunt line + setTrimmerHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); + startTrimmerHeater(); // Get the current volumes of R1 & R2. These values will be used to make sure the reservoirs' // volume does not change more than a certain amount during the actual heat disinfect cycle - R1HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ); //TODO change this back to primary + R1HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); R2HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); stateTimer = getMSTimerCount(); @@ -1103,9 +1125,11 @@ rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; break; + case HEAT_DISINFECT_IN_PROGRESS: default: // Do nothing, heat disinfect is in progress break; @@ -1131,6 +1155,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_TRANSITION_HOT_WATER; + // First reservoir 1 must be partially full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { @@ -1150,21 +1177,17 @@ state = DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1; } -#ifdef IGNORE_HEAT_DISINFECT_RSRVR_TIMEOUT else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevHeatDisinfectState = state; state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; } -#endif } -#ifdef IGNORE_HEAT_DISINFECT_RSRVR_TIMEOUT else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevHeatDisinfectState = state; state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; } -#endif return state; } @@ -1176,8 +1199,8 @@ * temperature within a certain period of time, it transitions to water * cancellation state. If heat disinfect reservoir 1 to reservoir 2 is * completed, it transitions to the next state. - * @details Inputs: hasPostHeatDisinfectWaitStarted, stateTimer, rsrvr1Status - * @details Outputs: hasPostHeatDisinfectWaitStarted, stateTimer, rsrvr1Status + * @details Inputs: stateTimer, rsrvr1Status + * @details Outputs: stateTimer, rsrvr1Status * @return next state of the heat disinfect state machine *************************************************************************/ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR2ToR1State( void ) @@ -1193,13 +1216,18 @@ break; case HEAT_DISINFECT_COMPLETE: - // Turn off the pumps and heaters + // Turn off the heaters // TODO turn off CP1 and CP2 stopPrimaryHeater(); stopTrimmerHeater(); stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; break; + + case HEAT_DISINFECT_IN_PROGRESS: + default: + // Do nothing heat disinfect is in progress. + break; } return state; @@ -1218,6 +1246,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_COOL_DOWN_DEVICE; + if ( TRUE == didTimeout( stateTimer, POST_HEAT_DISINFECT_WAIT_TIME_MS ) ) { // Stop the drain pump and the RO pump to exit the closed loop @@ -1226,8 +1257,8 @@ // De-energize all the valves that are not in the path anymore // and wait for the RO membrane to be cooled down. - // In this state, VPi and VPd must still be kept energized to make sure fresh - // water does not enter the circulation path the membrane is cooling down + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_CLOSED ); #ifndef V_2_SYSTEM @@ -1250,32 +1281,68 @@ * The handleHeatDisinfectCoolDownROFilterState function handles the heat * disinfect cool down RO filter state. The state monitors the temperature * at THd and if it is less than 45 C, it transitions to the next state. - * @details Inputs: stateTimer, rsrvr1Status - * @details Outputs: stateTimer, rsrvr1Status + * @details Inputs: stateTimer, rsrvr1Status, hasROFCirculationBeenStarted, + * ROFCirculationCoolingCounter + * @details Outputs: stateTimer, rsrvr1Status, hasROFCirculationBeenStarted, + * ROFCirculationCoolingCounter * @return next state of the heat disinfect state machine *************************************************************************/ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCoolDownROFilterState( void ) { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_RO_FILTER; - F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODO change this to actual THd sensor later + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_COOL_DOWN_DEVICE; - // Check if the coldest spot temperature is less than 45 C so the RO filter - // can safely run fluid through - if ( ThdTemp < ROF_MIN_LOW_PRESSURE_TEMPERATURE_C ) + // TPo which is the temperature sensor after the heater is hottest spot + // and this temperature is monitored until it is dropped below 45 C to be able + // to run fluid through the RO filter + F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + + // Check if the coldest spot temperature is less than 45 C so the RO filter can safely run fluid through + if ( ( FALSE == isROPumpRunning() ) && ( TPoTemp < ROF_MIN_LOW_PRESSURE_TEMPERATURE_C ) ) { - setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // If the minimum number of circulations are done, transition to the next state + if ( ROFCirculationCoolingCounter > MIN_NUM_OF_ROF_CIRCULATIONS_FOR_COOLING ) + { + setValveState( VPI, VALVE_STATE_OPEN ); + // To make sure there is no leak from the reservoirs or drain to RO path during mix draining + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - stateTimer = getMSTimerCount(); - state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; + } + else + { + // Set the valves to circulation. VBf is opened because the fluid in the RO filter might still be hot + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + + // Set the RO flow to maximum pressure of 30psi since it is the maximum pressure on the RO filter + // at inlet temperature > 45 C + setROPumpTargetFlowRate( ROF_COOL_DOWN_TARGET_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); + + // Increment the RO filter cooling counter + ROFCirculationCoolingCounter++; + hasROFCirculationBeenStarted = TRUE; + ROFCirculationTimer = getMSTimerCount(); + } } + // If the RO filter water circulation is in progress and the time for it has elapsed, stop the pump + else if ( ( TRUE == hasROFCirculationBeenStarted ) && ( TRUE == didTimeout( ROFCirculationTimer, ROF_COOL_DOWN_CIRCULATION_TIME_MS ) ) ) + { + signalROPumpHardStop(); + // Done with running the RO pump + hasROFCirculationBeenStarted = FALSE; + } return state; } @@ -1296,13 +1363,18 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; + if ( ( TRUE == didTimeout( stateTimer, DRAIN_PUMP_START_TIME_IN_MIX_DRAIN_MS ) ) && ( isDrainPumpInMixDrainOn == FALSE ) ) { isDrainPumpInMixDrainOn = TRUE; #ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_OPEN ); #endif + setValveState( VRD1, VALVE_STATE_OPEN ); + // Turn on the drain pump to drain the reservoirs in open loop mode setDrainPumpTargetRPM( DRAIN_PUMP_RPM_IN_MIX_DRAIN ); } @@ -1410,6 +1482,18 @@ if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + // Keep monitoring the status of reservoir 2 at the same time + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already + // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue + // until reservoir 2 is filled up and the tubing might expand or leak. + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + prevHeatDisinfectState = state; + alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1487,6 +1571,21 @@ if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) { rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + U32 drainPumpRPM = getTargetDrainPumpRPM(); + // Keep monitoring the status of reservoir 1 as the same time + F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + // Reservoir 1 cannot be filled before reservoir 2 is filled and is overflowing to reservoir 1. If reservoir 1 has already + // reached to target volume, it means reservoir 2's load cell might be reading incorrect values. This situation might continue + // until reservoir 1 is filled up and the tubing might expand or leak. + // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make + // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL + if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + { + prevHeatDisinfectState = state; + alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } } // Once reservoir 2 is completely full, monitor reservoir 1 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) @@ -1576,6 +1675,9 @@ // Go to state complete, we are done DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_CANCEL_DISINFECT; + // Set the cancellation mode cancellationMode = CANCELLATION_MODE_BASIC; @@ -1601,6 +1703,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_CANCEL_DISINFECT; + if ( CANCELLATION_MODE_NONE == cancellationMode ) { U32 targetRPM = 0; @@ -1636,6 +1741,8 @@ rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; // The drain is set to start from reservoir 2 since all the actuators have been de-energized + // Set the drain valve to reservoir 2 + setValveState( VRD2, VALVE_STATE_OPEN ); // Start the drain pump setDrainPumpTargetRPM( targetRPM ); @@ -1699,6 +1806,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_COMPLETE; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_COMPLETE; + stopDGHeatDisinfect(); return state; @@ -1747,7 +1857,7 @@ * @brief * The failHeatDisinfect function sets the alarm that failed the heat * disinfect mode. - * @details Inputs: alarm, prevHeatDisinfectState + * @details Inputs: alarmDetectedPendingTrigger, prevHeatDisinfectState * @details Outputs: none * @return none *************************************************************************/ @@ -1775,7 +1885,7 @@ if ( r == DG_RESERVOIR_1 ) { - volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ); //TODO change back to primary + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else if ( r == DG_RESERVOIR_2 ) { @@ -1814,8 +1924,7 @@ * reservoir. * @details Inputs: stateTimer, prevHeatDisinfectState, heatDisinfectState, * alarm - * @details Outputs: stateTimer, heatDisinfectState heatDisinfectState, - * alarm + * @details Outputs: stateTimer, heatDisinfectState, alarm * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 * @param drainSteadyStateTimeout which is the time the reservoir's level * does not change and is steady state @@ -1856,21 +1965,21 @@ * If the heat disinfect has started or has elapsed, it set the status of * heat disinfect accordingly. * @details Inputs: areRsrvrsLeaking, areRsrvrsLeaking - * @details Outputs: areRsrvrsLeaking, areRsrvrsLeaking + * @details Outputs: areRsrvrsLeaking, areRsrvrsLeaking, heatDisinfectState * @return status of the heat disinfect (i.e in progress, complete) *************************************************************************/ static HEAT_DISINFECT_STATUS_T getHeatDisinfectStatus( void ) { HEAT_DISINFECT_STATUS_T status = HEAT_DISINFECT_IN_PROGRESS; F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODO change this to actual TPm sensor later + F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODO change this to actual THd sensor later - BOOL isR1OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ) - R1HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; //TODo change this to primary when the stupid load cell was fixed + 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; // Check if either reservoir 1 or reservoir 2 are losing volume more than allowed volume - if ( isR1OutOfRange || isR2OutOfRange ) + if ( ( TRUE == isR1OutOfRange ) || ( TRUE == isR2OutOfRange ) ) { // If the leak is the first time after a while, set the flag and start the timer if ( FALSE == areRsrvrsLeaking ) @@ -1882,7 +1991,7 @@ else if ( TRUE == didTimeout( rsrvrsVolMonitorTimer, RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ) ) { areRsrvrsLeaking = FALSE; - alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; status = HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT; } } @@ -1892,18 +2001,19 @@ areRsrvrsLeaking = FALSE; } - // If the coldest spot which is TPm is less than minimum heat disinfect temperature, + // If the coldest spot which is THd is less than minimum heat disinfect temperature, // reset the heat disinfect timers and check whether heating up has timed out if ( ThdTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) { // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts heatDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = FALSE; + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_HEAT_UP_WATER; if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) { // Heating up to minimum temperature for heat disinfect failed - alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; + alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; } } @@ -1912,6 +2022,16 @@ // The temperature of the coldest spot is in range to start the disinfect timer heatDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = TRUE; + + // Set the heat disinfect UI state + if ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) + { + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_1; + } + else + { + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_2; + } } // If heat disinfect temperature has been reached, check if this stage of heat disinfect is done @@ -1938,26 +2058,36 @@ if ( ++dataPublishCounter > HEAT_DISINFECT_DATA_PUB_INTERVAL ) { MODE_HEAT_DISINFECT_DATA_T data; + MODE_HEAT_DISINFECT_UI_DATA_T uiData; - data.heatDisinfectState = (U32)heatDisinfectState; - data.overallElapsedTime = calcTimeSince( overallHeatDisinfectTimer ); - data.stateElapsedTime = calcTimeSince( stateTimer ); - data.cancellationMode = (U32)cancellationMode; - data.R1FillLevel = R1HeatDisinfectVol; - data.R2FillLevel = R2HeatDisinfectVol; + data.heatDisinfectState = (U32)heatDisinfectState; + data.overallElapsedTime = calcTimeSince( overallHeatDisinfectTimer ); + data.stateElapsedTime = calcTimeSince( stateTimer ); + data.cancellationMode = (U32)cancellationMode; + data.heatDisinfectUIState = (U32)heatDisinfectUIState; // If the mode is in the actual heat disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion - if ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState || DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1 == heatDisinfectState ) + if ( ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) || + ( DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1 == heatDisinfectState ) ) { - data.heatDisinfectElapsedTime = calcTimeSince( heatDisinfectTimer ); + uiData.heatDisinfectTargetTime = HEAT_DISINFECT_TIME_MS; + uiData.heatDisinfectCountdownTime = HEAT_DISINFECT_TIME_MS - calcTimeSince( heatDisinfectTimer ); + data.R1FillLevel = R1HeatDisinfectVol; + data.R2FillLevel = R2HeatDisinfectVol; } else { - data.heatDisinfectElapsedTime = 0; + uiData.heatDisinfectTargetTime = 0; + uiData.heatDisinfectCountdownTime = 0; + data.R1FillLevel = 0.0; + data.R2FillLevel = 0.0; } broadcastHeatDisinfectData( &data ); + // Publish data to UI + broadcastHeatDisinfectData2UI( &uiData ); + dataPublishCounter = 0; } }