Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r19934ca6e36e2dcabd6a6083a9a1f15b1ed32189 -r56880de8222ca33ea60ebf9f0bba4d62ee9a80d2 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 19934ca6e36e2dcabd6a6083a9a1f15b1ed32189) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 56880de8222ca33ea60ebf9f0bba4d62ee9a80d2) @@ -7,8 +7,8 @@ * * @file ModeHeatDisinfect.c * -* @author (last) Bill Bracken -* @date (last) 26-Oct-2022 +* @author (last) Dara Navaei +* @date (last) 10-Nov-2022 * * @author (original) Sean * @date (original) 20-Apr-2020 @@ -150,31 +150,30 @@ // ********** private data ********** -static DG_HEAT_DISINFECT_STATE_T heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Current active heat disinfect state. -static DG_HEAT_DISINFECT_STATE_T prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Previous active heat disinfect state before alarm. -static DG_HEAT_DISINFECT_UI_STATE_T heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_NOT_RUNNING; ///< Current active heat disinfect UI state. -static U32 overallHeatDisinfectTimer = 0; ///< Heat disinfect cycle total timer. -static U32 stateTimer = 0; ///< Heat disinfect state timer to be used in different states. -static U32 stateTrialCounter = 0; ///< Heat disinfect state trial counter to be used for retries in different states. -static BOOL areTempSensorsInRange = FALSE; ///< Heat disinfect temperature sensors in/out range flag. -static U32 concentratePumpsPrimeTimer = 0; ///< Concentrate pumps prime timer. +static DG_HEAT_DISINFECT_STATE_T heatDisinfectState; ///< Current active heat disinfect state. +static DG_HEAT_DISINFECT_STATE_T prevHeatDisinfectState; ///< Previous active heat disinfect state before alarm. +static DG_HEAT_DISINFECT_UI_STATE_T heatDisinfectUIState; ///< Current active heat disinfect UI state. +static U32 overallHeatDisinfectTimer; ///< Heat disinfect cycle total timer. +static U32 stateTimer; ///< Heat disinfect state timer to be used in different states. +static U32 stateTrialCounter; ///< Heat disinfect state trial counter to be used for retries in different states. +static BOOL areTempSensorsInRange; ///< Heat disinfect temperature sensors in/out range flag. +static U32 concentratePumpsPrimeTimer; ///< Concentrate pumps prime timer. /// Boolean flag to check whether draining R1 and R2 is at the end of the heat disinfect cycle or in the beginning. So the drain states can be reused. -static BOOL isThisLastDrain = FALSE; -static DG_RESERVOIR_STATUS_T rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 1 status. -static DG_RESERVOIR_STATUS_T rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 2 status. -static F32 R1HeatDisinfectVol = 0.0; ///< Reservoir 1 full volume during heat disinfect. -static F32 R2HeatDisinfectVol = 0.0; ///< Reservoir 2 full volume during heat disinfect. -static U32 heatDisinfectTimer = 0; ///< Heat disinfect timer. -static BOOL isPartialDisinfectInProgress = FALSE; ///< Heat disinfect partial complete/in progess flag. -static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during heat disinfect. -static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during heat disinfect. -static U32 dataPublishCounter = 0; ///< Heat Disinfect data publish counter. -static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. +static DG_RESERVOIR_STATUS_T rsrvr1Status; ///< Reservoir 1 status. +static DG_RESERVOIR_STATUS_T rsrvr2Status; ///< Reservoir 2 status. +static F32 R1HeatDisinfectVol; ///< Reservoir 1 full volume during heat disinfect. +static F32 R2HeatDisinfectVol; ///< Reservoir 2 full volume during heat disinfect. +static U32 heatDisinfectTimer; ///< Heat disinfect timer. +static BOOL isPartialDisinfectInProgress; ///< Heat disinfect partial complete/in progess flag. +static U32 rsrvrsVolMonitorTimer; ///< Reservoir 1 & 2 volume monitor timers during heat disinfect. +static BOOL areRsrvrsLeaking; ///< Reservoir 1 & 2 leak check flag during heat disinfect. +static U32 dataPublishCounter; ///< Heat Disinfect data publish counter. +static CANCELLATION_MODE_T cancellationMode; ///< Cancellation mode. static U32 rsrvrFillStableTimeCounter; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Heat disinfect alarm to raise. -static BOOL isDrainPumpInMixDrainOn = FALSE; ///< Flag to indicate the drain pump is on during mix drain. -static U32 ROFCoolingTimer = 0; ///< RO filter cooling timer. -static U32 targetDisinfectTime = 0; ///< Target disinfect time. +static BOOL isDrainPumpInMixDrainOn; ///< Flag to indicate the drain pump is on during mix drain. +static U32 ROFCoolingTimer; ///< RO filter cooling timer. +static U32 targetDisinfectTime; ///< Target disinfect time. static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. static U32 tempGradOutOfRangeTimer; ///< Temperature gradient out of range start timer. static DISINFECT_NV_OPS_T disinfectNVOps; ///< Disinfect non-volatile memory operations. @@ -198,9 +197,6 @@ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCoolDownROFilterState( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectMixDrainR1State( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectMixDrainR2State( void ); -static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR1ToR2State( void ); -static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR2ToR1AndDrainR1State( void ); -static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseCirculationState( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeBasicPathState( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeWaterPathState( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCompleteState( void ); @@ -218,14 +214,15 @@ * The initHeatDisinfectMode function initializes the heat disinfect mode * module. * @details Inputs: none - * @details Outputs: heatDisinfectState, stateTimer, isThisLastDrain, + * @details Outputs: heatDisinfectState, stateTimer, * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, * R1HeatDisinfectVol, R2HeatDisinfectVol, overallHeatDisinfectTimer, * cancellationMode, rsrvrFillStableTimeCounter, prevHeatDisinfectState - * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain, + * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain, heatDisinfectTimer * hasROFCirculationBeenStarted, ROFCirculationTimer, targetDisinfectTime - * ROFCirculationCoolingCounter, concentratePumpsPrimeTimer, - * haveDrainParamsBeenInit, tempGradOutOfRangeTimer, disinfectNVOps + * ROFCirculationCoolingCounter, concentratePumpsPrimeTimer, areRsrvrsLeaking + * haveDrainParamsBeenInit, tempGradOutOfRangeTimer, disinfectNVOps, + * dataPublishCounter * @return none *************************************************************************/ void initHeatDisinfectMode( void ) @@ -234,13 +231,12 @@ prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_NOT_RUNNING; stateTimer = 0; - isThisLastDrain = FALSE; stateTrialCounter = 0; areTempSensorsInRange = FALSE; rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; - R1HeatDisinfectVol = 0.0; - R2HeatDisinfectVol = 0.0; + R1HeatDisinfectVol = 0.0F; + R2HeatDisinfectVol = 0.0F; overallHeatDisinfectTimer = 0; cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillStableTimeCounter = 0; @@ -254,6 +250,11 @@ tempGradOutOfRangeTimer = 0; disinfectNVOps.hasDisCompleteDateBeenWrittenToNV = FALSE; disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; + alarmDetectedPendingTrigger = ALARM_ID_NO_ALARM; + heatDisinfectTimer = 0; + rsrvrsVolMonitorTimer = 0; + areRsrvrsLeaking = FALSE; + dataPublishCounter = 0; } /*********************************************************************//** @@ -357,19 +358,7 @@ heatDisinfectState = handleHeatDisinfectMixDrainR2State(); break; - case DG_HEAT_DISINFECT_STATE_RINSE_R1_TO_R2: - heatDisinfectState = handleHeatDisinfectRinseR1ToR2State(); - break; - - case DG_HEAT_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1: - heatDisinfectState = handleHeatDisinfectRinseR2ToR1AndDrainR1State(); - break; - - case DG_HEAT_DISINFECT_STATE_RINSE_CIRCULATION: - heatDisinfectState = handleHeatDisinfectRinseCirculationState(); - break; - - case DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH: + case DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH: heatDisinfectState = handleHeatDisinfectCancelModeBasicPathState(); break; @@ -495,7 +484,7 @@ * drain R1 state. The state drains reservoir 1. If the 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 Inputs: stateTimer, rsrvr1Status, rsrvr2Status * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status * @return next state of the heat disinfect state machine *************************************************************************/ @@ -509,43 +498,19 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - if ( TRUE == isThisLastDrain ) - { - // 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 ); - setValveState( VRD1, VALVE_STATE_CLOSED ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + // Assume reservoir 2 is full and drain it + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - // TODO turn on the concentrate pumps + // Done with draining R1, close it + setValveState( VRD1, VALVE_STATE_CLOSED ); + // Set the actuators to drain R2. + // NOTE: Drain pump is already on and VDr is already on drain state + setValveState( VRD2, VALVE_STATE_OPEN ); + state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; - // 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_HEAT_DISINFECT_STATE_RINSE_CIRCULATION; - } - else - { - tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); - tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); - - // Assume reservoir 2 is full and drain it - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - - // Done with draining R1, close it - setValveState( VRD1, VALVE_STATE_CLOSED ); - // Set the actuators to drain R2. - // NOTE: Drain pump is already on and VDr is already on drain state - setValveState( VRD2, VALVE_STATE_OPEN ); - state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; - } - setValveState( VPO, VALVE_STATE_FILL_C_TO_NC); // Start the timer @@ -566,7 +531,7 @@ * drain R2 state. The state drains reservoir 2. If the transition is * finished within the time, it transitions to the next state, otherwise, * it transitions to basic cancellation path. - * @details Inputs: stateTimer, rsrvr2Status, isThisLastDrain, + * @details Inputs: stateTimer, rsrvr2Status * stateTrialCounter * @details Outputs: stateTimer, rsrvr2Status, stateTrialCounter * @return next state of the heat disinfect state machine @@ -581,33 +546,24 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - if ( TRUE == isThisLastDrain ) - { - setValveState( VRD1, VALVE_STATE_OPEN ); - setValveState( VRD2, VALVE_STATE_CLOSED ); - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; - } - else - { - tareLoadCell( LOAD_CELL_RESERVOIR_2_PRIMARY ); - tareLoadCell( LOAD_CELL_RESERVOIR_2_BACKUP ); + tareLoadCell( LOAD_CELL_RESERVOIR_2_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_2_BACKUP ); - signalDrainPumpHardStop(); + signalDrainPumpHardStop(); - // Done with draining R2, close it - setValveState( VRD2, VALVE_STATE_CLOSED ); - setValveState( VPI, VALVE_STATE_OPEN ); - stateTrialCounter = 0; - stateTimer = getMSTimerCount(); - state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; - } + // Done with draining R2, close it + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VPI, VALVE_STATE_OPEN ); + stateTrialCounter = 0; + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevHeatDisinfectState = state; - state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; + state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } return state; @@ -1139,8 +1095,12 @@ // at inlet temperature > 45 C setROPumpTargetFlowRateLPM( HEAT_DISINFECT_TARGET_RO_FLOW_TRANSFER_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); - // Set the drain pump to control mode + // Set the drain pump to control mode setDrainPumpTargetOutletPressure( HEAT_DISINFECT_TARGET_DRAIN_FILL_R2_PSI ); + + // Turn off trimmer heater for transition + stopHeater(DG_TRIMMER_HEATER); + // Although there is fluid in both reservoirs, but they are set to empty // to begin the transition of hot water from R1 to R2. rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; @@ -1194,7 +1154,6 @@ // Get the current volumes to be monitored during R2 to R1 heat disinfect state R1HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); R2HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - setROPumpTargetFlowRateLPM( HEAT_DISINFECT_TARGET_RO_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); // Set the drain pump to control mode setDrainPumpTargetOutletPressure( HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI ); @@ -1203,6 +1162,10 @@ // at inlet temperature > 45 C setROPumpTargetFlowRateLPM( HEAT_DISINFECT_TARGET_RO_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); + // Start the trimmer heater since we are recirculating water and there is flow in the shunt line + setHeaterTargetTemperature( DG_TRIMMER_HEATER, HEAT_DISINFECT_TARGET_TEMPERATURE_C ); + startHeater( DG_TRIMMER_HEATER ); + state = DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) @@ -1443,27 +1406,7 @@ } 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( 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 ); - 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_HEAT_DISINFECT_STATE_RINSE_R1_TO_R2; + state = DG_HEAT_DISINFECT_STATE_COMPLETE; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -1476,198 +1419,6 @@ /*********************************************************************//** * @brief - * The handleHeatDisinfectRinseR1ToR2State function handles the heat - * 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: stateTimer, rsrvr1Status, rsrvr2Status - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status - * @return next state of the heat disinfect state machine - *************************************************************************/ -static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR1ToR2State( void ) -{ - DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_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 ) - { - 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 ) - { - 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_HEAT_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevHeatDisinfectState = state; - state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevHeatDisinfectState = state; - state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleHeatDisinfectRinseR2ToR1AndDrainR1State function handles the - * heat 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: stateTimer, rsrvr1Status, rsrvr2Status, isThisLastDrain - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, isThisLastDrain - * @return next state of the heat disinfect state machine - *************************************************************************/ -static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR2ToR1AndDrainR1State( void ) -{ - DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_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 ) - { - prevHeatDisinfectState = state; - state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; - } - - // First reservoir 2 must be completely full - if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) - { - // Keep monitoring the status of reservoir 1 as the same time - F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - - U32 drainPumpRPM = getDrainPumpTargetRPM(); - - // 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 ) - { - 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 ); - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRD2, VALVE_STATE_OPEN ); - 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 ); - - // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, ACID_PUMP_SPEED_ML_PER_MIN ); - - // Turn on the concentrate pumps - requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); - - // This is the last drain of heat disinfect cycle - isThisLastDrain = TRUE; - stateTimer = getMSTimerCount(); - // Set the reservoir status - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevHeatDisinfectState = state; - state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevHeatDisinfectState = state; - state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleHeatDisinfectRinseCirculationState function handles the - * heat disinfect rinse RO circulation and concentrate pumps state. Once - * the defined flush circulation time has elapsed, it transitions to the next - * state. - * @details Inputs: none - * @details Outputs: none - * @return next state of the heat disinfect state machine - *************************************************************************/ -static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseCirculationState( void ) -{ - DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_RINSE_CIRCULATION; - - if ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) - { - state = DG_HEAT_DISINFECT_STATE_COMPLETE; - } - - return state; -} - -/*********************************************************************//** - * @brief * The handleHeatDisinfectCancelModeBasicPathState function handles the * heat disinfect cancel mode basic path state. The state sets the state * to complete and raises an alarm. @@ -1955,14 +1706,19 @@ /*********************************************************************//** * @brief * The getHeatDisinfectStatus function monitors and returns the current - * stage of heat disinfect cycle. If the level of the reservoirs is drifted - * consecutively for the define period of time, it sets the reservoir leak - * time out alarm. If the target temperature is not reached within the - * defined period of time, it set the temperature out of range alarm. - * If the heat disinfect has started or has elapsed, it set the status of - * heat disinfect accordingly. - * @details Inputs: areRsrvrsLeaking, areRsrvrsLeaking - * @details Outputs: areRsrvrsLeaking, areRsrvrsLeaking, heatDisinfectState + * stage of heat disinfect cycle. It monitors + * 1) The temperature gradient betweeen TPo and Thd + * 2) Reservoir 1 or Reservoir 2 have lost more than allowed loss volume + * 3) THd must be above the minimum target disinfect temp for the + * target disinfect time + * 4) The overall heat disinfect time + * + * @details Inputs: tempGradOutOfRangeTimer, areRsrvrsLeaking, + * isPartialDisinfectInProgress, heatDisinfectTimer, + * targetDisinfectTime + * @details Outputs: tempGradOutOfRangeTimer, alarmDetectedPendingTrigger, + * areRsrvrsLeaking, isPartialDisinfectInProgress, + * heatDisinfectTimer, targetDisinfectTime * @return status of the heat disinfect (i.e in progress, complete) *************************************************************************/ static HEAT_DISINFECT_STATUS_T getHeatDisinfectStatus( void ) @@ -1979,105 +1735,106 @@ // the timer has not started yet, start it BOOL gradientOutOfRange = ( fabs( TPoTemp - ThdTemp ) > HEAT_DISINFECT_MAX_TEMP_GRADIENT_C ) ? TRUE : FALSE; - if ( TRUE != gradientOutOfRange ) + // Perform check if no pending alarm + if (ALARM_ID_NO_ALARM == alarmDetectedPendingTrigger) { - tempGradOutOfRangeTimer = 0; - } - else if ( 0 == tempGradOutOfRangeTimer ) - { - tempGradOutOfRangeTimer = getMSTimerCount(); - } - else if ( TRUE == didTimeout( tempGradOutOfRangeTimer, HEAT_DISINFECT_TEMP_GRAD_OUT_RANGE_TIME_MS ) ) - { - alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TEMP_GRAD_OUT_OF_RANGE; - status = HEAT_DISINFECT_TEMP_GRADIENT_OUT_OF_RANGE; - } - - if ( ( fabs( TPoTemp - ThdTemp ) > HEAT_DISINFECT_MAX_TEMP_GRADIENT_C ) && ( 0 == tempGradOutOfRangeTimer ) ) - { - tempGradOutOfRangeTimer = getMSTimerCount(); - } - else if ( ( fabs( TPoTemp - ThdTemp ) > HEAT_DISINFECT_MAX_TEMP_GRADIENT_C ) && - ( TRUE == didTimeout( tempGradOutOfRangeTimer, HEAT_DISINFECT_TEMP_GRAD_OUT_RANGE_TIME_MS ) ) ) - { - alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TEMP_GRAD_OUT_OF_RANGE; - status = HEAT_DISINFECT_TEMP_GRADIENT_OUT_OF_RANGE; - } - - // Check if either reservoir 1 or reservoir 2 are losing volume more than allowed volume - 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 ) + if ( TRUE != gradientOutOfRange ) { - areRsrvrsLeaking = TRUE; - rsrvrsVolMonitorTimer = getMSTimerCount(); + tempGradOutOfRangeTimer = 0; } - // If the volume is out of range and it has timed out, exit - else if ( TRUE == didTimeout( rsrvrsVolMonitorTimer, RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ) ) + else if ( 0 == tempGradOutOfRangeTimer ) { - areRsrvrsLeaking = FALSE; - alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; - status = HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT; + tempGradOutOfRangeTimer = getMSTimerCount(); } + else if ( TRUE == didTimeout( tempGradOutOfRangeTimer, HEAT_DISINFECT_TEMP_GRAD_OUT_RANGE_TIME_MS ) ) + { + alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TEMP_GRAD_OUT_OF_RANGE; + status = HEAT_DISINFECT_TEMP_GRADIENT_OUT_OF_RANGE; + } } - // Reservoirs are in range - else - { - areRsrvrsLeaking = FALSE; - } - // If the coldest spot which is THd is less than minimum heat disinfect temperature, - // reset the heat disinfect timers and check whether heating up has timed out - if ( ThdTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) + // Perform check if no pending alarm + if (ALARM_ID_NO_ALARM == alarmDetectedPendingTrigger) { - // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts - heatDisinfectTimer = getMSTimerCount(); - isPartialDisinfectInProgress = FALSE; - targetDisinfectTime = 0; - - if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) + // Check if either reservoir 1 or reservoir 2 are losing volume more than allowed volume + if ( ( TRUE == isR1OutOfRange ) || ( TRUE == isR2OutOfRange ) ) { - // Heating up to minimum temperature for heat disinfect failed - alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; - status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; + // If the leak is the first time after a while, set the flag and start the timer + if ( FALSE == areRsrvrsLeaking ) + { + areRsrvrsLeaking = TRUE; + rsrvrsVolMonitorTimer = getMSTimerCount(); + } + // If the volume is out of range and it has timed out, exit + else if ( TRUE == didTimeout( rsrvrsVolMonitorTimer, RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ) ) + { + areRsrvrsLeaking = FALSE; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; + status = HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT; + } } + // Reservoirs are in range + else + { + areRsrvrsLeaking = FALSE; + } } - else if ( ( isPartialDisinfectInProgress != TRUE ) && ( ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) ) + + // Perform check if no pending alarm + if (ALARM_ID_NO_ALARM == alarmDetectedPendingTrigger) { - // The temperature of the coldest spot is in range to start the disinfect timer - heatDisinfectTimer = getMSTimerCount(); - isPartialDisinfectInProgress = TRUE; - targetDisinfectTime = HEAT_DISINFECT_TIME_MS; - status = HEAT_DISINFECT_DISINFECT_IN_PROGRESS; + // If the coldest spot which is THd is less than minimum heat disinfect temperature, + // reset the heat disinfect timers and check whether heating up has timed out + if ( ThdTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) + { + // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts + heatDisinfectTimer = getMSTimerCount(); + isPartialDisinfectInProgress = FALSE; + targetDisinfectTime = 0; - // In disinfect R1 to R2, concentrate pumps are also run - if ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) + if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) + { + // Heating up to minimum temperature for heat disinfect failed + alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; + status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; + } + } + else if ( ( isPartialDisinfectInProgress != TRUE ) && ( ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) ) { - // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + // The temperature of the coldest spot is in range to start the disinfect timer + heatDisinfectTimer = getMSTimerCount(); + isPartialDisinfectInProgress = TRUE; + targetDisinfectTime = HEAT_DISINFECT_TIME_MS; + status = HEAT_DISINFECT_DISINFECT_IN_PROGRESS; - // During R1 to R2 disinfect, the concentrate pumps turn on - requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + // In disinfect R1 to R2, concentrate pumps are also run + if ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) + { + // Turn the pumps on in reverse + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + + // During R1 to R2 disinfect, the concentrate pumps turn on + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + } } } - else if ( ( TRUE == isPartialDisinfectInProgress ) && ( ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) ) - { - status = HEAT_DISINFECT_DISINFECT_IN_PROGRESS; - } - // 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 ) ) ) + // Perform check if no pending alarm + if (ALARM_ID_NO_ALARM == alarmDetectedPendingTrigger) { - // Done with this stage of heat disnfect. Reset the variables - // Target disinfect time is the time that is published to the UI and when there is - // no disinfect count down, this variable is set to 0. When the target time is 0, the UI - // hides the timer on the UI disinfect screen - targetDisinfectTime = 0; - status = HEAT_DISINFECT_COMPLETE; - isPartialDisinfectInProgress = FALSE; + // 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 ) ) ) + { + // Done with this stage of heat disnfect. Reset the variables + // Target disinfect time is the time that is published to the UI and when there is + // no disinfect count down, this variable is set to 0. When the target time is 0, the UI + // hides the timer on the UI disinfect screen + targetDisinfectTime = 0; + status = HEAT_DISINFECT_COMPLETE; + isPartialDisinfectInProgress = FALSE; + } } return status;