Index: firmware/App/Controllers/HemoDiaFiltration.c =================================================================== diff -u -rfff7eb3560421130e0cd4788f84bce0a8ee7ff44 -r8acb1d02ac39d202a47338091b249ff2f30f5ea7 --- firmware/App/Controllers/HemoDiaFiltration.c (.../HemoDiaFiltration.c) (revision fff7eb3560421130e0cd4788f84bce0a8ee7ff44) +++ firmware/App/Controllers/HemoDiaFiltration.c (.../HemoDiaFiltration.c) (revision 8acb1d02ac39d202a47338091b249ff2f30f5ea7) @@ -34,20 +34,21 @@ #define HDF_DATA_PUBLISH_INTERVAL ( 1000 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the hemodiafiltration data published. #define SECONDS_PER_MINUTE 60 ///< seconds per minute -#define HDF_CONTROL_PERIOD_SECONDS 2 ///< Interval at which the hemodiafiltration flow rate adjustment is executed in seconds +#define HDF_CONTROL_PERIOD_SECONDS 4 ///< Interval at which the hemodiafiltration flow rate adjustment is executed in seconds #define HDF_CONTROL_PERIOD_MS ( HDF_CONTROL_PERIOD_SECONDS * MS_PER_SECOND ) ///< Interval at which the hemodiafiltration flow rate adjustment is executed in milliseconds #define HDF_CONTROL_INTERVAL ( HDF_CONTROL_PERIOD_MS / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the peroidic hemodiafiltration flow rate is calculated. #define ZERO_RATE 0.0F ///< Zero value. #define SUB_PUMP_PRESSURE_CONTROL_P_COEFFICIENT 0.5F ///< P term for Sub pump pressure control. #define SUB_PUMP_PRESSURE_CONTROL_I_COEFFICIENT 5.0F ///< I term for Sub pump pressure control. +#define HDF_TMP_TARGET 250.0F ///< TMP pressure that the controller will target to once volume has been set. // ********** private data ********** static HDF_EXEC_STATE_T hdfExecState; ///< Current hemodiafiltration executive state. static BOOL isHemodiafiltrationRequested; ///< Flag indicating hemodiafiltration request. static U32 hdfControlTimerCounter; ///< Counter (in task interval) to initiate the periodic hemodiafiltration rate recalculation. -static F32 hdfCurrentRate; ///< current HDF rate in ml/min -static F32 hdfTMPTarget; ///< HDF target TMP +static OVERRIDE_F32_T hdfCurrentRate; ///< current HDF rate in ml/min +static OVERRIDE_F32_T hdfTMPTarget; ///< HDF target TMP static F32 hdfManualRate; ///< Manually set HDF rate static F32 hdfMaximumVolume; ///< Maximum HDF volume setting static F32 hdfCurrentVolume; ///< current HDF delivered substitution volume @@ -85,10 +86,16 @@ hdfDataPublishInterval.ovInitData = 0; hdfDataPublishInterval.override = OVERRIDE_RESET; isHemodiafiltrationRequested = FALSE; - hdfTMPTarget = 0.0; + hdfTMPTarget.data = 0.0; + hdfTMPTarget.ovData = 0.0; + hdfTMPTarget.ovInitData = 0.0; + hdfTMPTarget.override = OVERRIDE_RESET; hdfManualRate = 0.0; hdfControlTimerCounter = 0; - hdfCurrentRate = 0.0; + hdfCurrentRate.data = 0.0; + hdfCurrentRate.ovData = 0.0; + hdfCurrentRate.ovInitData = 0.0; + hdfCurrentRate.override = OVERRIDE_RESET; hdfLastActiveRate = HDF_MAX_RATE; hdfMaximumVolume = 0.0; hdfCurrentVolume = 0.0; @@ -127,7 +134,7 @@ if ( TRUE == isHDFRateUpdated ) { // Update HDF rate - cmdChangeQhdf( hdfCurrentRate ); // this results in a message to DD to change the hdf pump rate + cmdChangeQhdf( getCurrentHDFRate() ); // this results in a message to DD to change the hdf pump rate isHDFRateUpdated = FALSE; } @@ -171,16 +178,16 @@ // manual rate set, use that as the proposed rate if ( hdfManualRate > ZERO_RATE ) { - hdfCurrentRate = CheckHDFRate( hdfManualRate ); + hdfCurrentRate.data = CheckHDFRate( hdfManualRate ); } else { // TMP control, resume with previous HDF rate // TODO: make sure that hdfCurrentRate is not 0 if HDF is actually wanted (volume not > max) - hdfCurrentRate = CheckHDFRate( hdfCurrentRate ); - if ( hdfCurrentRate > ZERO_RATE ) + hdfCurrentRate.data = CheckHDFRate( hdfCurrentRate.data ); + if ( getCurrentHDFRate() > ZERO_RATE ) { - resetPIDController( PID_CONTROLLER_ID_SUB_PUMP_PRES, hdfCurrentRate, 0.0F ); + resetPIDController( PID_CONTROLLER_ID_SUB_PUMP_PRES, getCurrentHDFRate(), 0.0F ); hdfControlTimerCounter = 0; } } @@ -206,7 +213,7 @@ if ( TRUE != isHemodiafiltrationRequested ) { - hdfCurrentRate = 0.0; + hdfCurrentRate.data = 0.0; isHDFRateUpdated = TRUE; state = TD_HDF_PAUSED; } @@ -227,7 +234,7 @@ *************************************************************************/ void setHemodiafiltrationParameters( F32 setHDFTMPTarget, F32 setHDFMaximumVolume ) { - hdfTMPTarget = setHDFTMPTarget; // mmHg + hdfTMPTarget.data = setHDFTMPTarget; // mmHg hdfMaximumVolume = setHDFMaximumVolume; // ml } @@ -256,7 +263,7 @@ void StartHemodiafiltration( void ) { isHemodiafiltrationRequested = TRUE; - hdfCurrentRate = hdfLastActiveRate; + hdfCurrentRate.data = hdfLastActiveRate; } /*********************************************************************//** @@ -269,7 +276,7 @@ void StopHemodiafiltration( void ) { isHemodiafiltrationRequested = FALSE; - hdfLastActiveRate = hdfCurrentRate; + hdfLastActiveRate = hdfCurrentRate.data; } /*********************************************************************//** @@ -302,7 +309,7 @@ /*********************************************************************//** * @brief - * The UpdateHDFCompensation function updates the hemodiafiltration rate + * The UpdateHDFRateAndVolume function updates the hemodiafiltration rate * based on the trans-membrane-pressure * @details \b Inputs: D41 and H14 temperature * @details \b Outputs: updated HDF rate @@ -318,17 +325,17 @@ // get new rate from PI controller if ( ZERO_RATE == hdfManualRate ) { - new_rate = runPIDController( PID_CONTROLLER_ID_SUB_PUMP_PRES, hdfTMPTarget, getLongFilteredTMPPressure() ); - hdfCurrentRate = CheckHDFRate( new_rate ); + new_rate = runPIDController( PID_CONTROLLER_ID_SUB_PUMP_PRES, getCurrentHDFTMPTarget(), getLongFilteredTMPPressure() ); + hdfCurrentRate.data = CheckHDFRate( new_rate ); } // update and check volume - hdfCurrentVolume += ((F32) HDF_CONTROL_PERIOD_SECONDS / (F32) SECONDS_PER_MINUTE) * hdfCurrentRate; //ml + hdfCurrentVolume += ((F32) HDF_CONTROL_PERIOD_SECONDS / (F32) SECONDS_PER_MINUTE) * hdfCurrentRate.data; //ml if ( hdfCurrentVolume > hdfMaximumVolume ) { reachedMaximumHDFVolume = TRUE; // Done delivering HDF, turn off pump and go to pause state - hdfCurrentRate = ZERO_RATE; + hdfCurrentRate.data = ZERO_RATE; hdfExecState = TD_HDF_PAUSED; } hdfControlTimerCounter = 0; @@ -351,6 +358,19 @@ /*********************************************************************//** * @brief + * The getCurrentHDFTMPTarget function returns the current TMP Target + * of the hemodiafiltration. + * @details \b Inputs: hdfTMPTarget + * @details \b Outputs: none + * @return the current state of HDF TMP Target. + *************************************************************************/ +F32 getCurrentHDFTMPTarget( void ) +{ + return getF32OverrideValue( &hdfTMPTarget ); +} + +/*********************************************************************//** + * @brief * The getCurrentHDFRate function returns the current rate * of the hemodiafiltration. * @details \b Inputs: hdfCurrentRate @@ -359,7 +379,7 @@ *************************************************************************/ F32 getCurrentHDFRate( void ) { - return hdfCurrentRate; + return getF32OverrideValue( &hdfCurrentRate ); } /*********************************************************************//** @@ -380,8 +400,8 @@ data.hdfExecState = (U32)hdfExecState; data.hdfRequestedRate = hdfManualRate; - data.hdfTargetTMP = hdfTMPTarget; - data.hdfCurrentRate = hdfCurrentRate; + data.hdfTargetTMP = getCurrentHDFTMPTarget(); + data.hdfCurrentRate = getCurrentHDFRate(); data.hdfCurrentTMP = getLongFilteredTMPPressure(); data.isHDFRequested = (U32)isHemodiafiltrationRequested; data.hdfRequestedVolume = hdfMaximumVolume; @@ -400,7 +420,7 @@ /*********************************************************************//** * @brief * The testTDHDFDataPublishIntervalOverride function overrides the - * DD hemodiafiltration data publish interval. + * TD hemodiafiltration data publish interval. * @details \b Inputs: hdfDataPublishInterval * @details \b Outputs: hdfDataPublishInterval * @param Override message from Dialin which includes the interval @@ -414,6 +434,50 @@ return result; } +/*********************************************************************//** + * @brief + * The testTDHDFCurrentRateOverride function overrides the + * HDF current rate. + * @details \b Inputs: none + * @details \b Outputs: hdfCurrentRate + * @param: message Override message from Dialin which includes + * HDF current rate (in mL/hour) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testTDHDFCurrentRateOverride( MESSAGE_T *message ) +{ + BOOL result = f32Override( message, &hdfCurrentRate ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testTDHDFTargetTMPOverride function overrides the + * TMP target. + * @details \b Inputs: none + * @details \b Outputs: hdfTMPTarget + * @param: message Override message from Dialin which includes + * tmp target that HDF controls to in mm/hg. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testTDHDFTargetTMPOverride( MESSAGE_T *message ) +{ + BOOL result = f32Override( message, &hdfTMPTarget ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testTDHDFStartStopHDFOverride function starts the HDF Controller + * at mentioned TMP target, flow rate, and total volume. + * @details \b Inputs: tester logged in + * @details \b Outputs: hdfTMPTarget, hdfCurrentRate, hdfVolume + * @param message set message from Dialin which includes the data to set + * and the state to set the sub pump to. + * @return TRUE if set request is successful, FALSE if not + *************************************************************************/ BOOL testTDHDFStartStopHDFOverride( MESSAGE_T *message ) { BOOL result = FALSE; Index: firmware/App/Controllers/HemoDiaFiltration.h =================================================================== diff -u -rfff7eb3560421130e0cd4788f84bce0a8ee7ff44 -r8acb1d02ac39d202a47338091b249ff2f30f5ea7 --- firmware/App/Controllers/HemoDiaFiltration.h (.../HemoDiaFiltration.h) (revision fff7eb3560421130e0cd4788f84bce0a8ee7ff44) +++ firmware/App/Controllers/HemoDiaFiltration.h (.../HemoDiaFiltration.h) (revision 8acb1d02ac39d202a47338091b249ff2f30f5ea7) @@ -71,13 +71,17 @@ U32 execHDFControl( void ); // Execute the hemodiafiltration state machine HDF_EXEC_STATE_T getCurrentHDFExecState( void ); // Get the current state of the hemodifiltration execution F32 getCurrentHDFRate( void ); +F32 getCurrentHDFTMPTarget( void ); void setHemodiafiltrationParameters( F32 setHDFTMPTarget, F32 setHDFMaximumVolume); void setHemoDiafiltrationManualRate( F32 setHDFManualRate ); void StartHemodiafiltration( void ); void StopHemodiafiltration( void ); BOOL testTDHDFDataPublishIntervalOverride( MESSAGE_T *message ); // To override the HDF data publish interval +BOOL testTDHDFCurrentRateOverride( MESSAGE_T *message ); +BOOL testTDHDFTargetTMPOverride( MESSAGE_T *message ); +BOOL testTDHDFStartStopHDFOverride( MESSAGE_T *message ); /**@}*/ #endif Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -rbbd48b033ef7307a30815e490eb28825c7afcc2b -r8acb1d02ac39d202a47338091b249ff2f30f5ea7 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision bbd48b033ef7307a30815e490eb28825c7afcc2b) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 8acb1d02ac39d202a47338091b249ff2f30f5ea7) @@ -31,6 +31,7 @@ #include "StateTxBloodPrime.h" #include "StateTxDialysis.h" #include "StateTxPaused.h" +#include "StateTxHDF.h" //#include "Switches.h" #include "TaskGeneral.h" #include "Timers.h" @@ -81,6 +82,7 @@ static U32 treatmentStateBroadcastTimerCtr; ///< Treatment state data broadcast timer counter used to schedule when to transmit data. static U32 treatmentParamsRangesBroadcastTimerCtr; ///< Treatment parameter ranges broadcast timer counter used to schedule when to transmit updated ranges. static U32 ultrafiltrationBroadcastTimerCtr; ///< Ultrafiltration data broadcast timer counter used to schedule when to transmit data. +static TREATMENT_TYPE_T treatmentType; ///< Treatment type. HDF or dialysis /// Interval (in task intervals) at which to publish alarm status to CAN bus. static OVERRIDE_U32_T treatmentTimePublishInterval; @@ -93,7 +95,7 @@ static BOOL initiateRinsebackAlarmResponseRequest; ///< Flag indicates user has requested rinseback. static BOOL endTreatmentAlarmResponseRequest; ///< Flag indicates user has requested treatment end. static BOOL endTreatmentRequest; ///< Flag indicates user has requested end of treatment from rinseback workflow. -static BOOL bloodPrimeToDialysisRequest; ///< Flag indicates blood prime has completed and time to start dialysis. +static BOOL bloodPrimeToTreatmentRequest; ///< Flag indicates blood prime has completed and time to start dialysis. static BOOL resumeBlockedByAlarm; ///< Flag indicates an alarm has blocked resume of this treatment. static U32 treatmentStartTimeStamp; ///< Treatment start timestamp for logging purpose. @@ -114,6 +116,7 @@ static TREATMENT_STATE_T handleTreatmentRinsebackState( void ); static TREATMENT_STATE_T handleTreatmentRecircState( void ); static TREATMENT_STATE_T handleTreatmentEndState( void ); +static TREATMENT_STATE_T handleTreatmentHDFState( void ); static void resetSignalFlags( void ); static void resetAlarmSignalFlags( void ); @@ -162,6 +165,7 @@ treatmentStartTimeStamp = 0; treatmentEndTimeStamp = 0; + treatmentType = TREATMENT_MODALITY_HD_SALINE_FLUID; } /*********************************************************************//** @@ -190,6 +194,7 @@ // initTreatmentRecirc(); // initTreatmentEnd(); initFluidBolus(); + initHDF(); // Started the treatment - set the start time in epoch // setTxLastStartTimeEpoch( getRTCTimestamp() ); @@ -208,14 +213,28 @@ presUFRateMlMin = presUFVolumeMl / (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFVolumeMl, presUFRateMlMin ); bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; + treatmentType = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_MODALITY ); - // Direct DD to generate dialysate and bypass while priming blood - cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateMlMin, HDF_MAX_RATE, - getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, - getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), - bicarbConvFactor, - getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ), - getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); + if (treatmentType == TREATMENT_MODALITY_HDF_ONLINE_FLUID ) + { + // Direct DD to generate dialysate and bypass while priming blood with HDF. + cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateMlMin, HDF_MAX_RATE, + getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, + getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), + bicarbConvFactor, + getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ), + getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); + } + else + { + // Direct DD to generate dialysate and bypass while priming blood + cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateMlMin, 0.0F, + getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, + getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), + bicarbConvFactor, + getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ), + getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); + } // Read back limits for transmit to UI. respRecord.artPresLimitWindowmmHg = getSysConfigTreatmentParameterU32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ); respRecord.venPresLimitWindowmmHg = getSysConfigTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_HIGH_LIMIT_WINDOW ); @@ -411,7 +430,7 @@ *************************************************************************/ void signalBloodPrimeToDialysis( void ) { - bloodPrimeToDialysisRequest = TRUE; + bloodPrimeToTreatmentRequest = TRUE; } /*********************************************************************//** @@ -484,6 +503,10 @@ currentTreatmentState = handleTreatmentEndState(); break; + case TREATMENT_HDF_STATE: + currentTreatmentState = handleTreatmentHDFState(); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_INVALID_STATE, (U32)currentTreatmentState ); break; @@ -584,7 +607,7 @@ execBloodPrime(); // Handle signals from blood prime sub-mode - if ( TRUE == bloodPrimeToDialysisRequest ) + if ( TRUE == bloodPrimeToTreatmentRequest ) { lastTreatmentTimeStamp = getMSTimerCount(); // Kick dialysis sub-mode off @@ -595,10 +618,21 @@ // { // sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, presUFRate ); // } - transitionToDialysis(); -// // To update partial blood pump occlusion baseline - start of treatment -// signalBloodPumpPressureOcclBaseline(); - result = TREATMENT_DIALYSIS_STATE; + if ( treatmentType == TREATMENT_MODALITY_HDF_ONLINE_FLUID ) + { + transitionToHDF(); +// // To update partial blood pump occlusion baseline - start of treatment +// signalBloodPumpPressureOcclBaseline(); + result = TREATMENT_HDF_STATE; + } + else + { + transitionToDialysis(); +// // To update partial blood pump occlusion baseline - start of treatment +// signalBloodPumpPressureOcclBaseline(); + result = TREATMENT_DIALYSIS_STATE; + } + } } @@ -624,6 +658,9 @@ // Always update timestamp to avoid time jump on bolus exit lastTreatmentTimeStamp = newTime; + + //TODO: Handle UI integration switching between HDF and Dialysis sub modes. + // Only update treatment time when fluid bolus is not active if ( FALSE == isFluidBolusActive() ) { @@ -658,6 +695,60 @@ /*********************************************************************//** * @brief + * The handleTreatmentHDFState function handles the Dialysis state of + * the Treatment Mode state machine. + * @details \b Inputs: none + * @details \b Outputs: treatmentTimeMS, lastTreatmentTimeStamp, dialysis sub-mode + * executed. + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentHDFState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_HDF_STATE; + U32 newTime = getMSTimerCount(); + U32 msSinceLast = calcTimeBetween( lastTreatmentTimeStamp, newTime ); + DIALYSIS_STATE_T dialysisState = getDialysisState(); + + // Always update timestamp to avoid time jump on bolus exit + lastTreatmentTimeStamp = newTime; + + //TODO: Handle UI integration switching between HDF and Dialysis sub modes. + + // Only update treatment time when fluid bolus is not active + if ( FALSE == isFluidBolusActive() ) + { + treatmentTimeMS += msSinceLast; + } + + // End treatment if treatment duration has been reached + if ( CALC_ELAPSED_TREAT_TIME_IN_SECS() >= presTreatmentTimeSecs ) + { + treatmentCompleted = TRUE; +// sendLastTreatmentPeriodicData = TRUE; +// treatmentEndTimeStamp = getRTCTimestamp(); + pauseHDF(); + requestNewOperationMode( MODE_STAN ); // TODO transitionToTreatmentEnd(); + //SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_END_OF_TREATMENT_WARNING, presTreatmentTimeSecs ); + result = TREATMENT_END_STATE; + } + // Otherwise, execute state machine for treatment dialysis sub-mode + else + { + execHDF(); + // Handle alarm page + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + transitionToTreatmentPaused(); + result = TREATMENT_PAUSED_STATE; + } + } + + return result; +} + + +/*********************************************************************//** + * @brief * The handleTreatmentPausedState function executes the Paused state of the * Treatment Mode state machine. * @details \b Inputs: none @@ -677,8 +768,16 @@ if ( TRUE == getBloodIsPrimed() ) { lastTreatmentTimeStamp = getMSTimerCount(); - transitionToDialysis(); - result = TREATMENT_DIALYSIS_STATE; + if ( treatmentType == TREATMENT_MODALITY_HDF_ONLINE_FLUID ) + { + transitionToDialysis(); + result = TREATMENT_HDF_STATE; + } + else + { + transitionToDialysis(); + result = TREATMENT_DIALYSIS_STATE; + } } else { @@ -1065,11 +1164,10 @@ #if 0 // TODO implement the test configuration //if ( TRUE == getTestConfigStatus( TEST_CONFIG_ENABLE_ONE_MINUTE_TREATMENT ) ) -#endif { treatmentTime = 1; } - +#endif return treatmentTime; } @@ -1099,7 +1197,7 @@ // rinsebackTopedRequest = FALSE; endTreatmentRequest = FALSE; // rinsebackToRecircRequest = FALSE; - bloodPrimeToDialysisRequest = FALSE; + bloodPrimeToTreatmentRequest = FALSE; // treatmentEndToRinsebackRequest = FALSE; } Index: firmware/App/Modes/StateTxHDF.c =================================================================== diff -u --- firmware/App/Modes/StateTxHDF.c (revision 0) +++ firmware/App/Modes/StateTxHDF.c (revision 8acb1d02ac39d202a47338091b249ff2f30f5ea7) @@ -0,0 +1,540 @@ +/************************************************************************** +* +* 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 StateTxHDF.c +* +* @author (last) Praneeth Bunne +* @date (last) 03-Jun-2026 +* +* @author (original) Sean Nash +* @date (original) 21-Apr-2025 +* +***************************************************************************/ + +#include "TDCommon.h" +#include "AirTrap.h" +#include "BloodFlow.h" +#include "Buttons.h" +#include "DDInterface.h" +#include "HemoDiaFiltration.h" +#include "FluidBolus.h" +#include "Messaging.h" +#include "ModeTreatment.h" +//#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "StateTxHDF.h" +#include "Switches.h" +#include "TaskGeneral.h" +#include "TxParams.h" +#include "Valves.h" + +/** + * @addtogroup StateTxHDF + * @{ + */ + +// ********** private definitions ********** + +// ********** private data ********** + +static HDF_STATE_T currentHDFState; ///< Current state of the HDF sub-mode state machine. +static HDF_STATE_T HDFResumeState; ///< HDF sub-state prior to fluid bolus. + +static U32 setBloodFlowRate; ///< Currently set blood flow rate (from prescription). +static U32 setDialysateFlowRate; ///< Currently set dialysate flow rate (from prescription). +static U32 setHDFFlowRate; ///< Currently set HDF flow rate. +static F32 setUFVolumeL; ///< Currently set total ultrafiltration volume (in L) for treatment (from prescription). +static F32 setUFRateMlMin; ///< Currently set ultrafiltration rate (in mL/min from prescription). +static OVERRIDE_F32_T measUFVolumeL; ///< Current total measured volume (in L) for ultrafiltration . +static F32 measHDFVolumeL; ///< Current total measured volume (in L) for HDF. + +static BOOL ufPauseRequested; ///< Flag indicates UF pause has been requested by user. +static BOOL ufResumeRequested; ///< Flag indicates UF resume has been requested by user. +static BOOL autoResumeUF; ///< Flag indicates UF should be auto-resumed after saline bolus completes. +static BOOL fluidBolusRequested; ///< Flag indicating fluid bolus has been requested by user. + +// ********** private function prototypes ********** + +static void transitionToHDFState( HDF_STATE_T newState ); + +static HDF_STATE_T handleHDFUltrafiltrationState( void ); +static HDF_STATE_T handleHDFUltrafiltrationPausedState( void ); +static HDF_STATE_T handleHDFFluidBolusState( void ); + +static void updateUFVolume( void ); + +/*********************************************************************//** + * @brief + * The initHDF function initializes the HDF sub-mode module. + * Calling this function will reset HDF and therefore should only + * be called when a new treatment is due to begin. + * @details \b Inputs: none + * @details \b Outputs: HDF sub-mode module initialized. + * @return none + *************************************************************************/ +void initHDF( void ) +{ + currentHDFState = HDF_UF_STATE; + HDFResumeState = HDF_UF_STATE; + + measUFVolumeL.data = 0.0F; + measUFVolumeL.ovData = 0.0F; + measUFVolumeL.ovInitData = 0.0F; + measUFVolumeL.override = OVERRIDE_RESET; + + setBloodFlowRate = 0; + setDialysateFlowRate = 0; + setUFVolumeL = 0.0F; + setUFRateMlMin = 0.0F; + + ufPauseRequested = FALSE; + ufResumeRequested = FALSE; + autoResumeUF = FALSE; + fluidBolusRequested = FALSE; +} + +/*********************************************************************//** + * @brief + * The transitionToHDF function prepares for transition to HDF sub-mode. + * This function will reset anything required for resuming HDF in a + * treatment that has already begun. It does not reset everything as HDF + * may be stopped and resumed multiple times due to alarms or user intervention + * and we don't want to start the treatment all over again. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +void transitionToHDF( void ) +{ + F32 dialTemp = getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ); + F32 acidConvFactor = getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ); + F32 bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; + U32 sodium = getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ); + U32 bicarbonate = getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ); + F32 hdfRate = getCurrentHDFRate(); + + doorClosedRequired( TRUE ); + + // Set user alarm recovery actions allowed in this sub-mode + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, TRUE ); + setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); + + // Set actuators as appropriate for state + cmdStartGenerateDialysate( setDialysateFlowRate, setUFRateMlMin, hdfRate, dialTemp, FALSE, + acidConvFactor, bicarbConvFactor, sodium, bicarbonate ); + transitionToHDFState( currentHDFState ); + + if ( hdfRate > 0.0F ) + { + StartHemodiafiltration(); + } + + // Set substate for event + setCurrentSubState( (U32)currentHDFState ); +} + +/*********************************************************************//** + * @brief + * The transitionToHDFState function sets all actuators as appropriate + * go the given new HDF state. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid state is given + * @details \b Inputs: none + * @details \b Outputs: none + * @param newState The new state that we are transitioning to. + * @return none + *************************************************************************/ +static void transitionToHDFState( HDF_STATE_T newState ) +{ + switch ( newState ) + { + case HDF_UF_STATE: + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); // set arterial valve to pump blood from patient + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); // set venous valve to open, allowing blood to return to patient + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + cmdChangeQuf( setUFRateMlMin ); + + // Start auto-control of air trap valve + startAirTrapControl(); + break; + + case HDF_UF_PAUSED_STATE: + // Set valves for HDF + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); // set arterial valve to pump blood from patient + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); // set venous valve to open, allowing blood to return to patient + + // Restart pumps + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + cmdChangeQuf( 0.0F ); + + // Start auto-control of air trap valve + startAirTrapControl(); + break; + + case HDF_UF_FLUID_BOLUS_STATE: + // State prior to bolus + HDFResumeState = currentHDFState; + cmdBypassDialyzer( TRUE ); + cmdChangeQuf( 0.0F ); + // Start bolus and transition to bolus state + signalStartFluidBolus( setBloodFlowRate ); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TX_HDF_INVALID_STATE1, (U32)newState ) + break; + } +} + +/*********************************************************************//** + * @brief + * The getHDFState function gets the current HDF state. + * @details \b Inputs: currentHDFState + * @details \b Outputs: none + * @return currentHDFState + *************************************************************************/ +HDF_STATE_T getHDFState( void ) +{ + return currentHDFState; +} + +/*********************************************************************//** + * @brief + * The getUltrafiltrationVolumeDrawn function gets the current total + * ultrafiltration volume (in L) drawn from the patient so far. + * @details \b Inputs: measUFVolumeL + * @details \b Outputs: none + * @return Total ultrafiltration volume (in L) drawn from the patient so far. + *************************************************************************/ +F32 getHDFUltrafiltrationVolumeDrawn( void ) +{ + F32 result = getF32OverrideValue( &measUFVolumeL ); + + return result; +} + +/*********************************************************************//** + * @brief + * The setHDFBloodPumpFlowRate function sets the blood pump flow rate parameter. + * This function should be called prior to beginning HDF treatment + * and when the user changes the blood flow rate during treatment. + * @details \b Inputs: none + * @details \b Outputs: setBloodFlowRate + * @param bPFlow target blood pump flow rate (in mL/min) + * @return none + *************************************************************************/ +void setHDFBloodPumpFlowRate( U32 bPFlow ) +{ + setBloodFlowRate = bPFlow; + + // Make rate changes in real time if currently performing HDF. + if ( TREATMENT_HDF_STATE == getTreatmentState() ) + { + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + } +} + +/*********************************************************************//** + * @brief + * The setHDFDDParams function sets the dialysate rate and ultrafiltration + * volume and rate parameters. + * @details \b Inputs: none + * @details \b Outputs: setDialysateFlowRate, setUFVolumeL, setUFRateMlMin + * @param qd target dialysate flow rate (in mL/min) + * @param ufVol target ultrafiltration volume (in mL) + * @param quf target ultrafiltration flow rate (in mL/min) + * @return none + *************************************************************************/ +void setHDFDDParams( U32 qd, F32 ufVol, F32 quf ) +{ + setDialysateFlowRate = qd; + setUFVolumeL = ufVol; + setUFRateMlMin = quf; +} + +/*********************************************************************//** + * @brief + * The signalHDFPauseResumeUF function handles a request to pause or resume + * ultrafiltration. + * @details \b Message \b Sent: MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE + * @details \b Message \b Sent: UF_START_PAUSE_EVENT / UF_START_RESUME_EVENT + * @details \b Inputs: currentHDFState, setUFRateMlMin + * @details \b Outputs: ufPauseRequested, ufResumeRequested + * @param message Message from UI which includes a flag indicating whether + * to pause or resume ultrafiltration. + * @return TRUE if pause + *************************************************************************/ +BOOL signalHDFPauseResumeUF( MESSAGE_T *message ) +{ + TREATMENT_STATE_T trtState = getTreatmentState(); + TD_OP_MODE_T currMode = getCurrentOperationMode(); + UI_RESPONSE_PAYLOAD_T response; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // Verify payload length is valid + if ( sizeof( BOOL ) == message->hdr.payloadLen ) + { + BOOL payload; + + memcpy( &payload, message->payload, sizeof( BOOL ) ); + + // Handle request to resume ultrafiltration + if ( TRUE == payload ) + { + if ( ( MODE_TREA == currMode ) && ( TREATMENT_HDF_STATE == trtState ) && ( HDF_UF_PAUSED_STATE == currentHDFState ) ) + { + ufResumeRequested = TRUE; + response.accepted = TRUE; + if ( setUFRateMlMin > 0.0 ) + { + //sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, setUFRateMlMin ); + } + } + else + { + if ( MODE_TREA != currMode ) + { + response.rejectionReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; + } + else if ( TREATMENT_HDF_STATE != trtState ) + { + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_UF_NOT_PAUSED; + } + } + } + // Handle request to pause ultrafiltration + else + { + if ( ( MODE_TREA == currMode ) && ( TREATMENT_HDF_STATE == trtState ) && ( HDF_UF_STATE == currentHDFState ) ) + { + ufPauseRequested = TRUE; + response.accepted = TRUE; + if ( setUFRateMlMin > 0.0 ) + { + //sendTreatmentLogEventData( UF_PAUSE_EVENT, setUFRateMlMin, 0.0 ); + } + } + else + { + if ( MODE_TREA != currMode ) + { + response.rejectionReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; + } + else if ( TREATMENT_HDF_STATE != trtState ) + { + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_UF_NOT_IN_PROGESS; + } + } + } + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + // Send response w/ reason code if rejected + sendMessage( MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&response), sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return response.accepted; +} + +/*********************************************************************//** + * @brief + * The pauseHDF function pauses HDF. This function will be called + * by Treatment Mode when an alarm occurs or the user pressed the stop button. + * HDF may be resumed later. + * @details Inputs: none + * @details Outputs: Pumps stopped. DD commanded to bypass. + * @return none + *************************************************************************/ +void pauseHDF( void ) +{ + // Stop pumps + signalBloodPumpHardStop(); + // Tell DD to bypass dialyzer and stop HDF while alarm has HDF paused + cmdBypassDialyzer( TRUE ); + StopHemodiafiltration(); +} + +/*********************************************************************//** + * @brief + * The execHDF function executes the HDF sub-mode state machine. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if state is invalid + * @details \b Message \b Sent: TD_EVENT_SUB_STATE_CHANGE when state changes + * @details \b Inputs: currentHDFState + * @details \b Outputs: currentHDFState + * @return none + *************************************************************************/ +void execHDF( void ) +{ + HDF_STATE_T priorSubState = currentHDFState; + + // HDF state machine + switch ( currentHDFState ) + { + case HDF_UF_STATE: + currentHDFState = handleHDFUltrafiltrationState(); + break; + + case HDF_UF_PAUSED_STATE: + currentHDFState = handleHDFUltrafiltrationPausedState(); + break; + + case HDF_UF_FLUID_BOLUS_STATE: + currentHDFState = handleHDFFluidBolusState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TX_HDF_INVALID_STATE1, (U32)currentHDFState ) + break; + } + + // Update total UF volume drawn + updateUFVolume(); + + if ( priorSubState != currentHDFState ) + { + setCurrentSubState( (U32)currentHDFState ); + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_STATE_CHANGE, priorSubState, currentHDFState ); + } +} + +/*********************************************************************//** + * @brief + * The handleHDFUltrafiltrationState function handles the ultrafiltration + * state of the HDF state machine. + * @details \b Inputs: ufPauseRequested, fluidBolusRequested + * @details \b Outputs: ufPauseRequested, fluidBolusRequested + * @return next HDF state. + *************************************************************************/ +static HDF_STATE_T handleHDFUltrafiltrationState( void ) +{ + HDF_STATE_T result = HDF_UF_STATE; + + if ( TRUE == ufPauseRequested ) + { + ufPauseRequested = FALSE; + transitionToHDFState( HDF_UF_PAUSED_STATE ); + result = HDF_UF_PAUSED_STATE; + } + // When UI requests fluid bolus + else if ( TRUE == fluidBolusRequested ) + { + fluidBolusRequested = FALSE; + transitionToHDFState( HDF_UF_FLUID_BOLUS_STATE ); + result = HDF_UF_FLUID_BOLUS_STATE; + } + else + { + // No action required. + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleHDFUltrafiltrationPausedState function handles the + * ultrafiltration paused state of the HDF state machine. + * @details \b Inputs: ufResumeRequested, fluidBolusRequested + * @details \b Outputs: ufResumeRequested, fluidBolusRequested + * @return next HDF state. + *************************************************************************/ +static HDF_STATE_T handleHDFUltrafiltrationPausedState( void ) +{ + HDF_STATE_T result = HDF_UF_PAUSED_STATE; + + if ( TRUE == ufResumeRequested ) + { + ufResumeRequested = FALSE; + transitionToHDFState( HDF_UF_STATE ); + result = HDF_UF_STATE; + } + // When UI requests fluid bolus + else if ( TRUE == fluidBolusRequested ) + { + fluidBolusRequested = FALSE; + transitionToHDFState( HDF_UF_FLUID_BOLUS_STATE ); + result = HDF_UF_FLUID_BOLUS_STATE; + } + else + { + // No action required. + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleHDFFluidBolusState function handles the fluid bolus + * sub-state of the HDF state machine. Signals the fluid bolus + * service to start. + * @details \b Inputs: HDFResumeState + * @details \b Outputs: none + * @return next HDF state. + *************************************************************************/ +static HDF_STATE_T handleHDFFluidBolusState( void ) +{ + HDF_STATE_T result = HDF_UF_FLUID_BOLUS_STATE; + + // Restore actuators and return to pre-bolus sub-state upon bolus complete or abort + if ( FALSE == isFluidBolusActive() ) + { + cmdBypassDialyzer( FALSE ); + transitionToHDFState( HDFResumeState ); + result = HDFResumeState; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The updateUFVolume function updates the total measured ultrafiltration + * volume based on set rate and whether or not DD is currently running + * the ultrafiltration pump. + * @details \b Inputs: none + * @details \b Outputs: measUFVolumeL + * @return none + *************************************************************************/ +static void updateUFVolume( void ) +{ + // Update total UF volume drawn + measUFVolumeL.data = 0.0F; // TODO +} + +/*********************************************************************//** + * @brief + * The signalHDFFluidBolusRequest function signals a fluid bolus + * request to the HDF sub-mode. + * @details \b Inputs: none + * @details \b Outputs: fluidBolusRequested + * @return TRUE if request is accepted, FALSE if rejected. + *************************************************************************/ +BOOL signalHDFFluidBolusRequest( void ) +{ + BOOL result = FALSE; + + // Allow from both UF & UF pause states + fluidBolusRequested = TRUE; + result = TRUE; + + return result; +} + +/**@}*/ Index: firmware/App/Modes/StateTxHDF.h =================================================================== diff -u --- firmware/App/Modes/StateTxHDF.h (revision 0) +++ firmware/App/Modes/StateTxHDF.h (revision 8acb1d02ac39d202a47338091b249ff2f30f5ea7) @@ -0,0 +1,55 @@ +/************************************************************************** +* +* 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 StateTxHDF.h +* +* @author (last) Praneeth Bunne +* @date (last) 27-May-2026 +* +* @author (original) Sean Nash +* @date (original) 21-Apr-2025 +* +***************************************************************************/ + +#ifndef __STATE_TX_HDF_H__ +#define __STATE_TX_HDF_H__ + +#include "TDCommon.h" +#include "TDDefs.h" + +/** + * @defgroup StateTxHDF StateTxHDF + * @brief Treatment mode HDF state unit. The HDF sub-mode is where + * HDF and (optionally) ultrafiltration are being provided by the system. + * Heparin is added to the blood when appropriate. + * + * @addtogroup StateTxHDF + * @{ + */ + +// ********** public definitions ********** + +// ********** public function prototypes ********** + +void initHDF( void ); // Initialize this unit +void transitionToHDF( void ); // Prepares for transition to treatment HDF state +void execHDF( void ); // Execute the treatment HDF state machine + +void pauseHDF( void ); // Pauses HDF due to alarm + +HDF_STATE_T getHDFState( void ); // Gets current HDF state +F32 getHDFUltrafiltrationVolumeDrawn( void ); // Gets current total ultrafiltration volume drawn from patient. + +void setHDFBloodPumpFlowRate( U32 bPFlow ); // Signal new BP flow rate +void setHDFDDParams( U32 qd, F32 ufVol, F32 quf ); // Signal new DD params + +BOOL signalHDFPauseResumeUF( MESSAGE_T *message ); // Handles a user request to pause or resume ultrafiltration +BOOL signalHDFFluidBolusRequest( void ); // Fluid Bolus request from UI + +/**@}*/ + +#endif Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -rbbd48b033ef7307a30815e490eb28825c7afcc2b -r8acb1d02ac39d202a47338091b249ff2f30f5ea7 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision bbd48b033ef7307a30815e490eb28825c7afcc2b) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 8acb1d02ac39d202a47338091b249ff2f30f5ea7) @@ -199,7 +199,8 @@ SW_FAULT_ID_PRE_TX_RECIRC_INVALID_STATE = 168, SW_FAULT_ID_TD_VALVES_INVALID_VALVE2 = 169, SW_FAULT_ID_INVALID_TUBE_SET_TYPE = 170, - SW_FAULT_ID_HDF_INVALID_EXEC_STATE = 169, + SW_FAULT_ID_HDF_INVALID_EXEC_STATE = 171, + SW_FAULT_ID_TX_HDF_INVALID_STATE1 = 172, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/Messaging.c =================================================================== diff -u -r83310420ae862de4724f8cfbbaeda9936c47801b -r8acb1d02ac39d202a47338091b249ff2f30f5ea7 --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision 83310420ae862de4724f8cfbbaeda9936c47801b) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 8acb1d02ac39d202a47338091b249ff2f30f5ea7) @@ -29,6 +29,7 @@ #include "Ejector.h" #include "FluidBolus.h" #include "FpgaTD.h" +#include "HemoDiaFiltration.h" #include "LevelSensors.h" #include "Messaging.h" #include "ModeStandby.h" @@ -219,6 +220,10 @@ { MSG_ID_TD_HEPARIN_BOLUS_TARGET_RATE_OVERRIDE_REQUEST, &testHeparinBolusTargetRateOverride }, { MSG_ID_TD_SYRINGE_PUMP_FORCE_SENSOR_CALIBRATION_REQUEST, &testCalibrateForceSensor }, { MSG_ID_TD_GET_ALARM_PROPERTIES_REQUEST, &testGetAlarmPropertiesRequest }, + { MSG_ID_TD_HDF_START_STOP_OVERRIDE_REQUEST, &testTDHDFStartStopHDFOverride }, + { MSG_ID_TD_HDF_CURRENT_RATE_OVERRIDE_REQUEST, &testTDHDFCurrentRateOverride }, + { MSG_ID_TD_HDF_TARGET_TMP_OVERRIDE_REQUEST, &testTDHDFTargetTMPOverride }, + { MSG_ID_TD_HDF_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testTDHDFDataPublishIntervalOverride }, }; /// Number of entries in the message handling function lookup table. Index: firmware/App/Services/StateServices/TubeSetInstall.c =================================================================== diff -u -r83310420ae862de4724f8cfbbaeda9936c47801b -r8acb1d02ac39d202a47338091b249ff2f30f5ea7 --- firmware/App/Services/StateServices/TubeSetInstall.c (.../TubeSetInstall.c) (revision 83310420ae862de4724f8cfbbaeda9936c47801b) +++ firmware/App/Services/StateServices/TubeSetInstall.c (.../TubeSetInstall.c) (revision 8acb1d02ac39d202a47338091b249ff2f30f5ea7) @@ -153,8 +153,10 @@ // Request DD to generate dialysate with Qd = 600 mL/min, // Quf = 0, and dialyzer bypassed. + // Qsub = 0. cmdStartGenerateDialysate( 600.0F, 0.0F, + 0.0F, getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ),