Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r213c09d4f8c37e562611df2539f73ffaea022f83 -r54abf84364e737dd350153d5fab7dd652f917ef4 --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 213c09d4f8c37e562611df2539f73ffaea022f83) +++ 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) 28-Jul-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" @@ -80,7 +82,9 @@ #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_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. @@ -112,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. @@ -148,11 +152,19 @@ 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. - F32 acidCondAvgUSPCM; ///< Acid conductivity average 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. @@ -185,6 +197,7 @@ 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 @@ -248,6 +261,7 @@ * rsrvrFillToFullStableTimeCounter, R2FullVolume, disinfectantMixRatio, * haveDrainParamsBeenInit[ DG_RESERVOIR_1 ], haveDrainParamsBeenInit[ DG_RESERVOIR_2 ], * maxTemperatureOutOfRangeStartTimeMS, maxCondOutOfRangeStartTimeMS, + * rsrvrFullStatus * @return none *************************************************************************/ void initChemicalDisinfectMode( void ) @@ -291,12 +305,18 @@ maxTemperatureOutOfRangeStartTimeMS = getMSTimerCount(); maxCondOutOfRangeStartTimeMS = getMSTimerCount(); acidDataStatus.acidDataColHasTimerBeenSet = FALSE; - acidDataStatus.acidCondAvgUSPCM = 0.0F; + 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(); @@ -782,13 +802,15 @@ * cancellation path. * @details Inputs: stateTimer, primeAcidSteadyStateCounter * @details Outputs: stateTimer, prevChemDisinfectState, - * primeAcidSteadyStateCounter + * 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; + 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 ) ) @@ -797,7 +819,7 @@ if ( nelsonSupport != NELSON_CHEM_DISINFECT ) #endif { - if ( acidDataStatus.acidCondAvgUSPCM < MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM ) + if ( getF32OverrideValue( &acidDataStatus.acidCondAvgUSPCM ) < MIN_PRIME_ACID_CONDUCTIVITY_US_PER_CM ) { primeAcidSteadyStateCounter = 0; } @@ -813,10 +835,13 @@ 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(); - state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH; + 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 ) ) { @@ -841,17 +866,15 @@ * @details Inputs: stateTimer, disinfectantMixRatio, stateTrialCounter * @details Outputs: stateTimer, stateTrialCounter, rsrvr1Status, rsrvr2Status, * chemDisinfectReservoirTime, rsrvrFillStableTimeCounter, isChemDisinfectTempAboveTarget, - * disinfectNVOps * @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; - writeDisinfectDataToNV( USAGE_INFO_CHEM_DIS_START ); handleDisinfectantMixing( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER, disinfectantMixRatio ); - if ( TRUE == didTimeout( stateTimer, ( ( stateTrialCounter + 1 ) * FLUSH_DISINFECTANT_TIMEOUT_MS ) ) ) + if ( TRUE == didTimeout( stateTimer, FLUSH_DISINFECTANT_TIMEOUT_MS ) ) { BOOL isCD2OutOfRange = isAcidCondOutOfRange(); @@ -862,10 +885,13 @@ if ( TRUE == isCD2OutOfRange ) { + stateTimer = getMSTimerCount(); + if ( ++stateTrialCounter >= MAX_ALLOWED_DISINFECTANT_FLUSH_PERIODS ) { - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; + alarmDetectedPendingTrigger = ALARM_ID_DG_CHEM_DISINFECT_TARGET_COND_OUT_OF_RANGE; + prevChemDisinfectState = state; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } } else @@ -878,14 +904,13 @@ 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; - rsrvrFillStableTimeCounter = 0; - isChemDisinfectTempAboveTarget = FALSE; - stateTimer = getMSTimerCount(); - disinfectNVOps.hasDisStatusBeenWrittenToNV = FALSE; - state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; + rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; + rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + chemDisinfectReservoirTime = 0; + rsrvrFillStableTimeCounter = 0; + isChemDisinfectTempAboveTarget = FALSE; + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT; } } @@ -903,7 +928,8 @@ * @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 ) @@ -936,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; } @@ -1105,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(); @@ -1225,7 +1253,8 @@ * chemical disinfect cancel mode cold water path state. It drains the reservoirs * before the cancel basic path mode is entered. * @details Inputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer - * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer + * @details Outputs: rsrvr1Status, rsrvr2Status, cancellationMode, stateTimer, + * haveDrainParamsBeenInit * @return next state of the chemical disinfect state machine *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCancelModeWaterPathState( void ) @@ -1237,10 +1266,12 @@ // 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; - stateTimer = getMSTimerCount(); + 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 ); @@ -1451,39 +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 currentVolumeML = 0.0F; - if ( DG_RESERVOIR_1 == r ) + switch( r ) { - currentVolume = getLoadCellSmallFilteredWeight( 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 ); - } - 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 ) + 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 ) ) @@ -1635,7 +1691,7 @@ data.overallElapsedTime = calcTimeSince( overallChemDisinfectTimer ); data.stateElapsedTime = calcTimeSince( stateTimer ); data.cancellationMode = (U32)cancellationMode; - data.acidAvgCondUSPCM = acidDataStatus.acidCondAvgUSPCM; + 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 ) @@ -1688,16 +1744,16 @@ // 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; + // 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 ); @@ -1728,22 +1784,25 @@ 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 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); @@ -1753,6 +1812,12 @@ maxTemperatureOutOfRangeStartTimeMS = ( TRUE == isTPoOutofRange ? maxTemperatureOutOfRangeStartTimeMS : getMSTimerCount() ); maxCondOutOfRangeStartTimeMS = ( TRUE == isCD2OutofRange ? maxCondOutOfRangeStartTimeMS : getMSTimerCount() ); + if ( TRUE == getTestConfigStatus( TEST_CONFIG_MIX_WITH_WATER ) ) + { + // If the mix with water is enabled, keep reseting the time + maxCondOutOfRangeStartTimeMS = getMSTimerCount(); + } + if ( TRUE == didTimeout( maxTemperatureOutOfRangeStartTimeMS, DISINFECT_TEMP_OUT_OF_RANGE_TIMEOUT_MS ) ) { signalMaxTempOrMaxCondIsOutOfRange = TRUE; @@ -1821,7 +1886,7 @@ 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 = acidDataStatus.acidCondRunningSumUSPCM / (F32)ACID_MOVING_AVG_NUM_OF_SAMPLES; + acidDataStatus.acidCondAvgUSPCM.data = acidDataStatus.acidCondRunningSumUSPCM / (F32)ACID_MOVING_AVG_NUM_OF_SAMPLES; } } @@ -1835,12 +1900,62 @@ *************************************************************************/ static BOOL isAcidCondOutOfRange( void ) { - F32 acidCondUSPCM = acidDataStatus.acidCondAvgUSPCM; + 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 **********