/************************************************************************** * * Copyright (c) 2022-2023 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 ModeChemicalDisinfectFlush.c * * @author (last) Dara Navaei * @date (last) 03-Oct-2023 * * @author (original) Dara Navaei * @date (original) 15-Nov-2022 * ***************************************************************************/ #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 DGChemicalDisinfectFlushMode * @{ */ // ********** 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_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. #define DRAIN_WEIGHT_UNCHANGE_TIMEOUT_MS ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. // Flush drain path state defines #define FLUSH_DRAIN_WAIT_TIME_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. // 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. // Fill reservoirs to full defines #define RESERVOIR_MINIMUM_FULL_VOLUME_ML 1850.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.0F ///< Concentrate pump CP1 speed for flush #define CONC_PUMP_CP2_FLUSH_SPEED_ML_PER_MIN 40.8F ///< 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. // Sample flush R1 to R2 drain R2 defines #define SAMPLE_FLUSH_WAIT_TIME_MS ( 2.5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time to wait for sampling flush R1 to R2 drain R2 in milliseconds. #define SAMPLE_FLUSH_WAIT_STATE_TIMEOUT_MS ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time to wait for sampling flush R1 to R2 drain R2 state waiting for the user to confirm in milliseconds. #define SAMPLE_FLUSH_RESULT_FAIL 0 ///< Chemical disinfect flush result fail. #define SAMPLE_FLUSH_RESULT_PASS 1 ///< Chemical disinfect flush result pass. /// Non-volatile write structure typedef struct { BOOL hasDisStatusBeenWrittenToNV; ///< Boolean flag to indicate whether the disinfect status been written to NV or not. } DISINFECT_NV_OPS_T; /// Chem flush sample results structure typedef struct { BOOL hasMessageBeenReceived; ///< Boolean flag to indicate whether the message has been received from HD. U32 chemFlushSampleResult; ///< Chemical disinfect flush sample results back from HD. } CHEM_FLUSH_SAMPLE_RESULT_T; // ********** private data ********** static DG_CHEM_DISINFECT_FLUSH_STATE_T chemDisinfectFlushState; ///< Currently active chemical disinfect flush state. static DG_CHEM_DISINFECT_FLUSH_STATE_T prevChemDisinfectFlushState; ///< Previous active chemical disinfect flush state before alarm. static DG_CHEM_DISINFECT_FLUSH_UI_STATE_T chemDisinfectFlushUIState; ///< Currently active chemical disinfect flush UI state. static U32 overallChemDisinfectFlushTimer; ///< Chemical disinfect flush cycle total timer. static U32 stateTimer; ///< Chemical disinfect flush state timer to be used in different states. static BOOL isThisLastDrain; ///< 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; ///< Reservoir 1 status. static DG_RESERVOIR_STATUS_T rsrvr2Status; ///< Reservoir 2 status. static U32 waitTimer; ///< Wait timer for reservoir flushing. static U32 dataPublishCounter; ///< Chemical disinfect flush data publish counter. static CANCELLATION_MODE_T cancellationMode; ///< Cancellation mode. static U32 rsrvrFillToFullStableTimerCounter; ///< 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_NV_OPS_T disinfectNVOps; ///< Disinfect non-volatile memory operations. static BOOL hasAlarmBeenTriggered; ///< Boolean flag to indicate that an alarm has been raised. static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. static CHEM_FLUSH_SAMPLE_RESULT_T sampleResult; ///< Chemical disinfect flush sample result. // ********** private function prototypes ********** 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 handleChemicalDisinfectFlushSampleFlushR1ToR2DrainR2State( 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 writeDisinfectDataToNV( DG_USAGE_INFO_ITEMS_T info ); /*********************************************************************//** * @brief * The initChemicalDisinfectFlushMode function initializes the chemical * disinfect flush mode module. * @details Inputs: none * @details Outputs: chemDisinfectFlushState, stateTimer, isThisLastDrain, * stateTrialCounter, rsrvr1Status, rsrvr2Status, haveInletWaterChecksPassed, * overallChemDisinfectFlushTimer, hasAlarmBeenTriggered, haveDrainParamsBeenInit * cancellationMode, rsrvrFillToFullStableTimeCounter, prevChemDisinfectFlushState * numberOfPostDisinfectRinses, chemDisinfectFlushUIState, disinfectFlushNVOps, * sampleResult * @return none *************************************************************************/ void initChemicalDisinfectFlushMode( void ) { chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; prevChemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_START; stateTimer = getMSTimerCount(); isThisLastDrain = FALSE; rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; overallChemDisinfectFlushTimer = getMSTimerCount(); cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillToFullStableTimerCounter = 0; numberOfPostDisinfectRinses = 0; alarmDetectedPendingTrigger = ALARM_ID_NO_ALARM; chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING; waitTimer = 0; dataPublishCounter = 0; disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; hasAlarmBeenTriggered = FALSE; haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; sampleResult.hasMessageBeenReceived = FALSE; sampleResult.chemFlushSampleResult = SAMPLE_FLUSH_RESULT_FAIL; } /*********************************************************************//** * @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( NO_PARK_CONC_PUMPS ); initChemicalDisinfectFlushMode(); setCurrentSubState( NO_SUB_STATE ); setCPLDCleanLEDColor( CPLD_CLEAN_LED_YELLOW ); // Upon transition to mode chemical flush set CD1 and CD2 calibration records to be picked to the normal // table. If the chemical disinfect is successful, mode chemical disinfect flush is automatically started setCondcutivitySensorCalTable( CONDUCTIVITYSENSORS_CD1_SENSOR, CAL_DATA_CD1_COND_SENSOR ); setCondcutivitySensorCalTable( CONDUCTIVITYSENSORS_CD2_SENSOR, CAL_DATA_CD2_COND_SENSOR ); activateAlarmNoData( ALARM_ID_DG_CHEM_DISINFECT_FLUSH_REMOVE_ACID ); 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 ) { // The inlet pressure shall be checked all the time as long as VPi is open checkInletWaterPressure(); if ( chemDisinfectFlushState != DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN ) { // Do not check on the inlet water temperature and conductivity until the inlet filters have been flushed // The initial states are drain reservoirs but in those states VPi is closed so these alarms are not checked checkInletWaterTemperature(); checkInletWaterConductivity(); } 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_SAMPLE_FLUSH_R1_TO_R2_DRAIN_R2: chemDisinfectFlushState = handleChemicalDisinfectFlushSampleFlushR1ToR2DrainR2State(); 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_FLUSH_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 setChemicalDisinfectFlushSampleResult function sets the received chemical * disinfect sample flush result. * @details Inputs: none * @details Outputs: sampleResult * @return none *************************************************************************/ void setChemicalDisinfectFlushSampleResult( U32 result ) { sampleResult.hasMessageBeenReceived = TRUE; sampleResult.chemFlushSampleResult = result; } /*********************************************************************//** * @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_START; chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_FLUSH_AFTER_DISINFECT; if ( FALSE == isAlarmActive( ALARM_ID_DG_CHEM_DISINFECT_FLUSH_REMOVE_ACID ) ) { if ( ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) { activateAlarmNoData( ALARM_ID_DG_CHEM_DISINFECT_FLUSH_REMOVE_ACID ); } else { // Close VPi to prevent wasting water setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VRD1, VALVE_STATE_OPEN ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_DRAIN_R1; } } 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, * @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 ( ( TRUE == isThisLastDrain ) && ( SAMPLE_FLUSH_RESULT_PASS == sampleResult.chemFlushSampleResult ) ) { // Drain R1 state comes after chemical flush sample result. If this is the last drain, and the sample flush result // has passed write the new chemical flush sample time to the NV memory. This is done in drain R1 so the write to NV // can be attempted until the write is scheduled in the NV queue. // If the sample result is failed, do not update the time so the chemical disinfect sample flush is considered failed. writeDisinfectDataToNV( USAGE_INFO_CHEM_FLUSH ); } if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT_MS, 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_WATER_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_MS, RSRVRS_INITIAL_FINAL_DRAIN_TIME_OUT_MS ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { signalDrainPumpHardStop(); // Done with draining setValveState( VRD2, VALVE_STATE_CLOSED ); 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 ); turnOnUVReactor( INLET_UV_REACTOR ); 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_WATER_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; // Check if flush time has elapsed if ( TRUE == didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) { // 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 acid concentrate pump to run at a constant speed during flushing in reverse setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMP_CP1_FLUSH_SPEED_ML_PER_MIN ); requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); // Turn on the bicarb line pump 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( OUTLET_UV_REACTOR ); stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE; } 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 * @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, numberOfPostDisinfectRinses, * rsrvrFillToFullStableTimerCounter * @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; numberOfPostDisinfectRinses = 0; rsrvrFillToFullStableTimerCounter = 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, waitTimer * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, * waitTimer, 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 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; 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 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; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1; } else { setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); // Number of rinse cycles complete stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_SAMPLE_FLUSH_R1_TO_R2_DRAIN_R2; } } return state; } /*********************************************************************//** * @brief * The handleChemicalDisinfectFlushSampleFlushR1ToR2DrainR2State function * handles the chemical disinfect flush sample flush R1 to R2 and drain R2 * state. * @details Inputs: stateTimer, hasAlarmBeenTriggered * @details Outputs: stateTimer, hasAlarmBeenTriggered, rsrvr1Status, * isThisLastDrain, alarmDetectedPendingTrigger, prevChemDisinfectFlushState * @return next state of the chemical disinfect flush state machine *************************************************************************/ static DG_CHEM_DISINFECT_FLUSH_STATE_T handleChemicalDisinfectFlushSampleFlushR1ToR2DrainR2State( void ) { DG_CHEM_DISINFECT_FLUSH_STATE_T state = DG_CHEM_DISINFECT_FLUSH_STATE_SAMPLE_FLUSH_R1_TO_R2_DRAIN_R2; if ( ( TRUE == didTimeout( stateTimer, SAMPLE_FLUSH_WAIT_TIME_MS ) ) && ( FALSE == hasAlarmBeenTriggered ) ) { hasAlarmBeenTriggered = TRUE; activateAlarmNoData( ALARM_ID_DG_CHEM_DISINFECT_FLUSH_FLUSH_SAMPLE ); } if ( ( TRUE == hasAlarmBeenTriggered ) && ( FALSE == isAlarmActive( ALARM_ID_DG_CHEM_DISINFECT_FLUSH_FLUSH_SAMPLE ) ) ) { if ( TRUE == sampleResult.hasMessageBeenReceived ) { // The sample flush message has been received. signalROPumpHardStop(); turnOffUVReactor( INLET_UV_REACTOR ); turnOffUVReactor( OUTLET_UV_REACTOR ); requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VDR, 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 ); isThisLastDrain = TRUE; rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; hasAlarmBeenTriggered = TRUE; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_FLUSH_STATE_DRAIN_R1; } } if ( TRUE == didTimeout( stateTimer, SAMPLE_FLUSH_WAIT_STATE_TIMEOUT_MS ) ) { alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_FLUSH_SAMPLE_TIMEOUT; prevChemDisinfectFlushState = state; state = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; } 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; chemDisinfectFlushUIState = CHEM_DISINFECT_FLUSH_UI_STATE_CANCEL_FLUSH; 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; 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( NO_PARK_CONC_PUMPS ); 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 ); setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); 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_MS, RSRVRS_INITIAL_DRAIN_TIMEOUT_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_MS, RSRVRS_INITIAL_DRAIN_TIMEOUT_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; 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 ) { // If a fault alarm is active go to mode fault otherwise for cleaning mode alarms, transition to standby DG_OP_MODE_T nextOpMode = ( FALSE == isDGFaultAlarmActive() ? DG_MODE_STAN : DG_MODE_FAUL ); // In the cleaning modes the alarms are triggered but the mode is not transitioned to fault automatically // so transition to fault mode is done here if ( alarmDetectedPendingTrigger != ALARM_ID_NO_ALARM ) { SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, prevChemDisinfectFlushState ) } requestNewOperationMode( nextOpMode ); } /*********************************************************************//** * @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 = FALSE; // If the drain parameters of the reservoir is not initialized, initialize them if ( FALSE == haveDrainParamsBeenInit[ r ] ) { initDrainParameters( r ); haveDrainParamsBeenInit[ r ] = TRUE; } // NOTE: the drain status should be checked once the reservoirs parameters are initialized. This is to make sure the // the timers for stable drain time are initialized prior to using them again isDrainComplete = hasTargetDrainToZeroBeenReached( r, drainSteadyStateTimeout ); if ( TRUE == isDrainComplete ) { 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 flush state and transition to basic cancellation prevChemDisinfectFlushState = chemDisinfectFlushState; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; haveDrainParamsBeenInit[ r ] = FALSE; 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 reservoir 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.0F; if ( DG_RESERVOIR_1 == r ) { currentVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else if ( DG_RESERVOIR_2 == r ) { currentVolume = 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 previous volume if ( currentVolume >= RESERVOIR_MINIMUM_FULL_VOLUME_ML ) { if ( ++rsrvrFillToFullStableTimerCounter >= RSRVRS_FILL_TO_FULL_STABLE_TASK_INT ) { status = DG_RESERVOIR_REACHED_TARGET; rsrvrFillToFullStableTimerCounter = 0; stateTimer = getMSTimerCount(); } } else if ( TRUE == didTimeout( stateTimer, timeout ) ) { // Failed to fill on time. 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 publishChemicalDisinfectFlushData function publishes chemical disinfect * flush data at the set interval. * @details Inputs: dataPublishCounter * @details Outputs: dataPublishCounter * @return: none *************************************************************************/ static void publishChemicalDisinfectFlushData( void ) { if ( ++dataPublishCounter >= CHEM_DISINFECT_FLUSH_DATA_PUB_INTERVAL ) { MODE_CHEMICAL_DISINFECT_FLUSH_DATA_T data; MODE_CHEMICAL_DISINFECT_FLUSH_UI_DATA_T uiData; data.chemDisinfectFlushState = (U32)chemDisinfectFlushState; data.stateElapsedTime = calcTimeSince( stateTimer ); data.overallElapsedTime = calcTimeSince( overallChemDisinfectFlushTimer ); data.postDisinfectCurrentRinseCount = numberOfPostDisinfectRinses; data.cancellationMode = (U32)cancellationMode; data.chemDisinfectFlushUIState = chemDisinfectFlushUIState; 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 { OPN_CLS_STATE_T concCap = getSwitchStatus( CONCENTRATE_CAP ); OPN_CLS_STATE_T dialysateCap = getSwitchStatus( DIALYSATE_CAP ); // If either the dialysate cap or the concentrate cap is open during any state, alarm if ( ( STATE_OPEN == concCap ) || ( STATE_OPEN == dialysateCap ) ) { if ( chemDisinfectFlushState != DG_CHEM_DISINFECT_FLUSH_STATE_START ) { prevChemDisinfectFlushState = chemDisinfectFlushState; chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_CAP_NOT_IN_PROPER_POSITION; if ( STATE_OPEN == concCap ) { alarmDetectedPendingTrigger = ALARM_ID_DG_CONCENTRATE_CAP_NOT_IN_PROPER_POSITION; } } } } if ( ( TRUE == isDGFaultAlarmActive() ) || ( TRUE == isAnyCleaningModeInletWaterConditionActive() ) ) { if ( chemDisinfectFlushState != DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH ) { prevChemDisinfectFlushState = chemDisinfectFlushState; chemDisinfectFlushState = DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH; } } } /*********************************************************************//** * @brief * The writeDisinfectDataToNV function writes the disinfect flush data to the * non-volatile memory. * @details Inputs: disFlushNVOps * @details Outputs: disinfectFlushNVOps * @return: none *************************************************************************/ static void writeDisinfectDataToNV( DG_USAGE_INFO_ITEMS_T info ) { if ( FALSE == disinfectNVOps.hasDisStatusBeenWrittenToNV ) { disinfectNVOps.hasDisStatusBeenWrittenToNV = setLastDisinfectDate( info, getRTCTimestamp() ); } } /**@}*/