/************************************************************************** * * 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 CHEM_DISINFECT_FLUSH_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode chem disinfect data publish interval in counts. // 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. // Inlet water checks defines #define MIN_INLET_TEMPERATURE_C 24.0F ///< Minimum water inlet temperature in C. #define MAX_INLET_TEMPERATURE_C 37.0F ///< Maximum water inlet temperature in C. #define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0F ///< Maximum water inlet conductivity in us/cm #define MIN_INLET_CONDUCTIVITY_US_PER_CM 100.0F ///< Minimum water inlet conductivity in us/cm #define MIN_INLET_PRESSURE_PSI 10.0F ///< Minimum water inlet pressure in psi. #define MAX_INLET_PRESSURE_PSI 80.0F ///< Maximum water inlet pressure in psi. // 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 // 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 defines #define RSRVRS_FULL_STABLE_TIME_COUNT ( ( 4 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in counts. #define RSRVRS_FILL_UP_TIMEOUT_MS ( 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 RSRVRS_DRAIN_TARGET_VOLUME_ML 200.0F ///< While filling and draining at the same time, look for a volume that indicates draining is working, ml. #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 or not used? // Fill reservoirs to full defines #define RESERVOIR_FULL_VOLUME_CHANGE_LIMIT_ML 5.0F ///< The maximum difference between the short-term and long-term filtered reservoir volumes in ml that determines the tank is full. #define RESERVOIR_MINIMUM_FULL_VOLUME_ML 1700.0F ///< When filling the reservoir, the volume reading must be at least this value before checking for the volume to level off. #define RSRVRS_FILL_TO_FULL_STABLE_TASK_INT ( ( 2 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in task intervals. // Flush disinfectant lines and flush UF defines #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 haveInletWaterChecksPassed = TRUE; ///< Inlet water pressure, temperature, and pressure in range flag static BOOL isThisLastDrain = FALSE; /// Boolean flag to check whether draining R1 and R2 is at the end of the chemical disinfect flush cycle or in the beginning. 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 U32 waitTimer = 0; ///< Wait timer for reservoir flushing. static U32 drainTimer = 0; ///< Timer for reservoir draining during flush states 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 U32 rsrvrFillToFullStableTimeCounter = 0; ///< Task interval counter for determining if reservoir is full 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 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 getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); static DG_RESERVOIR_STATUS_T getRsrvrFillToFullStatus( DG_RESERVOIR_ID_T r, 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, rsrvr1Status, rsrvr2Status, haveInletWaterChecksPassed, * overallChemDisinfectFlushTimer, * cancellationMode, rsrvrFillStableTimeCounter, prevChemDisinfectFlushState * numberOfPostDisinfectRinses, * chemDisinfectFlushUIState, * 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; haveInletWaterChecksPassed = TRUE; rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; overallChemDisinfectFlushTimer = 0; cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillStableTimeCounter = 0; numberOfPostDisinfectRinses = 0; chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV = FALSE; disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV = 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 prepares for the next state and * transitions to the next state. * @details Inputs: none * @details Outputs: 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 flush state that is published on the UI chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_FLUSH_AFTER_DISINFECT; // 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; 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 * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, * ChemDisinfectFlushUIState * @return next state of the chemical disinfect flush 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; 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 ) { // Done with draining R1 if ( FALSE == isThisLastDrain ) { tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); } setValveState( VRD1, VALVE_STATE_CLOSED ); setValveState( VRD2, VALVE_STATE_OPEN ); rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; state = DG_CHEM_DISINFECT_FLUSH_STATE_DRAIN_R2; 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, * @details Outputs: stateTimer, rsrvr2Status, chemDisinfectFlushUIState * @return next state of the chemical disinfect flush 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 ); // 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 flush drain state. The state flushes the drain line for a * period of time and then measures the temperature and conductivity of the * 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, prevChemDisinfectFlushState * @details Outputs: stateTimer, stateTrialCounter, alarm, * prevChemDisinfectFlushState * @return next state of the chemical disinfect flush 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 flush the line that contains acid from the disinfect 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. if ( ++stateTrialCounter < MAX_ALLOWED_FLUSH_DRAIN_PERIODS ) { stateTimer = getMSTimerCount(); } else { // Couldn't get a good water sample after a couple of trials and the disinfect flush cycle failed alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //TODO: 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 it transitions to the * next state. * @details Inputs: stateTimer, prevChemDisinfectFlushState * @details Outputs: stateTimer * @return next state of the chemical disinfect flush 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. The state flushes the * UF filter for a period of time. After the flush it transitions to the * next state. * @details Inputs: stateTimer, * @details Outputs: stateTimer, * @return next state of the chemical disinfect flush 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; drainTimer = getMSTimerCount(); numberOfPostDisinfectRinses = 0; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1; } return state; } /*********************************************************************//** * @brief * The handleChemicalDisinfectFlushFlushR2ToR1DrainR1State function handles * the chemical disinfect flush 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 water cancellation state, and * if the fill 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 flush 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; // Check whether draining R1 has timed out if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { // Do not use the standard drain status function because we are filling and draining at the same time if ( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) < RSRVRS_DRAIN_TARGET_VOLUME_ML ) { rsrvr1Status = DG_RESERVOIR_REACHED_TARGET; } else if ( TRUE == didTimeout( drainTimer, RSRVRS_FLUSH_DRAIN_TIMEOUT_MS ) ) { // reservoir 1 drain timeout prevChemDisinfectFlushState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; } } // Check whether R2 fill has timed out if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) { rsrvr2Status = getRsrvrFillToFullStatus( DG_RESERVOIR_2, 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; } } // Overflow R2 to R1 for an additional period if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( TRUE == didTimeout( waitTimer, FLUSH_ADDITIONAL_TIME_MS ) ) ) { // Set the valves to flush 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 ); rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; drainTimer = getMSTimerCount(); stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2; } return state; } /*********************************************************************//** * @brief * The handleChemicalDisinfectFlushFlushR1ToR2DrainR2State function handles * the chemical disinfect flush flush R1 to R2 and drain R2 state. The state * fills reservoir 1 and drains reservoir 2 at the same time. If the drain * process times out, it transitions to water 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, numberOfPostDisinfectRinses * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, * prevChemDisinfectFlushState, alarmDetectedPendingTrigger, isThisLastDrain * numberOfPostDisinfectRinses * @return next state of the chemical disinfect flush 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; // Check whether draining R2 has timed out if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { // Do not use the standard drain status function because we are filling and draining at the same time if ( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) < RSRVRS_DRAIN_TARGET_VOLUME_ML ) { rsrvr2Status = DG_RESERVOIR_REACHED_TARGET; } else if ( TRUE == didTimeout( drainTimer, RSRVRS_FLUSH_DRAIN_TIMEOUT_MS ) ) { // reservoir 2 drain timeout prevChemDisinfectFlushState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; } } // Check whether R1 fill has timed out if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { rsrvr1Status = getRsrvrFillToFullStatus( DG_RESERVOIR_1, 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; } } // Overflow R2 to R1 for an additional period if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) && ( TRUE == didTimeout( waitTimer, FLUSH_ADDITIONAL_TIME_MS ) ) ) { if ( ++numberOfPostDisinfectRinses < 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 ); rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; drainTimer = getMSTimerCount(); 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( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VRD1, VALVE_STATE_OPEN ); setValveState( VRD2, VALVE_STATE_CLOSED ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); // Because this is the second reservoir drain in this mode, the drain parameters must be reset initDrainParameters( DG_RESERVOIR_1 ); initDrainParameters( DG_RESERVOIR_2 ); rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; // 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 ); isThisLastDrain = TRUE; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_DRAIN_R1; } } return state; } /*********************************************************************//** * @brief * The handleChemicalDisinfectFlushCancelModeBasicPathState function handles the * chemical disinfect flush 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 chemical disinfect flush 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 flush 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 water path state. * @details Inputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer, * ChemDisinfectFlushUIState * @return next state of the chemical disinfect flush 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 flush state 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 flush complete state. The state stops chemical disinfect flush and * requests transition to mode standby. * @details Inputs: none * @details Outputs: ChemDisinfectFlushUIState * @return next state of the chemical disinfect flush 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 flush state that is published on the UI chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_COMPLETE; writeDisinfectFlushDataToNV(); //TODO: is this needed? 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 getRsrvrDrainStatus function returns the status of draining a * reservoir. If the drain times out, an alarm is set. * @details Inputs: stateTimer * @details Outputs: reservoir drain status, 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; BOOL isDrainComplete = hasTargetDrainVolumeBeenReached( r, drainSteadyStateTimeout ); if ( TRUE == isDrainComplete ) { // Set the state timer in case it needs to be used for another timeout check stateTimer = getMSTimerCount(); status = DG_RESERVOIR_REACHED_TARGET; } else if ( TRUE == didTimeout( stateTimer, timeout ) ) { // Failed to drain on time. Update the previous chemical disinfect state prevChemDisinfectFlushState = chemDisinfectFlushState; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; status = DG_RESERVOIR_NOT_REACHED_TARGET; } return status; } /*********************************************************************//** * @brief * The getRsrvrFillToFullStatus function checks whether the target reservoir * is full or not based on a plateau in the tank readings. * If the fill times out, it sets an alarm. * @details Inputs: rsrvrFillToFullStableTimeCounter, stateTimer * @details Outputs: alarm, reservoir fill status, * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 * @param timeout is the fill up timeout * @return the status of the reservoirs during filling *************************************************************************/ static DG_RESERVOIR_STATUS_T getRsrvrFillToFullStatus( DG_RESERVOIR_ID_T r, U32 timeout ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; F32 currentVolume = 0.0; F32 filteredVolume = 0.0; if ( DG_RESERVOIR_1 == r ) { currentVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); filteredVolume = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else if ( DG_RESERVOIR_2 == r ) { currentVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); filteredVolume = getLoadCellLargeFilteredWeight( 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 previous volume if ( ( currentVolume > RESERVOIR_MINIMUM_FULL_VOLUME_ML ) && ( fabs( currentVolume - filteredVolume ) < RESERVOIR_FULL_VOLUME_CHANGE_LIMIT_ML ) ) { if ( ++rsrvrFillToFullStableTimeCounter >= RSRVRS_FILL_TO_FULL_STABLE_TASK_INT ) { status = DG_RESERVOIR_REACHED_TARGET; rsrvrFillToFullStableTimeCounter = 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; } else { rsrvrFillToFullStableTimeCounter = 0; } 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 ) { // TODO: decide what data to publish 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.postDisinfectCurrentRinseCount = numberOfPostDisinfectRinses; 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 ) { #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 some states, check inlet temperature, inlet pressure, and inlet conductivity. BOOL hasConductivityFailed = TRUE; BOOL hasInletPressureFailed = TRUE; BOOL hasInletTemperatureFailed = TRUE; haveInletWaterChecksPassed= TRUE; hasConductivityFailed = ( ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) > MAX_INLET_CONDUCTIVITY_US_PER_CM ) || ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) < MIN_INLET_CONDUCTIVITY_US_PER_CM ) ); hasInletPressureFailed = ( ( getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ) < MIN_INLET_PRESSURE_PSI ) || ( getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ) > MAX_INLET_PRESSURE_PSI ) ); hasInletTemperatureFailed = ( ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) < MIN_INLET_TEMPERATURE_C ) || ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MAX_INLET_TEMPERATURE_C ) ); #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_WATER_QUALITY_CHECK ) ) { hasConductivityFailed = FALSE; } #endif if ( hasInletTemperatureFailed || hasConductivityFailed || hasInletPressureFailed ) { // 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; //TODO: ALARM_ID_NEW_WAT; chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; break; } } } /*********************************************************************//** * @brief * The writeDisinfectDataToNV function writes the disinfect flush data to the * non-volatile memory. * @details Inputs: disinfectFlushNVOps * @details Outputs: disinfectFlushNVOps * @return: none *************************************************************************/ // TODO: is this necessary? static void writeDisinfectFlushDataToNV( void ) { if ( FALSE == disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV ) { disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV = setDisinfectStatus( TRUE ); } if ( FALSE == disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV ) { disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV = setLastDisinfectDate( USAGE_INFO_CHEMICAL_DISINFECT, getRTCTimestamp() ); } } /**@}*/