Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r2fff37fa585181917705645494549b5fd4a4d522 -rd7be59e36db5e9899b02dd0bfadadc50fed934c0 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision d7be59e36db5e9899b02dd0bfadadc50fed934c0) @@ -1,31 +1,37 @@ /************************************************************************** * -* Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +* Copyright (c) 2020-2022 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * -* @file ModeHeatDisinfect.c +* @file ModeHeatDisinfect.c * -* @author (last) Quang Nguyen -* @date (last) 01-Sep-2020 +* @author (last) Bill Bracken +* @date (last) 22-Aug-2022 * -* @author (original) Sean -* @date (original) 20-Apr-2020 +* @author (original) Sean +* @date (original) 20-Apr-2020 * ***************************************************************************/ +#include // For fabs + #include "ConcentratePumps.h" #include "ConductivitySensors.h" #include "DrainPump.h" #include "Heaters.h" #include "LoadCell.h" +#include "MessageSupport.h" #include "ModeFault.h" #include "ModeHeatDisinfect.h" +#include "NVDataMgmt.h" #include "OperationModes.h" #include "Pressures.h" #include "Reservoirs.h" #include "ROPump.h" +#include "RTC.h" +#include "Switches.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TemperatureSensors.h" @@ -38,72 +44,78 @@ * @{ */ +// TODO add the cooling, test the higher target flow to reduce the gradient + // ********** private definitions ********** // 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. // Start state defines -#define MIN_INLET_PRESSURE_PSI 30.0 ///< Minimum water inlet pressure in psi. -#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 3.0 ///< Max start state TDi and TRo difference tolerance in C. +#define MIN_INLET_PRESSURE_PSI 30.0F ///< Minimum water inlet pressure in psi. +#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 3.0F ///< Max start state TDi and TRo difference tolerance in C. // Drain R1 & R2 states defines -#define DRAIN_PUMP_TARGET_RPM 2200 ///< Drain pump target RPM during drain. +#define DRAIN_PUMP_TARGET_RPM 2400 ///< 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. // Flush drain path state defines #define FLUSH_DRAIN_WAIT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. -#define MIN_INLET_TEMPERATURE_C 15.0 ///< Minimum water inlet temperature in C. TODO original temperature was 25 C -#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0 ///< Maximum water inlet conductivity in us/cm +#define MIN_INLET_TEMPERATURE_C 15.0F ///< Minimum water inlet temperature in C. TODO original temperature was 25 C +#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0F ///< Maximum water inlet conductivity in us/cm // Flush circulation path state defines -#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.8 ///< RO pump target flow rate during flush/fill in L/min. +#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.8F ///< RO pump target flow rate during flush/fill in L/min. #define MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. #define FLUSH_CICRCULATION_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush/rinse circulation path wait time in milliseconds. TODO original time was 30 seconds -#define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 50.0 ///< Maximum flush circulation temperature difference tolerance in C. TODO original difference was 3.0 degrees -#define NUM_OF_TEMP_SENSORS_TO_AVG 4.0 ///< Number of temperature sensors to average to check the difference. -#define CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN -30.0 ///< Concentrate pumps reverse speed in mL/min. +#define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 50.0F ///< Maximum flush circulation temperature difference tolerance in C. TODO original difference was 3.0 degrees +#define NUM_OF_TEMP_SENSORS_TO_AVG 4.0F ///< Number of temperature sensors to average to check the difference. +#define ACID_PUMP_SPEED_ML_PER_MIN -30.0F ///< Acid concentrate pump speed in mL/min. +// The bicarb pump is 2% faster than the acid pump to create a flow from acid to bicarb line during heat disinfect +#define BICARB_PUMP_SPEED_ML_PER_MIN 30.6F ///< Bicarb concentrate pump speed in mL/min. // Flush and drain R1 and R2 -#define RSRVRS_FULL_VOL_ML 1750.0 ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 -#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< Reservoirs 1 & 2 partial volume in mL. +#define RSRVRS_FULL_VOL_ML 1850.0F ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 +#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0F ///< Reservoirs 1 & 2 partial volume in mL. #define RSRVRS_FULL_STABLE_TIME_COUNT ( ( 4 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in counts. #define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. TODO original value was 5 mins -#define RSRVRS_500ML_FILL_UP_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. +#define RSRVRS_500ML_FILL_UP_TIMEOUT_MS ( 4 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. TODO original value was 2 mins #define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. // Fill and heat water -#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 83.0 ///< Heat disinfect target water temperature in C. -#define HEAT_DISINFECT_START_TEMPERATURE_C 81.0 ///< Heat disinfect minimum acceptable temperature in C. +#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 82.0F ///< Heat disinfect target water temperature in C. +#define HEAT_DISINFECT_START_TEMPERATURE_C 81.0F ///< Heat disinfect minimum acceptable temperature in C. // R1 to R2 & R2 to R1 heat disinfect circulation -#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 1.3 ///< Heat disinfect target RO flow rate in L/min. +#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 1.3F ///< Heat disinfect target RO flow rate in L/min. #define HEAT_DISINFECT_MAX_RO_PRESSURE_PSI 30 ///< Heat disinfect maximum RO pressure in psi. -#define HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI 12.0 ///< Heat disinfect target drain outlet pressure in psi. +#define HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI 12.0F ///< Heat disinfect target drain outlet pressure in psi. #define HEAT_DISINFECT_TIME_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. #define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. -#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 heat 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 heat disinfect. TODO original value is 100 mL +#define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 0.5F * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disinfect. TODO change this to 5 seconds +#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 100.0F ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. #define POST_HEAT_DISINFECT_WAIT_TIME_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect final wait time before flushing the system in milliseconds. +#define HEAT_DISINFECT_MAX_TEMP_GRADIENT_C 15.0F ///< Heat disinfect maximum allowed temperature gradient in between hottest and coldest sensors. +#define HEAT_DISINFECT_TEMP_GRAD_OUT_RANGE_TIME_MS ( 0.16 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect temperature gradient out of range timeout in milliseconds. // Cool down RO filter #define THD_REACH_BELOW_45_AFTER_CIRC_TIME_MS ( 5 * MS_PER_SECOND ) ///< Number of circulations that are needed to make the RO filter is below 45 C. -#define ROF_COOL_DOWN_TARGET_FLOW_LPM 0.3 ///< RO filter cool down target flow in L/min. +#define ROF_COOL_DOWN_TARGET_FLOW_LPM 0.3F ///< RO filter cool down target flow in L/min. #define ROF_COOL_DOWN_CIRCULATION_TIME_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< RO filter cool down circulation timer in milliseconds. -#define TARGET_THD_SENSOR_FOR_RINSING_C 44.0 ///< Target THd temperature sensor value before rinsing in C. +#define TARGET_THD_SENSOR_FOR_RINSING_C 44.0F ///< Target THd temperature sensor value before rinsing in C. // Mix drain R1 and R2 -#define RSRVRS_MIX_DRAIN_TIMEOUT_MS ( 20 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 mix drain timeout in ms. +#define RSRVRS_MIX_DRAIN_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 mix drain timeout in ms. #define DRAIN_PUMP_START_TIME_IN_MIX_DRAIN_MS ( 5 * MS_PER_SECOND ) ///< Time to start the drain pump at mix drain after directing the flow to drain in ms. #define DRAIN_PUMP_RPM_IN_MIX_DRAIN 600 ///< The RPM that the drain pump should be run during mix drain. #define MIX_DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 15 * MS_PER_SECOND ) ///< Time period of unchanged weight during mix draining before timeout. // Rinse R1 to R2 -#define ROF_MIN_LOW_PRESSURE_TEMPERATURE_C 45.0 ///< RO filter minimum temperature that the pressure must be no more than 30psi in C. +#define ROF_MIN_LOW_PRESSURE_TEMPERATURE_C 45.0F ///< RO filter minimum temperature that the pressure must be no more than 30psi in C. -#define MIX_DRAIN_TEMPERATURE_THRESHOLD_C 60.0 ///< Temperature threshold for performing mix drain or normal drain. +#define MIX_DRAIN_TEMPERATURE_THRESHOLD_C 60.0F ///< Temperature threshold for performing mix drain or normal drain. /// Cancellation paths typedef enum Cancellation_modes @@ -118,9 +130,11 @@ /// Heat disinfect status typedef enum Heat_disinfect_status { - HEAT_DISINFECT_IN_PROGRESS = 0, ///< Heat disinfect in progress. + HEAT_DISINFECT_HEAT_UP_IN_PROGRESS = 0, ///< Heat disinfect in progress. + HEAT_DISINFECT_DISINFECT_IN_PROGRESS, ///< Heat disinfect disinfect in progress. HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT, ///< Heat disinfect reservoirs leak timeout. HEAT_DISINFECT_HEAT_UP_TIMEOUT, ///< Heat disinfect heat up timeout. + HEAT_DISINFECT_TEMP_GRADIENT_OUT_OF_RANGE, ///< Heat disinfect temperature gradient out of range. HEAT_DISINFECT_COMPLETE, ///< Heat disinfect complete. NUM_OF_HEAT_DISINFECT_STATUS ///< Number of heat disinfect status. } HEAT_DISINFECT_STATUS_T; @@ -147,12 +161,15 @@ 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 U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. +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 ROFCirculationTimer = 0; ///< RO filter circulation timer. static U32 ROFCoolingTimer = 0; ///< RO filter cooling timer. static BOOL hasROFCirculationBeenStarted = FALSE; ///< Flag to indicate the water in RO filter has been recirculated. +static U32 targetDisinfectTime = 0; ///< 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. // ********** private function prototypes ********** @@ -181,10 +198,11 @@ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCompleteState( void ); static void failHeatDisinfect( void ); -static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ); +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T reservoir, F32 targetVol, U32 timeout ); static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); static HEAT_DISINFECT_STATUS_T getHeatDisinfectStatus( void ); static void publishHeatDisinfectData( void ); +static void monitorModeHeatDisinfect( void ); /*********************************************************************//** * @brief @@ -196,32 +214,37 @@ * R1HeatDisinfectVol, R2HeatDisinfectVol, overallHeatDisinfectTimer, * cancellationMode, rsrvrFillStableTimeCounter, prevHeatDisinfectState * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain, - * hasROFCirculationBeenStarted, ROFCirculationTimer, - * ROFCirculationCoolingCounter, concentratePumpsPrimeTimer + * hasROFCirculationBeenStarted, ROFCirculationTimer, targetDisinfectTime + * ROFCirculationCoolingCounter, concentratePumpsPrimeTimer, + * haveDrainParamsBeenInit, tempGradOutOfRangeTimer * @return none *************************************************************************/ void initHeatDisinfectMode( void ) { - heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; - 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; - overallHeatDisinfectTimer = 0; - cancellationMode = CANCELLATION_MODE_NONE; - rsrvrFillStableTimeCounter = 0; - isPartialDisinfectInProgress = FALSE; - isDrainPumpInMixDrainOn = FALSE; - ROFCirculationTimer = 0; - ROFCoolingTimer = 0; - hasROFCirculationBeenStarted = FALSE; - concentratePumpsPrimeTimer = 0; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + 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; + overallHeatDisinfectTimer = 0; + cancellationMode = CANCELLATION_MODE_NONE; + rsrvrFillStableTimeCounter = 0; + isPartialDisinfectInProgress = FALSE; + isDrainPumpInMixDrainOn = FALSE; + ROFCirculationTimer = 0; + ROFCoolingTimer = 0; + hasROFCirculationBeenStarted = FALSE; + concentratePumpsPrimeTimer = 0; + targetDisinfectTime = 0; + haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; + haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; + tempGradOutOfRangeTimer = 0; } /*********************************************************************//** @@ -230,13 +253,15 @@ * heat disinfect mode. * @details Inputs: none * @details Outputs: none - * @return none + * @return initial state *************************************************************************/ -void transitionToHeatDisinfectMode( void ) +U32 transitionToHeatDisinfectMode( void ) { deenergizeActuators(); initHeatDisinfectMode(); + + return heatDisinfectState; } /*********************************************************************//** @@ -249,6 +274,8 @@ *************************************************************************/ U32 execHeatDisinfectMode( void ) { + monitorModeHeatDisinfect(); + switch ( heatDisinfectState ) { case DG_HEAT_DISINFECT_STATE_START: @@ -411,27 +438,23 @@ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStartState( void ) { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; + F32 ppiPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); + F32 TDiTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + F32 TRoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); // Start overall heat disinfect timer overallHeatDisinfectTimer = getMSTimerCount(); // Set all the actuators to reset and de-energized state deenergizeActuators(); - // Reset the load cells lowest weight prior to starting the run - resetReservoirsLowestWeight(); - - F32 ppiPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); - F32 TDiTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); - F32 TRoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); - - // If the inlet pressure is less than the threshold and TDi and TRo difference is greater than 3 C, the cycle + // If the inlet pressure is less than or equal to the threshold or 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 ) ) + if ( ( ppiPressure <= MIN_INLET_PRESSURE_PSI ) || ( fabs( TDiTemp - TRoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) ) { - prevHeatDisinfectState = state; + prevHeatDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_INLET_PRES_AND_TEMP_SNSRS_OUT; - state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; + state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } else { @@ -440,15 +463,10 @@ // Close VPi to prevent wasting water setValveState( VPI, VALVE_STATE_CLOSED ); - // Request a tare for reservoir 1 - tareReservoir(); -#ifndef V_2_SYSTEM + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC); + // 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; @@ -487,46 +505,38 @@ // 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 ); 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 ); // TODO turn on the concentrate pumps // Set the RO pump to run at full pressure - setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + 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; - // Request a tare for reservoir 2 - tareReservoir(); -#ifndef V_2_SYSTEM // 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 ); -#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_HEAT_DISINFECT_STATE_DRAIN_R2; } + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC); + // Start the timer stateTimer = getMSTimerCount(); } @@ -562,28 +572,26 @@ { 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_HEAT_DISINFECT_STATE_DRAIN_R1; } else { + tareLoadCell( LOAD_CELL_RESERVOIR_2_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_2_BACKUP ); + signalDrainPumpHardStop(); -#ifndef V_2_SYSTEM // Done with draining R2, close it setValveState( VRD2, VALVE_STATE_CLOSED ); -#endif 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 ) { @@ -614,16 +622,26 @@ // Check if flush time has elapsed if ( TRUE == didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) { + BOOL hasConductivityPassed = FALSE; + // If the inlet temperature and conductivity are in range, move onto the next state if ( ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MIN_INLET_TEMPERATURE_C ) && ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) <= MAX_INLET_CONDUCTIVITY_US_PER_CM ) ) { -#ifndef V_2_SYSTEM - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); -#else - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + hasConductivityPassed = TRUE; + } + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + { + hasConductivityPassed = TRUE; + } #endif - setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + + if ( TRUE == hasConductivityPassed ) + { + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); stateTimer = getMSTimerCount(); stateTrialCounter = 0; state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; @@ -698,15 +716,13 @@ else { areTempSensorsInRange = TRUE; -#ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); // Turn on the concentrate pumps - requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); -#endif + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); concentratePumpsPrimeTimer = getMSTimerCount(); } } @@ -719,9 +735,9 @@ rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - // Done with priming the concentrate pumps line - requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); + // Done with flushing the concentrate pumps line + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); @@ -779,11 +795,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(); @@ -833,10 +845,8 @@ { // Done with draining R1 signalDrainPumpHardStop(); -#ifndef V_2_SYSTEM // Close VRD1 setValveState( VRD1, VALVE_STATE_CLOSED ); -#endif } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -849,15 +859,15 @@ { rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - U32 drainPumpRPM = getTargetDrainPumpRPM(); + U32 drainPumpRPM = getDrainPumpTargetRPM(); // Keep monitoring the status of reservoir 1 as the same time F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); // Reservoir 1 cannot be filled before reservoir 2 is filled and is overflowing to reservoir 1. If reservoir 1 has already // reached to target volume, it means reservoir 2's load cell might be reading incorrect values. This situation might continue // until reservoir 1 is filled up and the tubing might expand or leak. // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL - if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + if ( ( volume >= RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) { prevHeatDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; @@ -877,18 +887,10 @@ // 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 ); -#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 setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); // Start the timer for drain timeout stateTimer = getMSTimerCount(); @@ -932,12 +934,8 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { -#ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_OPEN ); setValveState( VRD2, VALVE_STATE_CLOSED ); -#else - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif // Start the timer for drain timeout stateTimer = getMSTimerCount(); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; @@ -979,28 +977,20 @@ // 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 ); -#else - setValveState( VPD, VALVE_STATE_OPEN_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 ); -#ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_CLOSED ); setValveState( VRD2, VALVE_STATE_OPEN ); -#else - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); -#endif // Turn on the RO pump - setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); // Start heating the water while we are filling up the reservoirs - setPrimaryHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); - startPrimaryHeater(); + setHeaterTargetTemperature( DG_PRIMARY_HEATER, HEAT_DISINFECT_TARGET_TEMPERATURE_C ); + startHeater( DG_PRIMARY_HEATER ); rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; @@ -1055,11 +1045,7 @@ // 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 ); -#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 ); @@ -1068,11 +1054,11 @@ // Set the RO flow to maximum pressure of 30psi since it is the maximum pressure on the RO filter // at inlet temperature > 45 C - setROPumpTargetFlowRate( HEAT_DISINFECT_TARGET_RO_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); + 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 - setTrimmerHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); - startTrimmerHeater(); + setHeaterTargetTemperature( DG_TRIMMER_HEATER, HEAT_DISINFECT_TARGET_TEMPERATURE_C ); + startHeater( DG_TRIMMER_HEATER ); // 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 @@ -1107,7 +1093,7 @@ * If heat 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, tempGradOutOfRangeTimer * @return next state of the heat disinfect state machine *************************************************************************/ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR1ToR2State( void ) @@ -1119,35 +1105,37 @@ { case HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT: case HEAT_DISINFECT_HEAT_UP_TIMEOUT: + case HEAT_DISINFECT_TEMP_GRADIENT_OUT_OF_RANGE: state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; break; + case HEAT_DISINFECT_DISINFECT_IN_PROGRESS: + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_1; + break; + case HEAT_DISINFECT_COMPLETE: - requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); // 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. - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; - stateTimer = getMSTimerCount(); - - state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + stateTimer = getMSTimerCount(); + // Reset the timer for the next disinfect state + tempGradOutOfRangeTimer = 0; + state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; break; - case HEAT_DISINFECT_IN_PROGRESS: + case HEAT_DISINFECT_HEAT_UP_IN_PROGRESS: default: - // Do nothing, heat disinfect is in progress + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_HEAT_UP_WATER; break; } @@ -1221,23 +1209,29 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1; HEAT_DISINFECT_STATUS_T status = getHeatDisinfectStatus(); + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_2; switch ( status ) { case HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT: case HEAT_DISINFECT_HEAT_UP_TIMEOUT: + case HEAT_DISINFECT_TEMP_GRADIENT_OUT_OF_RANGE: state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; break; case HEAT_DISINFECT_COMPLETE: // Turn off the heaters - stopPrimaryHeater(); - stopTrimmerHeater(); + stopHeater( DG_PRIMARY_HEATER ); + stopHeater( DG_TRIMMER_HEATER ); stateTimer = getMSTimerCount(); - state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; + state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; + + // Set the disinfect flags + setDisinfectStatus( TRUE ); + setLastDisinfectDate( getRTCTimestamp() ); break; - case HEAT_DISINFECT_IN_PROGRESS: + case HEAT_DISINFECT_HEAT_UP_IN_PROGRESS: default: // Do nothing heat disinfect is in progress. break; @@ -1275,12 +1269,8 @@ setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_CLOSED ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); -#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 ROFCoolingTimer = getMSTimerCount(); stateTimer = getMSTimerCount(); @@ -1342,7 +1332,7 @@ // Set the RO flow to maximum pressure of 30psi since it is the maximum pressure on the RO filter // at inlet temperature > 45 C - setROPumpTargetFlowRate( ROF_COOL_DOWN_TARGET_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); + setROPumpTargetFlowRateLPM( ROF_COOL_DOWN_TARGET_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); hasROFCirculationBeenStarted = TRUE; ROFCirculationTimer = getMSTimerCount(); @@ -1382,9 +1372,7 @@ { isDrainPumpInMixDrainOn = TRUE; -#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 ); } @@ -1396,15 +1384,10 @@ } 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(); @@ -1445,20 +1428,16 @@ // 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 ); + 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; @@ -1514,11 +1493,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 ); @@ -1567,9 +1542,7 @@ { // Done with draining R1 signalDrainPumpHardStop(); -#ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_CLOSED ); -#endif } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -1580,17 +1553,19 @@ // 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 ); + + 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 ) ) + if ( ( volume >= RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) { prevHeatDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; @@ -1609,32 +1584,23 @@ // 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( VPO, VALVE_STATE_FILL_C_TO_NC); 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 ); -#ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT + // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + 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 - requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); -#endif + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); // This is the last drain of heat disinfect cycle isThisLastDrain = TRUE; @@ -1728,14 +1694,12 @@ if ( CANCELLATION_MODE_NONE == cancellationMode ) { U32 targetRPM = 0; + F32 TDi = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + F32 TRo = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); // Stop all the actuators first then decide who should run next deenergizeActuators(); - // Check inlet dialysate and redundant outlet temperature sensors - F32 TDi = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); - F32 TRo = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); - // The two sensors must be less than a threshold to decide if mix drain is needed to normal drain if ( ( TDi < MIX_DRAIN_TEMPERATURE_THRESHOLD_C ) && ( TRo < MIX_DRAIN_TEMPERATURE_THRESHOLD_C ) ) { @@ -1746,11 +1710,7 @@ { // The fluid is hot so this is a mix drain. Set the VPd to direct the cold inlet fluid to drain setValveState( VPI, VALVE_STATE_OPEN ); -#ifndef V_2_SYSTEM setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); -#else - setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); -#endif targetRPM = DRAIN_PUMP_RPM_IN_MIX_DRAIN; cancellationMode = CANCELLATION_MODE_HOT; @@ -1777,14 +1737,9 @@ if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { -#ifndef V_2_SYSTEM // Set the drain valve to reservoir 1 and close reservoir 2 setValveState( VRD1, VALVE_STATE_OPEN ); setValveState( VRD2, VALVE_STATE_CLOSED ); -#else - // Set the drain valve to reservoir 1 - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); -#endif } } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) @@ -1867,46 +1822,46 @@ * complete and exits the heat disinfect mode. * @details Inputs: rsrvrFillStableTimeCounter, alarm, stateTimer * @details Outputs: none - * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 + * @param reservoir is DG_RESERVOIR_1 or DG_RESERVOIR_2 * @param targetVol is the target fill volume * @param timeout is the fill up timeout * @return the status of the reservoirs during filling *************************************************************************/ -static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ) +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T reservoir, F32 targetVol, U32 timeout ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; F32 volume = 0.0; - if ( r == DG_RESERVOIR_1 ) + if ( DG_RESERVOIR_1 == reservoir ) { volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); } - else if ( r == DG_RESERVOIR_2 ) + else if ( DG_RESERVOIR_2 == reservoir ) { volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); } else { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, r ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, reservoir ) } // Check the volume of the reservoir against the target volume if ( volume >= targetVol ) { if ( ++rsrvrFillStableTimeCounter >= RSRVRS_FULL_STABLE_TIME_COUNT ) { - status = DG_RESERVOIR_REACHED_TARGET; + status = DG_RESERVOIR_REACHED_TARGET; rsrvrFillStableTimeCounter = 0; // Set the state timer in case it needs to be used for another timeout check - stateTimer = getMSTimerCount(); + stateTimer = getMSTimerCount(); } } else if ( TRUE == didTimeout( stateTimer, timeout ) ) { // Failed to fill ontime. Update the previous heat disinfect state and transition to basic cancellation - prevHeatDisinfectState = heatDisinfectState; + prevHeatDisinfectState = heatDisinfectState; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_FILL_TIMEOUT; - status = DG_RESERVOIR_NOT_REACHED_TARGET; + status = DG_RESERVOIR_NOT_REACHED_TARGET; } return status; @@ -1930,20 +1885,29 @@ { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_ABOVE_TARGET; + // If the drain parameters of the reservoir is not initialized, initialize them + if ( FALSE == haveDrainParamsBeenInit[ r ] ) + { + initDrainParameters( r ); + haveDrainParamsBeenInit[ r ] = TRUE; + } + BOOL isDrainComplete = hasTargetDrainVolumeBeenReached( r, drainSteadyStateTimeout ); if ( TRUE == isDrainComplete ) { // Set the state timer in case it needs to be used for another timeout check - stateTimer = getMSTimerCount(); - status = DG_RESERVOIR_REACHED_TARGET; + stateTimer = getMSTimerCount(); + haveDrainParamsBeenInit[ r ] = FALSE; + status = DG_RESERVOIR_REACHED_TARGET; } else if ( TRUE == didTimeout( stateTimer, timeout ) ) { // Failed to drain on time. Update the previous heat disinfect state and transition to basic cancellation - prevHeatDisinfectState = heatDisinfectState; - alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; - status = DG_RESERVOIR_NOT_REACHED_TARGET; + prevHeatDisinfectState = heatDisinfectState; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + haveDrainParamsBeenInit[ r ] = FALSE; + status = DG_RESERVOIR_NOT_REACHED_TARGET; } return status; @@ -1964,14 +1928,27 @@ *************************************************************************/ static HEAT_DISINFECT_STATUS_T getHeatDisinfectStatus( void ) { - HEAT_DISINFECT_STATUS_T status = HEAT_DISINFECT_IN_PROGRESS; + HEAT_DISINFECT_STATUS_T status = HEAT_DISINFECT_HEAT_UP_IN_PROGRESS; F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); F32 ThdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); 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 the temperature gradient in between the coldest and the hottest spot is more than the specified temperature and + // the timer has not started yet, start it + if ( ( TPoTemp - ThdTemp > HEAT_DISINFECT_MAX_TEMP_GRADIENT_C ) && ( 0 == tempGradOutOfRangeTimer ) ) + { + tempGradOutOfRangeTimer = getMSTimerCount(); + } + else if ( ( 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_RANAGE; + 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 ) ) { @@ -1984,9 +1961,9 @@ // 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; + areRsrvrsLeaking = FALSE; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; - status = HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT; + status = HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT; } } // Reservoirs are in range @@ -2002,46 +1979,49 @@ // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts heatDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = FALSE; - heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_HEAT_UP_WATER; + targetDisinfectTime = 0; 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; + status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; } } else if ( ( isPartialDisinfectInProgress != TRUE ) && ( ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) ) { // 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; - // Set the heat disinfect UI state + // In disinfect R1 to R2, concentrate pumps are also run if ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) { - heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_1; -#ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + 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 - requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); -#endif + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); } - else - { - heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_2; - } } + 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 ) ) ) { // Done with this stage of heat disnfect. Reset the variables - status = HEAT_DISINFECT_COMPLETE; + // 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; } @@ -2073,8 +2053,12 @@ if ( ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) || ( DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1 == heatDisinfectState ) ) { - uiData.heatDisinfectTargetTime = HEAT_DISINFECT_TIME_MS; - uiData.heatDisinfectCountdownTime = HEAT_DISINFECT_TIME_MS - calcTimeSince( heatDisinfectTimer ); + // If the disinfect target time is 0, meaning the actual disinfect has not started, set the count down to 0, otherwise, publish + // the actual value + U32 countDown = ( HEAT_DISINFECT_TIME_MS == targetDisinfectTime ? ( targetDisinfectTime - calcTimeSince( heatDisinfectTimer) ) : 0 ); + + uiData.heatDisinfectTargetTime = targetDisinfectTime; + uiData.heatDisinfectCountdownTime = countDown / 1000; // The count down is converted into seconds since the UI does not work with milliseconds data.R1FillLevel = R1HeatDisinfectVol; data.R2FillLevel = R2HeatDisinfectVol; } @@ -2086,13 +2070,41 @@ data.R2FillLevel = 0.0; } - broadcastHeatDisinfectData( &data ); + broadcastData( MSG_ID_DG_HEAT_DISINFECT_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( MODE_HEAT_DISINFECT_DATA_T ) ); // Publish data to UI - broadcastHeatDisinfectData2UI( &uiData ); + broadcastData( MSG_ID_DG_HEAT_DISINFECT_TIME_DATA, COMM_BUFFER_OUT_CAN_DG_2_UI, (U08*)&uiData, sizeof( MODE_HEAT_DISINFECT_UI_DATA_T ) ); dataPublishCounter = 0; } } +/*********************************************************************//** + * @brief + * The monitorModeHeatDisinfect function monitors the status of the caps and + * sets the state of the state machine to water cancellation path if the caps + * are not closed during the run. + * @details Inputs: none + * @details Outputs: prevHeatDisinfectState, heatDisinfectState, + * alarmDetectedPendingTrigger + * @return: none + *************************************************************************/ +static void monitorModeHeatDisinfect( void ) +{ +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + if ( ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ) && ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) + { + // Set the variables to fail and go to cancel water path. Set the pending alarm to no alarm so the cancel water path + // will not be raising the alarm at end of the cancel water path. The recoverable alarm is raised here in this function + U32 cap = (U32)( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ? CONCENTRATE_CAP : DIALYSATE_CAP ); + prevHeatDisinfectState = heatDisinfectState; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_OR_CONC_CAP_NOT_IN_PROPER_POSITION; + } + } +} + /**@}*/