Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -rc0700a4503f28288f16070634bb87f4eccb2568c -r8a4182663ef6b12e3fd6414c0c14158943cd4ce1 --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision c0700a4503f28288f16070634bb87f4eccb2568c) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 8a4182663ef6b12e3fd6414c0c14158943cd4ce1) @@ -15,6 +15,7 @@ * ***************************************************************************/ +#include "ConcentratePumps.h" #include "ConductivitySensors.h" #include "DrainPump.h" #include "Heaters.h" @@ -49,7 +50,7 @@ #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 2100 ///< 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. @@ -77,18 +78,29 @@ #define CHEM_DISINFECT_TARGET_RO_FLOW_LPM 0.9 ///< Chemical disinfect target RO flow rate in L/min. TODO original value was 0.8 #define CHEM_DISINFECT_MAX_RO_PRESSURE_PSI 130 ///< Chemical disinfect maximum RO pressure in psi. #define CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI 10.0 ///< Chemical disinfect target drain outlet pressure in psi. -#define CHEM_DISINFECT_TIME_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect time for each section in milliseconds. TODO original time was 10 minutes +#define CHEM_DISINFECT_TIME_MS ( 20 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect time for each section in milliseconds. TODO original time was 10 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. 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 chemical 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 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.0 ///< Concentrate pump prime speed in ml/min. +#define MIN_ACID_CONDUCTIVITY_US_PER_CM 2000.0 ///< 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. + +// Fill with disinfectant and water +#define MIN_RO_FLOW_FOR_CONC_PUMP_MIXING_LPM 0.3 ///< Minimum RO flow rate that is need to be able to turn on the concentrate pump for mixing. + // Fill heat up #define CHEM_DISINFECT_TARGET_TEMPERATURE_C 21.0 ///< Chemical disinfect target water temperature in C. // Post disinfect rinses #define NUM_OF_POST_DISINFECT_RINSES 1 ///< Number of rinses after a chemical disinfect. +static const F32 ACID_TO_WATER_MIXING_RATIO = ( 1.0 / 70.0 ); ///< Acid to water mixing ratio for chemical disinfect. + /// Cancellation paths typedef enum Cancellation_modes { @@ -113,6 +125,7 @@ static DG_CHEM_DISINFECT_STATE_T chemDisinfectState = DG_CHEM_DISINFECT_STATE_START; ///< Currently active chemical disinfect state. static DG_CHEM_DISINFECT_STATE_T prevChemDisinfectState = DG_CHEM_DISINFECT_STATE_START; ///< Previous active heat disinfect state before alarm. +static DG_CHEM_DISINFECT_UI_STATE_T chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_START; ///< Currently active chemical disinfect UI state. static U32 overallChemDisinfectTimer = 0; ///< Chemical disinfect cycle total timer. static U32 stateTimer = 0; ///< Chemical disinfect state timer to be used in different states. static U32 stateTrialCounter = 0; ///< Chemical disinfect state trial counter to be used for retries in different states. @@ -132,6 +145,7 @@ static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Chemical disinfect alarm to raise. static U32 numberOfPostDisinfectRinses = NUM_OF_POST_DISINFECT_RINSES; ///< Number of times to rinse the fluid path after chemical disinfect. +static U32 primeAcidSteadyStateCounter = 0; // ********** private function prototypes ********** @@ -144,7 +158,9 @@ 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 handleChemicalDisinfectDisinfectR1ToR2State( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillR2WithDisinfectantState( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR2ToR1State( void ); @@ -174,7 +190,8 @@ * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, * R1ChemDisinfectVol, R2ChemDisinfectVol, overallChemDisinfectTimer, * cancellationMode, rsrvrFillStableTimeCounter, prevChemDisinfectState - * isPartialDisinfectInProgress, numberOfPostDisinfectRinses + * isPartialDisinfectInProgress, numberOfPostDisinfectRinses, + * primeAcidSteadyStateCounter, chemDisinfectUIState * @return none *************************************************************************/ void initChemicalDisinfectMode( void ) @@ -194,6 +211,8 @@ rsrvrFillStableTimeCounter = 0; isPartialDisinfectInProgress = FALSE; numberOfPostDisinfectRinses = NUM_OF_POST_DISINFECT_RINSES; + primeAcidSteadyStateCounter = 0; + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_START; } /*********************************************************************//** @@ -259,10 +278,18 @@ chemDisinfectState = handleChemicalDisinfectFlushDrainR1State(); break; + case DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE: + chemDisinfectState = handleChemicalDisinfectPrimeAcidLineState(); + break; + 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; @@ -378,13 +405,16 @@ * @details Inputs: alarm, rsrvrFillStableTimeCounter, rsrvr1Status, * stateTimer * @details Outputs: alarm, rsrvrFillStableTimeCounter, rsrvr1Status, - * stateTimer + * stateTimer, chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectStartState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_START; + // Start overall chemical disinfect timer overallChemDisinfectTimer = getMSTimerCount(); @@ -413,13 +443,8 @@ // Request a tare for reservoir 1 tareReservoir(); -#ifndef V_2_SYSTEM // Set the actuators to drain R1 setValveState( VRD1, VALVE_STATE_OPEN ); -#else - // Set the actuators to drain R1 - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); rsrvrFillStableTimeCounter = 0; @@ -438,13 +463,17 @@ * transition is finished within the time, it transitions to the next state, * otherwise, it transitions to basic cancellation path. * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, isThisLastDrain - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDrainR1State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT; + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); @@ -453,18 +482,18 @@ { 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; + // Done with draining signalDrainPumpHardStop(); // Set the valves to flush the recirculation line setValveState( VPI, VALVE_STATE_OPEN ); -#ifndef V_2_SYSTEM setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); // Done with draining R1 setValveState( VRD1, VALVE_STATE_CLOSED ); -#else - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); -#endif setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); @@ -486,13 +515,9 @@ // Request a tare for reservoir 2 tareReservoir(); -#ifndef V_2_SYSTEM + // Done with draining R1 + setValveState( VRD1, VALVE_STATE_CLOSED ); setValveState( VRD2, VALVE_STATE_OPEN ); -#else - // Set the actuators to drain R2. - // NOTE: Drain pump is already on and VDr is already on drain state - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); -#endif state = DG_CHEM_DISINFECT_STATE_DRAIN_R2; } @@ -516,7 +541,8 @@ * state, otherwise, it transitions to basic cancellation path. * @details Inputs: stateTimer, rsrvr2Status, isThisLastDrain, * stateTrialCounter - * @details Outputs: stateTimer, rsrvr2Status, stateTrialCounter + * @details Outputs: stateTimer, rsrvr2Status, stateTrialCounter, + * chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDrainR2State( void ) @@ -531,21 +557,19 @@ { if ( TRUE == isThisLastDrain ) { -#ifndef V_2_SYSTEM + // 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 ); setValveState( VRD2, VALVE_STATE_CLOSED ); -#else - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; } else { signalDrainPumpHardStop(); -#ifndef V_2_SYSTEM setValveState( VRD2, VALVE_STATE_CLOSED ); -#endif setValveState( VPI, VALVE_STATE_OPEN ); stateTrialCounter = 0; stateTimer = getMSTimerCount(); @@ -585,11 +609,7 @@ if ( ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MIN_INLET_TEMPERATURE_C ) && ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) <= MAX_INLET_CONDUCTIVITY_US_PER_CM ) ) { -#ifndef V_2_SYSTEM setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); -#else - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); -#endif setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); stateTimer = getMSTimerCount(); stateTrialCounter = 0; @@ -737,11 +757,7 @@ setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); -#ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_OPEN ); -#else - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); stateTimer = getMSTimerCount(); @@ -792,6 +808,8 @@ { // Done with draining R1 signalDrainPumpHardStop(); + + setValveState( VRD1, VALVE_STATE_CLOSED ); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -832,14 +850,8 @@ // Set the valves to drain R2 and no fill setValveState( VPI, VALVE_STATE_CLOSED ); -#ifndef V_2_SYSTEM setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); - setValveState( VRD1, VALVE_STATE_CLOSED ); setValveState( VRD2, VALVE_STATE_OPEN ); -#else - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); -#endif setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); @@ -886,11 +898,8 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { -#ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_OPEN ); -#else - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif + setValveState( VRD2, VALVE_STATE_CLOSED ); // Start the timer for drain timeout stateTimer = getMSTimerCount(); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; @@ -931,34 +940,15 @@ // Done with draining the reservoirs signalDrainPumpHardStop(); - // Prepare for filling the reservoirs and heating the water - setValveState( VPI, VALVE_STATE_OPEN ); -#ifndef V_2_SYSTEM - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); - setValveState( VRD1, VALVE_STATE_CLOSED ); - setValveState( VRD2, VALVE_STATE_CLOSED ); -#else - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); -#endif - 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 ); + // The bicarb line is used to inject the acid into the fluid path during chemical disinfect + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); - // Turn on the RO pump - setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + // Set the concentrate pump to run at a constant speed during priming + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMP_PRIME_SPEED_ML_PER_MIN ); - // Start heating the water while we are filling up the rsrvrs - setPrimaryHeaterTargetTemperature( CHEM_DISINFECT_TARGET_TEMPERATURE_C ); - startPrimaryHeater(); - - rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - // Start the timer for drain timeout stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT; + state = DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -971,21 +961,103 @@ /*********************************************************************//** * @brief + * The handleChemicalDisinfectPrimeAcidLineState 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, primeAcidSteadyStateCounter, chemDisinfectUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeAcidLineState( void ) +{ + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE; + + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_MIX_WATER_AND_ACID; + + F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); + + if ( cd2Conductivity <= MIN_ACID_CONDUCTIVITY_US_PER_CM ) + { + primeAcidSteadyStateCounter = 0; + } + else if ( cd2Conductivity > MIN_ACID_CONDUCTIVITY_US_PER_CM ) + { + // 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 + requestConcentratePumpsOff( 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 + 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 reservoirs + setPrimaryHeaterTargetTemperature( CHEM_DISINFECT_TARGET_TEMPERATURE_C ); + startPrimaryHeater(); + + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + + state = DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT; + } + } + else if ( TRUE == didTimeout( stateTimer, PRIME_ACID_LINE_TIMEOUT_MS ) ) + { + // TODO transition to cancellation path + prevChemDisinfectState = state; + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleChemicalDisinfectFillWithWaterAndDisinfectantState function * handles the chemical disinfect fill with water state. The state fills * reservoir 1 until it overflows to reservoir 2. If the filling process * times out, it transitions to water cancellation state, otherwise, it * transitions to next state. The levels of the reservoirs are recorded to * be monitored during chemical disinfect. - * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, rsrvrsVolMonitorTimer - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, R1ChemDisinfectVol - * R2ChemDisinfectVol, rsrvrsVolMonitorTimer + * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, + * rsrvrsVolMonitorTimer + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * R1ChemDisinfectVol, R2ChemDisinfectVol, rsrvrsVolMonitorTimer * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillWithWaterAndDisinfectantState( 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 = getMeasuredROFlowRate(); + + // 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 ) + { + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); + } + else + { + F32 acidCP2PumpFlowRate = ACID_TO_WATER_MIXING_RATIO * measuredROFlowRate * ML_PER_LITER; + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, acidCP2PumpFlowRate ); + } + // First reservoir 1 must be full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { @@ -1002,15 +1074,14 @@ // Set the valves to drain R2 and no fill setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_OPEN ); -#ifndef V_2_SYSTEM setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRD2, VALVE_STATE_OPEN ); -#else - setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); -#endif setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + // Done with mixing acid + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); + // Set the drain pump to control mode setDrainPumpTargetOutletPressure( CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI ); @@ -1023,7 +1094,7 @@ stateTimer = getMSTimerCount(); rsrvrsVolMonitorTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; + state = DG_CHEM_DISINFECT_STATE_REMOVE_ACID_BOTTLE_FROM_UI; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -1042,21 +1113,50 @@ /*********************************************************************//** * @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 + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRemoveAcidBottleFromUIState( void ) +{ + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_REMOVE_ACID_BOTTLE_FROM_UI; + + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_REMOVE_ACID; + + // TODO fill up. We should wait for the user until the acid bottle is removed and it is confirmed by the user + state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; + + 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 * 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 + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR1ToR2State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; + switch ( status ) { case CHEM_DISINFECT_RSRVRS_LEAK_TIMEOUT: @@ -1068,12 +1168,8 @@ //TODO turn off CP1 and CP2 // Set the valves to transfer hot water from R1 to R2 and fill up R2. setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); -#ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_OPEN ); setValveState( VRD2, VALVE_STATE_CLOSED ); -#else - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); // Although there is fluid in both reservoirs, but they are set to empty @@ -1128,21 +1224,17 @@ state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; } -#ifdef IGNORE_DISINFECT_RSRVR_TIMEOUT else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } -#endif } -#ifdef IGNORE_DISINFECT_RSRVR_TIMEOUT else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } -#endif return state; } @@ -1207,13 +1299,10 @@ // and wait for the RO membrane to be cooled down. setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_CLOSED ); -#ifndef V_2_SYSTEM + 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 ); -#else - setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); stateTimer = getMSTimerCount(); @@ -1232,28 +1321,26 @@ * state. Otherwise, it transitions to the next state. * @details Inputs: rsrvr1Status, rsrvr2Status * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState + * prevChemDisinfectState, chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantDrainR1State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R1; + // 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 ) { -#ifndef V_2_SYSTEM // Done with draining reservoir 1 setValveState( VRD1, VALVE_STATE_CLOSED ); // Set the drain valve to reservoir 2 setValveState( VRD2, VALVE_STATE_OPEN ); -#else - // Set the drain valve to reservoir 2 - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); -#endif rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R2; @@ -1293,16 +1380,10 @@ // Set the valves to fill up R1 and overflow to R2 setValveState( VPI, VALVE_STATE_OPEN ); -#ifndef V_2_SYSTEM setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); // Done with draining reservoir 2 setValveState( VRD2, VALVE_STATE_CLOSED ); -#else - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); -#endif setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); @@ -1363,11 +1444,7 @@ // 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 ); -#ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_OPEN ); -#else - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); @@ -1417,9 +1494,7 @@ { // Done with draining R1 signalDrainPumpHardStop(); -#ifndef V_2_SYSTEM - setValveState( VRD1, VALVE_STATE_CLOSED ); -#endif + setValveState( VRD1, VALVE_STATE_CLOSED ); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -1454,15 +1529,8 @@ if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - // Done with filling, turn off the RO pump - signalROPumpHardStop(); - // Set the valves to rinse R2 to R1 and drain R1 -#ifndef V_2_SYSTEM setValveState( VRD2, VALVE_STATE_OPEN ); -#else - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); -#endif setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); @@ -1471,6 +1539,7 @@ 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(); @@ -1517,9 +1586,7 @@ { // Done with draining R2 signalDrainPumpHardStop(); -#ifndef V_2_SYSTEM setValveState( VRD2, VALVE_STATE_CLOSED ); -#endif } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -1530,7 +1597,7 @@ // First reservoir 1 must be completely full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); U32 drainPumpRPM = getTargetDrainPumpRPM(); // Keep monitoring the status of reservoir 2 as the same time @@ -1548,7 +1615,7 @@ } } // Once reservoir 1 is completely full, monitor reservoir 2 - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); @@ -1557,11 +1624,7 @@ // Done with filling, turn off the RO pump signalROPumpHardStop(); -#ifndef V_2_SYSTEM setValveState( VRD2, VALVE_STATE_OPEN ); -#else - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); -#endif // Turn on the drain pump to drain R2 setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); @@ -1570,49 +1633,183 @@ if ( ++numberOfPostDisinfectRinses > NUM_OF_POST_DISINFECT_RINSES ) { // Set the reservoir status - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; // This is last drain isThisLastDrain = TRUE; - state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + state = DG_CHEM_DISINFECT_STATE_DRAIN_R2; } else { - // Set the reservoir status - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2; + // 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(); } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + 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 == rsrvr2Status ) + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevChemDisinfectState = state; 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. + * @details Inputs: none + * @details Outputs: cancellationMode, chemDisinfectUIState + * @return next state of the heat disinfect state machine + *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeBasicPathState( void ) { + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_CANCEL_DISINFECT; + + // Set the cancellation mode + cancellationMode = CANCELLATION_MODE_BASIC; + + failChemicalDisinfect(); + + return state; } + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectCancelModeWaterPathState function handles the + * chemical disinfect cancel mode cold water path state. The state resets all + * the actuators. + * TODO fill up as the state goes + * @details Inputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer + * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer, + * chemDisinfectUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeWaterPathState( void ) { + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_CANCEL_DISINFECT; + + if ( CANCELLATION_MODE_NONE == cancellationMode ) + { + // Stop all the actuators first then decide who should run next + deenergizeActuators(); + + cancellationMode = CANCELLATION_MODE_WATER; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + + // The drain is set to start from reservoir 2 + setValveState( VRD2, VALVE_STATE_OPEN ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Start the timer for drain timeout + stateTimer = getMSTimerCount(); + } + + // If reservoir 2 is empty, set to drain reservoir 1 + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // Set the drain valve to reservoir 1 + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + } + } + // Could not drain reservoir 2. Transition to basic cancellation path + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + } + + // If reservoir 2 has already been drained and reservoir 1 is empty, reset and switch to complete + if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + failChemicalDisinfect(); + } + // Could not drain reservoir 1. Transition to basic cancellation path + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + } + } + + return state; } + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectCompleteState function handles the chemical + * disinfect complete state. The state stops chemical disinfect and + * requests transition to mode standby. + * @details Inputs: none + * @details Outputs: chemDisinfectUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCompleteState( void ) { + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_COMPLETE; + // Set the chemical disinfect that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_COMPLETE; + + stopChemicalDisinfect(); + + return state; } /*********************************************************************//** @@ -1806,30 +2003,38 @@ if ( ++dataPublishCounter > CHEM_DISINFECT_DATA_PUB_INTERVAL ) { MODE_CHEMICAL_DISINFECT_DATA_T data; + MODE_CHEMICAL_DISINFECT_UI_DATA_T uiData; data.chemDisinfectState = (U32)chemDisinfectState; data.overallElapsedTime = calcTimeSince( overallChemDisinfectTimer ); data.stateElapsedTime = calcTimeSince( stateTimer ); data.cancellationMode = (U32)cancellationMode; - data.R1FillLevel = R1ChemDisinfectVol; - data.R2FillLevel = R2ChemDisinfectVol; // If the mode is in the actual chemical disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion if ( ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) || ( DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 == chemDisinfectState ) ) { - data.chemDisinfectElapsedTime = calcTimeSince( chemDisinfectTimer ); + uiData.chemDisinfectElapsedTime = calcTimeSince( chemDisinfectTimer ); + data.R1FillLevel = R1ChemDisinfectVol; + data.R2FillLevel = R2ChemDisinfectVol; } else { - data.chemDisinfectElapsedTime = 0; + uiData.chemDisinfectElapsedTime = 0.0; + data.R1FillLevel = 0.0; + data.R2FillLevel = 0.0; } - data.postDisinfectTargetRinseCount = NUM_OF_POST_DISINFECT_RINSES; + data.postDisinfectTargetRinseCount = NUM_OF_POST_DISINFECT_RINSES; data.postDisinfectCurrentRinseCount = numberOfPostDisinfectRinses; + data.chemDisinfectUIState = chemDisinfectUIState; + // General data publish channel broadcastChemicalDisinfectData( &data ); + // Data publish channel to UI + broadcastChemicalDisinfectData2UI( &uiData ); + dataPublishCounter = 0; } }