Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u --- firmware/App/Modes/ModeHeatDisinfect.c (revision 0) +++ firmware/App/Modes/ModeHeatDisinfect.c (revision 0d5d4c781a0de550c6badbe3cd7c850091c62d29) @@ -0,0 +1,1136 @@ +/************************************************************************** +* +* Copyright (c) 2024-2026 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file ModeHeatDisinfect.c +* +* @author (last) Jashwant Gantyada +* @date (last) 18-Aug-2026 +* +* @author (original) Jashwant Gantyada +* @date (original) 17-Aug-2026 +* +***************************************************************************/ + +#include "BalancingChamber.h" +#include "ConcentratePumps.h" +#include "DialysatePumps.h" +#include "Heaters.h" +#include "Level.h" +#include "MessagePayloads.h" +#include "MessageSupport.h" +#include "Messaging.h" +#include "ModeFault.h" +#include "ModeHeatDisinfect.h" +#include "OperationModes.h" +#include "Pressure.h" +#include "RinsePump.h" +#include "TaskGeneral.h" +#include "Temperature.h" +#include "Timers.h" +#include "Valves.h" + +/** + * @addtogroup DDHeatDisinfectMode + * @{ + */ + +// ********** private definitions ********** + +#define HEAT_DISINFECT_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval at which heat disinfect mode data is published. +#define HEAT_DISINFECT_DWELL_TIME_MS ( 10 * 60 * MS_PER_SECOND ) ///< Required dwell time after the sensor is above target. +#define HEAT_DISINFECT_D78_DWELL_TEMP_C 80.0F ///< DD recirc dwell starts when D78 exceeds this (deg C). +#define HEAT_DISINFECT_D4_DWELL_TEMP_C 80.0F ///< WCID dwell counts while D4 exceeds this (deg C). +#define HEAT_DISINFECT_HEATER_TARGET_C 90.0F ///< D5 heater target temperature during DD recirc (deg C). +#define HEAT_DISINFECT_HYDROBLOCK_TARGET_C 88.0F ///< D5 heater target temperature during hydroblock recirc (deg C). +#define HEAT_DISINFECT_HYDROBLOCK_STOP_TEMP_C 88.0F ///< Stop D5 when D4 reaches this temperature (deg C). +#define HEAT_DISINFECT_D18_HEATER_ENABLE_PSI 3.0F ///< Minimum D18 pressure before D5 is started (PSI). +#define HEAT_DISINFECT_D66_TARGET_PSI 3.0F ///< D65 pressure target (PSI). +#define HEAT_DISINFECT_SETUP_STABILITY_MS ( 2 * 60 * MS_PER_SECOND ) ///< DD recirc setup stability before open loop (ms). +#define HEAT_DISINFECT_DEPRES_D80_DELAY_MS 100 ///< Delay after D64 open before opening D80 (ms). +#define HEAT_DISINFECT_DEPRES_D65_OPEN_MS ( 1 * MS_PER_SECOND ) ///< D65 open duration after D80 opens, then close D65 and exit (ms). +#define HEAT_DISINFECT_LINE_RECIRC_MS ( 5 * MS_PER_SECOND ) ///< DD line recirc cadence (ms). +#define HEAT_DISINFECT_D76_D47_RECIRC_MS ( 10 * MS_PER_SECOND ) ///< D76/D47 line recirc duration (ms). +#define HEAT_DISINFECT_BICART_SUPPLY_MS ( 6 * MS_PER_SECOND ) ///< WCID bicart supply duration (ms). +#define HEAT_DISINFECT_BICART_VENT_MS ( 6 * MS_PER_SECOND ) ///< WCID bicart vent duration (ms). +#define HEAT_DISINFECT_WCID_DWELL_CHECK_MS ( 6 * MS_PER_SECOND ) ///< Mix time before WCID D4 dwell check (ms). +#define HEAT_DISINFECT_D12_RECIRC_RPM 930 ///< Open-loop D12 speed for DD recirculation. +#define HEAT_DISINFECT_D48_RECIRC_RPM 2240 ///< Open-loop D48 speed for DD recirculation. +#define HEAT_DISINFECT_D12_HYDROBLOCK_RPM 1000 ///< D12 speed during hydroblock heating. +#define HEAT_DISINFECT_D12_POST_RECIRC_RPM 700 ///< D12 speed during WCID bicart recirculation. +#define HEAT_DISINFECT_D12_DWELL_CHECK_RPM 1000 ///< D12 mix speed before WCID dwell check. +#define HEAT_DISINFECT_CONC_FLUSH_SPEED_ML_MIN 50.0F ///< D10/D11/D76 recirculation speed (mL/min). + +/// Bicart depressurize sub-states. D64 and D80 remain open on exit. +typedef enum Heat_Depressurize_Sub_States +{ + HEAT_DEPRES_WAIT_D6 = 0, ///< Wait until D6 is full + HEAT_DEPRES_OPEN_D64, ///< Open D64; D80 opens after HEAT_DISINFECT_DEPRES_D80_DELAY_MS + HEAT_DEPRES_OPEN_D80, ///< Open D80 and D65, then close D65 after HEAT_DISINFECT_DEPRES_D65_OPEN_MS + NUM_OF_HEAT_DEPRES_SUB_STATES ///< Number of depressurize sub-states +} HEAT_DEPRES_SUB_STATE_T; + +// ********** private data ********** + +static DD_HEAT_DISINFECT_STATE_T heatDisinfectState; ///< Currently active heat disinfect state. +static HEAT_DEPRES_SUB_STATE_T depressurizeSubState; ///< Bicart depressurize sub-state. +static U32 stateTimerMS; ///< State or sub-state entry timestamp (ms). +static U32 ddDwellAccumulatedMS; ///< Banked DD dwell time while D78 was above target (ms). +static BOOL ddDwellAtTarget; ///< TRUE while D78 is currently above dwell temperature. +static U32 ddDwellAtTargetStartMS; ///< Timestamp when the current DD at-target interval started (ms). +static U32 wcidDwellAccumulatedMS; ///< Banked WCID dwell time while D4 was above target (ms). +static BOOL wcidDwellAtTarget; ///< TRUE while D4 is currently above dwell temperature. +static U32 wcidDwellAtTargetStartMS; ///< Timestamp when the current WCID at-target interval started (ms). +static BOOL hydroblockHeaterStopped; ///< TRUE after D4 exceeded the hydroblock stop temperature. +static BOOL pendingStopDDHeatDisinfectRequest; ///< Flag indicating TD has requested DD stop heat disinfect. +static U32 heatDisinfectPublishTimerCounter; ///< Heat disinfect data broadcast timer counter. +static OVERRIDE_U32_T heatDisinfectModePublishInterval; ///< Interval at which to publish heat disinfect mode data. + +// ********** private function prototypes ********** + +static void setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_STATE_T state ); +static void applyDepresPhaseActuators( HEAT_DEPRES_SUB_STATE_T phase ); +static void applyDdRecircActuators( void ); +static void applyDdRecircLineValves( DD_HEAT_DISINFECT_STATE_T state ); +static void stopGearPumps( void ); +static void stopConcentrateAndRinsePumps( void ); +static BOOL isDdRecircState( DD_HEAT_DISINFECT_STATE_T state ); +static BOOL isWcidState( DD_HEAT_DISINFECT_STATE_T state ); +static void updateDwell( BOOL *atTarget, U32 *accumMs, U32 *atTargetStartMs, BOOL isAtTarget ); +static U32 currentDwellMs( BOOL atTarget, U32 accumMs, U32 atTargetStartMs ); +static void resetDdDwell( void ); +static void resetWcidDwell( void ); +static void manageD65ForBicartRecirc( void ); +static void updateWcidDwellFromD4( void ); +static U32 ddRecircDurationMs( DD_HEAT_DISINFECT_STATE_T state ); +static DD_HEAT_DISINFECT_STATE_T nextDdRecircState( DD_HEAT_DISINFECT_STATE_T state ); +static DD_HEAT_DISINFECT_STATE_T handleDepressurizeBicartState( void ); +static DD_HEAT_DISINFECT_STATE_T handleDdRecircSetupState( void ); +static DD_HEAT_DISINFECT_STATE_T handlePressureCheckState( void ); +static DD_HEAT_DISINFECT_STATE_T handleDdRecircState( void ); +static DD_HEAT_DISINFECT_STATE_T handleHydroblockRecircState( void ); +static DD_HEAT_DISINFECT_STATE_T handleBicartSupplyState( void ); +static DD_HEAT_DISINFECT_STATE_T handleBicartVentState( void ); +static DD_HEAT_DISINFECT_STATE_T handleWcidDwellCheckState( void ); +static void publishHeatDisinfectModeData( void ); + +/*********************************************************************//** + * @brief + * The initHeatDisinfectMode function initializes the heat disinfect mode + * unit. + * @details \b Inputs: none + * @details \b Outputs: heatDisinfectState, depressurizeSubState, stateTimerMS, + * ddDwellAccumulatedMS, ddDwellAtTarget, ddDwellAtTargetStartMS, + * wcidDwellAccumulatedMS, wcidDwellAtTarget, wcidDwellAtTargetStartMS, + * hydroblockHeaterStopped, pendingStopDDHeatDisinfectRequest, + * heatDisinfectPublishTimerCounter, heatDisinfectModePublishInterval + * @return none + *************************************************************************/ +void initHeatDisinfectMode( void ) +{ + heatDisinfectState = DD_HEAT_DISINFECT_STATE_START; + depressurizeSubState = HEAT_DEPRES_WAIT_D6; + stateTimerMS = 0; + ddDwellAccumulatedMS = 0; + ddDwellAtTarget = FALSE; + ddDwellAtTargetStartMS = 0; + wcidDwellAccumulatedMS = 0; + wcidDwellAtTarget = FALSE; + wcidDwellAtTargetStartMS = 0; + hydroblockHeaterStopped = FALSE; + pendingStopDDHeatDisinfectRequest = FALSE; + heatDisinfectPublishTimerCounter = 0; + heatDisinfectModePublishInterval.data = HEAT_DISINFECT_DATA_PUBLISH_INTERVAL; + heatDisinfectModePublishInterval.ovData = HEAT_DISINFECT_DATA_PUBLISH_INTERVAL; + heatDisinfectModePublishInterval.ovInitData = 0; + heatDisinfectModePublishInterval.override = OVERRIDE_RESET; +} + +/*********************************************************************//** + * @brief + * The transitionToHeatDisinfectMode function prepares for transition to + * heat disinfect mode. + * @details \b Inputs: none + * @details \b Outputs: heatDisinfectState + * @return initial state + *************************************************************************/ +U32 transitionToHeatDisinfectMode( void ) +{ + initHeatDisinfectMode(); + deenergizeActuators( PARK_CONC_PUMPS ); + requestBalChamberSwitching( FALSE ); + stopHeater( D45_HEAT ); + setValveState( D8_VALV, VALVE_STATE_OPEN ); + setCurrentSubState( NO_SUB_STATE ); + + return heatDisinfectState; +} + +/*********************************************************************//** + * @brief + * The isDdRecircState function returns TRUE for DD line recirc cycle + * states. + * @details \b Inputs: none + * @details \b Outputs: none + * @param state heat disinfect execution state + * @return TRUE if the state is in the DD recirc cycle + *************************************************************************/ +static BOOL isDdRecircState( DD_HEAT_DISINFECT_STATE_T state ) +{ + BOOL result = FALSE; + + if ( ( DD_HEAT_DISINFECT_DD_RECIRC_MAIN == state ) || + ( DD_HEAT_DISINFECT_DD_RECIRC_DIALYZER == state ) || + ( DD_HEAT_DISINFECT_DD_RECIRC_D100 == state ) || + ( DD_HEAT_DISINFECT_DD_RECIRC_D34 == state ) || + ( DD_HEAT_DISINFECT_DD_RECIRC_D91 == state ) || + ( DD_HEAT_DISINFECT_DD_RECIRC_D76_D47 == state ) ) + { + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The isWcidState function returns TRUE for WCID loop states. + * @details \b Inputs: none + * @details \b Outputs: none + * @param state heat disinfect execution state + * @return TRUE if the state is in the WCID loop + *************************************************************************/ +static BOOL isWcidState( DD_HEAT_DISINFECT_STATE_T state ) +{ + BOOL result = FALSE; + + if ( ( DD_HEAT_DISINFECT_HYDROBLOCK_RECIRC == state ) || + ( DD_HEAT_DISINFECT_BICART_SUPPLY == state ) || + ( DD_HEAT_DISINFECT_BICART_VENT == state ) || + ( DD_HEAT_DISINFECT_WCID_DWELL_CHECK == state ) ) + { + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The updateDwell function banks dwell time when the sensor leaves the + * at-target band, and starts a new interval when it re-enters. + * @details \b Inputs: none + * @details \b Outputs: none + * @param atTarget current at-target flag + * @param accumMs banked dwell time (ms) + * @param atTargetStartMs start of the current at-target interval (ms) + * @param isAtTarget TRUE if the sensor is currently above target + * @return none + *************************************************************************/ +static void updateDwell( BOOL *atTarget, U32 *accumMs, U32 *atTargetStartMs, BOOL isAtTarget ) +{ + U32 nowMs = getMSTimerCount(); + + if ( TRUE == isAtTarget ) + { + if ( FALSE == *atTarget ) + { + *atTarget = TRUE; + *atTargetStartMs = nowMs; + } + } + else if ( TRUE == *atTarget ) + { + *accumMs += calcTimeSince( *atTargetStartMs ); + *atTarget = FALSE; + } + else + { + // Still below target with no active interval. + } +} + +/*********************************************************************//** + * @brief + * The currentDwellMs function returns banked dwell plus the active + * at-target interval. + * @details \b Inputs: none + * @details \b Outputs: none + * @param atTarget TRUE while currently at target + * @param accumMs banked dwell time (ms) + * @param atTargetStartMs start of the current at-target interval (ms) + * @return total dwell time (ms) + *************************************************************************/ +static U32 currentDwellMs( BOOL atTarget, U32 accumMs, U32 atTargetStartMs ) +{ + U32 dwellMs = accumMs; + + if ( TRUE == atTarget ) + { + dwellMs += calcTimeSince( atTargetStartMs ); + } + + return dwellMs; +} + +/*********************************************************************//** + * @brief + * The resetDdDwell function clears DD recirculation dwell tracking. + * @details \b Inputs: none + * @details \b Outputs: ddDwellAccumulatedMS, ddDwellAtTarget, ddDwellAtTargetStartMS + * @return none + *************************************************************************/ +static void resetDdDwell( void ) +{ + ddDwellAccumulatedMS = 0u; + ddDwellAtTarget = FALSE; + ddDwellAtTargetStartMS = 0u; +} + +/*********************************************************************//** + * @brief + * The resetWcidDwell function clears WCID dwell tracking. + * @details \b Inputs: none + * @details \b Outputs: wcidDwellAccumulatedMS, wcidDwellAtTarget, wcidDwellAtTargetStartMS + * @return none + *************************************************************************/ +static void resetWcidDwell( void ) +{ + wcidDwellAccumulatedMS = 0u; + wcidDwellAtTarget = FALSE; + wcidDwellAtTargetStartMS = 0u; +} + +/*********************************************************************//** + * @brief + * The applyDdRecircLineValves function sets the DD recirc cycle valves. + * @details \b Inputs: none + * @details \b Outputs: none + * @param state current DD recirc state + * @return none + *************************************************************************/ +static void applyDdRecircLineValves( DD_HEAT_DISINFECT_STATE_T state ) +{ + setValveState( D34_VALV, VALVE_STATE_CLOSED ); + setValveState( D91_VALV, VALVE_STATE_CLOSED ); + setValveState( D35_VALV, VALVE_STATE_CLOSED ); + setValveState( D40_VALV, VALVE_STATE_CLOSED ); + setValveState( D100_VALV, VALVE_STATE_CLOSED ); + setValveState( D47_VALV, VALVE_STATE_CLOSED ); + requestConcentratePumpOff( D76_PUMP, FALSE ); + + switch ( state ) + { + case DD_HEAT_DISINFECT_DD_RECIRC_MAIN: + setValveState( D34_VALV, VALVE_STATE_OPEN ); + setValveState( D91_VALV, VALVE_STATE_OPEN ); + setValveState( D35_VALV, VALVE_STATE_OPEN ); + setValveState( D40_VALV, VALVE_STATE_OPEN ); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_DIALYZER: + setValveState( D35_VALV, VALVE_STATE_OPEN ); + setValveState( D40_VALV, VALVE_STATE_OPEN ); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_D100: + setValveState( D35_VALV, VALVE_STATE_OPEN ); + setValveState( D100_VALV, VALVE_STATE_OPEN ); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_D34: + setValveState( D34_VALV, VALVE_STATE_OPEN ); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_D91: + setValveState( D91_VALV, VALVE_STATE_OPEN ); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_D76_D47: + setValveState( D35_VALV, VALVE_STATE_OPEN ); + setValveState( D34_VALV, VALVE_STATE_OPEN ); + setValveState( D40_VALV, VALVE_STATE_OPEN ); + setValveState( D91_VALV, VALVE_STATE_OPEN ); + setValveState( D47_VALV, VALVE_STATE_OPEN ); + setConcentratePumpTargetSpeed( D76_PUMP, HEAT_DISINFECT_CONC_FLUSH_SPEED_ML_MIN, DOSING_CONT_VOLUME ); + requestConcentratePumpOn( D76_PUMP ); + break; + + default: + break; + } +} + +/*********************************************************************//** + * @brief + * The applyDdRecircActuators function configures shared DD recirc pumps + * and valves. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +static void applyDdRecircActuators( void ) +{ + requestBalChamberSwitching( FALSE ); + valveControlForBCOpenState(); + stopHeater( D45_HEAT ); + + setValveState( D52_VALV, VALVE_STATE_OPEN ); + setValveState( D3_VALV, VALVE_STATE_OPEN ); + setValveState( D14_VALV, VALVE_STATE_OPEN ); + setValveState( D8_VALV, VALVE_STATE_OPEN ); + setValveState( D54_VALV, VALVE_STATE_OPEN ); + setValveState( D83_VALV, VALVE_STATE_OPEN ); + setValveState( M12_VALV, VALVE_STATE_OPEN ); + setValveState( P39_VALV, VALVE_STATE_OPEN ); + + setValveState( D31_VALV, VALVE_STATE_CLOSED ); + setValveState( D47_VALV, VALVE_STATE_CLOSED ); + setValveState( D95_VALV, VALVE_STATE_CLOSED ); + setValveState( D100_VALV, VALVE_STATE_CLOSED ); + setValveState( D64_VALV, VALVE_STATE_CLOSED ); + setValveState( D65_VALV, VALVE_STATE_CLOSED ); + setValveState( D80_VALV, VALVE_STATE_CLOSED ); + setValveState( D81_VALV, VALVE_STATE_CLOSED ); + setValveState( D85_VALV, VALVE_STATE_CLOSED ); + + setRinsePumpState( RINSE_PUMP_STATE_ON ); + setConcentratePumpTargetSpeed( D10_PUMP, HEAT_DISINFECT_CONC_FLUSH_SPEED_ML_MIN, DOSING_CONT_VOLUME ); + setConcentratePumpTargetSpeed( D11_PUMP, HEAT_DISINFECT_CONC_FLUSH_SPEED_ML_MIN, DOSING_CONT_VOLUME ); + requestConcentratePumpOn( D10_PUMP ); + requestConcentratePumpOn( D11_PUMP ); + setDialysatePumpTargetRPM( D12_PUMP, HEAT_DISINFECT_D12_RECIRC_RPM, TRUE ); + setDialysatePumpTargetRPM( D48_PUMP, HEAT_DISINFECT_D48_RECIRC_RPM, TRUE ); +} + +/*********************************************************************//** + * @brief + * The applyDepresPhaseActuators function applies bicart depressurize + * valves. D64 and D80 remain open when leaving this sequence. + * @details \b Inputs: none + * @details \b Outputs: none + * @param phase current depressurize phase + * @return none + *************************************************************************/ +static void applyDepresPhaseActuators( HEAT_DEPRES_SUB_STATE_T phase ) +{ + setValveState( D8_VALV, VALVE_STATE_OPEN ); + + switch ( phase ) + { + case HEAT_DEPRES_WAIT_D6: + setValveState( D64_VALV, VALVE_STATE_CLOSED ); + setValveState( D80_VALV, VALVE_STATE_CLOSED ); + setValveState( D65_VALV, VALVE_STATE_CLOSED ); + break; + + case HEAT_DEPRES_OPEN_D64: + setValveState( D3_VALV, VALVE_STATE_CLOSED ); + setValveState( D64_VALV, VALVE_STATE_OPEN ); + setValveState( D80_VALV, VALVE_STATE_CLOSED ); + setValveState( D65_VALV, VALVE_STATE_OPEN ); + break; + + case HEAT_DEPRES_OPEN_D80: + setValveState( D3_VALV, VALVE_STATE_CLOSED ); + setValveState( D64_VALV, VALVE_STATE_OPEN ); + setValveState( D80_VALV, VALVE_STATE_OPEN ); + setValveState( D65_VALV, VALVE_STATE_OPEN ); + break; + + default: + break; + } +} + +/*********************************************************************//** + * @brief + * The setModeHeatDisinfectStateTransition function sets the actuators + * and variables for the state transition in heat disinfect mode. + * @details \b Inputs: heatDisinfectState + * @details \b Outputs: stateTimerMS, depressurizeSubState, hydroblockHeaterStopped, + * ddDwellAccumulatedMS, ddDwellAtTarget, ddDwellAtTargetStartMS, + * wcidDwellAccumulatedMS, wcidDwellAtTarget, wcidDwellAtTargetStartMS + * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when an invalid heat disinfect + * state is requested. + * @param state heat disinfect state enum + * @return none + *************************************************************************/ +static void setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_STATE_T state ) +{ + stateTimerMS = getMSTimerCount(); + + switch ( state ) + { + case DD_HEAT_DISINFECT_STATE_START: + requestBalChamberSwitching( FALSE ); + setValveState( D8_VALV, VALVE_STATE_OPEN ); + break; + + case DD_HEAT_DISINFECT_DEPRESSURIZE_BICART: + requestBalChamberSwitching( FALSE ); + stopHeater( D5_HEAT ); + stopHeater( D45_HEAT ); + stopGearPumps(); + stopConcentrateAndRinsePumps(); + depressurizeSubState = HEAT_DEPRES_WAIT_D6; + applyDepresPhaseActuators( HEAT_DEPRES_WAIT_D6 ); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_SETUP: + resetDdDwell(); + applyDdRecircActuators(); + applyDdRecircLineValves( DD_HEAT_DISINFECT_DD_RECIRC_MAIN ); + stopHeater( D5_HEAT ); + break; + + case DD_HEAT_DISINFECT_PRESSURE_CHECK: + applyDdRecircActuators(); + applyDdRecircLineValves( DD_HEAT_DISINFECT_DD_RECIRC_MAIN ); + stopHeater( D5_HEAT ); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_MAIN: + case DD_HEAT_DISINFECT_DD_RECIRC_DIALYZER: + case DD_HEAT_DISINFECT_DD_RECIRC_D100: + case DD_HEAT_DISINFECT_DD_RECIRC_D34: + case DD_HEAT_DISINFECT_DD_RECIRC_D91: + case DD_HEAT_DISINFECT_DD_RECIRC_D76_D47: + if ( FALSE == isDdRecircState( heatDisinfectState ) ) + { + applyDdRecircActuators(); + } + applyDdRecircLineValves( state ); + setHeaterTargetTemperature( D5_HEAT, HEAT_DISINFECT_HEATER_TARGET_C ); + startHeater( D5_HEAT ); + stopHeater( D45_HEAT ); + break; + + case DD_HEAT_DISINFECT_HYDROBLOCK_RECIRC: + if ( FALSE == isWcidState( heatDisinfectState ) ) + { + resetWcidDwell(); + } + hydroblockHeaterStopped = FALSE; + requestBalChamberSwitching( FALSE ); + valveControlForBCClosedState(); + stopConcentrateAndRinsePumps(); + signalDialysatePumpHardStop( D48_PUMP ); + stopHeater( D45_HEAT ); + setValveState( D54_VALV, VALVE_STATE_CLOSED ); + setValveState( D52_VALV, VALVE_STATE_CLOSED ); + setValveState( D14_VALV, VALVE_STATE_CLOSED ); + setValveState( D3_VALV, VALVE_STATE_CLOSED ); + setValveState( D8_VALV, VALVE_STATE_OPEN ); + setValveState( D64_VALV, VALVE_STATE_CLOSED ); + setValveState( D65_VALV, VALVE_STATE_CLOSED ); + setValveState( D80_VALV, VALVE_STATE_CLOSED ); + setValveState( D85_VALV, VALVE_STATE_CLOSED ); + setValveState( D83_VALV, VALVE_STATE_CLOSED ); + setDialysatePumpTargetRPM( D12_PUMP, HEAT_DISINFECT_D12_HYDROBLOCK_RPM, TRUE ); + setHeaterTargetTemperature( D5_HEAT, HEAT_DISINFECT_HYDROBLOCK_TARGET_C ); + startHeater( D5_HEAT ); + break; + + case DD_HEAT_DISINFECT_BICART_SUPPLY: + requestBalChamberSwitching( FALSE ); + valveControlForBCClosedState(); + stopConcentrateAndRinsePumps(); + stopHeater( D5_HEAT ); + stopHeater( D45_HEAT ); + setValveState( D8_VALV, VALVE_STATE_OPEN ); + setValveState( D14_VALV, VALVE_STATE_CLOSED ); + setValveState( D64_VALV, VALVE_STATE_OPEN ); + setValveState( D80_VALV, VALVE_STATE_OPEN ); + setValveState( D65_VALV, VALVE_STATE_CLOSED ); + setValveState( D85_VALV, VALVE_STATE_CLOSED ); + setDialysatePumpTargetRPM( D12_PUMP, HEAT_DISINFECT_D12_POST_RECIRC_RPM, TRUE ); + break; + + case DD_HEAT_DISINFECT_BICART_VENT: + setValveState( D8_VALV, VALVE_STATE_OPEN ); + setValveState( D64_VALV, VALVE_STATE_OPEN ); + setValveState( D85_VALV, VALVE_STATE_OPEN ); + setValveState( D80_VALV, VALVE_STATE_CLOSED ); + break; + + case DD_HEAT_DISINFECT_WCID_DWELL_CHECK: + stopConcentrateAndRinsePumps(); + stopHeater( D5_HEAT ); + setValveState( D8_VALV, VALVE_STATE_OPEN ); + setDialysatePumpTargetRPM( D12_PUMP, HEAT_DISINFECT_D12_DWELL_CHECK_RPM, TRUE ); + break; + + case DD_HEAT_DISINFECT_STATE_COMPLETE: + deenergizeActuators( PARK_CONC_PUMPS ); + requestBalChamberSwitching( FALSE ); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_HEAT_DISINFECT_MODE_INVALID_EXEC_STATE, state ) + break; + } +} + +/*********************************************************************//** + * @brief + * The stopGearPumps function hard-stops D12 and D48. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +static void stopGearPumps( void ) +{ + signalDialysatePumpHardStop( D12_PUMP ); + signalDialysatePumpHardStop( D48_PUMP ); +} + +/*********************************************************************//** + * @brief + * The stopConcentrateAndRinsePumps function stops D10, D11, D76, and the + * rinse pump. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +static void stopConcentrateAndRinsePumps( void ) +{ + requestConcentratePumpOff( D10_PUMP, FALSE ); + requestConcentratePumpOff( D11_PUMP, FALSE ); + requestConcentratePumpOff( D76_PUMP, FALSE ); + setRinsePumpState( RINSE_PUMP_STATE_OFF ); +} + +/*********************************************************************//** + * @brief + * The manageD65ForBicartRecirc function flutters D65 during bicart supply + * and vent recirculation. D65 opens when D66 is below 3 PSI and closes + * when D66 is above 3 PSI. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +static void manageD65ForBicartRecirc( void ) +{ + F32 d66Psi = getFilteredPressure( D66_PRES ); + + if ( d66Psi > HEAT_DISINFECT_D66_TARGET_PSI ) + { + setValveState( D65_VALV, VALVE_STATE_CLOSED ); + } + else if ( d66Psi < HEAT_DISINFECT_D66_TARGET_PSI ) + { + setValveState( D65_VALV, VALVE_STATE_OPEN ); + } + else + { + // Hold the current D65 state at 3 PSI. + } +} + +/*********************************************************************//** + * @brief + * The updateWcidDwellFromD4 function accumulates WCID dwell while D4 is + * above 80 C. + * @details \b Inputs: wcidDwellAtTarget, wcidDwellAccumulatedMS, wcidDwellAtTargetStartMS + * @details \b Outputs: wcidDwellAtTarget, wcidDwellAccumulatedMS, wcidDwellAtTargetStartMS + * @return none + *************************************************************************/ +static void updateWcidDwellFromD4( void ) +{ + BOOL d4AtTarget = FALSE; + + if ( getFilteredTemperatureValue( D4_TEMP ) > HEAT_DISINFECT_D4_DWELL_TEMP_C ) + { + d4AtTarget = TRUE; + } + + updateDwell( &wcidDwellAtTarget, &wcidDwellAccumulatedMS, &wcidDwellAtTargetStartMS, d4AtTarget ); +} + +/*********************************************************************//** + * @brief + * The ddRecircDurationMs function returns the required time in a DD line + * recirc state. + * @details \b Inputs: none + * @details \b Outputs: none + * @param state current DD recirc state + * @return duration (ms) + *************************************************************************/ +static U32 ddRecircDurationMs( DD_HEAT_DISINFECT_STATE_T state ) +{ + U32 durationMs = HEAT_DISINFECT_LINE_RECIRC_MS; + + if ( DD_HEAT_DISINFECT_DD_RECIRC_D76_D47 == state ) + { + durationMs = HEAT_DISINFECT_D76_D47_RECIRC_MS; + } + + return durationMs; +} + +/*********************************************************************//** + * @brief + * The nextDdRecircState function returns the next DD line recirc state. + * @details \b Inputs: none + * @details \b Outputs: none + * @param state current DD recirc state + * @return next DD recirc state + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T nextDdRecircState( DD_HEAT_DISINFECT_STATE_T state ) +{ + DD_HEAT_DISINFECT_STATE_T next = DD_HEAT_DISINFECT_DD_RECIRC_MAIN; + + switch ( state ) + { + case DD_HEAT_DISINFECT_DD_RECIRC_MAIN: + next = DD_HEAT_DISINFECT_DD_RECIRC_DIALYZER; + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_DIALYZER: + next = DD_HEAT_DISINFECT_DD_RECIRC_D100; + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_D100: + next = DD_HEAT_DISINFECT_DD_RECIRC_D34; + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_D34: + next = DD_HEAT_DISINFECT_DD_RECIRC_D91; + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_D91: + next = DD_HEAT_DISINFECT_DD_RECIRC_D76_D47; + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_D76_D47: + next = DD_HEAT_DISINFECT_DD_RECIRC_MAIN; + break; + + default: + next = DD_HEAT_DISINFECT_DD_RECIRC_MAIN; + break; + } + + return next; +} + +/*********************************************************************//** + * @brief + * The handleDepressurizeBicartState function waits for D6 full, then + * depressurizes the bicart. D64 opens, D80 opens after 100 ms, D65 closes + * after 1 s. D64 and D80 stay open on exit. + * @details \b Inputs: depressurizeSubState, stateTimerMS + * @details \b Outputs: depressurizeSubState, stateTimerMS + * @return the current state of heat disinfect mode + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T handleDepressurizeBicartState( void ) +{ + DD_HEAT_DISINFECT_STATE_T state = DD_HEAT_DISINFECT_DEPRESSURIZE_BICART; + + switch ( depressurizeSubState ) + { + case HEAT_DEPRES_WAIT_D6: + if ( LEVEL_STATE_HIGH == getLevelStatus( D6_LEVL ) ) + { + setValveState( D3_VALV, VALVE_STATE_CLOSED ); + depressurizeSubState = HEAT_DEPRES_OPEN_D64; + stateTimerMS = getMSTimerCount(); + applyDepresPhaseActuators( HEAT_DEPRES_OPEN_D64 ); + } + else + { + setValveState( D3_VALV, VALVE_STATE_OPEN ); + } + break; + + case HEAT_DEPRES_OPEN_D64: + if ( TRUE == didTimeout( stateTimerMS, HEAT_DISINFECT_DEPRES_D80_DELAY_MS ) ) + { + depressurizeSubState = HEAT_DEPRES_OPEN_D80; + stateTimerMS = getMSTimerCount(); + applyDepresPhaseActuators( HEAT_DEPRES_OPEN_D80 ); + } + break; + + case HEAT_DEPRES_OPEN_D80: + if ( TRUE == didTimeout( stateTimerMS, HEAT_DISINFECT_DEPRES_D65_OPEN_MS ) ) + { + setValveState( D65_VALV, VALVE_STATE_CLOSED ); + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_DD_RECIRC_SETUP ); + state = DD_HEAT_DISINFECT_DD_RECIRC_SETUP; + } + break; + + default: + depressurizeSubState = HEAT_DEPRES_WAIT_D6; + stateTimerMS = getMSTimerCount(); + break; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleDdRecircSetupState function holds DD recirc setup until the + * 2 minute stability period completes. + * @details \b Inputs: stateTimerMS + * @details \b Outputs: none + * @return the current state of heat disinfect mode + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T handleDdRecircSetupState( void ) +{ + DD_HEAT_DISINFECT_STATE_T state = DD_HEAT_DISINFECT_DD_RECIRC_SETUP; + + if ( TRUE == didTimeout( stateTimerMS, HEAT_DISINFECT_SETUP_STABILITY_MS ) ) + { + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_PRESSURE_CHECK ); + state = DD_HEAT_DISINFECT_PRESSURE_CHECK; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePressureCheckState function starts D5 after D18 exceeds 3 PSI + * and enters the DD line recirc cycle. + * @details \b Inputs: none + * @details \b Outputs: none + * @return the current state of heat disinfect mode + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T handlePressureCheckState( void ) +{ + DD_HEAT_DISINFECT_STATE_T state = DD_HEAT_DISINFECT_PRESSURE_CHECK; + + if ( getFilteredPressure( D18_PRES ) > HEAT_DISINFECT_D18_HEATER_ENABLE_PSI ) + { + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_DD_RECIRC_MAIN ); + state = DD_HEAT_DISINFECT_DD_RECIRC_MAIN; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleDdRecircState function cycles DD line recirc states and + * accumulates D78 dwell. + * @details \b Inputs: heatDisinfectState, stateTimerMS, ddDwellAtTarget, + * ddDwellAccumulatedMS, ddDwellAtTargetStartMS + * @details \b Outputs: ddDwellAtTarget, ddDwellAccumulatedMS, ddDwellAtTargetStartMS + * @return the current state of heat disinfect mode + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T handleDdRecircState( void ) +{ + DD_HEAT_DISINFECT_STATE_T state = heatDisinfectState; + BOOL d78AtTarget = FALSE; + U32 dwellMs; + + if ( getFilteredTemperatureValue( D78_TEMP ) > HEAT_DISINFECT_D78_DWELL_TEMP_C ) + { + d78AtTarget = TRUE; + } + + updateDwell( &ddDwellAtTarget, &ddDwellAccumulatedMS, &ddDwellAtTargetStartMS, d78AtTarget ); + dwellMs = currentDwellMs( ddDwellAtTarget, ddDwellAccumulatedMS, ddDwellAtTargetStartMS ); + + if ( dwellMs >= HEAT_DISINFECT_DWELL_TIME_MS ) + { + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_HYDROBLOCK_RECIRC ); + state = DD_HEAT_DISINFECT_HYDROBLOCK_RECIRC; + } + else if ( TRUE == didTimeout( stateTimerMS, ddRecircDurationMs( heatDisinfectState ) ) ) + { + DD_HEAT_DISINFECT_STATE_T nextState = nextDdRecircState( heatDisinfectState ); + + setModeHeatDisinfectStateTransition( nextState ); + state = nextState; + } + else + { + // Remain in the current line recirc state. + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHydroblockRecircState function heats until D4 is at or above + * 88 C, then enters bicart supply. + * @details \b Inputs: hydroblockHeaterStopped, wcidDwellAtTarget, + * wcidDwellAccumulatedMS, wcidDwellAtTargetStartMS + * @details \b Outputs: hydroblockHeaterStopped, wcidDwellAtTarget, + * wcidDwellAccumulatedMS, wcidDwellAtTargetStartMS + * @return the current state of heat disinfect mode + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T handleHydroblockRecircState( void ) +{ + DD_HEAT_DISINFECT_STATE_T state = DD_HEAT_DISINFECT_HYDROBLOCK_RECIRC; + + updateWcidDwellFromD4(); + + if ( FALSE == hydroblockHeaterStopped ) + { + if ( getFilteredTemperatureValue( D4_TEMP ) >= HEAT_DISINFECT_HYDROBLOCK_STOP_TEMP_C ) + { + hydroblockHeaterStopped = TRUE; + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_BICART_SUPPLY ); + state = DD_HEAT_DISINFECT_BICART_SUPPLY; + } + } + else + { + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_BICART_SUPPLY ); + state = DD_HEAT_DISINFECT_BICART_SUPPLY; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleBicartSupplyState function runs supply recirc for 6 s and + * flutters D65 around 3 PSI. + * @details \b Inputs: stateTimerMS, wcidDwellAtTarget, wcidDwellAccumulatedMS, + * wcidDwellAtTargetStartMS + * @details \b Outputs: wcidDwellAtTarget, wcidDwellAccumulatedMS, wcidDwellAtTargetStartMS + * @return the current state of heat disinfect mode + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T handleBicartSupplyState( void ) +{ + DD_HEAT_DISINFECT_STATE_T state = DD_HEAT_DISINFECT_BICART_SUPPLY; + + updateWcidDwellFromD4(); + manageD65ForBicartRecirc(); + + if ( TRUE == didTimeout( stateTimerMS, HEAT_DISINFECT_BICART_SUPPLY_MS ) ) + { + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_BICART_VENT ); + state = DD_HEAT_DISINFECT_BICART_VENT; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleBicartVentState function runs vent recirc for 6 s and + * flutters D65 around 3 PSI. + * @details \b Inputs: stateTimerMS, wcidDwellAtTarget, wcidDwellAccumulatedMS, + * wcidDwellAtTargetStartMS + * @details \b Outputs: wcidDwellAtTarget, wcidDwellAccumulatedMS, wcidDwellAtTargetStartMS + * @return the current state of heat disinfect mode + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T handleBicartVentState( void ) +{ + DD_HEAT_DISINFECT_STATE_T state = DD_HEAT_DISINFECT_BICART_VENT; + + updateWcidDwellFromD4(); + manageD65ForBicartRecirc(); + + if ( TRUE == didTimeout( stateTimerMS, HEAT_DISINFECT_BICART_VENT_MS ) ) + { + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_WCID_DWELL_CHECK ); + state = DD_HEAT_DISINFECT_WCID_DWELL_CHECK; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleWcidDwellCheckState function mixes with D5 off for 6 s, then + * completes if D4 dwell is met or returns to hydroblock. + * @details \b Inputs: stateTimerMS, wcidDwellAtTarget, wcidDwellAccumulatedMS, + * wcidDwellAtTargetStartMS + * @details \b Outputs: wcidDwellAtTarget, wcidDwellAccumulatedMS, wcidDwellAtTargetStartMS + * @return the current state of heat disinfect mode + *************************************************************************/ +static DD_HEAT_DISINFECT_STATE_T handleWcidDwellCheckState( void ) +{ + DD_HEAT_DISINFECT_STATE_T state = DD_HEAT_DISINFECT_WCID_DWELL_CHECK; + U32 dwellMs; + + updateWcidDwellFromD4(); + dwellMs = currentDwellMs( wcidDwellAtTarget, wcidDwellAccumulatedMS, wcidDwellAtTargetStartMS ); + + if ( TRUE == didTimeout( stateTimerMS, HEAT_DISINFECT_WCID_DWELL_CHECK_MS ) ) + { + if ( dwellMs >= HEAT_DISINFECT_DWELL_TIME_MS ) + { + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_STATE_COMPLETE ); + state = DD_HEAT_DISINFECT_STATE_COMPLETE; + } + else + { + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_HYDROBLOCK_RECIRC ); + state = DD_HEAT_DISINFECT_HYDROBLOCK_RECIRC; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The execHeatDisinfectMode function executes the heat disinfect mode + * state machine. + * @details \b Inputs: pendingStopDDHeatDisinfectRequest, heatDisinfectState + * @details \b Outputs: pendingStopDDHeatDisinfectRequest, heatDisinfectState + * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when wrong heat disinfect + * state invoked. + * @return current state + *************************************************************************/ +U32 execHeatDisinfectMode( void ) +{ + if ( TRUE == pendingStopDDHeatDisinfectRequest ) + { + pendingStopDDHeatDisinfectRequest = FALSE; + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_STATE_COMPLETE ); + heatDisinfectState = DD_HEAT_DISINFECT_STATE_COMPLETE; + requestNewOperationMode( DD_MODE_STAN ); + } + else + { + switch ( heatDisinfectState ) + { + case DD_HEAT_DISINFECT_STATE_START: + setModeHeatDisinfectStateTransition( DD_HEAT_DISINFECT_DEPRESSURIZE_BICART ); + heatDisinfectState = DD_HEAT_DISINFECT_DEPRESSURIZE_BICART; + break; + + case DD_HEAT_DISINFECT_DEPRESSURIZE_BICART: + heatDisinfectState = handleDepressurizeBicartState(); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_SETUP: + heatDisinfectState = handleDdRecircSetupState(); + break; + + case DD_HEAT_DISINFECT_PRESSURE_CHECK: + heatDisinfectState = handlePressureCheckState(); + break; + + case DD_HEAT_DISINFECT_DD_RECIRC_MAIN: + case DD_HEAT_DISINFECT_DD_RECIRC_DIALYZER: + case DD_HEAT_DISINFECT_DD_RECIRC_D100: + case DD_HEAT_DISINFECT_DD_RECIRC_D34: + case DD_HEAT_DISINFECT_DD_RECIRC_D91: + case DD_HEAT_DISINFECT_DD_RECIRC_D76_D47: + heatDisinfectState = handleDdRecircState(); + break; + + case DD_HEAT_DISINFECT_HYDROBLOCK_RECIRC: + heatDisinfectState = handleHydroblockRecircState(); + break; + + case DD_HEAT_DISINFECT_BICART_SUPPLY: + heatDisinfectState = handleBicartSupplyState(); + break; + + case DD_HEAT_DISINFECT_BICART_VENT: + heatDisinfectState = handleBicartVentState(); + break; + + case DD_HEAT_DISINFECT_WCID_DWELL_CHECK: + heatDisinfectState = handleWcidDwellCheckState(); + break; + + case DD_HEAT_DISINFECT_STATE_COMPLETE: + requestNewOperationMode( DD_MODE_STAN ); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_HEAT_DISINFECT_MODE_INVALID_EXEC_STATE, heatDisinfectState ) + heatDisinfectState = DD_HEAT_DISINFECT_STATE_START; + break; + } + } + + publishHeatDisinfectModeData(); + + return heatDisinfectState; +} + +/*********************************************************************//** + * @brief + * The getCurrentHeatDisinfectState function returns the current heat + * disinfect state. + * @details \b Inputs: heatDisinfectState + * @details \b Outputs: none + * @return current heat disinfect state + *************************************************************************/ +DD_HEAT_DISINFECT_STATE_T getCurrentHeatDisinfectState( void ) +{ + return heatDisinfectState; +} + +/*********************************************************************//** + * @brief + * The requestDDHeatDisinfectStop function handles a request to stop heat + * disinfect. + * @details \b Inputs: none + * @details \b Outputs: pendingStopDDHeatDisinfectRequest + * @return TRUE if the request was accepted, FALSE if not + *************************************************************************/ +BOOL requestDDHeatDisinfectStop( void ) +{ + BOOL result = FALSE; + + if ( DD_MODE_HEAT == getCurrentOperationMode() ) + { + pendingStopDDHeatDisinfectRequest = TRUE; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The publishHeatDisinfectModeData function broadcasts heat disinfect + * mode data at the configured interval. + * @details \b Inputs: heatDisinfectPublishTimerCounter, heatDisinfectModePublishInterval + * @details \b Outputs: heatDisinfectPublishTimerCounter + * @details \b Message \Sent: MSG_ID_DD_HEAT_DISINFECT_STATE_DATA to publish the + * heat disinfect mode data. + * @return none + *************************************************************************/ +static void publishHeatDisinfectModeData( void ) +{ + if ( ++heatDisinfectPublishTimerCounter >= getU32OverrideValue( &heatDisinfectModePublishInterval ) ) + { + HEAT_DISINFECT_STATE_DATA_T data; + + data.heatDisinfectExecState = (U32)getCurrentHeatDisinfectState(); + broadcastData( MSG_ID_DD_HEAT_DISINFECT_STATE_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( HEAT_DISINFECT_STATE_DATA_T ) ); + heatDisinfectPublishTimerCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + +/*********************************************************************//** + * @brief + * The testDDHeatDisinfectDataPublishIntervalOverride function overrides + * the heat disinfect mode data publish interval. + * @details \b Inputs: heatDisinfectModePublishInterval + * @details \b Outputs: heatDisinfectModePublishInterval + * @param message Dial-in override message + * @return TRUE if override successful + *************************************************************************/ +BOOL testDDHeatDisinfectDataPublishIntervalOverride( MESSAGE_T *message ) +{ + return u32BroadcastIntervalOverride( message, &heatDisinfectModePublishInterval, TASK_GENERAL_INTERVAL ); +} + +/**@}*/ Index: firmware/App/Modes/ModeHeatDisinfect.h =================================================================== diff -u --- firmware/App/Modes/ModeHeatDisinfect.h (revision 0) +++ firmware/App/Modes/ModeHeatDisinfect.h (revision 0d5d4c781a0de550c6badbe3cd7c850091c62d29) @@ -0,0 +1,53 @@ +/************************************************************************** +* +* Copyright (c) 2024-2026 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file ModeHeatDisinfect.h +* +* @author (last) Jashwant Gantyada +* @date (last) 18-Aug-2026 +* +* @author (original) Jashwant Gantyada +* @date (original) 17-Aug-2026 +* +***************************************************************************/ + +#ifndef __MODE_HEAT_DISINFECT_H__ +#define __MODE_HEAT_DISINFECT_H__ + +#include "DDCommon.h" +#include "DDDefs.h" + +/** + * @defgroup DDHeatDisinfectMode DDHeatDisinfectMode + * @brief Heat disinfect mode unit. Manages heat disinfection via a state + * machine. + * + * @addtogroup DDHeatDisinfectMode + * @{ + */ + +// ********** public definitions ********** + +/// Heat disinfect mode data structure +typedef struct +{ + U32 heatDisinfectExecState; ///< Heat disinfect execution state +} HEAT_DISINFECT_STATE_DATA_T; + +// ********** public function prototypes ********** + +void initHeatDisinfectMode( void ); // Initialize this heat disinfect mode unit +U32 transitionToHeatDisinfectMode( void ); // Prepares for transition to heat disinfect mode +U32 execHeatDisinfectMode( void ); // Execute the heat disinfect mode state machine +DD_HEAT_DISINFECT_STATE_T getCurrentHeatDisinfectState( void ); // Get the current heat disinfect state +BOOL requestDDHeatDisinfectStop( void ); // Stop heat disinfect and return to standby + +BOOL testDDHeatDisinfectDataPublishIntervalOverride( MESSAGE_T *message ); // Heat disinfect data publish interval override + +/**@}*/ + +#endif