Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r6127d594f1673bd75ffe7be22eec69a2f39e025d -refc7f297febee73bf520b4c5646e49c8f53caf41 --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 6127d594f1673bd75ffe7be22eec69a2f39e025d) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision efc7f297febee73bf520b4c5646e49c8f53caf41) @@ -48,99 +48,95 @@ // ********** private definitions ********** // General defines -#define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. TODO: not used #define CHEM_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 20.0F ///< Minimum water inlet pressure in psi. TODO: set to 30.0 +// Inlet water check defines +#define MIN_INLET_PRESSURE_PSI 14.0F ///< Minimum water inlet pressure in psi. +#define MAX_INLET_PRESSURE_PSI 80.0F ///< Maximum water inlet pressure in psi. +#define MIN_INLET_TEMPERATURE_C 18.0F ///< Minimum water inlet temperature in C. +#define MAX_INLET_TEMPERATURE_C 37.0F ///< Maximum water inlet temperature in C. +#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0F ///< Maximum water inlet conductivity in us/cm +#define MIN_INLET_CONDUCTIVITY_US_PER_CM 100.0F ///< Minimum water inlet conductivity in us/cm // Drain R1 & R2 states defines #define DRAIN_PUMP_TARGET_RPM 2400 ///< Drain pump target RPM during drain. #define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. #define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. #define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. -// Fill R1 & R2 state defines -#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 ( 8 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. -#define RSRVRS_PARTIAL_FILL_UP_TIMEOUT_MS ( 7 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. -#define RSRVRS_ALMOST_FULL_FILL_UP_TIMEOUT_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. -#define RESERVOIR_FULL_VOLUME_CHANGE_LIMIT_ML 5.0F -#define RESERVOIR_MINIMUM_FULL_VOLUME_ML 1700.0F -#define RSRVRS_FILL_TO_FULL_STABLE_TIME_COUNT ( ( 2 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in counts. - // Flush drain path state defines #define FLUSH_DRAIN_WAIT_TIME_MS ( 60 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. -#define MIN_INLET_TEMPERATURE_C 20.0F ///< Minimum water inlet temperature in C. TODO: set to 24.0 -#define MAX_INLET_TEMPERATURE_C 35.0F ///< Maximum water inlet temperature in C. -#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0F ///< Maximum water inlet conductivity in us/cm -#define MIN_INLET_CONDUCTIVITY_US_PER_CM 0.0F ///< Minimum water inlet conductivity in us/cm #define MAX_ALLOWED_FLUSH_DRAIN_PERIODS 2 ///< Number of flush drain periods to wait for inlet water to come into range -#define INLET_WATER_CHECK_FAILURE_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Timer for inlet water check failures before alarm +#define INLET_WATER_CHECK_FAILURE_TASK_INT ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Task interval counter for inlet water check failures before alarm // Flush circulation path state defines #define RO_PUMP_TARGET_FLUSH_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. +#define FLUSH_CICRCULATION_INITIAL_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush/rinse circulation path wait time in milliseconds. #define FLUSH_CICRCULATION_ADDITIONAL_WAIT_TIME_MS ( 60 * MS_PER_SECOND ) ///< Flush/rinse circulation path additional wait time in milliseconds. #define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 3.0F ///< Maximum flush circulation temperature difference tolerance in C. #define NUM_OF_TEMP_SENSORS_TO_AVG 2.0F ///< Number of temperature sensors to average to check the difference. -#define MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM 2000.0F ///< Maximum allowed conductivity in flush circulation state in us/cm TODO: set to 100.0 -#define MAX_ALLOWED_FLUSH_CIRC_PERIODS 3 ///< Number of flush circulation periods to wait for sensors to come into range +#define MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM 100.0F ///< Maximum allowed conductivity in flush circulation state in us/cm +#define MAX_ALLOWED_FLUSH_CIRC_PERIODS 2 ///< Number of flush circulation periods to wait for sensors to come into range -// Prime acid line -#define PRIME_ACID_LINE_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Priming acid line timeout in milliseconds. -#define DISINFECTANT_PUMP_PRIME_SPEED_ML_PER_MIN 19.0F ///< Disinfectant pump prime speed in ml/min. -#define MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM 0.0F //3000.0F ///< Minimum conductivity that indicates acid is in the line in uS/cm. TODO: set to 600.0 -#define PRIME_ACID_STEADY_CONDUCTIVITY_TASK_INT ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Minimum time that a steady conductivity of acid must be read in task intervals. -#define RO_PUMP_TARGET_PRIME_DISINECTANT_FLOW_RATE_LPM 0.8F ///< ROP flow rate for disinfectant prime -#define DISINFECTANT_MIX_RATIO_PRIME 19.0F ///< Disinfectant mixing ratio during prime, water/disinfectant. -#define MAX_RO_PUMP_PRIME_DISINFECTANT_PRESSURE_PSI 130.0F ///< ROP max pressure for disinfectant prime +// Fill R1 & R2 state defines +#define RSRVRS_FULL_STABLE_TIME_TASK_INT ( ( 4 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in task interval counts. +#define RSRVRS_FILL_UP_TIMEOUT_MS ( 8 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. +#define RSRVRS_PARTIAL_FILL_UP_TIMEOUT_MS ( 7 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. +#define RSRVRS_ALMOST_FULL_FILL_UP_TIMEOUT_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. It is assumed the reservoir is nearly full to begin. +#define RESERVOIR_FULL_VOLUME_CHANGE_LIMIT_ML 5.0F ///< The maximum difference between the short-term and long-term filtered reservoir volumes in ml that determines the tank is full. +#define RESERVOIR_MINIMUM_FULL_VOLUME_ML 1700.0F ///< When filling the reservoir, the volume reading must be at least this value before checking for the volume to level off. +#define RSRVRS_FILL_TO_FULL_STABLE_TASK_INT ( ( 2 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in task intervals. -// Stabilize disinfectant mixing and begin to fill tanks with disinfectant -#define MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS 2 -#define MIN_RO_FLOW_FOR_CONC_PUMP_MIXING_LPM 0.3F ///< Minimum RO flow rate that is need to be able to turn on the concentrate pump for mixing. -#define DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN 7.61F -#define DISINFECTANT_MIX_RATIO_FILL 65.67F ///< Disinfectant mixing ratio during fill, water/disinfectant. -#define RO_PUMP_TARGET_FILL_DISINECTANT_FLOW_RATE_LPM 0.5F ///< ROP flow rate for disinfectant prime -#define MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI 130.0F ///< ROP max pressure for disinfectant fill -#define FLUSH_DISINFECTANT_INITIAL_WAIT_TIME ( 30 * MS_PER_SECOND ) ///< Initial time to wait for temperature and conductivity to reach target in disinfectant flush state -#define FLUSH_DISINFECTANT_ADDITIONAL_WAIT_TIME ( 60 * MS_PER_SECOND ) ///< Additional time to wait for temperature and conductivity to reach target in disinfectant flush state -#define MAX_DISINFECT_FLUSH_CYCLE_PERIODS 2 ///< Number of allowed periods to check conductivity and temperature in disinfectant flush state +// Prime acid line state defines +#define PRIME_ACID_LINE_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Priming acid line timeout in milliseconds. +#define DISINFECTANT_PUMP_PRIME_SPEED_ML_PER_MIN 19.0F ///< Default Disinfectant pump prime speed in ml/min. +#define MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM 600.0F ///< Minimum conductivity that indicates acid is in the line in uS/cm +#define PRIME_ACID_STEADY_CONDUCTIVITY_TASK_INT ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Minimum time that a steady conductivity of acid must be read in task intervals. +#define RO_PUMP_PRIME_DISINECTANT_FLOW_RATE_LPM 0.8F ///< ROP flow rate for disinfectant prime +#define MAX_RO_PUMP_PRIME_DISINFECTANT_PRESSURE_PSI 130.0F ///< ROP max pressure for disinfectant prime +#define DISINFECTANT_MIX_RATIO_PRIME 19.0F ///< Disinfectant mixing ratio during prime, water/disinfectant. -// RO pump speed and pressure during disinfect cycle +// Stabilize disinfectant mixing state defines +#define MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS 2 ///< Number of allowed periods to check conductivity and temperature in disinfectant flush state +#define DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN 7.61F ///< Default concentrate pump speed for mixing disinfectant. +#define DISINFECTANT_MIX_RATIO_FILL 65.67F ///< Disinfectant mixing ratio during fill, water/disinfectant. +#define RO_PUMP_FILL_DISINECTANT_FLOW_RATE_LPM 0.4F ///< ROP flow rate for disinfectant prime +#define MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI 130.0F ///< ROP max pressure for disinfectant fill +#define FLUSH_DISINFECTANT_INITIAL_WAIT_TIME ( 30 * MS_PER_SECOND ) ///< Initial time to wait for temperature and conductivity to reach target in disinfectant flush state +#define FLUSH_DISINFECTANT_ADDITIONAL_WAIT_TIME ( 60 * MS_PER_SECOND ) ///< Additional time to wait for temperature and conductivity to reach target in disinfectant flush state + +// Parameters during disinfect defines #define CHEM_DISINFECT_TARGET_RO_FLOW_LPM 0.5F ///< Chemical disinfect target RO flow rate in L/min. #define CHEM_DISINFECT_MAX_RO_PRESSURE_PSI 130 ///< Chemical disinfect maximum RO pressure in psi. +#define MIN_DISINFECT_CONDUCTIVITY_US_PER_CM 150.0F ///< Minimum conductivity for mixed disinfect fluid in us/cm +#define MAX_DISINFECT_CONDUCTIVITY_US_PER_CM 650.0F ///< Maximum conductivity for mixed disinfect fluid in us/cm +#define MAX_DISINFECT_TPO_TEMPERATURE_C 55.0F ///< Maximum temperature for mixed disinfect fluid at outlet of heater in dec C +#define MIN_MAX_CONDUCTIVITY_WAIT_TASK_INT ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Number of task intervals to wait for conductivity and temperature to stabilize -// Contuctivity and temperature absolute limits during disinfection -#define MIN_DISINFECT_CONDUCTIVITY_US_PER_CM 0.0F //1000.0F ///< Minimum conductivity for mixed disinfect fluid in us/cm TODO: set to 150.0 -#define MAX_DISINFECT_CONDUCTIVITY_US_PER_CM 50000.0F ///< Minimum conductivity for mixed disinfect fluid in us/cm TODO: set to 650.0 -#define MIN_DISINFECT_TPO_TEMPERATURE_C 35.0F ///< Minimum temperature for mixed disinfect fluid at outlet of heater in dec C TODO: set to 35.0 -#define MAX_DISINFECT_TPO_TEMPERATURE_C 45.0F ///< Maximum temperature for mixed disinfect fluid at outlet of heater in dec C TODO: set to 45.0 -#define MIN_MAX_CONDUCTIVITY_WAIT_TIME_MS ( 10 * MS_PER_SECOND ) - // Initial disinfectant fill of R1 and R2 -#define RSRVRS_FULL_VOL_ML 1750.0F ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 -#define RSRVRS_PARTIAL_FILL_VOL_ML 1000.0F ///< Reservoirs 1 & 2 partial volume in mL. TODO: remove -#define RSRVRS_LEAK_VOL_TIMEOUT_MS ( 30 * MS_PER_SECOND ) -#define RSRVRS_MAX_LEAK_VOL_CHANGE_ML 100.0F; +#define RSRVRS_FULL_VOL_ML 1800.0F ///< Reservoirs 1 & 2 full volume in mL. +#define RSRVRS_LEAK_VOL_TIMEOUT_TASK_INT ( ( 30 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Time delay for declaring that tank is leaking due to volume depletion. +#define RSRVRS_MAX_LEAK_VOL_CHANGE_ML 100.0F; ///< Volume loss that is necessary to declare a tank leak. // Parameters controlling chemical disinfect #define TARGET_CHEM_DISINFECT_TIME_MS ( 12 * SEC_PER_MIN * MS_PER_SECOND ) ///< Expected chemical disinfect time in ms. #define CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ( 6 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect reaching to minimum temperature timeout in milliseconds. -#define CHEM_DISINFECT_TARGET_TEMPERATURE_C 32.0F ///< Chemical disinfect target water temperature in C. // TODO this should be 35 +#define CHEM_DISINFECT_TARGET_TEMPERATURE_C 37.0F ///< Chemical disinfect target water temperature in C. +#define CHEM_DISINFECT_MINIMUM_TEMPERATURE_C 35.0F ///< Chemical disinfect target water temperature in C. #define CHEM_DISINFECT_HEATER_CONTROL_TEMPERATURE_C 45.0F ///< Chemical disinfect heater control water temperature in C. -#define DISINFECT_CYCLE_PERIOD_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time for each disinfectant filling and partial draining cycle -#define REQUIRED_DISINFECT_CYCLES 2 +#define DISINFECT_CYCLE_PERIOD_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time for each disinfectant filling and partial draining cycle. This is the time that the reservoir is full and the temperature is above the target. +#define REQUIRED_DISINFECT_CYCLES 2 ///< Number of times each tank is to be filled with disinfectant. +#define MAX_DISINFECT_STATE_TIME_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Maximum time in each tank disinfect cycle. // A PI control loop is used control the DRP speed while the tank is filling and draining, to maintain a constant level of disinfectant in the tank -#define RESERVOIR_VOLUME_BELOW_FULL_ML 250.0F ///< Volume to maintain in reservoir relative to full volume TODO: set to 100 or 150 -#define DRP_VOLUME_CONTROL_TARGET_VOLUME_ML 1700.0F ///< Tank level to maintain using DRP volume control, default value -#define DRP_VOLUME_CONTROL_INTERVAL_MS ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Update rate for DRP volume control in ms. -#define DRP_VOLUME_CONTROL_P_COEFFICIENT -0.8F ///< P term for DRP volume control. -#define DRP_VOLUME_CONTROL_I_COEFFICIENT 0.1F ///< I term for DRP volume control. -#define MIN_DRP_VOLUME_CONTROL_RPM 350.0F ///< Minimum DRP RPM for volume control. The minimum value allowed by the pump driver is 300 RPM -#define MAX_DRP_VOLUME_CONTROL_RPM 1500.0F ///< Maximum DRP RPM for volume control. The maximum recommended value is 2400 RPM +#define RESERVOIR_VOLUME_BELOW_FULL_ML 150.0F ///< Volume to maintain in reservoir relative to full volume +#define DRP_VOLUME_CONTROL_TARGET_VOLUME_ML 1800.0F ///< Tank level to maintain using DRP volume control, default value +#define DRP_VOLUME_CONTROL_INTERVAL_TASK_INT ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Update rate for DRP volume control in ms. +#define DRP_VOLUME_CONTROL_P_COEFFICIENT -2.5F ///< P term for DRP volume control. +#define DRP_VOLUME_CONTROL_I_COEFFICIENT -0.2F ///< I term for DRP volume control. +#define MIN_DRP_VOLUME_CONTROL_RPM 350.0F ///< Minimum DRP RPM for volume control. The minimum value allowed by the pump driver is 300 RPM +#define MAX_DRP_VOLUME_CONTROL_RPM 1500.0F ///< Maximum DRP RPM for volume control. The maximum recommended value is 2400 RPM /// Cancellation paths typedef enum Cancellation_modes @@ -167,37 +163,32 @@ static U32 overallChemDisinfectTimer = 0; ///< Chemical disinfect cycle total timer. static U32 stateTimer = 0; ///< Chemical disinfect state timer to be used in different states. static U32 stateTrialCounter = 0; ///< Chemical disinfect state trial counter to be used for retries in different states. -/// Boolean flag to check whether draining R1 and R2 is at the end of the chemical disinfect cycle or in the beginning. So the drain states can be reused. -static BOOL isThisLastDrain = FALSE; -static BOOL haveInletWaterChecksPassed = FALSE; ///< Chemical disinfect inlet water checks flag -static U32 inletWaterChecksFailTimer = 0; ///< Timer for inlet water check failures +static BOOL isThisLastDrain = FALSE; ///< Boolean flag to check whether draining R1 and R2 is at the end of the chemical disinfect cycle or in the beginning. +static BOOL haveInletWaterChecksPassed = FALSE; ///< Chemical disinfect inlet water checks flag. +static U32 inletWaterChecksFailCounter = 0; ///< Timer/counter for inlet water check failures. 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 R1ChemDisinfectVol = 0.0; ///< Reservoir 1 full volume during chemical disinfect. -static F32 R2ChemDisinfectVol = 0.0; ///< Reservoir 2 full volume during chemical disinfect. -static BOOL isRsrvrLeaking = FALSE; -static U32 rsrvrsVolMonitorTimer = 0; -static U32 chemDisinfectR1Timer = 0; ///< Chemical disinfect timer for reservoir 1. -static U32 chemDisinfectR2Timer = 0; ///< Chemical disinfect timer for reservoir 1. -static U32 chemDisinfectWarmupTimer = 0; ///< Chemical disinfect warmup timer. -static BOOL isPartialR1DisinfectInProgress = FALSE; ///< Chemical disinfect R1 partial complete/in progess flag. -static BOOL isPartialR2DisinfectInProgress = FALSE; ///< Chemical disinfect R2 partial complete/in progess flag. -static U32 DisinfectCycleCounter = 0; -static U32 drpControlTimerCounter = 0; -static U32 dataPublishCounter = 0; ///< Chemical Disinfect data publish counter. -static BOOL areTempSensorsInRange; +static F32 R1ChemDisinfectVol = 0.0; ///< Reservoir 1 full volume during chemical disinfect. TODO: decide if these volumes are needed +static F32 R2ChemDisinfectVol = 0.0; ///< Reservoir 2 full volume during chemical disinfect. TODO: decide if these volumes are needed +static BOOL isRsrvrLeaking = FALSE; ///< Flag used to determine if reservoir is leaking. +static U32 rsrvrsVolMonitorCounter = 0; ///< Timer/counter used to determine if reservoir is leaking. +static U32 chemDisinfectReservoirTime = 0; ///< Chemical disinfect accumulated time in ms above the temperature target in one cycle for reservoir 1 or reservoir 2. +static BOOL ischemDisinfectWarmupTargetReached = FALSE; ///< Flag that indicates whether the disinfect warmup target has been reached. +static BOOL isChemDisinfectTemperatureAboveTarget = FALSE; ///< Flag that indicates if the disinfect temperature is currently above the target. +static U32 DisinfectCycleCounter = 0; ///< Counter for disinfect cycles. +static U32 drpControlTimerCounter = 0; ///< Timer/counter for tank volume control of DRP. +static U32 dataPublishCounter = 0; ///< Chemical Disinfect data publish timer/counter. static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. static U32 rsrvrFillStableTimeCounter; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Chemical disinfect alarm to raise. -static U32 flushCircWaitTime; ///< Variable time period to wait in flush circulation state to check sensor values -static U32 flushDisinfectantWaitTime; ///< Variable time period to wait in disinfectant flush state to check sensor values +static U32 flushCircWaitTime; ///< Variable time period in ms to wait in flush circulation state to check sensor values. +static U32 flushDisinfectantWaitTime; ///< Variable time period in ms to wait in disinfectant flush state to check sensor values. static U32 primeAcidSteadyStateCounter = 0; ///< Prime acid steady state counter. -static U32 minMaxConductivityWaitTimer = 0; -static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. -static U32 rsrvrFillToFullStableTimeCounter = 0; -static F32 R1FullVolume = 0.0; -static F32 R2FullVolume = 0.0; -static F32 disinfectantMixRatio = 0.0; +static U32 minMaxConductivityWaitCounter = 0; ///< Timer/counter for the disinfect conductivity check. +static U32 rsrvrFillToFullStableTimeCounter = 0; ///< Task interval timer/counter for determining if reservoir is full. +static F32 R1FullVolume = 0.0; ///< R1 volume determined by fill to full function. +static F32 R2FullVolume = 0.0; ///< R2 volume determined by fill to full function. +static F32 disinfectantMixRatio = 0.0; ///< Current disinfectant mixing ratio. static DISINFECT_NV_OPS_T disinfectNVOps; ///< Disinfect non-volatile memory operations. // ********** private function prototypes ********** @@ -224,7 +215,7 @@ static DG_RESERVOIR_STATUS_T getRsrvrFillToFullStatus( DG_RESERVOIR_ID_T r, U32 timeout ); static void controlDRPByReservoirVolume( DG_RESERVOIR_ID_T r, BOOL initialize ); static void handleDisinfectantMixing( F32 measuredROFlowRate_mL_min, F32 disinfectantMixingRatio ); -static void chemicalDisinfectTimerUpdate( DG_RESERVOIR_ID_T r ); +static void chemicalDisinfectTimerUpdate( void ); static void publishChemicalDisinfectData( void ); static void monitorModeChemicalDisinfect( void ); static void writeDisinfectDataToNV( void ); @@ -250,24 +241,20 @@ stateTimer = 0; isThisLastDrain = FALSE; stateTrialCounter = 0; - areTempSensorsInRange = FALSE; rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; R1ChemDisinfectVol = 0.0; R2ChemDisinfectVol = 0.0; overallChemDisinfectTimer = 0; - chemDisinfectWarmupTimer = 0; - chemDisinfectR1Timer = 0; - chemDisinfectR2Timer = 0; cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillStableTimeCounter = 0; - isPartialR1DisinfectInProgress = FALSE; - isPartialR2DisinfectInProgress = FALSE; primeAcidSteadyStateCounter = 0; disinfectantMixRatio = 0.0; + isRsrvrLeaking = FALSE; + chemDisinfectReservoirTime = 0; + ischemDisinfectWarmupTargetReached = FALSE; + isChemDisinfectTemperatureAboveTarget = FALSE; chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_NOT_RUNNING; - haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; - haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; disinfectNVOps.hasDisCompleteDateBeenWrittenToNV = FALSE; disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; } @@ -432,24 +419,25 @@ { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; - // Set the chemical disinfect that is published on the UI - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_NOT_RUNNING; + // Set the chemical disinfect state that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT; // Start overall chemical disinfect timer overallChemDisinfectTimer = getMSTimerCount(); // Set all the actuators to reset and de-energized state deenergizeActuators(); + setValveState( VPI, VALVE_STATE_CLOSED ); // Set the actuators to drain R1 setValveState( VRD1, VALVE_STATE_OPEN ); setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - rsrvrFillStableTimeCounter = 0; // Assume reservoir 1 is full and drain it rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + + state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; stateTimer = getMSTimerCount(); return state; @@ -462,34 +450,31 @@ * transition is finished within the time, it transitions to the next state, * otherwise, it transitions to basic cancellation path. * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, isThisLastDrain - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * chemDisinfectUIState + * @details Outputs: rsrvr1Status, rsrvr2Status, chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDrainR1State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; - // Set the chemical disinfect that is published on the UI - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT; - - if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + 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 ) - { - tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); - tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); - - // Done with draining R1 + { // Done with draining R1 + if ( FALSE == isThisLastDrain ) + { + tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); + } setValveState( VRD1, VALVE_STATE_CLOSED ); setValveState( VRD2, VALVE_STATE_OPEN ); - // Assume reservoir 2 is full and drain it rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_CHEM_DISINFECT_STATE_DRAIN_R2; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DRAIN_R2; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -506,8 +491,7 @@ * disinfect 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, - * stateTrialCounter + * @details Inputs: stateTimer, rsrvr2Status, isThisLastDrain * @details Outputs: stateTimer, rsrvr2Status, stateTrialCounter, * chemDisinfectUIState * @return next state of the chemical disinfect state machine @@ -525,9 +509,7 @@ signalDrainPumpHardStop(); if ( TRUE == isThisLastDrain ) { - // Set the chemical disinfect that is published on the UI // This is the final drain of chemical disinfect - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; // ??? this may not be correct setValveState( VRD2, VALVE_STATE_CLOSED ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); state = DG_CHEM_DISINFECT_STATE_COMPLETE; @@ -579,40 +561,39 @@ // Check if flush time has elapsed if ( TRUE == didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) { - if ( TRUE == haveInletWaterChecksPassed ) - { + // haveInletWaterChecksPassed is set in the monitor function + if ( TRUE == haveInletWaterChecksPassed ) + { // set pumps and valves for next state, flush circulation setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); // Start heating the water while we are flushing setHeaterTargetTemperature( DG_PRIMARY_HEATER, CHEM_DISINFECT_HEATER_CONTROL_TEMPERATURE_C ); startHeater( DG_PRIMARY_HEATER ); + // The UV reactors will be on for the entire disinfect cycle turnOnUVReactor( INLET_UV_REACTOR ); turnOnUVReactor( OUTLET_UV_REACTOR ); - flushCircWaitTime = FLUSH_CICRCULATION_WAIT_TIME_MS; + flushCircWaitTime = FLUSH_CICRCULATION_INITIAL_WAIT_TIME_MS; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION; } else - { + { // The inlet water checks failed // If the number of failures have not exceeded the limit, try again. - ++stateTrialCounter; - if ( stateTrialCounter < MAX_ALLOWED_FLUSH_DRAIN_PERIODS ) + if ( ++stateTrialCounter < MAX_ALLOWED_FLUSH_DRAIN_PERIODS ) { stateTimer = getMSTimerCount(); } - // Couldn't get a good water sample after a couple of trials and the disinfect flush cycle failed else - { - //alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_INLET_COND_AND_TEMP_OUT; // Do we need an alarm like this? - alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; // Or a generic alarm? ALARM_ID_DG_NEW_WAT; + { // Couldn't get a good water sample after a couple of trials so the disinfect flush drain cycle failed + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; // TODO: ALARM_ID_DG_NEW_WAT; prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; } } - } + return state; } @@ -625,9 +606,8 @@ * transitions to basic cancellation path, otherwise, it transitions to the * next state. * @details Inputs: stateTimer, stateTrialCounter, prevChemDisinfectState - * alarm, areTempSensorsInRange, rsrvr1Status, rsrvr2Status * @details Outputs: stateTimer, stateTrialCounter, prevChemDisinfectState, - * alarm, areTempSensorsInRange, rsrvr1Status, rsrvr2Status + * alarm, * @return next state of the chemical disinfect state machine ************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushCirculationState( void ) @@ -637,16 +617,23 @@ // Check if the flush circulation time has elapsed and the temperature sensors are not in range yet if ( TRUE == didTimeout( stateTimer, flushCircWaitTime ) ) { - F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); - F32 avgTemp = ( TPoTemp + TD2Temp ) / NUM_OF_TEMP_SENSORS_TO_AVG; - F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); - F32 cpoConductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CPO_SENSOR ); + F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); + F32 avgTemp = ( TPoTemp + TD2Temp ) / NUM_OF_TEMP_SENSORS_TO_AVG; + F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); + F32 cpoConductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CPO_SENSOR ); // Check if any of the temperature sensors deviate for more than the defined value from the average of all // of the temperature sensors - BOOL isTPoOut = ( fabs( TPoTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); - BOOL isTD2Out = ( fabs( TD2Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); + BOOL isTPoOut = FALSE; + BOOL isTD2Out = FALSE; +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_TEMPERATURE_SENSORS_ALARM ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + isTPoOut = ( fabs( TPoTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); + isTD2Out = ( fabs( TD2Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); + } BOOL isCD2Out = ( cd2Conductivity > MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM ? TRUE : FALSE ); BOOL isCPoOut = ( cpoConductivity > MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM ? TRUE : FALSE ); // Check if any of the temperature sensors are out of tolerance @@ -659,29 +646,29 @@ stateTimer = getMSTimerCount(); flushCircWaitTime = FLUSH_CICRCULATION_ADDITIONAL_WAIT_TIME_MS; } - - else // State failed. Cancel chemical disinfect mode - // determine which alarm it is, temperature or conductivity, one of them has to take precedence - { + else + { // State failed. Cancel chemical disinfect mode + // determine which alarm it is, temperature or conductivity, one of them has to take precedence if ( ( TRUE == isTPoOut ) || ( TRUE == isTD2Out ) ) { alarmDetectedPendingTrigger = ALARM_ID_DG_TEMP_SENSORS_DIFF_OUT_OF_RANGE; } else { - alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE; //ALARM_ID_DG_NEW_CON; + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE; //TODO: ALARM_ID_DG_NEW_CON; } prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; } } else { - setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_PRIME_DISINECTANT_FLOW_RATE_LPM, MAX_RO_PUMP_PRIME_DISINFECTANT_PRESSURE_PSI ); + setROPumpTargetFlowRateLPM( RO_PUMP_PRIME_DISINECTANT_FLOW_RATE_LPM, MAX_RO_PUMP_PRIME_DISINFECTANT_PRESSURE_PSI ); // Set the acid dispense pump speed at the priming rate setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, DISINFECTANT_PUMP_PRIME_SPEED_ML_PER_MIN ); requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); disinfectantMixRatio = DISINFECTANT_MIX_RATIO_PRIME; + primeAcidSteadyStateCounter = 0; state = DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT; stateTimer = getMSTimerCount(); @@ -697,11 +684,11 @@ * chemical disinfect prime acid line state. The state primes the acid line * until a minimum conductivity is sensed for a period of time. The the * function transitions to another state. If the minimum conductivity was - * not reached within the defined period of time, it transition to a + * not reached within the defined period of time, it transitions to a * cancellation path. * @details Inputs: stateTimer, primeAcidSteadyStateCounter - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState, primeAcidSteadyStateCounter, chemDisinfectUIState + * @details Outputs: stateTimer, prevChemDisinfectState, + * primeAcidSteadyStateCounter, chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeDisinfectantState( void ) @@ -714,74 +701,81 @@ handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); - if ( cd2Conductivity <= MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM ) +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE != getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) { - primeAcidSteadyStateCounter = 0; +#endif + if ( cd2Conductivity < MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM ) + { + primeAcidSteadyStateCounter = 0; + } } - else + // Check if the acid conductivity value has been above the threshold for the specified time period + if ( ++primeAcidSteadyStateCounter >= PRIME_ACID_STEADY_CONDUCTIVITY_TASK_INT ) { - // Check if the acid conductivity value has been above the threshold for the specified time period - if ( ++primeAcidSteadyStateCounter >= PRIME_ACID_STEADY_CONDUCTIVITY_TASK_INT ) - { + // Turn off the concentrate pump + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + // Turn on the RO pump and concentrate pump to the disinfectant fill rates + setROPumpTargetFlowRateLPM( RO_PUMP_FILL_DISINECTANT_FLOW_RATE_LPM, MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + disinfectantMixRatio = DISINFECTANT_MIX_RATIO_FILL; + flushDisinfectantWaitTime = FLUSH_DISINFECTANT_INITIAL_WAIT_TIME; - // Turn off the concentrate pump - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - // Turn on the RO pump and concentrate pump to the disinfectant fill rates - setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FILL_DISINECTANT_FLOW_RATE_LPM, MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); - - disinfectantMixRatio = DISINFECTANT_MIX_RATIO_FILL; - flushDisinfectantWaitTime = FLUSH_DISINFECTANT_INITIAL_WAIT_TIME; - stateTrialCounter = 0; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; - } + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; } if ( TRUE == didTimeout( stateTimer, PRIME_ACID_LINE_TIMEOUT_MS ) ) { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_PRIME_ACID_LINE_TIME_OUT; + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_PRIME_ACID_LINE_TIME_OUT; } return state; } /*********************************************************************//** * @brief - * The handleChemicalDisinfectPrimeAcidLineState function handles the - * chemical disinfect prime acid line state. The state primes the acid line - * until a minimum conductivity is sensed for a period of time. The the - * function transitions to another state. If the minimum conductivity was - * not reached within the defined period of time, it transition to a - * cancellation path. - * @details Inputs: stateTimer, primeAcidSteadyStateCounter - * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * prevChemDisinfectState, primeAcidSteadyStateCounter, chemDisinfectUIState + * The handleChemicalDisinfectDisinfectantFlushState function handles the + * chemical disinfect disinfectant flush state. The state adds disinfectant + * to the heated RO product water and flushes it to drain while monitoring the + * conductivity and temperature. If the conductivity and temperature are + * within the specified range within the specified time, the function transitions + * to another state. If the minimum conductivity and temperature are not + * reached within the defined period of time, it transition to a cancellation path. + * @details Inputs: stateTimer, primeAcidSteadyStateCounter, + * temperature, conductivity + * @details Outputs: stateTimer, prevChemDisinfectState, chemDisinfectUIState, + * alarm * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantFlushState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; - // Set the chemical disinfect that is published on the UI + // Set the chemical disinfect state that is published on the UI chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_MIX_WATER_AND_ACID; handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); if ( TRUE == didTimeout( stateTimer, flushDisinfectantWaitTime ) ) { F32 TdiTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); - F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); + F32 cd2Conductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); BOOL isCD2OutofRange = ( cd2Conductivity < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM || cd2Conductivity > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ); - BOOL isTPoOutofRange = ( TPoTemp < MIN_DISINFECT_TPO_TEMPERATURE_C || TPoTemp > MAX_DISINFECT_TPO_TEMPERATURE_C ); +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + { + isCD2OutofRange = FALSE; + } +#endif + BOOL isTPoOutofRange = ( TPoTemp > MAX_DISINFECT_TPO_TEMPERATURE_C ); if ( ( TRUE == isCD2OutofRange ) || ( TRUE == isTPoOutofRange ) ) - { + { // The conditions have not been met // Check if we have exceeded the number of trials. If not, try another time - ++stateTrialCounter; - if (stateTrialCounter < MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS ) + if (++stateTrialCounter < MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS ) { stateTimer = getMSTimerCount(); flushDisinfectantWaitTime = FLUSH_DISINFECTANT_ADDITIONAL_WAIT_TIME; @@ -794,7 +788,7 @@ } else { - alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE; //ALARM_ID_DG_NEW_CON; TODO + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE; //TODO: ALARM_ID_DG_NEW_CON } state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } @@ -808,12 +802,13 @@ setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRD1, VALVE_STATE_CLOSED ); setValveState( VRD2, VALVE_STATE_CLOSED ); + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + chemDisinfectReservoirTime = 0; + isChemDisinfectTemperatureAboveTarget = FALSE; - rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - isPartialR1DisinfectInProgress = FALSE; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; } } @@ -822,7 +817,7 @@ /*********************************************************************//** * @brief - * The handleChemicalDisinfectFillWithWaterAndDisinfectantState function + * The handleChemicalDisinfectFillWithDisinfectantState function * handles the chemical disinfect fill with water state. The state fills * reservoir 1 until it overflows to reservoir 2. If the filling process * times out, it transitions to water cancellation state, otherwise, it @@ -838,6 +833,9 @@ { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; + // Set the chemical disinfect state that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; + handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); // First reservoir 1 must be full @@ -851,72 +849,86 @@ { // Once R1 is full, keep monitoring for R2 level and timeout rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_PARTIAL_FILL_UP_TIMEOUT_MS ); - chemicalDisinfectTimerUpdate( DG_RESERVOIR_1 ); + chemicalDisinfectTimerUpdate( ); // Once R2 is full, transition to the next state if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - // go to the next disinfect configuration cycle, fill R1 and drain R2 + // go to the next disinfect cycle, fill R1 and drain R2 setValveState( VRD2, VALVE_STATE_OPEN ); + setROPumpTargetFlowRateLPM( CHEM_DISINFECT_TARGET_RO_FLOW_LPM, MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI ); + // Set the drain pump to control mode controlDRPByReservoirVolume( DG_RESERVOIR_2, TRUE ); //Initialize the PI controller for DRP + R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + isRsrvrLeaking = FALSE; + ischemDisinfectWarmupTargetReached = FALSE; - chemDisinfectWarmupTimer = getMSTimerCount(); - isPartialR1DisinfectInProgress = FALSE; - R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - isRsrvrLeaking = FALSE; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } return state; } /*********************************************************************//** * @brief - * The handleChemicalDisinfectR2DisinfectantFillR1DrainState function handles the - * chemical disinfect R1 to R2 state. The state runs reservoir 1 to reservoir 2 - * chemical disinfect. If the reservoirs leak or it cannot reach to temperature + * The handleChemicalDisinfectDisinfectR1ToR2State function handles the + * chemical disinfect disinfect R1 to R2 state. The state fills reservoir 1 + * to reservoir 2. If the reservoirs leak or it cannot reach to temperature * within a certain period of time, it transitions to water cancellation. * If chemical disinfect reservoir 1 to reservoir 2 is completed, it * transitions to the next state. * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * chemDisinfectUIState + * chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR1ToR2State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; - handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); - // Set the chemical disinfect that is published on the UI chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; - chemicalDisinfectTimerUpdate( DG_RESERVOIR_1 ); - if ( TRUE == didTimeout( chemDisinfectR1Timer, DISINFECT_CYCLE_PERIOD_MS ) ) + handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); + chemicalDisinfectTimerUpdate( ); + + if ( (TRUE != ischemDisinfectWarmupTargetReached ) && ( TRUE == didTimeout( stateTimer, CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ) ) ) { + // Heating up to minimum temperature for chemical disinfect failed + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + } + + if ( TRUE == didTimeout( stateTimer, MAX_DISINFECT_STATE_TIME_MS ) ) + { + // Heating up to minimum temperature for chemical disinfect failed + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + } + + if ( chemDisinfectReservoirTime >= DISINFECT_CYCLE_PERIOD_MS ) + { // Set the actuators to fill R2 and drain R1 state setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRD1, VALVE_STATE_OPEN ); setValveState( VRD2, VALVE_STATE_CLOSED ); + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R1_FILL_R2_TO_R1; } @@ -928,6 +940,19 @@ return state; } +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectPartialDrainR1FillR2ToR1State function handles the + * chemical disinfect partial drain R1 fill R2 to R1 state. + * The state drains reservoir 1 to a specified volume, fills reservoir 2, and + * fills reservoir 2 to reservoir 1, If reservoir 2 cannot be filled + * within a certain period of time, it transitions to water cancellation. + * If reservoir 2 is filled within the specified time, it + * transitions to the next state. + * @details Inputs: stateTimer, rsrvr2Status + * @details Outputs: stateTimer, chemDisinfectUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR1FillR2ToR1State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R1_FILL_R2_TO_R1; @@ -942,11 +967,14 @@ } if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - isPartialR2DisinfectInProgress = FALSE; - R2ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - isRsrvrLeaking = FALSE; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; + R2ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + isRsrvrLeaking = FALSE; + chemDisinfectReservoirTime = 0; + isChemDisinfectTemperatureAboveTarget = FALSE; + ischemDisinfectWarmupTargetReached = FALSE; + + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -962,15 +990,15 @@ /*********************************************************************//** * @brief - * The handleChemicalDisinfectR2DisinfectantFillR1DrainState function handles the - * chemical disinfect R1 to R2 state. The state runs reservoir 1 to reservoir 2 - * chemical disinfect. If the reservoirs leak or it cannot reach to temperature + * The handleChemicalDisinfectDisinfectR2ToR1State function handles the + * chemical disinfect disinfect R2 to R1 state. The state fills reservoir 1 + * to reservoir 2. If the reservoirs leak or it cannot reach to temperature * within a certain period of time, it transitions to water cancellation. - * If chemical disinfect reservoir 1 to reservoir 2 is completed, it + * If chemical disinfect reservoir 2 to reservoir 1 is completed, it * transitions to the next state. * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * chemDisinfectUIState + * chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR2ToR1State( void ) @@ -981,30 +1009,54 @@ chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); + chemicalDisinfectTimerUpdate( ); - chemicalDisinfectTimerUpdate( DG_RESERVOIR_2 ); + if ( (TRUE != ischemDisinfectWarmupTargetReached ) && ( TRUE == didTimeout( stateTimer, CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ) ) ) + { + // Heating up to minimum temperature for chemical disinfect failed + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + } - if ( TRUE == didTimeout( chemDisinfectR2Timer, DISINFECT_CYCLE_PERIOD_MS ) ) + if ( TRUE == didTimeout( stateTimer, MAX_DISINFECT_STATE_TIME_MS ) ) { + // Heating up to minimum temperature for chemical disinfect failed + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + } + + if ( chemDisinfectReservoirTime >= DISINFECT_CYCLE_PERIOD_MS ) + { if ( REQUIRED_DISINFECT_CYCLES == ++DisinfectCycleCounter ) { //Disinfect is complete // turn pumps and valves off stopHeater( DG_PRIMARY_HEATER ); setValveState( VPI, VALVE_STATE_CLOSED ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRD2, VALVE_STATE_CLOSED ); - setValveState( VRD1, VALVE_STATE_CLOSED ); + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); signalROPumpHardStop(); - signalDrainPumpHardStop(); requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + // Prepare to drain reservoir 1 + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + // Because this is the second reservoir drain in this mode, the drain parameters must be reset + initDrainParameters( DG_RESERVOIR_1 ); + initDrainParameters( DG_RESERVOIR_2 ); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - isThisLastDrain = TRUE; - state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + isThisLastDrain = TRUE; + // Set the chemical disinfect state that is published on the UI + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; + + writeDisinfectDataToNV(); + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; } else { @@ -1014,6 +1066,7 @@ setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRD1, VALVE_STATE_CLOSED ); setValveState( VRD2, VALVE_STATE_OPEN ); + stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R2_FILL_R1_TO_R2; } @@ -1026,6 +1079,19 @@ return state; } +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectPartialDrainR2FillR1ToR2State function handles the + * chemical disinfect partial drain R2 fill R1 to R2 state. + * The state drains reservoir 2 to a specified volume, fills reservoir 1, and + * fills reservoir 1 to reservoir 2. If reservoir 1 cannot be filled + * within a certain period of time, it transitions to water cancellation. + * If reservoir 1 is filled within the specified time, it + * transitions to the next state. + * @details Inputs: stateTimer, rsrvr1Status + * @details Outputs: stateTimer, chemDisinfectUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR2FillR1ToR2State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R2_FILL_R1_TO_R2; @@ -1040,21 +1106,25 @@ } if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - isPartialR1DisinfectInProgress = FALSE; - R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - isRsrvrLeaking = FALSE; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; + chemDisinfectReservoirTime = 0; + isChemDisinfectTemperatureAboveTarget = FALSE; + ischemDisinfectWarmupTargetReached = FALSE; + R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + isRsrvrLeaking = FALSE; + + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } else { controlDRPByReservoirVolume( DG_RESERVOIR_2, FALSE ); } + return state; } @@ -1085,7 +1155,8 @@ /*********************************************************************//** * @brief * The handleChemicalDisinfectCancelModeWaterPathState function handles the - * chemical disinfect cancel mode cold water path state. + * chemical disinfect cancel mode cold water path state. It drains the tanks + * before the cancel basic path mode is entered. * @details Inputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer, * chemDisinfectUIState @@ -1193,10 +1264,10 @@ /*********************************************************************//** * @brief * The getRsrvrFillStatus function checks whether the target reservoir - * is full or not. If the fill times out, it sets the state machine to - * complete and exits the chemical disinfect mode. + * is full or not. If the fill times out, it sets the alarm for the + * reservoir fill time out, and returns the time out status. * @details Inputs: rsrvrFillStableTimeCounter, alarm, stateTimer - * @details Outputs: none + * @details Outputs: alarm * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 * @param targetVol is the target fill volume * @param timeout is the fill up timeout @@ -1223,7 +1294,7 @@ // Check the volume of the reservoir against the target volume if ( volume >= targetVol ) { - if ( ++rsrvrFillStableTimeCounter >= RSRVRS_FULL_STABLE_TIME_COUNT ) + if ( ++rsrvrFillStableTimeCounter >= RSRVRS_FULL_STABLE_TIME_TASK_INT ) { status = DG_RESERVOIR_REACHED_TARGET; rsrvrFillStableTimeCounter = 0; @@ -1234,9 +1305,9 @@ else if ( TRUE == didTimeout( stateTimer, timeout ) ) { // Failed to fill ontime. Update the previous chemical disinfect state and transition to basic cancellation - prevChemDisinfectState = chemDisinfectState; - alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_FILL_TIMEOUT; - status = DG_RESERVOIR_NOT_REACHED_TARGET; + prevChemDisinfectState = chemDisinfectState; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_FILL_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; } return status; @@ -1246,8 +1317,7 @@ * @brief * The getRsrvrDrainStatus function returns the status of draining a * reservoir. - * @details Inputs: stateTimer, prevChemDisinfectState, chemDisinfectState, - * alarm + * @details Inputs: stateTimer, prevChemDisinfectState, chemDisinfectState * @details Outputs: stateTimer, chemDisinfectState, alarm * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 * @param drainSteadyStateTimeout which is the time the reservoir's level @@ -1260,45 +1330,35 @@ { 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(); - haveDrainParamsBeenInit[ r ] = FALSE; status = DG_RESERVOIR_REACHED_TARGET; } else if ( TRUE == didTimeout( stateTimer, timeout ) ) { // Failed to drain on time. Update the previous chemical disinfect state and transition to basic cancellation - prevChemDisinfectState = chemDisinfectState; - haveDrainParamsBeenInit[ r ] = FALSE; - alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; - status = DG_RESERVOIR_NOT_REACHED_TARGET; + prevChemDisinfectState = chemDisinfectState; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; } return status; } /*********************************************************************//** * @brief - * The getRsrvrFillStatus function checks whether the target reservoir - * is full or not. If the fill times out, it sets the state machine to - * complete and exits the chemical disinfect mode. - * @details Inputs: rsrvrFillStableTimeCounter, alarm, stateTimer - * @details Outputs: none + * The getRsrvrFillToFullStatus function checks whether the target reservoir + * is full or not based on a plateau in the tank readings. + * If the fill times out, it sets an alarm. + * @details Inputs: rsrvrFillToFullStableTimeCounter, stateTimer, tank volume + * @details Outputs: alarm, reservoir fill status * @param r 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 + * @return the status of the reservoir during filling *************************************************************************/ static DG_RESERVOIR_STATUS_T getRsrvrFillToFullStatus( DG_RESERVOIR_ID_T r, U32 timeout ) { @@ -1321,13 +1381,14 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, r ) } - // Check the volume of the reservoir against the previous volume + // Check the volume of the reservoir against the long term filtered volume if ( ( currentVolume > RESERVOIR_MINIMUM_FULL_VOLUME_ML ) && ( fabs( currentVolume - filteredVolume ) < RESERVOIR_FULL_VOLUME_CHANGE_LIMIT_ML ) ) { - if ( ++rsrvrFillToFullStableTimeCounter >= RSRVRS_FILL_TO_FULL_STABLE_TIME_COUNT ) + if ( ++rsrvrFillToFullStableTimeCounter >= RSRVRS_FILL_TO_FULL_STABLE_TASK_INT ) { status = DG_RESERVOIR_REACHED_TARGET; rsrvrFillToFullStableTimeCounter = 0; + // Record the full volumes if ( DG_RESERVOIR_1 == r ) { R1FullVolume = currentVolume; @@ -1337,7 +1398,7 @@ R2FullVolume = currentVolume; } // 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 ) ) @@ -1361,7 +1422,7 @@ * @details Inputs: none * @details Outputs: Set concentrate pump speed relative to RO pump flow rate * @param measuredROFlowRate_mL_min measured RO flow rate in mL/min - * + * @param disinfectantMixingRatio is the ratio of RO flow rate to disinfectant flow rate * @return none *************************************************************************/ static void handleDisinfectantMixing( F32 measuredROFlowRate_mL_min, F32 disinfectantMixingRatio ) @@ -1380,17 +1441,18 @@ /*********************************************************************//** * @brief * The controlDRPByReservoirVolume function implements the volume control of the - * drain pump to maintain a specified volume in one of the reservoirs. - * @details Inputs: stateTimer, reservoir, initialize flag, control volume, - * tank volume, PI coefficients, min and max drain pump control RPM - * @details Outputs: stateTimer, chemDisinfectState, alarm + * drain pump to maintain a specified volume in one of the reservoirs. It uses + * a PI control loop to accomplish this. + * @details Inputs: tank volume, PI coefficients, full volume, + * volume below full to maintain, min and max drain pump control RPM + * @details Outputs: Sets drain pump RPM * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 - * @param initialize determines whether the function initializes the controller or - * runs it + * @param initialize determines whether the function initializes the controller (=TRUE) or + * runs it (=FALSE). + * @return none *************************************************************************/ static void controlDRPByReservoirVolume( DG_RESERVOIR_ID_T r, BOOL initialize ) { - if ( TRUE == initialize ) { // Initialize drain pump volume control PI controller @@ -1399,26 +1461,28 @@ MIN_DRP_VOLUME_CONTROL_RPM, MAX_DRP_VOLUME_CONTROL_RPM ); drpControlTimerCounter = getMSTimerCount(); resetPIController( PI_CONTROLLER_ID_DRAIN_PUMP_VOLUME, MIN_DRP_VOLUME_CONTROL_RPM ); - setDrainPumpTargetRPM( MIN_DRP_VOLUME_CONTROL_RPM ); + setDrainPumpTargetRPM( MIN_DRP_VOLUME_CONTROL_RPM ); //set the initial pump speed to the minimum } - else if ( TRUE == didTimeout( drpControlTimerCounter, DRP_VOLUME_CONTROL_INTERVAL_MS ) ) - { // Control at set interval - F32 tgtVolume = (F32)DRP_VOLUME_CONTROL_TARGET_VOLUME_ML; + else if ( TRUE == didTimeout( drpControlTimerCounter, DRP_VOLUME_CONTROL_INTERVAL_TASK_INT) ) + { // Control at set interval + F32 tgtVolume = (F32)DRP_VOLUME_CONTROL_TARGET_VOLUME_ML; // this is the default if no full volume is available F32 actVolume; U32 newRPM; if ( DG_RESERVOIR_1 == r ) { actVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); if ( R1FullVolume > 0.0 ) - { + { // If a tank full volume is known, use a set volume below full. This compensates for variations in + // the tank and load cell that may affect the volume read when the tank is full. tgtVolume = R1FullVolume - RESERVOIR_VOLUME_BELOW_FULL_ML; } } else if ( DG_RESERVOIR_2 == r ) { actVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); if ( R2FullVolume > 0.0 ) - { + { // If a tank full volume is known, use a set volume below full. This compensates for variations in + // the tank and load cell that may affect the volume read when the tank is full. tgtVolume = R2FullVolume - RESERVOIR_VOLUME_BELOW_FULL_ML; } } @@ -1427,62 +1491,45 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, r ) } - newRPM = runPIController( PI_CONTROLLER_ID_DRAIN_PUMP_VOLUME, tgtVolume, actVolume ); + newRPM = runPIController( PI_CONTROLLER_ID_DRAIN_PUMP_VOLUME, tgtVolume, actVolume ); setDrainPumpTargetRPM( newRPM ); drpControlTimerCounter = getMSTimerCount(); } } /*********************************************************************//** * @brief - * The getChemicalDisinfectStatus function monitors and returns the current - * stage of chemical 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 chemical disinfect has started or has elapsed, it + * The chemicalDisinfectTimerUpdate function monitors the disinfect temperature + * and returns the current + * stage of chemical disinfect cycle. If the chemical disinfect has started or has elapsed, it * set the status of chemical disinfect accordingly. * @details Inputs: areRsrvrsLeaking, areRsrvrsLeaking * @details Outputs: areRsrvrsLeaking, areRsrvrsLeaking * @return status of the chemical disinfect (i.e in progress, complete) *************************************************************************/ -static void chemicalDisinfectTimerUpdate( DG_RESERVOIR_ID_T r ) +static void chemicalDisinfectTimerUpdate( void ) { // Update the disinfect temperature F32 TdiTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); // If the coldest spot which is TDi is less than minimum chemical disinfect temperature, // reset the chemical disinfect timers and check whether heating up has timed out - if ( TdiTemp < CHEM_DISINFECT_TARGET_TEMPERATURE_C ) + + if ( TdiTemp >= CHEM_DISINFECT_TARGET_TEMPERATURE_C ) { - if ( TRUE == didTimeout( chemDisinfectWarmupTimer, CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ) ) - { - // Heating up to minimum temperature for chemical disinfect failed - alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; - chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - if ( DG_RESERVOIR_1 == r ) - { - chemDisinfectR1Timer = getMSTimerCount(); - } - else if ( DG_RESERVOIR_2 == r ) - { - chemDisinfectR2Timer = getMSTimerCount(); - } + isChemDisinfectTemperatureAboveTarget = TRUE; + ischemDisinfectWarmupTargetReached = TRUE; + } - else + else if ( TdiTemp < CHEM_DISINFECT_MINIMUM_TEMPERATURE_C ) { - if ( ( DG_RESERVOIR_1 == r ) && ( isPartialR1DisinfectInProgress != TRUE ) ) - { - // The temperature of the coldest spot is in range to start the disinfect timer - chemDisinfectR1Timer = getMSTimerCount(); - isPartialR1DisinfectInProgress = TRUE; - } - if ( ( DG_RESERVOIR_2 == r ) && ( isPartialR2DisinfectInProgress != TRUE ) ) - { - // The temperature of the coldest spot is in range to start the disinfect timer - chemDisinfectR2Timer = getMSTimerCount(); - isPartialR2DisinfectInProgress = TRUE; - } + isChemDisinfectTemperatureAboveTarget = FALSE; } + + if ( TRUE == isChemDisinfectTemperatureAboveTarget ) + { + chemDisinfectReservoirTime += TASK_GENERAL_INTERVAL; + } } /*********************************************************************//** @@ -1506,12 +1553,12 @@ data.cancellationMode = (U32)cancellationMode; //If the mode is in the actual chemical disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion - if ( TRUE ) + if ( chemDisinfectState > DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN ) { uiData.chemDisinfectTargetTime = TARGET_CHEM_DISINFECT_TIME_MS; - uiData.chemDisinfectCountdownTime = calcTimeSince( chemDisinfectR1Timer ); - data.R1FillLevel = R1ChemDisinfectVol; - data.R2FillLevel = R2ChemDisinfectVol; + uiData.chemDisinfectCountdownTime = chemDisinfectReservoirTime; + data.R1FillLevel = R1FullVolume; + data.R2FillLevel = R2FullVolume; } else { @@ -1520,8 +1567,6 @@ data.R2FillLevel = 0.0; } - data.postDisinfectTargetRinseCount = 0; - data.postDisinfectCurrentRinseCount = 0; data.chemDisinfectUIState = chemDisinfectUIState; // General data publish channel @@ -1538,37 +1583,43 @@ * @brief * The monitorModeChemicalDisinfect 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: chemDisinfectState - * @details Outputs: prevChemDisinfectState, chemDisinfectState, + * are not closed during the run. If the level of the reservoirs has drifted + * consecutively for the defined period of time, it sets the reservoir leak + * time out alarm and cancels the chemical disinfect mode. + * If the inlet water is not within the specified limits, an alarm is set and + * chemical disinfect is cancelled. If the conductivity of the diluted disinfectant + * mix is not within the specified limits, an alarm is set and disinfect is + * cancelled. + * @details Inputs: chemDisinfectState, tank volumes, tank volume monitor timer, + * inlet water temperature, pressure, and conductivity, disinfectant conductivity. + * @details Outputs: prevChemDisinfectState, chemDisinfectState, cancel state, * alarmDetectedPendingTrigger * @return: none *************************************************************************/ static void monitorModeChemicalDisinfect( void ) { - - // Reservoir leak detection. Perform check if no pending alarm. + // Reservoir leak detection. if ( ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) || ( DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 == chemDisinfectState ) ) { BOOL isRsrvrVolumeOutOfRange = FALSE; if ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) { - isRsrvrVolumeOutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1ChemDisinfectVol ) > RSRVRS_MAX_LEAK_VOL_CHANGE_ML; + isRsrvrVolumeOutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1FullVolume ) > RSRVRS_MAX_LEAK_VOL_CHANGE_ML; } - else if ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) + else if ( DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 == chemDisinfectState ) { - isRsrvrVolumeOutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) - R2ChemDisinfectVol ) > RSRVRS_MAX_LEAK_VOL_CHANGE_ML; + isRsrvrVolumeOutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) - R2FullVolume ) > RSRVRS_MAX_LEAK_VOL_CHANGE_ML; } if ( ( TRUE == isRsrvrVolumeOutOfRange ) ) { // If the leak is the first time after a while, set the flag and start the timer if ( FALSE == isRsrvrLeaking ) { - isRsrvrLeaking = TRUE; - rsrvrsVolMonitorTimer = getMSTimerCount(); + isRsrvrLeaking = TRUE; + rsrvrsVolMonitorCounter = 0; } // If the volume is out of range and it has timed out, set the alarm - else if ( TRUE == didTimeout( rsrvrsVolMonitorTimer, RSRVRS_LEAK_VOL_TIMEOUT_MS ) ) + else if ( ++rsrvrsVolMonitorCounter >= RSRVRS_LEAK_VOL_TIMEOUT_TASK_INT ) { isRsrvrLeaking = FALSE; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; @@ -1582,48 +1633,47 @@ } } - BOOL hasConductivityFailed = TRUE; - #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) #endif { // If the dialysate cap is open during any state, alarm if ( 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 ConcCap = (U32)getSwitchStatus( CONCENTRATE_CAP ); U32 DialysateCap = (U32)getSwitchStatus( DIALYSATE_CAP ); prevChemDisinfectState = chemDisinfectState; - chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_OR_CONC_CAP_NOT_IN_PROPER_POSITION; } } - + // In all states, check inlet temperature, inlet pressure, and inlet conductivity. + BOOL hasConductivityFailed = TRUE; + BOOL hasInletPressureFailed = TRUE; + BOOL hasInletTemperatureFailed = TRUE; haveInletWaterChecksPassed= TRUE; - hasConductivityFailed = ( ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) > MAX_INLET_CONDUCTIVITY_US_PER_CM ) || - ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) < MIN_INLET_CONDUCTIVITY_US_PER_CM ) ); + + hasConductivityFailed = ( ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) > MAX_INLET_CONDUCTIVITY_US_PER_CM ) || + ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) < MIN_INLET_CONDUCTIVITY_US_PER_CM ) ); + hasInletPressureFailed = ( ( getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ) < MIN_INLET_PRESSURE_PSI ) || + ( getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ) > MAX_INLET_PRESSURE_PSI ) ); + hasInletTemperatureFailed = ( ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) < MIN_INLET_TEMPERATURE_C ) || + ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MAX_INLET_TEMPERATURE_C ) ); + #ifndef _RELEASE_ - if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_WATER_QUALITY_CHECK ) ) { hasConductivityFailed = FALSE; } #endif - if ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) < MIN_INLET_TEMPERATURE_C || - getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MAX_INLET_TEMPERATURE_C || - hasConductivityFailed || - getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ) < MIN_INLET_PRESSURE_PSI) - { - // Inlet check failed, set timer if not already set - if ( 0 == inletWaterChecksFailTimer ) - { - inletWaterChecksFailTimer = getMSTimerCount(); - } + if ( hasInletTemperatureFailed || hasConductivityFailed || hasInletPressureFailed ) + { // Inlet check failed, haveInletWaterChecksPassed= FALSE; // set flag for flush drain state - if ( TRUE == didTimeout( inletWaterChecksFailTimer, INLET_WATER_CHECK_FAILURE_TIMEOUT_MS ) ) + // increment timer/counter and check for timeout + if ( ++inletWaterChecksFailCounter >= INLET_WATER_CHECK_FAILURE_TASK_INT ) { // alarm unless in the start, drain, or flush drain states switch( chemDisinfectState ) @@ -1634,6 +1684,7 @@ case DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN: break; + case DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION: case DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT: case DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH: prevChemDisinfectState = chemDisinfectState; @@ -1646,42 +1697,43 @@ case DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R1_FILL_R2_TO_R1: case DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1: case DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R2_FILL_R1_TO_R2: - prevChemDisinfectState = chemDisinfectState; + prevChemDisinfectState = chemDisinfectState; alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_NEW_WAT; chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; break; } } } else - { - // reset water check fail timer - inletWaterChecksFailTimer = 0; + { // inlet water checks passed, reset water check fail timer + inletWaterChecksFailCounter = 0; } - if ( chemDisinfectState > DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN ) + // Check the temperature and conductivity of the diluted disinfectant + if ( chemDisinfectState > DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT ) { // Disinfect conditions check F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); BOOL isCD2OutofRange = ( cd2Conductivity < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM || cd2Conductivity > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ); - BOOL isTPoOutofRange = ( TPoTemp < MIN_DISINFECT_TPO_TEMPERATURE_C || TPoTemp > MAX_DISINFECT_TPO_TEMPERATURE_C ); - // set the tank volumes for logging +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + { + isCD2OutofRange = FALSE; + } +#endif + BOOL isTPoOutofRange = ( TPoTemp > MAX_DISINFECT_TPO_TEMPERATURE_C ); if ( TRUE != isCD2OutofRange ) { - minMaxConductivityWaitTimer = 0; + minMaxConductivityWaitCounter = 0; } - else if ( 0 == minMaxConductivityWaitTimer ) + else if ( ++minMaxConductivityWaitCounter >= MIN_MAX_CONDUCTIVITY_WAIT_TASK_INT ) { - minMaxConductivityWaitTimer = getMSTimerCount(); - } - else if ( TRUE == didTimeout( minMaxConductivityWaitTimer, MIN_MAX_CONDUCTIVITY_WAIT_TIME_MS ) ) - { alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE; //ALARM_ID_DG_NEW_CON; TODO chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } - if ( ( TRUE == isTPoOutofRange ) ) + else if ( ( TRUE == isTPoOutofRange ) ) { alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; @@ -1697,6 +1749,7 @@ * @details Outputs: disinfectNVOps * @return: none *************************************************************************/ +// TODO: this may conflict with heat disinfect? static void writeDisinfectDataToNV( void ) { if ( FALSE == disinfectNVOps.hasDisCompleteDateBeenWrittenToNV )