Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r709def41bcde8e2e59d83c5e9c5a06ab0ee74ec8 -r487d3524cbf3b50dad1308fc1f68b733cc00c4cd --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 709def41bcde8e2e59d83c5e9c5a06ab0ee74ec8) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 487d3524cbf3b50dad1308fc1f68b733cc00c4cd) @@ -8,7 +8,7 @@ * @file Reservoirs.c * * @author (last) Sean Nash -* @date (last) 16-Mar-2023 +* @date (last) 18-Jul-2023 * * @author (original) Dara Navaei * @date (original) 21-Nov-2021 @@ -31,21 +31,28 @@ // ********** private definitions ********** -#define RESERVOIR_SETTLE_TIME_MS 5000 ///< Allocated time to settle the filled reservoir in milliseconds. +#define RESERVOIR_FRESH_SETTLE_TIME_MS 15000 ///< Allocated time to settle the freshly filled reservoir in milliseconds. +#define RESERVOIR_USED_SETTLE_TIME_MS 5000 ///< Allocated time to settle the depleted reservoir in milliseconds. #define RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS 8000 ///< Reservoir extra time in during the cycle for error in milliseconds. #define MAX_RESERVOIR_VOLUME_ML 1900.0F ///< Maximum allowed fluid in a reservoir in milliliters. #define MAX_RESERVOIR_DILUTION 0.15F ///< Maximum reservoir dilution limit. -#define MAX_RESERVOIR_RECIRCULATION 1.1F ///< Maximum reservoir recirculation limit. +#define MAX_RESERVOIR_RECIRCULATION_400_MLP 1.1F ///< Maximum reservoir recirculation limit <= 400mL/m. +#define MAX_RESERVOIR_RECIRCULATION_450_MLP 1.15F ///< Maximum reservoir recirculation limit <= 450mL/m. +#define MAX_RESERVOIR_RECIRCULATION_500_MLP 1.2F ///< Maximum reservoir recirculation limit <= 500mL/m. +#define MAX_RESERVOIR_RECIRCULATION_550_MLP 1.3F ///< Maximum reservoir recirculation limit <= 550mL/m. +#define MAX_RESERVOIR_RECIRCULATION_600_MLP 1.4F ///< Maximum reservoir recirculation limit <= 600mL/m. +#define RESERVOIR_FLOW_400_MLP 400.0F ///< Reservoir flow rate 400mL/m. +#define RESERVOIR_FLOW_450_MLP 450.0F ///< Reservoir flow rate 450mL/m. +#define RESERVOIR_FLOW_500_MLP 500.0F ///< Reservoir flow rate 500mL/m. +#define RESERVOIR_FLOW_550_MLP 550.0F ///< Reservoir flow rate 550mL/m. +#define RESERVOIR_FLOW_600_MLP 600.0F ///< Reservoir flow rate 600mL/m. #define MAX_RESERVOIR_DEPLETION_TIME_MS ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Maximum allowed depletion time in milliseconds. #define RESERVOIR_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the reservoir data is published on the CAN bus. -#define RESERVOIR_DEPLETION_INTERVAL ( MAX_RESERVOIR_DEPLETION_TIME_MS / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) for maximum allowed depletion time. -#define DIALYSATE_FLOW_RATE_350_ML_PER_MIN 0.35F ///< Dialysate flow rate 350 mL/min. -#define DIALYSATE_FLOW_RATE_550_ML_PER_MIN 0.55F ///< Dialysate flow rate 550 mL/min. -#define TGT_FILL_FLOW_FOR_DIA_FLOW_100_TO_350_ML_PER_MIN 0.5F ///< Target fill flow rate for dialysate flow rates in between 100 to 350 mL/min. -#define TGT_FILL_FLOW_FOR_DIA_FLOW_550_TO_600_ML_PER_MIN 0.8F ///< Target fill flow rate for dialysate flow rates in between 500 to 600 mL/min. +#define TGT_FILL_FLOW_800_ML_PER_MIN 0.8F ///< Target fill flow rate 800 mL/min. +#define TGT_FILL_FLOW_ERROR_ALLOWANCE 0.9F ///< Target fill flow rate for dialysate allowed error percentage. #define DIA_FLOW_TO_FILL_FLOW_SECOND_ORDER_COEFF 10.0F ///< Dialysate flow rate to fill flow rate second order coefficient. #define DIA_FLOW_TO_FILL_FLOW_FIRST_ORDER_COEFF 7.5F ///< Dialysate flow rate to fill flow rate first order coefficient. @@ -93,12 +100,13 @@ // ********** private function prototypes ********** // Reservoir management functions -static void checkReservoirDepletionTime( void ); static void checkReservoirMaxVolume( void ); static F32 getTargetFillFlowRateLPM( void ); static U32 getFillTimeMS( void ); static void calculateActiveReservoirCycleTime( void ); +static F32 getReservoirRecirculationMaxPercent( void ); static void publishReservoirData( void ); +static BOOL isDialysateTempAlarmActive( void ); static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtStartState( void ); static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtDrainState( void ); @@ -134,7 +142,7 @@ timeReservoirInUF = 0; lastTimeReservoirInUF = 0; volSpentUFML = 0.0F; - activeReservoir = DG_RESERVOIR_1; + activeReservoir = getDGActiveReservoir(); recirculationLevelPct = 0.0F; reservoirSwitchStartTimeMS = 0; timeWaitToFillMS = 0; @@ -164,7 +172,7 @@ * The execReservoirs function executes the state machine for the treatment * reservoir management during treatment mode. * @details Inputs: reservoirsState - * @details Outputs: reservoirsState, timeReservoirInUse, volSpentML + * @details Outputs: reservoirsState, timeReservoirInUse, volSpentML, recirculationLevelPct * @return none *************************************************************************/ void execReservoirs( void ) @@ -178,7 +186,6 @@ dgSubMode = getDGSubMode(); ratios = getDGMixingRatios(); - checkReservoirDepletionTime(); checkReservoirMaxVolume(); calculateActiveReservoirCycleTime(); @@ -191,6 +198,8 @@ #endif volSpentML += ( flowRateMLPerMS * msSinceLastVolumeCalc ); timeReservoirInUse++; + // Check the recirculation level + recirculationLevelPct = volSpentML / (F32)FILL_RESERVOIR_TO_VOLUME_ML; #ifdef DIALYZER_REPRIME_ENABLED } #endif @@ -236,20 +245,6 @@ /*********************************************************************//** * @brief - * The setDialysateHeatingParams function is an API to call other internal - * functions to set the trimmer's heater target temperature and times that are - * required to calculated the heaters target temperature in DG. - * @details Inputs: none - * @details Outputs: none - * @return none - *************************************************************************/ -void setDialysateHeatingParams( void ) -{ - calculateActiveReservoirCycleTime(); -} - -/*********************************************************************//** - * @brief * The getLastReservoirUFTimeInMs function returns the reservoir ultrafiltration * time (in ms) for the last reservoir used in treatment. * @details Inputs: none @@ -278,28 +273,6 @@ /*********************************************************************//** * @brief - * The checkReservoirDepletionTime function checks whether the active reservoir's - * depletion time has elapsed or not. If it has elapsed, it raises an alarm. - * @details Inputs: timeStartMS - * @details Outputs: none - * @return none - *************************************************************************/ -static void checkReservoirDepletionTime( void ) -{ - // Check if the time that the reservoir has been use has exceeded the limit - if ( timeReservoirInUse >= RESERVOIR_DEPLETION_INTERVAL ) - { -#ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_RESERVOIRS_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) -#endif - { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_DEPLETION_TIME_OUT, (timeReservoirInUse * TASK_GENERAL_INTERVAL) ) - } - } -} - -/*********************************************************************//** - * @brief * The checkReservoirMaxVolume function checks whether the active reservoir's * filled volume has exceeded maximum allowed value in milliliters. If it has * exceeded, it raises an alarm. @@ -322,31 +295,13 @@ * The getTargetFillFlowRateLPM function sets the target fill flow rate for DG * based on the target dialysate flow rate. * @details Inputs: none - * @details Outputs: none + * @details Outputs: targetFillFlowLPM * @return target fill flow rate *************************************************************************/ static F32 getTargetFillFlowRateLPM( void ) { - F32 fillFlowRate = 0.0; + F32 fillFlowRate = TGT_FILL_FLOW_800_ML_PER_MIN; - // Get the current dialysate flow rate set by the user and convert it L/min - F32 dialysateFlow = (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) / ML_PER_LITER; - - if ( dialysateFlow <= DIALYSATE_FLOW_RATE_350_ML_PER_MIN ) - { - fillFlowRate = TGT_FILL_FLOW_FOR_DIA_FLOW_100_TO_350_ML_PER_MIN; - } - else if ( dialysateFlow >= DIALYSATE_FLOW_RATE_550_ML_PER_MIN ) - { - fillFlowRate = TGT_FILL_FLOW_FOR_DIA_FLOW_550_TO_600_ML_PER_MIN; - } - else - { - // fill flow = 10 x dialysate_flow ^ 2 - 7.5 x dialysate_flow + 2.0 - fillFlowRate = pow( dialysateFlow, 2 ) * DIA_FLOW_TO_FILL_FLOW_SECOND_ORDER_COEFF - - dialysateFlow * DIA_FLOW_TO_FILL_FLOW_FIRST_ORDER_COEFF + DIA_FLOW_TO_FILL_FLOW_CONSTANT; - } - targetFillFlowLPM = fillFlowRate; return fillFlowRate; @@ -355,13 +310,14 @@ /*********************************************************************//** * @brief * The getFillTimeMS function calculates the fill time in milliseconds. - * @details Inputs: none + * @details Inputs: ratios * @details Outputs: none - * @return target fill flow rate + * @return target maximum fill time *************************************************************************/ static U32 getFillTimeMS( void ) { - F32 targetFillFlowRate = getTargetFillFlowRateLPM(); + // Get target flow * error allowance to make sure there is enough time to fill + F32 targetFillFlowRate = getTargetFillFlowRateLPM() * TGT_FILL_FLOW_ERROR_ALLOWANCE; // The target fill flow rate is RO flow rate plus acid and bicarb flow rates F32 totalTargetFillFlow = targetFillFlowRate + ( targetFillFlowRate * ratios.acidMixingRatio ) + ( targetFillFlowRate * ratios.bicarbMixingRatio ); @@ -380,7 +336,7 @@ * flow has changed the function sends the new active reservoir cycle time * to the DG. * @details Inputs: previousDialysateFlowMLP, previousUFFlowMLP - * @details Outputs: previousDialysateFlowMLP, previousUFFlowMLP + * @details Outputs: previousDialysateFlowMLP, previousUFFlowMLP, volSpentUFML, timeDepleteMS * @return none *************************************************************************/ static void calculateActiveReservoirCycleTime( void ) @@ -389,16 +345,30 @@ F32 fillTimeMS = ( (F32)FILL_RESERVOIR_TO_VOLUME_ML / ( getTargetFillFlowRateLPM() * ML_PER_LITER ) ) * SEC_PER_MIN * MS_PER_SECOND; F32 targetUFFlowMLP = getCurrentUFSetRate(); F32 timeDepletionMS = ( (F32)FILL_RESERVOIR_TO_VOLUME_ML / dialysateFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; - F32 timeTotalCycleMS = fillTimeMS + RESERVOIR_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS + ratios.timeFillPrepMS; + F32 timeTotalCycleMS = fillTimeMS + RESERVOIR_FRESH_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS + ratios.timeFillPrepMS; F32 timeReservoirCycleMS = 0.0F; F32 timeUFDepletionMS = NEARLY_INFINITY; + F32 volFreshML = FILL_RESERVOIR_TO_VOLUME_ML - volSpentML; + F32 timeFreshRemainingMS = ( volFreshML / (F32)dialysateFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; + F32 volMaxUFML = FILL_RESERVOIR_TO_VOLUME_ML * MAX_RESERVOIR_DILUTION; // Check if target UF flow is not zero to consider it in the calculations too if ( targetUFFlowMLP > NEARLY_ZERO ) { // If UF is not 0, the active reservoir cycle time is minimum of UF depletion and fill time timeUFDepletionMS = ( ( (F32)FILL_RESERVOIR_TO_VOLUME_ML * RESERVOIR_DILUTION_RATIO ) / targetUFFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; + // Calculate the ultra-filtration remaining volume + // Using the ultra-filtration remaining volume and the ultra-filtration target flow rate calculate the time + // The depletion time in milliseconds is the minimum time of the fresh remaining time and the depletion remaining time + // The depletion time is then used to calculate the time to wait to fill and whether to trigger a fill command or not + F32 volRemainingUFML = volMaxUFML - volSpentUFML; + F32 timeDepleteRemainingMS = ( volRemainingUFML / targetUFFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; + timeDepleteMS = MIN( timeFreshRemainingMS, timeDepleteRemainingMS ); } + else + { + timeDepleteMS = timeFreshRemainingMS; + } timeDepletionMS = MIN( timeDepletionMS, timeUFDepletionMS ); timeReservoirCycleMS = MAX( timeTotalCycleMS, timeDepletionMS ); @@ -410,7 +380,8 @@ DG_CMD_DIALYSATE_HEATING_PARAMS_T params; params.trimmerTargetTemperature = getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ); - params.timeReservoirWait2SwitchMS = RESERVOIR_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS; + // TODO timeReservoirWait2SwitchMS Should this be the calculated value? Or just RESERVOIR_FRESH_SETTLE_TIME_MS? + params.timeReservoirWait2SwitchMS = RESERVOIR_FRESH_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS; params.timeReservoirFillMS = fillTimeMS; params.timeReservoirCycleMS = timeReservoirCycleMS; params.dialysateFlowLPM = ( (F32)dialysateFlowMLP ) / ML_PER_LITER; @@ -427,6 +398,43 @@ /*********************************************************************//** * @brief + * The getReservoirRecirculationMaxPercent function returns the reservoir management + * maximum recirculation percentage. + * @details Inputs: TREATMENT_PARAM_DIALYSATE_FLOW + * @details Outputs: none + * @return reservoir management max recirculation percent + *************************************************************************/ +static F32 getReservoirRecirculationMaxPercent( void ) +{ + U32 targetDialysateFlowMLP = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ); + F32 maxPercent = 0.0F; + + if ( targetDialysateFlowMLP <= RESERVOIR_FLOW_400_MLP ) + { + maxPercent = MAX_RESERVOIR_RECIRCULATION_400_MLP; + } + else if ( targetDialysateFlowMLP <= RESERVOIR_FLOW_450_MLP ) + { + maxPercent = MAX_RESERVOIR_RECIRCULATION_450_MLP; + } + else if ( targetDialysateFlowMLP <= RESERVOIR_FLOW_500_MLP ) + { + maxPercent = MAX_RESERVOIR_RECIRCULATION_500_MLP; + } + else if ( targetDialysateFlowMLP <= RESERVOIR_FLOW_550_MLP ) + { + maxPercent = MAX_RESERVOIR_RECIRCULATION_550_MLP; + } + else + { + maxPercent = MAX_RESERVOIR_RECIRCULATION_600_MLP; + } + + return maxPercent; +} + +/*********************************************************************//** + * @brief * The publishReservoirData function publishes reservoirs data during treatment. * @details Inputs: reservoirsPublicationCounter * @details Outputs: reservoirsPublicationCounter @@ -445,7 +453,7 @@ data.recircLevelPct = recirculationLevelPct * 100; data.timeDepletionMS = timeDepleteMS; data.timeWaitFillMS = timeWaitToFillMS; - data.tempRemoveTragetFillFlow = targetFillFlowLPM; + data.tempRemoveTargetFillFlow = targetFillFlowLPM; broadcastData( MSG_ID_HD_RESERVOIRS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( RESERVOIRS_MANAGEMENT_DATA_T ) ); @@ -457,7 +465,7 @@ * @brief * The handleReservoirMgmtStartState function executes the reservoir management * start state. - * @details Inputs: none + * @details Inputs: dgOpMode * @details Outputs: none * @return next reservoir management state of the state machine *************************************************************************/ @@ -484,7 +492,7 @@ * @brief * The handleReservoirMgmtDrainState function executes the reservoir management * drain state. - * @details Inputs: none + * @details Inputs: dgOpMode * @details Outputs: none * @return next reservoir management state of the state machine *************************************************************************/ @@ -504,8 +512,8 @@ * @brief * The handleReservoirMgmtWaitToFillState function executes the reservoir management * wait to fill state. - * @details Inputs: dilutionLevel, volSpentML, dgSubMode - * @details Outputs: dilutionLevel, volSpentML, volSpentUFML, timeDepletionMS + * @details Inputs: volSpentML, dgOpMode, dgSubMode + * @details Outputs: dilutionLevelPct, volSpentUFML, timeDepleteMS, timeWaitToFillMS * @return next reservoir management state of the state machine *************************************************************************/ static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitToFillState( void ) @@ -530,38 +538,20 @@ cmdStartDGFill( FILL_RESERVOIR_TO_VOLUME_ML, targetFillFlowRateLPM ); } } - else + // If we have active dialysate temp alarms, we want to fill immediately. + else if ( TRUE == isDialysateTempAlarmActive() ) { - // The fresh left volume in the reservoir is the nominal volume - the spent volume - // Using the fresh remaining volume, time to spent the fresh remaining is calculated by dividing the volume to - // target dialysate flow rate. The target dialysate flow rate is used to be able to respond to the flow changes - // by the user - U32 targetDialysateFlowMLP = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ); - F32 volFreshML = FILL_RESERVOIR_TO_VOLUME_ML - volSpentML; - F32 timeFreshRemainingMS = ( volFreshML / (F32)targetDialysateFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; - F32 volMaxUFML = FILL_RESERVOIR_TO_VOLUME_ML * MAX_RESERVOIR_DILUTION; - F32 ultrafiltrationFlowMLP = getCurrentUFSetRate(); - - // If the ultra-filtration volume is not 0 check the depletion time for that too - if ( ultrafiltrationFlowMLP > NEARLY_ZERO ) + if ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) { - // Calculate the ultra-filtration remaining volume - // Using the ultra-filtration remaining volume and the ultra-filtration target flow rate calculate the time - // The depletion time in milliseconds is the minimum time of the fresh remaining time and the depletion remaining time - // The depletion time is then used to calculate the time to wait to fill and whether to trigger a fill command or not - F32 volRemainingUFML = volMaxUFML - volSpentUFML; - F32 timeDepleteRemainingMS = ( volRemainingUFML / ultrafiltrationFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; - timeDepleteMS = MIN( timeFreshRemainingMS, timeDepleteRemainingMS ); + cmdStartDGFill( FILL_RESERVOIR_TO_VOLUME_ML, targetFillFlowRateLPM ); } - else - { - timeDepleteMS = timeFreshRemainingMS; - } - + } + else + { // Time to wait prior to next fill is depletion time - the whole group of how much time is needed to fill a reservoir + // the time it takes to wait for a reservoir to settle and the extra margin time for ramp up of the RO and drain pumps and // any other extra times. - timeWaitToFillMS = timeDepleteMS - ( getFillTimeMS() + RESERVOIR_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS ); + timeWaitToFillMS = timeDepleteMS - ( getFillTimeMS() + RESERVOIR_FRESH_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS ); // If the wait time has elapsed, trigger a fill command if ( timeWaitToFillMS <= 0 ) @@ -587,19 +577,16 @@ * The handleReservoirMgmtFillState function executes the reservoir management * fill state. * @details Inputs: recirculationLevelPct, dgOpMode, dgSubMode - * @details Outputs: recirculationLevelPct, reservoirSwitchTimer + * @details Outputs: recirculationLevelPct, reservoirSwitchStartTimeMS * @return next reservoir management state of the state machine *************************************************************************/ static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtFillState( void ) { TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE; - // Check the recirculation level - recirculationLevelPct = volSpentML / (F32)FILL_RESERVOIR_TO_VOLUME_ML; - // If the recirculation level has exceeded the max allowed, raise the alarm to stop using the active reservoir as it has been // diluted to much - if ( recirculationLevelPct >= MAX_RESERVOIR_RECIRCULATION ) + if ( recirculationLevelPct >= getReservoirRecirculationMaxPercent() ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_RESERVOIRS_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) @@ -614,7 +601,6 @@ { // Clear any of the recoverable conditions in case they were raised during the fill or wait to fill clearAlarmCondition( ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE ); - clearAlarmCondition( ALARM_ID_HD_ACTIVE_RESERVOIR_DEPLETION_TIME_OUT ); clearAlarmCondition( ALARM_ID_HD_ACTIVE_RESERVOIR_WEIGHT_OUT_OF_RANGE ); reservoirSwitchStartTimeMS = getMSTimerCount(); @@ -628,8 +614,8 @@ * @brief * The handleReservoirMgmtWaitForFillSettleState function executes the reservoir * management wait for fill to settle state. - * @details Inputs: reservoirSwitchTimer, volSpentML - * @details Outputs: reservoirSwitchTimer, volSpentML + * @details Inputs: reservoirSwitchStartTimeMS, volSpentML + * @details Outputs: reservoirSwitchStartTimeMS, volSpentML, volSpentUFML, dilutionLevelPct * @return next reservoir management state of the state machine *************************************************************************/ static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForFillSettleState( void ) @@ -642,9 +628,9 @@ volSpentUFML = getReservoirUltrafiltrationVol( activeReservoir ); dilutionLevelPct = volSpentUFML / (F32)FILL_RESERVOIR_TO_VOLUME_ML; - // Wait for the reservoir to settle and then send the commands to switch the active reservoir TODO - restore #define below - if ( ( TRUE == didTimeout( reservoirSwitchStartTimeMS, 15000 /*RESERVOIR_SETTLE_TIME_MS*/ ) ) && - ( ( dilutionLevelPct >= MAX_RESERVOIR_DILUTION ) || ( volSpentML >= (F32)FILL_RESERVOIR_TO_VOLUME_ML ) || ( getReservoirWeight( active ) > MAX_RESERVOIR_VOL_BEFORE_SWITCH_ML ) ) ) + // Wait for the reservoir to settle and then send the commands to switch the active reservoir + if ( ( TRUE == didTimeout( reservoirSwitchStartTimeMS, RESERVOIR_FRESH_SETTLE_TIME_MS ) ) && + ( ( dilutionLevelPct >= MAX_RESERVOIR_DILUTION ) || ( volSpentML >= (F32)FILL_RESERVOIR_TO_VOLUME_ML ) || ( getReservoirWeight( active ) > MAX_RESERVOIR_VOL_BEFORE_SWITCH_ML ) || ( TRUE == isDialysateTempAlarmActive() ) ) ) { DG_SWITCH_RSRVRS_CMD_T rsrvrCmd; @@ -668,6 +654,7 @@ reservoirSwitchStartTimeMS = getMSTimerCount(); state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; + } return state; @@ -677,29 +664,51 @@ * @brief * The handleReservoirMgmtWaitForSwitchSettleState function executes the reservoir * management wait for switch to settle state. - * @details Inputs: reservoirSwitchTimer - * @details Outputs: none + * @details Inputs: reservoirSwitchStartTimeMS + * @details Outputs: timeReservoirInUse * @return next reservoir management state of the state machine *************************************************************************/ static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForSwitchSettleState( void ) { TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; - if ( TRUE == didTimeout( reservoirSwitchStartTimeMS, RESERVOIR_SETTLE_TIME_MS ) ) + if ( TRUE == didTimeout( reservoirSwitchStartTimeMS, RESERVOIR_USED_SETTLE_TIME_MS ) ) { - // Signal dialysis sub-mode to capture final volume of prior reservoir after settling. - setFinalReservoirVolume(); - - // Switched the active reservoir so reset the reservoir in use timer + // Switching the active reservoir so reset the reservoir in use timer lastTimeReservoirInUF = timeReservoirInUF; timeReservoirInUF = 0; timeReservoirInUse = 0; + // Signal dialysis sub-mode to capture final volume of prior reservoir after settling. + setFinalReservoirVolume(); + // Reset to start state to restart drain, fill, switch process. state = TREATMENT_RESERVOIR_MGMT_START_STATE; } return state; } +/*********************************************************************//** + * @brief + * The isDialysateTempAlarmActive function checks for active dialysate + * temperature alarms + * @details Inputs: none + * @details Outputs: none + * @return True if dialysate temperature alarm is active. False if not. + *************************************************************************/ +static BOOL isDialysateTempAlarmActive( void ) +{ + BOOL result = FALSE; + if ( ( TREATMENT_STOP_STATE == getTreatmentState() ) && + ( TRUE == isAlarmConditionDetected( ALARM_ID_HD_DIALYSATE_TEMP_BELOW_TARGET_TEMP ) || + TRUE == isAlarmConditionDetected( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_SAFETY_TEMP ) || + TRUE == isAlarmConditionDetected( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_TARGET_TEMP ) ) ) + { + result = TRUE; + } + + return result; +} + /**@}*/