Index: firmware/App/Modes/ModeChemicalDisinfectFlush.c =================================================================== diff -u -r12d64de03890be512d1ccaca5d258710f3de99bb -rd8686d68bf29761ee329fc638264d2e60a5191c0 --- firmware/App/Modes/ModeChemicalDisinfectFlush.c (.../ModeChemicalDisinfectFlush.c) (revision 12d64de03890be512d1ccaca5d258710f3de99bb) +++ firmware/App/Modes/ModeChemicalDisinfectFlush.c (.../ModeChemicalDisinfectFlush.c) (revision d8686d68bf29761ee329fc638264d2e60a5191c0) @@ -1,24 +1,1138 @@ +/************************************************************************** +* +* Copyright (c) 2020-2022 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file ModeChemicalDisinfect.c +* +* @author (last) Bill Bracken +* @date (last) 24-Oct-2022 +* +* @author (original) Sean +* @date (original) 04-Apr-2020 +* +***************************************************************************/ -#include "ModeChemicalDisinfectFlush.h" +#include "ConcentratePumps.h" +#include "ConductivitySensors.h" +#include "CPLD.h" +#include "DrainPump.h" +#include "FlowSensors.h" +#include "Heaters.h" +#include "LoadCell.h" +#include "MessageSupport.h" +#include "ModeChemicalDisinfect.h" +#include "ModeFault.h" +#include "ModeStandby.h" +#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "Pressures.h" +#include "Reservoirs.h" +#include "ROPump.h" +#include "RTC.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "TemperatureSensors.h" +#include "Timers.h" +#include "UVReactors.h" +#include "Valves.h" - /** - * @addtogroup DGChemicalDisinfectFlushMode + * @addtogroup DGChemicalDisinfectMode * @{ */ +// ********** private definitions ********** -void initChemicalDisinfectFlushMode( void ) +// General defines +#define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. +#define CHEM_DISINFECT_FLUSH_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode chem disinfect data publish interval in counts. + +// Start state defines +#define MIN_INLET_PRESSURE_PSI 30.0F ///< Minimum water inlet pressure in psi. + +// Drain R1 & R2 states defines +#define DRAIN_PUMP_TARGET_RPM 2400 ///< Drain pump target RPM during drain. +#define RSRVRS_INITIAL_FINAL_DRAIN_TIME_OUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. +#define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. +#define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. + +// Flush drain path state defines +#define FLUSH_DRAIN_WAIT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. +#define MAX_ALLOWED_FLUSH_DRAIN_PERIODS 2 ///< Number of flush drain periods to wait for inlet water to come in range +#define MIN_INLET_TEMPERATURE_C 24.0F ///< Minimum water inlet temperature in C. TODO original temperature was 25 C +#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0F ///< Maximum water inlet conductivity in us/cm +#define MIN_INLET_CONDUCTIVITY_US_PER_CM 100.0F ///< Minimum water inlet conductivity in us/cm + +// Flush circulation path state defines +#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.8F ///< RO pump target flow rate during flush/fill in L/min. +#define MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. +#define FLUSH_CICRCULATION_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush/rinse circulation path wait time in milliseconds. + +// Flush and drain R1 and R2 +#define RSRVRS_FULL_VOL_ML 1850.0F ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 +#define RSRVRS_FULL_STABLE_TIME_COUNT ( ( 4 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in counts. +#define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. +#define RSRVRS_FLUSH_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. +#define FLUSH_ADDITIONAL_TIME_MS ( 38 * MS_PER_SECOND ) ///< Additional time to flush after reservoir full +#define NUM_OF_RINSE_CYCLES 2 ///< Number of rinse cycles + +#define CONC_PUMP_FLUSH_SPEED_ML_PER_MIN 40.0 ///< Concentrate pump speed for flush +#define FLUSH_DISINFECTANT_LINE_WAIT_TIME_MS ( 2.5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time to flush disinfectant line in milliseconds. +#define FLUSH_UF_WAIT_TIME_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time to flush UF in milliseconds. + +/// Cancellation paths +typedef enum Cancellation_modes { + CANCELLATION_MODE_NONE = 0, ///< Cancellation mode none. + CANCELLATION_MODE_BASIC, ///< Cancellation mode basic. + CANCELLATION_MODE_WATER, ///< Cancellation mode water. + NUM_OF_CANCELLATION_MODES ///< Number of cancellation modes. +} CANCELLATION_MODE_T; +/// Non-volatile write structure +typedef struct +{ + BOOL hasDisFlushStatusBeenWrittenToNV; ///< Boolean flag to indicate whether the disinfect flush status been written to NV or not. + BOOL hasDisFlushCompleteDateBeenWrittenToNV; ///< Boolean flag to indicate whether the disinfect flush complete date been written to NV or not. +} DISINFECT_FLUSH_NV_OPS_T; + +// ********** private data ********** + +static DG_CHEM_DISINFECT_FLUSH_STATE_T chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; ///< Currently active chemical disinfect state. +static DG_CHEM_DISINFECT_FLUSH_STATE_T prevChemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; ///< Previous active chemical disinfect flush state before alarm. +static DG_CHEM_DISINFECT_UI_STATE_T chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; ///< Currently active chemical disinfect UI state. +static U32 overallChemDisinfectFlushTimer = 0; ///< Chemical disinfect cycle total timer. +static U32 stateTimer = 0; ///< Chemical disinfect state timer to be used in different states. +static U32 stateTrialCounter = 0; ///< Chemical disinfect state trial counter to be used for retries in different states. +static BOOL areTempSensorsInRange = FALSE; ///< Chemical disinfect temperature sensors in/out range flag. +static BOOL haveInletWaterChecksPassed = TRUE; ///< Inlet water pressure, temperature, and pressure in range flag +/// Boolean flag to check whether draining R1 and R2 is at the end of the chemical disinfect flush cycle or in the beginning. So the drain states can be reused. +static BOOL isThisLastDrain = FALSE; +static DG_RESERVOIR_STATUS_T rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 1 status. +static DG_RESERVOIR_STATUS_T rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 2 status. +static F32 R1ChemDisinfectFlushVol = 0.0; ///< Reservoir 1 full volume during chemical disinfect. +static F32 R2ChemDisinfectFlushVol = 0.0; ///< Reservoir 2 full volume during chemical disinfect. +static U32 chemDisinfectFlushTimer = 0; ///< Chemical disinfect timer. +static U32 rinseCycleCounter = 0; ///< Counter for rinse fill and drain cycles +static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during chemical disinfect. +static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during chemical disinfect. +static U32 dataPublishCounter = 0; ///< Chemical Disinfect data publish counter. +static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. +static U32 rsrvrFillStableTimeCounter; ///< Reservoirs fill stable time counter. +static ALARM_ID_T alarmDetectedPendingTrigger; ///< Chemical disinfect alarm to raise. +static U32 numberOfPostDisinfectRinses; ///< Number of times to rinse the fluid path after chemical disinfect. +static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. +static DISINFECT_FLUSH_NV_OPS_T disinfectFlushNVOps; ///< Disinfect flush non-volatile memory operations. + +// ********** private function prototypes ********** + +//static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushRemoveAcidBottleFromUIState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushStartState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushDrainR1State( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushDrainR2State( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushDrainState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushDisinfectantLineState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushUFState( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushR2ToR1DrainR1State( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushR1ToR2DrainR2State( void ); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCancelModeBasicPathState(void); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCancelModeWaterPathState(void); +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCompleteState( void ); + +static void failChemicalDisinfectFlush( void ); +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ); +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); +static void publishChemicalDisinfectFlushData( void ); +static void monitorModeChemicalDisinfectFlush( void ); +static void writeDisinfectDataToNV( void ); + +/*********************************************************************//** + * @brief + * The initChemicalDisinfectFlushMode function initializes the chemical + * disinfect flush mode module. + * @details Inputs: none + * @details Outputs: chemDisinfectFlushState, stateTimer, isThisLastDrain, + * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, + * overallChemDisinfectFlushTimer, + * cancellationMode, rsrvrFillStableTimeCounter, prevChemDisinfectFlushState + * numberOfPostDisinfectRinses, + * chemDisinfectFlushUIState, haveDrainParamsBeenInit, + * disinfectFlushNVOps + * @return none + *************************************************************************/ +void initChemicalDisinfectFlushMode( void ) +{ + chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; + prevChemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; + stateTimer = 0; + isThisLastDrain = FALSE; + stateTrialCounter = 0; + areTempSensorsInRange = FALSE; + haveInletWaterChecksPassed = TRUE; + rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; + rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; + overallChemDisinfectFlushTimer = 0; + cancellationMode = CANCELLATION_MODE_NONE; + rsrvrFillStableTimeCounter = 0; + numberOfPostDisinfectRinses = 0; + R1ChemDisinfectFlushVol = 0.0; + R2ChemDisinfectFlushVol = 0.0; + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; + haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; + haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; + //disinfectFlushNVOps.hasFlushCompleteDateBeenWrittenToNV = FALSE; + //disinfectFlushNVOps.hasFlushStatusBeenWrittenToNV = FALSE; } +/*********************************************************************//** + * @brief + * The transitionToChemicalDisinfectFlushMode function prepares for transition to + * chemical disinfect flush mode. + * @details Inputs: none + * @details Outputs: chemical disisnfect flush mode variables are reset + * @return initial state + *************************************************************************/ U32 transitionToChemicalDisinfectFlushMode( void ) { - return 1; + deenergizeActuators(); + + initChemicalDisinfectFlushMode(); + + setCPLDCleanLEDColor( CPLD_CLEAN_LED_YELLOW ); + + return chemDisinfectFlushState; } -U32 execChemicalDisinfectFlushMode( void ) +/*********************************************************************//** + * @brief + * The execChemicalDisinfectFlushMode function executes the chemical disinfect + * flush mode state machine. + * @details Inputs: none + * @details Outputs: Chemical disinfect flush mode state machine executed + * @return current state of chemical disinfect flush mode + *************************************************************************/ +U32 execChemicalDisinfectFlushMode( void ) { - return 1; + monitorModeChemicalDisinfectFlush(); + + switch ( chemDisinfectFlushState ) + { + case DG_CHEM_DISINFECT_FLUSH_STATE_START: + chemDisinfectFlushState = handleChemicalDisinfectFlushStartState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1: + chemDisinfectFlushState = handleChemicalDisinfectFlushDrainR1State(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2: + chemDisinfectFlushState = handleChemicalDisinfectFlushDrainR2State(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushDrainState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushDisinfectantLineState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushUFState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushR2ToR1DrainR1State(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2: + chemDisinfectFlushState = handleChemicalDisinfectFlushFlushR1ToR2DrainR2State(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH: + chemDisinfectFlushState = handleChemicalDisinfectFlushCancelModeBasicPathState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH: + chemDisinfectFlushState = handleChemicalDisinfectFlushCancelModeWaterPathState(); + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_COMPLETE: + chemDisinfectFlushState = handleChemicalDisinfectFlushCompleteState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_DG_CHEM_DISINFECT_INVALID_EXEC_STATE, chemDisinfectFlushState ) + chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; + break; + } + + //publishChemicalDisinfectFlushData(); + + return chemDisinfectFlushState; } + +/*********************************************************************//** + * @brief + * The getCurrentChemicalDisinfectFlushState function returns the current state + * of the chemical disinfect flush mode. + * @details Inputs: chemFlushState + * @details Outputs: none + * @return current state of chemical disinfect flush mode + *************************************************************************/ +DG_CHEM_DISINFECT_FLUSH_STATE_T getCurrentChemicalDisinfectFlushState( void ) +{ + return chemDisinfectFlushState; +} + +/*********************************************************************//** + * @brief + * The stopChemicalDisinfectFlush function stops chemical disinfect flush mode. + * @details Inputs: none + * @details Outputs: none + * @return TRUE is current operation mode is chemical disinfect flush, + * otherwise FALSE + *************************************************************************/ +BOOL stopChemicalDisinfectFlush( void ) +{ + BOOL status = FALSE; + + // Check if the current operation mode is chemical disinfect + if ( DG_MODE_CHFL == getCurrentOperationMode() ) + { + // Transition to mode standby + requestNewOperationMode( DG_MODE_STAN ); + + status = TRUE; + } + + return status; +} + +// ********** private functions ********** + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushStartState function handles the chemical + * disinfect flush start state. The state checks the inlet pressure and the + * difference in between TDi and TRo sensors and if they are not in + * range, it transitions to basic cancellation path. Otherwise, it + * transitions to the next state. + * @details Inputs: alarm, rsrvrFillStableTimeCounter, rsrvr1Status, + * stateTimer + * @details Outputs: alarm, rsrvrFillStableTimeCounter, rsrvr1Status, + * stateTimer, chemDisinfectFlushUIState + * @return next state of the chemical disinfect flush state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushStartState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1; + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; + + // Start overall chemical disinfect timer + overallChemDisinfectFlushTimer = getMSTimerCount(); + + // Set all the actuators to reset and de-energized state + deenergizeActuators(); + + // Close VPi to prevent wasting water + setValveState( VPI, VALVE_STATE_CLOSED ); + + // Set the actuators to drain R1 + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + rsrvrFillStableTimeCounter = 0; + // Assume reservoir 1 is full and drain it + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + stateTimer = getMSTimerCount(); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushDrainR1State function handles the chemical + * disinfect flush drain R1 state. The state drains reservoir 1. If the + * transition is finished within the time, it transitions to the next state, + * otherwise, it transitions to basic cancellation path. + * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, isThisLastDrain + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * ChemDisinfectFlushUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushDrainR1State( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1; + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; + + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_FINAL_DRAIN_TIME_OUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + // Assume reservoir 2 is full and drain it + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + + tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); + + // Done with draining R1 + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2; + + // Start the timer + stateTimer = getMSTimerCount(); + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushDrainR2State function handles the chemical + * disinfect flush drain R2 state. The state drains reservoir 2. If the + * transition is finished within the time, it transitions to the next + * state, otherwise, it transitions to basic cancellation path. + * @details Inputs: stateTimer, rsrvr2Status, isThisLastDrain, + * stateTrialCounter + * @details Outputs: stateTimer, rsrvr2Status, stateTrialCounter, + * chemDisinfectFlushUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushDrainR2State( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2; + + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_FINAL_DRAIN_TIME_OUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + signalDrainPumpHardStop(); // Done with draining + if ( TRUE == isThisLastDrain ) + { + state = DG_CHEM_DISINFECT_FLUSH_STATE_COMPLETE; + } + else + { + tareLoadCell( LOAD_CELL_RESERVOIR_2_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_2_BACKUP ); + // ??? make sure load cell check is done in tareLoadCell or add that here? + + // Set valves for next state, flush drain + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VPI, VALVE_STATE_OPEN ); + + stateTrialCounter = 0; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN; + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushFlushDrainState function handles the chemical + * disinfect flush drain state. The state flushes the drain line for a + * period of time and then measures the temperature and conductivity of + * water. If they are not within the range after the specified number of tries, + * it transitions to basic cancellation path, otherwise it transitions to the next state. + * @details Inputs: stateTimer, stateTrialCounter, alarm, + * prevChemDisinfectFlushState + * @details Outputs: stateTimer, stateTrialCounter, alarm, + * prevChemDisinfectFlushState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushDrainState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN; + + // TODO: check whether flush has already been completed within some time period, skip this state if it has + + // Check if flush time has elapsed + if ( TRUE == didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) + { + if (haveInletWaterChecksPassed) + { + // set pumps and valves for next state, flush disinfectant line + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + // Set the concentrate pump to run at a constant speed during priming in reverse + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, -1.0 * CONC_PUMP_FLUSH_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + // Turn on the bicarb line with forward direction, to dispense the chemical and mix + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMP_FLUSH_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE; + } + else + { + // If the number of failures have not exceeded the limit, try again. + stateTrialCounter++; + if ( stateTrialCounter < MAX_ALLOWED_FLUSH_DRAIN_PERIODS ) + { + stateTimer = getMSTimerCount(); + } + // Couldn't get a good water sample after a couple of trials and the disinfect flush cycle failed + else + { + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_DG_NEW_WAT; + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + } + + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushFlushDisinfectantLineState function handles the + * chemical disinfect flush flush disinfectant line state. The state flushes the + * disinfectant line for a period of time. After the flush if the temperature + * sensors are not within a certain degrees from each other, the state + * transitions to basic cancellation path, otherwise, it transitions to the + * next state. + * @details Inputs: stateTimer, stateTrialCounter, prevChemDisinfectFlushState + * alarm, areTempSensorsInRange, rsrvr1Status, rsrvr2Status + * @details Outputs: stateTimer, stateTrialCounter, prevChemDisinfectFlushState, + * alarm, areTempSensorsInRange, rsrvr1Status, rsrvr2Status + * @return next state of the chemical disinfect state machine + ************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushDisinfectantLineState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE; + + // Check if the flush disinfectant line time has elapsed + if ( TRUE == didTimeout( stateTimer, FLUSH_DISINFECTANT_LINE_WAIT_TIME_MS ) ) + { + + // set the pumps and valves for the next state, flush UF + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRD2, VALVE_STATE_OPEN ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushFlushUFState function handles the + * chemical disinfect flush flush UF state. + * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectFlushState + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectFlushState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushUFState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF; + + // Check if the flush UFtime has elapsed + if ( TRUE == didTimeout( stateTimer, FLUSH_UF_WAIT_TIME_MS ) ) + { + // set the pumps and valves for the next state, flush R2 to R1 and drain R1 + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRD1, VALVE_STATE_OPEN ); + + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + rinseCycleCounter = 0; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1; + } + + return state; +} + + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushRinseR2ToR1AndDrainR1State function handles + * the chemical disinfect rinse R2 to R1 and drain R1 state. The state + * rinses reservoir 2 and drains reservoir 1 at the same time. If the drain + * process times out, it transitions to basic cancellation state, and + * if the rinse times out, it transitions to water cancellation state. + * If the drain and rinse are completed within the define time, it + * transitions to the next state. + * @details Inputs: rsrvr1Status, rsrvr2Status + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectFlushState, alarmDetectedPendingTrigger + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushR2ToR1DrainR1State( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1; + static BOOL rsrvr1Empty = FALSE; + static BOOL rsrvr2Full = FALSE; + + if ( FALSE == rsrvr1Empty ) + { + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_FLUSH_DRAIN_TIMEOUT_MS ); + } + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + // Done with draining R1 + signalDrainPumpHardStop(); + setValveState( VRD1, VALVE_STATE_CLOSED ); + rsrvr1Empty = TRUE; + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + // reservoir 1 drain timeout + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + + if ( FALSE == rsrvr2Full ) + { + // Reservoir 2 must be completely full + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + } + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + rsrvr2Full = TRUE; + stateTimer = getMSTimerCount(); + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + + if ( ( TRUE == rsrvr2Full ) && ( TRUE == rsrvr1Empty ) && ( TRUE == didTimeout( stateTimer, FLUSH_ADDITIONAL_TIME_MS ) ) ) + { + // Set the valves to flush R1 to R2 and drain R2 + setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + + // Turn on the drain pump to drain R2 + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Set the reservoir status + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2; + + } + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushRinseR1ToR2AndDrainR2State function handles + * the chemical disinfect flush rinse R1 to R2 and drain R2 state. The state + * rinses reservoir 1 and drains reservoir 2 at the same time. If the drain + * process times out, it transitions to basic cancellation state, and + * if the rinse times out, it transitions to water cancellation state. + * If the drain and rinse are completed within the define time, it + * transitions to the next state. + * @details Inputs: rsrvr1Status, rsrvr2Status, rinseCycleCounter + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectFlushState, alarmDetectedPendingTrigger, isThisLastDrain + * numberOfPostDisinfectRinses + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushFlushR1ToR2DrainR2State( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2; + + static BOOL rsrvr2Empty = FALSE; + static BOOL rsrvr1Full = FALSE; + + if ( FALSE == rsrvr2Empty ) + { + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_FLUSH_DRAIN_TIMEOUT_MS ); + } + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // Done with draining R2 + signalDrainPumpHardStop(); + setValveState( VRD2, VALVE_STATE_CLOSED ); + rsrvr2Empty = TRUE; + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + // reservoir 2 drain timeout + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + + if ( FALSE == rsrvr1Full ) + { + // Reservoir 1 must be completely full + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + } + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + rsrvr1Full = TRUE; + stateTimer = getMSTimerCount(); + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + + if ( ( TRUE == rsrvr1Full ) && ( TRUE == rsrvr2Empty ) && ( TRUE == didTimeout( stateTimer, FLUSH_ADDITIONAL_TIME_MS ) ) ) + { + ++rinseCycleCounter; + if ( rinseCycleCounter < NUM_OF_RINSE_CYCLES ) + { + // Set the valves to flush R2 to R1 and drain R1 + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + + // Turn on the drain pump to drain R2 + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Set the reservoir status + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2; + } + else + { + // Set the valves to drain R1 + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_OPEN ); + + // Turn on the drain pump to drain R2 + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Turn off CP1 and CP2 + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + + //Turn off UV reactors + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + + // Set the reservoir status + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + + isThisLastDrain = TRUE; + state = DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1; + } + } + + return state; + +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushCancelModeBasicPathState function handles the + * chemical disinfect cancel mode basic path state. The state sets the state + * to complete and raises an alarm. + * @details Inputs: none + * @details Outputs: cancellationMode, ChemDisinfectFlushUIState + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCancelModeBasicPathState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_CANCEL_FLUSH; + + // Set the cancellation mode + cancellationMode = CANCELLATION_MODE_BASIC; + + failChemicalDisinfectFlush(); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushCancelModeWaterPathState function handles the + * chemical disinfect flush cancel mode cold water path state. + * @details Inputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer + * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer, + * ChemDisinfectFlushUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCancelModeWaterPathState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_CANCEL_FLUSH; + + if ( CANCELLATION_MODE_NONE == cancellationMode ) + { + // Stop all the actuators first then decide who should run next + deenergizeActuators(); + + cancellationMode = CANCELLATION_MODE_WATER; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + + // The drain is set to start from reservoir 2 + setValveState( VRD2, VALVE_STATE_OPEN ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Start the timer for drain timeout + stateTimer = getMSTimerCount(); + } + + // If reservoir 2 is empty, set to drain reservoir 1 + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // Set the drain valve to reservoir 1 + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + } + } + // Could not drain reservoir 2. Transition to basic cancellation path + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + // If reservoir 2 has already been drained and reservoir 1 is empty, reset and switch to complete + if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + failChemicalDisinfectFlush(); + } + // Could not drain reservoir 1. Transition to basic cancellation path + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevChemDisinfectFlushState = state; + state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectFlushCompleteState function handles the chemical + * disinfect complete state. The state stops chemical disinfect and + * requests transition to mode standby. + * @details Inputs: none + * @details Outputs: ChemDisinfectFlushUIState + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushCompleteState( void ) +{ + DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_COMPLETE; + + // Set the chemical disinfect that is published on the UI + chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_COMPLETE; + + stopChemicalDisinfectFlush(); + + return state; +} + +/*********************************************************************//** + * @brief + * The failChemicalDisinfectFlush function sets the alarm that failed the + * chemical disinfect mode. + * @details Inputs: alarmDetectedPendingTrigger, prevChemDisinfectFlushState + * @details Outputs: none + * @return none + *************************************************************************/ +static void failChemicalDisinfectFlush( void ) +{ + SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, prevChemDisinfectFlushState ) +} + +/*********************************************************************//** + * @brief + * The getRsrvrFillStatus function checks whether the target reservoir + * is full or not. If the fill times out, it sets the state machine to + * complete and exits the chemical disinfect mode. + * @details Inputs: rsrvrFillStableTimeCounter, alarm, stateTimer, chemDisinfectFlushState + * @details Outputs: prevChemDisinfectFlushState + * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 + * @param targetVol is the target fill volume + * @param timeout is the fill up timeout + * @return the status of the reservoirs during filling + *************************************************************************/ +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ) +{ + DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; + F32 volume = 0.0; + + if ( DG_RESERVOIR_1 == r ) + { + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + } + else if ( DG_RESERVOIR_2 == r ) + { + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, r ) + } + + // Check the volume of the reservoir against the target volume + if ( volume >= targetVol ) + { + if ( ++rsrvrFillStableTimeCounter >= RSRVRS_FULL_STABLE_TIME_COUNT ) + { + status = DG_RESERVOIR_REACHED_TARGET; + rsrvrFillStableTimeCounter = 0; + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + } + } + else if ( TRUE == didTimeout( stateTimer, timeout ) ) + { + // Failed to fill ontime. Update the previous chemical disinfect state and transition to basic cancellation + prevChemDisinfectFlushState = chemDisinfectFlushState; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_FILL_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; + } + + return status; +} + +/*********************************************************************//** + * @brief + * The getRsrvrDrainStatus function returns the status of draining a + * reservoir. + * @details Inputs: stateTimer, chemDisinfectFlushState + * alarm + * @details Outputs: stateTimer, prevChemDisinfectFlushState, alarm + * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 + * @param drainSteadyStateTimeout which is the time the reservoir's level + * does not change and is steady state + * @param timeout which is the timeout that a reservoir must be drained by + * then + * @return the status of the reservoirs during draining + *************************************************************************/ +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ) +{ + DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_ABOVE_TARGET; + + // If the drain parameters of the reservoir is not initialized, initialize them + if ( FALSE == haveDrainParamsBeenInit[ r ] ) + { + initDrainParameters( r ); + haveDrainParamsBeenInit[ r ] = TRUE; + } + + BOOL isDrainComplete = hasTargetDrainVolumeBeenReached( r, drainSteadyStateTimeout ); + + if ( TRUE == isDrainComplete ) + { + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + haveDrainParamsBeenInit[ r ] = FALSE; + status = DG_RESERVOIR_REACHED_TARGET; + } + else if ( TRUE == didTimeout( stateTimer, timeout ) ) + { + // Failed to drain on time. Update the previous chemical disinfect state + prevChemDisinfectFlushState = chemDisinfectFlushState; + haveDrainParamsBeenInit[ r ] = FALSE; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; + } + + return status; +} + + +/*********************************************************************//** + * @brief + * The publishChemicalDisinfectFlushData function publishes chemical disinfect + * flush data at the set interval. + * @details Inputs: dataPublishCounter + * @details Outputs: dataPublishCounter + * @return: none + *************************************************************************/ +/* needs work +static void publishChemicalDisinfectFlushData( void ) +{ + if ( ++dataPublishCounter >= CHEM_DISINFECT_FLUSH_DATA_PUB_INTERVAL ) + { + MODE_CHEMICAL_DISINFECT_FLUSH_DATA_T data; + MODE_CHEMICAL_DISINFECT_UI_DATA_T uiData; + + data.chemDisinfectFlushState = (U32)chemDisinfectFlushState; + data.stateElapsedTime = calcTimeSince( stateTimer ); + data.overallElapsedTime = calcTimeSince( overallChemDisinfectFlushTimer ); + data.cancellationMode = (U32)cancellationMode; + + // General data publish channel + broadcastData( MSG_ID_DG_CHEM_DISINFECT_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( MODE_CHEMICAL_DISINFECT_FLUSH_DATA_T ) ); + + // Publish data to UI + broadcastData( MSG_ID_DG_CHEM_DISINFECT_TIME_DATA, COMM_BUFFER_OUT_CAN_DG_2_UI, (U08*)&uiData, sizeof( MODE_CHEMICAL_DISINFECT_FLUSH_UI_DATA_T ) ); + + dataPublishCounter = 0; + } +} +*/ + +/*********************************************************************//** + * @brief + * The monitorModeChemicalDisinfectFlush function monitors the status of the caps and + * sets the state of the state machine to water cancellation path if the caps + * are not closed during the run. It also monitors inlet water conditions. + * @details Inputs: chemDisinfectState + * @details Outputs: prevChemDisinfectFlushState, chemDisinfectState, + * alarmDetectedPendingTrigger + * @return: none + *************************************************************************/ +static void monitorModeChemicalDisinfectFlush( void ) +{ + BOOL hasConductivityFailed = TRUE; + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + // If either the dialysate cap or the concentrate cap is open during any state, alarm + if ( ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) + { + + // Set the variables to fail and go to cancel water path. Set the pending alarm to no alarm so the cancel water path + // will not be raising the alarm at end of the cancel water path. The recoverable alarm is raised here in this function + U32 ConcCap = (U32)getSwitchStatus( CONCENTRATE_CAP ); + U32 DialysateCap = (U32)getSwitchStatus( DIALYSATE_CAP ); + prevChemDisinfectFlushState = chemDisinfectFlushState; + chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_OR_CONC_CAP_NOT_IN_PROPER_POSITION; + } + } + + // In all states, check inlet temperature, inlet pressure, and inlet conductivity. + haveInletWaterChecksPassed= TRUE; + hasConductivityFailed = ( ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) >= MAX_INLET_CONDUCTIVITY_US_PER_CM ) || + ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) <= MIN_INLET_CONDUCTIVITY_US_PER_CM ) ); +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + { + hasConductivityFailed = FALSE; + } +#endif + if ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) < MIN_INLET_TEMPERATURE_C || + hasConductivityFailed || + getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ) < MIN_INLET_PRESSURE_PSI) + { + // Inlet check failed, alarm unless in the start, drain, or flush drain states + haveInletWaterChecksPassed= FALSE; // set flag for flush drain state + switch( chemDisinfectFlushState ) + { + case DG_CHEM_DISINFECT_FLUSH_STATE_START: + case DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1: + case DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2: + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN: + break; + + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE: + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF: + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1: + case DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2: + prevChemDisinfectFlushState = chemDisinfectFlushState; + alarmDetectedPendingTrigger = ALARM_ID_INLET_WATER_TEMPERATURE_IN_LOW_RANGE; //ALARM_ID_NEW_WAT; + chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; + break; + } + } + + } + +/*********************************************************************//** + * @brief + * The writeDisinfectDataToNV function writes the disinfection data to the + * non-volatile memory. + * @details Inputs: disinfectNVOps + * @details Outputs: disinfectNVOps + * @return: none + *************************************************************************/ +static void writeDisinfectDataToNV( void ) +{ + ; ///< Boolean flag to indicate whether the disinfect flush status been written to NV or not. + BOOL ; + if ( FALSE == disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV ) + { + disinfectFlushNVOps.hasDisFlushCompleteDateBeenWrittenToNV = setDisinfectStatus( TRUE ); + } + + if ( FALSE == disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV ) + { + disinfectFlushNVOps.hasDisFlushStatusBeenWrittenToNV = setLastDisinfectDate( USAGE_INFO_CHEMICAL_DISINFECT, getRTCTimestamp() ); + } +} + +/**@}*/