/************************************************************************** * * 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 "ConcentratePumps.h" #include "ConductivitySensors.h" #include "CPLD.h" #include "DrainPump.h" #include "FlowSensors.h" #include "Heaters.h" #include "LoadCell.h" #include "MessageSupport.h" #include "ModeChemicalDisinfectFlush.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 DGChemicalDisinfectMode * @{ */ // ********** private definitions ********** // 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 10.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 ( 1 * 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 10.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 0.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 1700.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 CHEM_DISINFECT_FLUSH_TIME_MS ( 12 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect flush time in ms. TODO: get the correct time for the mode #define CONC_PUMP_CP1_FLUSH_SPEED_ML_PER_MIN 40.0 ///< Concentrate pump CP1 speed for flush #define CONC_PUMP_CP2_FLUSH_SPEED_ML_PER_MIN 40.8 ///< Concentrate pump CP2 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 flush 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_FLUSH_UI_STATE_T chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; ///< Currently active chemical disinfect flush UI state. static U32 overallChemDisinfectFlushTimer = 0; ///< Chemical disinfect flush cycle total timer. static U32 stateTimer = 0; ///< Chemical disinfect flush state timer to be used in different states. static U32 stateTrialCounter = 0; ///< Chemical disinfect flush state trial counter to be used for retries in different states. static BOOL areTempSensorsInRange = FALSE; ///< Chemical disinfect flush 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 flush. static F32 R2ChemDisinfectFlushVol = 0.0; ///< Reservoir 2 full volume during chemical disinfect flush. static BOOL rsrvr2Empty = FALSE; //static BOOL rsrvr1Full = FALSE; //static BOOL rsrvr1Empty = FALSE; //static BOOL rsrvr2Full = FALSE; //static U32 chemDisinfectFlushTimer = 0; ///< Chemical disinfect flush timer. static U32 waitTimer = 0; static U32 rinseCycleCounter = 0; ///< Counter for rinse fill and drain cycles static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during chemical disinfect flush. static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during chemical disinfect flush. static U32 dataPublishCounter = 0; ///< Chemical disinfect flush 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 flush alarm to raise. static U32 numberOfPostDisinfectRinses; ///< Number of times to rinse the fluid path after chemical disinfect flush. 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 writeDisinfectFlushDataToNV( 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; rinseCycleCounter = 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 ) { deenergizeActuators(); initChemicalDisinfectFlushMode(); setCPLDCleanLEDColor( CPLD_CLEAN_LED_YELLOW ); return chemDisinfectFlushState; } /*********************************************************************//** * @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 ) { monitorModeChemicalDisinfectFlush(); switch ( chemDisinfectFlushState ) { case DG_CHEM_DISINFECT_FLUSH_STATE_START: chemDisinfectFlushState = handleChemicalDisinfectFlushStartState(); break; case DG_CHEM_DISINFECT_FLUSH_STATE_DRAIN_R1: chemDisinfectFlushState = handleChemicalDisinfectFlushDrainR1State(); break; case DG_CHEM_DISINFECT_FLUSH_STATE_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_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_DRAIN_R1; // Set the chemical disinfect that is published on the UI chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_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_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_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 flushing in reverse setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, -1.0 * CONC_PUMP_CP1_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_CP2_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 ); setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); 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 defined 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; 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 ); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { // reservoir 1 drain timeout prevChemDisinfectFlushState = state; state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; } } // 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 ) { waitTimer = getMSTimerCount(); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevChemDisinfectFlushState = state; state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; } } if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) && ( TRUE == didTimeout( waitTimer, FLUSH_ADDITIONAL_TIME_MS ) ) ) { // Set the valves to rinse R1 to R2 and drain R2 setValveState( VRD2, VALVE_STATE_OPEN ); setValveState( VRD1, VALVE_STATE_CLOSED ); 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; stateTimer = getMSTimerCount(); 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 defined 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; 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 ); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { // reservoir 2 drain timeout prevChemDisinfectFlushState = state; state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; } } // Reservoir 1 must be completely full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { waitTimer = getMSTimerCount(); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevChemDisinfectFlushState = state; state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; } } if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) && ( TRUE == didTimeout( waitTimer, 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( VRD2, VALVE_STATE_CLOSED ); setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); // 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; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1; } else { // number of rinse cycles complete // 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 ); setValveState( VRD2, VALVE_STATE_CLOSED ); // Turn on the drain pump to drain R2 setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); // Turn off CP1 and CP2 and ROP signalROPumpHardStop(); 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; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_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 *************************************************************************/ static void publishChemicalDisinfectFlushData( void ) { if ( ++dataPublishCounter >= CHEM_DISINFECT_FLUSH_DATA_PUB_INTERVAL ) { MODE_CHEMICAL_DISINFECT_FLUSH_DATA_T data; MODE_CHEMICAL_DISINFECT_FLUSH_UI_DATA_T uiData; data.chemDisinfectFlushState = (U32)chemDisinfectFlushState; data.stateElapsedTime = calcTimeSince( stateTimer ); data.overallElapsedTime = calcTimeSince( overallChemDisinfectFlushTimer ); data.postDisinfectTargetRinseCount = (U32) NUM_OF_RINSE_CYCLES; data.postDisinfectCurrentRinseCount = rinseCycleCounter; data.cancellationMode = (U32)cancellationMode; uiData.chemDisinfectFlushTargetTime = CHEM_DISINFECT_FLUSH_TIME_MS; uiData.chemDisinfectFlushCountdownTime = calcTimeSince( overallChemDisinfectFlushTimer ); // General data publish channel broadcastData( MSG_ID_DG_CHEM_DISINFECT_FLUSH_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_FLUSH_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_DRAIN_R1: case DG_CHEM_DISINFECT_FLUSH_STATE_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 writeDisinfectFlushDataToNV( void ) { if ( FALSE == disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV ) { disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV = setDisinfectStatus( TRUE ); } if ( FALSE == disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV ) { disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV = setLastDisinfectDate( USAGE_INFO_CHEMICAL_DISINFECT, getRTCTimestamp() ); } } /**@}*/