Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r9e5ee62245eb2a73b167eabd6c274a71a76a7b0e -r939e488d71ae8511cba65e4a27e31660259e06ac --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 9e5ee62245eb2a73b167eabd6c274a71a76a7b0e) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 939e488d71ae8511cba65e4a27e31660259e06ac) @@ -78,23 +78,30 @@ #define RSRVRS_500ML_FILL_UP_TIMEOUT_MS ( 4 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. #define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. -// Fill and heat water -#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 82.0F ///< Heat disinfect target water temperature in C. -#define HEAT_DISINFECT_START_TEMPERATURE_C 81.0F ///< Heat disinfect minimum acceptable temperature in C. +// Target temperature +#define HEAT_DISINFECT_PRIM_HEATER_TARGET_TEMP_C 90.0F ///< Heat disinfect primary heater target temperature in C. +#define HEAT_DISINFECT_TRIM_HEATER_TARGET_TEMP_C 90.0F ///< Heat disinfect trimmer heater target temperature in C. +#define HEAT_DISINFECT_CONC_PUMPS_START_TEMP_C 75.0F ///< Heat disinfect start concentrate pumps target temperature in C. +#define HEAT_DISINFECT_TRIMMER_HEATER_STOP_TEMP_C 75.0F ///< Heat disinfect trimmer heater stop temperature in C. +#define HEAT_DISINFECT_START_TEMP_AT_77_C 77.0F ///< Heat disinfect start disinfect at 77 C in C. +#define HEAT_DISINFECT_STOP_TEMP_AT_76_C 76.0F ///< Heat disinfect stop disinfect at 76 C in C. +#define HEAT_DISINFECT_START_TEMP_AT_82_C 82.0F ///< Heat disinfect start disinfect at 82 C in C. +#define HEAT_DISINFECT_STOP_TEMP_AT_81_C 81.0F ///< Heat disinfect stop disinfect at 81 C in C. // R1 to R2 & R2 to R1 heat disinfect circulation #define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 1.3F ///< Heat disinfect target RO flow rate in L/min. #define HEAT_DISINFECT_TARGET_RO_FLOW_TRANSFER_LPM 0.8F ///< Heat disinfect target RO flow rate in L/min when transferring between reservoirs. #define HEAT_DISINFECT_MAX_RO_PRESSURE_PSI 30 ///< Heat disinfect maximum RO pressure in psi. -#define HEAT_DISINFECT_TIME_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. -#define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. -#define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 0.5F * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disinfect. TODO change this to 5 seconds -#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 250.0F // TODO temporary change. Change back to 100 ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. +#define HEAT_DISINFECT_START_TEMP_TIMEOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. +#define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disinfect. +#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 100.0F ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. #define POST_HEAT_DISINFECT_WAIT_TIME_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect final wait time before flushing the system in milliseconds. #define HEAT_DISINFECT_MAX_TEMP_GRADIENT_C 15.0F ///< Heat disinfect maximum allowed temperature gradient in between hottest and coldest sensors. #define HEAT_DISINFECT_TEMP_GRAD_OUT_RANGE_TIME_MS ( 0.16 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect temperature gradient out of range timeout in milliseconds. #define HEAT_DISINFECT_TARGET_RO_PUMP_DC 0.4F ///< Heat disinfect target RO pump duty cycle. #define HEAT_DISINFECT_REF_RSRVR_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Heat disinfect getting reference reservoirs value timeout in milliseconds. +#define HEAT_DISINFECT_AT_82_C_TIME_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time at 82 C in milliseconds. +#define HEAT_DISINFECT_AT_77_C_TIME_MS ( 32 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time at 77 C in milliseconds. // Mix drain R1 and R2 #define RSRVRS_MIX_DRAIN_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 mix drain timeout in ms. @@ -103,6 +110,12 @@ #define MIX_DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 15 * MS_PER_SECOND ) ///< Time period of unchanged weight during mix draining before timeout. #define MIX_DRAIN_TEMPERATURE_THRESHOLD_C 60.0F ///< Temperature threshold for performing mix drain or normal drain. +#ifndef _RELEASE_ +#define NELSON_SUPPORT_TARGET_TEMP_C 6.0F // Nelson support heat disinfect target temperature in C. +#define NELSON_SUPPORT_STOP_TEMP_C ( NELSON_SUPPORT_TARGET_TEMP_C - 5.0F ) // Nelson support heat disinfect stop temperature in C. +#define NELSON_SUPPORT_DISINFECT_TIME_MS ( 2 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) // Nelson support heat disinfect time in milliseconds. +#endif + /// Cancellation paths typedef enum Cancellation_modes { @@ -125,12 +138,32 @@ NUM_OF_HEAT_DISINFECT_STATUS ///< Number of heat disinfect status. } HEAT_DISINFECT_STATUS_T; +/// Heat disinfect times enum +typedef enum Heat_Disinfect_Times +{ + RO_AT_77_C = 0, ///< Heat disinfect RO disinfect at 77 C. + RO_AT_82_C, ///< Heat disinfect RO disinfect at 82 C. + RSRVR_AT_77_C, ///< Heat disinfect reservoir disinfect at 77 C. + RSRVR_AT_82_C, ///< Heat disinfect reservoir disinfect at 82 C. + NUM_OF_HEAT_DISINFECT_TIMES ///< Number of heat disinfect times. +} HEAT_DISINFECT_TIMES_T; + /// 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; +/// Heat disinfect time status structure +typedef struct +{ + U32 startTimeMS; ///< Heat disinfect start time in milliseconds. + U32 targetTimeMS; ///< Heat disinfect target time in milliseconds. + TEMPERATURE_SENSORS_T tempSensor; ///< Heat disinfect temperature sensor to check. + F32 startTempC; ///< Heat disinfect temperature to start disinfect in C. + F32 stopTempC; ///< Heat disinfect temperature to stop disinfect in C. +} HEAT_DISINFECT_TIME_STATUS_T; + // ********** private data ********** static DG_HEAT_DISINFECT_STATE_T heatDisinfectState; ///< Current active heat disinfect state. @@ -145,8 +178,6 @@ static DG_RESERVOIR_STATUS_T rsrvr2Status; ///< Reservoir 2 status. static F32 rsrvr1RefVolML; ///< Reservoir 1 reference volume in heat disinfect in milliliters. static F32 rsrvr2RefVolML; ///< Reservoir 2 reference volume in heat disinfect in milliliters. -static U32 heatDisinfectTimer; ///< Heat disinfect timer. -static BOOL isPartialDisinfectInProgress; ///< Heat disinfect partial complete/in progess flag. static U32 rsrvrsVolMonitorTimer; ///< Reservoir 1 & 2 volume monitor timers during heat disinfect. static BOOL areRsrvrsLeaking; ///< Reservoir 1 & 2 leak check flag during heat disinfect. static U32 dataPublishCounter; ///< Heat Disinfect data publish counter. @@ -158,7 +189,18 @@ static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. static U32 tempGradOutOfRangeTimer; ///< Temperature gradient out of range start timer. static DISINFECT_NV_OPS_T disinfectNVOps; ///< Disinfect non-volatile memory operations. +static HEAT_DISINFECT_TIME_STATUS_T timeStatus[ NUM_OF_HEAT_DISINFECT_TIMES ]; ///< Heat disinfect time status. +static F32 concPumpsStartTemperatureC; ///< Heat disinfect concentrate pumps start temperature in C. +static BOOL isRODisinfectDone; ///< Heat disinfect is RO disinfect done flag. +#ifndef _RELEASE_ +/* Nelson Labs is in charge of testing the efficacy of the disinfects (heat and chem). The codes that contain the name Nelson are used to + * support the special conditions that are needed to be created to test the disinfects. The support codes are not compiled in a release + * build. + */ +static NELSON_SUPPORT_T nelsonSupport; // Nelson support. +#endif + // ********** private function prototypes ********** static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStartState( void ); @@ -185,24 +227,30 @@ static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T reservoir, F32 targetVol, U32 timeout ); static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); static HEAT_DISINFECT_STATUS_T getHeatDisinfectStatus( void ); +static BOOL hasDisinfectTimeElapsed( HEAT_DISINFECT_TIMES_T disinfectTime ); static void publishHeatDisinfectData( void ); static void monitorModeHeatDisinfect( void ); static void writeDisinfectDataToNV( DG_USAGE_INFO_ITEMS_T info ); +#ifndef _RELEASE_ +static void setNelsonSupportConditions( void ); +static DG_HEAT_DISINFECT_STATE_T handleNelsonHeatDisinfectFillR1WithWaterState( void ); +#endif + /*********************************************************************//** * @brief * The initHeatDisinfectMode function initializes the heat disinfect mode * module. * @details Inputs: none - * @details Outputs: heatDisinfectState, stateTimer, + * @details Outputs: heatDisinfectState, stateTimer, isRODisinfectDone * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, * rsrvr1RefVolML, rsrvr2RefVolML, overallHeatDisinfectTimer, * cancellationMode, rsrvrFillStableTimeCounter, prevHeatDisinfectState * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain, heatDisinfectTimer * hasROFCirculationBeenStarted, ROFCirculationTimer, targetDisinfectTime * ROFCirculationCoolingCounter, concentratePumpsPrimeTimer, areRsrvrsLeaking * haveDrainParamsBeenInit, tempGradOutOfRangeTimer, disinfectNVOps, - * dataPublishCounter + * dataPublishCounter, timeStatus, concPumpsStartTemperatureC * @return none *************************************************************************/ void initHeatDisinfectMode( void ) @@ -220,7 +268,6 @@ overallHeatDisinfectTimer = 0; cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillStableTimeCounter = 0; - isPartialDisinfectInProgress = FALSE; isDrainPumpInMixDrainOn = FALSE; concentratePumpsPrimeTimer = 0; targetDisinfectTime = 0; @@ -229,10 +276,40 @@ tempGradOutOfRangeTimer = 0; disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; alarmDetectedPendingTrigger = ALARM_ID_NO_ALARM; - heatDisinfectTimer = 0; rsrvrsVolMonitorTimer = 0; areRsrvrsLeaking = FALSE; dataPublishCounter = 0; + concPumpsStartTemperatureC = HEAT_DISINFECT_CONC_PUMPS_START_TEMP_C; + isRODisinfectDone = FALSE; + + // Initialize the disinfect times + timeStatus[ RO_AT_77_C ].startTempC = HEAT_DISINFECT_START_TEMP_AT_77_C; + timeStatus[ RO_AT_77_C ].startTimeMS = 0; + timeStatus[ RO_AT_77_C ].stopTempC = HEAT_DISINFECT_STOP_TEMP_AT_76_C; + timeStatus[ RO_AT_77_C ].targetTimeMS = HEAT_DISINFECT_AT_77_C_TIME_MS; + timeStatus[ RO_AT_77_C ].tempSensor = TEMPSENSORS_HEAT_DISINFECT; + + timeStatus[ RO_AT_82_C ].startTempC = HEAT_DISINFECT_START_TEMP_AT_82_C; + timeStatus[ RO_AT_82_C ].startTimeMS = 0; + timeStatus[ RO_AT_82_C ].stopTempC = HEAT_DISINFECT_STOP_TEMP_AT_81_C; + timeStatus[ RO_AT_82_C ].targetTimeMS = HEAT_DISINFECT_AT_82_C_TIME_MS; + timeStatus[ RO_AT_82_C ].tempSensor = TEMPSENSORS_HEAT_DISINFECT; + + timeStatus[ RSRVR_AT_77_C ].startTempC = HEAT_DISINFECT_START_TEMP_AT_77_C; + timeStatus[ RSRVR_AT_77_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_77_C ].stopTempC = HEAT_DISINFECT_STOP_TEMP_AT_76_C; + timeStatus[ RSRVR_AT_77_C ].targetTimeMS = HEAT_DISINFECT_AT_77_C_TIME_MS; + timeStatus[ RSRVR_AT_77_C ].tempSensor = TEMPSENSORS_INLET_DIALYSATE; + + timeStatus[ RSRVR_AT_82_C ].startTempC = HEAT_DISINFECT_START_TEMP_AT_82_C; + timeStatus[ RSRVR_AT_82_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_82_C ].stopTempC = HEAT_DISINFECT_STOP_TEMP_AT_81_C; + timeStatus[ RSRVR_AT_82_C ].targetTimeMS = HEAT_DISINFECT_AT_82_C_TIME_MS; + timeStatus[ RSRVR_AT_82_C ].tempSensor = TEMPSENSORS_INLET_DIALYSATE; + +#ifndef _RELEASE_ + setNelsonSupportConditions(); +#endif } /*********************************************************************//** @@ -356,6 +433,12 @@ heatDisinfectState = handleHeatDisinfectCompleteState(); break; +#ifndef _RELEASE_ + case DG_NELSON_HEAT_DISINFECT_STATE_FILL_R1_WITH_WATER: + heatDisinfectState = handleNelsonHeatDisinfectFillR1WithWaterState(); + break; +#endif + default: 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; @@ -462,20 +545,17 @@ tareLoadCell( LOAD_CELL_RESERVOIR_1_PRIMARY ); tareLoadCell( LOAD_CELL_RESERVOIR_1_BACKUP ); - // Assume reservoir 2 is full and drain it - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - // Done with draining R1, close it setValveState( VRD1, VALVE_STATE_CLOSED ); // Set the actuators to drain R2. // NOTE: Drain pump is already on and VDr is already on drain state setValveState( VRD2, VALVE_STATE_OPEN ); - state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; - setValveState( VPO, VALVE_STATE_FILL_C_TO_NC); - // Start the timer - stateTimer = getMSTimerCount(); + // Assume reservoir 2 is full and drain it + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; + stateTimer = getMSTimerCount(); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -512,14 +592,23 @@ signalDrainPumpHardStop(); - // Done with draining R2, close it - turnOnUVReactor( INLET_UV_REACTOR ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VRD2, VALVE_STATE_CLOSED ); - setValveState( VPI, VALVE_STATE_OPEN ); - stateTrialCounter = 0; - stateTimer = getMSTimerCount(); - state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; +#ifndef _RELEASE_ + if ( NELSON_DRAIN_SAMPLES == nelsonSupport ) + { + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + } + else +#endif + { + // Done with draining R2, close it + turnOnUVReactor( INLET_UV_REACTOR ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VPI, VALVE_STATE_OPEN ); + stateTrialCounter = 0; + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; + } } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -639,9 +728,15 @@ setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); - setHeaterTargetTemperature( DG_PRIMARY_HEATER, HEAT_DISINFECT_TARGET_TEMPERATURE_C ); - startHeater( DG_PRIMARY_HEATER ); +#ifndef _RELEASE_ + if ( nelsonSupport != NELSON_INOCULATE ) +#endif + { + setHeaterTargetTemperature( DG_PRIMARY_HEATER, HEAT_DISINFECT_PRIM_HEATER_TARGET_TEMP_C ); + startHeater( DG_PRIMARY_HEATER ); + } + // Set the NV data to FLASE to be able to write another NV data ops disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; stateTimer = getMSTimerCount(); @@ -887,14 +982,19 @@ setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); setValveState( VRD1, VALVE_STATE_CLOSED ); - setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); turnOnUVReactor( INLET_UV_REACTOR ); // Turn on the RO pump setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); - // Start heating the water while we are filling up the reservoirs - setHeaterTargetTemperature( DG_PRIMARY_HEATER, HEAT_DISINFECT_TARGET_TEMPERATURE_C ); - startHeater( DG_PRIMARY_HEATER ); +#ifndef _RELEASE_ + if ( nelsonSupport != NELSON_INOCULATE ) +#endif + { + // Start heating the water while we are filling up the reservoirs + setHeaterTargetTemperature( DG_PRIMARY_HEATER, HEAT_DISINFECT_PRIM_HEATER_TARGET_TEMP_C ); + startHeater( DG_PRIMARY_HEATER ); + } rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; @@ -944,7 +1044,6 @@ if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { turnOffUVReactor( INLET_UV_REACTOR ); - // Set the valves to drain R2 and no fill setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_OPEN ); setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); @@ -954,9 +1053,13 @@ // Set the drain pump to control mode setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_LPM ); - // Start the trimmer heater since we are recirculating water and there is flow in the shunt line - setHeaterTargetTemperature( DG_TRIMMER_HEATER, HEAT_DISINFECT_TARGET_TEMPERATURE_C ); - startHeater( DG_TRIMMER_HEATER ); +#ifndef _RELEASE_ + if ( nelsonSupport != NELSON_INOCULATE ) +#endif + { + setHeaterTargetTemperature( DG_TRIMMER_HEATER, HEAT_DISINFECT_TRIM_HEATER_TARGET_TEMP_C ); + startHeater( DG_TRIMMER_HEATER ); + } stateTimer = getMSTimerCount(); rsrvrsVolMonitorTimer = getMSTimerCount(); @@ -1031,23 +1134,21 @@ setValveState( VRD2, VALVE_STATE_CLOSED ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - - // Set the drain pump to control mode setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_TRANSFER_LPM ); - // Turn off trimmer heater for transition stopHeater( DG_TRIMMER_HEATER ); // Although there is fluid in both reservoirs, but they are set to empty // to begin the transition of hot water from R1 to R2. - rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; - stateTimer = getMSTimerCount(); - rsrvr1RefVolML = 0.0F; - rsrvr2RefVolML = 0.0F; - // Reset the timer for the next disinfect state - tempGradOutOfRangeTimer = 0; - state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + stateTimer = getMSTimerCount(); + rsrvr1RefVolML = 0.0F; + rsrvr2RefVolML = 0.0F; + tempGradOutOfRangeTimer = 0; + state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + timeStatus[ RSRVR_AT_77_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_82_C ].startTimeMS = 0; break; case HEAT_DISINFECT_HEAT_UP_IN_PROGRESS: @@ -1092,10 +1193,6 @@ // Set the drain pump to control mode setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_LPM ); - // Start the trimmer heater since we are recirculating water and there is flow in the shunt line - setHeaterTargetTemperature( DG_TRIMMER_HEATER, HEAT_DISINFECT_TARGET_TEMPERATURE_C ); - startHeater( DG_TRIMMER_HEATER ); - stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1; } @@ -1152,13 +1249,49 @@ break; case HEAT_DISINFECT_COMPLETE: - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); - // Turn off the heaters - stopHeater( DG_PRIMARY_HEATER ); - stopHeater( DG_TRIMMER_HEATER ); - stateTimer = getMSTimerCount(); - state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; + + if ( TRUE == isRODisinfectDone ) + { + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + stopHeater( DG_PRIMARY_HEATER ); + stopHeater( DG_TRIMMER_HEATER ); + + timeStatus[ RSRVR_AT_77_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_82_C ].startTimeMS = 0; + timeStatus[ RO_AT_77_C ].startTimeMS = 0; + timeStatus[ RO_AT_82_C ].startTimeMS = 0; + rsrvr1RefVolML = 0.0F; + rsrvr2RefVolML = 0.0F; + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; + } +#ifndef _RELEASE_ + if ( NELSON_INOCULATE == nelsonSupport ) + { + // Set the valves to transfer hot water from R1 to R2 and fill up R2. + 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 ); + setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_TRANSFER_LPM ); + + // Although there is fluid in both reservoirs, but they are set to empty + // to begin the transition of hot water from R1 to R2. + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + stateTimer = getMSTimerCount(); + rsrvr1RefVolML = 0.0F; + rsrvr2RefVolML = 0.0F; + state = DG_NELSON_HEAT_DISINFECT_STATE_FILL_R1_WITH_WATER; + } + else if ( NELSON_HEAT_DISINFECT == nelsonSupport ) + { + deenergizeActuators( PARK_CONC_PUMPS ); + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + } +#endif break; case HEAT_DISINFECT_HEAT_UP_IN_PROGRESS: @@ -1445,7 +1578,16 @@ heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_COMPLETE; - requestNewOperationMode( DG_MODE_HCOL ); +#ifndef _RELEASE_ + if ( nelsonSupport != NELSON_NONE ) + { + requestNewOperationMode( DG_MODE_STAN ); + } + else +#endif + { + requestNewOperationMode( DG_MODE_HCOL ); + } return state; } @@ -1466,6 +1608,7 @@ { SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, prevHeatDisinfectState ) } + requestNewOperationMode( DG_MODE_FAUL ); } @@ -1504,7 +1647,7 @@ { if ( ++rsrvrFillStableTimeCounter >= RSRVRS_FULL_STABLE_TIME_COUNT ) { - status = DG_RESERVOIR_REACHED_TARGET; + status = DG_RESERVOIR_REACHED_TARGET; rsrvrFillStableTimeCounter = 0; // Set the state timer in case it needs to be used for another timeout check if ( ( DG_HEAT_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1 == heatDisinfectState) && ( DG_RESERVOIR_2 == reservoir ) ) @@ -1548,7 +1691,7 @@ static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_ABOVE_TARGET; - BOOL isDrainComplete = hasTargetDrainVolumeBeenReached( r, drainSteadyStateTimeout ); + BOOL isDrainComplete = FALSE; // If the drain parameters of the reservoir is not initialized, initialize them if ( FALSE == haveDrainParamsBeenInit[ r ] ) @@ -1557,6 +1700,10 @@ 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 = hasTargetDrainVolumeBeenReached( r, drainSteadyStateTimeout ); + if ( TRUE == isDrainComplete ) { if ( ( DG_HEAT_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1 == heatDisinfectState ) && ( DG_RESERVOIR_1 == r ) ) @@ -1607,14 +1754,22 @@ static HEAT_DISINFECT_STATUS_T getHeatDisinfectStatus( void ) { HEAT_DISINFECT_STATUS_T status = HEAT_DISINFECT_HEAT_UP_IN_PROGRESS; - F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 ThdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); + F32 TPoTempC = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 ThdTempC = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); + F32 TDiTempC = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); F32 loadCellA1 = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); F32 loadCellB1 = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); BOOL isR1OutOfRange = ( fabs( loadCellA1 - rsrvr1RefVolML ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML ? TRUE : FALSE ); BOOL isR2OutOfRange = ( fabs( loadCellB1 - rsrvr2RefVolML ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML ? TRUE : FALSE ); - BOOL isGradientOutOfRange = ( fabs( TPoTemp - ThdTemp ) > HEAT_DISINFECT_MAX_TEMP_GRADIENT_C ? TRUE : FALSE ); + BOOL isGradientOutOfRange = ( fabs( TPoTempC - ThdTempC ) > HEAT_DISINFECT_MAX_TEMP_GRADIENT_C ? TRUE : FALSE ); + if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMEOUT_MS ) ) + { + // Heating up to minimum temperature for heat disinfect failed + alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; + status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; + } + // Perform check if no pending alarm if ( ALARM_ID_NO_ALARM == alarmDetectedPendingTrigger ) { @@ -1663,58 +1818,92 @@ } } - // Perform check if no pending alarm if ( ALARM_ID_NO_ALARM == alarmDetectedPendingTrigger ) { - // If the coldest spot which is THd is less than minimum heat disinfect temperature, - // reset the heat disinfect timers and check whether heating up has timed out - if ( ThdTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) +#ifndef _RELEASE_ + if ( nelsonSupport != NELSON_INOCULATE ) +#endif { - // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts - heatDisinfectTimer = getMSTimerCount(); - isPartialDisinfectInProgress = FALSE; - targetDisinfectTime = 0; - - if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) + if ( TDiTempC >= HEAT_DISINFECT_TRIMMER_HEATER_STOP_TEMP_C ) { - // Heating up to minimum temperature for heat disinfect failed - alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; - status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; + stopHeater( DG_TRIMMER_HEATER ); } + else if ( ( TDiTempC < HEAT_DISINFECT_TRIMMER_HEATER_STOP_TEMP_C ) && ( FALSE == isHeaterOn( DG_TRIMMER_HEATER ) ) ) + { + setHeaterTargetTemperature( DG_TRIMMER_HEATER, HEAT_DISINFECT_TRIM_HEATER_TARGET_TEMP_C ); + startHeater( DG_TRIMMER_HEATER ); + } } - else if ( ( isPartialDisinfectInProgress != TRUE ) && ( ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) ) + } + + // Perform check if no pending alarm + if ( ALARM_ID_NO_ALARM == alarmDetectedPendingTrigger ) + { + BOOL disinfectStatus = FALSE; + + if ( TPoTempC >= concPumpsStartTemperatureC ) { - // The temperature of the coldest spot is in range to start the disinfect timer - heatDisinfectTimer = getMSTimerCount(); - isPartialDisinfectInProgress = TRUE; - targetDisinfectTime = HEAT_DISINFECT_TIME_MS; - status = HEAT_DISINFECT_DISINFECT_IN_PROGRESS; + F32 acidSpeed = getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP1_ACID ); + F32 bicarbSpeed = getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP2_BICARB ); - // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + if ( ( acidSpeed < NEARLY_ZERO ) || ( bicarbSpeed < NEARLY_ZERO ) ) + { + // Turn the pumps on in reverse + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); - // During R1 to R2 disinfect, the concentrate pumps turn on - requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + // During R1 to R2 disinfect, the concentrate pumps turn on + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + } } + + // Check whether the reservoir under disinfect has elapsed time. + disinfectStatus |= hasDisinfectTimeElapsed( RSRVR_AT_77_C ); + disinfectStatus |= hasDisinfectTimeElapsed( RSRVR_AT_82_C ); + + // If either of the reservoir's disinfect time has elapsed, call this section complete + status = ( TRUE == disinfectStatus ? HEAT_DISINFECT_COMPLETE : status ); } - // Perform check if no pending alarm - if ( ALARM_ID_NO_ALARM == alarmDetectedPendingTrigger ) + return status; +} + +/*********************************************************************//** + * @brief + * The hasDisinfectTimeElapsed function checks whether the disinfect time of + * either reservoirs or the RO filter has been elapsed. + * @details Inputs: timeStatus + * @details Outputs: timeStatus + * @param disinfectTime which is the time to check (i.e reservoir at 77 C or + * RO disinfect at 82 C) + * @return TRUE if the specified time has been elapsed otherwise FALSE + *************************************************************************/ +static BOOL hasDisinfectTimeElapsed( HEAT_DISINFECT_TIMES_T disinfectTime ) +{ + BOOL status = FALSE; + F32 temperatureValue = getTemperatureValue( timeStatus[ disinfectTime ].tempSensor ); + + if ( temperatureValue >= timeStatus[ disinfectTime ].startTempC ) { - // If heat disinfect temperature has been reached, check if this stage of heat disinfect is done - if ( ( TRUE == isPartialDisinfectInProgress ) && ( TRUE == didTimeout( heatDisinfectTimer, HEAT_DISINFECT_TIME_MS ) ) ) + // If the temperature of the specified temperature sensor has elapsed the start temperature and the start timer is in reset (it is 0) + // start the timer. + // If the timer has started and time of the disinfect has elapsed, set the status to TRUE. + if ( 0 == timeStatus[ disinfectTime ].startTimeMS ) { - // Done with this stage of heat disnfect. Reset the variables - // Target disinfect time is the time that is published to the UI and when there is - // no disinfect count down, this variable is set to 0. When the target time is 0, the UI - // hides the timer on the UI disinfect screen - targetDisinfectTime = 0; - status = HEAT_DISINFECT_COMPLETE; - isPartialDisinfectInProgress = FALSE; + timeStatus[ disinfectTime ].startTimeMS = getMSTimerCount(); } + else if ( TRUE == didTimeout( timeStatus[ disinfectTime ].startTimeMS, timeStatus[ disinfectTime ].targetTimeMS ) ) + { + + status = TRUE; + } } + else if ( temperatureValue < timeStatus[ disinfectTime ].stopTempC ) + { + // If the temperature dropped below the target, reset the timer + timeStatus[ disinfectTime ].startTimeMS = 0; + } return status; } @@ -1734,36 +1923,20 @@ MODE_HEAT_DISINFECT_DATA_T data; MODE_HEAT_DISINFECT_UI_DATA_T uiData; - data.heatDisinfectState = (U32)heatDisinfectState; - data.overallElapsedTime = calcTimeSince( overallHeatDisinfectTimer ); - data.stateElapsedTime = calcTimeSince( stateTimer ); - data.cancellationMode = (U32)cancellationMode; - data.heatDisinfectUIState = (U32)heatDisinfectUIState; + data.heatDisinfectState = (U32)heatDisinfectState; + data.overallElapsedTime = calcTimeSince( overallHeatDisinfectTimer ); + data.stateElapsedTime = calcTimeSince( stateTimer ); + data.cancellationMode = (U32)cancellationMode; + data.heatDisinfectUIState = (U32)heatDisinfectUIState; + uiData.heatDisinfectTargetTime = targetDisinfectTime; + uiData.ro77CountdownTimeS = ( 0 == timeStatus[ RO_AT_77_C ].startTimeMS ? 0 : ( timeStatus[ RO_AT_77_C ].targetTimeMS - calcTimeSince( timeStatus[ RO_AT_77_C ].startTimeMS ) ) / 1000 ); // The count down is converted into seconds since the UI does not work with milliseconds + uiData.ro82CountdownTimeS = ( 0 == timeStatus[ RO_AT_82_C ].startTimeMS ? 0 : ( timeStatus[ RO_AT_82_C ].targetTimeMS - calcTimeSince( timeStatus[ RO_AT_82_C ].startTimeMS ) ) / 1000 ); + uiData.r77CountdownTimeS = ( 0 == timeStatus[ RSRVR_AT_77_C ].startTimeMS ? 0 : ( timeStatus[ RSRVR_AT_77_C ].targetTimeMS - calcTimeSince( timeStatus[ RSRVR_AT_77_C ].startTimeMS ) ) / 1000 ); + uiData.r82CountdownTimeS = ( 0 == timeStatus[ RSRVR_AT_82_C ].startTimeMS ? 0 : ( timeStatus[ RSRVR_AT_82_C ].targetTimeMS - calcTimeSince( timeStatus[ RSRVR_AT_82_C ].startTimeMS ) ) / 1000 ); + data.R1FillLevel = rsrvr1RefVolML; + data.R2FillLevel = rsrvr2RefVolML; - // If the mode is in the actual heat disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion - if ( ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) || - ( DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1 == heatDisinfectState ) ) - { - // If the disinfect target time is 0, meaning the actual disinfect has not started, set the count down to 0, otherwise, publish - // the actual value - U32 countDown = ( HEAT_DISINFECT_TIME_MS == targetDisinfectTime ? ( targetDisinfectTime - calcTimeSince( heatDisinfectTimer) ) : 0 ); - - uiData.heatDisinfectTargetTime = targetDisinfectTime; - uiData.heatDisinfectCountdownTime = countDown / 1000; // The count down is converted into seconds since the UI does not work with milliseconds - data.R1FillLevel = rsrvr1RefVolML; - data.R2FillLevel = rsrvr2RefVolML; - } - else - { - uiData.heatDisinfectTargetTime = 0; - uiData.heatDisinfectCountdownTime = 0; - data.R1FillLevel = 0.0; - data.R2FillLevel = 0.0; - } - broadcastData( MSG_ID_DG_HEAT_DISINFECT_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( MODE_HEAT_DISINFECT_DATA_T ) ); - - // Publish data to UI broadcastData( MSG_ID_DG_HEAT_DISINFECT_TIME_DATA, COMM_BUFFER_OUT_CAN_DG_2_UI, (U08*)&uiData, sizeof( MODE_HEAT_DISINFECT_UI_DATA_T ) ); dataPublishCounter = 0; @@ -1782,8 +1955,12 @@ *************************************************************************/ static void monitorModeHeatDisinfect( void ) { + // Constantly check the status of the RO disinfect + isRODisinfectDone |= hasDisinfectTimeElapsed( RO_AT_77_C ); + isRODisinfectDone |= hasDisinfectTimeElapsed( RO_AT_82_C ); + #ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) + if ( ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) && ( nelsonSupport != NELSON_INOCULATE ) ) #endif { if ( ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) @@ -1823,3 +2000,178 @@ } /**@}*/ + +// ********** Nelson Support Functions ********** + +#ifndef _RELEASE_ +/*********************************************************************//** + * @brief + * The setNelsonSupportConditions function sets the disinfect variables for + * Nelson support. + * @details Inputs: nelsonSupport + * @details Outputs: timeStatus, heatDisinfectState + * @return: none + *************************************************************************/ +static void setNelsonSupportConditions( void ) +{ + concPumpsStartTemperatureC = NELSON_SUPPORT_TARGET_TEMP_C; + + switch ( nelsonSupport ) + { + case NELSON_INOCULATE: + timeStatus[ RO_AT_77_C ].startTempC = NELSON_SUPPORT_TARGET_TEMP_C; + timeStatus[ RO_AT_77_C ].startTimeMS = 0; + timeStatus[ RO_AT_77_C ].stopTempC = NELSON_SUPPORT_STOP_TEMP_C; + timeStatus[ RO_AT_77_C ].targetTimeMS = HEAT_DISINFECT_AT_77_C_TIME_MS; + timeStatus[ RO_AT_77_C ].tempSensor = TEMPSENSORS_HEAT_DISINFECT; + + timeStatus[ RO_AT_82_C ].startTempC = NELSON_SUPPORT_TARGET_TEMP_C; + timeStatus[ RO_AT_82_C ].startTimeMS = 0; + timeStatus[ RO_AT_82_C ].stopTempC = NELSON_SUPPORT_STOP_TEMP_C; + timeStatus[ RO_AT_82_C ].targetTimeMS = HEAT_DISINFECT_AT_82_C_TIME_MS; + timeStatus[ RO_AT_82_C ].tempSensor = TEMPSENSORS_HEAT_DISINFECT; + + timeStatus[ RSRVR_AT_77_C ].startTempC = NELSON_SUPPORT_TARGET_TEMP_C; + timeStatus[ RSRVR_AT_77_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_77_C ].stopTempC = NELSON_SUPPORT_STOP_TEMP_C; + timeStatus[ RSRVR_AT_77_C ].targetTimeMS = NELSON_SUPPORT_DISINFECT_TIME_MS; + timeStatus[ RSRVR_AT_77_C ].tempSensor = TEMPSENSORS_INLET_DIALYSATE; + + timeStatus[ RSRVR_AT_82_C ].startTempC = NELSON_SUPPORT_TARGET_TEMP_C; + timeStatus[ RSRVR_AT_82_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_82_C ].stopTempC = NELSON_SUPPORT_STOP_TEMP_C; + timeStatus[ RSRVR_AT_82_C ].targetTimeMS = NELSON_SUPPORT_DISINFECT_TIME_MS; + timeStatus[ RSRVR_AT_82_C ].tempSensor = TEMPSENSORS_INLET_DIALYSATE; + break; + + case NELSON_POS_CONTROL_HEAT_DISINFECT: + timeStatus[ RO_AT_77_C ].startTempC = NELSON_SUPPORT_TARGET_TEMP_C; + timeStatus[ RO_AT_77_C ].startTimeMS = 0; + timeStatus[ RO_AT_77_C ].stopTempC = NELSON_SUPPORT_STOP_TEMP_C; + timeStatus[ RO_AT_77_C ].targetTimeMS = NELSON_SUPPORT_DISINFECT_TIME_MS; + timeStatus[ RO_AT_77_C ].tempSensor = TEMPSENSORS_HEAT_DISINFECT; + + timeStatus[ RO_AT_82_C ].startTempC = NELSON_SUPPORT_TARGET_TEMP_C; + timeStatus[ RO_AT_82_C ].startTimeMS = 0; + timeStatus[ RO_AT_82_C ].stopTempC = NELSON_SUPPORT_STOP_TEMP_C; + timeStatus[ RO_AT_82_C ].targetTimeMS = NELSON_SUPPORT_DISINFECT_TIME_MS; + timeStatus[ RO_AT_82_C ].tempSensor = TEMPSENSORS_HEAT_DISINFECT; + + timeStatus[ RSRVR_AT_77_C ].startTempC = NELSON_SUPPORT_TARGET_TEMP_C; + timeStatus[ RSRVR_AT_77_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_77_C ].stopTempC = NELSON_SUPPORT_STOP_TEMP_C; + timeStatus[ RSRVR_AT_77_C ].targetTimeMS = HEAT_DISINFECT_AT_82_C_TIME_MS; + timeStatus[ RSRVR_AT_77_C ].tempSensor = TEMPSENSORS_INLET_DIALYSATE; + + timeStatus[ RSRVR_AT_82_C ].startTempC = NELSON_SUPPORT_TARGET_TEMP_C; + timeStatus[ RSRVR_AT_82_C ].startTimeMS = 0; + timeStatus[ RSRVR_AT_82_C ].stopTempC = NELSON_SUPPORT_STOP_TEMP_C; + timeStatus[ RSRVR_AT_82_C ].targetTimeMS = HEAT_DISINFECT_AT_82_C_TIME_MS; + timeStatus[ RSRVR_AT_82_C ].tempSensor = TEMPSENSORS_INLET_DIALYSATE; + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + signalROPumpHardStop(); + setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_LPM ); + heatDisinfectState = DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2; + break; + + case NELSON_HEAT_DISINFECT: + // Set the valves to drain R2 and no fill + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + signalROPumpHardStop(); + setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_LPM ); + setHeaterTargetTemperature( DG_PRIMARY_HEATER, HEAT_DISINFECT_PRIM_HEATER_TARGET_TEMP_C ); + setHeaterTargetTemperature( DG_TRIMMER_HEATER, HEAT_DISINFECT_TRIM_HEATER_TARGET_TEMP_C ); + startHeater( DG_PRIMARY_HEATER ); + startHeater( DG_TRIMMER_HEATER ); + heatDisinfectState = DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2; + break; + + case NELSON_DRAIN_SAMPLES: + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + break; + + case NELSON_NONE: + default: + // Do nothing for these cases. + break; + } +} + +/*********************************************************************//** + * @brief + * The handleNelsonHeatDisinfectFillR1WithWaterState function handles the Nelson + * fill reservoir 1 with water. + * @details Inputs: rsrvr1Status, rsrvr2Status + * @details Outputs: rsrvr1Status, rsrvr2Status, prevHeatDisinfectState + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleNelsonHeatDisinfectFillR1WithWaterState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_NELSON_HEAT_DISINFECT_STATE_FILL_R1_WITH_WATER; + + // First reservoir 2 must be partially full + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + deenergizeActuators( PARK_CONC_PUMPS ); + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + prevHeatDisinfectState = state; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + prevHeatDisinfectState = state; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } + + return state; +} + +#endif + +#ifndef _RELEASE_ +/*********************************************************************//** + * @brief + * The setHeatNelsonSupportMode function sets the requested Nelson support + * mode (i.e. inoculate, ...) + * @details Inputs: none + * @details Outputs: nelsonSupport + * @param support the type Nelson support (i.e. inoculate, heat disinfect) + * @return none + *************************************************************************/ +void setHeatNelsonSupportMode( NELSON_SUPPORT_T support ) +{ + nelsonSupport = support; +} +#endif