Index: firmware/App/Controllers/BalancingChamber.c =================================================================== diff -u -r7d24ef2e6a4130b3a049e6106a0371fc6503271f -r2d295ca85f19e95da42476a57ca6b4496baf980a --- firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 7d24ef2e6a4130b3a049e6106a0371fc6503271f) +++ firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 2d295ca85f19e95da42476a57ca6b4496baf980a) @@ -1,26 +1,29 @@ /************************************************************************** * -* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* Copyright (c) 2025-2026 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 BalancingChamber.c * -* @author (last) Vinayakam Mani -* @date (last) 24-Oct-2024 +* @author (last) Sameer Kalliadan Poyil +* @date (last) 28-Apr-2026 * * @author (original) Vinayakam Mani -* @date (original) 24-Oct-2024 +* @date (original) 28-Jan-2025 * ***************************************************************************/ #include "BalancingChamber.h" #include "Conductivity.h" #include "ConcentratePumps.h" #include "DialysatePumps.h" +#include "DryBiCart.h" #include "FpgaDD.h" #include "Heaters.h" +#include "Level.h" +#include "ModeGenDialysate.h" #include "ModeStandby.h" #include "Messaging.h" #include "OperationModes.h" @@ -41,12 +44,29 @@ #define BAL_CHAMBER_DATA_PUBLISH_INTERVAL ( 250 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the balancing chamber data published. #define BAL_CHAMBER_FILL_PRES_DROP_MS ( 200 / TASK_GENERAL_INTERVAL ) ///< Time (ms/tasktime) to confirm the balancing chamber filling started and corrosponding valves opened. #define BAL_CHAMBER_FILL_COMPLETE_MS ( 300 / TASK_GENERAL_INTERVAL ) ///< Time (ms/tasktime) to confirm the balancing chamber fill completed and pressure is within range +#define SPENT_FILL_COMPLETE_PRES 25.0F ///< Spent fill complete pressure (PSI) for Diener 2000 pump. +#define SPENT_FILL_COMPLETE_PRES_QD_MID_PSIG 15.0F ///< Spent fill complete pressure (PSI) when Diener 1000 and 200 < Qd <= 400. +#define SPENT_FILL_COMPLETE_PRES_QD_HIGH_PSIG 20.0F ///< Spent fill complete pressure (PSI) when Diener 1000 and Qd > 400. +#define SPENT_FILL_COMPLETE_QD_SLOPE_MAX_MLPM 300.0F ///< For Qd <= 300 mL/min, spent fill completion uses pressure-rise slope detection. +#define SPENT_FILL_COMPLETE_QD_TWO_HIT_MAX_MLPM 150.0F ///< For Qd <= 150 mL/min, require two rise detections; above this and <=300, one rise detection is enough. +#define SPENT_FILL_COMPLETE_DP_RISE_PSIG 0.5F ///< Minimum 100 ms spent pressure rise (current minus n-2) to count as a rise hit at low Qd. +#define SPENT_FILL_SLOPE_SPENT_PRESSURE_HIGH_PSIG 2.0F ///< Above this absolute spent pressure, only one rise hit is required. +#define SPENT_FILL_SLOPE_SPENT_PRESSURE_LOW_PSIG 0.5F ///< Below this absolute spent pressure, use Qd-based required rise hit count. +#define SPENT_FILL_SLOPE_MAX_RISE_HITS 2 ///< Rise hits required when Qd <= 150 in the low spent-pressure band. +#define SPENT_FILL_DETECT_COUNT_TOL_PCT 0.20F ///< Allowed detection timing tolerance as a fraction of expected BC switching count. +#define QD_THRESHOLD_HIGH_MLPM 400.0F ///< Qd threshold (mL/min) below which mid pressure limit applies. +#define SPENT_DIFF_COUNT_ZERO 0 ///< Zero count difference for spent side fill comparing target count +#define D48_SPEED_ADJUST_FACTOR 0.5F ///< D48 speed adjustment factor ( 50% of speed adjustment = 0.5) +#define D48_SPEED_RANGE_LIMIT 0.25F ///< D48 speed adjustment range check limit ( D48 speed can vary +/-25% of initial calculated speed) +#define BICARB_CHAMBER_PERIODIC_FILL_TIME ( 1 * SEC_PER_MIN * \ + ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ) ///< Periodic bicarb chamber fill request 60 sec x 20 = 1200 +#define BAL_CHAMBER_FILL_TIMEOUT_FACTOR 1.5 ///< Balancing Chamber fill timeout factor (150% of observed fill count) /// Payload record structure for balancing chamber switch only request typedef struct { - U32 startStop; ///< balancing chamber switching only start:1 and stop: 0 - F32 flowrate; ///< dialysate flowrate in ml/min + U32 startStop; ///< Balancing chamber switching only start:1 and stop: 0 + F32 flowrate; ///< Dialysate flowrate in ml/min } BC_SWITCHING_ONLY_START_CMD_PAYLOAD_T; // ********** private data ********** @@ -57,12 +77,14 @@ static U32 balChamberValveClosePeriod; ///< Close balancing chamber valves with the defined time prior switching state. static U32 currentBalChamberSwitchingCounter; ///< Counter (in task interval) to monitor the timing spent during balancing chamber fill/drain operation. static BOOL isBalChamberFillInProgress; ///< Flag indicating balancing chamber fill/drain is in progress. -static BOOL isPressureStalbilizedDuringFill; ///< Flag indicating that the pressure is stablized due to fill complete. +static BOOL isPressureStabilizedDuringFill; ///< Flag indicating that the pressure is stabilized due to fill complete. static BAL_CHAMBER_SW_STATE_T balChamberSWState; ///< Current balancing chamber switching state ( state 1 or state 2). static U32 balChamberDataPublicationTimerCounter; ///< Used to schedule balancing chamber data publication to CAN bus. static U32 balChamberFillPressureDropCounter; ///< Counter to check balancing chamber valves opened and there by pressure drop is seen. static OVERRIDE_U32_T balChamberDataPublishInterval; ///< Balancing chamber data publish interval. -static BOOL balanceChamberSwitchingOnly; ///< Balancing chamber switching without any pressure check and dosing delivery. +static BOOL balanceChamberSwitchingOnly; ///< Balancing chamber switching without any pressure check and dosing delivery +static BOOL balanceChamberSwitchingOnlyOnRequested; ///< Flag indicating that a request was made to activate balancing chamber switching only +static BOOL balanceChamberSwitchingOnlyOffRequested; ///< Flag indicating that a request was made to deactivate balancing chamber switching only static BOOL isPressureDroppedDuringFill; ///< Flag indicating that the pressure is dropped due to BC fill (state 1 or state 2) in progress condition. static BOOL isFirstCycleBCSwitchingCompleted; ///< Flag indicating that first time balancing chamber swithcing is done to trigger alarms from next cycle onwards. static U32 balChamberFillCompleteStablePressureCounter; ///< Counter to check balancing chamber fill complete and stable pressure is met. @@ -71,7 +93,21 @@ static F32 lastTdDialysateFlowrate; ///< Previous TD dialysate flow rate static F32 freshDialPressure; ///< Fresh side dialysate pressure static F32 spentDialPressure; ///< Spent side dialysate pressure +static U32 currentBalChamberFillCounter; ///< Counter (in task interval) to monitor the timing spent for the spent side fill operation. +static U32 balChamberFillTimeoutCount; ///< Timeout count (in task interval) to detect BC fill timeout. +static S32 diffSpentFillCompleteCount; ///< Difference between spent target fill to actual fill count +static BOOL isSpentFillComplete; ///< Flag indicating spent side fill complete. +static F32 lastPrevSpentDialPressure; ///< Low-Qd slope: spent pressure last sample of dosing (tick before VALVES_CLOSE); then n-2 in VC. +static F32 prevSpentDialPressure; ///< Spent pressure previous sample (n-1) during VALVES_CLOSE for low-Qd slope detection. +static U32 spentFillRiseHitCount; ///< Low-Qd slope: counted rise hits (only incremented when in timing window). +static U32 spentFillRiseMissCounter; ///< Missed samples after a rise hit before resetting hit count. +static BOOL isBalChamberSwitchingActive; ///< Flag indicating balancing chamber switching is active or not. +static BOOL isBalChamberSwitchingOnRequested; ///< Flag indicating that a request was made to activate balancing chamber switching. +static BOOL isBalChamberSwitchingOffRequested; ///< Flag indicating that a request was made to deactivate balancing chamber switching. +//TODO: remove later once level sensor working +static U32 bicarbChamberPeriodicFillCounter; + // ********** private function prototypes ********** static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillStart( void ); @@ -81,8 +117,11 @@ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2FillStart( void ); static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2ValvesClose( void ); static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2FillEnd(void); +static BAL_CHAMBER_EXEC_STATE_T handleBalChamberStateIdle( void ); static void publishBalChamberData( void ); static U32 getBalChamberDataPublishInterval( void ); +static void checkSpentFillComplete( F32 spentDialPressure ); +static BOOL isSpentFillCompleteByPressure( F32 spentDialPressure, F32 qdMlpm, F32 spentFillCompletePresPsig ); /*********************************************************************//** * @brief @@ -93,7 +132,7 @@ *************************************************************************/ void initBalanceChamber( void ) { - balChamberExecState = BAL_CHAMBER_STATE_START; + balChamberExecState = BAL_CHAMBER_STATE_IDLE; balChamberSWState = BAL_CHAMBER_SW_STATE1; balChamberSwitchingFreq.data = 0.0F; balChamberSwitchingFreq.ovData = 0.0F; @@ -112,11 +151,12 @@ bicarbDoseVolume.ovInitData = 0.0F; bicarbDoseVolume.override = OVERRIDE_RESET; balanceChamberSwitchingOnly = FALSE; + balanceChamberSwitchingOnlyOnRequested = FALSE; + balanceChamberSwitchingOnlyOffRequested = FALSE; balChamberSwitchingPeriod = 0; balChamberValveClosePeriod = 0; isBalChamberFillInProgress = FALSE; - currentBalChamberSwitchingCounter = 0; - isPressureStalbilizedDuringFill = FALSE; + isPressureStabilizedDuringFill = FALSE; lastTdDialysateFlowrate = 0.0F; balChamberDataPublicationTimerCounter = 0; balChamberFillPressureDropCounter = 0; @@ -125,6 +165,20 @@ isPressureDroppedDuringFill = FALSE; freshDialPressure = 0.0F; spentDialPressure = 0.0F; + balChamberFillTimeoutCount = 0; + diffSpentFillCompleteCount = 0; + lastPrevSpentDialPressure = 0.0F; + prevSpentDialPressure = 0.0F; + currentBalChamberSwitchingCounter = 0; + currentBalChamberFillCounter = 0; + spentFillRiseHitCount = 0; + spentFillRiseMissCounter = 0; + isSpentFillComplete = FALSE; + isBalChamberSwitchingActive = FALSE; + isBalChamberSwitchingOnRequested = FALSE; + isBalChamberSwitchingOffRequested = FALSE; + //TODO:remove once level sensor working + bicarbChamberPeriodicFillCounter = 0; } /*********************************************************************//** @@ -167,6 +221,9 @@ //Update last td dialysate flow rate lastTdDialysateFlowrate = tdDialysateFlowrate; + // Update fill timeout count based on the switching period (e.g. 150% of period) + balChamberFillTimeoutCount = (U32)( (F32)balChamberSwitchingPeriod * BAL_CHAMBER_FILL_TIMEOUT_FACTOR ); + //Reset the BC switching flag for new Qd. isFirstCycleBCSwitchingCompleted = FALSE; @@ -176,6 +233,15 @@ //Testing balChamberValveClosePeriod = balChamberSwitchingPeriod; balChamberValveClosePeriod -= 1; // Close valves prior 50 msecond for testing + + currentBalChamberFillCounter = 0; + currentBalChamberSwitchingCounter = 0; + spentFillRiseHitCount = 0; + spentFillRiseMissCounter = 0; + isSpentFillComplete = FALSE; + spentDialPressure = getFilteredPressure( D51_PRES ); + lastPrevSpentDialPressure = spentDialPressure; + prevSpentDialPressure = spentDialPressure; } } @@ -189,14 +255,47 @@ *************************************************************************/ U32 execBalancingChamberControl( void ) { + LVL_STATE_T bicarbChamberLevel = getBicarbChamberLevelStatus(); + + updateBalChamberSwitchingPeriod(); + // Increment counter indicating fill is in progress. currentBalChamberSwitchingCounter += 1; + currentBalChamberFillCounter += 1; - // execute current balancing chamber exec state + if ( ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == TRUE ) && ( balChamberExecState > BAL_CHAMBER_STATE_IDLE ) ) + { +#ifdef CONDUCTIVE_LEVEL_SENSOR_ENABLED + if ( LVL_STATE_LOW == bicarbChamberLevel ) + { + if ( FALSE == setBicarbChamberFillRequested() ) + { + // TODO + //drybicart state machines are combined and so this is not an issue in future + //set alarm ? + } + } +#else // time based chamber F fill + // Increment counter for dry bicarb chamber fill + bicarbChamberPeriodicFillCounter += 1; + // Fill bicarb chamber once every 60secs. + if ( bicarbChamberPeriodicFillCounter >= BICARB_CHAMBER_PERIODIC_FILL_TIME ) + { + if ( FALSE == setBicarbChamberFillRequested() ) + { + // TODO + //drybicart state machines are combined and so this is not an issue in future + //set alarm ? + } + bicarbChamberPeriodicFillCounter = 0; + } +#endif + } + switch ( balChamberExecState ) { - case BAL_CHAMBER_STATE_START: - balChamberExecState = BAL_CHAMBER_STATE1_FILL_START; + case BAL_CHAMBER_STATE_IDLE: + balChamberExecState = handleBalChamberStateIdle(); break; case BAL_CHAMBER_STATE1_FILL_START: @@ -233,7 +332,7 @@ default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_BAL_CHAMBER_INVALID_EXEC_STATE, balChamberExecState ) - balChamberExecState = BAL_CHAMBER_STATE_START; + balChamberExecState = BAL_CHAMBER_STATE_IDLE; break; } @@ -245,6 +344,26 @@ /*********************************************************************//** * @brief + * The requestBalChamberSwitching function activates or deactivates balancing chamber switching. + * @details \b Inputs: none + * @details \b Outputs: isBalChamberSwitchingOnRequested, isBalChamberSwitchingOffRequested + * @param activate - TRUE to activate and FALSE to deactivate. + * @return none. + *************************************************************************/ +void requestBalChamberSwitching( BOOL activate ) +{ + if ( TRUE == activate ) + { + isBalChamberSwitchingOnRequested = TRUE; + } + else + { + isBalChamberSwitchingOffRequested = TRUE; + } +} + +/*********************************************************************//** + * @brief * The valveControlForBCState1FillStart function actuates the valve combination * for state 1 fill/drain process. * @details \b Inputs: none @@ -399,28 +518,57 @@ * @details \b Inputs: Pressure * @details \b Outputs: valve states * @details \b Alarm: ALARM_ID_DD_BC_STATE1_FILL_START_PRESSURE_OUT_OF_RANGE - * when pressure is not in range during balacing chamber fill start. + * when pressure is not in range during balancing chamber fill start. * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillStart( void ) { + F32 acidVolume; + F32 bicarbVolume; BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE1_FILL_START; - currentBalChamberSwitchingCounter = 0; + + balChamberSWState = BAL_CHAMBER_SW_STATE1; + balChamberFillTimeoutCount = 0; isBalChamberFillInProgress = FALSE; - isPressureStalbilizedDuringFill = FALSE; + isPressureStabilizedDuringFill = FALSE; isPressureDroppedDuringFill = FALSE; - balChamberSWState = BAL_CHAMBER_SW_STATE1; + lastPrevSpentDialPressure = 0.0F; + prevSpentDialPressure = 0.0F; + currentBalChamberSwitchingCounter = 0; + currentBalChamberFillCounter = 0; + spentFillRiseHitCount = 0; + spentFillRiseMissCounter = 0; + isSpentFillComplete = FALSE; - F32 acidVolume = getF32OverrideValue( &acidDoseVolume ); - F32 bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); - freshDialPressure = getFilteredPressure( D18_PRES ); - spentDialPressure = getFilteredPressure( D51_PRES ); + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == TRUE ) + { + bicarbVolume = getBicarbMixVol(); + acidVolume = getAcidMixVol(); + } + else // wet bicarb + { + acidVolume = getF32OverrideValue( &acidDoseVolume ); + bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); + } - // Check fresh and spent dialysate pressure in range or BC switch only flag set - if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) && - ( ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ) ) || - ( TRUE == getBalChamberSwitchingOnlyStatus() ) || ( TRUE == getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) ) ) + freshDialPressure = getFilteredPressure( D18_PRES ); + spentDialPressure = getFilteredPressure( D51_PRES ); + + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) == TRUE ) { + //Set Trimmer heater Target temp every BC cycle to catch up fresh dialysate temp + setHeaterTargetTemperature( D45_HEAT, getFilteredTemperatureValue( D4_TEMP ) ); + } + else + { + //Set Trimmer heater Target temp every BC cycle to catch up fresh dialysate temp + setHeaterTargetTemperature( D45_HEAT, getFilteredTemperatureValue( D99_TEMP ) ); + } + + // Check fresh dialysate pressure in range or BC switch only flag set or BC pressure alarms are disabled + if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) || + ( TRUE == getBalChamberSwitchingOnlyStatus() ) || ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) ) ) + { //Valve control for state 1 fill valveControlForBCState1FillStart(); @@ -431,8 +579,8 @@ if ( TRUE != getBalChamberSwitchingOnlyStatus() ) { // start acid and bicarb pump with the expected quantity - setConcentratePumpTargetSpeed( D11_PUMP, CONCENTRATE_PUMP_MAX_SPEED, acidVolume ); - setConcentratePumpTargetSpeed( D10_PUMP, CONCENTRATE_PUMP_MAX_SPEED, bicarbVolume ); + setConcentratePumpTargetSpeed( D11_PUMP, DOSING_CONCENTRATE_PUMP_SPEED, acidVolume ); + setConcentratePumpTargetSpeed( D10_PUMP, DOSING_CONCENTRATE_PUMP_SPEED, bicarbVolume ); requestConcentratePumpOn( D11_PUMP ); requestConcentratePumpOn( D10_PUMP ); } @@ -441,10 +589,13 @@ } else { - if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { //Alarm when pressure is not in range SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_START_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; } } @@ -454,18 +605,21 @@ /*********************************************************************//** * @brief * The handleBalChamberConcentrateControl function handles the Acid and Bicarb - * concentrate doisng and checks the conductivity of the dialysate for the treatment. + * concentrate dosing and checks the conductivity of the dialysate for the treatment. * @details \b Inputs: balChamberSWState , Concentrate volume * @details \b Outputs: isPressureDroppedDuringFill, state * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberConcentrateControl( void ) { BAL_CHAMBER_EXEC_STATE_T state; - freshDialPressure = getFilteredPressure( D18_PRES ); - spentDialPressure = getFilteredPressure( D51_PRES ); - if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) + freshDialPressure = getFilteredPressure( D18_PRES ); + spentDialPressure = getFilteredPressure( D51_PRES ); + lastPrevSpentDialPressure = prevSpentDialPressure; + prevSpentDialPressure = spentDialPressure; + + if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) { state = BAL_CHAMBER_STATE1_BICARB_ACID_DOSING_CNTRL; } @@ -488,13 +642,17 @@ ( TRUE == isConcentratePumpDosingCompleted( D10_PUMP ) ) ) || ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) { + if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) { - state = BAL_CHAMBER_STATE1_VALVES_CLOSE; + // Low-Qd spent slope: baseline = spent pressure on last dosing tick (this task period) before VALVES_CLOSE. + prevSpentDialPressure = spentDialPressure; + state = BAL_CHAMBER_STATE1_VALVES_CLOSE; } else { - state = BAL_CHAMBER_STATE2_VALVES_CLOSE; + prevSpentDialPressure = spentDialPressure; + state = BAL_CHAMBER_STATE2_VALVES_CLOSE; } } @@ -512,37 +670,53 @@ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1ValvesClose( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE1_VALVES_CLOSE; + BOOL isBothFillsComplete = FALSE; + BOOL isFirstCycleNotDone = FALSE; + BOOL isFillCompleteOrFirstCycle = FALSE; - freshDialPressure = getFilteredPressure( D18_PRES ); - spentDialPressure = getFilteredPressure( D51_PRES ); + freshDialPressure = getFilteredPressure( D18_PRES ); + spentDialPressure = getFilteredPressure( D51_PRES ); - // Check fresh and spent dialysate pressure back in range to indicate fill complete. - if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + // If fill is taking too long, set an alarm for fill timeout + if ( ( balChamberFillTimeoutCount > 0 ) && ( currentBalChamberFillCounter > balChamberFillTimeoutCount ) ) { - if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) && - ( ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ) ) ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_BC_FILL_TIMEOUT_FAULT, currentBalChamberFillCounter, balChamberFillTimeoutCount ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; + } + + // Check fresh dialysate pressure back in range to indicate fresh fill complete. + if ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) + { + if ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) { - if ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) - { - // stabilized pressure indicating fill is complete - isPressureStalbilizedDuringFill = TRUE; - } + // stabilized pressure indicating fresh side fill is complete + isPressureStabilizedDuringFill = TRUE; } } - else + + // Spent side of balancing chamber fill is complete or not + checkSpentFillComplete( spentDialPressure ); + + // Check both spent and fresh side fill is complete + isBothFillsComplete = ( TRUE == isSpentFillComplete ) && ( TRUE == isPressureStabilizedDuringFill ); + isFirstCycleNotDone = ( FALSE == isFirstCycleBCSwitchingCompleted ); + + if ( FALSE == getBalChamberSwitchingOnlyStatus() ) { - isPressureStalbilizedDuringFill = FALSE; + isFillCompleteOrFirstCycle = isBothFillsComplete || isFirstCycleNotDone; } - // Switching time met or pressure in range, close valves - if ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) || - ( TRUE == isPressureStalbilizedDuringFill ) ) + if ( ( TRUE == isFillCompleteOrFirstCycle ) || + ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) && ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) ) { // close the state 1 opened valves valveControlForBCState1FillEnd(); isBalChamberFillInProgress = FALSE; + setDialysatePumpTargetRPM( D48_PUMP, getD48PumpSpeedForBCFill(), TRUE ); - //Transition to next state + // Transition to next state state = BAL_CHAMBER_STATE1_FILL_END; } @@ -552,57 +726,94 @@ /*********************************************************************//** * @brief * The handleBalChamberState1FillEnd function check for the balancing chamber - * switching period and tranistion to next state switching. - * @details \b Inputs: currentBalChamberSwitchingCounter, balChamberSwitchingPeriod + * switching period and transition to next state switching. + * @details \b Inputs: currentBalChamberSwitchingCounter, balChamberSwitchingPeriod, + * isBalChamberSwitchingOffRequested, balanceChamberSwitchingOnlyOffRequested * @details \b Outputs: balChamberFillPressureDropCounter,balChamberFillCompleteStablePressureCounter + * isBalChamberSwitchingOnRequested, isBalChamberSwitchingOffRequested, isBalChamberSwitchingActive, + * balanceChamberSwitchingOnlyOffRequested * @details \b Alarm: ALARM_ID_DD_BC_STATE1_FILL_PRESSURE_DROP_OUT_OF_RANGE - * when pressure drop is not in range during balacing chamber fill in progress. + * when pressure drop is not in range during balancing chamber fill in progress. * @details \b Alarm: ALARM_ID_DD_BC_STATE1_FILL_END_PRESSURE_OUT_OF_RANGE - * when pressure is not in range during balacing chamber fill complete. + * when pressure is not in range during balancing chamber fill complete. * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillEnd( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE1_FILL_END; - // On completion of cycle time, transition to next state - if ( currentBalChamberSwitchingCounter >= balChamberSwitchingPeriod ) - { - balChamberFillPressureDropCounter = 0; - balChamberFillCompleteStablePressureCounter = 0; + balChamberFillPressureDropCounter = 0; + balChamberFillCompleteStablePressureCounter = 0; - if ( TRUE != getBalChamberSwitchingOnlyStatus() ) + if ( TRUE != getBalChamberSwitchingOnlyStatus() ) + { + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { - if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + if ( ( TRUE != isPressureDroppedDuringFill ) && ( TRUE == isFirstCycleBCSwitchingCompleted ) ) { - if ( ( TRUE != isPressureDroppedDuringFill ) && ( TRUE == isFirstCycleBCSwitchingCompleted ) ) - { - // When fill initiated, pressure is not dropped to the expected range, possible valve failures. - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_PRESSURE_DROP_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); - } - else if ( TRUE != isPressureStalbilizedDuringFill ) - { - // Alarm when switching time expired, but still pressure not in range which indicates fill is not yet completed. - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_END_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); - } - else - { - // Move to next state when pressure is in range. - state = BAL_CHAMBER_STATE2_FILL_START; - } + // When fill initiated, pressure is not dropped to the expected range, possible valve failures. + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_PRESSURE_DROP_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; } + else if ( TRUE != isPressureStabilizedDuringFill ) + { + // Alarm when switching time expired, but still pressure not in range which indicates fill is not yet completed. + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_END_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; + } else { - // Allow to proceed next state even though pressure is not stabilized. + // Move to next state when pressure is in range. state = BAL_CHAMBER_STATE2_FILL_START; } } else { + // Allow to proceed next state even though pressure is not stabilized. state = BAL_CHAMBER_STATE2_FILL_START; } } + else + { // For Balancing Chamber Switch Only command, change state as per the switching period + if ( currentBalChamberSwitchingCounter >= balChamberSwitchingPeriod ) + { + state = BAL_CHAMBER_STATE2_FILL_START; + } + } + // Clear the switching only on request flag. + balanceChamberSwitchingOnlyOnRequested = FALSE; + + // Check if switching only off was requested + if ( TRUE == balanceChamberSwitchingOnlyOffRequested ) + { + // Clear the Switch only off request flag + balanceChamberSwitchingOnlyOffRequested = FALSE; + + //Clear the switch only flag + setBalChamberSwitchingOnlyStatus( FALSE ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; + } + + // Keep Clearing the On request flag in case an On request was made while the switching is active + isBalChamberSwitchingOnRequested = FALSE; + + // Check if a request made was to deactivate the balancing chamber switching. + if ( TRUE == isBalChamberSwitchingOffRequested ) + { + //Clear the request flag to indicate that the request was processed. + isBalChamberSwitchingOffRequested = FALSE; + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; + } + return state; } @@ -613,28 +824,56 @@ * @details \b Inputs: fresh and spent dialysate pressure * @details \b Outputs: valve states * @details \b Alarm: ALARM_ID_DD_BC_STATE2_FILL_START_PRESSURE_OUT_OF_RANGE - * when pressure is not in range during balacing chamber state 2 fill start. + * when pressure is not in range during balancing chamber state 2 fill start. * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2FillStart( void ) { + F32 acidVolume; + F32 bicarbVolume; BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE2_FILL_START; - currentBalChamberSwitchingCounter = 0; + isBalChamberFillInProgress = FALSE; - isPressureStalbilizedDuringFill = FALSE; + isPressureStabilizedDuringFill = FALSE; isPressureDroppedDuringFill = FALSE; balChamberSWState = BAL_CHAMBER_SW_STATE2; + balChamberFillTimeoutCount = 0; + lastPrevSpentDialPressure = 0.0F; + prevSpentDialPressure = 0.0F; + currentBalChamberSwitchingCounter = 0; + currentBalChamberFillCounter = 0; + spentFillRiseHitCount = 0; + spentFillRiseMissCounter = 0; + isSpentFillComplete = FALSE; - F32 acidVolume = getF32OverrideValue( &acidDoseVolume ); - F32 bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); - freshDialPressure = getFilteredPressure( D18_PRES ); - spentDialPressure = getFilteredPressure( D51_PRES ); + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == TRUE ) + { + bicarbVolume = getBicarbMixVol(); + acidVolume = getAcidMixVol(); + } + else + { + acidVolume = getF32OverrideValue( &acidDoseVolume ); + bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); + } + freshDialPressure = getFilteredPressure( D18_PRES ); + spentDialPressure = getFilteredPressure( D51_PRES ); - // Check fresh and spent dialysate pressure in range - if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) && - ( ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ) ) || - ( TRUE == getBalChamberSwitchingOnlyStatus() ) || ( TRUE == getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) ) ) + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) == TRUE ) { + //Set Trimmer heater Target temp every BC cycle to catch up fresh dialysate temp + setHeaterTargetTemperature( D45_HEAT, getFilteredTemperatureValue( D4_TEMP ) ); + } + else + { + //Set Trimmer heater Target temp every BC cycle to catch up fresh dialysate temp + setHeaterTargetTemperature( D45_HEAT, getFilteredTemperatureValue( D99_TEMP ) ); + } + + // Check fresh dialysate pressure in range + if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) || + ( TRUE == getBalChamberSwitchingOnlyStatus() ) || ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) ) ) + { // Valve control for state 2 fill valveControlForBCState2FillStart(); @@ -645,8 +884,8 @@ if ( TRUE != getBalChamberSwitchingOnlyStatus() ) { // start acid and bicarb pump with the expected quantity - setConcentratePumpTargetSpeed( D11_PUMP, CONCENTRATE_PUMP_MAX_SPEED, acidVolume ); - setConcentratePumpTargetSpeed( D10_PUMP, CONCENTRATE_PUMP_MAX_SPEED, bicarbVolume ); + setConcentratePumpTargetSpeed( D11_PUMP, DOSING_CONCENTRATE_PUMP_SPEED, acidVolume ); + setConcentratePumpTargetSpeed( D10_PUMP, DOSING_CONCENTRATE_PUMP_SPEED, bicarbVolume ); requestConcentratePumpOn( D11_PUMP ); requestConcentratePumpOn( D10_PUMP ); } @@ -655,12 +894,16 @@ } else { - if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { //Alarm when pressure is not in range SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_START_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; } } + return state; } @@ -675,35 +918,51 @@ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2ValvesClose( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE2_VALVES_CLOSE; + BOOL isBothFillsComplete = FALSE; + BOOL isFirstCycleNotDone = FALSE; + BOOL isFillCompleteOrFirstCycle = FALSE; - freshDialPressure = getFilteredPressure( D18_PRES ); - spentDialPressure = getFilteredPressure( D51_PRES ); + freshDialPressure = getFilteredPressure( D18_PRES ); + spentDialPressure = getFilteredPressure( D51_PRES ); - // Check fresh and spent dialysate pressure back in range to indicate fill complete. - if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + // Check fresh dialysate pressure back in range to indicate fill complete. + if ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) { - if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) && - ( ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ) ) ) + if ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) { - if ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) - { - // stabilized pressure indicating fill is complete - isPressureStalbilizedDuringFill = TRUE; - } + // stabilized pressure indicating fresh side fill is complete + isPressureStabilizedDuringFill = TRUE; } } - else + + // If fill is taking too long, set an alarm for fill timeout + if ( ( balChamberFillTimeoutCount > 0 ) && ( currentBalChamberFillCounter > balChamberFillTimeoutCount ) ) { - isPressureStalbilizedDuringFill = FALSE; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_BC_FILL_TIMEOUT_FAULT, currentBalChamberFillCounter, balChamberFillTimeoutCount ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; } + // Spent side of balancing chamber fill is complete or not + checkSpentFillComplete( spentDialPressure ); + // Check switching cycle time or pressure check for valve closure - if ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) || - ( TRUE == isPressureStalbilizedDuringFill ) ) + isBothFillsComplete = ( TRUE == isSpentFillComplete ) && ( TRUE == isPressureStabilizedDuringFill ); + isFirstCycleNotDone = ( FALSE == isFirstCycleBCSwitchingCompleted ); + + if ( FALSE == getBalChamberSwitchingOnlyStatus() ) { + isFillCompleteOrFirstCycle = isBothFillsComplete || isFirstCycleNotDone; + } + + if ( ( TRUE == isFillCompleteOrFirstCycle ) || + ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) && ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) ) + { // close the valves valveControlForBCState2FillEnd(); isBalChamberFillInProgress = FALSE; + setDialysatePumpTargetRPM( D48_PUMP, getD48PumpSpeedForBCFill(), TRUE ); //Transition to next state state = BAL_CHAMBER_STATE2_FILL_END; @@ -716,8 +975,11 @@ * @brief * The handleBalChamberState2FillEnd function check for the balancing chamber * switching period complete and transition to next state. - * @details \b Inputs: currentBalChamberSwitchingCounter, balChamberSwitchingPeriod - * @details \b Outputs: isPressureStalbilizedDuringFill,isBalChamberFillInProgress + * @details \b Inputs: currentBalChamberSwitchingCounter, balChamberSwitchingPeriod, + * isBalChamberSwitchingOffRequested, balanceChamberSwitchingOnlyOffRequested + * @details \b Outputs: isPressureStabilizedDuringFill,isBalChamberFillInProgress, + * isBalChamberSwitchingOnRequested, isBalChamberSwitchingOffRequested, isBalChamberSwitchingActive, + * balanceChamberSwitchingOnlyOffRequested * @details \b Alarm: ALARM_ID_DD_BC_STATE2_FILL_PRESSURE_DROP_OUT_OF_RANGE * when pressure is not in range during balacing chamber state 2 fill in progress. * @details \b Alarm: ALARM_ID_DD_BC_STATE2_FILL_END_PRESSURE_OUT_OF_RANGE @@ -728,37 +990,34 @@ { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE2_FILL_END; - // On completion of cycle time, transition to next state - if ( currentBalChamberSwitchingCounter >= balChamberSwitchingPeriod ) - { - balChamberFillPressureDropCounter = 0; - balChamberFillCompleteStablePressureCounter = 0; + balChamberFillPressureDropCounter = 0; + balChamberFillCompleteStablePressureCounter = 0; // Pressure alarm check if ( TRUE != getBalChamberSwitchingOnlyStatus() ) { - if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { if ( ( TRUE != isPressureDroppedDuringFill ) && ( TRUE == isFirstCycleBCSwitchingCompleted ) ) { // When fill initiated, pressure is not dropped to the expected range, possible valve failures. SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_PRESSURE_DROP_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; } - else if ( TRUE != isPressureStalbilizedDuringFill ) + else if ( TRUE != isPressureStabilizedDuringFill ) { // Alarm when switching time expired, but still pressure not in range which indicates fill is not completed. SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_END_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; } else { // Move to next state when pressure is in range. state = BAL_CHAMBER_STATE1_FILL_START; - - // Trigger pressure drop alarm after first cycle of balancing chamber switching complete - if ( FALSE == isFirstCycleBCSwitchingCompleted ) - { - isFirstCycleBCSwitchingCompleted = TRUE; - } } } else @@ -769,15 +1028,268 @@ } else { - state = BAL_CHAMBER_STATE1_FILL_START; + // For Balancing Chamber Switch Only command, change state as per the switching period + if ( currentBalChamberSwitchingCounter >= balChamberSwitchingPeriod ) + { + state = BAL_CHAMBER_STATE1_FILL_START; + } } + + // Trigger pressure drop alarm after first cycle of balancing chamber switching complete + if ( FALSE == isFirstCycleBCSwitchingCompleted ) + { + isFirstCycleBCSwitchingCompleted = TRUE; + } + + // Clear the switching only on request flag. + balanceChamberSwitchingOnlyOnRequested = FALSE; + + // Check if switching only off was requested + if ( TRUE == balanceChamberSwitchingOnlyOffRequested ) + { + // Clear the Switch only off request flag + balanceChamberSwitchingOnlyOffRequested = FALSE; + + //Clear the switch only flag + setBalChamberSwitchingOnlyStatus( FALSE ); + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; } + // Keep Clearing the On request flag in case an On request was made while the switching is active + isBalChamberSwitchingOnRequested = FALSE; + + // Check if a request made was to deactivate the balancing chamber switching. + if ( TRUE == isBalChamberSwitchingOffRequested ) + { + // Clear the request flag to indicate that the request was processed. + isBalChamberSwitchingOffRequested = FALSE; + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; + } + return state; } /*********************************************************************//** * @brief + * The handleBalChamberStateIdle function handles balancing chamber idle state. + * @details \b Inputs: isBalChamberSwitchingOnRequested + * @details \b Outputs: isBalChamberSwitchingOnRequested, isBalChamberSwitchingOffRequested, + * isBalChamberSwitchingActive + * @return next balancing chamber state. + *************************************************************************/ +static BAL_CHAMBER_EXEC_STATE_T handleBalChamberStateIdle( void ) +{ + BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE_IDLE; + + // Clear the switching only off request flag. + balanceChamberSwitchingOnlyOffRequested = FALSE; + + // Check if the switching only on was requested + if ( TRUE == balanceChamberSwitchingOnlyOnRequested ) + { + // Clear the switching only on request flag. + balanceChamberSwitchingOnlyOnRequested = FALSE; + + // then set BC switching only flag to ignore pressure check and dosing. + setBalChamberSwitchingOnlyStatus( TRUE ); + + // Set flag to indicate that balancing chamber switching is active + isBalChamberSwitchingActive = TRUE; + + // Move to the start state1 + state = BAL_CHAMBER_STATE1_FILL_START; + } + + // Keep Clearing the off request flag in case an off request was made while we were already in the idle state + isBalChamberSwitchingOffRequested = FALSE; + + // Clear flag to indicate that balancing chamber switching is inactive + isBalChamberSwitchingActive = FALSE; + + // Check if a request made was to activate the balancing chamber switching. + if ( TRUE == isBalChamberSwitchingOnRequested ) + { + //Clear the request flag to indicate that the request was processed. + isBalChamberSwitchingOnRequested = FALSE; + + // Set flag to indicate that balancing chamber switching is active + isBalChamberSwitchingActive = TRUE; + + // Move to the start state1 + state = BAL_CHAMBER_STATE1_FILL_START; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The isSpentFillCompleteByPressure function evaluates whether the spent side of the + * balancing chamber fill is complete from D51 pressure. + * @details \b Inputs: spentDialPressure, qdMlpm, spentFillCompletePresPsig, valve-close period, + * fill counter, Diener pump test config, and D51 slope history for low-Qd slope mode. + * @details \b Outputs: spentFillRiseHitCount, spentFillRiseMissCounter, + * lastPrevSpentDialPressure, prevSpentDialPressure (updated only in slope mode). + * @param spentDialPressure filtered spent dialysate pressure (PSIG). + * @param qdMlpm dialysate flow rate (mL/min). + * @param spentFillCompletePresPsig spent fill complete pressure threshold for current Qd and pump. + * @return TRUE if spent fill is detected this task period; FALSE otherwise. + *************************************************************************/ +static BOOL isSpentFillCompleteByPressure( F32 spentDialPressure, F32 qdMlpm, F32 spentFillCompletePresPsig ) +{ + BOOL useSlopeDetector = ( ( ( TRUE != getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DIENER_2000_PUMP ) ) && + ( qdMlpm <= SPENT_FILL_COMPLETE_QD_SLOPE_MAX_MLPM ) ) ? TRUE : FALSE ); + BOOL state; + + if ( TRUE == useSlopeDetector ) + { + // Gate slope hits near expected valve-close count (current vs balChamberValveClosePeriod +/- tolerance). + U32 detectTolCount = (U32)( (F32)balChamberValveClosePeriod * SPENT_FILL_DETECT_COUNT_TOL_PCT ); + U32 maxDetectCount = balChamberValveClosePeriod + detectTolCount; + U32 minDetectCount = balChamberValveClosePeriod - detectTolCount; + BOOL isDetectionInCountWindow = ( ( currentBalChamberFillCounter >= minDetectCount ) && + ( currentBalChamberFillCounter <= maxDetectCount ) ) ? TRUE : FALSE; + F32 riseDeltaPsi = spentDialPressure - lastPrevSpentDialPressure; + BOOL riseHit = ( riseDeltaPsi > SPENT_FILL_COMPLETE_DP_RISE_PSIG ) ? TRUE : FALSE; + U32 requiredRiseCount; + + // Mid band between low/high spent pressure: require two rise hits. + if ( riseDeltaPsi > SPENT_FILL_SLOPE_SPENT_PRESSURE_HIGH_PSIG ) + { + requiredRiseCount = 1U; + } + else if ( riseDeltaPsi < SPENT_FILL_SLOPE_SPENT_PRESSURE_LOW_PSIG ) + { + requiredRiseCount = ( qdMlpm <= SPENT_FILL_COMPLETE_QD_TWO_HIT_MAX_MLPM ) ? SPENT_FILL_SLOPE_MAX_RISE_HITS : 1U; + } + else + { + requiredRiseCount = 2U; + } + + if ( ( TRUE == riseHit ) && ( TRUE == isDetectionInCountWindow ) ) + { + spentFillRiseHitCount += 1; + spentFillRiseMissCounter = 0; + } + else if ( spentFillRiseHitCount > 0 ) + { + if ( ( FALSE == riseHit ) && ( TRUE == isDetectionInCountWindow ) ) + { + spentFillRiseMissCounter += 1; + + if ( spentFillRiseMissCounter >= 2 ) + { + spentFillRiseHitCount = 0; + spentFillRiseMissCounter = 0; + } + } + } + + lastPrevSpentDialPressure = prevSpentDialPressure; + prevSpentDialPressure = spentDialPressure; + + // Complete on slope hits, or on absolute pressure at period only if Qd > low band (low Qd: slope-only, no absolute-pressure fallback). + state = ( spentFillRiseHitCount >= requiredRiseCount ) ? TRUE : FALSE; + } + else + { + // Not in slope mode (Diener 2000 pump or Qd > SPENT_FILL_COMPLETE_QD_SLOPE_MAX_MLPM): threshold-only spent fill complete. + state = ( spentDialPressure >= spentFillCompletePresPsig ) ? TRUE : FALSE; + } + return state; +} + +/*********************************************************************//** + * @brief + * The checkSpentFillComplete function checks the pressure difference for + * spent side fill completion and adjusts the D48 pump speed to align the + * fill timing close to the switching period time. + * @details \b Inputs: balChamberExecState + * @details \b Outputs: none + * @param spentDialPressure to check the switching time for BC and set D48 speed based on it. + * @return the current state of balancing chamber states. + *************************************************************************/ +static void checkSpentFillComplete( F32 spentDialPressure ) +{ + U32 absDiffSpentFillCount = 0; + U32 adjustedSpeed = 0; + U32 spentDialPumpSpeed = getD48PumpSpeedForBCFill(); + U32 initialD48PumpSpeed = getCalculatedD48PumpSpeedForBCFill(); + U32 minD48Speed = initialD48PumpSpeed - ( initialD48PumpSpeed * D48_SPEED_RANGE_LIMIT ); + U32 maxD48Speed = initialD48PumpSpeed + ( initialD48PumpSpeed * D48_SPEED_RANGE_LIMIT ); + U32 d48SpeedPostRangeCheck = 0; + F32 qdMlpm = getTDDialysateFlowrate(); + BOOL result = FALSE; + F32 spentFillCompletePresPsig; + BOOL isSpentFillCompleteDetected = FALSE; + + // Diener 2000 pump: spent fill complete pressure use legacy 25 PSI. Other pump: depends on Qd. + if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DIENER_2000_PUMP ) ) + { + spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES; + } + else + { + if ( qdMlpm <= QD_THRESHOLD_HIGH_MLPM ) + { + spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES_QD_MID_PSIG; + } + else + { + spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES_QD_HIGH_PSIG; + } + } + + isSpentFillCompleteDetected = isSpentFillCompleteByPressure( spentDialPressure, qdMlpm, spentFillCompletePresPsig ); + + if ( ( TRUE == isSpentFillCompleteDetected ) && ( isSpentFillComplete != TRUE ) ) + { + // Check spent fill time against the balancing chamber closing period + if ( balChamberValveClosePeriod > 0 ) + { + diffSpentFillCompleteCount = balChamberValveClosePeriod - currentBalChamberFillCounter; + absDiffSpentFillCount = abs(diffSpentFillCompleteCount); + adjustedSpeed = ( ( (F32)absDiffSpentFillCount / (F32)balChamberValveClosePeriod ) * spentDialPumpSpeed ) * D48_SPEED_ADJUST_FACTOR; + + // Skip D48 trim in deadband: diff 0..-2 counts (0..100 ms at 50 ms/task); positive band only (larger negative may mean under-fill). + result = ( ( diffSpentFillCompleteCount <= 0 ) && ( diffSpentFillCompleteCount >= -2 ) ) ? TRUE : FALSE; + + if ( FALSE == result ) + { + if ( diffSpentFillCompleteCount < SPENT_DIFF_COUNT_ZERO ) + { + // Increase the D48 pump speed + spentDialPumpSpeed += adjustedSpeed; + } + else + { + //Decrease the D48 pump speed + spentDialPumpSpeed -= adjustedSpeed; + } + + d48SpeedPostRangeCheck = RANGE( spentDialPumpSpeed, minD48Speed, maxD48Speed ); + + // Do not turn on the pump if the switching only is enabled in the standby mode. + if ( FALSE == getBalChamberSwitchingOnlyStatus() ) + { + // Update the D48 pump speed + setD48PumpSpeedForBCFill( d48SpeedPostRangeCheck ); + } + } + } + + //Update spent fill is complete + isSpentFillComplete = TRUE; + } +} + +/*********************************************************************//** + * @brief * The getCurrentBalancingChamberExecState function returns the current state * of the balancing chamber. * @details \b Inputs: balChamberExecState @@ -828,6 +1340,7 @@ * switching only On/Off status. * @details \b Inputs: balanceChamberSwitchingOnly * @details \b Outputs: none + * @param OnOff to set the BC switch status * @return none *************************************************************************/ void setBalChamberSwitchingOnlyStatus( BOOL OnOff ) @@ -901,11 +1414,12 @@ data.balChamberExecState = (U32)balChamberExecState; data.balChamberSWState = (U32)balChamberSWState; data.balChamberSWFreq = getBalChamberSwitchingFreq(); - data.balChamberSwPeriod = balChamberSwitchingPeriod; - data.isBalChamberFillInProgress = isBalChamberFillInProgress; - data.currentBalChamberSwitchingCounter = currentBalChamberSwitchingCounter; - data.isPressureStalbilizedDuringFill = isPressureStalbilizedDuringFill; + data.balChamberSwPeriod = getD48PumpSpeedForBCFill(); + data.isBalChamberFillInProgress = isSpentFillComplete; + data.currentBalChamberSwitchingCounter = currentBalChamberFillCounter; + data.isPressureStabilizedDuringFill = isPressureStabilizedDuringFill; data.balChamberSWOnlyState = balanceChamberSwitchingOnly; + data.isBalChamberSwitchingActive = isBalChamberSwitchingActive; broadcastData( MSG_ID_DD_BAL_CHAMBER_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( BAL_CHAMBER_DATA_T ) ); @@ -993,7 +1507,6 @@ * chamber switching only without dosing delivery and pressure check condition. * @details \b Inputs: tester logged in * @details \b Outputs: tdDialysateFlowrate,balanceChamberSwitchingOnly - * pendingBalanceChamberSwOnlyRequest * @param message set message from Dialin which includes the balancing chamber * to start/stop switching and update switching rate based on the flow rate. * @return TRUE if set request is successful, FALSE if not @@ -1002,7 +1515,7 @@ { BOOL result = FALSE; - // Verify tester has logged in with TD + // Verify tester has logged in with DD if ( TRUE == isTestingActivated() ) { // Verify payload length is valid @@ -1020,17 +1533,18 @@ setTDDialysateFlowrate( payload.flowrate ); // update switching rate transitionToBalChamberFill(); - // then set BC switching only flag to ignore pressure check and dosing. - setBalChamberSwitchingOnlyStatus( TRUE ); + // Set the flag to indicate that a request was made to start the switching only + balanceChamberSwitchingOnlyOnRequested = TRUE; // Now, if the current operating mode is standby mode idle state, execute the balancing chamber switching only control result = requestBCSwitchingOnlyStart(); } //Handle stop command if ( FALSE == payload.startStop ) { - //Reset the flag - setBalChamberSwitchingOnlyStatus( FALSE ); + // Set the flag to indicate that a request was made to stop the switching only + balanceChamberSwitchingOnlyOffRequested = TRUE; + //Stop the BC switching execution only control requestBCSwitchingOnlyStop(); result = TRUE;