Index: firmware/App/Controllers/Ultrafiltration.c =================================================================== diff -u -r94789b2f2324d5901685b6ff7b6224d4af3a0276 -r3f88f2878bfb58d9b67e05ed0717f6fbff136232 --- firmware/App/Controllers/Ultrafiltration.c (.../Ultrafiltration.c) (revision 94789b2f2324d5901685b6ff7b6224d4af3a0276) +++ firmware/App/Controllers/Ultrafiltration.c (.../Ultrafiltration.c) (revision 3f88f2878bfb58d9b67e05ed0717f6fbff136232) @@ -7,16 +7,18 @@ * * @file Ultrafiltration.c * -* @author (last) Vinayakam Mani -* @date (last) 14-Apr-2026 +* @author (last) Santhosh Reddy +* @date (last) 06-Jul-2026 * * @author (original) Vinayakam Mani * @date (original) 28-Jul-2025 * ***************************************************************************/ +#include "BalancingChamber.h" #include "ConcentratePumps.h" #include "Messaging.h" +#include "ModeGenDialysate.h" #include "OperationModes.h" #include "TaskGeneral.h" #include "Temperature.h" @@ -34,26 +36,22 @@ #define UF_DATA_PUBLISH_INTERVAL ( 1000 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the ultrafiltration data published. #define UF_COMPENSATION_PERIOD ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Interval at which the ultrafiltration compenstaion executed. #define UF_COMP_INTERVAL ( UF_COMPENSATION_PERIOD / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the peroidic ultrafiltration compensation calculated. -#define COMP_SLOPE -0.000376F ///< UF Temperature compensation slope factor -#define COMP_INTERCEPT 1.007269F ///< UF temperature compensation intercept factor #define ZERO_RATE 0.0F ///< Zero value. +#define UF_VOL_ML_PER_TASK_INTERVAL ( (F32)TASK_GENERAL_INTERVAL / ( (F32)MS_PER_SECOND * (F32)SEC_PER_MIN ) ) ///< UF volume (mL) delivered per task interval at 1 mL/min. // ********** private data ********** -static UF_EXEC_STATE_T ufExecState; ///< Current ultrafiltration executive state. static BOOL isUltrafiltrationRequested; ///< Flag indicating ultrafiltration request. static U32 currentUFCompCounter; ///< Counter (in task interval) to initiate the periodic ultrafiltration temperature compensation. static F32 compUFrate; ///< compensated UF rate static U32 ufDataPublicationTimerCounter; ///< Used to schedule ultrafiltration data publication to CAN bus. static BOOL isUFRateUpdated; ///< flag indicating to update UF rate needed. static OVERRIDE_U32_T ufDataPublishInterval; ///< Ultrafiltration data publish interval. +static F32 ufVolumeDeliveredMl; ///< Accumulated UF volume since last reset (mL); shared by delivery and isolated UF. // ********** private function prototypes ********** -static UF_EXEC_STATE_T handleUFRunningState( void ); -static UF_EXEC_STATE_T handleUFPausedState( void ); static void updateUFRequest( void ); -static void UpdateUFCompensation( void ); static void publishUltrafiltrationData( void ); /*********************************************************************//** @@ -65,7 +63,6 @@ *************************************************************************/ void initUltrafiltration( void ) { - ufExecState = DD_UF_PAUSED; ufDataPublishInterval.data = UF_DATA_PUBLISH_INTERVAL; ufDataPublishInterval.ovData = UF_DATA_PUBLISH_INTERVAL; ufDataPublishInterval.ovInitData = 0; @@ -74,7 +71,8 @@ currentUFCompCounter = 0; compUFrate = getTDUFRate(); ufDataPublicationTimerCounter = 0; - isUFRateUpdated = FALSE; + isUFRateUpdated = TRUE; + ufVolumeDeliveredMl = 0.0F; } /*********************************************************************//** @@ -92,106 +90,77 @@ /*********************************************************************//** * @brief - * The execUFControl function executes the ultrafiltration state machine. - * @details \b Inputs: ufExecState - * @details \b Outputs: ufExecState - * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when wrong ultrafiltration - * state invoked. + * The handleUFControl function handles the ultrafiltration run/stop states + * and calcualtes the final ultrafilration rate if the temp compensation is enbaled. + * @details \b Inputs: balancing error, TD UF rate + * @details \b Outputs: calculated UF rate * @details Warning: The compensated UF should be caclulated first and then * call 'updateUFRequest' function. * @return current state. *************************************************************************/ -U32 execUFControl( void ) +void handleUFControl( void ) { - // Trimmer heater enabled, hence UF temp compensation is optional + F32 balancingError; + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_UF_TEMP_COMPENSATION ) != TRUE ) { - // Compensate balancing error at defined interval - UpdateUFCompensation(); + if ( ( ++currentUFCompCounter >= UF_COMP_INTERVAL ) || ( TRUE == isUFRateUpdated ) ) + { + // Find the offset + balancingError = getBalancingChamberError(); + // Update compensate UF rate with the balancing chamber error + compUFrate = getTDUFRate() + balancingError; + + currentUFCompCounter = 0; + isUFRateUpdated = FALSE; + } } else if ( TRUE == isUFRateUpdated ) { - //get updated UF rate + // Get updated UF rate compUFrate = getTDUFRate(); - - // Update UF rate - setConcentratePumpTargetSpeed( D76_PUMP, compUFrate, DOSING_CONT_VOLUME ); - isUFRateUpdated = FALSE; + // Reset the flag + isUFRateUpdated = FALSE; } // Calculate UF volume and determine UF pause/run updateUFRequest(); - // execute current ultrafiltration exec state - switch ( ufExecState ) - { - case DD_UF_PAUSED: - ufExecState = handleUFPausedState(); - break; - - case DD_UF_RUNNING: - ufExecState = handleUFRunningState(); - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_UF_INVALID_EXEC_STATE, ufExecState ) - ufExecState = DD_UF_PAUSED; - break; - } - - //Publish ultrafiltration data - publishUltrafiltrationData(); - - return ufExecState; -} - -/*********************************************************************//** - * @brief - * The handleUFPausedState function handles the ultrafiltration - * paused state. - * @details \b Inputs:isUltrafiltrationRequested - * @details \b Outputs: UF state - * @return next UF state. - *************************************************************************/ -static UF_EXEC_STATE_T handleUFPausedState( void ) -{ - UF_EXEC_STATE_T state = DD_UF_PAUSED; - + // UF pump run or stop based on the flag if ( TRUE == isUltrafiltrationRequested ) { - // start with TD UF rate - compUFrate = getTDUFRate(); - currentUFCompCounter = 0; - setConcentratePumpTargetSpeed( D76_PUMP, compUFrate, DOSING_CONT_VOLUME ); requestConcentratePumpOn( D76_PUMP ); - - //Tranistion to run state - state = DD_UF_RUNNING; + ufVolumeDeliveredMl += ( compUFrate * UF_VOL_ML_PER_TASK_INTERVAL ); } + else + { + requestConcentratePumpOff( D76_PUMP, FALSE ); + } - return state; + //Publish ultrafiltration data + publishUltrafiltrationData(); } /*********************************************************************//** * @brief - * The handleUFPausedState function handles the ultrafiltration - * running state. - * @details \b Inputs:isUltrafiltrationRequested - * @details \b Outputs: UF state - * @return next UF state. + * The stopUltrafiltration function stops the UF pump and clears the run + * request flag. + * @details \b Inputs: isUltrafiltrationRequested + * @details \b Outputs: isUltrafiltrationRequested, D76 pump off + * @return none *************************************************************************/ -static UF_EXEC_STATE_T handleUFRunningState( void ) +void stopUltrafiltration( void ) { - UF_EXEC_STATE_T state = DD_UF_RUNNING; + BOOL prevUFState = isUltrafiltrationRequested; - if ( TRUE != isUltrafiltrationRequested ) + isUltrafiltrationRequested = FALSE; + requestConcentratePumpOff( D76_PUMP, FALSE ); + + if ( prevUFState != isUltrafiltrationRequested ) { - requestConcentratePumpOff( D76_PUMP, FALSE ); - state = DD_UF_PAUSED; + SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_UF_PUMP_ON_OFF, prevUFState, isUltrafiltrationRequested ); } - - return state; } /*********************************************************************//** @@ -204,15 +173,34 @@ *************************************************************************/ static void updateUFRequest( void ) { - // update latest UF run/pause request - if ( compUFrate > ZERO_RATE ) + F32 qd = getTDDialysateFlowrate(); + BOOL prevUFState = isUltrafiltrationRequested; + BOOL allowUF = FALSE; + + // Isolated UF may run with Qd = 0; delivery UF requires Qd > 0 + if ( DD_GEND_ISOLATED_UF_STATE == getCurrentGenDialysateState() ) { + allowUF = TRUE; + } + else if ( qd > ZERO_RATE ) + { + allowUF = TRUE; + } + + if ( ( compUFrate > ZERO_RATE ) && ( TRUE == allowUF ) ) + { isUltrafiltrationRequested = TRUE; } else { isUltrafiltrationRequested = FALSE; } + + // event update on state switch + if( prevUFState != isUltrafiltrationRequested ) + { + SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_UF_PUMP_ON_OFF, prevUFState, isUltrafiltrationRequested ); + } } /*********************************************************************//** @@ -230,58 +218,27 @@ /*********************************************************************//** * @brief - * The UpdateUFCompensation function updates the ultrafiltration rate - * based on the dialysate temperature compensation. - * @details \b Inputs: D4 and D50 temperature - * @details \b Outputs: updated UF rate - * @return none. + * The resetUFVolumeDelivered function clears the accumulated UF volume. + * @details \b Inputs: none + * @details \b Outputs: ufVolumeDeliveredMl + * @return none *************************************************************************/ -static void UpdateUFCompensation( void ) +void resetUFVolumeDelivered( void ) { - if ( ( ++currentUFCompCounter >= UF_COMP_INTERVAL ) || ( TRUE == isUFRateUpdated ) ) - { - 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 * getFilteredTemperatureValue( D4_TEMP ) ) + COMP_INTERCEPT; - } - else - { - freshDensity = ( COMP_SLOPE * getFilteredTemperatureValue( D99_TEMP ) ) + COMP_INTERCEPT; - } - spentDensity = ( COMP_SLOPE * getFilteredTemperatureValue( D50_TEMP ) ) + 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; - - // Update UF rate - setConcentratePumpTargetSpeed( D76_PUMP, compUFrate, DOSING_CONT_VOLUME ); - - currentUFCompCounter = 0; - isUFRateUpdated = FALSE; - } + ufVolumeDeliveredMl = 0.0F; } /*********************************************************************//** * @brief - * The getCurrentUFExecState function returns the current state - * of the ultrafiltration. - * @details \b Inputs: ufExecState + * The getUFVolumeDeliveredLiters function returns the accumulated UF volume + * delivered in liters. + * @details \b Inputs: ufVolumeDeliveredMl * @details \b Outputs: none - * @return the current state of UF execution state. + * @return Accumulated UF volume delivered in L. *************************************************************************/ -UF_EXEC_STATE_T getCurrentUFExecState( void ) +F32 getUFVolumeDeliveredLiters( void ) { - return ufExecState; + return ( ufVolumeDeliveredMl / (F32)ML_PER_LITER ); } /*********************************************************************//** @@ -300,10 +257,10 @@ { UF_DATA_T data; - data.ufExecState = (U32)ufExecState; data.ufRate = getTDUFRate(); data.compUFrate = compUFrate; data.isUFRequested = (U32)isUltrafiltrationRequested; + data.ufVolumeDeliveredMl = ufVolumeDeliveredMl; broadcastData( MSG_ID_DD_UF_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( UF_DATA_T ) );