Index: firmware/App/Modes/ModeHeatDisinfectActiveCool.c =================================================================== diff -u -r7e1e7d1d8553ed24fe0460aa1c3bdbeb297a60e4 -reeaab2a9a685fb18845888d91040d3aa01977f6d --- firmware/App/Modes/ModeHeatDisinfectActiveCool.c (.../ModeHeatDisinfectActiveCool.c) (revision 7e1e7d1d8553ed24fe0460aa1c3bdbeb297a60e4) +++ firmware/App/Modes/ModeHeatDisinfectActiveCool.c (.../ModeHeatDisinfectActiveCool.c) (revision eeaab2a9a685fb18845888d91040d3aa01977f6d) @@ -7,25 +7,33 @@ * * @file ModeHeatDisinfectActiveCool.c * -* @author (last) Dara Navaei -* @date (last) 21-Dec-2022 +* @author (last) Michael Garthwaite +* @date (last) 16-May-2023 * * @author (original) Dara Navaei * @date (original) 18-Dec-2022 * ***************************************************************************/ #include "ConcentratePumps.h" +#include "ConductivitySensors.h" #include "CPLD.h" +#include "DrainPump.h" +#include "Heaters.h" +#include "LoadCell.h" #include "MessageSupport.h" #include "ModeFault.h" #include "ModeHeatDisinfectActiveCool.h" #include "OperationModes.h" +#include "Pressures.h" +#include "Reservoirs.h" #include "ROPump.h" +#include "RTC.h" #include "Switches.h" #include "TaskGeneral.h" #include "TemperatureSensors.h" #include "Timers.h" +#include "UVReactors.h" #include "Valves.h" /** @@ -36,50 +44,124 @@ // ********** private data ********** #define HEAT_DISINFECT_ACTIVE_COOL_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode heat disinfect active cool data publish interval in counts. -#define ROF_COOL_DOWN_TARGET_FLOW_LPM 0.3F ///< RO filter cool down target flow in L/min. -#define HEAT_DISINFECT_ACTIVE_COOL_MAX_RO_PRESSURE_PSI 40 ///< Heat disinfect active cool maximum RO pressure in psi. -#define TARGET_THD_SENSOR_FOR_RINSING_C 44.0F ///< Target THd temperature sensor value before rinsing in C. -#define ROF_COOL_DOWN_CIRCULATION_TIME_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< RO filter cool down circulation timer in milliseconds. -#define ROF_COOL_DOWN_MAX_TIME_MS ( 300 * SEC_PER_MIN * MS_PER_SECOND ) ///< RO filter cool down maximum state time in milliseconds. +#define ACID_PUMP_SPEED_ML_PER_MIN 30.6F ///< Acid concentrate pump speed in mL/min. +// The acid pump is 2% faster than the acid pump to create a flow from acid to bicarb line during heat disinfect +#define BICARB_PUMP_SPEED_ML_PER_MIN -30.0F ///< Bicarb concentrate pump speed in mL/min. +#define RSRVR_FILL_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoir fill timeout in milliseconds. +#define RSRVR_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoir drain timeout in milliseconds. +#define RSRVR_DRAIN_STEADY_TIMEOUT_MS ( 6 * MS_PER_SECOND ) ///< Reservoir drain steady timeout in milliseconds. +#define RSRVR_DRAIN_TARGET_RPM 2400 ///< Reservoir drain target RPM. +#define RSRVR_MIX_DRAIN_TIMEOUT_MS ( 4 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 mix drain timeout in ms. +#define RSRVR_MIX_DRAIN_TEMPERATURE_THRESHOLD_C 60.0F ///< Temperature threshold for performing mix drain or normal drain. +// RO filter cool down defines +#define ROF_ACTIVE_COOL_TARGET_FLOW_LPM 0.3F ///< RO active cool down target flow in L/min. +#define ROF_ACTIVE_COOL_MAX_ALLOWED_PRESSURE_PSI 30 ///< RO active cool down maximum pressure in psi. +#define ROF_ACTIVE_COOL_TARGET_RSRVR_FILL_ML 600.0F ///< RO active cool target reservoir fill in mL. +#define ROF_ACTIVE_COOL_TARGET_TEMP_C 40.0F ///< RO active cool target temperature in C. +#define ROF_ACTIVE_COOL_BELOW_TEMP_TIMEOUT_MS ( 30 * MS_PER_SECOND ) ///< RO active cool temperature below target for cooling timeout in milliseconds. +#define ROF_ACTIVE_COOL_INITIAL_TARGET_DRAIN_RPM 600 ///< RO active cool initial target drain RPM. +#define ROF_ACTIVE_COOL_TARGET_DARIN_RPM 300 ///< RO active cool target drain RPM. +#define ROF_ACTIVE_COOL_MIX_DRAIN_VALVE_ON_TIMEOUT_MS ( 4 * MS_PER_SECOND ) ///< RO active cool mix drain VPd turn on timeout in milliseconds. +#define ROF_ACTIVE_COOL_RSRVR_MIX_DRAIN_TIMEOUT_MS ( 4 * SEC_PER_MIN * MS_PER_SECOND ) ///< RO active cool reservoir mix drain timeout in milliseconds. +#define ROF_ACTIVE_COOL_MIX_DRAIN_STEADY_TIMEOUT_MS ( 15 * MS_PER_SECOND ) ///< RO active cool mix drain steady timeout in milliseconds. + +// Reservoir cool down defines +#define RSRVR_ACTIVE_COOL_TARGET_FLOW_LPM 0.8F ///< Reservoir active cool target flow in L/min. +#define RSRVR_ACTIVE_COOL_MAX_ALLOWED_PRESSURE_PSI 130 ///< Reservoir active cool max allowed pressure in psi. +#define RSRVR_ACTIVE_COOL_FILL_TARGET_FILL_ML 1850.0F ///< Reservoir active cool over fill target in mL. +#define RSRVR_ACTIVE_COOL_TARGET_TEMP_C 40.0F ///< Reservoir active cool target temperature in C. +#define RSRVR_ACTIVE_COOL_BELOW_TARGET_TEMP_TIMEOUT_MS ( 15 * MS_PER_SECOND ) ///< Reservoir active cool temperature below target timeout in milliseconds. +#define RSRVR_ACTIVE_COOL_TARGET_TEMP_TIMEOUT_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoir active cool target temperature met in milliseconds. + +/// 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; + +/// Temperature below target structure +typedef struct +{ + U32 tempBelowTargetStartTimeMS; ///< Mode heat disinfect active cool temperature below target time in milliseconds. + BOOL hasTempTargetTimeBeenSet; ///< Mode heat disinfect active cool temperature target time has been set. +} TEMP_BELOW_TARGET_T; + static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T heatDisinfectActiveCoolState; ///< Mode heat disinfect active cool state. static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T heatDisinfectActiceCoolPrevState; ///< Mode heat disinfect active cool previous state. -static U32 stateTimer; ///< Mode heat disinfect active cool state timer. +static U32 stateStartTimeMS; ///< Mode heat disinfect active cool state timer in milliseconds. static U32 dataPublishCounter; ///< Mode heat disinfect active cool data publish counter. static U32 overallHeatDisinfectActiveCoolTimer; ///< Mode heat disinfect active cool over mode timer. -static U32 ROFCoolingTimer; ///< Mode heat disinfect active cool RO filter cooling timer. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Mode heat disinfect active cool pending alarm trigger. +static DIS_RSRVR_STATUS_T rsrvrsStatus; ///< Mode heat disinfect active cool reservoirs status. +static TEMP_BELOW_TARGET_T tempBelowTarget; ///< Mode heat disinfect active cool temperature below target time in milliseconds. +static DISINFECT_NV_OPS_T disinfectNVOps; ///< Disinfect non-volatile memory operations. +static CANCELLATION_MODE_T cancellationMode; ///< Cancellation mode. // ********** private function prototypes ********** static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolStartState( void ); -static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolCoolDownROFilterState( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolMixDrainR1State( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolMixDrainR2State( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolFillR1State( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolFillR2State( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolDrainR2FillR1ToR2State( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolDrainR1FillR2ToR1State( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolDrainR1State( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolDrainR2State( void ); static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolCompleteState( void ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolCancelWaterPathState( void ); static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolCancelBasicPathState( void ); static void failHeatDisinfectActiveCool( void ); static void publishHeatDisinfectActiveCoolData( void ); static void monitorModeHeatDisinfectActiveCool( void ); +static void setHeatDisinfectActiveCoolActuators( DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ); +static void writeDisinfectDataToNV( DG_USAGE_INFO_ITEMS_T info ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrMgmtTimeoutStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrPartialFillStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrMixDrainStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrFillStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ); +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrDrainStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ); /*********************************************************************//** * @brief * The initHeatDisinfectActiveCoolMode function initializes the heat disinfect * active cool mode module. * @details Inputs: none - * @details Outputs: heatDisinfectActiveCoolState, stateTimer, dataPublishCounter, - * overallHeatDisinfectActiveCoolTimer, ROFCoolingTimer, alarmDetectedPendingTrigger - * heatDisinfectActiceCoolPrevState, + * @details Outputs: heatDisinfectActiveCoolState, stateStartTimeMS, + * dataPublishCounter, overallHeatDisinfectActiveCoolTimer, + * alarmDetectedPendingTrigger, heatDisinfectActiceCoolPrevState, rsrvrsStatus, + * tempBelowTarget, disinfectNVOps * @return none *************************************************************************/ void initHeatDisinfectActiveCoolMode( void ) { - heatDisinfectActiveCoolState = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_START; - heatDisinfectActiceCoolPrevState = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_START; - stateTimer = 0; - dataPublishCounter = 0; - overallHeatDisinfectActiveCoolTimer = 0; - ROFCoolingTimer = 0; - alarmDetectedPendingTrigger = ALARM_ID_NO_ALARM; + heatDisinfectActiveCoolState = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_START; + heatDisinfectActiceCoolPrevState = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_START; + stateStartTimeMS = getMSTimerCount(); + dataPublishCounter = 0; + overallHeatDisinfectActiveCoolTimer = getMSTimerCount(); + alarmDetectedPendingTrigger = ALARM_ID_NO_ALARM; + tempBelowTarget.tempBelowTargetStartTimeMS = getMSTimerCount(); + tempBelowTarget.hasTempTargetTimeBeenSet = FALSE; + cancellationMode = CANCELLATION_MODE_NONE; + disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; + + // Initialize the reservoirs + rsrvrsStatus.rsrvrFillStableTime = 0; + rsrvrsStatus.rsrvrFillStableTimeoutMS = RSRVRS_FULL_STABLE_TIME_COUNT; + rsrvrsStatus.isThisInitialDrain = TRUE; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].drainInit = FALSE; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].loadCell = LOAD_CELL_RESERVOIR_1_PRIMARY; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = NUM_OF_DG_RESERVOIR_STATUS; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].drainInit = FALSE; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].loadCell = LOAD_CELL_RESERVOIR_2_PRIMARY; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = NUM_OF_DG_RESERVOIR_STATUS; + + // In the active cool mode the heaters are not turned on + stopHeater( DG_PRIMARY_HEATER ); + stopHeater( DG_TRIMMER_HEATER ); } /*********************************************************************//** @@ -95,7 +177,7 @@ deenergizeActuators( NO_PARK_CONC_PUMPS ); initHeatDisinfectActiveCoolMode(); - + setCurrentSubState( NO_SUB_STATE ); setCPLDCleanLEDColor( CPLD_CLEAN_LED_ORANGE ); return heatDisinfectActiveCoolState; @@ -111,7 +193,17 @@ *************************************************************************/ U32 execHeatDisinfectActiveCoolMode( void ) { - // TODO the inlet water check? + // The inlet pressure shall be checked all the time as long as VPi is open + checkInletWaterPressure(); + + if ( heatDisinfectActiveCoolState > DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE ) + { + // Do not check on the inlet water temperature and conductivity until there has been some inlet water flow + // The initial states are drain reservoirs but in those states VPi is closed so these alarms are not checked + checkInletWaterTemperature(); + checkInletWaterConductivity(); + } + monitorModeHeatDisinfectActiveCool(); switch( heatDisinfectActiveCoolState ) @@ -120,11 +212,43 @@ heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolStartState(); break; - case DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COOL_DOWN_RO_FILTER: - heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolCoolDownROFilterState(); + case DG_HEAT_DISINFECT_ACITVE_COOL_MIX_DRAIN_R1_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolMixDrainR1State(); break; - case DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_CANCEL_BASIC_PATH: + case DG_HEAT_DISINFECT_ACTIVE_COOL_MIX_DRAIN_R2_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolMixDrainR2State(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolFillR1State(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R2_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolFillR2State(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_FILL_R1_TO_R2_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolDrainR2FillR1ToR2State(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_FILL_R2_TO_R1_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolDrainR1FillR2ToR1State(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolDrainR1State(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolDrainR2State(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_WATER_PATH_STATE: + heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolCancelWaterPathState(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_BASIC_PATH_STATE: heatDisinfectActiveCoolState = handleHeatDisinfectActiveCoolCancelBasicPathState(); break; @@ -184,95 +308,265 @@ return status; } +/*********************************************************************//** + * @brief + * The getDisinfectRsrvrFillStatus function gets the disinfect reservoir + * fill status. + * @details Inputs: none + * @details Outputs: none + * @param rsrvrID the reservoir to check + * @param *rsrvrStatus pointer to the reservoir status structure + * @param targetVolML the fill target for the reservoir in milliliters + * @param fillTimeoutMS the timeout in milliseconds that the reservoir should + * be filled by then + * @param stateTimerMS the time of the state that the reservoir fill is being + * requested in milliseconds + * @return status of the reservoir fill + *************************************************************************/ +DG_RESERVOIR_STATUS_T getDisinfectRsrvrFillStatus( DG_RESERVOIR_ID_T rsrvrID, DIS_RSRVR_STATUS_T *rsrvrStatus, F32 targetVolML, U32 fillTimeoutMS, U32 stateTimerMS ) +{ + DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; + F32 volumeML = 0.0F; + + if ( rsrvrID < NUM_OF_DG_RESERVOIRS ) + { + volumeML = getLoadCellSmallFilteredWeight( rsrvrStatus->rsrvr[ rsrvrID ].loadCell ); + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, rsrvrID ) + } + + if ( volumeML >= targetVolML ) + { + // If the fill volume is greater than the target volume and the stable time has elapsed, call it reached to target + if ( ++rsrvrStatus->rsrvrFillStableTime >= rsrvrStatus->rsrvrFillStableTimeoutMS ) + { + rsrvrStatus->rsrvrFillStableTime = 0; + status = DG_RESERVOIR_REACHED_TARGET; + } + } + else if ( TRUE == didTimeout( stateTimerMS, fillTimeoutMS ) ) + { + status = DG_RESERVOIR_NOT_REACHED_TARGET; + } + + return status; +} + +/*********************************************************************//** + * @brief + * The getDisinfectRsrvrDrainStatus function gets the disinfect reservoir + * drain status. + * @details Inputs: none + * @details Outputs: none + * @param rsrvrID the reservoir to check + * @param *rsrvrStatus pointer to the reservoir status structure + * @param drainSteayTimeoutMS the time in milliseconds that the reservoir's level + * should not change and stay steady + * @param drainStateTimeoutMS the timeout in milliseconds that the reservoir should + * be drained by then + * @param stateTimerMS the time of the state that the reservoir fill is being + * requested in milliseconds + * @return status of the reservoir drain + *************************************************************************/ +DG_RESERVOIR_STATUS_T getDisinfectRsrvrDrainStatus( DG_RESERVOIR_ID_T rsrvrID, DIS_RSRVR_STATUS_T *rsrvrStatus, U32 drainSteadyTimeoutMS, + U32 drainStateTimeoutMS, U32 stateTimerMS ) +{ + DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_ABOVE_TARGET; + BOOL isDrainComplete = FALSE; + + if ( rsrvrID >= NUM_OF_DG_RESERVOIRS ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, rsrvrID ) + } + else + { + if ( FALSE == rsrvrStatus->rsrvr[ rsrvrID ].drainInit ) + { + initDrainParameters( rsrvrID ); + rsrvrStatus->rsrvr[ rsrvrID ].drainInit = 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 = hasTargetDrainVolumeBeenReached( rsrvrID, drainSteadyTimeoutMS ); + + if ( TRUE == isDrainComplete ) + { + rsrvrStatus->rsrvr[ rsrvrID ].drainInit = FALSE; + status = DG_RESERVOIR_REACHED_TARGET; + } + else if ( TRUE == didTimeout( stateTimerMS, drainStateTimeoutMS ) ) + { + rsrvrStatus->rsrvr[ rsrvrID ].drainInit = FALSE; + status = DG_RESERVOIR_NOT_REACHED_TARGET; + } + } + + return status; +} + // ********** private functions ********** /*********************************************************************//** * @brief * The handleHeatDisinfectActiveCoolStartState function handles the heat * disinfect active cool start state. - * @details Inputs: anone - * @details Outputs: ROFCoolingTimer, stateTimer + * @details Inputs: none + * @details Outputs: stateStartTimeMS, rsrvrsStatus * @return next state of the heat disinfect active cool state machine *************************************************************************/ static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolStartState( void ) { - DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COOL_DOWN_RO_FILTER; - overallHeatDisinfectActiveCoolTimer = getMSTimerCount(); - ROFCoolingTimer = 0; - stateTimer = getMSTimerCount(); + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACITVE_COOL_MIX_DRAIN_R1_STATE; - // De-energize all the valves that are not in the path anymore - // and wait for the RO membrane to be cooled down. - setValveState( VPI, VALVE_STATE_CLOSED ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRD1, VALVE_STATE_CLOSED ); - setValveState( VBF, VALVE_STATE_OPEN ); - setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); - setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setROPumpTargetFlowRateLPM( ROF_COOL_DOWN_TARGET_FLOW_LPM, HEAT_DISINFECT_ACTIVE_COOL_MAX_RO_PRESSURE_PSI ); + stateStartTimeMS = getMSTimerCount(); + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; return state; } /*********************************************************************//** * @brief - * The handleHeatDisinfectActiveCoolCoolDownROFilterState function handles - * the heat disinfect active cool cool down RO filter state. The state - * monitors the temperature at THd and if it is less than 45 C, it transitions - * to the next state. - * @details Inputs: stateTimer, ROFCoolingTimer - * @details Outputs: stateTimer, ROFcoolingTimer, heatDisinfectUIState, - * heatDisinfectActiceCoolPrevState, heatDisinfectActiceCoolPrevState + * The handleHeatDisinfectActiveCoolMixDrainR1State function handles the heat + * disinfect active cool mix drain R1 state. + * @details Inputs: none + * @details Outputs: none * @return next state of the heat disinfect active cool state machine *************************************************************************/ -static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolCoolDownROFilterState( void ) +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolMixDrainR1State( void ) { - DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COOL_DOWN_RO_FILTER; + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACITVE_COOL_MIX_DRAIN_R1_STATE; - // THd is the closet sensor to the RO filter and this temperature is monitored - // until it is dropped below 45 C to be able to run fluid through the RO filter - F32 THdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); + state = checkRsrvrMixDrainStatus( DG_RESERVOIR_1, state ); - if ( ( 0 == ROFCoolingTimer ) && ( THdTemp < TARGET_THD_SENSOR_FOR_RINSING_C ) ) - { - // Temperature is below target - perform mandatory cool down - ROFCoolingTimer = getMSTimerCount(); - } - else if ( THdTemp >= TARGET_THD_SENSOR_FOR_RINSING_C ) - { - // Temperature is not below target - reset the timer and keep looking - ROFCoolingTimer = 0; - } + return state; +} - if ( ( ROFCoolingTimer != 0 ) && ( TRUE == didTimeout( ROFCoolingTimer, ROF_COOL_DOWN_CIRCULATION_TIME_MS ) ) ) - { - // Temperature is below target, transition to next state - setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VBF, VALVE_STATE_CLOSED ); - setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); - setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - signalROPumpHardStop(); +/*********************************************************************//** + * @brief + * The handleHeatDisinfectActiveCoolMixDrainR2State function handles the heat + * disinfect active cool mix drain R2 state. + * @details Inputs: none + * @details Outputs: tempBelowTarget + * @return next state of the heat disinfect active cool state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolMixDrainR2State( void ) +{ + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_MIX_DRAIN_R2_STATE; - stateTimer = getMSTimerCount(); - state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COMPLETE; - } - else if ( ( TRUE == didTimeout( stateTimer, ROF_COOL_DOWN_MAX_TIME_MS ) ) ) - { - heatDisinfectActiceCoolPrevState = state; - alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_ACTIVE_COOL_TIME_OUT; - state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_CANCEL_BASIC_PATH; - } + tempBelowTarget.tempBelowTargetStartTimeMS = getMSTimerCount(); + tempBelowTarget.hasTempTargetTimeBeenSet = FALSE; + state = checkRsrvrMixDrainStatus( DG_RESERVOIR_2, state ); return state; } /*********************************************************************//** * @brief + * The handleHeatDisinfectActiveCoolFillR1State function handles the heat + * disinfect active cool fill R1 state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect active cool state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolFillR1State( void ) +{ + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE; + + state = checkRsrvrPartialFillStatus( DG_RESERVOIR_1, state ); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectActiveCoolFillR2State function handles the heat + * disinfect active cool fill R2 state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect active cool state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolFillR2State( void ) +{ + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R2_STATE; + + state = checkRsrvrPartialFillStatus( DG_RESERVOIR_2, state ); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectActiveCoolDrainR2FillR1ToR2State function handles + * the heat disinfect active cool drain R2 and fill R1 to R2 state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect active cool state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolDrainR2FillR1ToR2State( void ) +{ + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_FILL_R1_TO_R2_STATE; + + state = checkRsrvrFillStatus( DG_RESERVOIR_1, state ); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectActiveCoolDrainR1FillR2ToR1State function handles + * the heat disinfect active cool drain R1 and fill R2 to R1 state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect active cool state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolDrainR1FillR2ToR1State( void ) +{ + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_FILL_R2_TO_R1_STATE; + + state = checkRsrvrFillStatus( DG_RESERVOIR_2, state ); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectActiveCoolDrainR1State function handles the heat + * disinfect active cool drain R1 state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect active cool state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolDrainR1State( void ) +{ + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_STATE; + + state = checkRsrvrDrainStatus( DG_RESERVOIR_1, state ); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectActiveCoolDrainR1State function handles the heat + * disinfect active cool drain R2 state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect active cool state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolDrainR2State( void ) +{ + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_STATE; + + state = checkRsrvrDrainStatus( DG_RESERVOIR_2, state ); + + return state; +} + +/*********************************************************************//** + * @brief * The handleHeatDisinfectActiveCoolCompleteState function handles the * heat disinfect active cool complete state. * @details Inputs: none @@ -283,13 +577,120 @@ { DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COMPLETE; - stopDGHeatDisinfectActiveCool(); + writeDisinfectDataToNV( USAGE_INFO_HEAT_DIS_ACTIVE_COOL ); + if ( TRUE == disinfectNVOps.hasDisStatusBeenWrittenToNV ) + { + stopDGHeatDisinfectActiveCool(); + } + return state; } /*********************************************************************//** * @brief + * The handleHeatDisinfectActiveCoolCancelWaterPathState function handles + * the heat disinfect active cool cancel water path state. + * @details Inputs: cancellationMode, rsrvrsStatus, stateStartTimeMS + * @details Outputs: cancellationMode, rsrvrsStatus, stateStartTimeMS + * @return next state of the heat disinfect active cool state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolCancelWaterPathState( void ) +{ + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_WATER_PATH_STATE; + U32 drainSteadyTimeoutMS = RSRVR_DRAIN_STEADY_TIMEOUT_MS; + U32 drainTimeoutMS = RSRVR_DRAIN_TIMEOUT_MS; + + if ( CANCELLATION_MODE_NONE == cancellationMode ) + { + U32 targetRPM = RSRVR_DRAIN_TARGET_RPM; + F32 TDi = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + F32 TRo = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); + + cancellationMode = CANCELLATION_MODE_COLD; + + // The two sensors must be less than a threshold to decide if mix drain is needed to normal drain + if ( ( TDi >= RSRVR_MIX_DRAIN_TEMPERATURE_THRESHOLD_C ) && ( TRo >= RSRVR_MIX_DRAIN_TEMPERATURE_THRESHOLD_C ) ) + { + // The fluid is hot so this is a mix drain. Set the VPd to direct the cold inlet fluid to drain + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + turnOnUVReactor( INLET_UV_REACTOR ); + + drainSteadyTimeoutMS = ROF_ACTIVE_COOL_MIX_DRAIN_STEADY_TIMEOUT_MS; + drainTimeoutMS = RSRVR_MIX_DRAIN_TIMEOUT_MS; + targetRPM = ROF_ACTIVE_COOL_INITIAL_TARGET_DRAIN_RPM; + cancellationMode = CANCELLATION_MODE_HOT; + } + + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + + // The drain is set to start from reservoir 2 since all the actuators have been de-energized + // Set the drain valve to reservoir 2 + setValveState( VRD2, VALVE_STATE_OPEN ); + setDrainPumpTargetRPM( targetRPM ); + + // Start the timer for drain timeout + stateStartTimeMS = getMSTimerCount(); + } + + // If reservoir 2 is empty, set to drain reservoir 1 + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = getDisinfectRsrvrDrainStatus( DG_RESERVOIR_2, &rsrvrsStatus, drainSteadyTimeoutMS, + drainTimeoutMS, stateStartTimeMS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) + { + // Reset the state timer for the next reservoir to drain + stateStartTimeMS = getMSTimerCount(); + // Set the drain valve to reservoir 1 and close reservoir 2 + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) + { + // Stop the actuators that are running before going to basic cancellation path + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + signalDrainPumpHardStop(); + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_BASIC_PATH_STATE; + } + + // If reservoir 2 has already been drained and reservoir 1 is empty, reset and switch to complete + if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) && + ( DG_RESERVOIR_ABOVE_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus ) ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = getDisinfectRsrvrDrainStatus( DG_RESERVOIR_1, &rsrvrsStatus, drainSteadyTimeoutMS, + drainTimeoutMS, stateStartTimeMS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus ) + { + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + signalDrainPumpHardStop(); + failHeatDisinfectActiveCool(); + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus ) + { + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + signalDrainPumpHardStop(); + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_BASIC_PATH_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleHeatDisinfectActiveCoolCancelBasicPathState function handles the * heat disinfect active cool cancel mode basic path state. The state sets * the state to complete and raises an alarm. @@ -299,7 +700,7 @@ *************************************************************************/ static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T handleHeatDisinfectActiveCoolCancelBasicPathState( void ) { - DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_CANCEL_BASIC_PATH; + DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_BASIC_PATH_STATE; failHeatDisinfectActiveCool(); @@ -322,7 +723,7 @@ { SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, heatDisinfectActiceCoolPrevState ) } - requestNewOperationMode( DG_MODE_FAUL ); + requestNewOperationMode( DG_MODE_STAN ); } /*********************************************************************//** @@ -341,7 +742,7 @@ data.heatDisinfectActivCoolState = (U32)heatDisinfectActiveCoolState; data.overallElapsedTime = calcTimeSince( overallHeatDisinfectActiveCoolTimer ); - data.stateElapsedTime = calcTimeSince( stateTimer ); + data.stateElapsedTime = calcTimeSince( stateStartTimeMS ); data.cancellationMode = 0; broadcastData( MSG_ID_DG_HEAT_DISINFECT_ACTIVE_COOL_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( MODE_HEAT_DISINFECT_ACTIVE_COOL_DATA_T ) ); @@ -370,13 +771,574 @@ { // 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 cap = (U32)( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ? CONCENTRATE_CAP : DIALYSATE_CAP ); heatDisinfectActiceCoolPrevState = heatDisinfectActiveCoolState; - heatDisinfectActiveCoolState = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_CANCEL_BASIC_PATH; - alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_OR_CONC_CAP_NOT_IN_PROPER_POSITION; + heatDisinfectActiveCoolState = DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_BASIC_PATH_STATE; + alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_CAP_NOT_IN_PROPER_POSITION; + + if ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ) + { + alarmDetectedPendingTrigger = ALARM_ID_DG_CONCENTRATE_CAP_NOT_IN_PROPER_POSITION; + } } } + + if ( ( TRUE == isDGFaultAlarmActive() ) && ( heatDisinfectActiveCoolState != DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_WATER_PATH_STATE ) ) + { + // If there is any fault alarm and we are not already in the cancel water path state, set it to cancel water path state + heatDisinfectActiceCoolPrevState = heatDisinfectActiveCoolState; + heatDisinfectActiveCoolState = DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_WATER_PATH_STATE; + } } +/*********************************************************************//** + * @brief + * The setHeatDisinfectActiveCoolActuators function sets all the actuators + * of the provided state. + * @details Inputs: none + * @details Outputs: none + * @param state the state of the heat disinfect active cool mode + * @return: none + *************************************************************************/ +static void setHeatDisinfectActiveCoolActuators( DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ) +{ + switch ( state ) + { + case DG_HEAT_DISINFECT_ACITVE_COOL_MIX_DRAIN_R1_STATE: + { + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + signalROPumpHardStop(); + // Drain pump + U32 rpm = ( TRUE == rsrvrsStatus.isThisInitialDrain ? ROF_ACTIVE_COOL_INITIAL_TARGET_DRAIN_RPM : ROF_ACTIVE_COOL_TARGET_DARIN_RPM ); + setDrainPumpTargetRPM( rpm ); + } + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_MIX_DRAIN_R2_STATE: + { + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + signalROPumpHardStop(); + // Drain pump + U32 rpm = ( TRUE == rsrvrsStatus.isThisInitialDrain ? ROF_ACTIVE_COOL_INITIAL_TARGET_DRAIN_RPM : ROF_ACTIVE_COOL_TARGET_DARIN_RPM ); + setDrainPumpTargetRPM( rpm ); + } + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + // RO pump + setROPumpTargetFlowRateLPM( ROF_ACTIVE_COOL_TARGET_FLOW_LPM, ROF_ACTIVE_COOL_MAX_ALLOWED_PRESSURE_PSI ); + // Drain pump + signalDrainPumpHardStop(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R2_STATE: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + // RO pump + setROPumpTargetFlowRateLPM( ROF_ACTIVE_COOL_TARGET_FLOW_LPM, ROF_ACTIVE_COOL_MAX_ALLOWED_PRESSURE_PSI ); + // Drain pump + signalDrainPumpHardStop(); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_FILL_R1_TO_R2_STATE: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + // RO pump + setROPumpTargetFlowRateLPM( RSRVR_ACTIVE_COOL_TARGET_FLOW_LPM, RSRVR_ACTIVE_COOL_MAX_ALLOWED_PRESSURE_PSI ); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_FILL_R2_TO_R1_STATE: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + // RO pump + setROPumpTargetFlowRateLPM( RSRVR_ACTIVE_COOL_TARGET_FLOW_LPM, RSRVR_ACTIVE_COOL_MAX_ALLOWED_PRESSURE_PSI ); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_STATE: + // Valves + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID , NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB , NO_PARK_CONC_PUMPS ); + // RO pump + signalROPumpHardStop(); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_STATE: + // Valves + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + signalROPumpHardStop(); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + break; + + case DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_START: + case DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_WATER_PATH_STATE: + case DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_BASIC_PATH_STATE: + case DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COMPLETE: + // Do nothing the actuators in the above states are handled in a different part of code + break; + } +} + +/*********************************************************************//** + * @brief + * The writeDisinfectDataToNV function writes the disinfection data to the + * non-volatile memory. + * @details Inputs: disinfectNVOps + * @details Outputs: disinfectNVOps + * @param info the type disinfect data to write to the memory (i.e. heat + * disinfect start time) + * @return: none + *************************************************************************/ +static void writeDisinfectDataToNV( DG_USAGE_INFO_ITEMS_T info ) +{ + if ( FALSE == disinfectNVOps.hasDisStatusBeenWrittenToNV ) + { + disinfectNVOps.hasDisStatusBeenWrittenToNV = setLastDisinfectDate( info, getRTCTimestamp() ); + } +} + +/*********************************************************************//** + * @brief + * The checkRsrvrMgmtTimeoutStatus function checks and manages the status + * of reservoir management timeout status + * @details Inputs: rsrvrsStatus + * @details Outputs: heatDisinfectActiceCoolPrevState + * @param rsrvrID the reservoir ID to check the status of the timeout + * @param state the state of the heat disinfect active cool mode + * @return: state of the heat disinfect active cool mode + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrMgmtTimeoutStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ) +{ + if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + deenergizeActuators( NO_PARK_CONC_PUMPS ); + + switch ( state ) + { + case DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE: + case DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R2_STATE: + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_FILL_R1_TO_R2_STATE: + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_FILL_R2_TO_R1_STATE: + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_FILL_TIMEOUT; + break; + + case DG_HEAT_DISINFECT_ACITVE_COOL_MIX_DRAIN_R1_STATE: + case DG_HEAT_DISINFECT_ACTIVE_COOL_MIX_DRAIN_R2_STATE: + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_STATE: + case DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_STATE: + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + break; + + default: + // Do nothing + break; + } + + heatDisinfectActiceCoolPrevState = state; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_WATER_PATH_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The checkRsrvrPartialFillStatus function checks and manages the status + * of the partial fill of a reservoir + * @details Inputs: tempBelowTarget, rsrvrsStatus, stateStartTimeMS + * @details Outputs: tempBelowTarget, rsrvrsStatus, stateStartTimeMS + * @param rsrvrID the reservoir ID to check the status of the timeout + * @param state the state of the heat disinfect active cool mode + * @return: state of the heat disinfect active cool mode + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrPartialFillStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ) +{ + F32 THdTemperatureC = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); + + if ( ( THdTemperatureC <= ROF_ACTIVE_COOL_TARGET_TEMP_C ) && ( FALSE == tempBelowTarget.hasTempTargetTimeBeenSet ) ) + { + tempBelowTarget.tempBelowTargetStartTimeMS = getMSTimerCount(); + tempBelowTarget.hasTempTargetTimeBeenSet = TRUE; + } + + if ( DG_RESERVOIR_BELOW_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + rsrvrsStatus.rsrvr[ rsrvrID ].rStatus = getDisinfectRsrvrFillStatus( rsrvrID, &rsrvrsStatus, ROF_ACTIVE_COOL_TARGET_RSRVR_FILL_ML, + RSRVR_FILL_TIMEOUT_MS, stateStartTimeMS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + if ( TRUE == didTimeout( tempBelowTarget.tempBelowTargetStartTimeMS, ROF_ACTIVE_COOL_BELOW_TEMP_TIMEOUT_MS ) ) + { + stateStartTimeMS = getMSTimerCount(); + tempBelowTarget.hasTempTargetTimeBeenSet = FALSE; + + // If THd temperature has been below the target temperature, transition to cooling the connection paths in between the two reservoirs + if ( DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE == state ) + { + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_BELOW_TARGET; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_FILL_R1_TO_R2_STATE; + } + else if ( DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R2_STATE == state ) + { + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = DG_RESERVOIR_BELOW_TARGET; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_FILL_R2_TO_R1_STATE; + } + setHeatDisinfectActiveCoolActuators( state ); + } + else + { + deenergizeActuators( NO_PARK_CONC_PUMPS ); + rsrvrsStatus.rsrvr[ rsrvrID ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + stateStartTimeMS = getMSTimerCount(); + + // If the temperature after fill is not below the target temperature, transition to mix drain since the fluid is considered + // as hot + if ( DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE == state ) + { + state = DG_HEAT_DISINFECT_ACITVE_COOL_MIX_DRAIN_R1_STATE; + } + else if ( DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R2_STATE == state ) + { + state = DG_HEAT_DISINFECT_ACTIVE_COOL_MIX_DRAIN_R2_STATE; + } + } + } + + state = checkRsrvrMgmtTimeoutStatus( rsrvrID, state ); + + return state; +} + +/*********************************************************************//** + * @brief + * The checkRsrvrMixDrainStatus function checks and manages the status + * of the mix drain of a reservoir + * @details Inputs: rsrvrsStatus, stateStartTimeMS + * @details Outputs: rsrvrsStatus, stateStartTimeMS + * @param rsrvrID the reservoir ID to check the status of the timeout + * @param state the state of the heat disinfect active cool mode + * @return: state of the heat disinfect active cool mode + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrMixDrainStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ) +{ + if ( ( TRUE == didTimeout( stateStartTimeMS, ROF_ACTIVE_COOL_MIX_DRAIN_VALVE_ON_TIMEOUT_MS ) ) && ( FALSE == isDrainPumpOn() ) ) + { + setHeatDisinfectActiveCoolActuators( state ); + } + else if ( ( DG_RESERVOIR_ABOVE_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) && ( TRUE == isDrainPumpOn() ) ) + { + rsrvrsStatus.rsrvr[ rsrvrID ].rStatus = getDisinfectRsrvrDrainStatus( rsrvrID, &rsrvrsStatus, ROF_ACTIVE_COOL_MIX_DRAIN_STEADY_TIMEOUT_MS, + ROF_ACTIVE_COOL_RSRVR_MIX_DRAIN_TIMEOUT_MS, stateStartTimeMS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + DG_RESERVOIR_ID_T switchRsrvrID = ( DG_RESERVOIR_1 == rsrvrID ? DG_RESERVOIR_2 : DG_RESERVOIR_1 ); + + if ( TRUE == rsrvrsStatus.isThisInitialDrain ) + { + // If this is the initial drain of the mode, tare the reservoirs and get ready for the mix drain + if ( DG_HEAT_DISINFECT_ACITVE_COOL_MIX_DRAIN_R1_STATE == state ) + { + tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); + deenergizeActuators( NO_PARK_CONC_PUMPS ); + rsrvrsStatus.rsrvr[ switchRsrvrID ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_MIX_DRAIN_R2_STATE; + } + else if ( DG_HEAT_DISINFECT_ACTIVE_COOL_MIX_DRAIN_R2_STATE == state ) + { + tareLoadCell( LOAD_CELL_RESERVOIR_2_PRIMARY ); + tareLoadCell( LOAD_CELL_RESERVOIR_2_BACKUP ); + rsrvrsStatus.rsrvr[ switchRsrvrID ].rStatus = DG_RESERVOIR_BELOW_TARGET; + rsrvrsStatus.isThisInitialDrain = FALSE; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE; + setHeatDisinfectActiveCoolActuators( state ); + } + } + else + { + rsrvrsStatus.rsrvr[ switchRsrvrID ].rStatus = DG_RESERVOIR_BELOW_TARGET; + + // If state are either of the mix drain reservoir states, transition the the fill state. + // If the mix drain is R1 transition to fill R2 and vice versa + if ( DG_HEAT_DISINFECT_ACITVE_COOL_MIX_DRAIN_R1_STATE == state ) + { + state = DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R2_STATE; + } + else if ( DG_HEAT_DISINFECT_ACTIVE_COOL_MIX_DRAIN_R2_STATE == state ) + { + state = DG_HEAT_DISINFECT_ACTIVE_COOL_FILL_R1_STATE; + } + setHeatDisinfectActiveCoolActuators( state ); + } + + stateStartTimeMS = getMSTimerCount(); + } + + state = checkRsrvrMgmtTimeoutStatus( rsrvrID, state ); + + return state; +} + +/*********************************************************************//** + * @brief + * The checkRsrvrFillStatus function checks and manages the status + * of the a reservoir's fill + * @details Inputs: rsrvrsStatus, stateStartTimeMS, tempBelowTarget + * @details Outputs: rsrvrsStatus, stateStartTimeMS, tempBelowTarget + * @param rsrvrID the reservoir ID to check the status of the timeout + * @param state the state of the heat disinfect active cool mode + * @return: state of the heat disinfect active cool mode + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrFillStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ) +{ + if ( DG_RESERVOIR_BELOW_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + rsrvrsStatus.rsrvr[ rsrvrID ].rStatus = getDisinfectRsrvrFillStatus( rsrvrID, &rsrvrsStatus, RSRVR_ACTIVE_COOL_FILL_TARGET_FILL_ML, + RSRVR_FILL_TIMEOUT_MS, stateStartTimeMS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + // once the reservoir is filled check for the temperature below target + F32 TDiTemperatureC = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + + if ( ( TDiTemperatureC < RSRVR_ACTIVE_COOL_TARGET_TEMP_C ) && ( FALSE == tempBelowTarget.hasTempTargetTimeBeenSet ) ) + { + // Keep setting the time until the temperature is below the target + tempBelowTarget.tempBelowTargetStartTimeMS = getMSTimerCount(); + tempBelowTarget.hasTempTargetTimeBeenSet = TRUE; + } + + // Keep waiting until the TDi temperature is below the target temperature for the specified time + if ( TRUE == didTimeout( tempBelowTarget.tempBelowTargetStartTimeMS, RSRVR_ACTIVE_COOL_BELOW_TARGET_TEMP_TIMEOUT_MS ) ) + { + stateStartTimeMS = getMSTimerCount(); + tempBelowTarget.hasTempTargetTimeBeenSet = FALSE; + + // Once the TDi has been below the specified temperature for the specified time, transition to the next state per the current state + if ( DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_FILL_R1_TO_R2_STATE == state ) + { + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_REACHED_TARGET; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = DG_RESERVOIR_BELOW_TARGET; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_FILL_R2_TO_R1_STATE; + } + else if ( DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_FILL_R2_TO_R1_STATE == state ) + { + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_STATE; + } + } + setHeatDisinfectActiveCoolActuators( state ); + } + + if ( DG_RESERVOIR_BELOW_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + // Check for the fill timeout only until the reservoir is being filled. After that the fluid is run until TDi is below + // the target temperature and it can take a while and varies. + state = checkRsrvrMgmtTimeoutStatus( rsrvrID, state ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The checkRsrvrDrainStatus function checks and manages the status + * of the a reservoir's drain + * @details Inputs: rsrvrsStatus, stateStartTimeMS + * @details Outputs: rsrvrsStatus, stateStartTimeMS + * @param rsrvrID the reservoir ID to check the status of the timeout + * @param state the state of the heat disinfect active cool mode + * @return: state of the heat disinfect active cool mode + *************************************************************************/ +static DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T checkRsrvrDrainStatus( DG_RESERVOIR_ID_T rsrvrID, DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state ) +{ + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + rsrvrsStatus.rsrvr[ rsrvrID ].rStatus = getDisinfectRsrvrDrainStatus( rsrvrID, &rsrvrsStatus, RSRVR_DRAIN_STEADY_TIMEOUT_MS, + RSRVR_DRAIN_TIMEOUT_MS, stateStartTimeMS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + if ( DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R1_STATE == state ) + { + DG_RESERVOIR_ID_T switchRsrvrID = ( DG_RESERVOIR_1 == rsrvrID ? DG_RESERVOIR_2 : DG_RESERVOIR_1 ); + + rsrvrsStatus.rsrvr[ switchRsrvrID ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_STATE; + setHeatDisinfectActiveCoolActuators( state ); + } + else if ( DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_STATE == state ) + { + deenergizeActuators( NO_PARK_CONC_PUMPS ); + state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COMPLETE; + } + + stateStartTimeMS = getMSTimerCount(); + } + + state = checkRsrvrMgmtTimeoutStatus( rsrvrID, state ); + + return state; +} + /**@}*/