Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r3223b2c9784261205928b3ee21edd88df5be8a60 -r54abf84364e737dd350153d5fab7dd652f917ef4 --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 3223b2c9784261205928b3ee21edd88df5be8a60) +++ 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) Michael Garthwaite -* @date (last) 11-Sep-2023 +* @author (last) Dara Navaei +* @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" @@ -114,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. @@ -801,13 +803,14 @@ * @details Inputs: stateTimer, primeAcidSteadyStateCounter * @details Outputs: stateTimer, prevChemDisinfectState, * primeAcidSteadyStateCounter, maxTemperatureOutOfRangeStartTimeMS, - * maxCondOutOfRangeStartTimeMS + * 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 ) ) @@ -832,12 +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(); - maxTemperatureOutOfRangeStartTimeMS = getMSTimerCount(); - maxCondOutOfRangeStartTimeMS = 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 ) ) { @@ -862,14 +866,12 @@ * @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, FLUSH_DISINFECTANT_TIMEOUT_MS ) ) @@ -902,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; } } @@ -1252,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 ) @@ -1264,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 ); @@ -1531,8 +1535,9 @@ { R1FullVolume = currentVolumeML; } - else if ( DG_RESERVOIR_2 == r ) + else { + // If the reservoir is neither 1 or 2, the current volume will be updated so the code will never get here R2FullVolume = currentVolumeML; } } @@ -1739,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 ); @@ -1779,17 +1784,20 @@ 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; - } } }