Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r5fc16235c1752c993b3f1285f3a2b9738372af7a --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 5fc16235c1752c993b3f1285f3a2b9738372af7a) @@ -15,9 +15,18 @@ * ***************************************************************************/ +#include "ConductivitySensors.h" +#include "DrainPump.h" +#include "Heaters.h" +#include "LoadCell.h" #include "ModeHeatDisinfect.h" #include "OperationModes.h" #include "Pressures.h" +#include "ROPump.h" +#include "TemperatureSensors.h" +#include "Timers.h" +#include "UVReactors.h" +#include "Valves.h" /** * @addtogroup DGHeatDisinfectMode @@ -26,29 +35,77 @@ // ********** private definitions ********** +// General defines +#define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. + +// Start state defines +#define MIN_INLET_PRESSURE_PSI 30.0 ///< Minimum water inlet pressure in psi. +#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 1.0 ///< Max start state TDi and TRo difference tolerance in C. + +// Drain R1 & R2 states defines +#define DRAIN_PUMP_TARGET_RPM 2500 ///< Drain pump target RPM during drain. +#define DRAIN_RESERVOIRS_TIME_OUT_MS ( 60 * MS_PER_SECOND ) ///< Drain reservoirs time out in milliseconds. +#define EMPTY_RESERVOIRS_WEIGHT_GRAMS 50 ///< The weight of an empty reservoir. //TODO Change this value to actual value + +// Flush drain path state defines +#define FLUSH_DRAIN_WAIT_TIME_MS ( 60 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. +#define MIN_INLET_TEMPERATURE_C 25.0 ///< Minimum water inlet temperature in C. +#define MIN_INLET_CONDUCTIVITY_S_PER_CM 0.0 ///< Minimum water inlet conductivity in mS/cm? TODO find out the real value + +// Flush circulation path state defines +#define RO_PUMP_TARGET_FLOW_RATE_LPM 0.8 ///< RO pump target flow rate in L/min. +#define MAX_RO_PUMP_PRESSURE_PSI 130 ///< Maximum RO pump pressure in psi. +#define FLUSH_CICRCULATION_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush circulation path wait time in milliseconds. +#define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 3.0 ///< Maximum flush circulation temperature difference tolerance in C. + + + + + + // ********** private data ********** -static DG_HEAT_DISINFECT_STATE_T heatState = DG_HEAT_DISINFECT_STATE_START; ///< Currently active heat disinfect state. +static DG_HEAT_DISINFECT_STATE_T heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Currently active heat disinfect state. +static U32 stateTimer = 0; ///< Heat disinfect state timer to be used in different states. +static U32 stateTrialCounter = 0; ///< Heat disinfect state trial counter to be used for retries in different states. +static BOOL areTempSensorsInRange = FALSE; ///< Heat disinfect temperature sensors in/out range flag. +/// Boolean flag to check whether draining R1 and R2 is at the end of the heat disinfect cycle or in the beginning. So the drain states can be reused. +static BOOL isThisLastDrain = FALSE; // ********** private function prototypes ********** +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStartState( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainR1State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainR2State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainState( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushCirculationState( void ); + +static void resetActuators( void ); +static void setModeToFailed( DG_HEAT_DISINFECT_STATE_T failedState ); + /*********************************************************************//** * @brief * The initHeatDisinfectMode function initializes the heat disinfect mode module. - * @details Inputs: none + * @details Inputs: none TODO update as we go * @details Outputs: Initialized heat disinfect mode module * @return none *************************************************************************/ void initHeatDisinfectMode( void ) { - heatState = DG_HEAT_DISINFECT_STATE_START; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + + stateTimer = 0; + isThisLastDrain = FALSE; + stateTrialCounter = 0; + areTempSensorsInRange = FALSE; } /*********************************************************************//** * @brief - * The transitionToHeatDisinfectMode function prepares for transition to heat disinfect mode. + * The transitionToHeatDisinfectMode function prepares for transition to + * heat disinfect mode. * @details Inputs: none - * @details Outputs: Prepare for transition to heat disinfect mode + * @details Outputs: none * @return none *************************************************************************/ void transitionToHeatDisinfectMode( void ) @@ -58,41 +115,385 @@ /*********************************************************************//** * @brief - * The execHeatDisinfectMode function executes the heat disinfect mode state machine. - * @details Inputs: none - * @details Outputs: Heat disinfect mode state machine executed + * The execHeatDisinfectMode function executes the heat disinfect mode + * state machine. + * @details Inputs: heatDisinfectState + * @details Outputs: heatDisinfectState * @return current state *************************************************************************/ U32 execHeatDisinfectMode( void ) { - checkInletPressureFault(); + checkInletPressureFault(); // TODO what is this? - // execute current heat disinfect state - switch ( heatState ) + switch ( heatDisinfectState ) { case DG_HEAT_DISINFECT_STATE_START: + heatDisinfectState = handleHeatDisinfectStartState(); break; + case DG_HEAT_DISINFECT_STATE_DRAIN_R1: + heatDisinfectState = handleHeatDisinfectDrainR1State(); + break; + + case DG_HEAT_DISINFECT_STATE_DRAIN_R2: + heatDisinfectState = handleHeatDisinfectDrainR2State(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN: + heatDisinfectState = handleHeatDisinfectFlushDrainState(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION: + heatDisinfectState = handleHeatDisinfectFlushCirculationState(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_R1_AND_R2: + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R2: + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R2: + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R1: + break; + + case DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER: + break; + + case DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2: + break; + + case DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER: + break; + + case DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1: + break; + + case DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1: + break; + + case DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R2: + break; + + case DG_HEAT_DISINFECT_STATE_RINSE_R1_TO_R2: + break; + + case DG_HEAT_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1: + break; + + case DG_HEAT_DISINFECT_STATE_RINSE_CIRCULATION: + break; + + case DG_HEAT_DISINFECT_STATE_COMPLETE: + break; + default: - // TODO - s/w fault - heatState = DG_HEAT_DISINFECT_STATE_START; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_HEAT_DISINFECT_INVALID_EXEC_STATE, heatDisinfectState ) + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; break; } - return heatState; + return heatDisinfectState; } /*********************************************************************//** * @brief - * The getCurrentHeatDisinfectState function returns the current state of the - * heat disinfect mode. - * @details Inputs: heatState + * The getCurrentHeatDisinfectState function returns the current state of + * the heat disinfect mode. + * @details Inputs: heatDisinfectState * @details Outputs: none * @return the current state of heat disinfect mode. *************************************************************************/ DG_HEAT_DISINFECT_STATE_T getCurrentHeatDisinfectState( void ) { - return heatState; + return heatDisinfectState; } +/*********************************************************************//** + * @brief + * The stopDGHeatDisinfect function stops heat disinfect mode. + * @details Inputs: heatDisinfectionState + * @details Outputs: heatDisinfectionState + * @return none + *************************************************************************/ +void stopDGHeatDisinfect( void ) +{ + heatDisinfectState = DG_HEAT_DISINFECT_STATE_COMPLETE; + + requestNewOperationMode( DG_MODE_STAN ); +} + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectStartState function handles the heat disinfect + * start state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStartState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; + + // Set all the actuators to reset and deenergized state + resetActuators(); + + F32 ppiPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); + F32 TDiTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + F32 TRoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); + + // If the inlet pressure is less than the threshold or TDi and TRo difference is greater than 1 C, the cycle + // should be canceled + if ( ppiPressure < MIN_INLET_PRESSURE_PSI && fabs( TDiTemp - TRoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) + { + setModeToFailed( state ); + } + else + { + // Close VPi to prevent wasting water + setValveState( VPI, VALVE_STATE_CLOSED ); + + // Set the actuators to drain R1 + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + stateTimer = getMSTimerCount(); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectDrainR1State function handles the heat disinfect + * drain R1 state. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainR1State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; + + F32 R1Weight = getLoadCellFilteredWeight( LOAD_CELL_A1 ); + + if ( R1Weight < EMPTY_RESERVOIRS_WEIGHT_GRAMS ) + { + // Set the actuators to drain R2. + // NOTE: Drain pump is already on and VDr is already on drain + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; + } + else if ( didTimeout( stateTimer, DRAIN_RESERVOIRS_TIME_OUT_MS ) ) + { + setModeToFailed( state ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectDrainR2State function handles the heat disinfect + * drain R2 state. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainR2State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; + + F32 R2Weight = getLoadCellFilteredWeight( LOAD_CELL_A2 ); + + if ( R2Weight < EMPTY_RESERVOIRS_WEIGHT_GRAMS ) + { + if ( isThisLastDrain ) + { + //TODO set the rest of the actuators + state = DG_HEAT_DISINFECT_STATE_RINSE_CIRCULATION; + } + else + { + stateTrialCounter = 0; + setValveState( VPI, VALVE_STATE_OPEN ); + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; + } + } + else if ( didTimeout( stateTimer, DRAIN_RESERVOIRS_TIME_OUT_MS ) ) + { + setModeToFailed( state ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFlushDrainState function handles the heat disinfect + * flush drain state. + * @details Inputs: stateTimer, stateTrialCounter + * @details Outputs: stateTimer, stateTrialCounter + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; + + // Check if flush time has elapsed + if ( didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) + { + // If the inlet temperature and conductivity are in range, move onto the next state + if ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MIN_INLET_TEMPERATURE_C && + getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) > MIN_INLET_CONDUCTIVITY_S_PER_CM ) + { + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM, MAX_RO_PUMP_PRESSURE_PSI ); + stateTimer = getMSTimerCount(); + stateTrialCounter = 0; + state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; + } + // If the failure is still in range, reset the timer and start over + else if ( ++stateTrialCounter < MAX_ALLOWED_STATE_TRIALS ) + { + stateTimer = getMSTimerCount(); + } + // Couldn't get a good water sample after a couple of trials and the disinfection cycle failed + else + { + setModeToFailed( state ); + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFlushCirculationState function handles the heat + * disinfect flush circulation state. + * @details Inputs: stateTimer, stateTrialCounter + * @details Outputs: stateTimer, stateTrialCounter + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushCirculationState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; + + // Check if the flush circulation time has elapsed and the temperature sensors are not in range yet + if ( didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) && FALSE == areTempSensorsInRange ) + { + F32 TPmTemp = 0; //TODO add TPm later. This is the new temp sensor of the coldest spot + F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 TD1Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_1 ); + F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); + F32 avgTemp = ( TPmTemp + TPoTemp + TD1Temp + TD2Temp ) / 3.0; //TODO change the number to 4 once the new sensor has been added + + BOOL isTPmOut = FALSE; //TODO change this calculations once TPm is added + BOOL isTPoOut = fabs( TPoTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; + BOOL isTD1Out = fabs( TD1Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; + BOOL isTD2Out = fabs( TD2Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; + + // Check if any of the temperature sensors are out of tolerance + if( isTPmOut || isTPoOut || isTD1Out || isTD2Out ) + { + // Check if we have exceeded the number of trials. If not, try another time + if ( ++stateTrialCounter < MAX_ALLOWED_STATE_TRIALS ) + { + stateTimer = getMSTimerCount(); + } + // State failed. Cancel heat disinfect mode + else + { + setModeToFailed( state ); + } + } + else + { + areTempSensorsInRange = TRUE; + stateTimer = getMSTimerCount(); + // TODO Turn on the composite pumps and wait for 30 seconds + } + } + + // Only start the concentrate pumps if the temperature sensors are in range + if ( areTempSensorsInRange ) + { + // TODO: enable the timeout once the concentrate pumps are available. + //if ( didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) + if ( TRUE ) + { + + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + } + } + + return state; +} + + +/*********************************************************************//** + * @brief + * The resetActuators function sets all the actuators to reset and + * deenergized state. + * @details Inputs: none + * @details Outputs: none + * @return none + *************************************************************************/ +static void resetActuators( void ) +{ + // UV reactors will not be used in the heat disinfection since their operating temperature + // range is below 85C and they might be damaged by the high temperature. + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + + // Deenergize all the valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + 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( VRD, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + + //TODO add the composition pumps + signalROPumpHardStop(); + signalDrainPumpHardStop(); + stopPrimaryHeater(); + stopTrimmerHeater(); +} + +/*********************************************************************//** + * @brief + * The setModeToFailed function sets the heat disinfect mode to failed + * by changing the state to complete and calling another function to set + * the actuators to reset state. + * @details Inputs: stateTrialCounter, stateTimer, areTempSensorsInRange, + * heatDisinfectState TODO add more variables if needed + * @details Outputs: none + * @return none + *************************************************************************/ +static void setModeToFailed( DG_HEAT_DISINFECT_STATE_T failedState ) +{ + // Reset all the variables + stateTrialCounter = 0; + stateTimer = 0; + areTempSensorsInRange = FALSE; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_COMPLETE; + + // Reset the actuators before alarming + resetActuators(); + + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_HEAT_DISINFECT_CYCLE_FAILED, failedState ) +} + /**@}*/