Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r19934ca6e36e2dcabd6a6083a9a1f15b1ed32189 -r3fae8c2aab5873ccfaf8b7e1e4a2abf78216a7fd --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 19934ca6e36e2dcabd6a6083a9a1f15b1ed32189) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 3fae8c2aab5873ccfaf8b7e1e4a2abf78216a7fd) @@ -52,7 +52,6 @@ // Start state defines #define MIN_INLET_PRESSURE_PSI 30.0F ///< Minimum water inlet pressure in psi. -#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 3.0F ///< Max start state TDi and TRo difference tolerance in C. // Drain R1 & R2 states defines #define DRAIN_PUMP_TARGET_RPM 2400 ///< Drain pump target RPM during drain. @@ -61,15 +60,21 @@ // Flush drain path state defines #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.0F ///< Minimum water inlet temperature in C. TODO original temperature was 25 C +#define MIN_INLET_TEMPERATURE_C 24.0F ///< Minimum water inlet temperature in C. +#define MIN_INLET_TEMPERATURE_C 35.0F ///< Maximum water inlet temperature in C. #define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0F ///< Maximum water inlet conductivity in us/cm - +#define MIN_INLET_CONDUCTIVITY_US_PER_CM 100.0F ///< Minimum water inlet conductivity in us/cm +#define MAX_ALLOWED_FLUSH_DRAIN_PERIODS 2 ///< Number of flush drain periods to wait for inlet water to come into range +#define INLET_WATER_CHECK_FAILURE_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Timer for inlet water check failures before alarm // Flush circulation path state defines -#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.8F ///< RO pump target flow rate during flush/fill in L/min. +#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.5F ///< RO pump target flow rate during flush/fill in L/min. #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. +#define FLUSH_CICRCULATION_ADDITIONAL_WAIT_TIME_MS ( 60 * MS_PER_SECOND ) ///< Flush/rinse circulation path additional wait time in milliseconds. #define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 3.0F ///< Maximum flush circulation temperature difference tolerance in C. -#define NUM_OF_TEMP_SENSORS_TO_AVG 4.0F ///< Number of temperature sensors to average to check the difference. +#define NUM_OF_TEMP_SENSORS_TO_AVG 2.0F ///< Number of temperature sensors to average to check the difference. +#define MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM 100.0F ///< Maximum allowed conductivity in flush circulation state in us/cm +#define MAX_ALLOWED_FLUSH_CIRC_PERIODS 3 ///< Number of flush circulation periods to wait for sensors to come into range // Flush and drain R1 and R2 #define RSRVRS_FULL_VOL_ML 1850.0F ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 @@ -80,30 +85,39 @@ #define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. // R1 to R2 & R2 to R1 chemical disinfect circulation -#define CHEM_DISINFECT_TARGET_RO_FLOW_LPM 0.8F ///< Chemical disinfect target RO flow rate in L/min. +#define CHEM_DISINFECT_TARGET_RO_FLOW_LPM 0.5F ///< Chemical disinfect target RO flow rate in L/min. #define CHEM_DISINFECT_MAX_RO_PRESSURE_PSI 130 ///< Chemical disinfect maximum RO pressure in psi. #define CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI 12.0 ///< Chemical disinfect target drain outlet pressure in psi. #define CHEM_DISINFECT_TIME_MS ( 36 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect time for each section in milliseconds. TODO original time was 36 minutes -#define CHEM_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect reaching to minimum temperature timeout in milliseconds. +#define CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect reaching to minimum temperature timeout in milliseconds. #define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 0.5F * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during chemical disinfect. TODO change this to 5 seconds #define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 600.0F ///< Reservoirs 1 & 2 maximum allowed volume change when full during chemical disinfect. TODO original value is 100 mL #define POST_CHEM_DISINFECT_WAIT_TIME_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect final wait time before flushing the system in milliseconds. // Prime acid line -#define PRIME_ACID_LINE_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Priming acid line timeout in milliseconds. -#define CONC_PUMP_PRIME_SPEED_ML_PER_MIN 40.0F ///< Concentrate pump prime speed in ml/min. -#define MIN_ACID_CONDUCTIVITY_US_PER_CM 2000.0F ///< Minimum conductivity that indicates acid is in the line in uS/cm. -#define PRIME_ACID_STEADY_CONDUCTIVITY_TIME_MS ( ( 2 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Minimum time that a steady conductivity of acid must be read in milliseconds. +#define PRIME_ACID_LINE_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Priming acid line timeout in milliseconds. +#define DISINFECTANT_PUMP_PRIME_SPEED_ML_PER_MIN 19.0F ///< Disinfectant pump prime speed in ml/min. +#define MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM 600.0F ///< Minimum conductivity that indicates acid is in the line in uS/cm. +#define PRIME_ACID_STEADY_CONDUCTIVITY_TIME_MS ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Minimum time that a steady conductivity of acid must be read in milliseconds. +#define RO_PUMP_TARGET_PRIME_DISINECTANT_FLOW_RATE_LPM 0.8F ///< ROP flow rate for disinfectant prime +#define MAX_RO_PUMP_PRIME_DISINFECTANT_PRESSURE_PSI 130.0F ///< ROP max pressure for disinfectant prime // Fill with disinfectant and water -#define MIN_RO_FLOW_FOR_CONC_PUMP_MIXING_LPM 0.3F ///< Minimum RO flow rate that is need to be able to turn on the concentrate pump for mixing. - +#define MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS 2 +#define MIN_RO_FLOW_FOR_CONC_PUMP_MIXING_LPM 0.3F ///< Minimum RO flow rate that is need to be able to turn on the concentrate pump for mixing. +#define DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN 7.5F ///< Disinfectant pump fill speed in ml/min. +#define RO_PUMP_TARGET_FILL_DISINECTANT_FLOW_RATE_LPM 0.5F ///< ROP flow rate for disinfectant prime +#define MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI 130.0F ///< ROP max pressure for disinfectant fill +#define FLUSH_DISINFECTANT_INITIAL_WAIT_TIME ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Initial time to wait for temperature and conductivity to reach target in disinfectant flush state +#define FLUSH_DISINFECTANT_ADDITIONAL_WAIT_TIME ( 60 * SEC_PER_MIN * MS_PER_SECOND ) ///< Additional time to wait for temperature and conductivity to reach target in disinfectant flush state +#define MAX_DISINFECT_FLUSH_CYCLE_PERIODS 2 ///< Number of allowed periods to check conductivity and temperature in disinfectant flush state +#define MIN_DISINFECT_CONDUCTIVITY_US_PER_CM 150.0F ///< Minimum conductivity for mixed disinfect fluid in us/cm +#define MAX_DISINFECT_CONDUCTIVITY_US_PER_CM 650.0F ///< Minimum conductivity for mixed disinfect fluid in us/cm +#define MIN_DISINFECT_TD2_TEMPERATURE_C 35.0F ///< Minimum temperature for mixed disinfect fluid at outlet of heater in dec C +#define MAX_DISINFECT_TD2_TEMPERATURE_C 45.0F ///< Maximum temperature for mixed disinfect fluid at outlet of heater in dec C // Fill heat up -#define CHEM_DISINFECT_TARGET_TEMPERATURE_C 21.0F ///< Chemical disinfect target water temperature in C. // TODO this used to 30.0 - -// Post disinfect rinses -#define NUM_OF_POST_DISINFECT_RINSES 12 ///< Number of rinses after a chemical disinfect. - +#define CHEM_DISINFECT_TARGET_TEMPERATURE_C 40.0F ///< Chemical disinfect target water temperature in C. // TODO this used to 30.0 +#define DISINFECT_CYCLE_PERIOD_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time for disinfectant filling and partial draining cycle static const F32 ACID_TO_WATER_MIXING_RATIO = ( 1.0F / 70.0F ); ///< Acid to water mixing ratio for chemical disinfect. /// Cancellation paths @@ -122,6 +136,9 @@ CHEM_DISINFECT_IN_PROGRESS = 0, ///< Chemical disinfect in progress. CHEM_DISINFECT_RSRVRS_LEAK_TIMEOUT, ///< Chemical disinfect reservoirs leak timeout. CHEM_DISINFECT_HEAT_UP_TIMEOUT, ///< Chemical disinfect heat up timeout. + CHEM_DISINFECT_HEATER_OUTLET_TEMPERATURE_OUT_OF_RANGE, + CHEM_DISINFECT_DISINFECTANT_CONDUCTIVITY_OUT_OF_RANGE, + CHEM_DISINFECT_DISINFECT_TEMPERATURE_LOW, CHEM_DISINFECT_COMPLETE, ///< Chemical disinfect complete. NUM_OF_CHEM_DISINFECT_STATUS ///< Number of chemical disinfect status. } CHEM_DISINFECT_STATUS_T; @@ -144,6 +161,8 @@ static BOOL areTempSensorsInRange = FALSE; ///< Chemical disinfect temperature sensors in/out range flag. /// Boolean flag to check whether draining R1 and R2 is at the end of the chemical disinfect cycle or in the beginning. So the drain states can be reused. static BOOL isThisLastDrain = FALSE; +static BOOL haveInletWaterChecksPassed = FALSE; ///< Chemical disinfect inlet water checks flag +static U32 inletWaterChecksFailTimer = 0; ///< Timer for inlet water check failures 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 R1ChemDisinfectVol = 0.0; ///< Reservoir 1 full volume during chemical disinfect. @@ -157,6 +176,8 @@ static U32 rsrvrFillStableTimeCounter; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Chemical disinfect alarm to raise. static U32 numberOfPostDisinfectRinses; ///< Number of times to rinse the fluid path after chemical disinfect. +static U32 flushCircWaitTime; ///< Variable time period to wait in flush circulation state to check sensor values +static U32 flushDisinfectantWaitTime; ///< Variable time period to wait in disinfectant flush state to check sensor values static U32 primeAcidSteadyStateCounter = 0; ///< Prime acid steady state counter. static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. static DISINFECT_NV_OPS_T disinfectNVOps; ///< Disinfect non-volatile memory operations. @@ -168,27 +189,18 @@ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDrainR2State( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushDrainState( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushCirculationState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushR1AndR2State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushR2AndDrainR1State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushDrainR2State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushDrainR1State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeAcidLineState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillWithWaterAndDisinfectantState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRemoveAcidBottleFromUIState( void ); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeDisinfectantState( void ); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantFlushState( void ); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillWithDisinfectantState( void ); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectR1DisinfectantFillR2DrainState( void ); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectR2DisinfectantFillR1DrainState( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR1ToR2State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillR2WithDisinfectantState( void ); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR1FillR1ToR2State( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR2ToR1State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCoolDownHeatersState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantDrainR1State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantDrainR2State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseR1ToR2State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseR2ToR1AndDrainR1State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseR1ToR2AndDrainR2State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseCirculationState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeBasicPathState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeWaterPathState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCompleteState( void ); - +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR2FillR1ToR2State( void ); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeBasicPathState(void); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeWaterPathState(void); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCompleteState(void); static void failChemicalDisinfect( void ); static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ); static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); @@ -227,7 +239,7 @@ cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillStableTimeCounter = 0; isPartialDisinfectInProgress = FALSE; - numberOfPostDisinfectRinses = 0; + // numberOfPostDisinfectRinses = 0; primeAcidSteadyStateCounter = 0; chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_NOT_RUNNING; haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; @@ -289,74 +301,40 @@ chemDisinfectState = handleChemicalDisinfectFlushCirculationState(); break; - case DG_CHEM_DISINFECT_STATE_FLUSH_R1_AND_R2: - chemDisinfectState = handleChemicalDisinfectFlushR1AndR2State(); + case DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT: + chemDisinfectState = handleChemicalDisinfectPrimeDisinfectantState(); break; - case DG_CHEM_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1: - chemDisinfectState = handleChemicalDisinfectFlushR2AndDrainR1State(); - break; + case DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH: + chemDisinfectState = handleChemicalDisinfectDisinfectantFlushState(); + break; - case DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R2: - chemDisinfectState = handleChemicalDisinfectFlushDrainR2State(); + case DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT: + chemDisinfectState = handleChemicalDisinfectFillWithDisinfectantState(); break; - case DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R1: - chemDisinfectState = handleChemicalDisinfectFlushDrainR1State(); - break; + case DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN: + chemDisinfectState = handleChemicalDisinfectR2DisinfectantFillR1DrainState(); - case DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE: - chemDisinfectState = handleChemicalDisinfectPrimeAcidLineState(); - break; + case DG_CHEM_DISINFECT_STATE_R1_DISINFECTANT_FILL_R2_DRAIN: + chemDisinfectState = handleChemicalDisinfectR1DisinfectantFillR2DrainState(); - case DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT: - chemDisinfectState = handleChemicalDisinfectFillWithWaterAndDisinfectantState(); - break; - - case DG_CHEM_DISINFECT_STATE_REMOVE_ACID_BOTTLE_FROM_UI: - chemDisinfectState = handleChemicalDisinfectRemoveAcidBottleFromUIState(); - break; - case DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2: chemDisinfectState = handleChemicalDisinfectDisinfectR1ToR2State(); break; - case DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT: - chemDisinfectState = handleChemicalDisinfectFillR2WithDisinfectantState(); + case DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R1_FILL_R1_TO_R2: + chemDisinfectState = handleChemicalDisinfectPartialDrainR1FillR1ToR2State(); break; case DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1: chemDisinfectState = handleChemicalDisinfectDisinfectR2ToR1State(); break; - case DG_CHEM_DISINFECT_STATE_COOL_DOWN_HEATERS: - chemDisinfectState = handleChemicalDisinfectCoolDownHeatersState(); + case DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R2_FILL_R1_TO_R2: + chemDisinfectState = handleChemicalDisinfectPartialDrainR2FillR1ToR2State(); break; - case DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R1: - chemDisinfectState = handleChemicalDisinfectDisinfectantDrainR1State(); - break; - - case DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R2: - chemDisinfectState = handleChemicalDisinfectDisinfectantDrainR2State(); - break; - - case DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2: - chemDisinfectState = handleChemicalDisinfectRinseR1ToR2State(); - break; - - case DG_CHEM_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1: - chemDisinfectState = handleChemicalDisinfectRinseR2ToR1AndDrainR1State(); - break; - - case DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2: - chemDisinfectState = handleChemicalDisinfectRinseR1ToR2AndDrainR2State(); - break; - - case DG_CHEM_DISINFECT_STATE_RINSE_CIRCULATION: - chemDisinfectState = handleChemicalDisinfectRinseCirculationState(); - break; - case DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH: chemDisinfectState = handleChemicalDisinfectCancelModeBasicPathState(); break; @@ -445,32 +423,17 @@ // Set all the actuators to reset and de-energized state deenergizeActuators(); - F32 ppiPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); - F32 THdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); - F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + // Set the actuators to drain R1 + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - // 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( THdTemp - TPoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) ) - { - prevChemDisinfectState = state; - alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_INLET_PRES_AND_TEMP_SNSRS_OUT; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } - else - { - // Close VPi to prevent wasting water - setValveState( VPI, VALVE_STATE_CLOSED ); + rsrvrFillStableTimeCounter = 0; + // Assume reservoir 1 is full and drain it + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + stateTimer = getMSTimerCount(); - // Set the actuators to drain R1 - setValveState( VRD1, VALVE_STATE_OPEN ); - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - - rsrvrFillStableTimeCounter = 0; - // Assume reservoir 1 is full and drain it - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - stateTimer = getMSTimerCount(); - } - return state; } @@ -492,53 +455,22 @@ // Set the chemical disinfect that is published on the UI chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT; - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - if ( TRUE == isThisLastDrain ) - { - // Set the chemical disinfect that is published on the UI - // This is the final drain of chemical disinfect - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; + // Assume reservoir 2 is full and drain it + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - // Done with draining - signalDrainPumpHardStop(); + tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); - // Set the valves to flush the recirculation line - setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); - // Done with draining R1 - setValveState( VRD1, VALVE_STATE_CLOSED ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); - - // Set the RO pump to run at full pressure - setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); - - // Done with final draining - isThisLastDrain = FALSE; - state = DG_CHEM_DISINFECT_STATE_RINSE_CIRCULATION; - } - else - { - // Assume reservoir 2 is full and drain it - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - - tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); - tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); - - // Done with draining R1 - setValveState( VRD1, VALVE_STATE_CLOSED ); - setValveState( VRD2, VALVE_STATE_OPEN ); - state = DG_CHEM_DISINFECT_STATE_DRAIN_R2; - } - - // Start the timer - stateTimer = getMSTimerCount(); + // Done with draining R1 + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + state = DG_CHEM_DISINFECT_STATE_DRAIN_R2; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -549,7 +481,7 @@ return state; } -/*********************************************************************//** + /*********************************************************************//** * @brief * The handleChemicalDisinfectDrainR2State function handles the chemical * disinfect drain R2 state. The state drains reservoir 2. If the @@ -571,26 +503,26 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { + signalDrainPumpHardStop(); if ( TRUE == isThisLastDrain ) { // Set the chemical disinfect that is published on the UI // This is the final drain of chemical disinfect - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; - - setValveState( VRD1, VALVE_STATE_OPEN ); + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; // ??? this may not be correct setValveState( VRD2, VALVE_STATE_CLOSED ); - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + state = DG_CHEM_DISINFECT_STATE_COMPLETE; } else { tareLoadCell( LOAD_CELL_RESERVOIR_2_PRIMARY ); tareLoadCell( LOAD_CELL_RESERVOIR_2_BACKUP ); - signalDrainPumpHardStop(); setValveState( VRD2, VALVE_STATE_CLOSED ); setValveState( VPI, VALVE_STATE_OPEN ); - + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + stateTrialCounter = 0; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN; @@ -622,47 +554,41 @@ { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN; + // TODO: check whether flush has already been completed within some time period, skip this state if it has + // Check if flush time has elapsed if ( TRUE == didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) { - BOOL hasConductivityPassed = FALSE; - - // If the inlet temperature and conductivity are in range, move onto the next state - if ( ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MIN_INLET_TEMPERATURE_C ) && - ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) <= MAX_INLET_CONDUCTIVITY_US_PER_CM ) ) - { - hasConductivityPassed = TRUE; - } - -#ifndef _RELEASE_ - if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) - { - hasConductivityPassed = TRUE; - } -#endif - - if ( TRUE == hasConductivityPassed ) - { + if (haveInletWaterChecksPassed) + { + // set pumps and valves for next state, flush disinfectant line setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + + flushCircWaitTime = FLUSH_CICRCULATION_WAIT_TIME_MS; stateTimer = getMSTimerCount(); - stateTrialCounter = 0; state = DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION; } - // If the number of failures have not exceeded the limit, try again. - else if ( stateTrialCounter < MAX_ALLOWED_STATE_TRIALS ) - { - stateTrialCounter++; - stateTimer = getMSTimerCount(); - } - // Couldn't get a good water sample after a couple of trials and the disinfect cycle failed - else - { - alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_INLET_COND_AND_TEMP_OUT; - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } + else + { + // If the number of failures have not exceeded the limit, try again. + ++stateTrialCounter; + if ( stateTrialCounter < MAX_ALLOWED_FLUSH_DRAIN_PERIODS ) + { + stateTimer = getMSTimerCount(); + } + // Couldn't get a good water sample after a couple of trials and the disinfect flush cycle failed + else + { + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_DG_NEW_WAT; + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + } + } + } return state; @@ -685,321 +611,132 @@ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushCirculationState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_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, flushCircWaitTime ) ) { - F32 ThdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 TD1Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_1 ); F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); - F32 avgTemp = ( ThdTemp + TPoTemp + TD1Temp + TD2Temp ) / NUM_OF_TEMP_SENSORS_TO_AVG; - + F32 avgTemp = ( TPoTemp + TD2Temp ) / NUM_OF_TEMP_SENSORS_TO_AVG; + F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); + F32 cpoConductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CPO_SENSOR ); + // Check if any of the temperature sensors deviate for more than the defined value from the average of all // of the temperature sensors - BOOL isThdOut = ( fabs( ThdTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); BOOL isTPoOut = ( fabs( TPoTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); - BOOL isTD1Out = ( fabs( TD1Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); BOOL isTD2Out = ( fabs( TD2Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); - + BOOL isCD2Out = ( cd2Conductivity > MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM ? TRUE : FALSE ); + BOOL isCPoOut = ( cpoConductivity > MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM ? TRUE : FALSE ); // Check if any of the temperature sensors are out of tolerance - if( ( TRUE == isThdOut ) || ( TRUE == isTPoOut ) || ( TRUE == isTD1Out ) || ( TRUE == isTD2Out ) ) + if( ( TRUE == isTPoOut ) || ( TRUE == isTD2Out ) || ( TRUE == isCD2Out ) || ( TRUE == isCPoOut) ) { // Check if we have exceeded the number of trials. If not, try another time - if ( ++stateTrialCounter < MAX_ALLOWED_STATE_TRIALS ) + ++stateTrialCounter; + if ( stateTrialCounter < MAX_ALLOWED_FLUSH_CIRC_PERIODS ) { stateTimer = getMSTimerCount(); + flushCircWaitTime = FLUSH_CICRCULATION_ADDITIONAL_WAIT_TIME_MS; } // State failed. Cancel chemical disinfect mode else + // determine which alarm it is, temperature or conductivity, one of them has to take precedence { - alarmDetectedPendingTrigger = ALARM_ID_DG_TEMP_SENSORS_DIFF_OUT_OF_RANGE; + if ( ( TRUE == isTPoOut ) || ( TRUE == isTD2Out ) ) + { + alarmDetectedPendingTrigger = ALARM_ID_DG_TEMP_SENSORS_DIFF_OUT_OF_RANGE; + } + else + { + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE; //ALARM_ID_DG_NEW_CON; + } prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; } } else - { - areTempSensorsInRange = TRUE; + { // Set the valves for the prime disinfectant state + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + // Set the acid dispense pump speed + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, DISINFECTANT_PUMP_PRIME_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + state = DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT; stateTimer = getMSTimerCount(); - // Set the concentrate pump to run at a constant speed during priming in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, -1.0F * CONC_PUMP_PRIME_SPEED_ML_PER_MIN ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); - } - } - // Only start the concentrate pumps if the temperature sensors are in range - if ( ( TRUE == areTempSensorsInRange ) && ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) ) - { - rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - - // Turn off the concentrate pumps - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); - - setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); - setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); - - // Turn on the bicarb line with forward direction, to dispense the chemical and mix - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMP_PRIME_SPEED_ML_PER_MIN ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); - - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_FLUSH_R1_AND_R2; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectFlushR1AndR2State function handles the - * chemical disinfect flush reservoir 1 and reservoir 2 state. If the - * reservoirs did not flush within a period time, the state transitions - * to water cancellation path. - * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushR1AndR2State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FLUSH_R1_AND_R2; - - // If R1 is not full, keep monitoring for R1 level and timeout - 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 ) - { - prevChemDisinfectState = state; - alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } } - // Once R1 is full, keep monitoring for R2 level and timeout - else if( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); - // Once R2 is full (to 500mL in this case), transition to the next state - if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - // Set the actuators to flush R2 and drain R1 state - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRD1, VALVE_STATE_OPEN ); - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - stateTimer = getMSTimerCount(); - - // Set both reservoirs status - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - state = DG_CHEM_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - return state; } /*********************************************************************//** * @brief - * The handleChemicalDisinfectFlushR2AndDrainR1State function handles the - * chemical disinfect flush reservoir 2 and drain reservoir 1 state. The - * state drains reservoir 1 and flushes reservoir 2 at the same time until - * the water in reservoir 2 overflows to reservoir 1. If this process is - * done within a certain period of time, it transitions to the next state. - * If the drain process times out, it transitions to basic cancellation and - * if the flush process times out, it transitions to water cancellation. - * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status + * The handleChemicalDisinfectPrimeDisinfectantState function handles the + * chemical disinfect prime acid line state. The state primes the acid line + * until a minimum conductivity is sensed for a period of time. The the + * function transitions to another state. If the minimum conductivity was + * not reached within the defined period of time, it transition to a + * cancellation path. + * @details Inputs: stateTimer, primeAcidSteadyStateCounter * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState + * prevChemDisinfectState, primeAcidSteadyStateCounter, chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushR2AndDrainR1State( void ) +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeDisinfectantState( void ) { - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1; + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE; + F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); - // If reservoir 1 is empty, turn off the drain pump - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) - { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); - } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - // Done with draining R1 - signalDrainPumpHardStop(); + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_MIX_WATER_AND_ACID; - setValveState( VRD1, VALVE_STATE_CLOSED ); - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + if ( cd2Conductivity <= MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM ) { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + primeAcidSteadyStateCounter = 0; } - - // First reservoir 2 must be completely full - if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) + else { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - - U32 drainPumpRPM = getDrainPumpTargetRPM(); - // 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 ) ) + // Check if the acid conductivity value has been above the threshold for the specified time period + if ( ++primeAcidSteadyStateCounter >= PRIME_ACID_STEADY_CONDUCTIVITY_TIME_MS ) { - prevChemDisinfectState = state; - alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - // Once R2 is full, R1 must be partially full - else if( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + // Turn off the concentrate pump + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - // Once R1 is partially full, transition to the next state - if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - // Done with filing turn off the RO pump - signalROPumpHardStop(); + // Prepare for filling the reservoirs and heating the water - // Set the valves to drain R2 and no fill - setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); - setValveState( VRD2, VALVE_STATE_OPEN ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - // Start the timer for drain timeout - stateTimer = getMSTimerCount(); - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R2; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - return state; -} + // Turn on the RO pump and concentrate pump + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FILL_DISINECTANT_FLOW_RATE_LPM, MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + + // Start heating the water while we are filling up the reservoirs + setHeaterTargetTemperature( DG_PRIMARY_HEATER, CHEM_DISINFECT_TARGET_TEMPERATURE_C ); + startHeater( DG_PRIMARY_HEATER ); -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectFlushDrainR2State function handles the - * chemical disinfect flush drain reservoir 2 state. The state drains - * reservoir 2 and if the drain times out, it transitions to basic - * cancellation. If the drain is finished within a certain period of time, - * it transitions to the next state. - * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushDrainR2State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R2; - - // If reservoir 2 is empty, set the drain valve to drain R1 - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) - { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + flushDisinfectantWaitTime = FLUSH_DISINFECTANT_INITIAL_WAIT_TIME; + stateTrialCounter = 0; + state = DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT; + stateTimer = getMSTimerCount(); + } } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - setValveState( VRD1, VALVE_STATE_OPEN ); - setValveState( VRD2, VALVE_STATE_CLOSED ); - // Start the timer for drain timeout - stateTimer = getMSTimerCount(); - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R1; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectFlushDrainR1State function handles the - * chemical disinfect flush drain reservoir 1 state. The state drains - * reservoir 1 and if the drain times out, it transitions to basic - * cancellation. If the drain is finished within a certain period of time, - * it transitions to the next state. - * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushDrainR1State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R1; - - // If reservoir 1 is empty, set the state to fill water state - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + if ( TRUE == didTimeout( stateTimer, PRIME_ACID_LINE_TIMEOUT_MS ) ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_PRIME_ACID_LINE_TIME_OUT; } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - // Done with draining the reservoirs - signalDrainPumpHardStop(); - // Set the concentrate pump to run at a constant speed during priming - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMP_PRIME_SPEED_ML_PER_MIN ); - - // The bicarb line is used to inject the acid into the fluid path during chemical disinfect - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); // TODO why do we need to turn off CP2 while we are going to turn it on immediately? - - // Start the timer for drain timeout - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } - return state; } + /*********************************************************************//** * @brief * The handleChemicalDisinfectPrimeAcidLineState function handles the @@ -1013,56 +750,43 @@ * prevChemDisinfectState, primeAcidSteadyStateCounter, chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeAcidLineState( void ) +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantFlushState( void ) { - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE; - F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; // Set the chemical disinfect that is published on the UI chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_MIX_WATER_AND_ACID; - if ( cd2Conductivity <= MIN_ACID_CONDUCTIVITY_US_PER_CM ) + if ( TRUE == didTimeout( stateTimer, flushDisinfectantWaitTime ) ) { - primeAcidSteadyStateCounter = 0; - } - else - { - // Check if the acid conductivity value has been - if ( ++primeAcidSteadyStateCounter >= PRIME_ACID_STEADY_CONDUCTIVITY_TIME_MS ) - { - // Turn off the concentrate pump for now until there is sufficient RO flow to turn it - // back for mixing - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - - // Prepare for filling the reservoirs and heating the water - setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); - setValveState( VRD1, VALVE_STATE_CLOSED ); - setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); - - // Turn on the RO pump - setROPumpTargetFlowRateLPM( 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 reservoirs - setHeaterTargetTemperature( DG_PRIMARY_HEATER, CHEM_DISINFECT_TARGET_TEMPERATURE_C ); - startHeater( DG_PRIMARY_HEATER ); - + CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); + if ( ( CHEM_DISINFECT_HEATER_OUTLET_TEMPERATURE_OUT_OF_RANGE == state ) || + ( CHEM_DISINFECT_DISINFECTANT_CONDUCTIVITY_OUT_OF_RANGE == state ) ) + { + // Check if we have exceeded the number of trials. If not, try another time + ++stateTrialCounter; + if (stateTrialCounter < MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS ) + { + stateTimer = getMSTimerCount(); + flushDisinfectantWaitTime = FLUSH_DISINFECTANT_ADDITIONAL_WAIT_TIME; + } + else + { + // fail, alarm has already been set + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + } + } + else + { + // No changes in valves and pumps for next state rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT; } } - if ( TRUE == didTimeout( stateTimer, PRIME_ACID_LINE_TIMEOUT_MS ) ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_PRIME_ACID_LINE_TIME_OUT; - } - return state; } @@ -1080,28 +804,12 @@ * R1ChemDisinfectVol, R2ChemDisinfectVol, rsrvrsVolMonitorTimer * @return next state of the chemical disinfect state machine *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillWithWaterAndDisinfectantState( void ) +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillWithDisinfectantState( void ) { - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT; - - // Get the flow rate that is used for mixing - F32 measuredROFlowRate = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); - - // If the flow is less than the minimum, request the concentrate pump to be on but do - // control it. - if ( measuredROFlowRate < MIN_RO_FLOW_FOR_CONC_PUMP_MIXING_LPM ) - { - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); - } - else - { - F32 acidCP2PumpFlowRate = ACID_TO_WATER_MIXING_RATIO * measuredROFlowRate * ML_PER_LITER; - - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, acidCP2PumpFlowRate ); - - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); - } - + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; + CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); + static BOOL rsvr2TimerStarted = FALSE; + // First reservoir 1 must be full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { @@ -1110,35 +818,35 @@ // Once reservoir 1 is full, check the status of reservoir 2 since the water overflows to reservoir 2 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + if ( FALSE == rsvr2TimerStarted ) + { + // have to reset timer for reservoir 2 fill + stateTimer = getMSTimerCount(); + rsvr2TimerStarted = TRUE; + } + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - // Once reservoir 2 is full, set the actuators for recirculation + // Once reservoir 2 is full, set the actuators for next state if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - // Set the valves to drain R2 and no fill - setValveState( VPI, VALVE_STATE_CLOSED ); - setValveState( VBF, VALVE_STATE_OPEN ); - setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRD2, VALVE_STATE_OPEN ); - setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); - setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + // Set the valves to drain R1 and fill R2 + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); - // Done with mixing acid - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - - // Set the drain pump to control mode + // Set the drain pump to control mode TODO: change to volume control mode setDrainPumpTargetOutletPressure( CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI ); - setROPumpTargetFlowRateLPM( CHEM_DISINFECT_TARGET_RO_FLOW_LPM, CHEM_DISINFECT_MAX_RO_PRESSURE_PSI ); - // 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 chemical disinfect cycle R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); R2ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); stateTimer = getMSTimerCount(); rsrvrsVolMonitorTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_REMOVE_ACID_BOTTLE_FROM_UI; + isPartialDisinfectInProgress = TRUE; + chemDisinfectTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -1157,32 +865,109 @@ /*********************************************************************//** * @brief - * The handleChemicalDisinfectRemoveAcidBottleFromUIState function - * handles the chemical disinfect remove acid bottle from UI state. - * The state fills sends a command to the UI to prompt the user to remove - * the acid bottle and shut the acid and bicarb line. The state continues - * waiting in this state until the user confirms that the bottle has been - * removed and acid and bicarb lines are closed. - * @details Inputs: TODO fill up - * @details Outputs: chemDisinfectUIState TODO fill up + * The handleChemicalDisinfectR2DisinfectantFillR1DrainState function handles the + * chemical disinfect R1 to R2 state. The state runs reservoir 1 to reservoir 2 + * chemical disinfect. If the reservoirs leak or it cannot reach to temperature + * within a certain period of time, it transitions to water cancellation. + * If chemical disinfect reservoir 1 to reservoir 2 is completed, it + * transitions to the next state. + * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRemoveAcidBottleFromUIState( void ) +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectR2DisinfectantFillR1DrainState( void ) { - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_REMOVE_ACID_BOTTLE_FROM_UI; + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN; + CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); // Set the chemical disinfect that is published on the UI - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_REMOVE_ACID; + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; - // TODO fill up. We should wait for the user until the acid bottle is removed and it is confirmed by the user - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, -1.0F * CONC_PUMP_PRIME_SPEED_ML_PER_MIN ); - state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; + if ( CHEM_DISINFECT_COMPLETE == status) + { + // turn pumps and valves off + stopHeater( DG_PRIMARY_HEATER ); + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + signalROPumpHardStop(); + signalDrainPumpHardStop(); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + + state = DG_CHEM_DISINFECT_STATE_COMPLETE; + } + if ( TRUE == didTimeout( stateTimer, DISINFECT_CYCLE_PERIOD_MS ) ) + { + // go to the next disinfect configuration cycle + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_R1_DISINFECTANT_FILL_R2_DRAIN; + } return state; } /*********************************************************************//** * @brief + * The handleChemicalDisinfectR1DisinfectantFillR2DrainState function handles the + * chemical disinfect R1 to R2 state. The state runs reservoir 1 to reservoir 2 + * chemical disinfect. If the reservoirs leak or it cannot reach to temperature + * within a certain period of time, it transitions to water cancellation. + * If chemical disinfect reservoir 1 to reservoir 2 is completed, it + * transitions to the next state. + * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * chemDisinfectUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectR1DisinfectantFillR2DrainState( void ) +{ + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_R1_DISINFECTANT_FILL_R2_DRAIN; + CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); + + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; + + if ( CHEM_DISINFECT_COMPLETE == status) + { + // turn pumps and valves off + stopHeater( DG_PRIMARY_HEATER ); + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + signalROPumpHardStop(); + signalDrainPumpHardStop(); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + + state = DG_CHEM_DISINFECT_STATE_COMPLETE; + } + if ( TRUE == didTimeout( stateTimer, DISINFECT_CYCLE_PERIOD_MS ) ) + { + // go to the next disinfect configuration cycle + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN; + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleChemicalDisinfectDisinfectR1ToR2State function handles the * chemical disinfect R1 to R2 state. The state runs reservoir 1 to reservoir 2 * chemical disinfect. If the reservoirs leak or it cannot reach to temperature @@ -1206,7 +991,7 @@ { case CHEM_DISINFECT_RSRVRS_LEAK_TIMEOUT: case CHEM_DISINFECT_HEAT_UP_TIMEOUT: - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + break; case CHEM_DISINFECT_COMPLETE: @@ -1248,10 +1033,11 @@ * R2ChemDisinfectVol, prevChemDisinfectState * @return next state of the chemical disinfect state machine *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillR2WithDisinfectantState( void ) +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR1FillR1ToR2State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT; - + CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); + // First reservoir 1 must be partially full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { @@ -1320,434 +1106,56 @@ /*********************************************************************//** * @brief - * The handleChemicalDisinfectCoolDownHeatersState function handles the - * chemical disinfect cool down heaters state. The state continues running - * the fluid while the heaters are off for a certain period of time. - * @details Inputs: stateTimer - * @details Outputs: stateTimer - * @return next state of the heat disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCoolDownHeatersState( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_COOL_DOWN_HEATERS; - - // Done with chemical disinfect, write the data to NV memory - writeDisinfectDataToNV(); - - if ( TRUE == didTimeout( stateTimer, POST_CHEM_DISINFECT_WAIT_TIME_MS ) ) - { - // Stop the drain pump and the RO pump to exit the closed loop - signalDrainPumpHardStop(); - signalROPumpHardStop(); - - if ( 0 == getDrainPumpTargetRPM() ) - { - // De-energize all the valves that are not in the path anymore - // and wait for the RO membrane to be cooled down. - setValveState( VPI, VALVE_STATE_CLOSED ); - setValveState( VBF, VALVE_STATE_CLOSED ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRD1, VALVE_STATE_OPEN ); - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R1; - } - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectDisinfectantDrainR1State function handles - * the chemical disinfect disinfectant drain R1 state. The state drains - * reservoir 1 and if it times out, it transitions to basic cancellation - * state. Otherwise, it transitions to the next state. + * The handleChemicalDisinfectFillR2WithDisinfectantState function + * handles fill R2 with water state. The state transfers disinfectant from + * reservoir 1 to reservoir 2 until disinfectant overflows from reservoir 2 + * to reservoir 1. + * If the fill times out, it transitions to water cancellation state, + * otherwise, it transitions to the next state. * @details Inputs: rsrvr1Status, rsrvr2Status - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState, chemDisinfectUIState + * @details Outputs: rsrvr1Status, rsrvr2Status, R1ChemDisinfectVol, + * R2ChemDisinfectVol, prevChemDisinfectState * @return next state of the chemical disinfect state machine *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantDrainR1State( void ) +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR2FillR1ToR2State( void ) { - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R1; + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT; + CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); - // Set the chemical disinfect that is published on the UI - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; - - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) - { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); - } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - // Done with draining reservoir 1 - setValveState( VRD1, VALVE_STATE_CLOSED ); - // Set the drain valve to reservoir 2 - setValveState( VRD2, VALVE_STATE_OPEN ); - - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R2; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectDisinfectantDrainR1State function handles - * the chemical disinfect disinfectant drain R2 state. The state drains - * reservoir 1 and if it times out, it transitions to basic cancellation - * state. Otherwise, it transitions to the next state. - * @details Inputs: rsrvr1Status, rsrvr2Status - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantDrainR2State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R2; - - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) - { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); - } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - // Done with draining the reservoirs - signalDrainPumpHardStop(); - - // Set the valves to fill up R1 and overflow to R2 - setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); - // Done with draining reservoir 2 - setValveState( VRD2, VALVE_STATE_CLOSED ); - setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); - setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); - - rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectRinseR1ToR2State function handles the chemical - * disinfect rinse R1 to R2 state. The state rinses reservoir 1 to reservoir - * 2. If the rinse process times out, it transitions to water cancellation - * state, otherwise, it transitions to the next state. - * @details Inputs: rsrvr1Status, rsrvr2Status - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState, alarmDetectedPendingTrigger - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseR1ToR2State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2; - + // First reservoir 1 must be partially full 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 ) - { - prevChemDisinfectState = state; - alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); - - if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - // Set the valves to rinse R2 to R1 and drain R1 - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRD1, VALVE_STATE_OPEN ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectRinseR2ToR1AndDrainR1State function handles - * the chemical disinfect rinse R2 to R1 and drain R1 state. The state - * rinses reservoir 2 and drains reservoir 1 at the same time. If the drain - * process times out, it transitions to basic cancellation state, and - * if the rinse times out, it transitions to water cancellation state. - * If the drain and rinse are completed within the define time, it - * transitions to the next state. - * @details Inputs: rsrvr1Status, rsrvr2Status - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState, alarmDetectedPendingTrigger - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseR2ToR1AndDrainR1State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1; - - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) - { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); - } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - // Done with draining R1 - signalDrainPumpHardStop(); - setValveState( VRD1, VALVE_STATE_CLOSED ); - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } - - // First reservoir 2 must be completely full - if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) - { rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - U32 drainPumpRPM = getDrainPumpTargetRPM(); - // 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 ) ) - { - prevChemDisinfectState = state; - alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - // Once reservoir 2 is completely full, monitor reservoir 1 - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); - - if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - // Set the valves to rinse R2 to R1 and drain R1 - setValveState( VRD2, VALVE_STATE_OPEN ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); - - // Turn on the drain pump to drain R2 - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - - // Set the reservoir status - rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2; - stateTimer = getMSTimerCount(); - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectRinseR1ToR2AndDrainR2State function handles - * the chemical disinfect rinse R1 to R2 and drain R2 state. The state - * rinses reservoir 1 and drains reservoir 2 at the same time. If the drain - * process times out, it transitions to basic cancellation state, and - * if the rinse times out, it transitions to water cancellation state. - * If the drain and rinse are completed within the define time, it - * transitions to the next state. - * @details Inputs: rsrvr1Status, rsrvr2Status, numberOfPostDisinfectRinses - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState, alarmDetectedPendingTrigger, isThisLastDrain - * numberOfPostDisinfectRinses - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseR1ToR2AndDrainR2State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2; - - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) - { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); - } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - // Done with draining R2 - signalDrainPumpHardStop(); - setValveState( VRD2, VALVE_STATE_CLOSED ); - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } - - // First reservoir 1 must be completely full - if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) - { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - - U32 drainPumpRPM = getDrainPumpTargetRPM(); - // Keep monitoring the status of reservoir 2 as the same time - F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_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 ) ) - { - prevChemDisinfectState = state; - alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - // Once reservoir 1 is completely full, monitor reservoir 2 - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); - if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - // If the number of post chemical disinfect rinses have finished, - // transition to drain R1 state. Otherwise, start the next rinse. - if ( ++numberOfPostDisinfectRinses >= NUM_OF_POST_DISINFECT_RINSES ) - { - // Done with filling, turn off the RO pump - signalROPumpHardStop(); + // Get the current volumes to be monitored during R2 to R1 chemical disinfect state + R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + R2ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - // Set the rest of the valve to be in the de-enrgize mode - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRD2, VALVE_STATE_OPEN ); - - // Turn on the drain pump to drain R2 - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - - // Set the reservoir status - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - // This is last drain - isThisLastDrain = TRUE; - state = DG_CHEM_DISINFECT_STATE_DRAIN_R2; - } - else - { - // Set the reservoirs' status - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRD1, VALVE_STATE_OPEN ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - state = DG_CHEM_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1; - } - - stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } return state; } /*********************************************************************//** * @brief - * The handleChemicalDisinfectRinseCirculationState function handles the - * chemical disinfect rinse RO circulation and concentrate pumps state. - * Once the defined flush circulation time has elapsed, it transitions to - * the next state. - * @details Inputs: stateTimer - * @details Outputs: none - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseCirculationState( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_RINSE_CIRCULATION; - - if ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) - { - state = DG_CHEM_DISINFECT_STATE_COMPLETE; - } - - return state; -} - -/*********************************************************************//** - * @brief * The handleChemicalDisinfectCancelModeBasicPathState function handles the * chemical disinfect cancel mode basic path state. The state sets the state * to complete and raises an alarm. @@ -1992,10 +1400,14 @@ CHEM_DISINFECT_STATUS_T status = CHEM_DISINFECT_IN_PROGRESS; // Update the variables - F32 ThdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); + F32 TdiTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); BOOL isR1OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1ChemDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; BOOL isR2OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) - R2ChemDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; - + F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); + F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); + BOOL isCD2OutofRange = ( cd2Conductivity < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM || cd2Conductivity > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ); + BOOL isTD2OutofRange = ( TD2Temp < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM || TD2Temp > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ); + // Check if either reservoir 1 or reservoir 2 are losing volume more than allowed volume if ( ( TRUE == isR1OutOfRange ) || ( TRUE == isR2OutOfRange ) ) { @@ -2011,6 +1423,7 @@ areRsrvrsLeaking = FALSE; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; status = CHEM_DISINFECT_RSRVRS_LEAK_TIMEOUT; + } } // Reservoirs are in range @@ -2019,22 +1432,38 @@ areRsrvrsLeaking = FALSE; } + // For the following checks, if multiple failures occur at the same time, the last one will take precedence + // Check if the acid conductivity and temperature are within range + if ( TRUE == isCD2OutofRange ) + { + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE; //ALARM_ID_DG_NEW_CON; + status = CHEM_DISINFECT_DISINFECTANT_CONDUCTIVITY_OUT_OF_RANGE; + } + if ( ( TRUE == isTD2OutofRange ) ) + { + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; + status = CHEM_DISINFECT_HEATER_OUTLET_TEMPERATURE_OUT_OF_RANGE; + } + // If the coldest spot which is THd is less than minimum chemical disinfect temperature, // reset the chemical disinfect timers and check whether heating up has timed out - if ( ThdTemp < CHEM_DISINFECT_TARGET_TEMPERATURE_C ) + if ( TdiTemp < CHEM_DISINFECT_TARGET_TEMPERATURE_C ) { - // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts - chemDisinfectTimer = getMSTimerCount(); - isPartialDisinfectInProgress = FALSE; - - if ( TRUE == didTimeout( stateTimer, CHEM_DISINFECT_START_TEMP_TIMOUT_MS ) ) + if ( TRUE == didTimeout( stateTimer, CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ) ) { // Heating up to minimum temperature for chemical disinfect failed alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; status = CHEM_DISINFECT_HEAT_UP_TIMEOUT; } + else + { + // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts + chemDisinfectTimer = getMSTimerCount(); + isPartialDisinfectInProgress = FALSE; + status = CHEM_DISINFECT_DISINFECT_TEMPERATURE_LOW; + } } - else if ( ( isPartialDisinfectInProgress != TRUE ) && ( ThdTemp > CHEM_DISINFECT_TARGET_TEMPERATURE_C ) ) + else if ( ( isPartialDisinfectInProgress != TRUE ) && ( TdiTemp >= CHEM_DISINFECT_TARGET_TEMPERATURE_C ) ) { // The temperature of the coldest spot is in range to start the disinfect timer chemDisinfectTimer = getMSTimerCount(); @@ -2088,8 +1517,8 @@ data.R2FillLevel = 0.0; } - data.postDisinfectTargetRinseCount = NUM_OF_POST_DISINFECT_RINSES; - data.postDisinfectCurrentRinseCount = numberOfPostDisinfectRinses; + data.postDisinfectTargetRinseCount = 0; + data.postDisinfectCurrentRinseCount = 0; data.chemDisinfectUIState = chemDisinfectUIState; // General data publish channel @@ -2114,65 +1543,83 @@ *************************************************************************/ static void monitorModeChemicalDisinfect( void ) { - BOOL isAlarmNeeded = FALSE; - switch( chemDisinfectState ) - { - case DG_CHEM_DISINFECT_STATE_START: - case DG_CHEM_DISINFECT_STATE_DRAIN_R1: - case DG_CHEM_DISINFECT_STATE_DRAIN_R2: - case DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN: - case DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION: - case DG_CHEM_DISINFECT_STATE_FLUSH_R1_AND_R2: - case DG_CHEM_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1: - case DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R2: - case DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R1: - if ( ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) - { - isAlarmNeeded = TRUE; - } - break; - - case DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE: - case DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT: - if ( ( STATE_CLOSED == getSwitchStatus( CONCENTRATE_CAP ) ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) - { - isAlarmNeeded = TRUE; - } - break; - - case DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2: - case DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT: - case DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1: - case DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R1: - case DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R2: - case DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2: - case DG_CHEM_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1: - case DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2: - case DG_CHEM_DISINFECT_STATE_RINSE_CIRCULATION: - case DG_CHEM_DISINFECT_STATE_COMPLETE: - if ( ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) - { - isAlarmNeeded = TRUE; - } - break; - } - + BOOL hasConductivityFailed = TRUE; + #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) #endif { - if ( TRUE == isAlarmNeeded ) + // If either the dialysate cap or the concentrate cap is open during any state, alarm + if ( ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) { + // Set the variables to fail and go to cancel water path. Set the pending alarm to no alarm so the cancel water path // will not be raising the alarm at end of the cancel water path. The recoverable alarm is raised here in this function U32 ConcCap = (U32)getSwitchStatus( CONCENTRATE_CAP ); U32 DialysateCap = (U32)getSwitchStatus( DIALYSATE_CAP ); prevChemDisinfectState = chemDisinfectState; - chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_OR_CONC_CAP_NOT_IN_PROPER_POSITION; - } + } } + + // In all states, check inlet temperature, inlet pressure, and inlet conductivity. + haveInletWaterChecksPassed= TRUE; + hasConductivityFailed = ( ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) >= MAX_INLET_CONDUCTIVITY_US_PER_CM ) || + ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) <= MIN_INLET_CONDUCTIVITY_US_PER_CM ) ); +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + { + hasConductivityFailed = FALSE; + } +#endif + if ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) < MIN_INLET_TEMPERATURE_C || + hasConductivityFailed || + getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ) < MIN_INLET_PRESSURE_PSI) + { + // Inlet check failed, set timer if not already set + if ( 0 == inletWaterChecksFailTimer ) + { + inletWaterChecksFailTimer = getMSTimerCount(); + } + haveInletWaterChecksPassed= FALSE; // set flag for flush drain state + if ( TRUE == didTimeout( inletWaterChecksFailTimer, INLET_WATER_CHECK_FAILURE_TIMEOUT_MS ) ) + { + // alarm unless in the start, drain, or flush drain states + switch( chemDisinfectState ) + { + case DG_CHEM_DISINFECT_STATE_START: + case DG_CHEM_DISINFECT_STATE_DRAIN_R1: + case DG_CHEM_DISINFECT_STATE_DRAIN_R2: + case DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN: + break; + + case DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION: + case DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT: + case DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH: + prevChemDisinfectState = chemDisinfectState; + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_NEW_WAT; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + break; + case DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT: + case DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2: + case DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R1_FILL_R2_TO_R1: + case DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1: + case DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R2_FILL_R1_TO_R2: + prevChemDisinfectState = chemDisinfectState; + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_NEW_WAT; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + break; + } + } + } + else + { + // reset water check fail timer + inletWaterChecksFailTimer = 0; + } + } /*********************************************************************//**