Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r86eec09ab556fbd970ddcae9dc622727928ee757 -r379f78f1fad668d741b3ccf1e78c69f3fccc45b5 --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 86eec09ab556fbd970ddcae9dc622727928ee757) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 379f78f1fad668d741b3ccf1e78c69f3fccc45b5) @@ -75,25 +75,17 @@ // R1 to R2 & R2 to R1 chemical disinfect circulation #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 30 ///< Chemical disinfect maximum RO pressure in psi. +#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 ( 5 * 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. // Fill and heat up #define CHEM_DISINFECT_TARGET_TEMPERATURE_C 21.0 ///< Chemical disinfect target water temperature in C. -// R1 to R2 & R2 to R1 chemical disinfect circulation -#define CHEM_DISINFECT_TARGET_RO_FLOW_LPM 0.9 ///< 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 10.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 is 36 minutes -#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. - /// Cancellation paths typedef enum Cancellation_modes { @@ -107,10 +99,11 @@ /// Chemical disinfect status typedef enum Chemical_disinfect_status { - CHEMICAL_DISINFECT_IN_PROGRESS = 0, ///< Chemical disinfect in progress. - CHEMICAL_DISINFECT_RSRVRS_LEAK_TIMEOUT, ///< Chemical disinfect reservoirs leak timeout. - CHEMICAL_DISINFECT_COMPLETE, ///< Chemical disinfect complete. - NUM_OF_CHEMICAL_DISINFECT_STATUS ///< Number of chemical disinfect status. + 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_COMPLETE, ///< Chemical disinfect complete. + NUM_OF_CHEM_DISINFECT_STATUS ///< Number of chemical disinfect status. } CHEM_DISINFECT_STATUS_T; // ********** private data ********** @@ -135,7 +128,6 @@ static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Chemical disinfect alarm to raise. -static BOOL isDrainPumpInMixDrainOn = FALSE; ///< Flag to show the drain pump is on during mix drain. // ********** private function prototypes ********** @@ -153,11 +145,11 @@ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillR2WithDisinfectantState( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR2ToR1State( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCoolDownHeatersState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCoolDownROFilterState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectMixDrainR1State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectMixDrainR2State( 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 ); @@ -178,7 +170,7 @@ * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, * R1ChemDisinfectVol, R2ChemDisinfectVol, overallChemDisinfectTimer, * cancellationMode, rsrvrFillStableTimeCounter, prevChemDisinfectState - * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain + * isPartialDisinfectInProgress * @return none *************************************************************************/ void initChemicalDisinfectMode( void ) @@ -197,7 +189,6 @@ cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillStableTimeCounter = 0; isPartialDisinfectInProgress = FALSE; - isDrainPumpInMixDrainOn = FALSE; } /*********************************************************************//** @@ -272,36 +263,51 @@ break; case DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT: + chemDisinfectState = handleChemicalDisinfectFillR2WithDisinfectantState(); break; case DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1: + chemDisinfectState = handleChemicalDisinfectDisinfectR2ToR1State(); break; + case DG_CHEM_DISINFECT_STATE_COOL_DOWN_HEATERS: + chemDisinfectState = handleChemicalDisinfectCoolDownHeatersState(); + 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; case DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH: + chemDisinfectState = handleChemicalDisinfectCancelModeWaterPathState(); break; case DG_CHEM_DISINFECT_STATE_COMPLETE: + chemDisinfectState = handleChemicalDisinfectCompleteState(); break; default: @@ -372,7 +378,7 @@ *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectStartState( void ) { - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_START; + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; // Start overall chemical disinfect timer overallChemDisinfectTimer = getMSTimerCount(); @@ -402,8 +408,13 @@ // 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; @@ -442,7 +453,13 @@ // 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 ); @@ -464,9 +481,13 @@ // Request a tare for reservoir 2 tareReservoir(); +#ifndef V_2_SYSTEM + 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; } @@ -505,13 +526,21 @@ { if ( TRUE == isThisLastDrain ) { +#ifndef V_2_SYSTEM + 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(); @@ -551,11 +580,15 @@ 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; - state = DG_CHEM_DISINFECT_STATE_RINSE_CIRCULATION; + 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 ) @@ -699,7 +732,11 @@ 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(); @@ -790,10 +827,16 @@ // 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 ); - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); // Start the timer for drain timeout stateTimer = getMSTimerCount(); @@ -838,7 +881,11 @@ } 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 // Start the timer for drain timeout stateTimer = getMSTimerCount(); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; @@ -881,12 +928,18 @@ // 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 ); - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); // Turn on the RO pump setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); @@ -944,7 +997,12 @@ // 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 ); @@ -996,21 +1054,25 @@ switch ( status ) { - case CHEMICAL_DISINFECT_IN_PROGRESS: - case CHEMICAL_DISINFECT_RSRVRS_LEAK_TIMEOUT: + case CHEM_DISINFECT_RSRVRS_LEAK_TIMEOUT: + case CHEM_DISINFECT_HEAT_UP_TIMEOUT: state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; break; - case CHEMICAL_DISINFECT_COMPLETE: - + case CHEM_DISINFECT_COMPLETE: //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 - // to begin the transition of hot water from R1 to R2. + // to begin the transition of disinfectant water from R1 to R2. rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; stateTimer = getMSTimerCount(); @@ -1025,17 +1087,418 @@ return state; } +/*********************************************************************//** + * @brief + * 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: rsrvr1Status, rsrvr2Status, R1ChemDisinfectVol, + * R2ChemDisinfectVol, prevChemDisinfectState + * @return next state of the chemical disinfect state machine + *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillR2WithDisinfectantState( void ) { + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT; + // First reservoir 1 must be partially full + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) + { + 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_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // 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 ); + + //TODO turn on CP1 and CP2 + + 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; } + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectDisinfectR2ToR1State function handles the + * chemical disinfect R2 to R1 state. If the reservoirs leak or it cannot + * reach to temperature within a certain period of time, it transitions to + * water cancellation state. If heat disinfect reservoir 1 to reservoir 2 is + * completed, it transitions to the next state. + * @details Inputs: stateTimer, rsrvr1Status + * @details Outputs: stateTimer, rsrvr1Status + * @return next state of the heat disinfect state machine + *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR2ToR1State( void ) { + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; + CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); + switch ( status ) + { + 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: + // Turn off the heaters + // TODO turn off CP1 and CP2 + stopPrimaryHeater(); + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_COOL_DOWN_HEATERS; + break; + } + + return state; } /*********************************************************************//** * @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; + + 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(); + + // 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 ); +#ifndef V_2_SYSTEM + 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 + 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. + * @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 handleChemicalDisinfectDisinfectantDrainR1State( void ) +{ + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_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 ) + { +#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; + } + 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 ); +#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 ); + setROPumpTargetFlowRate( 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; + + 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_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } + } + 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 ); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_R1_C_TO_NC ); +#else + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); +#endif + 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; +} + + +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(); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_CLOSED ); +#endif + } + 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 = getTargetDrainPumpRPM(); + // Keep monitoring the status of reservoir 1 as the same time + F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + // Reservoir 1 cannot be filled before reservoir 2 is filled and is overflowing to reservoir 1. If reservoir 1 has already + // reached to target volume, it means reservoir 2's load cell might be reading incorrect values. This situation might continue + // until reservoir 1 is filled up and the tubing might expand or leak. + // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make + // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL + if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + { + 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 ) + { + // Done with filling, turn off the RO pump + signalROPumpHardStop(); + + // De-energize all the valves and set the VDr to drain R2 + setValveState( VPI, VALVE_STATE_CLOSED ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); +#else + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); +#endif + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); +#ifndef V_2_SYSTEM + setValveState( VRD2, VALVE_STATE_OPEN ); +#else + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); +#endif + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + + // Turn on the drain pump to drain R2 + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // This is the last drain of heat disinfect cycle + isThisLastDrain = TRUE; + stateTimer = getMSTimerCount(); + // Set the reservoir status + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_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; +} +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 ) +{ + +} + +/*********************************************************************//** + * @brief * The failChemicalDisinfect function sets the alarm that failed the * chemical disinfect mode. * @details Inputs: alarmDetectedPendingTrigger, prevChemDisinfectState @@ -1066,7 +1529,7 @@ if ( r == DG_RESERVOIR_1 ) { - volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ); //TODO change back to primary + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else if ( r == DG_RESERVOIR_2 ) { @@ -1149,8 +1612,10 @@ *************************************************************************/ static CHEM_DISINFECT_STATUS_T getChemicalDisinfectStatus( void ) { - CHEM_DISINFECT_STATUS_T status = CHEMICAL_DISINFECT_IN_PROGRESS; + CHEM_DISINFECT_STATUS_T status = CHEM_DISINFECT_IN_PROGRESS; + F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODO change this to actual THd sensor later + 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; @@ -1168,7 +1633,7 @@ { areRsrvrsLeaking = FALSE; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; - status = CHEMICAL_DISINFECT_RSRVRS_LEAK_TIMEOUT; + status = CHEM_DISINFECT_RSRVRS_LEAK_TIMEOUT; } } // Reservoirs are in range @@ -1177,35 +1642,35 @@ areRsrvrsLeaking = FALSE; } - // If the coldest spot which is TPm is less than minimum heat disinfect temperature, - // reset the heat disinfect timers and check whether heating up has timed out - /*if ( ThdTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) + // 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 ) { // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts - heatDisinfectTimer = getMSTimerCount(); + chemDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = FALSE; - if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) + if ( TRUE == didTimeout( stateTimer, CHEM_DISINFECT_START_TEMP_TIMOUT_MS ) ) { - // Heating up to minimum temperature for heat disinfect failed - alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; - status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; + // 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 if ( isPartialDisinfectInProgress != TRUE && ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) + else if ( ( isPartialDisinfectInProgress != TRUE ) && ( ThdTemp > CHEM_DISINFECT_TARGET_TEMPERATURE_C ) ) { // The temperature of the coldest spot is in range to start the disinfect timer - heatDisinfectTimer = getMSTimerCount(); + chemDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = TRUE; } - // If heat disinfect temperature has been reached, check if this stage of heat disinfect is done - if ( ( TRUE == isPartialDisinfectInProgress ) && ( TRUE == didTimeout( heatDisinfectTimer, HEAT_DISINFECT_TIME_MS ) ) ) + // If chemical disinfect temperature has been reached, check if this stage of chemical disinfect is done + if ( ( TRUE == isPartialDisinfectInProgress ) && ( TRUE == didTimeout( chemDisinfectTimer, CHEM_DISINFECT_TIME_MS ) ) ) { - // Done with this stage of heat disnfect. Reset the variables - status = HEAT_DISINFECT_COMPLETE; + // Done with this stage of chemical disnfect. Reset the variables + status = CHEM_DISINFECT_COMPLETE; isPartialDisinfectInProgress = FALSE; - }*/ + } return status; }