Index: firmware/App/Controllers/BalancingChamber.c =================================================================== diff -u -r7d24ef2e6a4130b3a049e6106a0371fc6503271f -r97a38c5fddfc9e5dbebfae9742cbf82d2d1a3487 --- firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 7d24ef2e6a4130b3a049e6106a0371fc6503271f) +++ firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 97a38c5fddfc9e5dbebfae9742cbf82d2d1a3487) @@ -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 +*f +* @author (last) Dara Navaei +* @date (last) 18-Mar-2026 * -* @author (last) Vinayakam Mani -* @date (last) 24-Oct-2024 -* * @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" // For request setBicarbChamberFillRequested #include "FpgaDD.h" #include "Heaters.h" +#include "ModeGenDialysate.h" #include "ModeStandby.h" #include "Messaging.h" #include "OperationModes.h" @@ -41,12 +43,23 @@ #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 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,7 +70,7 @@ 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. @@ -71,7 +84,17 @@ static F32 lastTdDialysateFlowrate; ///< Previous TD dialysate flow rate static F32 freshDialPressure; ///< Fresh side dialysate pressure static F32 spentDialPressure; ///< Spent side dialysate pressure +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 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. +//TODO: remove later once level sensor working +static U32 bicarbChamberPeriodicFillCounter; + // ********** private function prototypes ********** static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillStart( void ); @@ -81,8 +104,10 @@ 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 ); /*********************************************************************//** * @brief @@ -93,7 +118,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; @@ -116,7 +141,7 @@ balChamberValveClosePeriod = 0; isBalChamberFillInProgress = FALSE; currentBalChamberSwitchingCounter = 0; - isPressureStalbilizedDuringFill = FALSE; + isPressureStabilizedDuringFill = FALSE; lastTdDialysateFlowrate = 0.0F; balChamberDataPublicationTimerCounter = 0; balChamberFillPressureDropCounter = 0; @@ -125,6 +150,17 @@ isPressureDroppedDuringFill = FALSE; freshDialPressure = 0.0F; spentDialPressure = 0.0F; + isBalChamberSwitchingActive = FALSE; + isBalChamberSwitchingOnRequested = FALSE; + isBalChamberSwitchingOffRequested = FALSE; + + //TODO:remove once level sensor working + bicarbChamberPeriodicFillCounter = 0; + + currentBalChamberFillCounter = 0; + balChamberFillTimeoutCount = 0; + diffSpentFillCompleteCount = 0; + isSpentFillComplete = FALSE; } /*********************************************************************//** @@ -167,6 +203,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; @@ -191,12 +230,29 @@ { // 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 ) + { + // 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 +289,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 +301,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 +475,52 @@ * @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; + currentBalChamberFillCounter = 0; + balChamberFillTimeoutCount = 0; isBalChamberFillInProgress = FALSE; - isPressureStalbilizedDuringFill = FALSE; + isPressureStabilizedDuringFill = FALSE; isPressureDroppedDuringFill = FALSE; - balChamberSWState = BAL_CHAMBER_SW_STATE1; + isSpentFillComplete = FALSE; - F32 acidVolume = getF32OverrideValue( &acidDoseVolume ); - F32 bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == TRUE ) + { + bicarbVolume = getBicarbDoseVol(); + acidVolume = getAcidDoseVol(); + } + else + { + acidVolume = getF32OverrideValue( &acidDoseVolume ); + bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); + } + freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); - // 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 ) ) ) + 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(); @@ -441,7 +541,7 @@ } 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 ); @@ -454,7 +554,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 +565,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,6 +588,7 @@ ( TRUE == isConcentratePumpDosingCompleted( D10_PUMP ) ) ) || ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) { + if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) { state = BAL_CHAMBER_STATE1_VALVES_CLOSE; @@ -512,37 +613,48 @@ 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 ) + // 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 ) { // 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 +664,69 @@ /*********************************************************************//** * @brief * The handleBalChamberState1FillEnd function check for the balancing chamber - * switching period and tranistion to next state switching. + * switching period and transition to next state switching. * @details \b Inputs: currentBalChamberSwitchingCounter, balChamberSwitchingPeriod * @details \b Outputs: balChamberFillPressureDropCounter,balChamberFillCompleteStablePressureCounter * @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 ); } + 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 ); + } 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; + } + // 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; + + // Clear the flag to indicate that balancing chamber switching is inactive + isBalChamberSwitchingActive = FALSE; + + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; + } + return state; } @@ -613,28 +737,51 @@ * @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; + currentBalChamberFillCounter = 0; + balChamberFillTimeoutCount = 0; + isSpentFillComplete = FALSE; - F32 acidVolume = getF32OverrideValue( &acidDoseVolume ); - F32 bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == TRUE ) + { + bicarbVolume = getBicarbDoseVol(); + acidVolume = getAcidDoseVol(); + } + 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, 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(); @@ -655,12 +802,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_STATE2_FILL_START_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } } + return state; } @@ -675,35 +823,46 @@ 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 ); } + // 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 ) { // 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; @@ -728,23 +887,20 @@ { 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 ); } - 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 ); @@ -753,12 +909,6 @@ { // 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 +921,141 @@ { state = BAL_CHAMBER_STATE1_FILL_START; } + + // Trigger pressure drop alarm after first cycle of balancing chamber switching complete + if ( FALSE == isFirstCycleBCSwitchingCompleted ) + { + isFirstCycleBCSwitchingCompleted = TRUE; + } + + // 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; + + // Clear flag to indicate that balancing chamber switching is inactive + isBalChamberSwitchingActive = 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: isBalChamberSwitchingActive + * @return next balancing chamber state. + *************************************************************************/ +static BAL_CHAMBER_EXEC_STATE_T handleBalChamberStateIdle( void ) +{ + BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE_IDLE; + + // Keep Clearing the off request flag in case an off request was made while we were already in the idle state + isBalChamberSwitchingOffRequested = 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 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; + + // 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; + } + } + + if ( ( spentDialPressure >= spentFillCompletePresPsig ) && ( isSpentFillComplete != TRUE ) ) + { + // Check spent fill time against the balancing chamber closing period + 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 ); + + // 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 +1106,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 +1180,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 +1273,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 +1281,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