Index: firmware/.launches/DG.launch =================================================================== diff -u -re86af65442a36724461317980814f0868bd8c995 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/.launches/DG.launch (.../DG.launch) (revision e86af65442a36724461317980814f0868bd8c995) +++ firmware/.launches/DG.launch (.../DG.launch) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -1,10 +1,34 @@ +<<<<<<< HEAD + + + + + + + + + + + + + + + + + + + + + +======= +>>>>>>> staging Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r1a7b3fdc8c9b47ae713a7ec37670a96df7d73818 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 1a7b3fdc8c9b47ae713a7ec37670a96df7d73818) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -114,6 +114,10 @@ static PUMP_CONTROL_MODE_T roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Requested RO pump control mode. static PUMP_CONTROL_MODE_T roPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Currently set RO pump control mode. TODO do we need this? +static F32 pendingROPumpCmdMaxPressure = 0.0; ///< Delayed (pending) RO pump max pressure (in PSI) setting. +static F32 pendingROPumpCmdTargetFlow = 0.0; ///< Delayed (pending) RO pump target flow rate (in mL/min) setting. +static U32 pendingROPumpCmdCountDown = 0; ///< Delayed (pending) RO pump command count down timer (in task intervals). + static F32 targetROPumpFlowRate = 0.0; ///< Target RO flow rate (in L/min). static F32 targetROPumpMaxPressure = 0.0; ///< Target RO max allowed pressure (in PSI). @@ -179,9 +183,6 @@ initPersistentAlarm( ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL, MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL ); - // Initialize the persistent alarm for ramp up to target flow timeout - initPersistentAlarm( ALARM_ID_RO_PUMP_RAMP_UP_TO_FLOW_TIMEOUT, MAX_ALLOWED_RAMP_UP_TIME, MAX_ALLOWED_RAMP_UP_TIME ); - // Initialize the persistent alarm for not turning off the pump initPersistentAlarm( ALARM_ID_RO_PUMP_OFF_FAULT, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); @@ -249,6 +250,49 @@ /*********************************************************************//** * @brief + * The setROPumpTargetFlowRateDelayed function sets a new target flow rate for the + * RO pump to be set after given delay. + * @details Inputs: none + * @details Outputs: pendingROPumpCmdMaxPressure, pendingROPumpCmdTargetFlow, + * pendingROPumpCmdCountDown + * @param roFlowRate which is target RO flow rate + * @param maxPressure which is the maximum allowed pressure that the RO pump + * can reach + * @param delayMs delay duration (in ms) before RO pump started + * @return TRUE if new target flow rate is set successfully, FALSE if not + *************************************************************************/ +BOOL setROPumpTargetFlowRateDelayed( F32 roFlowRate, U32 maxPressure, U32 delayMs ) +{ + BOOL result = FALSE; + + // First of all, the flow rate must be in range + if ( ( roFlowRate <= MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM ) ) + { + // Then the max pressure that we are allowed to reach must be in range + if ( ( maxPressure >= MIN_ALLOWED_PRESSURE_PSI ) && ( maxPressure <= MAX_ALLOWED_PRESSURE_PSI ) ) + { + pendingROPumpCmdMaxPressure = (F32)maxPressure; + pendingROPumpCmdTargetFlow = roFlowRate; + pendingROPumpCmdCountDown = delayMs / TASK_GENERAL_INTERVAL; + result = TRUE; + } + // Requested max pressure is out of range + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_FLOW_RATE_SET, maxPressure ) + } + } + // Requested flow rate is out of range + else + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_PRESSURE_SELECTED, roFlowRate ) + } + + return result; +} + +/*********************************************************************//** + * @brief * The signalROPumpHardStop function stops the RO pump immediately and * resets all the variables associated with the RO pump run. * @details Inputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, @@ -362,6 +406,26 @@ *************************************************************************/ void execROPumpController( void ) { + // Handle pending delayed RO pump command + if ( pendingROPumpCmdCountDown > 0 ) + { + pendingROPumpCmdCountDown--; + if ( 0 == pendingROPumpCmdCountDown ) + { + targetROPumpMaxPressure = pendingROPumpCmdMaxPressure; + targetROPumpFlowRate = pendingROPumpCmdTargetFlow; + pendingROPumpCmdMaxPressure = 0.0; + pendingROPumpCmdTargetFlow = 0.0; + roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; + roPumpState = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; + // Get the initial guess of the duty cycle + roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( targetROPumpFlowRate ); + roControlTimerCounter = 0; + isROPumpOn = TRUE; + } + } + + // Execute RO pump control state machine switch ( roPumpState ) { case RO_PUMP_OFF_STATE: @@ -393,13 +457,13 @@ /*********************************************************************//** * @brief - * The isReverseOsmosisPumpOn function returns the on/off status of RO pump. + * The isROPumpRunning function returns the on/off status of RO pump. * @details Inputs: isROPumpOn * @details Outputs: none * @return isROPumpOn the boolean flag that is TRUE if the pump is on and * FALSE if it is off *************************************************************************/ -BOOL isReverseOsmosisPumpOn( void ) +BOOL isROPumpRunning( void ) { return isROPumpOn; } Index: firmware/App/Controllers/TemperatureSensors.c =================================================================== diff -u -r34ed52c598042fdcfa5526e3b1d46fa09b040199 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Controllers/TemperatureSensors.c (.../TemperatureSensors.c) (revision 34ed52c598042fdcfa5526e3b1d46fa09b040199) +++ firmware/App/Controllers/TemperatureSensors.c (.../TemperatureSensors.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -255,7 +255,7 @@ // Persistent alarm for temperature sensors internal error // When the FPGA read count does not increment for a period of time, it is considered as an internal error of the temperature sensors // driver. This is internal because FPGA does not error out if the FPGA read count does not increment. - initPersistentAlarm( ALARM_ID_TEMPERATURE_SENSORS_FAULT, TEMPERATURE_SENSORS_FPGA_ERROR_PERSISTENT_PERIOD, TEMPERATURE_SENSORS_FPGA_ERROR_PERSISTENT_PERIOD ); + initPersistentAlarm( ALARM_ID_DG_TEMPERATURE_SENSORS_ADC_FAULT, TEMPERATURE_SENSORS_FPGA_ERROR_PERSISTENT_PERIOD, TEMPERATURE_SENSORS_FPGA_ERROR_PERSISTENT_PERIOD ); } /*********************************************************************//** @@ -559,7 +559,7 @@ BOOL isThereAnError = !isFPGACountChanging || !isFPGAErrorZero; - checkPersistentAlarm( ALARM_ID_TEMPERATURE_SENSORS_FAULT, isThereAnError, sensorIndex, TEMPERATURE_SENSORS_FPGA_ERROR_PERSISTENT_PERIOD ); + checkPersistentAlarm( ALARM_ID_DG_TEMPERATURE_SENSORS_ADC_FAULT, isThereAnError, sensorIndex, TEMPERATURE_SENSORS_FPGA_ERROR_PERSISTENT_PERIOD ); return isADCValid; } @@ -670,7 +670,7 @@ if ( ( TRUE == isLessThanZero ) || ( TRUE == isGreaterThanFullScale ) ) { tempSensorsSelfTestResult = SELF_TEST_STATUS_FAILED; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TEMPERATURE_SENSORS_FAULT, TEMPSENSORS_SELF_TEST_ADC_CHECK ); + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_TEMPERATURE_SENSORS_ADC_FAULT, TEMPSENSORS_SELF_TEST_ADC_CHECK ); } return TEMPSENSORS_SELF_TEST_COMPLETE; @@ -735,9 +735,9 @@ rawADC = getFPGACD2Temp(); processTempSnsrsADCRead( TEMPSENSORS_CONDUCTIVITY_SENSOR_2, rawADC, errorCount, readCount ); - rawADC = getFPGATHDoTemp(); - errorCount = (U32)getFPGATHDoErrorCount(); - readCount = (U32)getFPGATHDoReadCount(); + rawADC = getFPGATRoTemp(); + errorCount = (U32)getFPGATRoErrorCount(); + readCount = (U32)getFPGATRoReadCount(); processTempSnsrsADCRead( TEMPSENSORS_OUTLET_REDUNDANT, rawADC, errorCount, readCount ); rawADC = getFPGATDiTemp(); @@ -768,7 +768,7 @@ processTempSnsrsADCRead( TEMPSENSORS_FPGA_BOARD_SENSOR, getFPGABoardTemp(), 0, ++simulatedCounter ); processTempSnsrsADCRead( TEMPSENSORS_LOAD_CELL_A1_B1, getFPGALoadCellsA1B1Temp(), getFPGAADC1ErrorCount(), getFPGAADC1ReadCount() ); processTempSnsrsADCRead( TEMPSENSORS_LOAD_CELL_A2_B2, getFPGALoadCellsA2B2Temp(), getFPGAADC2ErrorCount(), getFPGAADC2ReadCount() ); - processTempSnsrsADCRead( TEMPSENSORS_INTERNAL_THDO_RTD, getFPGATHDoInternalTemp(), getFPGATHDoErrorCount(), getFPGATHDoReadCount() ); + processTempSnsrsADCRead( TEMPSENSORS_INTERNAL_THDO_RTD, getFPGATRoInternalTemp(), getFPGATRoErrorCount(), getFPGATRoReadCount() ); processTempSnsrsADCRead( TEMPSENSORS_INTERNAL_TDI_RTD, getFPGATDiInternalTemp(), getFPGATDiErrorCount(), getFPGATDiReadCount() ); processTempSnsrsADCRead( TEMPSENSORS_INTERNAL_COND_TEMP_SENSOR, getFPGACondSnsrInternalTemp(), getFPGARTDErrorCount(), getFPGARTDReadCount() ); Index: firmware/App/DGCommon.h =================================================================== diff -u -r1a7b3fdc8c9b47ae713a7ec37670a96df7d73818 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/DGCommon.h (.../DGCommon.h) (revision 1a7b3fdc8c9b47ae713a7ec37670a96df7d73818) +++ firmware/App/DGCommon.h (.../DGCommon.h) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -37,8 +37,8 @@ // #define SIMULATE_UI 1 // #define TASK_TIMING_OUTPUT_ENABLED 1 // re-purposes drain pump enable pin for task timing // #define DISABLE_HEATERS_AND_TEMPS 1 - #define DISABLE_ACCELS 1 - #define SKIP_POST 1 +// #define DISABLE_ACCELS 1 +// #define SKIP_POST 1 #define DISABLE_CAL_CHECK 1 // #define ENABLE_DIP_SWITCHES 1 // #define EMC_TEST_BUILD 1 @@ -50,7 +50,7 @@ #define IGNORE_HEATERS_MONITOR 1 #define IGNORE_RO_PUMP_MONITOR 1 #define IGNORE_HEAT_DISINFECT_RSRVR_TIMEOUT 1 - #define DISABLE_RO_RATIO_CHECK 1 +// #define DISABLE_RO_RATIO_CHECK 1 #define DISABLE_COND_SENSOR_CHECK 1 #define DISABLE_MIXING 1 #define DISABLE_WATER_QUALITY_CHECK 1 Index: firmware/App/Modes/ModeFault.c =================================================================== diff -u -rd7926685f2fe3086bab183166119f0965a192a69 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision d7926685f2fe3086bab183166119f0965a192a69) +++ firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -20,6 +20,7 @@ #include "ModeFault.h" #include "OperationModes.h" #include "ROPump.h" +#include "SystemCommMessages.h" #include "UVReactors.h" #include "Valves.h" @@ -57,6 +58,12 @@ *************************************************************************/ void transitionToFaultMode( void ) { + // Publish POST failure status to UI if fault triggered in Init/POST mode + if ( DG_MODE_INIT == getPreviousOperationMode() ) + { + // Broadcast final POST failed + sendPOSTFinalResult( FALSE ); + } } /*********************************************************************//** @@ -113,7 +120,7 @@ setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_CLOSED ); setValveState( VSP, VALVE_STATE_CLOSED ); - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); Index: firmware/App/Modes/ModeFlush.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Modes/ModeFlush.c (.../ModeFlush.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Modes/ModeFlush.c (.../ModeFlush.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -15,9 +15,20 @@ * ***************************************************************************/ +#include "DrainPump.h" +#include "Heaters.h" +#include "LoadCell.h" +#include "ModeFault.h" #include "ModeFlush.h" #include "OperationModes.h" #include "Pressures.h" +#include "Reservoirs.h" +#include "ROPump.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "Timers.h" +#include "UVReactors.h" +#include "Valves.h" /** * @addtogroup DGFlushMode @@ -26,22 +37,103 @@ // ********** private definitions ********** +// General defines +#define FLUSH_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode flush data publish interval in counts. +#define RO_PUMP_TARGET_FLOW_RATE_LPM 0.8 ///< RO pump target flow rate during flush/fill in L/min. TODO original flow was 0.8 +#define RO_PUMP_MAX_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. +#define DRAIN_PUMP_TARGET_RPM 1800 ///< Drain pump target RPM during drain. + +// Drain R1 & R2 states defines +#define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. + +// Flush drain path state defines +#define FLUSH_DRAIN_WAIT_TIME_MS ( 1 * 60 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. TODo original time is 2 minutes + +// Flush dialysate state defines +#define FLUSH_DIALYSATE_WAIT_TIME_MS ( 0.5 * 60 * MS_PER_SECOND ) ///< Flush dialysate wait time in milliseconds. + +// Flush concentrate straws state defines +#define FLUSH_CONCENTRATE_STRAWS_TIME_MS ( 0.5 * 60 * MS_PER_SECOND ) ///< Flush concentrate straws wait time in milliseconds. TODO original time is 3 minutes + +// Flush and drain R1 and R2 state defines +#define RSRVRS_FULL_VOL_ML 1650.0 ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 +#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< 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 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. TODO original value was 5 minutes +#define RSRVRS_PARTIAL_FILL_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. +#define RSRVRS_DRAIN_TIMEOUT_MS ( 3 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. TODO original value was 2 minutes +#define FINAL_DRAIN_RO_PUMP_FLOW_LPM 0.6 ///< Final drain RO pump flow rate in L/min. This is used to flush the drain line during drain. + +// Flush drain line state defines +#define FLUSH_DRAIN_LINE_VOLUME_L 0.1 ///< Water volume to flush in liters. +#define FLUSH_DRAIN_LINE_TIMEOUT_MS ( 1 * 60 * MS_PER_SECOND ) ///< Flush drain lines timeout in milliseconds. + +// Flush circulation state defines +#define FLUSH_CIRCULATION_WAIT_TIME_MS ( 0.5 * 60 * MS_PER_SECOND ) ///< Flush circulation wait time in milliseconds. + +// Flush with fresh water state defines +#define FLUSH_WITH_FRESH_WATER_WAIT_TIME_MS ( 0.5 * 60 * MS_PER_SECOND ) ///< Flush with fresh water wait time in milliseconds. + // ********** private data ********** -static DG_FLUSH_STATE_T flushState = DG_FLUSH_STATE_START; ///< Currently active flush state. +static DG_FLUSH_STATE_T flushState = DG_FLUSH_STATE_START; ///< Current active flush state. +static DG_FLUSH_STATE_T prevFlushState = DG_FLUSH_STATE_START; ///< Previous flush state. +static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. +static U32 overallFlushElapsedTimeStart = 0; ///< Overall flush mode elapsed time start. +static U32 stateTimerStart = 0; ///< State timer start. +static ALARM_ID_T alarmDetectedPendingTrigger; ///< Alarm ID that is detected and is pending to be triggered. +static DG_RESERVOIR_STATUS_T rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 1 status. +static DG_RESERVOIR_STATUS_T rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 2 status. +static BOOL isThisInitialDrain = TRUE; ///< Initial drain boolean flag. +static U32 dataPublishCounter = 0; ///< Flush data publish counter. +static BOOL hasWaterCancellationBeenSet = FALSE; ///< Water cancellation set/not set boolean flag. +static F32 flushLinesVolumeL = 0.0; ///< Volume of water pumped by RO pump during flush lines state. // ********** private function prototypes ********** +static DG_FLUSH_STATE_T handleFlushModeStartState( void ); +static DG_FLUSH_STATE_T handleFlushModeDrainR1State( void ); +static DG_FLUSH_STATE_T handleFlushModeDrainR2State( void ); +static DG_FLUSH_STATE_T handleFlushModeFlushDrainState( void ); +static DG_FLUSH_STATE_T handleFlushModeFlushDialysateState( void ); +static DG_FLUSH_STATE_T handleFlushModeFlushConcentrateStrawsState( void ); +static DG_FLUSH_STATE_T handleFlushModeFlushR1ToR2State( void ); +static DG_FLUSH_STATE_T handleFlushModeFlushR2AndDrainR1State( void ); +static DG_FLUSH_STATE_T handleFlushModeFlushCirculationDrainLineState( void ); +static DG_FLUSH_STATE_T handleFlushModeFlushCirculationState( void ); +static DG_FLUSH_STATE_T handleFlushModeFlushWithFreshWaterState( void ); +static DG_FLUSH_STATE_T handleFlushModeCancelBasicPathState( void ); +static DG_FLUSH_STATE_T handleFlushModeCancelWaterPathState( void ); +static DG_FLUSH_STATE_T handleFlushModeComplete( void ); + +static void failFlushMode( void ); +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ); +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); +static void publishFlushData( void ); + /*********************************************************************//** * @brief * The initFlushMode function initializes flush mode module. * @details Inputs: none - * @details Outputs: Initialized flush mode module + * @details Outputs: flushState, prevFlushState, rsrvrFillStableTimeCounter, + * overallFlushElapsedTime, isThisInitialDrain, dataPublishCounter, + * rsrvr1Status, rsrvr2Status, hasWaterCancellationBeenSet, + * flushLinesVolumeL * @return none *************************************************************************/ void initFlushMode( void ) { - flushState = DG_FLUSH_STATE_START; + // Initialize the variables + flushState = DG_FLUSH_STATE_START; + prevFlushState = DG_FLUSH_STATE_START; + rsrvrFillStableTimeCounter = 0; + overallFlushElapsedTimeStart = 0; + isThisInitialDrain = TRUE; + dataPublishCounter = 0; + rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; + rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; + hasWaterCancellationBeenSet = FALSE; + flushLinesVolumeL = 0.0; } /*********************************************************************//** @@ -53,45 +145,832 @@ *************************************************************************/ void transitionToFlushMode( void ) { + // Reset all the actuators + deenergizeActuators(); + initFlushMode(); } /*********************************************************************//** * @brief * The execFlushMode function executes the flush mode state machine. - * @details Inputs: none - * @details Outputs: Flush mode state machine executed + * @details Inputs: flushState + * @details Outputs: flushState * @return current state *************************************************************************/ U32 execFlushMode( void ) { - checkInletPressureFault(); - - // execute current flush state + // Execute current flush state switch ( flushState ) { case DG_FLUSH_STATE_START: + flushState = handleFlushModeStartState(); break; + case DG_FLUSH_STATE_DRAIN_R1: + flushState = handleFlushModeDrainR1State(); + break; + + case DG_FLUSH_STATE_DRAIN_R2: + flushState = handleFlushModeDrainR2State(); + break; + + case DG_FLUSH_STATE_FLUSH_DRAIN: + flushState = handleFlushModeFlushDrainState(); + break; + + case DG_FLUSH_STATE_FLUSH_DIALYSATE: + flushState = handleFlushModeFlushDialysateState(); + break; + + case DG_FLUSH_STATE_FLUSH_CONCENTRATE_STRAWS: + flushState = handleFlushModeFlushConcentrateStrawsState(); + break; + + case DG_FLUSH_STATE_FLUSH_R1_TO_R2: + flushState = handleFlushModeFlushR1ToR2State(); + break; + + case DG_FLUSH_STATE_FLUSH_R2_AND_DRAIN_R1: + flushState = handleFlushModeFlushR2AndDrainR1State(); + break; + + case DG_FLUSH_STATE_FLUSH_CIRCULATION_DRAIN_LINE: + flushState = handleFlushModeFlushCirculationDrainLineState(); + break; + + case DG_FLUSH_STATE_FLUSH_CIRCULATION: + flushState = handleFlushModeFlushCirculationState(); + break; + + case DG_FLUSH_STATE_FLUSH_WITH_FRESH_WATER: + flushState = handleFlushModeFlushWithFreshWaterState(); + break; + + case DG_FLUSH_STATE_CANCEL_BASIC_PATH: + flushState = handleFlushModeCancelBasicPathState(); + break; + + case DG_FLUSH_STATE_CANCEL_WATER_PATH: + flushState = handleFlushModeCancelWaterPathState(); + break; + + case DG_FLUSH_STATE_COMPLETE: + flushState = handleFlushModeComplete(); + break; + default: - // TODO - s/w fault + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_DG_FLUSH_INVALID_EXEC_STATE, flushState ) flushState = DG_FLUSH_STATE_START; break; } - return flushState; + // Publish the data + publishFlushData(); + + return (U32)flushState; } /*********************************************************************//** * @brief - * The getCurrentFlushState function returns the current state of the flush mode. + * The getCurrentFlushState function returns the current state of the flush + * mode. * @details Inputs: flushState * @details Outputs: none - * @return current state of flush mode. + * @return flushState which is the current state of flush mode. *************************************************************************/ DG_FLUSH_STATE_T getCurrentFlushState( void ) { return flushState; } +/*********************************************************************//** + * @brief + * The stopDGFlush function stops flush mode if the current operation mode + * is flush mode. + * @details Inputs: none + * @details Outputs: none + * @return TRUE if the current mode is flush otherwise, FALSE + *************************************************************************/ +BOOL stopDGFlush( void ) +{ + BOOL status = FALSE; + + // Check if the current operation mode is flush + if ( DG_MODE_FLUS == getCurrentOperationMode() ) + { + // Reset all the actuators + deenergizeActuators(); + + // Transition to mode standby + requestNewOperationMode( DG_MODE_STAN ); + + status = TRUE; + } + + return status; +} + +// ********** private functions ********** + +/*********************************************************************//** + * @brief + * The handleFlushModeStartState function handles the flush start state. + * If the sensors are in range, it transitions to the next state otherwise, + * it transitions to basic cancellation state. + * @details Inputs: stateTimerStart, rsrvr1Status + * @details Outputs: stateTimerStart, rsrvr1Status + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeStartState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_START; + + // Reset the load cells lowest weight prior to starting the run + resetReservoirsLowestWeight(); + + // Start overall flush timer + overallFlushElapsedTimeStart = getMSTimerCount(); + + // Close VPi to prevent wasting water + setValveState( VPI, VALVE_STATE_CLOSED ); + + // Request a tare for reservoir 1 + tareReservoir(); + + // Set the actuators to drain R1 + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + stateTimerStart = getMSTimerCount(); + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_FLUSH_STATE_DRAIN_R1; + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeDrainR1State function handles the drain reservoir 1. + * If the drain is completed within the defined time, it transitions to the + * next state, otherwise, it transitions to basic cancellation state. + * @details Inputs: stateTimerStart, rsrvr1Status,rsrvr2Status, isThisInitialDrain + * @details Outputs: stateTimerStart, rsrvr1Status, rsrvr2Status + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeDrainR1State( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_DRAIN_R1; + + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_DRAIN_TIMEOUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + if ( TRUE == isThisInitialDrain ) + { + // Request a tare for reservoir 2 + tareReservoir(); + } + + // Set the actuators to drain R2 + // NOTE: Drain pump is already on and VDr is already on drain state + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + + stateTimerStart = getMSTimerCount(); + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_FLUSH_STATE_DRAIN_R2; + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + state = DG_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeDrainR2State function handles the drain reservoir 2. + * If the drain is completed within the defined time, it transitions to the + * next state, otherwise, it transitions to basic cancellation state. + * @details Inputs: stateTimerStart, rsrvr1Status, rsrvr2Status, isThisInitialDrain + * @details Outputs: stateTimerStart, rsrvr1Status, rsrvr2Status + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeDrainR2State( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_DRAIN_R2; + + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_DRAIN_TIMEOUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // Done with draining + signalDrainPumpHardStop(); + + if ( TRUE == isThisInitialDrain ) + { + // Set the actuators to flush drain + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + + state = DG_FLUSH_STATE_FLUSH_DRAIN; + } + else + { + // Set the actuators to pull fresh water in to drain the circulation line + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setROPumpTargetFlowRate( FINAL_DRAIN_RO_PUMP_FLOW_LPM, RO_PUMP_MAX_PRESSURE_PSI ); + + state = DG_FLUSH_STATE_FLUSH_CIRCULATION_DRAIN_LINE; + } + + stateTimerStart = getMSTimerCount(); + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + state = DG_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeFlushDrainState function handles the flush drain state. + * Once the flush drain time has elapsed, it transitions to the next state. + * @details Inputs: stateTimerStart + * @details Outputs: stateTimerStart + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeFlushDrainState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_FLUSH_DRAIN; + + if ( TRUE == didTimeout( stateTimerStart, FLUSH_DRAIN_WAIT_TIME_MS ) ) + { + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM, RO_PUMP_MAX_PRESSURE_PSI ); + + // Turn on the UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + + stateTimerStart = getMSTimerCount(); + + state = DG_FLUSH_STATE_FLUSH_DIALYSATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeFlushDialysateState function handles the flush + * dialysate state. Once the flush dialysate time has elapsed, it + * transitions to the next state. + * @details Inputs: stateTimerStart + * @details Outputs: stateTimerStart + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeFlushDialysateState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_FLUSH_DIALYSATE; + + if ( TRUE == didTimeout( stateTimerStart, FLUSH_DIALYSATE_WAIT_TIME_MS ) ) + { + // TODO turn on the concentrate pumps + stateTimerStart = getMSTimerCount(); + + state = DG_FLUSH_STATE_FLUSH_CONCENTRATE_STRAWS; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeFlushDialysateState function handles the flush + * dialysate state. Once the flush dialysate time has elapsed, it + * transitions to the next state. + * @details Inputs: rsrvr1Status, rsrvr2Status, stateTimerStart + * @details Outputs: rsrvr1Status, rsrvr2Status, stateTimerStart + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeFlushConcentrateStrawsState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_FLUSH_CONCENTRATE_STRAWS; + + if ( TRUE == didTimeout( stateTimerStart, FLUSH_CONCENTRATE_STRAWS_TIME_MS ) ) + { + // TODO turn off the concentrate pumps + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + stateTimerStart = getMSTimerCount(); + + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + state = DG_FLUSH_STATE_FLUSH_R1_TO_R2; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeFlushR1ToR2State function handles the flush + * reservoir 1 to reservoir 2 state. If any of the reservoirs flush within + * the defined period of time, it transitions to the next state, otherwise, + * it transitions to water cancellation state. If reservoir 2 is filled to + * 500 mL before reservoir 1 is filled, it transitions to water cancellation + * state. + * @details Inputs: rsrvr1Status, rsrvr2Status, stateTimerStart + * @details Outputs: rsrvr1Status, rsrvr2Status, stateTimerStart, + * prevFlushState, alarmDetectedPendingTrigger + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeFlushR1ToR2State( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_FLUSH_R1_TO_R2; + + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + // Keep monitoring the status of reservoir 2 as the same time + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_PARTIAL_FILL_TIMEOUT_MS ); + // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already + // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue + // until reservoir 2 is filled up and the tubing might expand or leak. + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + prevFlushState = state; + alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; + state = DG_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_PARTIAL_FILL_TIMEOUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // Set the actuators to flush R2 and drain R1 state + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + stateTimerStart = getMSTimerCount(); + + // Set both reservoirs' status + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + state = DG_FLUSH_STATE_FLUSH_R2_AND_DRAIN_R1; + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + state = DG_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + state = DG_FLUSH_STATE_CANCEL_WATER_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeFlushR2AndDrainR1State function handles the flush + * reservoir 2 and drain reservoir 1 state. If reservoir 2 flushes within + * the defined period of time and reservoir 1 drains within the defined + * period of time, it transitions to the next state. If the flush times out, + * the function transitions to water cancellation state. If the drain times + * out the function transitions to basic cancellation state. If reservoir 1 + * is filled to 500 mL before reservoir 2 is filled, it transitions to + * water cancellation state. + * @details Inputs: rsrvr1Status, rsrvr2Status, stateTimerStart + * @details Outputs: rsrvr1Status, rsrvr2Status, stateTimerStart, + * prevFlushState, alarmDetectedPendingTrigger, isThisInitialDrain + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeFlushR2AndDrainR1State( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_FLUSH_R2_AND_DRAIN_R1; + + // If reservoir 1 is empty, turn off the drain pump + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) + { + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_DRAIN_TIMEOUT_MS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + // Done with draining R1 + signalDrainPumpHardStop(); + } + // Reservoir 1 drain time out + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + state = DG_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + // First reservoir 2 must be completely full + if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) + { + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + U32 drainPumpRPM = getTargetDrainPumpRPM(); + // Keep monitoring the status of reservoir 1 as the same time + F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + // Reservoir 1 cannot be filled before reservoir 2 is filled and is overflowing to reservoir 1. If reservoir 1 has already + // reached to target volume, it means reservoir 2's load cell might be reading incorrect values. This situation might continue + // until reservoir 1 is filled up and the tubing might expand or leak. + // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make + // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL + if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + { + prevFlushState = state; + alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; + state = DG_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + // Once reservoir 2 is full, reservoir 1 must be partially full + else if( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_PARTIAL_FILL_TIMEOUT_MS ); + + // Once R1 is partially full, transition to the next state + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + signalROPumpHardStop(); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + stateTimerStart = getMSTimerCount(); + isThisInitialDrain = FALSE; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_FLUSH_STATE_DRAIN_R1; + } + // Check if reservoir 1 fill timed out + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + state = DG_FLUSH_STATE_CANCEL_WATER_PATH; + } + } + // Check if reservoir 2 fill time out + else if( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + state = DG_FLUSH_STATE_CANCEL_WATER_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeFlushCirculationDrainLineState function handles the + * flush drain line state. Once the drain line was flushed with sufficient + * water, it transitions to the next state. If the line is not drained + * within the defined time, it transitions to water cancellation state. + * @details Inputs: stateTimerStart, flushLinesVolumeL + * @details Outputs: stateTimerStart, flushLinesVolumeL, + * alarmDetectedPendingTrigger + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeFlushCirculationDrainLineState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_FLUSH_CIRCULATION_DRAIN_LINE; + + F32 waterFlowRate = getMeasuredROFlowRate(); + F32 waterVolume = ( ( waterFlowRate / SEC_PER_MIN ) / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); + + // Integrate volume of water moved through line + flushLinesVolumeL += waterVolume; + + // When enough water volume has flowed to flush the lines, transition to flush circulation state + if ( flushLinesVolumeL >= FLUSH_DRAIN_LINE_VOLUME_L ) + { + // Set the actuators to transition to flush circulation + // The valves are set to do flush drain and flush circulation + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM, RO_PUMP_MAX_PRESSURE_PSI ); + + stateTimerStart = getMSTimerCount(); + + state = DG_FLUSH_STATE_FLUSH_CIRCULATION; + } + else if ( TRUE == didTimeout( stateTimerStart, FLUSH_DRAIN_LINE_TIMEOUT_MS ) ) + { + alarmDetectedPendingTrigger = ALARM_ID_DG_DRAIN_CIRCULATION_LINE_TIMEOUT; + // Could not reach to the defined drain line on time + state = DG_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeFlushCirculationState function handles the flush + * circulation state. Once the flush circulation time has elapsed, it + * transitions to the next state. + * @details Inputs: stateTimerStart + * @details Outputs: stateTimerStart + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeFlushCirculationState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_FLUSH_CIRCULATION; + + if ( TRUE == didTimeout( stateTimerStart, FLUSH_CIRCULATION_WAIT_TIME_MS ) ) + { + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + + stateTimerStart = getMSTimerCount(); + + state = DG_FLUSH_STATE_FLUSH_WITH_FRESH_WATER; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeFlushWithFreshWaterState function handles the + * flush with fresh water state. It runs the circulation state with fresh + * water for the defined period of time. + * @details Inputs: stateTimerStart + * @details Outputs: none + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeFlushWithFreshWaterState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_FLUSH_WITH_FRESH_WATER; + + if ( TRUE == didTimeout( stateTimerStart, FLUSH_WITH_FRESH_WATER_WAIT_TIME_MS ) ) + { + deenergizeActuators(); + + state = DG_FLUSH_STATE_COMPLETE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeCancelBasicPathState function handles the flush + * cancel mode basic path state. The state sets the state to complete and + * raises an alarm. + * @details Inputs: none + * @details Outputs: none + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeCancelBasicPathState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_CANCEL_BASIC_PATH; + + // Once the fault alarm is raised, the DG Software will + // deenergize all the actuators + failFlushMode(); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeCancelWaterPathState function handles the flush mode + * cancel water path state. The state drains the 2 reservoirs. If the drain + * times out, it transitions to basic cancellation path. + * @details Inputs: rsrvr1Status, rsrvr2Status, stateTimer, + * hasWaterCancellationBeenSet + * @details Outputs: rsrvr1Status, rsrvr2Status, stateTimer, + * hasWaterCancellationBeenSet + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeCancelWaterPathState( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_CANCEL_WATER_PATH; + + if ( FALSE == hasWaterCancellationBeenSet ) + { + // Stop all the actuators first then decide who should run next + deenergizeActuators(); + + // Set the actuators + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + + // Set both reservoirs to be considered as full + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + + // Water cancellation path was set + hasWaterCancellationBeenSet = TRUE; + + // The drain is set to start from reservoir 2 since all the actuators have been de-energized + // Start the drain pump + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // Start the timer for drain timeout + stateTimerStart = getMSTimerCount(); + } + + // If reservoir 2 is empty, set to drain reservoir 1 + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) + { + // If the cancellation water path cannot be done, got to basic cancellation path + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_DRAIN_TIMEOUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + // Set the drain valve to reservoir 1 + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + { + state = DG_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + // If reservoir 2 has already been drained and reservoir 1 is empty, reset and switch to complete + if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) ) + { + // If the cancellation water path cannot be done, go to basic cancellation path + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_DRAIN_TIMEOUT_MS ); + + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) + { + // Done with draining + signalDrainPumpHardStop(); + + // Raise the alarm + failFlushMode(); + } + } + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) + { + state = DG_FLUSH_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFlushModeComplete function handles the complete state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the flush state machine + *************************************************************************/ +static DG_FLUSH_STATE_T handleFlushModeComplete( void ) +{ + DG_FLUSH_STATE_T state = DG_FLUSH_STATE_COMPLETE; + + stopDGFlush(); + + return state; +} + +/*********************************************************************//** + * @brief + * The failFlushMode function sets the alarm that failed the flush mode. + * @details Inputs: alarm, prevHeatDisinfectState + * @details Outputs: none + * @return none + *************************************************************************/ +static void failFlushMode( void ) +{ + SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, prevFlushState ) +} + +/*********************************************************************//** + * @brief + * The getRsrvrFillStatus function checks whether the target reservoir is + * full or not. If the fill times out, the function sets the status to did + * not reach to target. + * @details Inputs: rsrvrFillStableTimeCounter, alarm, stateTimer, flushState, + * prevFlushState + * @details Outputs: rsrvrFillStableTimeCounter, alarm, stateTimer + * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 + * @param targetVol is the target fill volume + * @param timeout is the fill up time out that is checked against + * @return the status of the reservoirs during filling + *************************************************************************/ +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ) +{ + DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; + F32 volume = 0.0; + + if ( DG_RESERVOIR_1 == r ) + { + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + } + else if ( DG_RESERVOIR_2 == r ) + { + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + } + + // Check the volume of the reservoir against the target volume + if ( volume >= targetVol ) + { + if ( ++rsrvrFillStableTimeCounter >= RSRVRS_FULL_STABLE_TIME_COUNT ) + { + status = DG_RESERVOIR_REACHED_TARGET; + rsrvrFillStableTimeCounter = 0; + // Set the state timer in case it needs to be used for another timeout check + stateTimerStart = getMSTimerCount(); + } + } + else if ( TRUE == didTimeout( stateTimerStart, timeout ) ) + { + // Failed to fill on time + prevFlushState = flushState; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_FILL_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; + } + + return status; +} + +/*********************************************************************//** + * @brief + * The getRsrvrDrainStatus function returns the status of draining a + * reservoir. If the drain times out, it set the status to did not reach + * target. + * @details Inputs: rsrvrFillStableTimeCounter, alarm, stateTimer + * @details Outputs: rsrvrFillStableTimeCounter, alarm, stateTimer, + * prevFlushState + * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 + * @param drainSteadyStateTimeout which is the time the reservoir's level + * does not change and is steady state + * @param timeout which is the timeout that a reservoir must be drained by + * then + * @return the status of the reservoirs during draining + *************************************************************************/ +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 ); + + if ( TRUE == isDrainComplete ) + { + // Set the state timer in case it needs to be used for another timeout check + stateTimerStart = getMSTimerCount(); + status = DG_RESERVOIR_REACHED_TARGET; + } + else if ( TRUE == didTimeout( stateTimerStart, timeout ) ) + { + // Failed to drain on time + prevFlushState = flushState; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; + } + + return status; +} + +/*********************************************************************//** + * @brief + * The publishFlushData function publishes the flush mode data at the set + * interval. + * @details Inputs: dataPublishCounter + * @details Outputs: dataPublishCounter + * @return: none + *************************************************************************/ +static void publishFlushData( void ) +{ + if ( ++dataPublishCounter > FLUSH_DATA_PUB_INTERVAL ) + { + MODE_FLUSH_DATA_T data; + + data.flushState = (U32)flushState; + data.overallElapsedTime = calcTimeSince( overallFlushElapsedTimeStart ); + data.stateElapsedTime = calcTimeSince( stateTimerStart ); + data.drainLineVolume = flushLinesVolumeL; + + broadcastFlushData( &data ); + + dataPublishCounter = 0; + } +} + /**@}*/ Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r8b8b9bbb288c06acec1fdf8a2e93248c3d775478 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 8b8b9bbb288c06acec1fdf8a2e93248c3d775478) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -420,8 +420,13 @@ setValveState( VPI, VALVE_STATE_CLOSED ); // Request a tare for reservoir 1 tareReservoir(); +#ifndef V_2_SYSTEM // Set the actuators to drain R1 + setValveState( VRD1, VALVE_STATE_OPEN ); +#else + // Set the actuators to drain R1 setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); +#endif setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); rsrvrFillStableTimeCounter = 0; @@ -460,7 +465,12 @@ // Set the valves to flush the recirculation line setValveState( VPI, VALVE_STATE_OPEN ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_CLOSED ); +#else setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); +#endif setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); @@ -480,9 +490,17 @@ rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; // Request a tare for reservoir 2 tareReservoir(); +#ifndef V_2_SYSTEM + // 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 ); +#else + // Set the actuators to drain R2. + // NOTE: Drain pump is already on and VDr is already on drain state setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); +#endif state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; } @@ -521,13 +539,22 @@ { if ( TRUE == isThisLastDrain ) { +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); +#else setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); +#endif rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; } else { signalDrainPumpHardStop(); +#ifndef V_2_SYSTEM + // Done with draining R2, close it + setValveState( VRD2, VALVE_STATE_CLOSED ); +#endif setValveState( VPI, VALVE_STATE_OPEN ); stateTrialCounter = 0; stateTimer = getMSTimerCount(); @@ -567,7 +594,11 @@ if ( ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MIN_INLET_TEMPERATURE_C ) && ( getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) <= MAX_INLET_CONDUCTIVITY_US_PER_CM ) ) { +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); +#else setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); +#endif setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); stateTimer = getMSTimerCount(); stateTrialCounter = 0; @@ -714,7 +745,11 @@ setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_OPEN ); +#else setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); +#endif setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); stateTimer = getMSTimerCount(); @@ -764,6 +799,10 @@ { // Done with draining R1 signalDrainPumpHardStop(); +#ifndef V_2_SYSTEM + // Close VRD1 + setValveState( VRD1, VALVE_STATE_CLOSED ); +#endif } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -804,10 +843,18 @@ // Set the valves to drain R2 and no fill setValveState( VPI, VALVE_STATE_CLOSED ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); +#else setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); +#endif setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); +#ifndef V_2_SYSTEM + setValveState( VRD2, VALVE_STATE_OPEN ); +#else setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); +#endif setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); // Start the timer for drain timeout stateTimer = getMSTimerCount(); @@ -851,7 +898,12 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); +#else setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); +#endif // Start the timer for drain timeout stateTimer = getMSTimerCount(); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; @@ -893,12 +945,21 @@ // Prepare for filling the reservoirs and heating the water setValveState( VPI, VALVE_STATE_OPEN ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); +#else setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); +#endif setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); +#else setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); +#endif // Turn on the RO pump setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); @@ -957,7 +1018,11 @@ // Set the valves to drain R2 and no fill setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_OPEN ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); +#else setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); +#endif setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); @@ -1025,7 +1090,12 @@ //TODO turn off CP1 and CP2 // Set the valves to transfer hot water from R1 to R2 and fill up R2. setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); +#else setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); +#endif setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); // Although there is fluid in both reservoirs, but they are set to empty @@ -1160,8 +1230,14 @@ // water does not enter the circulation path the membrane is cooling down setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_CLOSED ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); +#else setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); +#endif + stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_RO_FILTER; } @@ -1223,6 +1299,9 @@ if ( ( TRUE == didTimeout( stateTimer, DRAIN_PUMP_START_TIME_IN_MIX_DRAIN_MS ) ) && ( isDrainPumpInMixDrainOn == FALSE ) ) { isDrainPumpInMixDrainOn = TRUE; +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_OPEN ); +#endif // Turn on the drain pump to drain the reservoirs in open loop mode setDrainPumpTargetRPM( DRAIN_PUMP_RPM_IN_MIX_DRAIN ); @@ -1235,8 +1314,15 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { +#ifndef V_2_SYSTEM + // Done with draining reservoir 1 + setValveState( VRD1, VALVE_STATE_CLOSED ); // Set the drain valve to reservoir 2 + setValveState( VRD2, VALVE_STATE_OPEN ); +#else + // Set the drain valve to reservoir 2 setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); +#endif rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; stateTimer = getMSTimerCount(); @@ -1245,7 +1331,7 @@ else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevHeatDisinfectState = state; - state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } } @@ -1277,7 +1363,13 @@ // Set the valves to fill up R1 and overflow to R2 setValveState( VPI, VALVE_STATE_OPEN ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + // Done with draining reservoir 2 + setValveState( VRD2, VALVE_STATE_CLOSED ); +#else setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); +#endif setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); @@ -1295,7 +1387,7 @@ else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevHeatDisinfectState = state; - state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } return state; @@ -1328,7 +1420,11 @@ // Set the valves to rinse R2 to R1 and drain R1 setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_R1_C_TO_NC ); +#else setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); +#endif setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); @@ -1377,6 +1473,9 @@ { // Done with draining R1 signalDrainPumpHardStop(); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_CLOSED ); +#endif } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -1401,10 +1500,18 @@ // De-energize all the valves and set the VDr to drain R2 setValveState( VPI, VALVE_STATE_CLOSED ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); +#else setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); +#endif setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); +#ifndef V_2_SYSTEM + setValveState( VRD2, VALVE_STATE_OPEN ); +#else setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); +#endif setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); @@ -1515,7 +1622,11 @@ { // The fluid is hot so this is a mix drain. Set the VPd to direct the cold inlet fluid to drain setValveState( VPI, VALVE_STATE_OPEN ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); +#else setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); +#endif targetRPM = DRAIN_PUMP_RPM_IN_MIX_DRAIN; cancellationMode = CANCELLATION_MODE_HOT; @@ -1540,8 +1651,13 @@ if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { +#ifndef V_2_SYSTEM // Set the drain valve to reservoir 1 + setValveState( VRD1, VALVE_STATE_OPEN ); +#else + // Set the drain valve to reservoir 1 setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); +#endif } } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) @@ -1590,6 +1706,45 @@ /*********************************************************************//** * @brief + * The resetActuators function sets all the actuators to reset and + * de-energized state. + * @details Inputs: none + * @details Outputs: none + * @return none + *************************************************************************/ +static void resetActuators( void ) +{ + // UV reactors will not be used in the heat disinfection since their operating temperature + // range is below 85C and they might be damaged by the high temperature. + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + + // De-energize all the valves + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); +#else + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); +#endif + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + + //TODO add the composition pumps + signalROPumpHardStop(); + signalDrainPumpHardStop(); + stopPrimaryHeater(); + stopTrimmerHeater(); +} + +/*********************************************************************//** + * @brief * The failHeatDisinfect function sets the alarm that failed the heat * disinfect mode. * @details Inputs: alarm, prevHeatDisinfectState @@ -1752,7 +1907,7 @@ status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; } } - else if ( isPartialDisinfectInProgress != TRUE && ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) + else if ( ( isPartialDisinfectInProgress != TRUE ) && ( ThdTemp > HEAT_DISINFECT_START_TEMPERATURE_C ) ) { // The temperature of the coldest spot is in range to start the disinfect timer heatDisinfectTimer = getMSTimerCount(); Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r24fd1893101af40cc6736aacaa20382875c80bf1 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 24fd1893101af40cc6736aacaa20382875c80bf1) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -97,7 +97,12 @@ // set initial actuator states setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); +#else setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); +#endif setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); @@ -181,7 +186,11 @@ flushFilterRequest = FALSE; filterFlushStartTime = getMSTimerCount(); setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VPD, VALVE_STATE_OPEN ); // TODO: VPD drain state is closed for V3 +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); +#else + setValveState( VPD, VALVE_STATE_OPEN ); // TODO: VPD drain state is closed for V3 +#endif state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; } else if ( TRUE == pendingStartDGRequest ) @@ -246,7 +255,11 @@ if ( TRUE == endSampleWaterRequest ) { setValveState( VPI, VALVE_STATE_CLOSED ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); +#else setValveState( VPD, VALVE_STATE_CLOSED ); +#endif state = DG_STANDBY_MODE_STATE_IDLE; } @@ -269,7 +282,11 @@ if ( ( TRUE == stopSampleWaterRequest ) || ( TRUE == didTimeout( waterSampleStartTime, MAX_WATER_SAMPLE_TIME_MS ) ) ) { setValveState( VSP, VALVE_STATE_CLOSED ); +#ifndef V_2_SYSTEM + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); +#else setValveState( VPD, VALVE_STATE_OPEN ); // TODO: VPD drain state is closed for V3 +#endif state = DG_STANDBY_MODE_STATE_FLUSH_FILTER_IDLE; } Index: firmware/App/Services/AlarmMgmt.h =================================================================== diff -u -r3eb7c2e62c727be195cd937d49957db9d4ba83b4 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 3eb7c2e62c727be195cd937d49957db9d4ba83b4) +++ firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -33,17 +33,6 @@ #include "AlarmDefs.h" -/// Alarm data types list. -typedef enum Alarm_Data_Types -{ - ALARM_DATA_TYPE_NONE = 0, ///< No data given - ALARM_DATA_TYPE_U32 = 1, ///< Alarm data is unsigned 32-bit integer type - ALARM_DATA_TYPE_S32 = 2, ///< Alarm data is signed 32-bit integer type - ALARM_DATA_TYPE_F32 = 3, ///< Alarm data is 32-bit floating point type - ALARM_DATA_TYPE_BOOL = 4, ///< Alarm data is 32-bit boolean type - NUM_OF_ALARM_DATA_TYPES ///< Total number of alarm data types -} ALARM_DATA_TYPES_T; - #pragma pack(push,4) /// Record structure for unsigned integer alarm data. typedef struct @@ -169,10 +158,13 @@ SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, SW_FAULT_ID_STANDBY_MODE_INVALID_EXEC_STATE, SW_FAULT_ID_RECIRC_MODE_INVALID_EXEC_STATE, - SW_FAULT_ID_DRAIN_MODE_INVALID_EXEC_STATE, // 80 - SW_FAULT_ID_FILL_MODE_INVALID_EXEC_STATE, + SW_FAULT_ID_DRAIN_MODE_INVALID_EXEC_STATE, + SW_FAULT_ID_FILL_MODE_INVALID_EXEC_STATE, // 80 SW_FAULT_ID_PRESSURE_INVALID_EXEC_STATE, SW_FAULT_ID_INVALID_NVDATAMGMT_EXEC_CAL_STATE, + SW_FAULT_ID_INVALID_VOLTAGE_MONITOR_STATE, + SW_FAULT_ID_INVALID_MONITORED_VOLTAGE_ID, + SW_FAULT_ID_INVALID_LOAD_CELL_ID, // 85 NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -re86af65442a36724461317980814f0868bd8c995 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision e86af65442a36724461317980814f0868bd8c995) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -129,23 +129,31 @@ { case DG_RESERVOIR_1: activeReservoir.data = (U32)resID; - cmdResponse.rejected = FALSE; - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + cmdResponse.rejected = FALSE; + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); +#ifndef V_2_SYSTEM + setValveState( VRD1, VALVE_STATE_OPEN ); +#else setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - break; - - case DG_RESERVOIR_2: +#endif + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + break; + + case DG_RESERVOIR_2: activeReservoir.data = (U32)resID; - cmdResponse.rejected = FALSE; - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + cmdResponse.rejected = FALSE; + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); +#ifndef V_2_SYSTEM + setValveState( VRD2, VALVE_STATE_OPEN ); +#else setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); - setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); - break; - - default: +#endif + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + break; + + default: // invalid reservoir given - cmd will be NAK'd w/ false result. cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; break; @@ -466,21 +474,47 @@ if ( hasTimeOut || hasTargetReached ) { result = TRUE; + // Reset for next drain reservoirLowestWeight[ reservoirId ] = MAX_RESERVOIR_WEIGHT; - - if ( tareLoadCellRequest ) - { - tareLoadCellRequest = FALSE; - tareLoadCell( associatedLoadCell[ reservoirId ] ); - tareLoadCell( redundantLoadCell[ reservoirId ] ); - } } return result; } /*********************************************************************//** * @brief + * The tareLoadCellsAtEmpty function tares the load cells for the given + * reservoir when empty and tare request is pending. + * @details Inputs: tareLoadCellRequest + * @details Outputs: tareLoadCellRequest + * @param reservoirId ID of reservoir to tare + * @return none + *************************************************************************/ +void tareLoadCellsAtEmpty( DG_RESERVOIR_ID_T reservoirId ) +{ + if ( TRUE == tareLoadCellRequest ) + { + tareLoadCellRequest = FALSE; + tareLoadCell( associatedLoadCell[ reservoirId ] ); + tareLoadCell( redundantLoadCell[ reservoirId ] ); + } +} + +/*********************************************************************//** + * @brief + * The isReservoirTarePending function determines whether a reservoir tare + * request is currently pending. + * @details Inputs: tareLoadCellRequest + * @details Outputs: none + * @return tareLoadCellRequest + *************************************************************************/ +BOOL isReservoirTarePending( void ) +{ + return tareLoadCellRequest; +} + +/*********************************************************************//** + * @brief * The getActiveReservoir function gets the active reservoir. * @details Inputs: activeReservoir * @details Outputs: none Index: firmware/App/Services/Reservoirs.h =================================================================== diff -u -re86af65442a36724461317980814f0868bd8c995 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Services/Reservoirs.h (.../Reservoirs.h) (revision e86af65442a36724461317980814f0868bd8c995) +++ firmware/App/Services/Reservoirs.h (.../Reservoirs.h) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -82,10 +82,12 @@ DG_RESERVOIR_ID_T getInactiveReservoir( void ); F32 getReservoirWeight( DG_RESERVOIR_ID_T reservoirId ); - -BOOL hasTargetFillVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId ); -BOOL hasTargetDrainVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId , U32 timeout ); +BOOL hasTargetFillVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId ); +BOOL hasTargetDrainVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId, U32 timeout ); +void tareLoadCellsAtEmpty( DG_RESERVOIR_ID_T reservoirId ); +BOOL isReservoirTarePending( void ); + BOOL testSetDGActiveReservoirOverride( DG_RESERVOIR_ID_T value ); BOOL testResetDGActiveReservoirOverride( void ); BOOL testSetReservoirFillVolumeMlOverride( U32 value ); Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r3eb7c2e62c727be195cd937d49957db9d4ba83b4 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 3eb7c2e62c727be195cd937d49957db9d4ba83b4) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -1040,10 +1040,6 @@ handleStartStopTrimmerHeaterCmd( message ); break; - case MSG_ID_DG_TESTER_LOGIN_REQUEST: - handleTesterLogInRequest( message ); - break; - case MSG_ID_DG_START_STOP_FLUSH: handleStartStopDGFlush( message ); break; @@ -1052,6 +1048,14 @@ handleStartStopDGHeatDisinfect( message ); break; + case MSG_ID_UI_DG_SET_RTC_REQUEST: + handleUIClockSyncRequest( message ); + break; + + case MSG_ID_DG_TESTER_LOGIN_REQUEST: + handleTesterLogInRequest( message ); + break; + default: // unrecognized message ID received - ok, ignore - may be a test message handled below break; @@ -1154,6 +1158,14 @@ handleTestDGAccelBroadcastIntervalOverrideRequest( message ); break; + case MSG_ID_DG_MONITORED_VOLTAGES_SEND_INTERVAL_OVERRIDE: + handleTestMonitoredVoltagesSendIntervalOverrideRequest( message ); + break; + + case MSG_ID_DG_MONITORED_VOLTAGES_OVERRIDE: + handleTestMonitoredVoltageOverrideRequest( message ); + break; + case MSG_ID_DRAIN_PUMP_SET_DELTA_PRESSURE_OVERRIDE: handleSetDrainPumpDeltaPressureOverrideRequest( message ); break; Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r24fd1893101af40cc6736aacaa20382875c80bf1 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 24fd1893101af40cc6736aacaa20382875c80bf1) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -1021,6 +1021,34 @@ /*********************************************************************//** * @brief + * The broadcastVoltagesData function constructs a monitored voltages data msg to + * be broadcast and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: monitored voltages data msg constructed and queued. + * @param data Latest monitored voltage values. + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastVoltagesData( VOLTAGES_DATA_PAYLOAD_T data ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_DG_VOLTAGES_DATA; + msg.hdr.payloadLen = sizeof( VOLTAGES_DATA_PAYLOAD_T ); + + memcpy( payloadPtr, &data, sizeof( VOLTAGES_DATA_PAYLOAD_T ) ); + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); + + return result; +} + + /*********************************************************************//** + * @brief * The broadcastFlushData function sends out the flush mode data. * @details Inputs: none * @details Outputs: flush data msg constructed and queued @@ -1165,6 +1193,67 @@ /*********************************************************************//** * @brief + * The sendPOSTTestResult function constructs an DG POST test result message + * and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: DG POST test result msg constructed and queued. + * @param test ID of DG POST test + * @param passed TRUE if POST test passed, FALSE if not + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendPOSTTestResult( DG_POST_STATE_T test, BOOL passed ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + U32 testID = (U32)test; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_DG_POST_SINGLE_TEST_RESULT; + msg.hdr.payloadLen = sizeof( BOOL ) + sizeof( U32 ); + + memcpy( payloadPtr, &passed, sizeof( BOOL ) ); + payloadPtr += sizeof( BOOL ); + memcpy( payloadPtr, &testID, sizeof( U32) ); + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); + + return result; + +} + +/*********************************************************************//** + * @brief + * The sendPOSTFinalResult function constructs an DG POST final result message + * and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: DG POST final result msg constructed and queued. + * @param passed TRUE if DG POST passed, FALSE if not + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendPOSTFinalResult( BOOL passed ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_DG_POST_FINAL_TEST_RESULT; + msg.hdr.payloadLen = sizeof( BOOL ); + + memcpy( payloadPtr, &passed, sizeof( BOOL ) ); + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); + + return result; +} + +/*********************************************************************//** + * @brief * The sendCommandResponseMsg function constructs a command response to HD * and queues the msg for transmit on the appropriate CAN channel. * @details Inputs: none @@ -2195,6 +2284,70 @@ /*********************************************************************//** * @brief + * The handleTestMonitoredVoltagesSendIntervalOverrideRequest function handles a + * request to override the monitored DG voltages data publication interval. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestMonitoredVoltagesSendIntervalOverrideRequest( MESSAGE_T *message ) +{ + TEST_OVERRIDE_PAYLOAD_T payload; + BOOL result = FALSE; + + // Verify payload length + if ( sizeof(TEST_OVERRIDE_PAYLOAD_T) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof(TEST_OVERRIDE_PAYLOAD_T) ); + if ( FALSE == payload.reset ) + { + result = testSetVoltagesDataPublishIntervalOverride( payload.state.u32 ); + } + else + { + result = testResetVoltagesDataPublishIntervalOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestMonitoredVoltageOverrideRequest function handles a + * request to override the monitored DG voltage override. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestMonitoredVoltageOverrideRequest( MESSAGE_T *message ) +{ + TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + BOOL result = FALSE; + + // Verify payload length + if ( sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) ); + if ( FALSE == payload.reset ) + { + result = testSetLineLevelOverride( payload.index, payload.state.f32 ); + } + else + { + result = testResetLineLevelOverride( payload.index ); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief * The handleTestSetConductivityOverrideRequest function handles a * request to override a conductivity sensor's value * @details Inputs: none @@ -2809,6 +2962,51 @@ } /*********************************************************************//** + * @brief + * The handleUIClockSyncRequest function handles a UI clock sync message. + * @details Inputs: none + * @details Outputs: message handled, response constructed and queued for transmit. + * @param messagePtr pointer to the message to handle. + * @return none + *************************************************************************/ +void handleUIClockSyncRequest( MESSAGE_T *message ) +{ + BOOL result = FALSE; + U32 rejReason = REQUEST_REJECT_REASON_NONE; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + if ( message->hdr.payloadLen == sizeof( U32 ) ) + { + U32 epoch; + + memcpy( &epoch, message->payload, sizeof( U32 ) ); + result = setRTCEpoch( epoch ); + if ( FALSE == result ) + { + rejReason = REQUEST_REJECT_REASON_INVALID_DATE_OR_TIME; + } + } + else + { + rejReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } + + // Create a response message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_DG_UI_SET_RTC_RESPONSE; + msg.hdr.payloadLen = sizeof( BOOL ) + sizeof( U32 ); + memcpy( payloadPtr, &result, sizeof( BOOL ) ); + payloadPtr += sizeof( BOOL ); + memcpy( payloadPtr, &rejReason, sizeof( U32 ) ); + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_2_UI, ACK_REQUIRED ); + + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_UI, result ); +} + +/*********************************************************************//** * @brief * The handleSetDGCalibrationRecord function handles a request to set the DG * calibration data record. Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r3eb7c2e62c727be195cd937d49957db9d4ba83b4 -r99b0c8f1ff9f9319f68e5043cd8c007e317a05c0 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 3eb7c2e62c727be195cd937d49957db9d4ba83b4) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 99b0c8f1ff9f9319f68e5043cd8c007e317a05c0) @@ -32,6 +32,7 @@ #include "TemperatureSensors.h" #include "Thermistors.h" #include "UVReactors.h" +#include "Voltages.h" /** * @defgroup SystemCommMessages SystemCommMessages @@ -111,6 +112,9 @@ // MSG_ID_DG_FLUID_LEAK_STATE BOOL broadcastFluidLeakState( FLUID_LEAK_STATES_T state); +// MSG_ID_DG_VOLTAGES_DATA +BOOL broadcastVoltagesData( VOLTAGES_DATA_PAYLOAD_T data ); + // MSG_ID_DG_FLUSH_DATA BOOL broadcastFlushData( MODE_FLUSH_DATA_T *flushData ); @@ -171,6 +175,12 @@ // MSG_ID_DG_SEND_SCHEDULED_RUNS_RECORD BOOL sendDGScheduledRunsRecord( U32 payloadCurrNum, U32 payloadTotalNum, U32 length, U08* scheduledRcrdAddress ); +// MSG_ID_DG_POST_SINGLE_TEST_RESULT +BOOL sendPOSTTestResult( DG_POST_STATE_T test, BOOL passed ); + +// MSG_ID_DG_POST_FINAL_TEST_RESULT +BOOL sendPOSTFinalResult( BOOL passed ); + // *********** public test support message functions ********** #ifdef DEBUG_ENABLED @@ -254,6 +264,12 @@ // MSG_ID_DG_ACCEL_SEND_INTERVAL_OVERRIDE: void handleTestDGAccelBroadcastIntervalOverrideRequest( MESSAGE_T *message ); +// MSG_ID_DG_MONITORED_VOLTAGES_SEND_INTERVAL_OVERRIDE +void handleTestMonitoredVoltagesSendIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DG_MONITORED_VOLTAGES_OVERRIDE +void handleTestMonitoredVoltageOverrideRequest( MESSAGE_T *message ); + // MSG_ID_DG_START_STOP_INLET_UV_REACTOR void handleStartStopUVReactors( MESSAGE_T *message ); @@ -311,6 +327,9 @@ // MSG_ID_DG_START_STOP_HEAT_DISINFECT BOOL handleStartStopDGHeatDisinfect( MESSAGE_T *message ); +// MSG_ID_UI_DG_SET_RTC_REQUEST +void handleUIClockSyncRequest( MESSAGE_T *message ); + // MSG_ID_DG_SET_CALIBRATION_DATA void handleSetDGCalibrationRecord( MESSAGE_T *message );