/************************************************************************** * * 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 Ultrafiltration.c * * @author (last) Vinayakam Mani * @date (last) 06-May-2026 * * @author (original) Vinayakam Mani * @date (original) 28-Jul-2025 * ***************************************************************************/ #include "BalancingChamber.h" #include "ConcentratePumps.h" #include "Messaging.h" #include "OperationModes.h" #include "TaskGeneral.h" #include "Temperature.h" #include "TDInterface.h" #include "TestSupport.h" #include "Ultrafiltration.h" /** * @addtogroup Ultrafiltration * @{ */ // ********** private definitions ********** #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 ZERO_RATE 0.0F ///< Zero value. // ********** private data ********** 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. // ********** private function prototypes ********** static void updateUFRequest( void ); static void publishUltrafiltrationData( void ); /*********************************************************************//** * @brief * The initUltrafiltration function initializes the ultrafiltration unit. * @details \b Inputs: none * @details \b Outputs: unit variables initialized * @return none *************************************************************************/ void initUltrafiltration( void ) { ufDataPublishInterval.data = UF_DATA_PUBLISH_INTERVAL; ufDataPublishInterval.ovData = UF_DATA_PUBLISH_INTERVAL; ufDataPublishInterval.ovInitData = 0; ufDataPublishInterval.override = OVERRIDE_RESET; isUltrafiltrationRequested = FALSE; currentUFCompCounter = 0; compUFrate = getTDUFRate(); ufDataPublicationTimerCounter = 0; isUFRateUpdated = TRUE; } /*********************************************************************//** * @brief * The transitionToUltrafiltration function prepares for transition to * ultrafiltration. * @details \b Inputs: none * @details \b Outputs: isUltrafiltrationRequested,ufDataPublicationTimerCounter * @return none *************************************************************************/ void transitionToUltrafiltration( void ) { initUltrafiltration(); } /*********************************************************************//** * @brief * 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. *************************************************************************/ void handleUFControl( void ) { F32 balancingError; if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_UF_TEMP_COMPENSATION ) != TRUE ) { 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 compUFrate = getTDUFRate(); // Reset the flag isUFRateUpdated = FALSE; } // Calculate UF volume and determine UF pause/run updateUFRequest(); // UF pump run or stop based on the flag if ( TRUE == isUltrafiltrationRequested ) { setConcentratePumpTargetSpeed( D76_PUMP, compUFrate, DOSING_CONT_VOLUME ); requestConcentratePumpOn( D76_PUMP ); } else { requestConcentratePumpOff( D76_PUMP, FALSE ); } //Publish ultrafiltration data publishUltrafiltrationData(); } /*********************************************************************//** * @brief * 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 ) { F32 qd = getTDDialysateFlowrate(); BOOL bypass = getTDDialyzerBypass(); // update latest UF run/pause request // if qd is zero or dialyzer is bypassed, UF pump should be turn off if ( ( compUFrate > ZERO_RATE ) && ( qd > ZERO_RATE ) && ( FALSE == bypass ) ) { isUltrafiltrationRequested = TRUE; } else { isUltrafiltrationRequested = FALSE; } } /*********************************************************************//** * @brief * The signalUFRateUpdate function sets the flag to udpate the * UF rate. * @details \b Inputs: none * @details \b Outputs: isUFRateUpdated * @return none. *************************************************************************/ void signalUFRateUpdate( void ) { isUFRateUpdated = TRUE; } /*********************************************************************//** * @brief * The publishUltrafiltrationData function broadcasts the ultrafiltration * data at defined interval. * @details \b Inputs: ufDataPublicationTimerCounter * @details \b Outputs: DD ultrafiltration data broadcast message sent * @details \b Message \Sent: MSG_ID_DD_UF_DATA to publish the ultrafiltration * data. * @return none *************************************************************************/ static void publishUltrafiltrationData( void ) { if ( ++ufDataPublicationTimerCounter >= getU32OverrideValue( &ufDataPublishInterval ) ) { UF_DATA_T data; data.ufRate = getTDUFRate(); data.compUFrate = compUFrate; data.isUFRequested = (U32)isUltrafiltrationRequested; broadcastData( MSG_ID_DD_UF_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( UF_DATA_T ) ); ufDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testDDUFDataPublishIntervalOverride function overrides the * DD ultrafiltration data publish interval. * @details \b Inputs: ufDataPublishInterval * @details \b Outputs: ufDataPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the DD ultrafiltration data publish interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testDDUFDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &ufDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /**@}*/