Index: firmware/App/Modes/ModeGenDialysate.c =================================================================== diff -u -r573a26b2a0273a4983b1de1cbff5bed63e01dce0 -r623587d96bf6c0bafd3ff94d47f8c783b4b999f0 --- firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 573a26b2a0273a4983b1de1cbff5bed63e01dce0) +++ firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 623587d96bf6c0bafd3ff94d47f8c783b4b999f0) @@ -1,19 +1,20 @@ /************************************************************************** * -* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* Copyright (c) 2024-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 ModeGenDialysate.c * * @author (last) Vinayakam Mani -* @date (last) 30-Oct-2024 +* @date (last) 06-Apr-2026 * * @author (original) Vinayakam Mani -* @date (original) 30-Oct-2024 +* @date (original) 06-Nov-2024 * ***************************************************************************/ +#include // For ceilf #include "BalancingChamber.h" #include "ConcentratePumps.h" @@ -28,9 +29,12 @@ #include "OperationModes.h" #include "PersistentAlarm.h" #include "Pressure.h" +#include "RinsePump.h" +#include "SpentChamberFill.h" #include "TaskGeneral.h" #include "TDInterface.h" #include "Temperature.h" +#include "TestSupport.h" #include "Timers.h" #include "Ultrafiltration.h" #include "Valves.h" @@ -58,9 +62,17 @@ #define LINEAR_SLOPE_FACTOR -0.0029F ///< Slope factor used in adjusted dialysate temperature linear calculation for high Qds #define LINEAR_INTERCEPT_FACTOR 3.47F ///< Intercept factor used in adjusted dialysate temperature linear calculation for high Qds #define LOW_DIAL_FLOW_RATE 150.0F ///< Dialysate flow rate lesser than 150 considered to be low Qds. +#define ZERO_DIAL_FLOW_RATE 0.0F ///< Zero dialysate flow rate +#define SPENT_CHAMBER_FILL_MAX_COUNT 10 ///< Total number of spent chamber fill allowed. +#define BICARB_CHAMBER_FILL_TIMEOUT ( 1 * MS_PER_SECOND ) ///< Bicarb chamber fill timeout. +#define PUMP_SPEED_SLOPE_FACTOR_DIENER_2000 1.24F ///< D48 Diener 2000 pump speed slope (y = 1.24x + 30). +#define PUMP_SPEED_INTERCEPT_FACTOR_DIENER_2000 30.0F ///< D48 Diener 2000 pump speed intercept. +#define PUMP_SPEED_SLOPE_FACTOR_DIENER_1000 2.869F ///< D48 Diener 1000 pump speed slope (y = 2.869x + 25.956). +#define PUMP_SPEED_INTERCEPT_FACTOR_DIENER_1000 25.956F ///< D48 Diener 1000 pump speed intercept. +#define BICARB_CHAMBER_FILL_TIMEOUT ( 1 * MS_PER_SECOND ) ///< Bicarb chamber fill timeout. //Testing -#define DELAY_BC_SWITCHING_AT_START_UP ( 10 * MS_PER_SECOND ) ///< Provide a balancing chamber switching start up delay to stabilize pump speed etc., +#define DELAY_BC_SWITCHING_AT_START_UP ( 10 * MS_PER_SECOND ) ///< Provide a balancing chamber switching start up delay to stabilize pump speed etc., /// Payload record structure for Gen dialysate execution state set request typedef struct { @@ -69,29 +81,39 @@ // ********** private data ********** -static DD_GEND_MODE_STATE_T genDialysateState = DD_GEND_STATE_START; ///< Currently active gen dialysate state. +static DD_GEND_MODE_STATE_T genDialysateState; ///< Currently active gen dialysate state. static OVERRIDE_F32_T targetHydChamberFluidTemp; ///< Target hydraulics chamber fluid temperature. static OVERRIDE_U32_T isDialDeliveryInProgress; ///< To indicate dialysate started delivering to dialyzer for treatment (overrideable) static OVERRIDE_U32_T isDialysateGoodtoDeliver; ///< Flag indicating whether ready to deliver dialysate or not. +static BOOL pendingSpentChamberFill; ///< Flag indicating spent chamber fill process to be initiated. +static BOOL pendingBicarbChamberFill; ///< Flag indicating bicarb chamber fill process to be initiated. static BOOL pendingStopDDGenDialRequest; ///< Flag indicating TD has requested DD stop the generate dialysate. static U32 genDialysateDataPublicationTimerCounter; ///< Used to schedule generate dialysate data publication to CAN bus. static OVERRIDE_U32_T genDialysateDataPublishInterval; ///< Generate dialysate mode data publish interval. static BOOL isTreatmentParamUpdated; ///< To indicate change in treatment parameters +static U32 bicarbFillStartTimeMS; ///< Bicarb fill start time to check the timeout for filling process. //Testing static U32 bypassStateDelayStartTimeMS; ///< Delay balancing chamber switching for a second to preapre pump steady state. static BOOL delayBypassStateFlag; ///< To indicate change in treatment parameters +static F32 dialysateToDialyzerFlowRate; ///< Current dialysate to dialyzer flow rate (ml/min) +static U32 d48PumpSpeed; ///< Initial D48 pump speed based on the Qd. // ********** private function prototypes ********** static void setModeGenDStateTransition( DD_GEND_MODE_STATE_T state ); static DD_GEND_MODE_STATE_T handleGenDDialysateBypassState( void ); static DD_GEND_MODE_STATE_T handleGenDDialysateDeliveryState( void ); static DD_GEND_MODE_STATE_T handleGenDDialysateDeliveryPauseState( void ); -static DD_GEND_MODE_STATE_T handleGenDDialysateIsolatedUFState( void ); +static DD_GEND_MODE_STATE_T handleGenDSpentChamberFillState(void); +static DD_GEND_MODE_STATE_T handleGenDBicarbChamberFillState( void ); +static DD_GEND_MODE_STATE_T handleGenDIsolatedUFState( void ); static F32 getGenDialysateTargetTemperature( void ); -static void checkDialysateTemperature( void ); static void calculateTargetDialysateTemp( void ); +static void updateDialysateToDialyzerFlowRate( void ); +static void checkDialysateTemperature( void ); +static void monitorChamberLevelStatus( void ); static void publishGenDialysateModeData( void ); +static U32 getFreshDialPumpInitialRpm( void ); /*********************************************************************//** * @brief @@ -122,9 +144,14 @@ genDialysateDataPublishInterval.override = OVERRIDE_RESET; genDialysateDataPublicationTimerCounter = 0; isTreatmentParamUpdated = FALSE; + bicarbFillStartTimeMS = 0; + pendingSpentChamberFill = FALSE; + pendingBicarbChamberFill = FALSE; + d48PumpSpeed = getDialysatePumpMinRPM( D48_PUMP ); //Testing bypassStateDelayStartTimeMS = 0; delayBypassStateFlag = TRUE; + dialysateToDialyzerFlowRate = 0.0F; //Initialize balancing chamber module initBalanceChamber(); @@ -144,8 +171,13 @@ *************************************************************************/ U32 transitionToGenDialysateMode( void ) { + U32 initialD48PumpSpeed = 0U; + initGenDialysateMode(); setCurrentSubState( NO_SUB_STATE ); + //calculateD48PumpSpeedForBCFill(); + initialD48PumpSpeed = getCalculatedD48PumpSpeedForBCFill(); + setD48PumpSpeedForBCFill( initialD48PumpSpeed ); transitionToUltrafiltration(); return genDialysateState; @@ -178,6 +210,26 @@ /*********************************************************************//** * @brief + * The getFreshDialPumpInitialRpm function returns fresh dialysate pump initial + * rpm based on hardwawre configuration. + * @details Inputs: FRESH_DIAL_PUMP_INITIAL_RPM, FRESH_DIAL_PUMP_INITIAL_RPM_B1_9_B2_0 + * @details Outputs: none + * @return fresh dialysate pump initial RPM for the active hardware variant + *************************************************************************/ +static U32 getFreshDialPumpInitialRpm( void ) +{ + U32 rpm = FRESH_DIAL_PUMP_INITIAL_RPM_B1_9_B2_0; + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) ) + { + rpm = FRESH_DIAL_PUMP_INITIAL_RPM; + } + + return rpm; +} + +/*********************************************************************//** + * @brief * The setModeGenDStateTransition function sets the actuators and variables * for the state transition in generate dialysis mode. * @details Inputs: Valve states, Pump speed @@ -195,72 +247,225 @@ break; case DD_GEND_DIALYSATE_BYPASS_STATE: - //Previous state - setValveState( DD_M4_VALV, VALVE_STATE_OPEN ); - // Get the target temperature from TD - //targetHydChamberFluidTemp.data = getTDTargetDialysateTemperature(); - calculateTargetDialysateTemp(); + setValveState( D14_VALV, VALVE_STATE_OPEN ); + setValveState( D53_VALV, VALVE_STATE_OPEN ); // Drain valve + setValveState( D35_VALV, VALVE_STATE_CLOSED ); // VDI + setValveState( D40_VALV, VALVE_STATE_CLOSED ); // VDO + setValveState( D47_VALV, VALVE_STATE_CLOSED ); // spent chamber purge valve + setValveState( D34_VALV, VALVE_STATE_OPEN ); // Bypass valve + setValveState( D8_VALV, VALVE_STATE_CLOSED ); + setValveState( D54_VALV, VALVE_STATE_CLOSED ); + setValveState( D81_VALV, VALVE_STATE_CLOSED ); + setValveState( D85_VALV, VALVE_STATE_CLOSED ); + setValveState( D31_VALV, VALVE_STATE_CLOSED ); + + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == FALSE ) + { + setValveState( D80_VALV, VALVE_STATE_OPEN ); // Bicarb valve + setValveState( D64_VALV, VALVE_STATE_CLOSED ); + } + // Turn on the primary heater + calculateTargetDialysateTemp(); setHeaterTargetTemperature( D5_HEAT, getGenDialysateTargetTemperature() ); + setD28TempFeedbackControl( TRUE ); startHeater( D5_HEAT ); - setValveState( D14_VALV, VALVE_STATE_OPEN ); + //Turn on Trimmer heater + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) == TRUE ) + { + setHeaterTargetTemperature( D45_HEAT, getD4AverageTemperature() ); + } + else + { + setHeaterTargetTemperature( D45_HEAT, getD99AverageTemperature() ); + } + startHeater( D45_HEAT ); + //Testing : Enable close loop once testing is complete //setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); - setValveState( D53_VALV, VALVE_STATE_OPEN ); // Drain valve - setValveState( D35_VALV, VALVE_STATE_CLOSED ); // VDI - setValveState( D40_VALV, VALVE_STATE_CLOSED ); // VDO - setValveState( D34_VALV, VALVE_STATE_OPEN ); // Bypass valve + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); //setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); + //Rinse pump On + setRinsePumpState( RINSE_PUMP_STATE_ON ); + transitionToBalChamberFill(); //Testing bypassStateDelayStartTimeMS = getMSTimerCount(); + delayBypassStateFlag = TRUE; break; case DD_GEND_DIALYSATE_DELIVERY_STATE: //Previous state - setValveState( DD_M4_VALV, VALVE_STATE_OPEN ); - // Get the target temperature from TD - //targetHydChamberFluidTemp.data = getTDTargetDialysateTemperature(); + setValveState( D47_VALV, VALVE_STATE_CLOSED ); // spent chamber purge valve + setValveState( D8_VALV, VALVE_STATE_CLOSED ); + setValveState( D54_VALV, VALVE_STATE_CLOSED ); + setValveState( D81_VALV, VALVE_STATE_CLOSED ); + setValveState( D85_VALV, VALVE_STATE_CLOSED ); + setValveState( D31_VALV, VALVE_STATE_CLOSED ); + setValveState( D14_VALV, VALVE_STATE_OPEN ); + setValveState( D53_VALV, VALVE_STATE_OPEN ); // Drain valve + + // Turn on the primary heater calculateTargetDialysateTemp(); setHeaterTargetTemperature( D5_HEAT, getGenDialysateTargetTemperature() ); + setD28TempFeedbackControl( TRUE ); startHeater( D5_HEAT ); - setValveState( D14_VALV, VALVE_STATE_OPEN ); + + //Turn on Trimmer heater + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) == TRUE ) + { + setHeaterTargetTemperature( D45_HEAT, getD4AverageTemperature() ); + } + else + { + setHeaterTargetTemperature( D45_HEAT, getD99AverageTemperature() ); + } + startHeater( D45_HEAT ); + //setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); - setValveState( D53_VALV, VALVE_STATE_OPEN ); // Drain valve + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); //setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); + //Rinse pump On + setRinsePumpState( RINSE_PUMP_STATE_ON ); + // Disable bypass valve setValveState( D34_VALV, VALVE_STATE_CLOSED ); // Bypass valve setValveState( D35_VALV, VALVE_STATE_OPEN ); // VDI setValveState( D40_VALV, VALVE_STATE_OPEN ); // VDO + + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == FALSE ) + { + setValveState( D80_VALV, VALVE_STATE_OPEN ); // Bicarb valve + setValveState( D64_VALV, VALVE_STATE_CLOSED ); + } break; - case DD_GEND_DIALYSATE_DELIVERY_PAUSE: - // stop the motor during pause conditions - signalDialysatePumpHardStop( D12_PUMP ); - signalDialysatePumpHardStop( D48_PUMP ); + case DD_GEND_SPENT_CHAMBER_FILL_STATE: + //Set valves and actuators + setValveState( D35_VALV, VALVE_STATE_CLOSED ); // VDI + setValveState( D40_VALV, VALVE_STATE_CLOSED ); // VDO + setValveState( D8_VALV, VALVE_STATE_CLOSED ); + setValveState( D54_VALV, VALVE_STATE_CLOSED ); + setValveState( D81_VALV, VALVE_STATE_CLOSED ); + setValveState( D85_VALV, VALVE_STATE_CLOSED ); + setValveState( D31_VALV, VALVE_STATE_CLOSED ); + setValveState( D14_VALV, VALVE_STATE_OPEN ); + setValveState( D53_VALV, VALVE_STATE_OPEN ); // Drain valve + setValveState( D34_VALV, VALVE_STATE_OPEN ); // Bypass valve + + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == FALSE ) + { + setValveState( D80_VALV, VALVE_STATE_OPEN ); // Bicarb valve + setValveState( D64_VALV, VALVE_STATE_CLOSED ); + } + + setValveState( D47_VALV, VALVE_STATE_OPEN ); // Spent chamber purge valve + + requestConcentratePumpOff( D76_PUMP, FALSE ); requestConcentratePumpOff( D11_PUMP, FALSE ); requestConcentratePumpOff( D10_PUMP, FALSE ); - requestConcentratePumpOff( D76_PUMP, FALSE ); - stopHeater( D5_HEAT ); + // Turn on the primary heater + calculateTargetDialysateTemp(); + setHeaterTargetTemperature( D5_HEAT, getGenDialysateTargetTemperature() ); + setD28TempFeedbackControl( TRUE ); + startHeater( D5_HEAT ); + // Stop trimmer heater stopHeater( D45_HEAT ); - //Enable bypass valve + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); + setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_FILL_RPM, TRUE ); + + //Rinse pump On + setRinsePumpState( RINSE_PUMP_STATE_ON ); + + //Transition to spent chamber fill + transitionToSpentChamberFill(); + break; + + case DD_GEND_BICARB_CHAMBER_FILL_STATE: + requestConcentratePumpOff( D11_PUMP, FALSE ); + requestConcentratePumpOff( D10_PUMP, FALSE ); + requestConcentratePumpOff( D76_PUMP, FALSE ); + + //Set valves and actuators + setValveState( D47_VALV, VALVE_STATE_CLOSED ); // spent chamber purge valve setValveState( D35_VALV, VALVE_STATE_CLOSED ); // VDI setValveState( D40_VALV, VALVE_STATE_CLOSED ); // VDO + setValveState( D14_VALV, VALVE_STATE_CLOSED ); + + setValveState( D53_VALV, VALVE_STATE_OPEN ); // Drain valve setValveState( D34_VALV, VALVE_STATE_OPEN ); // Bypass valve - //TODO : close the DD - water inlet and drain valves? + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == FALSE ) + { + setValveState( D80_VALV, VALVE_STATE_OPEN ); // Bicarb valve + setValveState( D64_VALV, VALVE_STATE_OPEN ); // Bicarb chamber purge valve + } + + bicarbFillStartTimeMS = getMSTimerCount(); + + // Turn on the primary heater + calculateTargetDialysateTemp(); + setHeaterTargetTemperature( D5_HEAT, getGenDialysateTargetTemperature() ); + //Disable the D28 based temp control as fluid dispense being stopped by balancing chamber. + setD28TempFeedbackControl( FALSE ); + startHeater( D5_HEAT ); + + //Rinse pump On + setRinsePumpState( RINSE_PUMP_STATE_ON ); + + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); + setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); break; + case DD_GEND_DIALYSATE_DELIVERY_PAUSE: + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); + signalDialysatePumpHardStop( D48_PUMP ); + requestConcentratePumpOff( D11_PUMP, FALSE ); + requestConcentratePumpOff( D10_PUMP, FALSE ); + requestConcentratePumpOff( D76_PUMP, FALSE ); + //Rinse pump Off + setRinsePumpState( RINSE_PUMP_STATE_OFF ); + + // Turn on the primary heater + calculateTargetDialysateTemp(); + setHeaterTargetTemperature( D5_HEAT, getGenDialysateTargetTemperature() ); + //Disable the D28 based temp control as fluid dispense being stopped by balancing chamber. + setD28TempFeedbackControl( FALSE ); + startHeater( D5_HEAT ); + stopHeater( D45_HEAT ); + + //close valves + setValveState( D35_VALV, VALVE_STATE_CLOSED ); + setValveState( D40_VALV, VALVE_STATE_CLOSED ); + setValveState( D31_VALV, VALVE_STATE_CLOSED ); + setValveState( D47_VALV, VALVE_STATE_CLOSED ); + setValveState( D54_VALV, VALVE_STATE_CLOSED ); + setValveState( D14_VALV, VALVE_STATE_CLOSED ); + setValveState( D52_VALV, VALVE_STATE_CLOSED ); + setValveState( D65_VALV, VALVE_STATE_CLOSED ); + setValveState( D81_VALV, VALVE_STATE_CLOSED ); + setValveState( D8_VALV, VALVE_STATE_CLOSED ); + //Close all balancing chamber valves + valveControlForBCClosedState(); + + setValveState( D34_VALV, VALVE_STATE_OPEN ); + setValveState( D53_VALV, VALVE_STATE_OPEN ); + + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DRY_BICARB ) == FALSE ) + { + setValveState( D80_VALV, VALVE_STATE_OPEN ); + setValveState( D64_VALV, VALVE_STATE_CLOSED ); + } + break; + case DD_GEND_ISOLATED_UF_STATE: //TODO : define actuators states break; @@ -292,9 +497,15 @@ checkDialysateTemperature(); #endif + // Update dialysate flow rate only when in the Dialysate Delivery state + updateDialysateToDialyzerFlowRate(); + //Check temperature drift between D30 and D28 checkDialysateTemperatureSensors(); + //Monitor spent and bicarb chamber level + monitorChamberLevelStatus(); + //TODO: Transition to post gen dialysate then standby. if ( TRUE == pendingStopDDGenDialRequest ) { @@ -319,12 +530,20 @@ genDialysateState = handleGenDDialysateDeliveryState(); break; + case DD_GEND_SPENT_CHAMBER_FILL_STATE: + genDialysateState = handleGenDSpentChamberFillState(); + break; + + case DD_GEND_BICARB_CHAMBER_FILL_STATE: + genDialysateState = handleGenDBicarbChamberFillState(); + break; + case DD_GEND_DIALYSATE_DELIVERY_PAUSE: genDialysateState = handleGenDDialysateDeliveryPauseState(); break; case DD_GEND_ISOLATED_UF_STATE: - genDialysateState = handleGenDDialysateIsolatedUFState(); + genDialysateState = handleGenDIsolatedUFState(); break; default: @@ -351,12 +570,10 @@ BOOL hydChamberWaterInletControl( void ) { // Read floater switch - BOOL result = FALSE; - LEVEL_STATE_T floaterLevel = getLevelStatus( D6_LEVL ); + BOOL result = FALSE; + LEVEL_STATE_T floaterLevel = getLevelStatus( D6_LEVL ); + BOOL balancingChambFillInProgress = getBalancingChamberFillinProgressStatus(); - //Make sure Water Inlet Valve is open - setValveState( DD_M4_VALV, VALVE_STATE_OPEN ); - // High level is met if ( LEVEL_STATE_HIGH == floaterLevel ) { @@ -366,7 +583,7 @@ // Water level reached high. result = TRUE; } - else + else if ( LEVEL_STATE_LOW == floaterLevel || TRUE != balancingChambFillInProgress ) { // if level is not met,allow inlet water to hydraulics chamber setValveState( D3_VALV, VALVE_STATE_OPEN ); @@ -377,6 +594,55 @@ /*********************************************************************//** * @brief + * The getD48PumpSpeedForBCFill function returns the calculated D48 pump speed + * @details \b Inputs: d48PumpSpeed + * @details \b Outputs: none + * @return D48 pump speed. + *************************************************************************/ +U32 getD48PumpSpeedForBCFill( void ) +{ + return d48PumpSpeed; +} + +/*********************************************************************//** + * @brief + * The setD48PumpSpeedForBCFill function sets the updated D48 pump speed. + * @details \b Inputs: none + * @details \b Outputs: d48PumpSpeed + * @param pumpSpeed Dialysate pump speed + * @return none. + *************************************************************************/ +void setD48PumpSpeedForBCFill( U32 pumpSpeed ) +{ + d48PumpSpeed = pumpSpeed; +} + +/*********************************************************************//** + * @brief + * The monitorChamberLevelStatus function checks the spent chamber and bicarb + * chamber level status and updates the corrosponding flags. + * @details \b Inputs: Spent and bicarb chamber levels. + * @details \b Outputs: none + * @return none + *************************************************************************/ +static void monitorChamberLevelStatus( void ) +{ + LEVEL_STATE_T spentChamberLevel = getLevelStatus( D46_LEVL ); + LEVEL_STATE_T bicarbChamberLevel = getLevelStatus( D63_LEVL ); + + if ( LEVEL_STATE_LOW == spentChamberLevel ) + { + pendingSpentChamberFill = TRUE; + } + + if ( LEVEL_STATE_LOW == bicarbChamberLevel ) + { + pendingBicarbChamberFill = TRUE; + } +} + +/*********************************************************************//** + * @brief * The calculateTargetDialysateTemp function calculate the delta temperature * required for dialysate temperature to meet the set temperature at dialyzer. * @details \b Inputs: Qd and target temperature. @@ -391,7 +657,7 @@ if ( dialFlowrate >= LOW_DIAL_FLOW_RATE ) { - // linear releationship seen against high dialysate flowrate Vs DeltaTemp + // linear relationship seen against high dialysate flowrate Vs DeltaTemp // deltaTemp = (-0.0029 * Qd) + 3.47 deltaTemp = ( LINEAR_SLOPE_FACTOR * dialFlowrate ) + LINEAR_INTERCEPT_FACTOR; } @@ -408,13 +674,54 @@ /*********************************************************************//** * @brief + * The getCalculatedD48PumpSpeedForBCFill function returns the D48 pump speed + * calculated from dialysate flow rate (Qd) for continuous delivery. + * @details \b Inputs: Qd from TD, test config TEST_CONFIG_DD_ENABLE_DIENER_1000_PUMP. + * @details \b Outputs: none + * @return Calculated D48 pump speed in RPM (Diener 1000 or 2000 formula per test config). + *************************************************************************/ +U32 getCalculatedD48PumpSpeedForBCFill( void ) +{ + F32 dialFlowrate = getTDDialysateFlowrate(); + F32 slope; + F32 intercept; + F32 calculatedSpeed; + U32 rpm; + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DIENER_2000_PUMP ) ) + { + slope = PUMP_SPEED_SLOPE_FACTOR_DIENER_2000; + intercept = PUMP_SPEED_INTERCEPT_FACTOR_DIENER_2000; + } + else + { + slope = PUMP_SPEED_SLOPE_FACTOR_DIENER_1000; + intercept = PUMP_SPEED_INTERCEPT_FACTOR_DIENER_1000; + } + + // Calculate nominal speed from Qd. + calculatedSpeed = ( slope * dialFlowrate ) + intercept; + + // Prevent negative before converting to unsigned and round up using ceilf. + if ( calculatedSpeed < 0.0F ) + { + calculatedSpeed = 0.0F; + } + + rpm = (U32)ceilf( calculatedSpeed ); + + return rpm; +} + +/*********************************************************************//** + * @brief * The handleGenDDialysateIsolatedUFState function performs the * Isolated ultrafiltration operations. * @details \b Inputs: none. * @details \b Outputs: none * @return the current state of gen dialysate mode *************************************************************************/ -static DD_GEND_MODE_STATE_T handleGenDDialysateIsolatedUFState( void ) +static DD_GEND_MODE_STATE_T handleGenDIsolatedUFState( void ) { DD_GEND_MODE_STATE_T state = DD_GEND_ISOLATED_UF_STATE; @@ -434,12 +741,16 @@ *************************************************************************/ static DD_GEND_MODE_STATE_T handleGenDDialysateBypassState( void ) { - DD_GEND_MODE_STATE_T state = DD_GEND_DIALYSATE_BYPASS_STATE; + DD_GEND_MODE_STATE_T state = DD_GEND_DIALYSATE_BYPASS_STATE; + BOOL balancingChambFillInProgress = getBalancingChamberFillinProgressStatus(); + F32 freshDialPressure = getFilteredPressure( D18_PRES ); + F32 spentDialPressure = getFilteredPressure( D51_PRES ); - //Testing + //Testing : Wait for the fresh and spent pressure in range or timeout if ( TRUE == delayBypassStateFlag ) { - if ( TRUE == didTimeout( bypassStateDelayStartTimeMS, DELAY_BC_SWITCHING_AT_START_UP ) ) + if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) ) || + ( TRUE == didTimeout( bypassStateDelayStartTimeMS, DELAY_BC_SWITCHING_AT_START_UP ) ) ) { delayBypassStateFlag = FALSE; } @@ -450,6 +761,25 @@ execBalancingChamberControl(); } + if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_SPENT_CHAMBER_H_FILL ) == TRUE ) + { + if ( ( TRUE == pendingSpentChamberFill ) && ( FALSE == balancingChambFillInProgress ) ) + { + setModeGenDStateTransition( DD_GEND_SPENT_CHAMBER_FILL_STATE ); + pendingSpentChamberFill = FALSE; + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_SPENT_CHAMBER_FILL_STATE; + } + } +#ifdef __BICARB_CHAMBER_FILL__ + if ( ( TRUE == pendingBicarbChamberFill ) && ( FALSE == balancingChambFillInProgress ) ) + { + setModeGenDStateTransition( DD_GEND_BICARB_CHAMBER_FILL_STATE ); + pendingBicarbChamberFill = FALSE; + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_BICARB_CHAMBER_FILL_STATE; + } +#endif //if the produced dialysate is good and TD asks for dialysate delivery //move to next state if ( ( TRUE == getDialGoodToDeliverStatus() ) && ( FALSE == getTDDialyzerBypass() ) ) @@ -472,14 +802,11 @@ *************************************************************************/ static DD_GEND_MODE_STATE_T handleGenDDialysateDeliveryState( void ) { - DD_GEND_MODE_STATE_T state = DD_GEND_DIALYSATE_DELIVERY_STATE; + DD_GEND_MODE_STATE_T state = DD_GEND_DIALYSATE_DELIVERY_STATE; + LEVEL_STATE_T spentChamberLevel = getLevelStatus( D46_LEVL ); + LEVEL_STATE_T bicarbChamberLevel = getLevelStatus( D63_LEVL ); + BOOL balancingChambFillInProgress = getBalancingChamberFillinProgressStatus(); - //Execute balancing chamber - execBalancingChamberControl(); - - //Execute ultrafiltration - execUFControl(); - // if TD asks for bypass or dialysate is not good to deliver //transition to bypass dialystate state if ( ( FALSE == getDialGoodToDeliverStatus() ) || ( TRUE == getTDDialyzerBypass() ) ) @@ -488,12 +815,114 @@ isDialDeliveryInProgress.data = FALSE; state = DD_GEND_DIALYSATE_BYPASS_STATE; } + else if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_SPENT_CHAMBER_H_FILL ) == TRUE ) + { + if ( ( TRUE == pendingSpentChamberFill ) && ( FALSE == balancingChambFillInProgress ) ) + { + setModeGenDStateTransition( DD_GEND_SPENT_CHAMBER_FILL_STATE ); + pendingSpentChamberFill = FALSE; + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_SPENT_CHAMBER_FILL_STATE; + } + } +#ifdef __BICARB_CHAMBER_FILL__ + else if ( ( TRUE == pendingBicarbChamberFill ) && ( FALSE == balancingChambFillInProgress ) ) + { + setModeGenDStateTransition( DD_GEND_BICARB_CHAMBER_FILL_STATE ); + pendingBicarbChamberFill = FALSE; + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_BICARB_CHAMBER_FILL_STATE; + } +#endif + else + { + //Execute balancing chamber + execBalancingChamberControl(); + //Execute ultrafiltration + execUFControl(); + } + return state; } /*********************************************************************//** * @brief + * The handleGenDSpentChamberFillState function performing spent + * chamber filling/degassing by executing balancing chamber. + * @details \b Inputs: D46 level. + * @details \b Outputs: balancing chamber state. + * @return the current state of gen dialysate mode + *************************************************************************/ +static DD_GEND_MODE_STATE_T handleGenDSpentChamberFillState( void ) +{ + DD_GEND_MODE_STATE_T state = DD_GEND_SPENT_CHAMBER_FILL_STATE; + + LEVEL_STATE_T spentChamberLevel = getLevelStatus( D46_LEVL ); + U32 totalSpentChamberFill = getTotalSpentChamberFillCounts(); + + // High level is met or total fill count exceeded + if ( ( LEVEL_STATE_HIGH == spentChamberLevel ) || + ( totalSpentChamberFill >= SPENT_CHAMBER_FILL_MAX_COUNT ) ) + { + setModeGenDStateTransition( DD_GEND_DIALYSATE_BYPASS_STATE ); + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_DIALYSATE_BYPASS_STATE; + + //Trigger alarm if count exceeded + if ( totalSpentChamberFill >= SPENT_CHAMBER_FILL_MAX_COUNT ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SC_FILL_TIMEOUT_FAULT, SPENT_CHAMBER_FILL_MAX_COUNT, 0 ) + } + } + else + { + //Execute Spent chamber fill + execSpentChamberFillControl(); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleGenDBicarbChamberFillState function performing Bicarb + * chamber filling/degassing by opening up the purge valve which is connected + * to negative pressure chamber D of Hydraulics chamber. + * @details \b Inputs: D63 level. + * @details \b Outputs: isBicarbFillTimeout,valves actuation. + * @return the current state of gen dialysate mode + *************************************************************************/ +static DD_GEND_MODE_STATE_T handleGenDBicarbChamberFillState( void ) +{ + DD_GEND_MODE_STATE_T state = DD_GEND_BICARB_CHAMBER_FILL_STATE; + + LEVEL_STATE_T bicarbChamberLevel = getLevelStatus( D63_LEVL ); + BOOL isBicarbFillTimeout = FALSE; + + if ( TRUE == didTimeout( bicarbFillStartTimeMS, BICARB_CHAMBER_FILL_TIMEOUT ) ) + { + isBicarbFillTimeout = TRUE; + // Raise alarm for bicarb fill timeout + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_BICARB_FILL_TIMEOUT_FAULT, BICARB_CHAMBER_FILL_TIMEOUT, 0 ) + } + + // High level is met or fill timeout + if ( ( LEVEL_STATE_HIGH == bicarbChamberLevel ) || ( TRUE == isBicarbFillTimeout ) ) + { + setValveState( D64_VALV, VALVE_STATE_CLOSED ); // Close Bicarb chamber purge valve + bicarbFillStartTimeMS = 0; + + setModeGenDStateTransition( DD_GEND_DIALYSATE_BYPASS_STATE ); + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_DIALYSATE_BYPASS_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief * The requestDDGenDialyasteStop function handles an TD request to stop * generation dialysis mode. * @details \b Inputs: Generation dialysate mode / state @@ -525,8 +954,13 @@ static DD_GEND_MODE_STATE_T handleGenDDialysateDeliveryPauseState( void ) { DD_GEND_MODE_STATE_T state = DD_GEND_DIALYSATE_DELIVERY_PAUSE; + F32 dialFlowrate = getTDDialysateFlowrate(); - //TODO : Handle pause state. + // Resume pause when Qd is not zero + if ( dialFlowrate > ZERO_DIAL_FLOW_RATE ) + { + state = DD_GEND_DIALYSATE_BYPASS_STATE; + } return state; } @@ -568,6 +1002,8 @@ *************************************************************************/ void updateTreatmentSettings( void ) { + F32 initialPumpSpeed = 0.0F; + // Update any dynamic treatment parameter changes if ( TRUE == isTreatmentParamUpdated ) { @@ -586,13 +1022,42 @@ //TODO: update others parameters setting as needed. signalUFRateUpdate(); + //Update D48 pump speed + //calculateD48PumpSpeedForBCFill(); + initialPumpSpeed = getCalculatedD48PumpSpeedForBCFill(); + setD48PumpSpeedForBCFill( initialPumpSpeed ); + //reset the flag isTreatmentParamUpdated = FALSE; } } /*********************************************************************//** * @brief + * The updateDialysateToDialyzerFlowRate function updates the current dialysate + * to dialyzer flow rate only when in the dialysate delivery state, otherwise + * the flow rate is set to zero + * @details \b Inputs: genDialysateState + * @details \b Outputs: dialysateToDialyzerFlowRate + * @return none + *************************************************************************/ +void updateDialysateToDialyzerFlowRate( void ) +{ + // Check the current Gen Dialysate Mode state + if ( DD_GEND_DIALYSATE_DELIVERY_STATE == genDialysateState ) + { + // Update the dialysate flow rate to the TD request + dialysateToDialyzerFlowRate = getTDDialysateFlowrate(); + } + else + { + // Set the dialysate flow rate to zero + dialysateToDialyzerFlowRate = 0.0F; + } +} + +/*********************************************************************//** + * @brief * The getDialGoodToDeliverStatus function gets the dialysate good to deliver * status. * @details \b Inputs: isDialysateGoodtoDeliver @@ -667,7 +1132,7 @@ *************************************************************************/ static void checkDialysateTemperature( void ) { - F32 dialysateTemp = getConductivityTemperatureValue( D29_COND ); // Assuming the closest temp sensor to dialyzer + F32 dialysateTemp = getFilteredConductivitySensorTemperature( D29_COND ); // Assuming the closest temp sensor to dialyzer F32 targetTemp = getTDTargetDialysateTemperature(); BOOL isDialTempAboveHighSafety = ( dialysateTemp >= DIALYSATE_TEMP_UPPER_MAX_SAFETY_LIMIT_C ? TRUE : FALSE ); BOOL isDialTempAboveLowSafety = ( dialysateTemp > DIALYSATE_TEMP_UPPER_SAFETY_LIMIT_C ? TRUE : FALSE ); @@ -726,13 +1191,8 @@ data.genDialysateExecState = (U32)getCurrentGenDialysateState(); data.isDialDelInProgress = (BOOL)getDialDeliveryProgressStatus(); - data.d6Level = (U32)getLevelStatus( D6_LEVL ); - data.d63Level = (U32)getLevelStatus( D63_LEVL ); - data.d46Level = (U32)getLevelStatus( D46_LEVL ); - data.d9Pressure = getFilteredPressure( D9_PRES ); - data.d18Pressure = getFilteredPressure( D18_PRES ); - data.d51Pressure = getFilteredPressure( D51_PRES ); data.isDialysateGoodtoDeliver = (BOOL)getDialGoodToDeliverStatus(); + data.currentQd = dialysateToDialyzerFlowRate; broadcastData( MSG_ID_DD_GEN_DIALYSATE_MODE_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( GEN_DIALYSATE_MODE_DATA_T ) );