Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r1b04f01736d4a9dcbb0b1d716fcb55dabc5d230d -r28e9d54e3e8b43589cc06c33a563cb6fec8c576f --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 1b04f01736d4a9dcbb0b1d716fcb55dabc5d230d) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 28e9d54e3e8b43589cc06c33a563cb6fec8c576f) @@ -7,8 +7,8 @@ * * @file ModeHeatDisinfect.c * -* @author (last) James Walter Taylor -* @date (last) 28-Jun-2023 +* @author (last) Dara Navaei +* @date (last) 16-Aug-2023 * * @author (original) Sean * @date (original) 20-Apr-2020 @@ -66,12 +66,15 @@ #define FLUSH_CIRCULATION_CONC_PUMPS_WAIT_TIME_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Flush circulation concentrate pumps on time in milliseconds. #define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 3.0F ///< Maximum flush circulation temperature difference tolerance in C. #define NUM_OF_TEMP_SENSORS_TO_AVG 3.0F ///< Number of temperature sensors to average to check the difference. +#define ACID_PUMP_FLUSH_RECIRCULATE_SPEED_MLPM -30.0F ///< Acid pump in flush recirculate speed in mL/min. +#define BICARB_PUMP_FLUSH_RECIRCULATE_SPEED_MLPM 30.6F ///< Bicarb pump in flush recirculate speed in mL/min. + #define ACID_PUMP_SPEED_ML_PER_MIN 30.6F ///< Acid concentrate pump speed in mL/min. // The acid pump is 2% faster than the bicarb 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. // Flush and drain R1 and R2 -#define RSRVRS_FULL_VOL_ML 1900.0F ///< Reservoirs 1 & 2 full volume in mL. +#define RSRVRS_FULL_VOL_ML 1850.0F ///< Reservoirs 1 & 2 full volume in mL. #define RSRVRS_PARTIAL_FILL_VOL_ML 500.0F ///< Reservoirs 1 & 2 partial volume in mL. #define RSRVRS_FULL_STABLE_TIME_COUNT ( ( 4 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in counts. #define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. @@ -103,6 +106,8 @@ #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. +#define HEAT_DISNFECT_MIN_OVERRIDE_TIME ( SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect minimum override time. +#define HEAT_DISINFECT_PREP_FOR_TRANSFER_TIME_MS ( 30 * MS_PER_SECOND ) ///< Heat disinfect prepare for transfer hot water time 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. @@ -184,6 +189,8 @@ 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. +static OVERRIDE_U32_T targetTimer77C = { HEAT_DISINFECT_AT_77_C_TIME_MS, 0, 0, 0 }; ///< Heat disinfection override target timer at 77 C +static OVERRIDE_U32_T targetTimer82C = { HEAT_DISINFECT_AT_82_C_TIME_MS, 0, 0, 0 }; ///< Heat disinfection override target timer at 82 C #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 @@ -206,6 +213,7 @@ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainR1State( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillWithWaterState( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR1ToR2State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectPrepareForHotWaterTransitionState( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillR2WithHotWaterState( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR2ToR1State( void ); static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCoolDownHeatersState( void ); @@ -278,25 +286,25 @@ 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 ].targetTimeMS = getU32OverrideValue( &targetTimer77C ); 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 ].targetTimeMS = getU32OverrideValue( &targetTimer82C );; 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 ].targetTimeMS = getU32OverrideValue( &targetTimer77C ); 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 ].targetTimeMS = getU32OverrideValue( &targetTimer82C ); timeStatus[ RSRVR_AT_82_C ].tempSensor = TEMPSENSORS_INLET_DIALYSATE; #ifndef _RELEASE_ @@ -326,6 +334,28 @@ /*********************************************************************//** * @brief + * The isHeatDisinfectInTransitionHotWater function returns the status of + * heat disinfect that whether it is in transition hot water water mode or + * not + * @details Inputs: heatDisinfectState + * @details Outputs: none + * @return TRUE if the mode is transfer hot water mode otherwise, FALSE + *************************************************************************/ +BOOL isHeatDisinfectInTransitionHotWater( void ) +{ + BOOL status = FALSE; + + if ( ( DG_HEAT_DISINFECT_STATE_PREPARE_FOR_HOT_WATER_TRANSITION == heatDisinfectState ) || + ( DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER == heatDisinfectState ) ) + { + status = TRUE; + } + + return status; +} + +/*********************************************************************//** + * @brief * The execHeatDisinfectMode function executes the heat disinfect mode * state machine. * @details Inputs: heatDisinfectState @@ -393,6 +423,10 @@ heatDisinfectState = handleHeatDisinfectDisinfectR1ToR2State(); break; + case DG_HEAT_DISINFECT_STATE_PREPARE_FOR_HOT_WATER_TRANSITION: + heatDisinfectState = handleHeatDisinfectPrepareForHotWaterTransitionState(); + break; + case DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER: heatDisinfectState = handleHeatDisinfectFillR2WithHotWaterState(); break; @@ -694,8 +728,8 @@ { areTempSensorsInRange = TRUE; // 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 ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_FLUSH_RECIRCULATE_SPEED_MLPM ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_FLUSH_RECIRCULATE_SPEED_MLPM ); // Turn on the concentrate pumps requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); @@ -1121,15 +1155,6 @@ case HEAT_DISINFECT_COMPLETE: requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); - // Set the valves to transfer hot water from R1 to R2 and fill up R2. - 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 ); - 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. @@ -1139,7 +1164,7 @@ rsrvr1RefVolML = 0.0F; rsrvr2RefVolML = 0.0F; tempGradOutOfRangeTimer = 0; - state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + state = DG_HEAT_DISINFECT_STATE_PREPARE_FOR_HOT_WATER_TRANSITION; timeStatus[ RSRVR_AT_77_C ].startTimeMS = 0; timeStatus[ RSRVR_AT_82_C ].startTimeMS = 0; break; @@ -1155,6 +1180,39 @@ /*********************************************************************//** * @brief + * The handleHeatDisinfectPrepareForHotWaterTransitionState function handles + * the heat disinfect prepare for hot water state. In this state, the fluid is + * run a certain period of time with the heaters are at a much lower duty cycle + * and then the actuators are set to transition the hot water to reservoir 2. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectPrepareForHotWaterTransitionState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_PREPARE_FOR_HOT_WATER_TRANSITION; + + if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_PREP_FOR_TRANSFER_TIME_MS ) ) + { + // Set the valves to transfer hot water from R1 to R2 and fill up R2. + 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 ); + setDrainPumpTargetOutletFlowLPM( HEAT_DISINFECT_TARGET_RO_FLOW_TRANSFER_LPM ); + // Turn off trimmer heater for transition + stopHeater( DG_TRIMMER_HEATER ); + + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleHeatDisinfectFillR2WithHotWaterState function handles fill R2 * with water state. The state transfers hot water from reservoir 1 to * reservoir 2 until hot water overflows from reservoir 2 to reservoir 1. @@ -1329,6 +1387,8 @@ } else { + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; @@ -1363,7 +1423,7 @@ setValveState( VPI, VALVE_STATE_OPEN ); setValveState( VRD1, VALVE_STATE_OPEN ); setValveState( VBF, VALVE_STATE_CLOSED ); - setValveState( VPO, VALVE_STATE_NOFILL_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 ); @@ -1462,7 +1522,8 @@ * If the drain is completed within the define time, it transitions to the * complete state. * @details Inputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer - * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer + * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer, + * haveDrainParamsBeenInit * @return next state of the heat disinfect state machine *************************************************************************/ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeWaterPathState( void ) @@ -1498,16 +1559,17 @@ cancellationMode = CANCELLATION_MODE_HOT; } - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; + haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; + stateTimer = getMSTimerCount(); // 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 ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setDrainPumpTargetRPM( targetRPM ); - - // Start the timer for drain timeout - stateTimer = getMSTimerCount(); } // If reservoir 2 is empty, set to drain reservoir 1 @@ -1600,14 +1662,16 @@ *************************************************************************/ static void failHeatDisinfect( void ) { + // If a fault alarm is active go to mode fault otherwise for cleaning mode alarms, transition to standby + DG_OP_MODE_T nextOpMode = ( FALSE == isDGFaultAlarmActive() ? DG_MODE_STAN : DG_MODE_FAUL ); + // In the cleaning modes the alarms are triggered but the mode is not transitioned to fault automatically // so transition to fault mode is done here if ( alarmDetectedPendingTrigger != ALARM_ID_NO_ALARM ) { SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, prevHeatDisinfectState ) } - - requestNewOperationMode( DG_MODE_STAN ); + requestNewOperationMode( nextOpMode ); } /*********************************************************************//** @@ -1840,8 +1904,8 @@ if ( TPoTempC >= concPumpsStartTemperatureC ) { - F32 acidSpeed = getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP1_ACID ); - F32 bicarbSpeed = getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP2_BICARB ); + F32 acidSpeed = getMeasuredPumpSpeedMLPM( CONCENTRATEPUMPS_CP1_ACID ); + F32 bicarbSpeed = getMeasuredPumpSpeedMLPM( CONCENTRATEPUMPS_CP2_BICARB ); if ( ( acidSpeed < NEARLY_ZERO ) || ( bicarbSpeed < NEARLY_ZERO ) ) { @@ -2003,6 +2067,104 @@ } } + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetDG77CStateTimerOverride function checks whether the disinfection + * time of either reservoirs or the RO filter has been elapsed. + * @details Inputs: none + * @details Outputs: targetTimer77C + * @param timer which is the time to check at 77 C + * @return TRUE if request successful, FALSE if not + *************************************************************************/ +BOOL testSetDG77CStateTimerOverride( U32 timer ) +{ + BOOL result = FALSE; + + if ( ( TRUE == isTestingActivated() ) && ( timer >= HEAT_DISNFECT_MIN_OVERRIDE_TIME ) ) + { + targetTimer77C.ovData = timer; + targetTimer77C.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetDG77CStateTimerOverride function checks whether the disinfection + * time of either reservoirs or the RO filter has been elapsed. + * @details Inputs: none + * @details Outputs: targetTimer77C + * @param timer which is the time to check at 77 C + * @return TRUE if request successful, FALSE if not + *************************************************************************/ +BOOL testResetDG77CStateTimerOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + targetTimer77C.override = OVERRIDE_RESET; + targetTimer77C.ovData = targetTimer77C.ovInitData; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetDG82CStateTimerOverride function checks whether the disinfection + * time of either reservoirs or the RO filter has been elapsed. + * @details Inputs: none + * @details Outputs: targetTimer82C + * @param timer which is the time to check at 82 C + * @return TRUE if request successful, FALSE if not + *************************************************************************/ +BOOL testSetDG82CStateTimerOverride( U32 timer ) +{ + BOOL result = FALSE; + + if ( ( TRUE == isTestingActivated() ) && ( timer >= HEAT_DISNFECT_MIN_OVERRIDE_TIME ) ) + { + targetTimer82C.ovData = timer; + targetTimer82C.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetDG82CStateTimerOverride function checks whether the disinfection + * time of either reservoirs or the RO filter has been elapsed. + * @details Inputs: none + * @details Outputs: targetTimer82C + * @param timer which is the time to check at 82 C + * @return TRUE if request successful, FALSE if not + *************************************************************************/ +BOOL testResetDG82CStateTimerOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + targetTimer82C.override = OVERRIDE_RESET; + targetTimer82C.ovData = targetTimer82C.ovInitData; + result = TRUE; + } + + return result; +} + /**@}*/ // ********** Nelson Support Functions **********