Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -re2cf7feff54dad3fc5be72619fa64b5421fc6f9f -rcd5be724d5a3ba7457e761191d82f278654d7f5c --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision e2cf7feff54dad3fc5be72619fa64b5421fc6f9f) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision cd5be724d5a3ba7457e761191d82f278654d7f5c) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2021-2023 Diality Inc. - All Rights Reserved. +* Copyright (c) 2021-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 Reservoirs.c * -* @author (last) Dara Navaei -* @date (last) 19-Sep-2023 +* @author (last) Sean Nash +* @date (last) 06-Oct-2023 * * @author (original) Dara Navaei * @date (original) 21-Nov-2021 @@ -26,6 +26,7 @@ #include "NVDataMgmt.h" #include "OperationModes.h" #include "Reservoirs.h" +#include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" @@ -58,11 +59,6 @@ #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. -#define DIA_FLOW_TO_FILL_FLOW_CONSTANT 2.0F ///< Dialysate flow rate to fill flow rate constant. - -#define MAX_RESERVOIR_VOL_BEFORE_SWITCH_ML 1900.0F ///< Maximum reservoir volume before we switch reservoirs (in mL). #define FILL_VOLUME_INTERCEPT_ML_QD_ABOVE_400_MLPM 1100 ///< Fill volume intercept in milliliters for Qd above 400 mL/min. // ********** private data ********** @@ -92,7 +88,7 @@ static U32 lastTimeReservoirInUF; ///< Reservoir time in ultrafiltration from prior reservoir (in ms). static F32 volSpentUFML; ///< Ultrafiltration volume in milliliters. static DG_RESERVOIR_ID_T activeReservoir; ///< Active reservoir. -static F32 recirculationLevelPct; ///< Recirculation level in percent. +static OVERRIDE_F32_T recirculationLevelPct = { 0.0, 0.0, 0.0, 0 }; ///< Recirculation level in percent. static U32 reservoirSwitchStartTimeMS; ///< Reservoir switch start time in milliseconds. static S32 timeWaitToFillMS; ///< Time to wait to fill in milliseconds. static F32 targetFillFlowLPM; ///< Target fill flow in liters/minutes. @@ -150,7 +146,7 @@ lastTimeReservoirInUF = 0; volSpentUFML = 0.0F; activeReservoir = getDGActiveReservoir(); - recirculationLevelPct = 0.0F; + recirculationLevelPct.data = 0.0F; reservoirSwitchStartTimeMS = 0; timeWaitToFillMS = 0; targetFillFlowLPM = 0.0F; @@ -207,7 +203,7 @@ volSpentML += ( flowRateMLPerMS * msSinceLastVolumeCalc ); timeReservoirInUse++; // Check the recirculation level - recirculationLevelPct = volSpentML / (F32)prevTargetFillVolumeML[ getDGActiveReservoir() ]; + recirculationLevelPct.data = volSpentML / (F32)prevTargetFillVolumeML[ getDGActiveReservoir() ]; } // Update the reservoir start time @@ -457,7 +453,7 @@ data.activeReservoirUFVolML = volSpentUFML; data.activeReservoirVolSpentML = volSpentML; data.dilLevelPct = dilutionLevelPct * 100; - data.recircLevelPct = recirculationLevelPct * 100; + data.recircLevelPct = getF32OverrideValue( &recirculationLevelPct ) * 100; data.timeDepletionMS = timeDepleteMS; data.timeWaitFillMS = timeWaitToFillMS; data.tempRemoveTargetFillFlow = targetFillFlowLPM; @@ -540,7 +536,9 @@ // Check if the dilution level has exceeded the limit or the spent volume is more than the amount of volume in the reservoir // If it has, trigger the fill command. This if should not happen and the predictive dilution level should trigger just in time // in advance - if ( ( dilutionLevelPct >= MAX_RESERVOIR_DILUTION ) || ( volSpentML >= (F32)prevTargetFillVolumeML[ activeRsrvr ] ) ) + if ( ( dilutionLevelPct >= MAX_RESERVOIR_DILUTION ) || + ( volSpentML >= (F32)prevTargetFillVolumeML[ activeRsrvr ] ) || + ( TRUE == isAlarmActive( ALARM_ID_HD_ACTIVE_RESERVOIR_WEIGHT_OUT_OF_RANGE ) ) ) { if ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) { @@ -598,23 +596,19 @@ // 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 >= getReservoirRecirculationMaxPercent() ) + if ( getF32OverrideValue( &recirculationLevelPct ) >= getReservoirRecirculationMaxPercent() ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_RESERVOIRS_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE, recirculationLevelPct ) + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE, getF32OverrideValue( &recirculationLevelPct ) ) } } // Check if DG has moved out of the fill mode if ( ( DG_MODE_GENE == dgOpMode ) && ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) ) { - // 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_WEIGHT_OUT_OF_RANGE ); - reservoirSwitchStartTimeMS = getMSTimerCount(); state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE; } @@ -659,9 +653,13 @@ // Signal dialysis sub-mode to switch reservoirs signalReservoirsSwitched(); - // Get ready for the next delivery + // Reset spent volume for fresh reservoir that we've just switched to volSpentML = 0.0; + // Clear any of the recoverable conditions that were waiting for reservoir switch to allow treatment resume + clearAlarmCondition( ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE ); + clearAlarmCondition( ALARM_ID_HD_ACTIVE_RESERVOIR_WEIGHT_OUT_OF_RANGE ); + // Wait for used reservoir to settle reservoirSwitchStartTimeMS = getMSTimerCount(); @@ -743,4 +741,55 @@ return targetFillVolumeML; } + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetRecirculationLevelPctOverride function overrides the recirculation + * percentage. + * @details Inputs: none + * @details Outputs: recirculationLevelPct + * @param value override percentage value with this + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetRecirculationLevelPctOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + recirculationLevelPct.ovData = value; + recirculationLevelPct.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetRecirculationLevelPctOverride function resets the override of the + * recirculation percentage. + * @details Inputs: none + * @details Outputs: recirculationLevelPct + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetRecirculationLevelPctOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + recirculationLevelPct.override = OVERRIDE_RESET; + recirculationLevelPct.ovData = recirculationLevelPct.ovInitData; + } + + return result; +} + /**@}*/