Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r3fae8c2aab5873ccfaf8b7e1e4a2abf78216a7fd -rd8686d68bf29761ee329fc638264d2e60a5191c0 --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 3fae8c2aab5873ccfaf8b7e1e4a2abf78216a7fd) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision d8686d68bf29761ee329fc638264d2e60a5191c0) @@ -31,6 +31,7 @@ #include "Pressures.h" #include "Reservoirs.h" #include "ROPump.h" +#include "PIControllers.h" #include "RTC.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" @@ -51,19 +52,18 @@ #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 30.0F ///< Minimum water inlet pressure in psi. +#define MIN_INLET_PRESSURE_PSI 20.0F ///< Minimum water inlet pressure in psi. TODO: set to 30.0 // Drain R1 & R2 states defines #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 24.0F ///< Minimum water inlet temperature in C. -#define MIN_INLET_TEMPERATURE_C 35.0F ///< Maximum water inlet temperature in C. +#define FLUSH_DRAIN_WAIT_TIME_MS ( 30 * 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 100.0F ///< Minimum 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 // Flush circulation path state defines @@ -73,32 +73,47 @@ #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 100.0F ///< Maximum allowed conductivity in flush circulation state in us/cm +#define MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM 1000.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 // Flush and drain R1 and R2 -#define RSRVRS_FULL_VOL_ML 1850.0F ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 +#define RSRVRS_FULL_VOL_ML 1000.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. -#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_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. +#define RSRVRS_FILL_UP_TIMEOUT_MS ( 6 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. +#define RSRVRS_BOTH_FILL_UP_TIMEOUT_MS ( 12 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. +#define RSRVRS_PARTIAL_FILL_UP_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. +#define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. +#define RSRVRS_DRAIN_TIMEOUT_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. // R1 to R2 & R2 to R1 chemical disinfect circulation #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 CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI 12.0 ///< Chemical disinfect target drain outlet pressure in psi. -#define CHEM_DISINFECT_TIME_MS ( 36 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect time for each section in milliseconds. TODO original time was 36 minutes -#define CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect reaching to minimum temperature timeout in milliseconds. + +#define CHEM_DISINFECT_TIME_MS ( 7 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect time for each section in milliseconds. TODO original time was 36 minutes +#define CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ( 6 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect reaching to minimum temperature timeout in milliseconds. +#define DRAIN_PUMP_VOLUME_CONTROL_RPM 1200 +#define RSRVR_DRAIN_CONTROL_MIN_VOLUME 1600.0F +#define RSRVR_DRAIN_CONTROL_MAX_VOLUME 1750.0F + +#define DRP_VOLUME_CONTROL_TARGET_VOLUME_ML 1000.0F +#define DRP_VOLUME_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) +#define DRP_VOLUME_CONTROL_P_COEFFICIENT -0.5F ///< P term for dialIn pump control. +#define DRP_VOLUME_CONTROL_I_COEFFICIENT 0.0F ///< P term for dialIn pump control. +#define MIN_DRP_VOLUME_CONTROL_RPM 200.0F +#define MAX_DRP_VOLUME_CONTROL_RPM 1500.0F + +// the next 4 not currently used +//#define CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI 12.0 ///< Chemical disinfect target drain outlet pressure in psi. #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 chemical disinfect. TODO change this to 5 seconds #define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 600.0F ///< Reservoirs 1 & 2 maximum allowed volume change when full during chemical disinfect. TODO original value is 100 mL #define POST_CHEM_DISINFECT_WAIT_TIME_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect final wait time before flushing the system in milliseconds. // 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 600.0F ///< Minimum conductivity that indicates acid is in the line in uS/cm. -#define PRIME_ACID_STEADY_CONDUCTIVITY_TIME_MS ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Minimum time that a steady conductivity of acid must be read in milliseconds. +#define MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM 2.0F ///< Minimum conductivity that indicates acid is in the line in uS/cm. TODO: set to 600.0 +#define PRIME_ACID_STEADY_CONDUCTIVITY_TIME_MS ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Minimum time that a steady conductivity of acid must be read in milliseconds. TODO: set to 10 sec #define RO_PUMP_TARGET_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 @@ -108,15 +123,16 @@ #define DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN 7.5F ///< Disinfectant pump fill speed in ml/min. #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 * SEC_PER_MIN * 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 * SEC_PER_MIN * MS_PER_SECOND ) ///< Additional time to wait for temperature and conductivity to reach target in disinfectant flush state +#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 -#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 ///< Minimum conductivity for mixed disinfect fluid in us/cm -#define MIN_DISINFECT_TD2_TEMPERATURE_C 35.0F ///< Minimum temperature for mixed disinfect fluid at outlet of heater in dec C -#define MAX_DISINFECT_TD2_TEMPERATURE_C 45.0F ///< Maximum temperature for mixed disinfect fluid at outlet of heater in dec C +#define MIN_DISINFECT_CONDUCTIVITY_US_PER_CM 5.0F ///< Minimum conductivity for mixed disinfect fluid in us/cm TODO: set to 150.0 +#define MAX_DISINFECT_CONDUCTIVITY_US_PER_CM 5000.0F ///< Minimum conductivity for mixed disinfect fluid in us/cm TODO: set to 650.0 +#define MIN_DISINFECT_TD2_TEMPERATURE_C 25.0F ///< Minimum temperature for mixed disinfect fluid at outlet of heater in dec C TODO: set to 35.0 +#define MAX_DISINFECT_TD2_TEMPERATURE_C 45.0F ///< Maximum temperature for mixed disinfect fluid at outlet of heater in dec C TODO: set to 45.0 // Fill heat up -#define CHEM_DISINFECT_TARGET_TEMPERATURE_C 40.0F ///< Chemical disinfect target water temperature in C. // TODO this used to 30.0 +#define CHEM_DISINFECT_TARGET_TEMPERATURE_C 30.0F ///< Chemical disinfect target water temperature in C. // TODO this used to 30.0 +#define CHEM_DISINFECT_HEATER_CONTROL_TEMPERATURE_C 40.0F ///< Chemical disinfect heater control water temperature in C. // TODO this used to 30.0 #define DISINFECT_CYCLE_PERIOD_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time for disinfectant filling and partial draining cycle static const F32 ACID_TO_WATER_MIXING_RATIO = ( 1.0F / 70.0F ); ///< Acid to water mixing ratio for chemical disinfect. @@ -168,8 +184,10 @@ 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 U32 chemDisinfectTimer = 0; ///< Chemical disinfect timer. +static U32 chemDisinfectWarmupTimer = 0; ///< Chemical disinfect warmup timer. static BOOL isPartialDisinfectInProgress = FALSE; ///< Chemical disinfect partial complete/in progess flag. -static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during chemical disinfect. +static U32 rsrvrsVolMonitorTimer = 0; +static U32 drpControlTimerCounter = 0; static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during chemical disinfect. static U32 dataPublishCounter = 0; ///< Chemical Disinfect data publish counter. static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. @@ -194,16 +212,13 @@ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillWithDisinfectantState( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectR1DisinfectantFillR2DrainState( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectR2DisinfectantFillR1DrainState( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR1ToR2State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR1FillR1ToR2State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR2ToR1State( void ); -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR2FillR1ToR2State( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeBasicPathState(void); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeWaterPathState(void); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCompleteState(void); static void failChemicalDisinfect( void ); static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ); static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); +static void controlDRPByReservoirVolume( DG_RESERVOIR_ID_T r, BOOL initialize ); static CHEM_DISINFECT_STATUS_T getChemicalDisinfectStatus( void ); static void publishChemicalDisinfectData( void ); static void monitorModeChemicalDisinfect( void ); @@ -236,6 +251,8 @@ R1ChemDisinfectVol = 0.0; R2ChemDisinfectVol = 0.0; overallChemDisinfectTimer = 0; + chemDisinfectWarmupTimer = 0; + chemDisinfectTimer = 0; cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillStableTimeCounter = 0; isPartialDisinfectInProgress = FALSE; @@ -315,26 +332,12 @@ case DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN: chemDisinfectState = handleChemicalDisinfectR2DisinfectantFillR1DrainState(); + break; case DG_CHEM_DISINFECT_STATE_R1_DISINFECTANT_FILL_R2_DRAIN: chemDisinfectState = handleChemicalDisinfectR1DisinfectantFillR2DrainState(); - - case DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2: - chemDisinfectState = handleChemicalDisinfectDisinfectR1ToR2State(); break; - case DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R1_FILL_R1_TO_R2: - chemDisinfectState = handleChemicalDisinfectPartialDrainR1FillR1ToR2State(); - break; - - case DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1: - chemDisinfectState = handleChemicalDisinfectDisinfectR2ToR1State(); - break; - - case DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R2_FILL_R1_TO_R2: - chemDisinfectState = handleChemicalDisinfectPartialDrainR2FillR1ToR2State(); - break; - case DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH: chemDisinfectState = handleChemicalDisinfectCancelModeBasicPathState(); break; @@ -559,21 +562,21 @@ // Check if flush time has elapsed if ( TRUE == didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) { - if (haveInletWaterChecksPassed) + if ( TRUE == haveInletWaterChecksPassed ) { // set pumps and valves for next state, flush disinfectant line setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); - turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( INLET_UV_REACTOR ); turnOnUVReactor( OUTLET_UV_REACTOR ); flushCircWaitTime = FLUSH_CICRCULATION_WAIT_TIME_MS; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION; } else - { + { // If the number of failures have not exceeded the limit, try again. ++stateTrialCounter; if ( stateTrialCounter < MAX_ALLOWED_FLUSH_DRAIN_PERIODS ) @@ -587,7 +590,7 @@ prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; } - } + } } @@ -642,15 +645,15 @@ // 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 - { + } + else + { alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE; //ALARM_ID_DG_NEW_CON; - } - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; + } + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; } } else @@ -660,7 +663,7 @@ // Set the acid dispense pump speed setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, DISINFECTANT_PUMP_PRIME_SPEED_ML_PER_MIN ); requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); - state = DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT; + state = DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT; stateTimer = getMSTimerCount(); @@ -685,7 +688,7 @@ *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeDisinfectantState( void ) { - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE; + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT; F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); // Set the chemical disinfect that is published on the UI @@ -716,12 +719,12 @@ requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); // Start heating the water while we are filling up the reservoirs - setHeaterTargetTemperature( DG_PRIMARY_HEATER, CHEM_DISINFECT_TARGET_TEMPERATURE_C ); + setHeaterTargetTemperature( DG_PRIMARY_HEATER, CHEM_DISINFECT_HEATER_CONTROL_TEMPERATURE_C ); startHeater( DG_PRIMARY_HEATER ); flushDisinfectantWaitTime = FLUSH_DISINFECTANT_INITIAL_WAIT_TIME; stateTrialCounter = 0; - state = DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT; + state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; stateTimer = getMSTimerCount(); } } @@ -760,30 +763,32 @@ if ( TRUE == didTimeout( stateTimer, flushDisinfectantWaitTime ) ) { CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); - if ( ( CHEM_DISINFECT_HEATER_OUTLET_TEMPERATURE_OUT_OF_RANGE == state ) || - ( CHEM_DISINFECT_DISINFECTANT_CONDUCTIVITY_OUT_OF_RANGE == state ) ) - { + if ( ( CHEM_DISINFECT_HEATER_OUTLET_TEMPERATURE_OUT_OF_RANGE == status ) || + ( CHEM_DISINFECT_DISINFECTANT_CONDUCTIVITY_OUT_OF_RANGE == status ) ) + { // Check if we have exceeded the number of trials. If not, try another time ++stateTrialCounter; if (stateTrialCounter < MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS ) { stateTimer = getMSTimerCount(); flushDisinfectantWaitTime = FLUSH_DISINFECTANT_ADDITIONAL_WAIT_TIME; - } - else - { + } + else + { // fail, alarm has already been set - prevChemDisinfectState = state; + prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - } + } } else - { + { // No changes in valves and pumps for next state + //setValveState( VRD1, VALVE_STATE_OPEN ); // for testing, may prevent tubing breaks, TODO: remove + //setValveState( VRD2, VALVE_STATE_OPEN ); // for testing, may prevent tubing breaks, TODO: remove rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT; + state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; } } @@ -807,58 +812,55 @@ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillWithDisinfectantState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; - CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); - static BOOL rsvr2TimerStarted = FALSE; - // First reservoir 1 must be full - if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) - { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - } +// if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) +// { +// rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); +// } // Once reservoir 1 is full, check the status of reservoir 2 since the water overflows to reservoir 2 - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - if ( FALSE == rsvr2TimerStarted ) - { - // have to reset timer for reservoir 2 fill - stateTimer = getMSTimerCount(); - rsvr2TimerStarted = TRUE; - } - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); +// else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) +// { + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_BOTH_FILL_UP_TIMEOUT_MS ); - // Once reservoir 2 is full, set the actuators for next state + // If R1 is not full, keep monitoring for R1 level and timeout + // Once R1 is full, keep monitoring for R2 level and timeout + // Once R2 is full, transition to the next state if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { + // Set the actuators to flush R2 and drain R1 state // Set the valves to drain R1 and fill R2 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 ); - + // Set both reservoirs status + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; // Set the drain pump to control mode TODO: change to volume control mode - setDrainPumpTargetOutletPressure( CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI ); + //setDrainPumpTargetOutletPressure( CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI ); + controlDRPByReservoirVolume( DG_RESERVOIR_1, TRUE ); //Initialize the PI controller for DRP // 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 chemical disinfect cycle R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); R2ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - + chemDisinfectWarmupTimer = getMSTimerCount(); + isPartialDisinfectInProgress = FALSE; stateTimer = getMSTimerCount(); rsrvrsVolMonitorTimer = getMSTimerCount(); - isPartialDisinfectInProgress = TRUE; - chemDisinfectTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + 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; - } +// } +// else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) +// { +// prevChemDisinfectState = state; +// state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; +// } return state; } @@ -887,29 +889,34 @@ if ( CHEM_DISINFECT_COMPLETE == status) { // turn pumps and valves off - stopHeater( DG_PRIMARY_HEATER ); + stopHeater( DG_PRIMARY_HEATER ); setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRD1, VALVE_STATE_CLOSED ); - signalROPumpHardStop(); + signalROPumpHardStop(); signalDrainPumpHardStop(); requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - - state = DG_CHEM_DISINFECT_STATE_COMPLETE; + + state = DG_CHEM_DISINFECT_STATE_COMPLETE; } if ( TRUE == didTimeout( stateTimer, DISINFECT_CYCLE_PERIOD_MS ) ) { // go to the next disinfect configuration cycle setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); 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_R1_DISINFECTANT_FILL_R2_DRAIN; + state = DG_CHEM_DISINFECT_STATE_R1_DISINFECTANT_FILL_R2_DRAIN; } + else + { + controlDRPByReservoirVolume( DG_RESERVOIR_1, FALSE ); + } return state; } @@ -938,224 +945,41 @@ if ( CHEM_DISINFECT_COMPLETE == status) { // turn pumps and valves off - stopHeater( DG_PRIMARY_HEATER ); + 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 ); - signalROPumpHardStop(); + signalROPumpHardStop(); signalDrainPumpHardStop(); requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - state = DG_CHEM_DISINFECT_STATE_COMPLETE; + state = DG_CHEM_DISINFECT_STATE_COMPLETE; } - if ( TRUE == didTimeout( stateTimer, DISINFECT_CYCLE_PERIOD_MS ) ) + else if ( TRUE == didTimeout( stateTimer, DISINFECT_CYCLE_PERIOD_MS ) ) { // go to the next disinfect configuration cycle 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 ); - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN; + state = DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN; } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectDisinfectR1ToR2State 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 - * 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 - * @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; - CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); - - // Set the chemical disinfect that is published on the UI - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; - - switch ( status ) + else { - case CHEM_DISINFECT_RSRVRS_LEAK_TIMEOUT: - case CHEM_DISINFECT_HEAT_UP_TIMEOUT: - - break; - - case CHEM_DISINFECT_COMPLETE: - // Turn off the concentrate pumps - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); - - // Set the valves to transfer hot water from R1 to R2 and fill up R2. - setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRD1, VALVE_STATE_OPEN ); - setValveState( VRD2, VALVE_STATE_CLOSED ); - 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 disinfectant water from R1 to R2. - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT; - break; - - default: - // Do nothing, chemical disinfect is in progress - break; + controlDRPByReservoirVolume( DG_RESERVOIR_2, FALSE ); } return state; } -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectFillR2WithDisinfectantState function - * handles fill R2 with water state. The state transfers disinfectant from - * reservoir 1 to reservoir 2 until disinfectant overflows from reservoir 2 - * to reservoir 1. - * If the fill times out, it transitions to water cancellation state, - * otherwise, it transitions to the next state. - * @details Inputs: rsrvr1Status, rsrvr2Status - * @details Outputs: rsrvr1Status, rsrvr2Status, R1ChemDisinfectVol, - * R2ChemDisinfectVol, prevChemDisinfectState - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR1FillR1ToR2State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT; - CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); - - // First reservoir 1 must be partially full - if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) - { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); - } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - // Get the current volumes to be monitored during R2 to R1 chemical disinfect state - R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - R2ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - - state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - - return state; -} - /*********************************************************************//** * @brief - * The handleChemicalDisinfectDisinfectR2ToR1State function handles the - * chemical disinfect R2 to R1 state. If the reservoirs leak or it cannot - * reach to temperature within a certain period of time, it transitions to - * water cancellation state. If heat disinfect reservoir 1 to reservoir 2 is - * completed, it transitions to the next state. - * @details Inputs: stateTimer, rsrvr1Status - * @details Outputs: stateTimer, rsrvr1Status - * @return next state of the heat disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR2ToR1State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; - CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); - - switch ( status ) - { - case CHEM_DISINFECT_RSRVRS_LEAK_TIMEOUT: - case CHEM_DISINFECT_HEAT_UP_TIMEOUT: - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - break; - - case CHEM_DISINFECT_COMPLETE: - // Turn off the heaters - stopHeater( DG_PRIMARY_HEATER ); - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_COOL_DOWN_HEATERS; - break; - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleChemicalDisinfectFillR2WithDisinfectantState function - * handles fill R2 with water state. The state transfers disinfectant from - * reservoir 1 to reservoir 2 until disinfectant overflows from reservoir 2 - * to reservoir 1. - * If the fill times out, it transitions to water cancellation state, - * otherwise, it transitions to the next state. - * @details Inputs: rsrvr1Status, rsrvr2Status - * @details Outputs: rsrvr1Status, rsrvr2Status, R1ChemDisinfectVol, - * R2ChemDisinfectVol, prevChemDisinfectState - * @return next state of the chemical disinfect state machine - *************************************************************************/ -static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR2FillR1ToR2State( void ) -{ - DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT; - CHEM_DISINFECT_STATUS_T status = getChemicalDisinfectStatus(); - - // First reservoir 1 must be partially full - if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) - { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); - } - else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) - { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - - if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) - { - // Get the current volumes to be monitored during R2 to R1 chemical disinfect state - R1ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - R2ChemDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - - state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - } - else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - } - - return state; -} - -/*********************************************************************//** - * @brief * The handleChemicalDisinfectCancelModeBasicPathState function handles the * chemical disinfect cancel mode basic path state. The state sets the state * to complete and raises an alarm. @@ -1383,7 +1207,67 @@ return status; } +static void controlDRPByReservoirVolume( DG_RESERVOIR_ID_T r, BOOL initialize ) +{ + if ( TRUE == initialize ) + { + // Initialize dialysate inlet flow PI controller + initializePIController( PI_CONTROLLER_ID_DRAIN_PUMP_VOLUME, MIN_DRP_VOLUME_CONTROL_RPM, + DRP_VOLUME_CONTROL_P_COEFFICIENT, DRP_VOLUME_CONTROL_I_COEFFICIENT, + 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 ); + } + else if ( TRUE == didTimeout( drpControlTimerCounter, DRP_VOLUME_CONTROL_INTERVAL ) ) + { // Control at set interval + F32 tgtVolume = (F32)DRP_VOLUME_CONTROL_TARGET_VOLUME_ML; + F32 actVolume; + U32 newRPM; + if ( DG_RESERVOIR_1 == r ) + { + actVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + } + else if ( DG_RESERVOIR_2 == r ) + { + actVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + } + else + { + actVolume = tgtVolume + 500.0; + //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 ); + setDrainPumpTargetRPM( newRPM ); + drpControlTimerCounter = getMSTimerCount(); + } + + + +/* + if ( volume > RSRVR_DRAIN_CONTROL_MAX_VOLUME ) + { + // If volume is above target, turn pump on. + setDrainPumpTargetRPM( DRAIN_PUMP_VOLUME_CONTROL_RPM ); + } + else if ( volume < RSRVR_DRAIN_CONTROL_MIN_VOLUME ) + { + //if volume is below target, turn pump off. + signalDrainPumpHardStop(); + } + // TODO: somehow prevent both reservoirs from being full at the same time + //if ( volume > RSRVR_DRAIN_CONTROL_MAX_VOLUME ) + //{ + // //there is a problem with draining, alarm + // prevChemDisinfectState = chemDisinfectState; + // alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; //TODO: get correct alarm + // failChemicalDisinfect(); //TODO: fail in the correct way + //} +*/ +} + /*********************************************************************//** * @brief * The getChemicalDisinfectStatus function monitors and returns the current @@ -1400,14 +1284,14 @@ CHEM_DISINFECT_STATUS_T status = CHEM_DISINFECT_IN_PROGRESS; // Update the variables - F32 TdiTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); + F32 TdiTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); BOOL isR1OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1ChemDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; BOOL isR2OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) - R2ChemDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); BOOL isCD2OutofRange = ( cd2Conductivity < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM || cd2Conductivity > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ); - BOOL isTD2OutofRange = ( TD2Temp < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM || TD2Temp > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ); - + BOOL isTD2OutofRange = ( TD2Temp < MIN_DISINFECT_TD2_TEMPERATURE_C || TD2Temp > MAX_DISINFECT_TD2_TEMPERATURE_C ); + /* // Check if either reservoir 1 or reservoir 2 are losing volume more than allowed volume if ( ( TRUE == isR1OutOfRange ) || ( TRUE == isR2OutOfRange ) ) { @@ -1431,7 +1315,7 @@ { areRsrvrsLeaking = FALSE; } - + */ // For the following checks, if multiple failures occur at the same time, the last one will take precedence // Check if the acid conductivity and temperature are within range if ( TRUE == isCD2OutofRange ) @@ -1442,28 +1326,28 @@ if ( ( TRUE == isTD2OutofRange ) ) { alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_TIMEOUT; - status = CHEM_DISINFECT_HEATER_OUTLET_TEMPERATURE_OUT_OF_RANGE; + status = CHEM_DISINFECT_HEATER_OUTLET_TEMPERATURE_OUT_OF_RANGE; } - // If the coldest spot which is THd is less than minimum chemical disinfect temperature, + // 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 ( TRUE == didTimeout( stateTimer, CHEM_DISINFECT_START_TEMP_TIMEOUT_MS ) ) + 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; status = CHEM_DISINFECT_HEAT_UP_TIMEOUT; } - else - { + else + { // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts chemDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = FALSE; status = CHEM_DISINFECT_DISINFECT_TEMPERATURE_LOW; - } + } } - else if ( ( isPartialDisinfectInProgress != TRUE ) && ( TdiTemp >= CHEM_DISINFECT_TARGET_TEMPERATURE_C ) ) + else if ( isPartialDisinfectInProgress != TRUE ) { // The temperature of the coldest spot is in range to start the disinfect timer chemDisinfectTimer = getMSTimerCount(); @@ -1473,7 +1357,7 @@ // If chemical disinfect temperature has been reached, check if this stage of chemical disinfect is done if ( ( TRUE == isPartialDisinfectInProgress ) && ( TRUE == didTimeout( chemDisinfectTimer, CHEM_DISINFECT_TIME_MS ) ) ) { - // Done with this stage of chemical disnfect. Reset the variables + // Done with this stage of chemical disinfect. Reset the variables status = CHEM_DISINFECT_COMPLETE; isPartialDisinfectInProgress = FALSE; } @@ -1501,12 +1385,12 @@ data.stateElapsedTime = calcTimeSince( stateTimer ); 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 ( ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) || - ( DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 == chemDisinfectState ) ) + //If the mode is in the actual chemical disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion + if ( ( DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN == chemDisinfectState ) || + ( DG_CHEM_DISINFECT_STATE_R1_DISINFECTANT_FILL_R2_DRAIN == chemDisinfectState ) ) { uiData.chemDisinfectTargetTime = CHEM_DISINFECT_TIME_MS; - uiData.chemDisinfectCountdownTime = CHEM_DISINFECT_TIME_MS - calcTimeSince( chemDisinfectTimer ); + uiData.chemDisinfectCountdownTime = calcTimeSince( chemDisinfectTimer ); //CHEM_DISINFECT_TIME_MS - calcTimeSince( chemDisinfectTimer ); data.R1FillLevel = R1ChemDisinfectVol; data.R2FillLevel = R2ChemDisinfectVol; } @@ -1563,27 +1447,29 @@ alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_OR_CONC_CAP_NOT_IN_PROPER_POSITION; } } + // In all states, check inlet temperature, inlet pressure, and inlet conductivity. 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 ) ); #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_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(); - } - haveInletWaterChecksPassed= FALSE; // set flag for flush drain state + { + inletWaterChecksFailTimer = getMSTimerCount(); + } + haveInletWaterChecksPassed= FALSE; // set flag for flush drain state if ( TRUE == didTimeout( inletWaterChecksFailTimer, INLET_WATER_CHECK_FAILURE_TIMEOUT_MS ) ) { // alarm unless in the start, drain, or flush drain states @@ -1602,16 +1488,14 @@ alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_NEW_WAT; chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; break; - case DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT: - case DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2: - 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: + case DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT: + case DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN: + case DG_CHEM_DISINFECT_STATE_R1_DISINFECTANT_FILL_R2_DRAIN: 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 Index: firmware/App/Modes/ModeChemicalDisinfectFlush.c =================================================================== diff -u -r12d64de03890be512d1ccaca5d258710f3de99bb -rd8686d68bf29761ee329fc638264d2e60a5191c0 --- firmware/App/Modes/ModeChemicalDisinfectFlush.c (.../ModeChemicalDisinfectFlush.c) (revision 12d64de03890be512d1ccaca5d258710f3de99bb) +++ firmware/App/Modes/ModeChemicalDisinfectFlush.c (.../ModeChemicalDisinfectFlush.c) (revision d8686d68bf29761ee329fc638264d2e60a5191c0) @@ -1,24 +1,1138 @@ +/************************************************************************** +* +* 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 ModeChemicalDisinfect.c +* +* @author (last) Bill Bracken +* @date (last) 24-Oct-2022 +* +* @author (original) Sean +* @date (original) 04-Apr-2020 +* +***************************************************************************/ -#include "ModeChemicalDisinfectFlush.h" +#include "ConcentratePumps.h" +#include "ConductivitySensors.h" +#include "CPLD.h" +#include "DrainPump.h" +#include "FlowSensors.h" +#include "Heaters.h" +#include "LoadCell.h" +#include "MessageSupport.h" +#include "ModeChemicalDisinfect.h" +#include "ModeFault.h" +#include "ModeStandby.h" +#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "Pressures.h" +#include "Reservoirs.h" +#include "ROPump.h" +#include "RTC.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "TemperatureSensors.h" +#include "Timers.h" +#include "UVReactors.h" +#include "Valves.h" - /** - * @addtogroup DGChemicalDisinfectFlushMode + * @addtogroup DGChemicalDisinfectMode * @{ */ +// ********** private definitions ********** -void initChemicalDisinfectFlushMode( void ) +// General defines +#define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. +#define CHEM_DISINFECT_FLUSH_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode chem disinfect data publish interval in counts. + +// Start state defines +#define MIN_INLET_PRESSURE_PSI 30.0F ///< Minimum water inlet pressure in psi. + +// Drain R1 & R2 states defines +#define DRAIN_PUMP_TARGET_RPM 2400 ///< Drain pump target RPM during drain. +#define RSRVRS_INITIAL_FINAL_DRAIN_TIME_OUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. +#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 MAX_ALLOWED_FLUSH_DRAIN_PERIODS 2 ///< Number of flush drain periods to wait for inlet water to come in range +#define MIN_INLET_TEMPERATURE_C 24.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 +#define MIN_INLET_CONDUCTIVITY_US_PER_CM 100.0F ///< Minimum water inlet conductivity in us/cm + +// Flush circulation path state defines +#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. + +// Flush and drain R1 and R2 +#define RSRVRS_FULL_VOL_ML 1850.0F ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 +#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. +#define RSRVRS_FLUSH_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. +#define FLUSH_ADDITIONAL_TIME_MS ( 38 * MS_PER_SECOND ) ///< Additional time to flush after reservoir full +#define NUM_OF_RINSE_CYCLES 2 ///< Number of rinse cycles + +#define CONC_PUMP_FLUSH_SPEED_ML_PER_MIN 40.0 ///< Concentrate pump speed for flush +#define FLUSH_DISINFECTANT_LINE_WAIT_TIME_MS ( 2.5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time to flush disinfectant line in milliseconds. +#define FLUSH_UF_WAIT_TIME_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time to flush UF in milliseconds. + +/// Cancellation paths +typedef enum Cancellation_modes { + CANCELLATION_MODE_NONE = 0, ///< Cancellation mode none. + CANCELLATION_MODE_BASIC, ///< Cancellation mode basic. + CANCELLATION_MODE_WATER, ///< Cancellation mode water. + NUM_OF_CANCELLATION_MODES ///< Number of cancellation modes. +} CANCELLATION_MODE_T; +/// Non-volatile write structure +typedef struct +{ + BOOL hasDisFlushStatusBeenWrittenToNV; ///< Boolean flag to indicate whether the disinfect flush status been written to NV or not. + BOOL hasDisFlushCompleteDateBeenWrittenToNV; ///< Boolean flag to indicate whether the disinfect flush complete date been written to NV or not. +} DISINFECT_FLUSH_NV_OPS_T; + +// ********** private data ********** + +static DG_CHEM_DISINFECT_FLUSH_STATE_T chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; ///< Currently active chemical disinfect state. +static DG_CHEM_DISINFECT_FLUSH_STATE_T prevChemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; ///< Previous active chemical disinfect flush state before alarm. +static DG_CHEM_DISINFECT_UI_STATE_T chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; ///< Currently active chemical disinfect UI state. +static U32 overallChemDisinfectFlushTimer = 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. +static BOOL areTempSensorsInRange = FALSE; ///< Chemical disinfect temperature sensors in/out range flag. +static BOOL haveInletWaterChecksPassed = TRUE; ///< Inlet water pressure, temperature, and pressure in range flag +/// Boolean flag to check whether draining R1 and R2 is at the end of the chemical disinfect flush cycle or in the beginning. So the drain states can be reused. +static BOOL isThisLastDrain = FALSE; +static DG_RESERVOIR_STATUS_T rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 1 status. +static DG_RESERVOIR_STATUS_T rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 2 status. +static F32 R1ChemDisinfectFlushVol = 0.0; ///< Reservoir 1 full volume during chemical disinfect. +static F32 R2ChemDisinfectFlushVol = 0.0; ///< Reservoir 2 full volume during chemical disinfect. +static U32 chemDisinfectFlushTimer = 0; ///< Chemical disinfect timer. +static U32 rinseCycleCounter = 0; ///< Counter for rinse fill and drain cycles +static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during chemical disinfect. +static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during chemical disinfect. +static U32 dataPublishCounter = 0; ///< Chemical Disinfect data publish 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 numberOfPostDisinfectRinses; ///< Number of times to rinse the fluid path after chemical disinfect. +static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. +static DISINFECT_FLUSH_NV_OPS_T disinfectFlushNVOps; ///< Disinfect flush non-volatile memory operations. + +// ********** private function prototypes ********** + +//static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushRemoveAcidBottleFromUIState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushStartState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushDrainR1State( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushDrainR2State( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushDrainState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushDisinfectantLineState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushUFState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushR2ToR1DrainR1State( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushR1ToR2DrainR2State( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCancelModeBasicPathState(void); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCancelModeWaterPathState(void); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCompleteState( void ); + +static void failChemicalDisinfectFlush( void ); +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ); +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); +static void publishChemicalDisinfectFlushData( void ); +static void monitorModeChemicalDisinfectFlush( void ); +static void writeDisinfectDataToNV( void ); + +/*********************************************************************//** + * @brief + * The initChemicalDisinfectFlushMode function initializes the chemical + * disinfect flush mode module. + * @details Inputs: none + * @details Outputs: chemDisinfectFlushState, stateTimer, isThisLastDrain, + * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, + * overallChemDisinfectFlushTimer, + * cancellationMode, rsrvrFillStableTimeCounter, prevChemDisinfectFlushState + * numberOfPostDisinfectRinses, + * chemDisinfectFlushUIState, haveDrainParamsBeenInit, + * disinfectFlushNVOps + * @return none + *************************************************************************/ +void initChemicalDisinfectFlushMode( void ) +{ + chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; + prevChemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; + stateTimer = 0; + isThisLastDrain = FALSE; + stateTrialCounter = 0; + areTempSensorsInRange = FALSE; + haveInletWaterChecksPassed = TRUE; + rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; + rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; + overallChemDisinfectFlushTimer = 0; + cancellationMode = CANCELLATION_MODE_NONE; + rsrvrFillStableTimeCounter = 0; + numberOfPostDisinfectRinses = 0; + R1ChemDisinfectFlushVol = 0.0; + R2ChemDisinfectFlushVol = 0.0; + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; + haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; + haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; + //disinfectFlushNVOps.hasFlushCompleteDateBeenWrittenToNV = FALSE; + //disinfectFlushNVOps.hasFlushStatusBeenWrittenToNV = FALSE; } +/*********************************************************************//** + * @brief + * The transitionToChemicalDisinfectFlushMode function prepares for transition to + * chemical disinfect flush mode. + * @details Inputs: none + * @details Outputs: chemical disisnfect flush mode variables are reset + * @return initial state + *************************************************************************/ U32 transitionToChemicalDisinfectFlushMode( void ) { - return 1; + deenergizeActuators(); + + initChemicalDisinfectFlushMode(); + + setCPLDCleanLEDColor( CPLD_CLEAN_LED_YELLOW ); + + return chemDisinfectFlushState; } -U32 execChemicalDisinfectFlushMode( void ) +/*********************************************************************//** + * @brief + * The execChemicalDisinfectFlushMode function executes the chemical disinfect + * flush mode state machine. + * @details Inputs: none + * @details Outputs: Chemical disinfect flush mode state machine executed + * @return current state of chemical disinfect flush mode + *************************************************************************/ +U32 execChemicalDisinfectFlushMode( void ) { - return 1; + monitorModeChemicalDisinfectFlush(); + + switch ( chemDisinfectFlushState ) + { + case DG_CHEM_DISINFECT_FLUSH_STATE_START: + chemDisinfectFlushState = handleChemicalDisinfectFlushStartState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1: + chemDisinfectFlushState = handleChemicalDisinfectFlushDrainR1State(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2: + chemDisinfectFlushState = handleChemicalDisinfectFlushDrainR2State(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushDrainState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushDisinfectantLineState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushUFState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushR2ToR1DrainR1State(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushR1ToR2DrainR2State(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH: + chemDisinfectFlushState = handleChemicalDisinfectFlushCancelModeBasicPathState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH: + chemDisinfectFlushState = handleChemicalDisinfectFlushCancelModeWaterPathState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_COMPLETE: + chemDisinfectFlushState = handleChemicalDisinfectFlushCompleteState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_DG_CHEM_DISINFECT_INVALID_EXEC_STATE, chemDisinfectFlushState ) + chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; + break; + } + + //publishChemicalDisinfectFlushData(); + + return chemDisinfectFlushState; } + +/*********************************************************************//** + * @brief + * The getCurrentChemicalDisinfectFlushState function returns the current state + * of the chemical disinfect flush mode. + * @details Inputs: chemFlushState + * @details Outputs: none + * @return current state of chemical disinfect flush mode + *************************************************************************/ +DG_CHEM_DISINFECT_FLUSH_STATE_T getCurrentChemicalDisinfectFlushState( void ) +{ + return chemDisinfectFlushState; +} + +/*********************************************************************//** + * @brief + * The stopChemicalDisinfectFlush function stops chemical disinfect flush mode. + * @details Inputs: none + * @details Outputs: none + * @return TRUE is current operation mode is chemical disinfect flush, + * otherwise FALSE + *************************************************************************/ +BOOL stopChemicalDisinfectFlush( void ) +{ + BOOL status = FALSE; + + // Check if the current operation mode is chemical disinfect + if ( DG_MODE_CHFL == getCurrentOperationMode() ) + { + // Transition to mode standby + requestNewOperationMode( DG_MODE_STAN ); + + status = TRUE; + } + + return status; +} + +// ********** private functions ********** + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushStartState function handles the chemical + * disinfect flush start state. The state checks the inlet pressure and the + * difference in between TDi and TRo sensors and if they are not in + * range, it transitions to basic cancellation path. Otherwise, it + * transitions to the next state. + * @details Inputs: alarm, rsrvrFillStableTimeCounter, rsrvr1Status, + * stateTimer + * @details Outputs: alarm, rsrvrFillStableTimeCounter, rsrvr1Status, + * stateTimer, chemDisinfectFlushUIState + * @return next state of the chemical disinfect flush state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushStartState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1; + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; + + // Start overall chemical disinfect timer + overallChemDisinfectFlushTimer = getMSTimerCount(); + + // Set all the actuators to reset and de-energized state + deenergizeActuators(); + + // Close VPi to prevent wasting water + setValveState( VPI, VALVE_STATE_CLOSED ); + + // Set the actuators to drain R1 + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + rsrvrFillStableTimeCounter = 0; + // Assume reservoir 1 is full and drain it + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + stateTimer = getMSTimerCount(); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushDrainR1State function handles the chemical + * disinfect flush drain R1 state. The state drains reservoir 1. If the + * transition is finished within the time, it transitions to the next state, + * otherwise, it transitions to basic cancellation path. + * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, isThisLastDrain + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * ChemDisinfectFlushUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushDrainR1State( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1; + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; + + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_FINAL_DRAIN_TIME_OUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + // Assume reservoir 2 is full and drain it + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + + tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); + + // Done with draining R1 + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2; + + // Start the timer + stateTimer = getMSTimerCount(); + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushDrainR2State function handles the chemical + * disinfect flush 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 Outputs: stateTimer, rsrvr2Status, stateTrialCounter, + * chemDisinfectFlushUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushDrainR2State( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2; + + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_FINAL_DRAIN_TIME_OUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + signalDrainPumpHardStop(); // Done with draining + if ( TRUE == isThisLastDrain ) + { + state = DG_CHEM_DISINFECT_FLUSH_STATE_COMPLETE; + } + else + { + tareLoadCell( LOAD_CELL_RESERVOIR_2_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_2_BACKUP ); + // ??? make sure load cell check is done in tareLoadCell or add that here? + + // Set valves for next state, flush drain + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VPI, VALVE_STATE_OPEN ); + + stateTrialCounter = 0; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN; + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushFlushDrainState function handles the chemical + * disinfect flush drain state. The state flushes the drain line for a + * period of time and then measures the temperature and conductivity of + * water. If they are not within the range after the specified number of tries, + * it transitions to basic cancellation path, otherwise it transitions to the next state. + * @details Inputs: stateTimer, stateTrialCounter, alarm, + * prevChemDisinfectFlushState + * @details Outputs: stateTimer, stateTrialCounter, alarm, + * prevChemDisinfectFlushState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushDrainState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN; + + // TODO: check whether flush has already been completed within some time period, skip this state if it has + + // Check if flush time has elapsed + if ( TRUE == didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) + { + if (haveInletWaterChecksPassed) + { + // set pumps and valves for next state, flush disinfectant line + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + // Set the concentrate pump to run at a constant speed during priming in reverse + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, -1.0 * CONC_PUMP_FLUSH_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + // Turn on the bicarb line with forward direction, to dispense the chemical and mix + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMP_FLUSH_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE; + } + else + { + // If the number of failures have not exceeded the limit, try again. + stateTrialCounter++; + 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_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_DG_NEW_WAT; + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + } + + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushFlushDisinfectantLineState function handles the + * chemical disinfect flush flush disinfectant line state. The state flushes the + * disinfectant line for a period of time. After the flush if the temperature + * sensors are not within a certain degrees from each other, the state + * transitions to basic cancellation path, otherwise, it transitions to the + * next state. + * @details Inputs: stateTimer, stateTrialCounter, prevChemDisinfectFlushState + * alarm, areTempSensorsInRange, rsrvr1Status, rsrvr2Status + * @details Outputs: stateTimer, stateTrialCounter, prevChemDisinfectFlushState, + * alarm, areTempSensorsInRange, rsrvr1Status, rsrvr2Status + * @return next state of the chemical disinfect state machine + ************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushDisinfectantLineState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE; + + // Check if the flush disinfectant line time has elapsed + if ( TRUE == didTimeout( stateTimer, FLUSH_DISINFECTANT_LINE_WAIT_TIME_MS ) ) + { + + // set the pumps and valves for the next state, flush UF + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRD2, VALVE_STATE_OPEN ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushFlushUFState function handles the + * chemical disinfect flush flush UF state. + * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectFlushState + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectFlushState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushUFState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF; + + // Check if the flush UFtime has elapsed + if ( TRUE == didTimeout( stateTimer, FLUSH_UF_WAIT_TIME_MS ) ) + { + // set the pumps and valves for the next state, flush R2 to R1 and drain R1 + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRD1, VALVE_STATE_OPEN ); + + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + rinseCycleCounter = 0; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1; + } + + return state; +} + + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushRinseR2ToR1AndDrainR1State function handles + * the chemical disinfect rinse R2 to R1 and drain R1 state. The state + * rinses reservoir 2 and drains reservoir 1 at the same time. If the drain + * process times out, it transitions to basic cancellation state, and + * if the rinse times out, it transitions to water cancellation state. + * If the drain and rinse are completed within the define time, it + * transitions to the next state. + * @details Inputs: rsrvr1Status, rsrvr2Status + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectFlushState, alarmDetectedPendingTrigger + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushR2ToR1DrainR1State( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1; + static BOOL rsrvr1Empty = FALSE; + static BOOL rsrvr2Full = FALSE; + + if ( FALSE == rsrvr1Empty ) + { + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_FLUSH_DRAIN_TIMEOUT_MS ); + } + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + // Done with draining R1 + signalDrainPumpHardStop(); + setValveState( VRD1, VALVE_STATE_CLOSED ); + rsrvr1Empty = TRUE; + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + // reservoir 1 drain timeout + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + + if ( FALSE == rsrvr2Full ) + { + // 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 ); + } + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + rsrvr2Full = TRUE; + stateTimer = getMSTimerCount(); + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + + if ( ( TRUE == rsrvr2Full ) && ( TRUE == rsrvr1Empty ) && ( TRUE == didTimeout( stateTimer, FLUSH_ADDITIONAL_TIME_MS ) ) ) + { + // Set the valves to flush R1 to R2 and drain R2 + setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + + // Turn on the drain pump to drain R2 + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Set the reservoir status + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2; + + } + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushRinseR1ToR2AndDrainR2State function handles + * the chemical disinfect flush rinse R1 to R2 and drain R2 state. The state + * rinses reservoir 1 and drains reservoir 2 at the same time. If the drain + * process times out, it transitions to basic cancellation state, and + * if the rinse times out, it transitions to water cancellation state. + * If the drain and rinse are completed within the define time, it + * transitions to the next state. + * @details Inputs: rsrvr1Status, rsrvr2Status, rinseCycleCounter + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectFlushState, alarmDetectedPendingTrigger, isThisLastDrain + * numberOfPostDisinfectRinses + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushR1ToR2DrainR2State( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2; + + static BOOL rsrvr2Empty = FALSE; + static BOOL rsrvr1Full = FALSE; + + if ( FALSE == rsrvr2Empty ) + { + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_FLUSH_DRAIN_TIMEOUT_MS ); + } + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // Done with draining R2 + signalDrainPumpHardStop(); + setValveState( VRD2, VALVE_STATE_CLOSED ); + rsrvr2Empty = TRUE; + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + // reservoir 2 drain timeout + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + + if ( FALSE == rsrvr1Full ) + { + // Reservoir 1 must be completely full + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + } + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + rsrvr1Full = TRUE; + stateTimer = getMSTimerCount(); + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + + if ( ( TRUE == rsrvr1Full ) && ( TRUE == rsrvr2Empty ) && ( TRUE == didTimeout( stateTimer, FLUSH_ADDITIONAL_TIME_MS ) ) ) + { + ++rinseCycleCounter; + if ( rinseCycleCounter < NUM_OF_RINSE_CYCLES ) + { + // Set the valves to flush R2 to R1 and drain R1 + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + + // Turn on the drain pump to drain R2 + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Set the reservoir status + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2; + } + else + { + // Set the valves to drain R1 + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_OPEN ); + + // Turn on the drain pump to drain R2 + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Turn off CP1 and CP2 + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + + //Turn off UV reactors + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + + // Set the reservoir status + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + + isThisLastDrain = TRUE; + state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1; + } + } + + return state; + +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushCancelModeBasicPathState function handles the + * chemical disinfect cancel mode basic path state. The state sets the state + * to complete and raises an alarm. + * @details Inputs: none + * @details Outputs: cancellationMode, ChemDisinfectFlushUIState + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCancelModeBasicPathState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_CANCEL_FLUSH; + + // Set the cancellation mode + cancellationMode = CANCELLATION_MODE_BASIC; + + failChemicalDisinfectFlush(); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushCancelModeWaterPathState function handles the + * chemical disinfect flush cancel mode cold water path state. + * @details Inputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer + * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer, + * ChemDisinfectFlushUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCancelModeWaterPathState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_CANCEL_FLUSH; + + if ( CANCELLATION_MODE_NONE == cancellationMode ) + { + // Stop all the actuators first then decide who should run next + deenergizeActuators(); + + cancellationMode = CANCELLATION_MODE_WATER; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + + // The drain is set to start from reservoir 2 + setValveState( VRD2, VALVE_STATE_OPEN ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Start the timer for drain timeout + stateTimer = getMSTimerCount(); + } + + // If reservoir 2 is empty, set to drain reservoir 1 + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // Set the drain valve to reservoir 1 + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + } + } + // Could not drain reservoir 2. Transition to basic cancellation path + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + // If reservoir 2 has already been drained and reservoir 1 is empty, reset and switch to complete + if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + failChemicalDisinfectFlush(); + } + // Could not drain reservoir 1. Transition to basic cancellation path + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushCompleteState function handles the chemical + * disinfect complete state. The state stops chemical disinfect and + * requests transition to mode standby. + * @details Inputs: none + * @details Outputs: ChemDisinfectFlushUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCompleteState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_COMPLETE; + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_COMPLETE; + + stopChemicalDisinfectFlush(); + + return state; +} + +/*********************************************************************//** + * @brief + * The failChemicalDisinfectFlush function sets the alarm that failed the + * chemical disinfect mode. + * @details Inputs: alarmDetectedPendingTrigger, prevChemDisinfectFlushState + * @details Outputs: none + * @return none + *************************************************************************/ +static void failChemicalDisinfectFlush( void ) +{ + SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, prevChemDisinfectFlushState ) +} + +/*********************************************************************//** + * @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, chemDisinfectFlushState + * @details Outputs: prevChemDisinfectFlushState + * @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 + *************************************************************************/ +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ) +{ + DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; + F32 volume = 0.0; + + if ( DG_RESERVOIR_1 == r ) + { + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + } + else if ( DG_RESERVOIR_2 == r ) + { + 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 ) + } + + // 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; + rsrvrFillStableTimeCounter = 0; + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + } + } + else if ( TRUE == didTimeout( stateTimer, timeout ) ) + { + // Failed to fill ontime. Update the previous chemical disinfect state and transition to basic cancellation + prevChemDisinfectFlushState = chemDisinfectFlushState; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_FILL_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; + } + + return status; +} + +/*********************************************************************//** + * @brief + * The getRsrvrDrainStatus function returns the status of draining a + * reservoir. + * @details Inputs: stateTimer, chemDisinfectFlushState + * alarm + * @details Outputs: stateTimer, prevChemDisinfectFlushState, alarm + * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 + * @param drainSteadyStateTimeout which is the time the reservoir's level + * does not change and is steady state + * @param timeout which is the timeout that a reservoir must be drained by + * then + * @return the status of the reservoirs during draining + *************************************************************************/ +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ) +{ + 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 + prevChemDisinfectFlushState = chemDisinfectFlushState; + haveDrainParamsBeenInit[ r ] = FALSE; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; + } + + return status; +} + + +/*********************************************************************//** + * @brief + * The publishChemicalDisinfectFlushData function publishes chemical disinfect + * flush data at the set interval. + * @details Inputs: dataPublishCounter + * @details Outputs: dataPublishCounter + * @return: none + *************************************************************************/ +/* needs work +static void publishChemicalDisinfectFlushData( void ) +{ + if ( ++dataPublishCounter >= CHEM_DISINFECT_FLUSH_DATA_PUB_INTERVAL ) + { + MODE_CHEMICAL_DISINFECT_FLUSH_DATA_T data; + MODE_CHEMICAL_DISINFECT_UI_DATA_T uiData; + + data.chemDisinfectFlushState = (U32)chemDisinfectFlushState; + data.stateElapsedTime = calcTimeSince( stateTimer ); + data.overallElapsedTime = calcTimeSince( overallChemDisinfectFlushTimer ); + data.cancellationMode = (U32)cancellationMode; + + // General data publish channel + broadcastData( MSG_ID_DG_CHEM_DISINFECT_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( MODE_CHEMICAL_DISINFECT_FLUSH_DATA_T ) ); + + // Publish data to UI + broadcastData( MSG_ID_DG_CHEM_DISINFECT_TIME_DATA, COMM_BUFFER_OUT_CAN_DG_2_UI, (U08*)&uiData, sizeof( MODE_CHEMICAL_DISINFECT_FLUSH_UI_DATA_T ) ); + + dataPublishCounter = 0; + } +} +*/ + +/*********************************************************************//** + * @brief + * The monitorModeChemicalDisinfectFlush 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. It also monitors inlet water conditions. + * @details Inputs: chemDisinfectState + * @details Outputs: prevChemDisinfectFlushState, chemDisinfectState, + * alarmDetectedPendingTrigger + * @return: none + *************************************************************************/ +static void monitorModeChemicalDisinfectFlush( void ) +{ + BOOL hasConductivityFailed = TRUE; + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + // If either the dialysate cap or the concentrate cap is open during any state, alarm + 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 ConcCap = (U32)getSwitchStatus( CONCENTRATE_CAP ); + U32 DialysateCap = (U32)getSwitchStatus( DIALYSATE_CAP ); + prevChemDisinfectFlushState = chemDisinfectFlushState; + chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_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. + haveInletWaterChecksPassed= TRUE; + hasConductivityFailed = ( ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) >= MAX_INLET_CONDUCTIVITY_US_PER_CM ) || + ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) <= MIN_INLET_CONDUCTIVITY_US_PER_CM ) ); +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + { + hasConductivityFailed = FALSE; + } +#endif + if ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) < MIN_INLET_TEMPERATURE_C || + hasConductivityFailed || + getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ) < MIN_INLET_PRESSURE_PSI) + { + // Inlet check failed, alarm unless in the start, drain, or flush drain states + haveInletWaterChecksPassed= FALSE; // set flag for flush drain state + switch( chemDisinfectFlushState ) + { + case DG_CHEM_DISINFECT_FLUSH_STATE_START: + case DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1: + case DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2: + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN: + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE: + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF: + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1: + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2: + prevChemDisinfectFlushState = chemDisinfectFlushState; + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_NEW_WAT; + chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + break; + } + } + + } + +/*********************************************************************//** + * @brief + * The writeDisinfectDataToNV function writes the disinfection data to the + * non-volatile memory. + * @details Inputs: disinfectNVOps + * @details Outputs: disinfectNVOps + * @return: none + *************************************************************************/ +static void writeDisinfectDataToNV( void ) +{ + ; ///< Boolean flag to indicate whether the disinfect flush status been written to NV or not. + BOOL ; + if ( FALSE == disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV ) + { + disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV = setDisinfectStatus( TRUE ); + } + + if ( FALSE == disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV ) + { + disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV = setLastDisinfectDate( USAGE_INFO_CHEMICAL_DISINFECT, getRTCTimestamp() ); + } +} + +/**@}*/ Index: firmware/App/Services/PIControllers.h =================================================================== diff -u -ra9315539f527b92523b1598ff91e47db4d71dae2 -rd8686d68bf29761ee329fc638264d2e60a5191c0 --- firmware/App/Services/PIControllers.h (.../PIControllers.h) (revision a9315539f527b92523b1598ff91e47db4d71dae2) +++ firmware/App/Services/PIControllers.h (.../PIControllers.h) (revision d8686d68bf29761ee329fc638264d2e60a5191c0) @@ -36,6 +36,7 @@ PI_CONTROLLER_ID_RO_PUMP_FLOW = 0, ///< RO Pump controller to flow PI_CONTROLLER_ID_DRAIN_PUMP, ///< Drain Pump controller PI_CONTROLLER_ID_RO_PUMP_MAX_PRES, ///< RO pump controller to maximum pressure + PI_CONTROLLER_ID_DRAIN_PUMP_VOLUME, ///< Drain pump controller using tank volume NUM_OF_PI_CONTROLLERS_IDS ///< Number of PI controllers } PI_CONTROLLER_ID_T;