Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r5a36a768d11cc597a36b894c1fb3a5e5590130f1 -re44aad7a9d5fa48aeaa55c65bd28ad9acde6ce05 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 5a36a768d11cc597a36b894c1fb3a5e5590130f1) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision e44aad7a9d5fa48aeaa55c65bd28ad9acde6ce05) @@ -41,11 +41,11 @@ // General defines #define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. -#define HEAT_DISINFECT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode Heat Disinfect data publish interval in counts. +#define HEAT_DISINFECT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode chem disinfect data publish interval in counts. // Start state defines #define MIN_INLET_PRESSURE_PSI 30.0 ///< Minimum water inlet pressure in psi. -#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 1.0 ///< Max start state TDi and TRo difference tolerance in C. +#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 3.0 ///< Max start state TDi and TRo difference tolerance in C. // Drain R1 & R2 states defines #define DRAIN_PUMP_TARGET_RPM 1800 ///< Drain pump target RPM during drain. @@ -106,7 +106,7 @@ CANCELLATION_MODE_HOT, ///< Cancellation mode hot. CANCELLATION_MODE_COLD, ///< Cancellation mode cold. NUM_OF_CANCELLATION_MODES ///< Number of cancellation modes. -} CANCELLATION_MODES_T; +} CANCELLATION_MODE_T; /// Heat disinfect status typedef enum Heat_disinfect_status @@ -137,7 +137,7 @@ static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during heat disinfect. static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during heat disinfect. static U32 dataPublishCounter = 0; ///< Heat Disinfect data publish counter. -static CANCELLATION_MODES_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. +static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Heat disinfect alarm to raise. static BOOL isDrainPumpInMixDrainOn = FALSE; ///< Flag to show the drain pump is on during mix drain. @@ -182,8 +182,8 @@ * @details Outputs: heatDisinfectState, stateTimer, isThisLastDrain, * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, * R1HeatDisinfectVol, R2HeatDisinfectVol, overallHeatDisinfectTimer, - * cancellationMode, rsrvrFillStableTimeCounter, isPartialDisinfectInProgress, - * isDrainPumpOnInMixDrain + * cancellationMode, rsrvrFillStableTimeCounter, prevHeatDisinfectState + * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain * @return none *************************************************************************/ void initHeatDisinfectMode( void ) @@ -406,7 +406,7 @@ F32 TDiTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODo change to TDi F32 TRoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); - // If the inlet pressure is less than the threshold and TDi and TRo difference is greater than 1 C, the cycle + // If the inlet pressure is less than the threshold and TDi and TRo difference is greater than 3 C, the cycle // should be canceled if ( ( ppiPressure < MIN_INLET_PRESSURE_PSI ) && ( fabs( TDiTemp - TRoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) ) { @@ -574,7 +574,7 @@ * @brief * The handleHeatDisinfectFlushDrainState function handles the heat disinfect * flush drain state. The state flushes the drain line for a period of time - * and then measure the temperature and conductivity of water. If they are + * and then measures the temperature and conductivity of water. If they are * not within the range, it transitions to basic cancellation path, otherwise * it transitions to the next state. * @details Inputs: stateTimer, stateTrialCounter, alarm, @@ -640,7 +640,7 @@ DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; // Check if the flush circulation time has elapsed and the temperature sensors are not in range yet - if ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) && ( FALSE == areTempSensorsInRange ) ) + if ( ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) && ( FALSE == areTempSensorsInRange ) ) { F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); // TODO add THd later. This is the new temp sensor of the coldest spot. F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); @@ -721,7 +721,7 @@ { rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - // Keep monitoring the status of reservoir 2 as the same time + // Keep monitoring the status of reservoir 2 at the same time rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue @@ -1039,7 +1039,7 @@ // Get the current volumes of R1 & R2. These values will be used to make sure the reservoirs' // volume does not change more than a certain amount during the actual heat disinfect cycle - R1HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ); //TODO change this back to primary + R1HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); R2HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); stateTimer = getMSTimerCount(); @@ -1150,15 +1150,15 @@ state = DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1; } -#ifdef IGNORE_HEAT_DISINFECT_RSRVR_TIMEOUT +#ifdef IGNORE_DISINFECT_RSRVR_TIMEOUT else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevHeatDisinfectState = state; state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; } #endif } -#ifdef IGNORE_HEAT_DISINFECT_RSRVR_TIMEOUT +#ifdef IGNORE_DISINFECT_RSRVR_TIMEOUT else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevHeatDisinfectState = state; @@ -1176,8 +1176,8 @@ * temperature within a certain period of time, it transitions to water * cancellation state. If heat disinfect reservoir 1 to reservoir 2 is * completed, it transitions to the next state. - * @details Inputs: hasPostHeatDisinfectWaitStarted, stateTimer, rsrvr1Status - * @details Outputs: hasPostHeatDisinfectWaitStarted, stateTimer, rsrvr1Status + * @details Inputs: stateTimer, rsrvr1Status + * @details Outputs: stateTimer, rsrvr1Status * @return next state of the heat disinfect state machine *************************************************************************/ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR2ToR1State( void ) @@ -1193,7 +1193,7 @@ break; case HEAT_DISINFECT_COMPLETE: - // Turn off the pumps and heaters + // Turn off the heaters // TODO turn off CP1 and CP2 stopPrimaryHeater(); stopTrimmerHeater(); @@ -1226,18 +1226,14 @@ // De-energize all the valves that are not in the path anymore // and wait for the RO membrane to be cooled down. - // In this state, VPi and VPd must still be kept energized to make sure fresh - // water does not enter the circulation path the membrane is cooling down setValveState( 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_CLOSED ); #else setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); - #endif - stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_RO_FILTER; } @@ -1303,6 +1299,10 @@ setValveState( VRD1, VALVE_STATE_OPEN ); #endif +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_OPEN ); +#endif + // Turn on the drain pump to drain the reservoirs in open loop mode setDrainPumpTargetRPM( DRAIN_PUMP_RPM_IN_MIX_DRAIN ); } @@ -1410,6 +1410,18 @@ if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + // Keep monitoring the status of reservoir 2 at the same time + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already + // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue + // until reservoir 2 is filled up and the tubing might expand or leak. + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + prevHeatDisinfectState = state; + alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1487,6 +1499,21 @@ if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) { rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + U32 drainPumpRPM = getTargetDrainPumpRPM(); + // Keep monitoring the status of reservoir 1 as the same time + F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + // Reservoir 1 cannot be filled before reservoir 2 is filled and is overflowing to reservoir 1. If reservoir 1 has already + // reached to target volume, it means reservoir 2's load cell might be reading incorrect values. This situation might continue + // until reservoir 1 is filled up and the tubing might expand or leak. + // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make + // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL + if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + { + prevHeatDisinfectState = state; + alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } } // Once reservoir 2 is completely full, monitor reservoir 1 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) @@ -1706,48 +1733,9 @@ /*********************************************************************//** * @brief - * The resetActuators function sets all the actuators to reset and - * de-energized state. - * @details Inputs: none - * @details Outputs: none - * @return none - *************************************************************************/ -static void resetActuators( void ) -{ - // UV reactors will not be used in the heat disinfection since their operating temperature - // range is below 85C and they might be damaged by the high temperature. - turnOffUVReactor( INLET_UV_REACTOR ); - turnOffUVReactor( OUTLET_UV_REACTOR ); - - // De-energize all the valves - setValveState( VPI, VALVE_STATE_CLOSED ); - setValveState( VBF, VALVE_STATE_CLOSED ); - setValveState( VSP, 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( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - - //TODO add the composition pumps - signalROPumpHardStop(); - signalDrainPumpHardStop(); - stopPrimaryHeater(); - stopTrimmerHeater(); -} - -/*********************************************************************//** - * @brief * The failHeatDisinfect function sets the alarm that failed the heat * disinfect mode. - * @details Inputs: alarm, prevHeatDisinfectState + * @details Inputs: alarmDetectedPendingTrigger, prevHeatDisinfectState * @details Outputs: none * @return none *************************************************************************/ @@ -1775,7 +1763,7 @@ if ( r == DG_RESERVOIR_1 ) { - volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ); //TODO change back to primary + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else if ( r == DG_RESERVOIR_2 ) { @@ -1814,8 +1802,7 @@ * reservoir. * @details Inputs: stateTimer, prevHeatDisinfectState, heatDisinfectState, * alarm - * @details Outputs: stateTimer, heatDisinfectState heatDisinfectState, - * alarm + * @details Outputs: stateTimer, heatDisinfectState, alarm * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 * @param drainSteadyStateTimeout which is the time the reservoir's level * does not change and is steady state @@ -1866,11 +1853,11 @@ F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODO change this to actual TPm sensor later - BOOL isR1OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ) - R1HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; //TODo change this to primary when the stupid load cell was fixed + BOOL isR1OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; BOOL isR2OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) - R2HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; // Check if either reservoir 1 or reservoir 2 are losing volume more than allowed volume - if ( isR1OutOfRange || isR2OutOfRange ) + if ( ( TRUE == isR1OutOfRange ) || ( TRUE == isR2OutOfRange ) ) { // If the leak is the first time after a while, set the flag and start the timer if ( FALSE == areRsrvrsLeaking )