Index: firmware/App/Controllers/BalancingChamber.c =================================================================== diff -u -r8cbea3e2adffedd6d2efce94c2fa0b1d18442685 -r48c4d25d6918813d93165fe4e7fee3bf0c247b7c --- firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 8cbea3e2adffedd6d2efce94c2fa0b1d18442685) +++ firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 48c4d25d6918813d93165fe4e7fee3bf0c247b7c) @@ -8,7 +8,7 @@ * @file BalancingChamber.c * * @author (last) Jashwant Gantyada -* @date (last) 05-Mar-2026 +* @date (last) 13-Mar-2026 * * @author (original) Vinayakam Mani * @date (original) 28-Jan-2025 @@ -21,8 +21,8 @@ #include "DialysatePumps.h" #include "FpgaDD.h" #include "Heaters.h" -#include "ModeStandby.h" #include "ModeGenDialysate.h" +#include "ModeStandby.h" #include "Messaging.h" #include "OperationModes.h" #include "Pressure.h" @@ -49,15 +49,15 @@ #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 SPENT_DIFF_COUNT_DEADBAND 1 ///< Stop changing D48 pump speed when fill difference reaches close to 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 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 ********** @@ -68,7 +68,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 stablized 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. @@ -92,8 +92,9 @@ static F32 prevSpentDialPressure; ///< Previous spent side dialysate pressure static F32 lastPrevSpentDialPressure; ///< Last previous 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; +static BOOL isSpentFillComplete; ///< Flag indicating spent side fill complete. // ********** private function prototypes ********** @@ -141,7 +142,7 @@ balChamberValveClosePeriod = 0; isBalChamberFillInProgress = FALSE; currentBalChamberSwitchingCounter = 0; - isPressureStalbilizedDuringFill = FALSE; + isPressureStabilizedDuringFill = FALSE; lastTdDialysateFlowrate = 0.0F; balChamberDataPublicationTimerCounter = 0; balChamberFillPressureDropCounter = 0; @@ -160,6 +161,7 @@ prevSpentDialPressure = 0.0F; lastPrevSpentDialPressure = 0.0F; currentBalChamberFillCounter = 0; + balChamberFillTimeoutCount = 0; diffSpentFillCompleteCount = 0; isSpentFillComplete = FALSE; } @@ -204,6 +206,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; @@ -466,12 +471,11 @@ currentBalChamberSwitchingCounter = 0; balChamberSWState = BAL_CHAMBER_SW_STATE1; currentBalChamberFillCounter = 0; + balChamberFillTimeoutCount = 0; isBalChamberFillInProgress = FALSE; - isPressureStalbilizedDuringFill = FALSE; + isPressureStabilizedDuringFill = FALSE; isPressureDroppedDuringFill = FALSE; isSpentFillComplete = FALSE; - lastPrevSpentDialPressure = 0.0F; - prevSpentDialPressure = 0.0F; F32 acidVolume = getF32OverrideValue( &acidDoseVolume ); F32 bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); @@ -560,9 +564,6 @@ ( TRUE == isConcentratePumpDosingCompleted( D10_PUMP ) ) ) || ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) { - //Collect first sample of spent pressure - lastPrevSpentDialPressure = prevSpentDialPressure; - prevSpentDialPressure = spentDialPressure; if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) { @@ -590,22 +591,35 @@ 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; + // 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 dialysate pressure back in range to indicate fresh fill complete. if ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) { if ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) { // stabilized pressure indicating fresh side fill is complete - isPressureStalbilizedDuringFill = TRUE; + isPressureStabilizedDuringFill = TRUE; } } // Spent side of balancing chamber fill is complete or not checkSpentFillComplete( spentDialPressure ); // Check both spent and fresh side fill is complete - if ( ( TRUE == isSpentFillComplete ) && ( TRUE == isPressureStalbilizedDuringFill ) || ( FALSE == isFirstCycleBCSwitchingCompleted ) ) + isBothFillsComplete = ( TRUE == isSpentFillComplete ) && ( TRUE == isPressureStabilizedDuringFill ); + isFirstCycleNotDone = ( FALSE == isFirstCycleBCSwitchingCompleted ); + isFillCompleteOrFirstCycle = isBothFillsComplete || isFirstCycleNotDone; + + if ( TRUE == isFillCompleteOrFirstCycle ) { // close the state 1 opened valves valveControlForBCState1FillEnd(); @@ -651,7 +665,7 @@ // 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 ) + 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 ); @@ -707,13 +721,12 @@ 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; - lastPrevSpentDialPressure = 0.0F; - prevSpentDialPressure = 0.0F; F32 acidVolume = getF32OverrideValue( &acidDoseVolume ); F32 bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); @@ -733,7 +746,6 @@ // Check fresh 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_DD_DISABLE_BC_PRESSURE_ALARMS ) ) ) { // Valve control for state 2 fill @@ -777,28 +789,37 @@ 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 ); - - BOOL isFreshDialysatePressureInRange = ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ); - BOOL isSpentDialysatePressureInRange = ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ); - - // Check fresh and spent dialysate pressure back in range to indicate fill complete. + // 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 ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) { // stabilized pressure indicating fresh side fill is complete - isPressureStalbilizedDuringFill = TRUE; + isPressureStabilizedDuringFill = TRUE; } } + // 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 ); + } + // Spent side of balancing chamber fill is complete or not checkSpentFillComplete( spentDialPressure ); // Check switching cycle time or pressure check for valve closure - if ( ( TRUE == isSpentFillComplete ) && ( TRUE == isPressureStalbilizedDuringFill ) || ( FALSE == isFirstCycleBCSwitchingCompleted ) ) + isBothFillsComplete = ( TRUE == isSpentFillComplete ) && ( TRUE == isPressureStabilizedDuringFill ); + isFirstCycleNotDone = ( FALSE == isFirstCycleBCSwitchingCompleted ); + isFillCompleteOrFirstCycle = isBothFillsComplete || isFirstCycleNotDone; + + if ( TRUE == isFillCompleteOrFirstCycle ) { // close the valves valveControlForBCState2FillEnd(); @@ -845,7 +866,7 @@ // 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 ); @@ -929,11 +950,11 @@ * 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 ) { - F32 diffInSpentPressure = 0.0F; U32 absDiffSpentFillCount = 0; U32 adjustedSpeed = 0; U32 spentDialPumpSpeed = getD48PumpSpeedForBCFill(); @@ -942,11 +963,16 @@ U32 maxD48Speed = initialD48PumpSpeed + ( initialD48PumpSpeed * D48_SPEED_RANGE_LIMIT ); U32 d48SpeedPostRangeCheck = 0; F32 qdMlpm = getTDDialysateFlowrate(); + BOOL result = FALSE; F32 spentFillCompletePresPsig; - // Diener 1000 pump: spent fill complete pressure depends on Qd (7/15/20 PSI). Other pump: use legacy 25 PSI. - if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DIENER_1000_PUMP ) ) + // 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; @@ -960,27 +986,17 @@ spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES_QD_HIGH_PSIG; } } - else - { - spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES; - } - // Collect the next sample of spent pressure - lastPrevSpentDialPressure = prevSpentDialPressure; - prevSpentDialPressure = spentDialPressure; - // find the pressure difference for pressure spike detection - diffInSpentPressure = fabs(spentDialPressure - lastPrevSpentDialPressure); - 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; - //Not adjust the D48 pump speed if the fill counter is just 50ms difference from the closing period. - if ( 0 == ( ( diffSpentFillCompleteCount <= 0 ) && ( diffSpentFillCompleteCount >= -2 ) ) ) - //if ( absDiffSpentFillCount > SPENT_DIFF_COUNT_DEADBAND ) + 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 ) { @@ -1056,6 +1072,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 ) @@ -1132,7 +1149,7 @@ data.balChamberSwPeriod = getD48PumpSpeedForBCFill(); data.isBalChamberFillInProgress = isSpentFillComplete; data.currentBalChamberSwitchingCounter = currentBalChamberFillCounter; - data.isPressureStabilizedDuringFill = isPressureStalbilizedDuringFill; + data.isPressureStabilizedDuringFill = isPressureStabilizedDuringFill; data.balChamberSWOnlyState = balanceChamberSwitchingOnly; data.isBalChamberSwitchingActive = isBalChamberSwitchingActive; Index: firmware/App/Controllers/BalancingChamber.h =================================================================== diff -u -r0bcd9e3ddfeb40efa313e7ed8d8d58f996a13960 -r48c4d25d6918813d93165fe4e7fee3bf0c247b7c --- firmware/App/Controllers/BalancingChamber.h (.../BalancingChamber.h) (revision 0bcd9e3ddfeb40efa313e7ed8d8d58f996a13960) +++ firmware/App/Controllers/BalancingChamber.h (.../BalancingChamber.h) (revision 48c4d25d6918813d93165fe4e7fee3bf0c247b7c) @@ -8,7 +8,7 @@ * @file BalancingChamber.h * * @author (last) Jashwant Gantyada -* @date (last) 05-Mar-2026 +* @date (last) 06-Mar-2026 * * @author (original) Vinayakam Mani * @date (original) 28-Jan-2025 Index: firmware/App/Controllers/Ultrafiltration.c =================================================================== diff -u -r5d60262836ddc8f80ac98f07f2cfd6707a5b7b79 -r48c4d25d6918813d93165fe4e7fee3bf0c247b7c --- firmware/App/Controllers/Ultrafiltration.c (.../Ultrafiltration.c) (revision 5d60262836ddc8f80ac98f07f2cfd6707a5b7b79) +++ firmware/App/Controllers/Ultrafiltration.c (.../Ultrafiltration.c) (revision 48c4d25d6918813d93165fe4e7fee3bf0c247b7c) @@ -97,16 +97,31 @@ * @details \b Outputs: ufExecState * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when wrong ultrafiltration * state invoked. + * @details Warning: The compensated UF should be caclulated first and then + * call 'updateUFRequest' function. * @return current state. *************************************************************************/ U32 execUFControl( void ) { + // Trimmer heater enabled, hence UF temp compensation is optional + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_UF_TEMP_COMPENSATION ) != TRUE ) + { + // Compensate balancing error at defined interval + UpdateUFCompensation(); + } + else if ( TRUE == isUFRateUpdated ) + { + //get updated UF rate + compUFrate = getTDUFRate(); + + // Update UF rate + setConcentratePumpTargetSpeed( D76_PUMP, compUFrate, DOSING_CONT_VOLUME ); + isUFRateUpdated = FALSE; + } + // Calculate UF volume and determine UF pause/run updateUFRequest(); - // Compensate balancing error at defined interval - UpdateUFCompensation(); - // execute current ultrafiltration exec state switch ( ufExecState ) { @@ -181,17 +196,16 @@ /*********************************************************************//** * @brief - * The updateUFRequest function updates the ultrafiltration rate per iteration - * and of the ultrafiltration. - * @details \b Inputs: TD Uf rate, TD Dialysate flow rate and bypass flag - * @details \b Outputs: ufVolumeperIteration , isUltrafiltrationRequested + * The updateUFRequest function updates the ultrafiltration requested + * flag to true or false based on the compensated UF rate. + * @details \b Inputs: compensated UF + * @details \b Outputs: isUltrafiltrationRequested * @return none. *************************************************************************/ static void updateUFRequest( void ) { // update latest UF run/pause request - if ( ( getTDUFRate() > ZERO_RATE ) && ( TRUE != getTDDialyzerBypass() ) && - ( getTDDialysateFlowrate() > ZERO_RATE ) ) + if ( compUFrate > ZERO_RATE ) { isUltrafiltrationRequested = TRUE; } @@ -226,12 +240,26 @@ { if ( ( ++currentUFCompCounter >= UF_COMP_INTERVAL ) || ( TRUE == isUFRateUpdated ) ) { - F32 freshDensity = ( COMP_SLOPE * getD4AverageTemperature() ) + COMP_INTERCEPT; // Fresh side dialysate density - F32 spentDensity = ( COMP_SLOPE * getD50AverageTemperature() ) + COMP_INTERCEPT; // spent side dialysate density - F32 compFreshFlowrate = getTDDialysateFlowrate() * freshDensity; // Qd * fresh density - F32 compSpentFlowrate = getTDDialysateFlowrate() * spentDensity; // Qd * spent density - F32 balancingError = compFreshFlowrate - compSpentFlowrate; // Error in g/min + F32 freshDensity = 0.0F; + F32 spentDensity = 0.0F; + F32 compFreshFlowrate = 0.0F; + F32 compSpentFlowrate = 0.0F; + F32 balancingError = 0.0F; + // Fresh side dialysate density + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) == TRUE ) + { + freshDensity = ( COMP_SLOPE * getD4AverageTemperature() ) + COMP_INTERCEPT; + } + else + { + freshDensity = ( COMP_SLOPE * getD99AverageTemperature() ) + COMP_INTERCEPT; + } + spentDensity = ( COMP_SLOPE * getD50AverageTemperature() ) + COMP_INTERCEPT; // spent side dialysate density + compFreshFlowrate = getTDDialysateFlowrate() * freshDensity; // Qd * fresh density + compSpentFlowrate = getTDDialysateFlowrate() * spentDensity; // Qd * spent density + balancingError = compFreshFlowrate - compSpentFlowrate; // Error in g/min + //Update compensate UF rate with the balancing chamber error compUFrate = getTDUFRate() + balancingError; Index: firmware/App/DDCommon.h =================================================================== diff -u -rd703b8b0f4ab05f7d0f9b9a91be7cf89e914f6ed -r48c4d25d6918813d93165fe4e7fee3bf0c247b7c --- firmware/App/DDCommon.h (.../DDCommon.h) (revision d703b8b0f4ab05f7d0f9b9a91be7cf89e914f6ed) +++ firmware/App/DDCommon.h (.../DDCommon.h) (revision 48c4d25d6918813d93165fe4e7fee3bf0c247b7c) @@ -7,8 +7,8 @@ * * @file DDCommon.h * -* @author (last) Sameer Kalliadan Poyil -* @date (last) 10-Feb-2026 +* @author (last) Jashwant Gantyada +* @date (last) 13-Mar-2026 * * @author (original) Vinayakam Mani * @date (original) 07-Aug-2024 @@ -54,10 +54,6 @@ //Uncomment below to disable heaters debug message #define __HEATERS_DEBUG__ 1 -//Uncomment below to disable Teensy conductivity driver -#define __TEENSY_CONDUCTIVITY_DRIVER__ 1 - - #include #include #endif Index: firmware/App/Modes/ModeGenDialysate.c =================================================================== diff -u -r0bcd9e3ddfeb40efa313e7ed8d8d58f996a13960 -r48c4d25d6918813d93165fe4e7fee3bf0c247b7c --- firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 0bcd9e3ddfeb40efa313e7ed8d8d58f996a13960) +++ firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 48c4d25d6918813d93165fe4e7fee3bf0c247b7c) @@ -7,8 +7,8 @@ * * @file ModeGenDialysate.c * -* @author (last) Vinayakam Mani -* @date (last) 11-Feb-2026 +* @author (last) Jashwant Gantyada +* @date (last) 13-Mar-2026 * * @author (original) Vinayakam Mani * @date (original) 06-Nov-2024 @@ -63,15 +63,15 @@ #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 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 { @@ -112,6 +112,7 @@ static void checkDialysateTemperature( void ); static void monitorChamberLevelStatus( void ); static void publishGenDialysateModeData( void ); +static U32 getFreshDialPumpInitialRpm( void ); /*********************************************************************//** * @brief @@ -145,7 +146,7 @@ bicarbFillStartTimeMS = 0; pendingSpentChamberFill = FALSE; pendingBicarbChamberFill = FALSE; - d48PumpSpeed = getD48MinPumpRPM(); + d48PumpSpeed = getDialysatePumpMinRPM( D48_PUMP ); //Testing bypassStateDelayStartTimeMS = 0; delayBypassStateFlag = TRUE; @@ -210,6 +211,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 @@ -267,7 +288,7 @@ //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 ); + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); //setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, FALSE ); setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); @@ -315,7 +336,7 @@ startHeater( D45_HEAT ); //setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); //setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, FALSE ); setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); @@ -367,10 +388,8 @@ setHeaterTargetTemperature( D5_HEAT, getGenDialysateTargetTemperature() ); setD28TempFeedbackControl( TRUE ); startHeater( D5_HEAT ); - // Stop trimmer heater - stopHeater( D45_HEAT ); - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_FILL_RPM, TRUE ); //Rinse pump On @@ -684,19 +703,32 @@ F32 dialFlowrate = getTDDialysateFlowrate(); F32 slope; F32 intercept; + F32 calculatedSpeed; + U32 rpm; - if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DIENER_1000_PUMP ) ) + 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; } - else + + // Calculate nominal speed from Qd. + calculatedSpeed = ( slope * dialFlowrate ) + intercept; + + // Prevent negative before converting to unsigned and round up using ceilf. + if ( calculatedSpeed < 0.0F ) { - slope = PUMP_SPEED_SLOPE_FACTOR_DIENER_2000; - intercept = PUMP_SPEED_INTERCEPT_FACTOR_DIENER_2000; + calculatedSpeed = 0.0F; } - return (U32)( ( slope * dialFlowrate ) + intercept ); + rpm = (U32)ceilf( calculatedSpeed ); + + return rpm; } /*********************************************************************//** Index: firmware/App/Services/Messaging.c =================================================================== diff -u -r7d942b84ed7e3d45772cd7e4617f5670f66a12ff -r48c4d25d6918813d93165fe4e7fee3bf0c247b7c --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision 7d942b84ed7e3d45772cd7e4617f5670f66a12ff) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 48c4d25d6918813d93165fe4e7fee3bf0c247b7c) @@ -129,28 +129,21 @@ { MSG_ID_DD_PRESSURE_SENSOR_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testDDPressureSensorDataPublishIntervalOverride }, { MSG_ID_DD_PRESSURE_SENSOR_FILTER_READINGS_OVERRIDE_REQUEST, &testDDPressureSensorFilteredReadingsOverride }, { MSG_ID_DD_PRESSURE_SENSOR_FILTER_TEMPERATURE_OVERRIDE_REQUEST, &testDDPressureSensorFilteredTemperatureReadingsOverride }, -#ifdef __TEENSY_CONDUCTIVITY_DRIVER__ + { MSG_ID_DD_CONDUCTIVITY_SENSOR_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testDDConductivitySensorDataPublishIntervalOverride }, { MSG_ID_FP_CONDUCTIVITY_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testFPConductivitySensorDataPublishIntervalOverride }, + { MSG_ID_DD_CONDUCTIVITY_SENSOR_READINGS_OVERRIDE_REQUEST, &testConductivitySensorReadingsOverride }, + { MSG_ID_DD_CONDUCTIVITY_SENSOR_TEMPERATURE_OVERRIDE_REQUEST, &testConductivitySensorTemperatureOverride }, + { MSG_ID_FP_CONDUCTIVITY_SENSOR_READINGS_OVERRIDE_REQUEST, &testConductivitySensorReadingsOverride }, + { MSG_ID_FP_CONDUCTIVITY_SENSOR_TEMPERATURE_OVERRIDE_REQUEST, &testConductivitySensorTemperatureOverride }, { MSG_ID_DD_SET_CONDUCTIVITY_MODEL_REQUEST, &testSetTeenyConductivityModel }, - { MSG_ID_DD_CONDUCTIVITY_SENSOR_READINGS_OVERRIDE_REQUEST, &testTeensyConductivitySensorReadingsOverride }, - { MSG_ID_DD_CONDUCTIVITY_SENSOR_TEMPERATURE_OVERRIDE_REQUEST, &testTeensyConductivitySensorTemperatureReadingsOverride }, { MSG_ID_DD_CONDUCTIVITY_SENSOR_RESISTANCE_OVERRIDE_REQUEST, &testTeensyConductivitySensorResistanceReadingsOverride }, - { MSG_ID_FP_CONDUCTIVITY_OVERRIDE_REQUEST, &testTeensyConductivitySensorReadingsOverride }, - { MSG_ID_FP_CONDUCTIVITY_TEMP_OVERRIDE_REQUEST, &testTeensyConductivitySensorTemperatureReadingsOverride }, { MSG_ID_FP_CONDUCTIVITY_SENSOR_RESISTANCE_OVERRIDE_REQUEST, &testTeensyConductivitySensorResistanceReadingsOverride }, -#else - { MSG_ID_DD_CONDUCTIVITY_SENSOR_READINGS_OVERRIDE_REQUEST, &testDDConductivitySensorReadingsOverride }, - { MSG_ID_DD_CONDUCTIVITY_SENSOR_TEMPERATURE_OVERRIDE_REQUEST, &testDDConductivitySensorTemperatureReadingsOverride }, - { MSG_ID_DD_CONDUCTIVITY_SENSOR_READ_COUNTER_OVERRIDE_REQUEST, &testDDConductivitySensorReadCounterOverride }, - { MSG_ID_DD_CONDUCTIVITY_SENSOR_ERROR_COUNTER_OVERRIDE_REQUEST, &testDDConductivitySensorErrorCounterOverride }, - { MSG_ID_DD_CONDUCTIVITY_SENSOR_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testDDConductivitySensorDataPublishIntervalOverride }, - { MSG_ID_FP_CONDUCTIVITY_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testFPConductivitySensorDataPublishIntervalOverride }, - { MSG_ID_FP_CONDUCTIVITY_OVERRIDE_REQUEST, &testFPConductivitySensorReadingsOverride }, - { MSG_ID_FP_CONDUCTIVITY_TEMP_OVERRIDE_REQUEST, &testFPConductivitySensorTemperatureReadingsOverride }, - { MSG_ID_FP_CONDUCTIVITY_READ_COUNT_OVERRIDE_REQUEST, &testFPConductivitySensorReadCounterOverride }, - { MSG_ID_FP_CONDUCTIVITY_ERROR_COUNT_OVERRIDE_REQUEST, &testFPConductivitySensorErrorCounterOverride }, -#endif + { MSG_ID_DD_CONDUCTIVITY_SENSOR_CONDUCTIVITY_READ_COUNTER_OVERRIDE_REQUEST, &testConductivitySensorConductivityReadCounterOverride }, + { MSG_ID_DD_CONDUCTIVITY_SENSOR_CONDUCTIVITY_ERROR_COUNTER_OVERRIDE_REQUEST, &testConductivitySensorConductivityErrorCounterOverride }, + { MSG_ID_FP_CONDUCTIVITY_SENSOR_CONDUCTIVITY_READ_COUNT_OVERRIDE_REQUEST, &testConductivitySensorConductivityReadCounterOverride }, + { MSG_ID_FP_CONDUCTIVITY_SENSOR_CONDUCTIVITY_ERROR_COUNT_OVERRIDE_REQUEST, &testConductivitySensorConductivityErrorCounterOverride }, + { MSG_ID_DD_CONCENTRATE_PUMP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testConcentratePumpDataPublishIntervalOverride }, { MSG_ID_DD_CONCENTRATE_PUMP_TARGET_SPEED_OVERRIDE_REQUEST, &testConcentratePumpTargetSpeedOverride }, { MSG_ID_DD_CONCENTRATE_PUMP_MEASURED_SPEED_OVERRIDE_REQUEST, &testConcentratePumpMeasuredSpeedOverride },