Index: firmware/App/Controllers/BalancingChamber.c =================================================================== diff -u -r7d24ef2e6a4130b3a049e6106a0371fc6503271f -rdeba34e5074da9ac97d8bcbe995f554eec5c70ed --- firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 7d24ef2e6a4130b3a049e6106a0371fc6503271f) +++ firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision deba34e5074da9ac97d8bcbe995f554eec5c70ed) @@ -1,26 +1,28 @@ /************************************************************************** * -* 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) Dara Navaei +* @date (last) 18-Mar-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 "ModeGenDialysate.h" #include "ModeStandby.h" #include "Messaging.h" #include "OperationModes.h" @@ -41,12 +43,30 @@ #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_LOW_PSIG 3.5F ///< Spent fill complete pressure (PSI) when Diener 1000 and Qd <= 200. +#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_LOW_MLPM 200.0F ///< Qd threshold (mL/min) below which low pressure limit applies. +#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,6 +93,19 @@ 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 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. +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. +//TODO: remove later once level sensor working +static U32 bicarbChamberPeriodicFillCounter; // ********** private function prototypes ********** @@ -81,8 +116,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 +131,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 +150,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 +164,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 +220,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 +232,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 +254,33 @@ *************************************************************************/ U32 execBalancingChamberControl( void ) { + 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) + { + // 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; + } + } + 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 +317,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 +329,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 +503,58 @@ * @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 = getBicarbDoseVol(); + acidVolume = getAcidDoseVol(); + } + else + { + 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 ); + + lastPrevSpentDialPressure = spentDialPressure; + + 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, getD4AverageTemperature() ); + } + else + { + //Set Trimmer heater Target temp every BC cycle to catch up fresh dialysate temp + setHeaterTargetTemperature( D45_HEAT, getD99AverageTemperature() ); + } + + // 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 +565,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 +575,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,7 +591,7 @@ /*********************************************************************//** * @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. @@ -465,7 +602,7 @@ freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); - if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) + if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) { state = BAL_CHAMBER_STATE1_BICARB_ACID_DOSING_CNTRL; } @@ -488,13 +625,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 +653,52 @@ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1ValvesClose( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE1_VALVES_CLOSE; + freshDialPressure = getFilteredPressure( D18_PRES ); + spentDialPressure = getFilteredPressure( D51_PRES ); + BOOL isBothFillsComplete = FALSE; + BOOL isFirstCycleNotDone = FALSE; + BOOL isFillCompleteOrFirstCycle = FALSE; - freshDialPressure = getFilteredPressure( D18_PRES ); - spentDialPressure = getFilteredPressure( D51_PRES ); + // If fill is taking too long, set an alarm for fill timeout + if ( ( balChamberFillTimeoutCount > 0 ) && ( currentBalChamberFillCounter > balChamberFillTimeoutCount ) ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_BC_FILL_TIMEOUT_FAULT, currentBalChamberFillCounter, balChamberFillTimeoutCount ); - // Check fresh and spent dialysate pressure back in range to indicate fill complete. - if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + // 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 ( ( ( 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 - { - isPressureStalbilizedDuringFill = FALSE; - } - // Switching time met or pressure in range, close valves - if ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) || - ( TRUE == isPressureStalbilizedDuringFill ) ) + // 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 ); + isFillCompleteOrFirstCycle = isBothFillsComplete || isFirstCycleNotDone; + + if ( ( TRUE == isFillCompleteOrFirstCycle ) || + ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) && ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) ) { // close the state 1 opened valves valveControlForBCState1FillEnd(); isBalChamberFillInProgress = FALSE; + //setDialysatePumpTargetRPM( D48_PUMP, getD48PumpSpeedForBCFill(), TRUE ); + if ( TRUE == isFirstCycleBCSwitchingCompleted ) + { + setDialysatePumpTargetRPM( D48_PUMP, getD48PumpSpeedForBCFill(), TRUE ); + } - //Transition to next state + // Transition to next state state = BAL_CHAMBER_STATE1_FILL_END; } @@ -552,57 +708,92 @@ /*********************************************************************//** * @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 + { + 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 +804,58 @@ * @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 = getBicarbDoseVol(); + acidVolume = getAcidDoseVol(); + } + else + { + acidVolume = getF32OverrideValue( &acidDoseVolume ); + bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); + } - // 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 ) ) ) + freshDialPressure = getFilteredPressure( D18_PRES ); + spentDialPressure = getFilteredPressure( D51_PRES ); + + lastPrevSpentDialPressure = spentDialPressure; + + 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, getD4AverageTemperature() ); + } + else + { + //Set Trimmer heater Target temp every BC cycle to catch up fresh dialysate temp + setHeaterTargetTemperature( D45_HEAT, getD99AverageTemperature() ); + } + + // 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 +866,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 +876,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 +900,51 @@ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2ValvesClose( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE2_VALVES_CLOSE; + freshDialPressure = getFilteredPressure( D18_PRES ); + spentDialPressure = getFilteredPressure( D51_PRES ); + BOOL isBothFillsComplete = FALSE; + BOOL isFirstCycleNotDone = FALSE; + BOOL isFillCompleteOrFirstCycle = FALSE; - 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 ); + isFillCompleteOrFirstCycle = isBothFillsComplete || isFirstCycleNotDone; + + if ( ( TRUE == isFillCompleteOrFirstCycle ) || + ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) && ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) ) { // close the valves valveControlForBCState2FillEnd(); isBalChamberFillInProgress = FALSE; + //setDialysatePumpTargetRPM( D48_PUMP, getD48PumpSpeedForBCFill(), TRUE ); + if ( TRUE == isFirstCycleBCSwitchingCompleted ) + { + setDialysatePumpTargetRPM( D48_PUMP, getD48PumpSpeedForBCFill(), TRUE ); + } //Transition to next state state = BAL_CHAMBER_STATE2_FILL_END; @@ -716,8 +957,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 +972,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 @@ -771,13 +1012,259 @@ { 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 ) ); + + if ( TRUE == useSlopeDetector ) + { + 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 ) ); + F32 riseDeltaPsi = spentDialPressure - lastPrevSpentDialPressure; + BOOL riseHit = ( riseDeltaPsi > SPENT_FILL_COMPLETE_DP_RISE_PSIG ); + U32 requiredRiseCount; + + 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 = 1U; + } + + 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; + + return ( ( spentFillRiseHitCount >= requiredRiseCount ) || + ( ( currentBalChamberFillCounter >= balChamberValveClosePeriod ) && + ( spentDialPressure >= spentFillCompletePresPsig ) ) ); + } + + return ( spentDialPressure >= spentFillCompletePresPsig ); +} + +/*********************************************************************//** + * @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_LOW_MLPM ) + { + spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES_QD_LOW_PSIG; + } + 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; + + result = ( ( diffSpentFillCompleteCount <= 0 ) && ( diffSpentFillCompleteCount >= -2 ) ) ? TRUE : FALSE; + //Not adjust the D48 pump speed if the fill counter is just 50ms difference from the closing period (considering only positive DEADBAND as negative deadband might indicate under fill of BC). + 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 +1315,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 +1389,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 +1482,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 +1490,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 +1508,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;