Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r20244278848db264bc95062f4d8df907da93abe5 -r54abf84364e737dd350153d5fab7dd652f917ef4 --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 20244278848db264bc95062f4d8df907da93abe5) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 54abf84364e737dd350153d5fab7dd652f917ef4) @@ -1,20 +1,22 @@ /************************************************************************** * -* Copyright (c) 2020-2023 Diality Inc. - All Rights Reserved. +* Copyright (c) 2020-2024 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 ModeChemicalDisinfect.c * * @author (last) Dara Navaei -* @date (last) 02-Jun-2023 +* @date (last) 09-Sep-2024 * * @author (original) Sean * @date (original) 04-Apr-2020 * ***************************************************************************/ +#include // for memset() + #include "ConcentratePumps.h" #include "ConductivitySensors.h" #include "CPLD.h" @@ -60,6 +62,10 @@ // Flush drain path state defines #define FLUSH_DRAIN_WAIT_TIME_MS ( 60 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. +// Deprime acid line state defines +#define DEPRIME_ACID_LINE_TIMEOUT_MS ( 30 * MS_PER_SECOND ) ///< Deprime acid line timeout in milliseconds. +#define DEPRIME_ACID_LINE_ACID_CONC_PUMP_SPEED_MLPM 40.0F ///< Deprime acid line acid concentrate pump speed in mL/min. + // Flush circulation path state defines #define RO_PUMP_TARGET_FLUSH_FLOW_RATE_LPM 0.8F ///< RO pump target flow rate during flush/fill in L/min. #define MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. @@ -75,9 +81,10 @@ #define RSRVRS_FILL_UP_TIMEOUT_MS ( 8 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. #define RSRVRS_PARTIAL_FILL_UP_TIMEOUT_MS ( 7 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. #define RSRVRS_ALMOST_FULL_FILL_UP_TIMEOUT_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. It is assumed the reservoir is nearly full to begin. -#define RESERVOIR_FULL_VOLUME_CHANGE_LIMIT_ML 5.0F ///< The maximum difference between the short-term and long-term filtered reservoir volumes in ml that determines the reservoir is full. #define RESERVOIR_MINIMUM_FULL_VOLUME_ML 1850.0F ///< When filling the reservoir, the volume reading must be at least this value before checking for the volume to level off. -#define RSRVRS_FILL_TO_FULL_STABLE_TASK_INT ( ( 2 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in task intervals. +#define RSRVRS_STEADY_STATE_MAX_VOL_CHANGE_ML 5.0F ///< Reservoirs steady state maximum volume change in milliliters. +#define RSRVRS_FULL_STATUS_CHECK_TIME_INTERVAL_MS ( 1 * MS_PER_SECOND ) ///< Reservoirs full status check time interval in milliseconds. +#define RSRVRS_FILL_TO_FULL_STABLE_TASK_INT 4 ///< Reservoirs 1 & 2 full stable time in task intervals. // Prime acid line state defines #define PRIME_ACID_LINE_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Priming acid line timeout in milliseconds. @@ -87,15 +94,15 @@ #define RO_PUMP_PRIME_DISINECTANT_FLOW_RATE_LPM 0.8F ///< ROP flow rate for disinfectant prime #define MAX_RO_PUMP_PRIME_DISINFECTANT_PRESSURE_PSI 130.0F ///< ROP max pressure for disinfectant prime #define DISINFECTANT_MIX_RATIO_PRIME 19.0F ///< Disinfectant mixing ratio during prime, water/disinfectant. +#define PRIME_ACID_MINIMUM_PRIME_TIME_MS ( 60 * MS_PER_SECOND ) ///< Prime acid minimum prime time in milliseconds. // Stabilize disinfectant mixing state defines -#define MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS 2 ///< Number of allowed periods to check conductivity and temperature in disinfectant flush state +#define MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS 4 ///< Number of allowed periods to check conductivity and temperature in disinfectant flush state #define DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN 7.61F ///< Default concentrate pump speed for mixing disinfectant. #define DISINFECTANT_MIX_RATIO_FILL 65.67F ///< Disinfectant mixing ratio during fill, water/disinfectant. #define RO_PUMP_FILL_DISINECTANT_FLOW_RATE_LPM 0.4F ///< ROP flow rate for disinfectant prime #define MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI 130.0F ///< ROP max pressure for disinfectant fill -#define FLUSH_DISINFECTANT_INITIAL_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Initial time to wait for temperature and conductivity to reach target in disinfectant flush state in milliseconds. -#define FLUSH_DISINFECTANT_ADDITIONAL_WAIT_TIME_MS ( 60 * MS_PER_SECOND ) ///< Additional time to wait for temperature and conductivity to reach target in disinfectant flush state +#define FLUSH_DISINFECTANT_TIMEOUT_MS ( 30 * MS_PER_SECOND ) ///< Flush disinfectant temperature and conductivity to reach target in disinfectant flush state in milliseconds. // Parameters during disinfect defines #define CHEM_DISINFECT_TARGET_RO_FLOW_LPM 0.5F ///< Chemical disinfect target RO flow rate in L/min. @@ -109,7 +116,7 @@ // Initial disinfectant fill of R1 and R2 #define RSRVRS_FULL_VOL_ML 1850.0F ///< Reservoirs 1 & 2 full volume in mL. #define RSRVRS_LEAK_VOL_TIMEOUT_TASK_INT ( ( 30 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Time delay for declaring that reservoir is leaking due to volume depletion. -#define RSRVRS_MAX_LEAK_VOL_CHANGE_ML 100.0F; ///< Volume loss that is necessary to declare a reservoir leak. +#define RSRVRS_MAX_LEAK_VOL_CHANGE_ML 100.0F ///< Volume loss that is necessary to declare a reservoir leak. // Parameters controlling chemical disinfect #define TARGET_CHEM_DISINFECT_TIME_MS ( 12 * SEC_PER_MIN * MS_PER_SECOND ) ///< Expected chemical disinfect time in ms. @@ -130,17 +137,38 @@ #define MIN_DRP_VOLUME_CONTROL_RPM 350.0F ///< Minimum DRP RPM for volume control. The minimum value allowed by the pump driver is 300 RPM #define MAX_DRP_VOLUME_CONTROL_RPM 1500.0F ///< Maximum DRP RPM for volume control. The maximum recommended value is 2400 RPM +#define ACID_MOVING_AVG_NUM_OF_SAMPLES 30 ///< Acid moving average number of samples. +#define ACID_DATA_COLLECTION_TIME_MS ( 0.5F * MS_PER_SECOND ) ///< Acid data collection time in milliseconds. + /// Non-volatile write structure typedef struct { BOOL hasDisStatusBeenWrittenToNV; ///< Boolean flag to indicate whether the disinfect status been written to NV or not. } DISINFECT_NV_OPS_T; +/// Acid status data structure +typedef struct +{ + BOOL acidDataColHasTimerBeenSet; ///< Acid has data collection timer started boolean flag. + U32 acidDataColStartTimeMS; ///< Acid data collection start time in milliseconds. + F32 acidCondRunningSumUSPCM; ///< Acid conductivity running sum in uS/cm. + OVERRIDE_F32_T acidCondAvgUSPCM; ///< Acid conductivity average in uS/cm. + F32 acidCondSamplesUSPCM[ ACID_MOVING_AVG_NUM_OF_SAMPLES ]; ///< Acid conductivity samples array in uS/cm. + U32 acidCondSamplesNextIndex; ///< Acid conductivity sample next index number. +} ACID_DATA_STATUS_T; + +/// Reservoir full data structure +typedef struct +{ + F32 prevRsrvrVolumeML[ NUM_OF_DG_RESERVOIRS ]; ///< Previous reservoir volumes in milliliters. + U32 startTimeStampMS; ///< Start time stamp in milliseconds. + BOOL hasTimeStampBeenSet; ///< Boolean flag to indicate that the timer has been set or not. +} RSRVR_FULL_STATUS_T; + // ********** private data ********** static DG_CHEM_DISINFECT_STATE_T chemDisinfectState; ///< Currently active chemical disinfect state. static DG_CHEM_DISINFECT_STATE_T prevChemDisinfectState; ///< Previous active heat disinfect state before alarm. -static DG_CHEM_DISINFECT_UI_STATE_T chemDisinfectUIState; ///< Currently active chemical disinfect UI state. static U32 overallChemDisinfectTimer; ///< Chemical disinfect cycle total timer. static U32 stateTimer; ///< Chemical disinfect state timer to be used in different states. static U32 stateTrialCounter; ///< Chemical disinfect state trial counter to be used for retries in different states. @@ -158,7 +186,6 @@ static CANCELLATION_MODE_T cancellationMode; ///< Cancellation mode. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Chemical disinfect alarm to raise. static U32 flushCircWaitTime; ///< Variable time period in ms to wait in flush circulation state to check sensor values. -static U32 flushDisinfectantWaitTime; ///< Variable time period in ms to wait in disinfectant flush state to check sensor values. static U32 primeAcidSteadyStateCounter; ///< Prime acid steady state counter. static U32 rsrvrFillStableTimeCounter; ///< Task interval timer/counter for determining if reservoir has reached fill target. static U32 rsrvrFillToFullStableTimeCounter; ///< Task interval timer/counter for determining if reservoir is full. @@ -167,6 +194,10 @@ static F32 disinfectantMixRatio ; ///< Current disinfectant mixing ratio. static DISINFECT_NV_OPS_T disinfectNVOps; ///< Disinfect non-volatile memory operations. static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. +static U32 maxTemperatureOutOfRangeStartTimeMS; ///< Maximum temperature out of range start time in milliseconds. +static U32 maxCondOutOfRangeStartTimeMS; ///< Maximum conductivity out of range start time in milliseconds. +static ACID_DATA_STATUS_T acidDataStatus; ///< Acid data status. +static RSRVR_FULL_STATUS_T rsrvrFullStatus; ///< Reservoir full status. #ifndef _RELEASE_ /* Nelson Labs is in charge of testing the efficacy of the disinfects (heat and chem). The codes that contain the name Nelson are used to @@ -182,6 +213,7 @@ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDrainR1State( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDrainR2State( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushDrainState( void ); +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDeprimeAcidLine( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushCirculationState( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeDisinfectantState( void ); static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantFlushState( void ); @@ -204,6 +236,8 @@ static void publishChemicalDisinfectData( void ); static void monitorModeChemicalDisinfect( void ); static void writeDisinfectDataToNV( DG_USAGE_INFO_ITEMS_T info ); +static void processAcidConductivityData( void ); +static BOOL isAcidCondOutOfRange( void ); #ifndef _RELEASE_ static void setNelsonSupportConditions( void ); @@ -219,13 +253,15 @@ * rsrvr1Status, rsrvr2Status, overallChemDisinfectTimer, cancellationMode, * rsrvrFillToFullStableTimeCounter, primeAcidSteadyStateCounter, isRsrvrLeaking, * chemDisinfectReservoirTime, ischemDisinfectWarmupTargetReached, - * isChemDisinfectTempAboveTarget, chemDisinfectUIState, isRsrvrLeaking, + * isChemDisinfectTempAboveTarget, isRsrvrLeaking, * disinfectNVOps.hasDisStatusBeenWrittenToNV, rsrvrsVolMonitorCounter, * DisinfectCycleCounter, drpControlTimerCounter, dataPublishCounter, - * alarmDetectedPendingTrigger, flushCircWaitTime, flushDisinfectantWaitTime + * alarmDetectedPendingTrigger, flushCircWaitTime, acidDataStatus * primeAcidSteadyStateCounter, rsrvrFillStableTimeCounter, R1FullVolume, * rsrvrFillToFullStableTimeCounter, R2FullVolume, disinfectantMixRatio, - * haveDrainParamsBeenInit[ DG_RESERVOIR_1 ], haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] + * haveDrainParamsBeenInit[ DG_RESERVOIR_1 ], haveDrainParamsBeenInit[ DG_RESERVOIR_2 ], + * maxTemperatureOutOfRangeStartTimeMS, maxCondOutOfRangeStartTimeMS, + * rsrvrFullStatus * @return none *************************************************************************/ void initChemicalDisinfectMode( void ) @@ -234,7 +270,7 @@ for ( rsrvr = DG_RESERVOIR_1; rsrvr < NUM_OF_DG_RESERVOIRS; rsrvr++ ) { - haveDrainParamsBeenInit[ rsrvr ] = FALSE; + haveDrainParamsBeenInit[ rsrvr ] = FALSE; } chemDisinfectState = DG_CHEM_DISINFECT_STATE_START; @@ -253,7 +289,6 @@ chemDisinfectReservoirTime = 0; ischemDisinfectWarmupTargetReached = FALSE; isChemDisinfectTempAboveTarget = FALSE; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_NOT_RUNNING; disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; isRsrvrLeaking = FALSE; rsrvrsVolMonitorCounter = 0; @@ -262,21 +297,30 @@ dataPublishCounter = 0; alarmDetectedPendingTrigger = ALARM_ID_NO_ALARM; flushCircWaitTime = 0; - flushDisinfectantWaitTime = 0; rsrvrFillStableTimeCounter = 0; rsrvrFillToFullStableTimeCounter = 0; R1FullVolume = 0.0F; R2FullVolume = 0.0F; disinfectantMixRatio = 0.0F; + maxTemperatureOutOfRangeStartTimeMS = getMSTimerCount(); + maxCondOutOfRangeStartTimeMS = getMSTimerCount(); + acidDataStatus.acidDataColHasTimerBeenSet = FALSE; + acidDataStatus.acidCondAvgUSPCM.data = 0.0F; + acidDataStatus.acidCondAvgUSPCM.ovData = 0.0F; + acidDataStatus.acidCondAvgUSPCM.ovInitData = 0.0F; + acidDataStatus.acidCondAvgUSPCM.override = 0.0F; + acidDataStatus.acidDataColHasTimerBeenSet = getMSTimerCount(); + acidDataStatus.acidCondRunningSumUSPCM = 0.0F; + acidDataStatus.acidCondSamplesNextIndex = 0; + rsrvrFullStatus.hasTimeStampBeenSet = FALSE; + rsrvrFullStatus.startTimeStampMS = getMSTimerCount(); + memset( acidDataStatus.acidCondSamplesUSPCM, 0x0, sizeof( F32 ) * ACID_MOVING_AVG_NUM_OF_SAMPLES ); + memset( rsrvrFullStatus.prevRsrvrVolumeML, 0x0, sizeof( F32 ) * NUM_OF_DG_RESERVOIRS ); + #ifndef _RELEASE_ setNelsonSupportConditions(); #endif - - initPersistentAlarm( ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_OUT_OF_RANGE, DISINFECT_TEMP_OUT_OF_RANGE_TIMEOUT_MS, DISINFECT_TEMP_OUT_OF_RANGE_TIMEOUT_MS ); - initPersistentAlarm( ALARM_ID_DG_CHEM_DISINFECT_TARGET_COND_OUT_OF_RANGE, DISINFECT_COND_OUT_OF_RANGE_TIMEOUT_MS, DISINFECT_COND_OUT_OF_RANGE_TIMEOUT_MS ); - - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, PARK_CONC_PUMPS ); } /*********************************************************************//** @@ -319,6 +363,8 @@ *************************************************************************/ U32 execChemicalDisinfectMode( void ) { + processAcidConductivityData(); + // The inlet pressure shall be checked all the time as long as VPi is open checkInletWaterPressure(); @@ -350,6 +396,10 @@ chemDisinfectState = handleChemicalDisinfectFlushDrainState(); break; + case DG_CHEM_DISINFECT_STATE_DEPRIME_ACID_LINE: + chemDisinfectState = handleChemicalDisinfectDeprimeAcidLine(); + break; + case DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION: chemDisinfectState = handleChemicalDisinfectFlushCirculationState(); break; @@ -457,16 +507,13 @@ * @details Inputs: alarm, rsrvrFillStableTimeCounter, rsrvr1Status, * stateTimer * @details Outputs: alarm, rsrvrFillStableTimeCounter, rsrvr1Status, - * stateTimer, chemDisinfectUIState + * stateTimer * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectStartState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_START; - // Set the chemical disinfect state that is published on the UI - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT; - if ( FALSE == isAlarmActive( ALARM_ID_DG_CHEM_DISINFECT_INSERT_ACID ) ) { if ( ( STATE_CLOSED == getSwitchStatus( CONCENTRATE_CAP ) ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) @@ -499,7 +546,7 @@ * transition is finished within the time, it transitions to the next state, * otherwise, it transitions to basic cancellation path. * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, isThisLastDrain - * @details Outputs: rsrvr1Status, rsrvr2Status, chemDisinfectUIState + * @details Outputs: rsrvr1Status, rsrvr2Status * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDrainR1State( void ) @@ -531,6 +578,7 @@ } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { + setValveState( VRD1, VALVE_STATE_CLOSED ); prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } @@ -545,8 +593,7 @@ * transition is finished within the time, it transitions to the next * state, otherwise, it transitions to basic cancellation path. * @details Inputs: stateTimer, rsrvr2Status, isThisLastDrain - * @details Outputs: stateTimer, rsrvr2Status, stateTrialCounter, - * chemDisinfectUIState + * @details Outputs: stateTimer, rsrvr2Status, stateTrialCounter * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDrainR2State( void ) @@ -600,10 +647,8 @@ * period of time and then measures the temperature and conductivity of * water. If they are not within the range, it transitions to basic * cancellation path, otherwise it transitions to the next state. - * @details Inputs: stateTimer, stateTrialCounter, alarm, - * prevChemDisinfectState - * @details Outputs: stateTimer, stateTrialCounter, alarm, - * prevChemDisinfectState + * @details Inputs: stateTimer + * @details Outputs: stateTimer * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFlushDrainState( void ) @@ -621,7 +666,34 @@ startHeater( DG_PRIMARY_HEATER ); // The UV reactors will be on for the entire disinfect cycle turnOnUVReactor( OUTLET_UV_REACTOR ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, DEPRIME_ACID_LINE_ACID_CONC_PUMP_SPEED_MLPM ); + // Turn on the concentrate pumps + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DEPRIME_ACID_LINE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectDeprimeAcidLine function handles the chemical + * disinfect deprime acid line state. In this state the acid pump is run for + * a couple of seconds to remove the residual fluid from the acid line to + * prevent any leaks from the acid port. + * @details Inputs: stateTimer + * @details Outputs: stateTimer, flushCircWaitTime + * @return next state of the chemical disinfect state machine + *************************************************************************/ +static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDeprimeAcidLine( void ) +{ + DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DEPRIME_ACID_LINE; + + if ( TRUE == didTimeout( stateTimer, DEPRIME_ACID_LINE_TIMEOUT_MS ) ) + { + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, PARK_CONC_PUMPS ); flushCircWaitTime = FLUSH_CICRCULATION_INITIAL_WAIT_TIME_MS; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION; @@ -650,8 +722,15 @@ // Check if the flush circulation time has elapsed and the temperature sensors are not in range yet if ( TRUE == didTimeout( stateTimer, flushCircWaitTime ) ) { - F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); + F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); + F32 avgTemp = ( TPoTemp + TD2Temp ) / NUM_OF_TEMP_SENSORS_TO_AVG; + F32 cd2CondUSPCM = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); + F32 cpoCondUSPCM = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CPO_SENSOR ); + BOOL isTPoOut = FALSE; + BOOL isTD2Out = FALSE; + BOOL isCD2Out = FALSE; + BOOL isCPoOut = FALSE; #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_USING_TPO_FOR_PRIMARY_HEATER_CONTROL ) ) @@ -660,14 +739,6 @@ } #endif - F32 avgTemp = ( TPoTemp + TD2Temp ) / NUM_OF_TEMP_SENSORS_TO_AVG; - F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); - F32 cpoConductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CPO_SENSOR ); - BOOL isTPoOut = FALSE; - BOOL isTD2Out = FALSE; - BOOL isCD2Out = FALSE; - BOOL isCPoOut = FALSE; - #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_TEMPERATURE_SENSORS_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif @@ -676,13 +747,8 @@ isTD2Out = ( fabs( TD2Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C ? TRUE : FALSE ); } -#ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) != SW_CONFIG_ENABLE_VALUE ) -#endif - { - isCD2Out = ( cd2Conductivity > MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM ? TRUE : FALSE ); - isCPoOut = ( cpoConductivity > MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM ? TRUE : FALSE ); - } + isCD2Out = ( cd2CondUSPCM > MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM ? TRUE : FALSE ); + isCPoOut = ( cpoCondUSPCM > MAX_FLUSH_CIRC_CONDUCTIVITY_US_PER_CM ? TRUE : FALSE ); // Check if any of the temperature sensors are out of tolerance if( ( TRUE == isTPoOut ) || ( TRUE == isTD2Out ) || ( TRUE == isCD2Out ) || ( TRUE == isCPoOut ) ) @@ -695,17 +761,15 @@ flushCircWaitTime = FLUSH_CICRCULATION_ADDITIONAL_WAIT_TIME_MS; } else - { // State failed. Cancel chemical disinfect mode + { + alarmDetectedPendingTrigger = ALARM_ID_DG_CLEANING_MODE_COND_SENSORS_OUT_OF_RANGE; + + // State failed. Cancel chemical disinfect mode // determine which alarm it is, temperature or conductivity, one of them has to take precedence if ( ( TRUE == isTPoOut ) || ( TRUE == isTD2Out ) ) { alarmDetectedPendingTrigger = ALARM_ID_DG_CLEANING_MODE_TEMP_SENSORS_DIFF_OUT_OF_RANGE; } - else - { - alarmDetectedPendingTrigger = ALARM_ID_DG_CLEANING_MODE_COND_SENSORS_OUT_OF_RANGE; - } - prevChemDisinfectState = state; state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } @@ -719,6 +783,7 @@ disinfectantMixRatio = DISINFECTANT_MIX_RATIO_PRIME; primeAcidSteadyStateCounter = 0; + stateTrialCounter = 0; state = DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT; stateTimer = getMSTimerCount(); } @@ -737,49 +802,54 @@ * cancellation path. * @details Inputs: stateTimer, primeAcidSteadyStateCounter * @details Outputs: stateTimer, prevChemDisinfectState, - * primeAcidSteadyStateCounter, chemDisinfectUIState + * primeAcidSteadyStateCounter, maxTemperatureOutOfRangeStartTimeMS, + * maxCondOutOfRangeStartTimeMS, disinfectNVOps * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPrimeDisinfectantState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT; - F32 cd2Conductivity = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_MIX_WATER_AND_ACID; - + writeDisinfectDataToNV( USAGE_INFO_CHEM_DIS_START ); handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); + if ( TRUE == didTimeout( stateTimer, PRIME_ACID_MINIMUM_PRIME_TIME_MS ) ) + { #ifndef _RELEASE_ - if ( ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) != SW_CONFIG_ENABLE_VALUE ) && - ( nelsonSupport != NELSON_CHEM_DISINFECT ) ) + if ( nelsonSupport != NELSON_CHEM_DISINFECT ) #endif - { - if ( cd2Conductivity < MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM ) { - primeAcidSteadyStateCounter = 0; + if ( getF32OverrideValue( &acidDataStatus.acidCondAvgUSPCM ) < MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM ) + { + primeAcidSteadyStateCounter = 0; + } } + + // Check if the acid conductivity value has been above the threshold for the specified time period + if ( ( ++primeAcidSteadyStateCounter >= PRIME_ACID_STEADY_CONDUCTIVITY_TASK_INT ) || + ( TRUE == getTestConfigStatus( TEST_CONFIG_MIX_WITH_WATER ) ) ) + { + // Turn off the concentrate pump + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // Turn on the RO pump and concentrate pump to the disinfectant fill rates + setROPumpTargetFlowRateLPM( CHEM_DISINFECT_TARGET_RO_FLOW_LPM, MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + stateTrialCounter = 0; + disinfectantMixRatio = DISINFECTANT_MIX_RATIO_FILL; + stateTimer = getMSTimerCount(); + maxTemperatureOutOfRangeStartTimeMS = getMSTimerCount(); + maxCondOutOfRangeStartTimeMS = getMSTimerCount(); + disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; + state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; + } + else if ( TRUE == didTimeout( stateTimer, PRIME_ACID_LINE_TIMEOUT_MS ) ) + { + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_PRIME_ACID_LINE_TIME_OUT; + } } - // Check if the acid conductivity value has been above the threshold for the specified time period - if ( ( ++primeAcidSteadyStateCounter >= PRIME_ACID_STEADY_CONDUCTIVITY_TASK_INT ) || - ( TRUE == getTestConfigStatus( TEST_CONFIG_MIX_WITH_WATER ) ) ) - { - // Turn off the concentrate pump - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); - // Turn on the RO pump and concentrate pump to the disinfectant fill rates - setROPumpTargetFlowRateLPM( CHEM_DISINFECT_TARGET_RO_FLOW_LPM, MAX_RO_PUMP_FILL_DISINFECTANT_PRESSURE_PSI ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, DISINFECTANT_PUMP_FILL_SPEED_ML_PER_MIN ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); - disinfectantMixRatio = DISINFECTANT_MIX_RATIO_FILL; - flushDisinfectantWaitTime = FLUSH_DISINFECTANT_INITIAL_WAIT_TIME_MS; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; - } - if ( TRUE == didTimeout( stateTimer, PRIME_ACID_LINE_TIMEOUT_MS ) ) - { - prevChemDisinfectState = state; - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_PRIME_ACID_LINE_TIME_OUT; - } return state; } @@ -793,46 +863,36 @@ * within the specified range within the specified time, the function transitions * to another state. If the minimum conductivity and temperature are not * reached within the defined period of time, it transition to a cancellation path. - * @details Inputs: stateTimer, primeAcidSteadyStateCounter, - * temperature, conductivity - * @details Outputs: stateTimer, prevChemDisinfectState, chemDisinfectUIState, - * alarm + * @details Inputs: stateTimer, disinfectantMixRatio, stateTrialCounter + * @details Outputs: stateTimer, stateTrialCounter, rsrvr1Status, rsrvr2Status, + * chemDisinfectReservoirTime, rsrvrFillStableTimeCounter, isChemDisinfectTempAboveTarget, * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectantFlushState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_MIX_WATER_AND_ACID; - - writeDisinfectDataToNV( USAGE_INFO_CHEM_DIS_START ); handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); - if ( TRUE == didTimeout( stateTimer, flushDisinfectantWaitTime ) ) + if ( TRUE == didTimeout( stateTimer, FLUSH_DISINFECTANT_TIMEOUT_MS ) ) { - F32 cd2Cond = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); - BOOL isCD2OutOfRange = ( ( cd2Cond < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM || cd2Cond > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ) ? TRUE : FALSE ); + BOOL isCD2OutOfRange = isAcidCondOutOfRange(); -#ifndef _RELEASE_ - if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + if ( TRUE == getTestConfigStatus( TEST_CONFIG_MIX_WITH_WATER ) ) { isCD2OutOfRange = FALSE; } -#endif if ( TRUE == isCD2OutOfRange ) { - // The conditions have not been met - // Check if we have exceeded the number of trials. If not, try another time - if ( ++stateTrialCounter < MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS ) + stateTimer = getMSTimerCount(); + + if ( ++stateTrialCounter >= MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS ) { - stateTimer = getMSTimerCount(); - flushDisinfectantWaitTime = FLUSH_DISINFECTANT_ADDITIONAL_WAIT_TIME_MS; + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_COND_OUT_OF_RANGE; + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } - else - { - state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; - } } else { @@ -843,6 +903,7 @@ setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRD1, VALVE_STATE_CLOSED ); setValveState( VRD2, VALVE_STATE_CLOSED ); + turnOffUVReactor( OUTLET_UV_REACTOR ); rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; chemDisinfectReservoirTime = 0; @@ -867,15 +928,14 @@ * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status, * rsrvrsVolMonitorTimer * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * R1ChemDisinfectVol, R2ChemDisinfectVol, rsrvrsVolMonitorTimer + * R1ChemDisinfectVol, R2ChemDisinfectVol, rsrvrsVolMonitorTimer, + * chemDisinfectReservoirTime * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectFillWithDisinfectantState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; - handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); // First reservoir 1 must be full @@ -902,6 +962,7 @@ controlDRPByReservoirVolume( DG_RESERVOIR_2, TRUE ); //Initialize the PI controller for DRP isRsrvrLeaking = FALSE; ischemDisinfectWarmupTargetReached = FALSE; + chemDisinfectReservoirTime = 0; stateTimer = getMSTimerCount(); state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; } @@ -930,15 +991,13 @@ * transitions to the next state. * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * chemDisinfectUIState, prevChemDisinfectState + * prevChemDisinfectState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR1ToR2State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; - handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); chemicalDisinfectTimerUpdate(); @@ -987,8 +1046,10 @@ * within a certain period of time, it transitions to water cancellation. * If reservoir 2 is filled within the specified time, it * transitions to the next state. - * @details Inputs: stateTimer, rsrvr2Status - * @details Outputs: stateTimer, chemDisinfectUIState + * @details Inputs: stateTimer, rsrvr2Status, disinfectantMixRatio + * @details Outputs: stateTimer, isRsrvrLeaking, chemDisinfectReservoirTime, + * isChemDisinfectTempAboveTarget, ischemDisinfectWarmupTargetReached, + * prevChemDisinfectState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR1FillR2ToR1State( void ) @@ -1034,15 +1095,12 @@ * transitions to the next state. * @details Inputs: stateTimer, rsrvr1Status, rsrvr2Status * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, - * chemDisinfectUIState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectDisinfectR2ToR1State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE; - handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); chemicalDisinfectTimerUpdate(); @@ -1074,6 +1132,7 @@ setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); turnOffUVReactor( INLET_UV_REACTOR ); turnOffUVReactor( OUTLET_UV_REACTOR ); signalROPumpHardStop(); @@ -1087,10 +1146,9 @@ initDrainParameters( DG_RESERVOIR_2 ); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - isThisLastDrain = TRUE; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + isThisLastDrain = TRUE; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; #ifndef _RELEASE_ if ( NELSON_CHEM_DISINFECT == nelsonSupport ) @@ -1130,8 +1188,9 @@ * within a certain period of time, it transitions to water cancellation. * If reservoir 1 is filled within the specified time, it * transitions to the next state. - * @details Inputs: stateTimer, rsrvr1Status - * @details Outputs: stateTimer, chemDisinfectUIState + * @details Inputs: stateTimer, rsrvr1Status, disinfectantMixRatio + * @details Outputs: stateTimer, chemDisinfectReservoirTime, isChemDisinfectTempAboveTarget, + * ischemDisinfectWarmupTargetReached, isRsrvrLeaking, prevChemDisinfectState * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectPartialDrainR2FillR1ToR2State( void ) @@ -1174,15 +1233,14 @@ * chemical disinfect cancel mode basic path state. The state sets the state * to complete and raises an alarm. * @details Inputs: none - * @details Outputs: cancellationMode, chemDisinfectUIState + * @details Outputs: cancellationMode * @return next state of the heat disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeBasicPathState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_CANCEL_DISINFECT; - cancellationMode = CANCELLATION_MODE_BASIC; + cancellationMode = CANCELLATION_MODE_BASIC; failChemicalDisinfect(); @@ -1196,29 +1254,28 @@ * before the cancel basic path mode is entered. * @details Inputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer, - * chemDisinfectUIState + * haveDrainParamsBeenInit * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeWaterPathState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_CANCEL_DISINFECT; - if ( CANCELLATION_MODE_NONE == cancellationMode ) { // Stop all the actuators first then decide who should run next deenergizeActuators( NO_PARK_CONC_PUMPS ); - cancellationMode = CANCELLATION_MODE_WATER; - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; + haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; + cancellationMode = CANCELLATION_MODE_WATER; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + stateTimer = getMSTimerCount(); // The drain is set to start from reservoir 2 setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - - // Start the timer for drain timeout - stateTimer = getMSTimerCount(); } // If reservoir 2 is empty, set to drain reservoir 1 @@ -1268,15 +1325,13 @@ * disinfect complete state. The state stops chemical disinfect and * requests transition to mode standby. * @details Inputs: none - * @details Outputs: chemDisinfectUIState + * @details Outputs: none * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCompleteState( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_COMPLETE; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_COMPLETE; - #ifndef _RELEASE_ if ( nelsonSupport != NELSON_NONE ) { @@ -1302,14 +1357,16 @@ *************************************************************************/ static void failChemicalDisinfect( void ) { + // If a fault alarm is active go to mode fault otherwise for cleaning mode alarms, transition to standby + DG_OP_MODE_T nextOpMode = ( FALSE == isDGFaultAlarmActive() ? DG_MODE_STAN : DG_MODE_FAUL ); + // In the cleaning modes the alarms are triggered but the mode is not transitioned to fault automatically // so transition to fault mode is done here if ( alarmDetectedPendingTrigger != ALARM_ID_NO_ALARM ) { SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, prevChemDisinfectState ) } - - requestNewOperationMode( DG_MODE_STAN ); + requestNewOperationMode( nextOpMode ); } /*********************************************************************//** @@ -1380,7 +1437,7 @@ static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_ABOVE_TARGET; - BOOL isDrainComplete = hasTargetDrainToZeroBeenReached( r, drainSteadyStateTimeout ); + BOOL isDrainComplete = FALSE; // If the drain parameters of the reservoir is not initialized, initialize them if ( FALSE == haveDrainParamsBeenInit[ r ] ) @@ -1389,6 +1446,10 @@ haveDrainParamsBeenInit[ r ] = TRUE; } + // NOTE: the drain status should be checked once the reservoirs parameters are initialized. This is to make sure the + // the timers for stable drain time are initialized prior to using them again + isDrainComplete = hasTargetDrainToZeroBeenReached( r, drainSteadyStateTimeout ); + if ( TRUE == isDrainComplete ) { stateTimer = getMSTimerCount(); @@ -1421,42 +1482,64 @@ static DG_RESERVOIR_STATUS_T getRsrvrFillToFullStatus( DG_RESERVOIR_ID_T r, U32 timeout ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; - F32 currentVolume = 0.0F; - F32 filteredVolume = 0.0F; + F32 currentVolumeML = 0.0F; - if ( DG_RESERVOIR_1 == r ) + switch( r ) { - currentVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - filteredVolume = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + case DG_RESERVOIR_1: + currentVolumeML = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + break; + + case DG_RESERVOIR_2: + currentVolumeML = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, r ) + break; } - else if ( DG_RESERVOIR_2 == r ) - { - currentVolume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - filteredVolume = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_RESERVOIR_SELECTED, r ) - } // Check the volume of the reservoir against the long term filtered volume - if ( ( currentVolume > RESERVOIR_MINIMUM_FULL_VOLUME_ML ) && ( fabs( currentVolume - filteredVolume ) < RESERVOIR_FULL_VOLUME_CHANGE_LIMIT_ML ) ) + if ( currentVolumeML > RESERVOIR_MINIMUM_FULL_VOLUME_ML ) { - if ( ++rsrvrFillToFullStableTimeCounter >= RSRVRS_FILL_TO_FULL_STABLE_TASK_INT ) + if ( FALSE == rsrvrFullStatus.hasTimeStampBeenSet ) { - status = DG_RESERVOIR_REACHED_TARGET; - rsrvrFillToFullStableTimeCounter = 0; + rsrvrFullStatus.startTimeStampMS = getMSTimerCount(); + rsrvrFullStatus.hasTimeStampBeenSet = TRUE; + } + else if ( TRUE == didTimeout( rsrvrFullStatus.startTimeStampMS, RSRVRS_FULL_STATUS_CHECK_TIME_INTERVAL_MS ) ) + { + if ( fabs( currentVolumeML - rsrvrFullStatus.prevRsrvrVolumeML[ r ] ) < RSRVRS_STEADY_STATE_MAX_VOL_CHANGE_ML ) + { + rsrvrFillToFullStableTimeCounter++; + } + else + { + rsrvrFillToFullStableTimeCounter = 0; + } + + rsrvrFullStatus.prevRsrvrVolumeML[ r ] = currentVolumeML; + rsrvrFullStatus.hasTimeStampBeenSet = FALSE; + } + + if ( rsrvrFillToFullStableTimeCounter > RSRVRS_FILL_TO_FULL_STABLE_TASK_INT ) + { + status = DG_RESERVOIR_REACHED_TARGET; + rsrvrFillToFullStableTimeCounter = 0; + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + rsrvrFullStatus.prevRsrvrVolumeML[ r ] = 0.0F; + // Record the full volumes if ( DG_RESERVOIR_1 == r ) { - R1FullVolume = currentVolume; + R1FullVolume = currentVolumeML; } - else if ( DG_RESERVOIR_2 == r ) + else { - R2FullVolume = currentVolume; + // If the reservoir is neither 1 or 2, the current volume will be updated so the code will never get here + R2FullVolume = currentVolumeML; } - // Set the state timer in case it needs to be used for another timeout check - stateTimer = getMSTimerCount(); } } else if ( TRUE == didTimeout( stateTimer, timeout ) ) @@ -1580,8 +1663,7 @@ } else if ( TdiTemp < CHEM_DISINFECT_MINIMUM_TEMPERATURE_C ) { - isChemDisinfectTempAboveTarget = FALSE; - ischemDisinfectWarmupTargetReached = FALSE; + isChemDisinfectTempAboveTarget = FALSE; } if ( TRUE == isChemDisinfectTempAboveTarget ) @@ -1609,6 +1691,7 @@ data.overallElapsedTime = calcTimeSince( overallChemDisinfectTimer ); data.stateElapsedTime = calcTimeSince( stateTimer ); data.cancellationMode = (U32)cancellationMode; + data.acidAvgCondUSPCM = getF32OverrideValue( &acidDataStatus.acidCondAvgUSPCM ); //If the mode is in the actual chemical disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion if ( chemDisinfectState > DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN ) @@ -1625,8 +1708,6 @@ data.R2FillLevel = 0.0F; } - data.chemDisinfectUIState = chemDisinfectUIState; - // General data publish channel broadcastData( MSG_ID_DG_CHEM_DISINFECT_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( MODE_CHEMICAL_DISINFECT_DATA_T ) ); @@ -1648,28 +1729,31 @@ * chemical disinfect is cancelled. If the conductivity of the diluted disinfectant * mix is not within the specified limits, an alarm is set and disinfect is * cancelled. - * @details Inputs: chemDisinfectState, reservoir volumes, reservoir volume monitor timer, - * inlet water temperature, pressure, and conductivity, disinfectant conductivity. - * @details Outputs: prevChemDisinfectState, chemDisinfectState, cancel state, - * alarmDetectedPendingTrigger + * @details Inputs: chemDisinfectState, R1FullVolume, isRsrvrLeaking, + * rsrvrsVolMonitorCounter, maxTemperatureOutOfRangeStartTimeMS, + * maxCondOutOfRangeStartTimeMS + * @details Outputs: chemDisinfectState, isRsrvrLeaking, rsrvrsVolMonitorCounter, + * alarmDetectedPendingTrigger, prevChemDisinfectState, + * maxTemperatureOutOfRangeStartTimeMS, maxCondOutOfRangeStartTimeMS * @return: none *************************************************************************/ static void monitorModeChemicalDisinfect( void ) { + BOOL signalMaxTempOrMaxCondIsOutOfRange = FALSE; + // Reservoir leak detection. if ( ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) || ( DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 == chemDisinfectState ) ) { - BOOL isRsrvrVolumeOutOfRange = FALSE; - //isRsrvrLeaking = FALSE; + // Since the reservoir level is only checked if the mode is in R1 to R2 or it is in R2 to R1, it is assumed that the default is R2 to R1 so VectorCAST + // can cover the cases + F32 loadCellValueML = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + BOOL isRsrvrVolumeOutOfRange = ( fabs( loadCellValueML - R2FullVolume ) > RSRVRS_MAX_LEAK_VOL_CHANGE_ML ? TRUE : FALSE ); if ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) { - isRsrvrVolumeOutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1FullVolume ) > RSRVRS_MAX_LEAK_VOL_CHANGE_ML; + loadCellValueML = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + isRsrvrVolumeOutOfRange = ( fabs( loadCellValueML - R1FullVolume ) > RSRVRS_MAX_LEAK_VOL_CHANGE_ML ? TRUE : FALSE ); } - else - { - isRsrvrVolumeOutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) - R2FullVolume ) > RSRVRS_MAX_LEAK_VOL_CHANGE_ML; - } isRsrvrLeaking = ( TRUE == isRsrvrLeaking ? isRsrvrLeaking : FALSE ); @@ -1700,48 +1784,55 @@ if ( ( ( STATE_CLOSED == getSwitchStatus( CONCENTRATE_CAP ) || ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) ) ) && ( chemDisinfectState != DG_CHEM_DISINFECT_STATE_START ) ) { - prevChemDisinfectState = chemDisinfectState; - chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; - - if ( STATE_CLOSED == getSwitchStatus( CONCENTRATE_CAP ) ) + if ( ( chemDisinfectState != DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH ) && ( chemDisinfectState != DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH ) ) { - alarmDetectedPendingTrigger = ALARM_ID_DG_CONCENTRATE_CAP_NOT_IN_PROPER_POSITION; + prevChemDisinfectState = chemDisinfectState; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + + if ( STATE_CLOSED == getSwitchStatus( CONCENTRATE_CAP ) ) + { + alarmDetectedPendingTrigger = ALARM_ID_DG_CONCENTRATE_CAP_NOT_IN_PROPER_POSITION; + } + if ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) + { + alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_CAP_NOT_IN_PROPER_POSITION; + } } - if ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) - { - alarmDetectedPendingTrigger = ALARM_ID_DG_DIALYSATE_CAP_NOT_IN_PROPER_POSITION; - } } } // Check the temperature and conductivity of the diluted disinfectant - if ( ( chemDisinfectState >= DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH ) && ( chemDisinfectState <= DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R2_FILL_R1_TO_R2 ) ) + if ( ( chemDisinfectState >= DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT ) && ( chemDisinfectState <= DG_CHEM_DISINFECT_STATE_PARTIAL_DRAIN_R2_FILL_R1_TO_R2 ) ) { // Disinfect conditions check - F32 cd2CondUSCM = getConductivityValue( (U32)CONDUCTIVITYSENSORS_CD2_SENSOR ); F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - BOOL isCD2OutofRange = ( ( cd2CondUSCM < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM ) || ( cd2CondUSCM > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ) ? TRUE : FALSE ); - BOOL isTPoOutofRange = ( TPoTemp > MAX_DISINFECT_TPO_TEMPERATURE_C ); + BOOL isCD2OutofRange = isAcidCondOutOfRange(); + BOOL isTPoOutofRange = ( TPoTemp > MAX_DISINFECT_TPO_TEMPERATURE_C ? TRUE : FALSE ); -#ifndef _RELEASE_ - if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DISINFECT_CONDUCTIVITY_CHECK ) ) + maxTemperatureOutOfRangeStartTimeMS = ( TRUE == isTPoOutofRange ? maxTemperatureOutOfRangeStartTimeMS : getMSTimerCount() ); + maxCondOutOfRangeStartTimeMS = ( TRUE == isCD2OutofRange ? maxCondOutOfRangeStartTimeMS : getMSTimerCount() ); + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_MIX_WITH_WATER ) ) { - isCD2OutofRange = FALSE; + // If the mix with water is enabled, keep reseting the time + maxCondOutOfRangeStartTimeMS = getMSTimerCount(); } -#endif - checkPersistentAlarm( ALARM_ID_DG_CHEM_DISINFECT_TARGET_COND_OUT_OF_RANGE, isCD2OutofRange, cd2CondUSCM, MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ); - checkPersistentAlarm( ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_OUT_OF_RANGE, isTPoOutofRange, TPoTemp, MAX_DISINFECT_TPO_TEMPERATURE_C ); + if ( TRUE == didTimeout( maxTemperatureOutOfRangeStartTimeMS, DISINFECT_TEMP_OUT_OF_RANGE_TIMEOUT_MS ) ) + { + signalMaxTempOrMaxCondIsOutOfRange = TRUE; + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_OUT_OF_RANGE; + } - if ( ( TRUE == isAlarmActive( ALARM_ID_DG_CHEM_DISINFECT_TARGET_COND_OUT_OF_RANGE ) ) || - ( TRUE == isAlarmActive( ALARM_ID_DG_CHEM_DISINFECT_TARGET_TEMP_OUT_OF_RANGE ) ) ) + if ( ( TRUE == didTimeout( maxCondOutOfRangeStartTimeMS, DISINFECT_COND_OUT_OF_RANGE_TIMEOUT_MS ) ) && + ( getTestConfigStatus( TEST_CONFIG_MIX_WITH_WATER ) != TRUE ) ) { - prevChemDisinfectState = chemDisinfectState; - chemDisinfectState = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + signalMaxTempOrMaxCondIsOutOfRange = TRUE; + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_COND_OUT_OF_RANGE; } } - if ( ( TRUE == isDGFaultAlarmActive() ) || ( TRUE == isAnyCleaningModeInletWaterConditionActive() ) ) + if ( ( TRUE == isDGFaultAlarmActive() ) || ( TRUE == isAnyCleaningModeInletWaterConditionActive() ) || ( TRUE == signalMaxTempOrMaxCondIsOutOfRange ) ) { if ( chemDisinfectState != DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH ) { @@ -1769,6 +1860,102 @@ } } +/*********************************************************************//** + * @brief + * The processAcidConductivityData function processes the moving average + * of the acid conductivity values. + * @details Inputs: acidDataStatus + * @details Outputs: acidDataStatus + * @return: none + *************************************************************************/ +static void processAcidConductivityData( void ) +{ + if ( FALSE == acidDataStatus.acidDataColHasTimerBeenSet ) + { + acidDataStatus.acidDataColStartTimeMS = getMSTimerCount(); + acidDataStatus.acidDataColHasTimerBeenSet = TRUE; + } + else if ( TRUE == didTimeout( acidDataStatus.acidDataColStartTimeMS, ACID_DATA_COLLECTION_TIME_MS ) ) + { + F32 acidCondUSPCM = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); + U32 currentIndex = acidDataStatus.acidCondSamplesNextIndex; + F32 prevSampleToRemoveUSPCM = acidDataStatus.acidCondSamplesUSPCM[ currentIndex ]; + + acidDataStatus.acidDataColStartTimeMS = getMSTimerCount(); + acidDataStatus.acidDataColHasTimerBeenSet = TRUE; + acidDataStatus.acidCondSamplesUSPCM[ currentIndex ] = acidCondUSPCM; + acidDataStatus.acidCondRunningSumUSPCM = acidDataStatus.acidCondRunningSumUSPCM + acidCondUSPCM - prevSampleToRemoveUSPCM; + acidDataStatus.acidCondSamplesNextIndex = INC_WRAP( acidDataStatus.acidCondSamplesNextIndex, 0, ACID_MOVING_AVG_NUM_OF_SAMPLES - 1 ); + acidDataStatus.acidCondAvgUSPCM.data = acidDataStatus.acidCondRunningSumUSPCM / (F32)ACID_MOVING_AVG_NUM_OF_SAMPLES; + } +} + +/*********************************************************************//** + * @brief + * The isAcidCondOutOfRange function checks whether the acid conductivity + * is out of range or not. + * @details Inputs: acidDataStatus + * @details Outputs: acidDataStatus + * @return: TRUE is acid conductivity is out of range, otherwise, FALSE + *************************************************************************/ +static BOOL isAcidCondOutOfRange( void ) +{ + F32 acidCondUSPCM = getF32OverrideValue( &acidDataStatus.acidCondAvgUSPCM ); + BOOL isCD2OutOfRange = ( ( acidCondUSPCM < MIN_DISINFECT_CONDUCTIVITY_US_PER_CM || acidCondUSPCM > MAX_DISINFECT_CONDUCTIVITY_US_PER_CM ) ? TRUE : FALSE ); + + return isCD2OutOfRange; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetChemDisinfectionCD2AvgOverride function overrides the + * CD2 acid value in chemical disinfect. + * @details Inputs: none + * @details Outputs: acidDataStatus.acidCondAvgUSPCM + * @param value override concentrate pump data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetChemDisinfectionCD2AvgOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + acidDataStatus.acidCondAvgUSPCM.ovData = value; + acidDataStatus.acidCondAvgUSPCM.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetConcentratePumpDataPublishIntervalOverride function resets the + * override of the CD2 acid value in chemical disinfect. + * @details Inputs: none + * @details Outputs: acidDataStatus.acidCondAvgUSPCM + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetChemDisinfectionCD2AvgOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + acidDataStatus.acidCondAvgUSPCM.override = OVERRIDE_RESET; + acidDataStatus.acidCondAvgUSPCM.ovData = acidDataStatus.acidCondAvgUSPCM.ovInitData; + } + + return result; +} /**@}*/ // ********** Nelson Support Functions **********