Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -r1edea1b3b13b1e0f69a7209363ae6886cb89f89c -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 1edea1b3b13b1e0f69a7209363ae6886cb89f89c) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -7,15 +7,15 @@ * * @file BloodFlow.c * -* @author (last) Jashwant Gantyada -* @date (last) 21-Apr-2026 +* @author (last) Sean Nash +* @date (last) 01-May-2026 * * @author (original) Sean Nash * @date (original) 24-Oct-2024 * ***************************************************************************/ -#include // Used for fabs() functions +#include // Used for abs(), fabs() functions #include // Used for memset() #include "BloodFlow.h" @@ -967,31 +967,20 @@ U32 absFlowU32 = 0; F32 tFilterSec = 0.0F; F32 windowSamplesF = 0.0F; - U32 windowSamples = 0; + U32 windowSamples = BP_SPEED_FILTER_DEFAULT_SAMPLES; - if ( 0 != targetBloodFlowRate ) + absFlowU32 = abs( targetBloodFlowRate ); + if ( absFlowU32 != 0 ) { - absFlowU32 = ( targetBloodFlowRate >= 0 ) ? (U32)targetBloodFlowRate : (U32)( -targetBloodFlowRate ); - if ( 0 != absFlowU32 ) + if ( absFlowU32 > (U32)MAX_SETTABLE_BLOOD_FLOW_RATE ) { - if ( absFlowU32 > (U32)MAX_SETTABLE_BLOOD_FLOW_RATE ) - { - absFlowU32 = (U32)MAX_SETTABLE_BLOOD_FLOW_RATE; - } - - tFilterSec = (F32)BP_SPEED_FILTER_TIME_FLOW_PRODUCT / (F32)absFlowU32; - windowSamplesF = ( tFilterSec * (F32)MS_PER_SECOND / (F32)TASK_GENERAL_INTERVAL ) + 0.5F; - windowSamples = (U32)windowSamplesF; - - if ( windowSamples < BP_SPEED_FILTER_DEFAULT_SAMPLES ) - { - windowSamples = BP_SPEED_FILTER_DEFAULT_SAMPLES; - } - if ( windowSamples > (U32)MAX_BP_SPEED_FILTER_SAMPLES ) - { - windowSamples = (U32)MAX_BP_SPEED_FILTER_SAMPLES; - } + absFlowU32 = (U32)MAX_SETTABLE_BLOOD_FLOW_RATE; } + + tFilterSec = (F32)BP_SPEED_FILTER_TIME_FLOW_PRODUCT / (F32)absFlowU32; + windowSamplesF = ( tFilterSec * (F32)MS_PER_SECOND / (F32)TASK_GENERAL_INTERVAL ) + 0.5F; + windowSamples = (U32)windowSamplesF; + windowSamples = RANGE( windowSamples, BP_SPEED_FILTER_DEFAULT_SAMPLES, MAX_BP_SPEED_FILTER_SAMPLES ); } return windowSamples; Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -r6f02ff4686ec9dfc60247e9ed3fc9c5cc7771543 -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 6f02ff4686ec9dfc60247e9ed3fc9c5cc7771543) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -7,15 +7,16 @@ * * @file ModePreTreat.c * -* @author (last) Varshini Nagabooshanam -* @date (last) 26-Jan-2026 +* @author (last) Raghu Kallala +* @date (last) 08-May-2026 * * @author (original) Dara Navaei * @date (original) 25-Sep-2025 * ***************************************************************************/ #include "Buttons.h" +#include "DDInterface.h" #include "ModePreTreat.h" #include "OperationModes.h" #include "Timers.h" @@ -143,19 +144,64 @@ *************************************************************************/ static TD_PRE_TREATMENT_MODE_STATE_T handleRxState( void ) { - BOOL paramsValid = getValidTreatParamsReceived(); - BOOL paramsConfirmed = getTreatParamsConfirmed(); - TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_CONFIRM_RX_STATE; + BOOL paramsValid = getValidTreatParamsReceived(); + BOOL paramsConfirmed = getTreatParamsConfirmed(); + BOOL isDialysateGoodToDeliver = TRUE; // TODO replace TRUE with getDialysateGoodToDeliverStatus() when we are ready + F32 bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; + F32 presUFVolumeL = 0.0F; + F32 presUFRateMlMin = 0.0F; + U32 ddSubMode = getDDSubMode(); + TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_CONFIRM_RX_STATE; + DD_OP_MODE_T ddOpMode = getDDOpMode(); // Valid + confirmed – move to next state: Patient Connection if ( ( TRUE == paramsValid ) && ( TRUE == paramsConfirmed ) ) { + // TODO this command of requesting dialysate delivery will move to appropriate state in pre-treatment once implemented + if ( ( ddOpMode == DD_MODE_PREG ) && ( ddSubMode == DD_PRE_GEN_DIALYSATE_WAIT_FOR_GEND ) ) + { + presUFVolumeL = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); + presUFRateMlMin = ( presUFVolumeL * (F32)ML_PER_LITER ) / (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + // Direct DD to generate dialysate and bypass while priming blood + cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateMlMin, + getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, + getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), + bicarbConvFactor, + getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ), + getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); + } // TODO: when additional Pre-Treatment states are implemented, change to TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE. // state = TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; - requestNewOperationMode( MODE_TREA ); + if ( ( ddOpMode == DD_MODE_GEND ) && ( TRUE == isDialysateGoodToDeliver ) ) + { + requestNewOperationMode( MODE_TREA ); + } } return state; } +/*********************************************************************//** + * @brief + * The signalAlarmActionToPreTreatmentMode function executes the given alarm action + * as appropriate while in Pre-Treatment Mode. + * @details \b Inputs: none + * @details \b Outputs: given alarm action executed + * @param action ID of alarm action to execute + * @return none + *************************************************************************/ +void signalAlarmActionToPreTreatmentMode( ALARM_ACTION_T action ) +{ + switch ( action ) + { + case ALARM_ACTION_STOP: + // TODO add logic once we have pre-treatment mode developed + break; + + default: + // do not handle other actions in pre-treatment mode + break; + } +} + /**@}*/ Index: firmware/App/Modes/ModePreTreat.h =================================================================== diff -u -r395522dffef1348e176564925656012f529c1910 -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/ModePreTreat.h (.../ModePreTreat.h) (revision 395522dffef1348e176564925656012f529c1910) +++ firmware/App/Modes/ModePreTreat.h (.../ModePreTreat.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -7,8 +7,8 @@ * * @file ModePreTreat.h * -* @author (last) Dara Navaei -* @date (last) 26-Oct-2025 +* @author (last) Raghu Kallala +* @date (last) 08-May-2026 * * @author (original) Dara Navaei * @date (original) 25-Sep-2025 @@ -21,6 +21,7 @@ #include "TDCommon.h" #include "TDDefs.h" +#include "DDDefs.h" /** * @defgroup TDPreTreatmentMode TDPreTreatmentMode @@ -35,6 +36,7 @@ void initPreTreatmentMode( void ); // Initialize this module U32 transitionToPreTreatmentMode( void ); // Prepares for transition to pre-treatment mode U32 execPreTreatmentMode( void ); // Execute the pre-treatment mode state machine (call from OperationModes) +void signalAlarmActionToPreTreatmentMode( ALARM_ACTION_T action ); // Execute alarm action as appropriate for pre-treatment mode /**@}*/ Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file ModeStandby.c * * @author (last) Raghu Kallala -* @date (last) 06-Apr-2026 +* @date (last) 30-Apr-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -208,6 +208,7 @@ { TD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_TREATMENT_STATE; DD_OP_MODE_T ddOperationMode = getDDOpMode(); + F32 bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; // switch ( dgOperationMode ) // { @@ -259,6 +260,13 @@ respRecord.venPresLimitAsymmetricmmHg = getSysConfigTreatmentParameterU32DefaultValue( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ); respRecord.tmpPresLimitWindowmmHg = getSysConfigTreatmentParameterU32DefaultValue( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ); sendPressureLimitsChangeResponse( &respRecord ); + // start DD pre-gen // TODO + cmdStartPreGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), + getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), + getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), + bicarbConvFactor, + getTreatmentParameterU32( TREATMENT_PARAM_SODIUM ), + getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); // Start treatment workflow with pretreatment mode requestNewOperationMode( MODE_PRET ); treatStartReqReceived = FALSE; Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file ModeTreatment.c * * @author (last) Raghu Kallala -* @date (last) 17-Apr-2026 +* @date (last) 04-May-2026 * * @author (original) Sean Nash * @date (original) 21-Apr-2025 @@ -71,8 +71,8 @@ static BOOL treatmentCompleted; ///< Flag indicates whether the treatment has completed. static U32 presTreatmentTimeSecs; ///< Prescribed treatment time (in seconds). -static F32 presUFVolumeL; ///< Prescribed ultrafiltration volume (in L). -static F32 presUFRateLHr; ///< Prescribed ultrafiltration rate (in L/hr). +static F32 presUFVolumeMl; ///< Prescribed ultrafiltration volume (in L). +static F32 presUFRateMlMin; ///< Prescribed ultrafiltration rate (in mL/Min). static U32 treatmentTimeMS; ///< Elapsed treatment time (in ms). static U32 lastTreatmentTimeStamp; ///< Last time elapsed treatment time was recorded (a timestamp in ms). @@ -109,7 +109,6 @@ static TREATMENT_STATE_T handleTreatmentDialysisState( void ); static TREATMENT_STATE_T handleTreatmentIsoUFState( void ); static TREATMENT_STATE_T handleTreatmentDialysatePausedState( void ); -static TREATMENT_STATE_T handleTreatmentSalineBolusState( void ); static TREATMENT_STATE_T handleTreatmentPausedState( void ); static TREATMENT_STATE_T handleTreatmentRinsebackState( void ); static TREATMENT_STATE_T handleTreatmentRecircState( void ); @@ -154,8 +153,8 @@ ultrafiltrationBroadcastTimerCtr = ULTRAFILTRATION_DATA_PUB_INTERVAL; // So we send ultrafiltration immediately when we begin treatment mode presTreatmentTimeSecs = 0; - presUFVolumeL = 0.0F; - presUFRateLHr = 0.0F; + presUFVolumeMl = 0.0F; + presUFRateMlMin = 0.0F; resetSignalFlags(); resetAlarmSignalFlags(); @@ -204,13 +203,13 @@ // Set treatment parameters presTreatmentTimeSecs = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ) * SEC_PER_MIN; - presUFVolumeL = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); - presUFRateLHr = presUFVolumeL / ( (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ) / (F32)MIN_PER_HOUR ); - setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFVolumeL, presUFRateLHr ); + presUFVolumeMl = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ) * (F32)ML_PER_LITER; + presUFRateMlMin = presUFVolumeMl / (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFVolumeMl, presUFRateMlMin ); bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; // Direct DD to generate dialysate and bypass while priming blood - cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateLHr, + cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateMlMin, getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), bicarbConvFactor, @@ -437,7 +436,6 @@ if ( ( TRUE == doesAlarmStatusIndicateStop() ) && ( TRUE == isFluidBolusActive() ) ) { signalAbortFluidBolus(); - execFluidBolus(); } // Check if resume treatment blocked by alarm @@ -471,10 +469,6 @@ // currentTreatmentState = handleTreatmentIsoUFState(); // break; // -// case TREATMENT_SALINE_BOLUS_STATE: -// currentTreatmentState = handleTreatmentSalineBolusState(); -// break; -// // case TREATMENT_DIALYSATE_PAUSED_STATE: // currentTreatmentState = handleTreatmentDialysatePausedState(); // break; @@ -511,12 +505,13 @@ broadcastTreatmentPeriodicData(); // Publish ultrafiltration data at set interval (whether we are performing UF or not) publishUltrafiltrationData(); - // Publish fluid bolus data at set interval (whether we are delivering one or not) - publishFluidBolusData(); // Manage air trap control execAirTrapMonitorTreatment(); + // Call fluid bolus + execFluidBolus(); + return currentTreatmentState; } @@ -631,10 +626,15 @@ U32 msSinceLast = calcTimeBetween( lastTreatmentTimeStamp, newTime ); DIALYSIS_STATE_T dialysisState = getDialysisState(); - // Update treatment time - treatmentTimeMS += msSinceLast; + // Always update timestamp to avoid time jump on bolus exit lastTreatmentTimeStamp = newTime; + // 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 ) { @@ -953,7 +953,7 @@ F32 minUFVol = 0.0F; // TODO getUltrafiltrationReferenceVolume() + presUFRate; // current UF volume + 1 min at current rate // Compute maximum UF volume (considering from adjustment of UF rate and time perspectives) F32 maxUFVol1 = minUFVol + ( (F32)( presTime - elapseTime ) * MAX_UF_RATE_ML_MIN ); - F32 maxUFVol2 = ( presUFRateLHr > 0.0F ? minUFVol + ( (F32)( MAX_TREATMENT_TIME_MINUTES - elapseTime - 1 ) * presUFRateLHr ) : minUFVol ); + F32 maxUFVol2 = ( presUFRateMlMin > 0.0F ? minUFVol + ( (F32)( MAX_TREATMENT_TIME_MINUTES - elapseTime - 1 ) * presUFRateMlMin ) : minUFVol ); F32 maxUFVol = MAX( maxUFVol1, maxUFVol2 ); // Set minimum dialysate flow rate U32 minDialRate = MIN_DIALYSATE_FLOW_RATE; @@ -1108,7 +1108,7 @@ * @brief * The publishUltrafiltrationData function publishes the ultrafiltration data * at the set time interval. - * @details \b Inputs: presUFVolumeL, presUFRate + * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ @@ -1117,7 +1117,10 @@ if ( ++ultrafiltrationBroadcastTimerCtr >= ULTRAFILTRATION_DATA_PUB_INTERVAL ) { UF_DATA_PAYLOAD_T data; + F32 presUFRateLHr = 0.0F; + F32 presUFVolumeL = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); + presUFRateLHr = presUFVolumeL / ( (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ) / (F32)MIN_PER_HOUR ); data.setUFVolumeL = presUFVolumeL; data.tgtUFRateLHr = presUFRateLHr; data.ufVolumeDeliveredL = getUltrafiltrationVolumeDrawn(); Index: firmware/App/Modes/OperationModes.c =================================================================== diff -u -reef41b7363d82763095a1317f1757f360f0d9ec1 -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision eef41b7363d82763095a1317f1757f360f0d9ec1) +++ firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -7,8 +7,8 @@ * * @file OperationModes.c * -* @author (last) Varshini Nagabooshanam -* @date (last) 29-Jan-2026 +* @author (last) Raghu Kallala +* @date (last) 07-May-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -319,9 +319,9 @@ case MODE_STAN: signalAlarmActionToStandbyMode( action ); break; -// case MODE_PRET: -// signalAlarmActionToPreTreatmentMode( action ); -// break; + case MODE_PRET: + signalAlarmActionToPreTreatmentMode( action ); + break; case MODE_TREA: signalAlarmActionToTreatmentMode( action ); break; Index: firmware/App/Modes/StateTxBloodPrime.c =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/StateTxBloodPrime.c (.../StateTxBloodPrime.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Modes/StateTxBloodPrime.c (.../StateTxBloodPrime.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -70,6 +70,8 @@ static BOOL pendingPauseRequest; ///< Flag indicating UI has requested blood prime pause. static BOOL pendingResumeRequest; ///< Flag indicating UI has requested blood prime resume. static BOOL pendingFlowChangeRequest; ///< Flag indicating UI has requested blood prime flow change +static BOOL fluidBolusRequested; ///< Flag indicating fluid bolus has been requested by user. +static BOOL bolusStarted; ///< Flag indicating fluid bolus start signal has been sent. static F32 bloodPrimeRampFlowRate_mL_min; ///< Current blood pump ramp flow rate. static F32 bloodPrimeRampStep_mL; ///< Blood pump volume step size for ramping. @@ -95,9 +97,9 @@ static BLOOD_PRIME_STATE_T handleBloodPrimeRampState( void ); static BLOOD_PRIME_STATE_T handleBloodPrimeRunState( void ); static BLOOD_PRIME_STATE_T handleBloodPrimePausedState( void ); +static BLOOD_PRIME_STATE_T handleBloodPrimeFluidBolusState( void ); static void handleBloodPrimePauseTimer( void ); static void publishBloodPrimeData( void ); -static BLOOD_PRIME_STATE_T handleBloodPrimeFluidBolusState( void ); /*********************************************************************//** * @brief @@ -132,6 +134,9 @@ } bloodPrimeRampStep_mL = rampRateSpan / estRampSeconds; bloodPrimeStartMS = 0; + + fluidBolusRequested = FALSE; + bolusStarted = FALSE; } /*********************************************************************//** @@ -191,6 +196,8 @@ pendingPauseRequest = FALSE; pendingResumeRequest = FALSE; pendingFlowChangeRequest = FALSE; + fluidBolusRequested = FALSE; + bolusStarted = FALSE; } /*********************************************************************//** @@ -303,6 +310,14 @@ bloodPrimeResumeState = BLOOD_PRIME_RUN_STATE; result = BLOOD_PRIME_RUN_STATE; } + // When UI requests fluid bolus + else if ( TRUE == fluidBolusRequested ) + { + fluidBolusRequested = FALSE; + bloodPrimeResumeState = bloodPrimeState; + lastBloodPrimeFlowRate_mL_min = getTargetBloodFlowRate(); + result = BLOOD_PRIME_FLUID_BOLUS_STATE; + } else { // Continue ramping @@ -358,6 +373,18 @@ pendingFlowChangeRequest = FALSE; setBloodPumpTargetFlowRate( requestedBloodFlowRate_mL_min, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); } + // When UI requests fluid bolus + else if ( TRUE == fluidBolusRequested ) + { + fluidBolusRequested = FALSE; + bloodPrimeResumeState = bloodPrimeState; + lastBloodPrimeFlowRate_mL_min = getTargetBloodFlowRate(); + result = BLOOD_PRIME_FLUID_BOLUS_STATE; + } + else + { + // No action required. + } return result; } @@ -391,6 +418,36 @@ /*********************************************************************//** * @brief + * The handleBloodPrimeFluidBolusState function handles the fluid bolus + * state of the blood prime sub-mode. + * @details \b Inputs: bloodPrimeResumeState, lastBloodPrimeFlowRate_mL_min + * @details \b Outputs: bloodPrimeState + * @return next blood prime state + *************************************************************************/ +static BLOOD_PRIME_STATE_T handleBloodPrimeFluidBolusState( void ) +{ + BLOOD_PRIME_STATE_T result = BLOOD_PRIME_FLUID_BOLUS_STATE; + + // Start fluid bolus if not started + if ( FALSE == bolusStarted ) + { + bolusStarted = signalStartFluidBolus( lastBloodPrimeFlowRate_mL_min ); + } + // Restore actuators and return to pre-bolus sub-state upon bolus complete or abort + else if ( FALSE == isFluidBolusActive() ) + { + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( lastBloodPrimeFlowRate_mL_min, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + bolusStarted = FALSE; + result = bloodPrimeResumeState; + } + + return result; +} + +/*********************************************************************//** + * @brief * The getCurrentBloodPrimeState function returns the current state of the * blood prime state. * @details \b Inputs: bloodPrimeState @@ -549,52 +606,23 @@ /*********************************************************************//** * @brief - * The handleBloodPrimeFluidBolusState function handles the fluid bolus - * state of the blood prime sub-mode. - * @details \b Inputs: bloodPrimeResumeState, bloodPrimeState - * @details \b Outputs: bloodPrimeState - * @return next blood prime state - *************************************************************************/ -static BLOOD_PRIME_STATE_T handleBloodPrimeFluidBolusState( void ) -{ - BLOOD_PRIME_STATE_T state = BLOOD_PRIME_FLUID_BOLUS_STATE; - - // start fluid bolus - signalStartFluidBolus(); - - // Call fluid bolus service - execFluidBolus(); - - if ( FALSE == isFluidBolusActive() ) - { - setBloodPumpTargetFlowRate( lastBloodPrimeFlowRate_mL_min, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - // Open art/ven pinch valves - setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); - setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); - // Return to state prior to bolus - state = bloodPrimeResumeState; - } - - return state; -} - -/*********************************************************************//** - * @brief * The bloodPrimeSetPendingFluidBolusRequest function handles a fluid bolus * request while in blood prime sub-mode. * @details \b Inputs: bloodPrimeState - * @details \b Outputs: bloodPrimeResumeState, lastBloodPrimeFlowRate_mL_min, - * bloodPrimeState - * @return none + * @details \b Outputs: fluidBolusRequested + * @return TRUE if request is accepted, FALSE if rejected. *************************************************************************/ -void signalBloodPrimeFluidBolusRequest( void ) +BOOL signalBloodPrimeFluidBolusRequest( void ) { + BOOL result = FALSE; + if ( ( BLOOD_PRIME_RAMP_STATE == bloodPrimeState ) || ( BLOOD_PRIME_RUN_STATE == bloodPrimeState ) ) { - bloodPrimeResumeState = bloodPrimeState; - lastBloodPrimeFlowRate_mL_min = (U32)getTargetBloodFlowRate(); - bloodPrimeState = BLOOD_PRIME_FLUID_BOLUS_STATE; + fluidBolusRequested = TRUE; + result = TRUE; } + + return result; } /*********************************************************************//** Index: firmware/App/Modes/StateTxBloodPrime.h =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/StateTxBloodPrime.h (.../StateTxBloodPrime.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Modes/StateTxBloodPrime.h (.../StateTxBloodPrime.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -54,7 +54,7 @@ BLOOD_PRIME_STATE_T getCurrentBloodPrimeState( void ); // Get the current treatment sub-mode state BOOL bloodPrimeHandleCmdRequest( MESSAGE_T *message ); // Handle blood prime command from UI BOOL bloodPrimeHandleBloodFlowChangeRequest( MESSAGE_T *message ); // Handle blood prime command from UI -void signalBloodPrimeFluidBolusRequest( void ); // Fluid Bolus request from UI +BOOL signalBloodPrimeFluidBolusRequest( void ); // Fluid Bolus request from UI BOOL testBloodPrimePublishIntervalOverride( MESSAGE_T *message ); BOOL testBloodPrimeVolumeOverride( MESSAGE_T *message ); Index: firmware/App/Modes/StateTxDialysis.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/StateTxDialysis.c (.../StateTxDialysis.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Modes/StateTxDialysis.c (.../StateTxDialysis.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file StateTxDialysis.c * * @author (last) Raghu Kallala -* @date (last) 17-Apr-2026 +* @date (last) 04-May-2026 * * @author (original) Sean Nash * @date (original) 21-Apr-2025 @@ -20,6 +20,7 @@ #include "BloodFlow.h" #include "Buttons.h" #include "DDInterface.h" +#include "FluidBolus.h" #include "Messaging.h" #include "ModeTreatment.h" //#include "NVDataMgmt.h" @@ -40,23 +41,27 @@ // ********** private data ********** static DIALYSIS_STATE_T currentDialysisState; ///< Current state of the dialysis sub-mode state machine. +static DIALYSIS_STATE_T dialysisResumeState; ///< Dialysis 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 F32 setUFVolumeL; ///< Currently set total ultrafiltration volume (in L) for treatment (from prescription). -static F32 setUFRateLHr; ///< Currently set ultrafiltration rate (in L/hr 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 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. +static BOOL bolusStarted; ///< Flag indicating fluid bolus start signal has been sent. // ********** private function prototypes ********** static void transitionToDialysisState( DIALYSIS_STATE_T newState ); static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ); static DIALYSIS_STATE_T handleDialysisUltrafiltrationPausedState( void ); +static DIALYSIS_STATE_T handleDialysisFluidBolusState( void ); static void updateUFVolume( void ); @@ -72,6 +77,7 @@ void initDialysis( void ) { currentDialysisState = DIALYSIS_UF_STATE; + dialysisResumeState = DIALYSIS_UF_STATE; measUFVolumeL.data = 0.0F; measUFVolumeL.ovData = 0.0F; @@ -81,11 +87,13 @@ setBloodFlowRate = 0; setDialysateFlowRate = 0; setUFVolumeL = 0.0F; - setUFRateLHr = 0.0F; + setUFRateMlMin = 0.0F; ufPauseRequested = FALSE; ufResumeRequested = FALSE; autoResumeUF = FALSE; + fluidBolusRequested = FALSE; + bolusStarted = FALSE; } /*********************************************************************//** @@ -115,7 +123,7 @@ setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); // Set actuators as appropriate for state - cmdStartGenerateDialysate( setDialysateFlowRate, setUFRateLHr, dialTemp, FALSE, + cmdStartGenerateDialysate( setDialysateFlowRate, setUFRateMlMin, dialTemp, FALSE, acidConvFactor, bicarbConvFactor, sodium, bicarbonate ); transitionToDialysisState( currentDialysisState ); @@ -141,7 +149,7 @@ 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( setUFRateLHr ); + cmdChangeQuf( setUFRateMlMin ); // Start auto-control of air trap valve startAirTrapControl(); @@ -160,6 +168,13 @@ startAirTrapControl(); break; + case DIALYSIS_UF_FLUID_BOLUS_STATE: + // State prior to bolus + dialysisResumeState = currentDialysisState; + cmdBypassDialyzer( TRUE ); + cmdChangeQuf( 0.0F ); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TX_DIALYSIS_INVALID_STATE1, (U32)newState ) break; @@ -219,17 +234,17 @@ * The setDialysisDDParams function sets the dialysate rate and ultrafiltration * volume and rate parameters. * @details \b Inputs: none - * @details \b Outputs: setDialysateFlowRate, setUFVolumeL, setUFRateLHr + * @details \b Outputs: setDialysateFlowRate, setUFVolumeL, setUFRateMlMin * @param qd target dialysate flow rate (in mL/min) - * @param ufVol target ultrafiltration volume (in L) - * @param quf target ultrafiltration flow rate (in L/hr) + * @param ufVol target ultrafiltration volume (in mL) + * @param quf target ultrafiltration flow rate (in mL/min) * @return none *************************************************************************/ void setDialysisDDParams( U32 qd, F32 ufVol, F32 quf ) { setDialysateFlowRate = qd; setUFVolumeL = ufVol; - setUFRateLHr = quf; + setUFRateMlMin = quf; } /*********************************************************************//** @@ -238,7 +253,7 @@ * 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: currentDialysisState, setUFRateLHr + * @details \b Inputs: currentDialysisState, setUFRateMlMin * @details \b Outputs: ufPauseRequested, ufResumeRequested * @param message Message from UI which includes a flag indicating whether * to pause or resume ultrafiltration. @@ -267,9 +282,9 @@ { ufResumeRequested = TRUE; response.accepted = TRUE; - if ( setUFRateLHr > 0.0 ) + if ( setUFRateMlMin > 0.0 ) { - //sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, setUFRateLHr ); + //sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, setUFRateMlMin ); } } else @@ -295,9 +310,9 @@ { ufPauseRequested = TRUE; response.accepted = TRUE; - if ( setUFRateLHr > 0.0 ) + if ( setUFRateMlMin > 0.0 ) { - //sendTreatmentLogEventData( UF_PAUSE_EVENT, setUFRateLHr, 0.0 ); + //sendTreatmentLogEventData( UF_PAUSE_EVENT, setUFRateMlMin, 0.0 ); } } else @@ -369,6 +384,10 @@ currentDialysisState = handleDialysisUltrafiltrationPausedState(); break; + case DIALYSIS_UF_FLUID_BOLUS_STATE: + currentDialysisState = handleDialysisFluidBolusState(); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TX_DIALYSIS_INVALID_STATE1, (U32)currentDialysisState ) break; @@ -388,8 +407,8 @@ * @brief * The handleDialysisUltrafiltrationState function handles the ultrafiltration * state of the Dialysis state machine. - * @details \b Inputs: ufPauseRequested - * @details \b Outputs: ufPauseRequested + * @details \b Inputs: ufPauseRequested, fluidBolusRequested + * @details \b Outputs: ufPauseRequested, fluidBolusRequested * @return next Dialysis state. *************************************************************************/ static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ) @@ -402,6 +421,17 @@ transitionToDialysisState( DIALYSIS_UF_PAUSED_STATE ); result = DIALYSIS_UF_PAUSED_STATE; } + // When UI requests fluid bolus + else if ( TRUE == fluidBolusRequested ) + { + fluidBolusRequested = FALSE; + transitionToDialysisState( DIALYSIS_UF_FLUID_BOLUS_STATE ); + result = DIALYSIS_UF_FLUID_BOLUS_STATE; + } + else + { + // No action required. + } return result; } @@ -430,6 +460,36 @@ /*********************************************************************//** * @brief + * The handleDialysisFluidBolusState function handles the fluid bolus + * sub-state of the Dialysis state machine. Signals the fluid bolus + * service to start. + * @details \b Inputs: dialysisResumeState, bolusStarted + * @details \b Outputs: bolusStarted + * @return next dialysis state. + *************************************************************************/ +static DIALYSIS_STATE_T handleDialysisFluidBolusState( void ) +{ + DIALYSIS_STATE_T result = DIALYSIS_UF_FLUID_BOLUS_STATE; + + // Start fluid bolus if not started + if ( FALSE == bolusStarted ) + { + bolusStarted = signalStartFluidBolus( setBloodFlowRate ); + } + // Restore actuators and return to pre-bolus sub-state upon bolus complete or abort + else if ( FALSE == isFluidBolusActive() ) + { + cmdBypassDialyzer( FALSE ); + transitionToDialysisState( dialysisResumeState ); + bolusStarted = FALSE; + result = dialysisResumeState; + } + + 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. @@ -443,4 +503,26 @@ measUFVolumeL.data = 0.0F; // TODO } +/*********************************************************************//** + * @brief + * The signalDialysisFluidBolusRequest function signals a fluid bolus + * request to the Dialysis sub-mode. + * @details \b Inputs: currentDialysisState + * @details \b Outputs: fluidBolusRequested + * @return TRUE if request is accepted, FALSE if rejected. + *************************************************************************/ +BOOL signalDialysisFluidBolusRequest( void ) +{ + BOOL result = FALSE; + + // Only allow from UF state + if ( DIALYSIS_UF_STATE == currentDialysisState ) + { + fluidBolusRequested = TRUE; + result = TRUE; + } + + return result; +} + /**@}*/ Index: firmware/App/Modes/StateTxDialysis.h =================================================================== diff -u -r395522dffef1348e176564925656012f529c1910 -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/StateTxDialysis.h (.../StateTxDialysis.h) (revision 395522dffef1348e176564925656012f529c1910) +++ firmware/App/Modes/StateTxDialysis.h (.../StateTxDialysis.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -48,6 +48,7 @@ void setDialysisDDParams( U32 qd, F32 ufVol, F32 quf ); // Signal new DD params BOOL signalPauseResumeUF( MESSAGE_T *message ); // Handles a user request to pause or resume ultrafiltration +BOOL signalDialysisFluidBolusRequest( void ); // Fluid Bolus request from UI /**@}*/ Index: firmware/App/Modes/StateTxPaused.c =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/StateTxPaused.c (.../StateTxPaused.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Modes/StateTxPaused.c (.../StateTxPaused.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -50,6 +50,8 @@ static U32 treatmentPausedPublishTimerCtr; ///< Timer counter (in GP task intervals) counts time to next treatment paused status broadcast. static OVERRIDE_U32_T treatmentPausedPublishInterval; ///< Interval (in task intervals) at which to publish treatment paused state data to CAN bus. static TREATMENT_PAUSED_STATE_T pauseBolusResumeState; ///< Treatment pause sub-state prior to bolus. +static BOOL fluidBolusRequested; ///< Flag indicating fluid bolus has been requested by user. +static BOOL bolusStarted; ///< Flag indicating fluid bolus start signal has been sent. // ********** private function prototypes ********** @@ -81,6 +83,9 @@ treatmentPausedPublishInterval.ovData = TREATMENT_PAUSED_DATA_PUBLISH_INTERVAL; treatmentPausedPublishInterval.ovInitData = TREATMENT_PAUSED_DATA_PUBLISH_INTERVAL; treatmentPausedPublishInterval.override = OVERRIDE_RESET; + + fluidBolusRequested = FALSE; + bolusStarted = FALSE; } /*********************************************************************//** @@ -132,6 +137,9 @@ // coming back to stop state via non-alarm path, so no audio - just want alarm for its options signalAlarmSilence( ALARM_SILENCE_CMD_CANCEL ); } + + // Set if bolus is permitted or not. + setBolusPermitted( isBolusAllowedByActiveAlarms() ); } /*********************************************************************//** @@ -147,6 +155,13 @@ { TREATMENT_PAUSED_STATE_T priorSubState = currentTxPausedState; + if ( TRUE == fluidBolusRequested ) + { + fluidBolusRequested = FALSE; + pauseBolusResumeState = currentTxPausedState; + currentTxPausedState = TREATMENT_PAUSED_FLUID_BOLUS_STATE; + } + switch ( currentTxPausedState ) { case TREATMENT_PAUSED_RECIRC_STATE: @@ -300,31 +315,35 @@ * the user requests a new bolus from the paused state. * Monitors the permitted alarm set every tick — aborts the bolus if a * non-permitted alarm becomes active. - * @details \b Inputs: none - * @details \b Outputs: currentTxPausedState + * @details \b Inputs: bolusStarted + * @details \b Outputs: currentTxPausedState, bolusStarted * @return next treatment paused state. *************************************************************************/ static TREATMENT_PAUSED_STATE_T handleTreatmentPausedFluidBolusState( void ) { TREATMENT_PAUSED_STATE_T state = TREATMENT_PAUSED_FLUID_BOLUS_STATE; - // Signal start - signalStartFluidBolus(); - - // Monitor permitted alarms every tick - if ( ( TRUE == isFluidBolusActive() ) && ( FALSE == areAllActiveAlarmsPermittedForBolus() ) ) + // Start fluid bolus if not started + if ( FALSE == bolusStarted ) { - signalAbortFluidBolus(); + bolusStarted = signalStartFluidBolus( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ); } - - // Run the bolus service every tick - execFluidBolus(); - - // Bolus complete or aborted — return to appropriate paused recirc sub-state - if ( FALSE == isFluidBolusActive() ) + else { - state = pauseBolusResumeState; - transitionToTxPausedState( state ); + // Monitor permitted alarms every tick + if ( ( TRUE == isFluidBolusActive() ) && ( FALSE == isBolusAllowedByActiveAlarms() ) ) + { + signalAbortFluidBolus(); + setBolusPermitted( FALSE ); + } + + // Return to pre-bolus sub-state upon bolus complete or abort + if ( FALSE == isFluidBolusActive() ) + { + bolusStarted = FALSE; + state = pauseBolusResumeState; + transitionToTxPausedState( state ); + } } return state; @@ -333,21 +352,19 @@ /*********************************************************************//** * @brief * The signalPauseFluidBolusRequest function handles a fluid bolus request - * while in the Treatment Paused state. Transitions to the fluid bolus - * sub-state only from recirc sub-states where the blood pump is running. - * Not allowed from no-recirc or dialysate-only recirc sub-states since - * the blood pump is stopped in those states. - * @details \b Inputs: currentTxPausedState - * @details \b Outputs: currentTxPausedState - * @return none + * while in the Treatment Paused state. + * @details \b Inputs: none + * @details \b Outputs: fluidBolusRequested + * @return TRUE if request is accepted, FALSE if rejected. *************************************************************************/ -void signalPauseTreatFluidBolusRequest( void ) +BOOL signalPauseTreatFluidBolusRequest( void ) { - if ( ( TREATMENT_PAUSED_RECIRC_STATE == currentTxPausedState ) || ( TREATMENT_PAUSED_RECIRC_BLOOD_ONLY_STATE == currentTxPausedState ) ) - { - pauseBolusResumeState = currentTxPausedState; - currentTxPausedState = TREATMENT_PAUSED_FLUID_BOLUS_STATE; - } + BOOL result = FALSE; + + fluidBolusRequested = TRUE; + result = TRUE; + + return result; } /*********************************************************************//** @@ -529,6 +546,9 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TREATMENT_STOP_INVALID_STATE, (U32)newState ) break; } + + // Set if bolus is permitted or not. + setBolusPermitted( isBolusAllowedByActiveAlarms() ); } /*********************************************************************//** Index: firmware/App/Modes/StateTxPaused.h =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Modes/StateTxPaused.h (.../StateTxPaused.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Modes/StateTxPaused.h (.../StateTxPaused.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -46,7 +46,7 @@ TREATMENT_PAUSED_STATE_T getCurrentTreatmentPausedState( void );// Get current treatment paused state -void signalPauseTreatFluidBolusRequest( void ); // Fluid Bolus request from UI +BOOL signalPauseTreatFluidBolusRequest( void ); // Fluid Bolus request from UI /**@}*/ Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file AlarmMgmtSWFaults.h * * @author (last) Raghu Kallala -* @date (last) 29-Apr-2026 +* @date (last) 30-Apr-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -186,10 +186,10 @@ SW_FAULT_ID_TD_AIR_PUMP_DUTY_CYCLE_OUT_OF_RANGE = 155, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER = 156, SW_FAULT_ID_INVALID_TREATMENT_MODALITY = 157, - SW_FAULT_ID_INVALID_FLUID_BOLUS_STATE = 158, - SW_FAULT_ID_INVALID_DD_GEN_DIALYSATE_DATA = 159, + SW_FAULT_ID_INVALID_DD_DIALYSATE_DATA = 158, + SW_FAULT_ID_INVALID_FLUID_BOLUS_STATE = 159, SW_FAULT_INVALID_PAYLOAD_LENGTH =160, - NUM_OF_SW_FAULT_IDS + NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; /**@}*/ Index: firmware/App/Services/DDInterface.c =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file DDInterface.c * * @author (last) Raghu Kallala -* @date (last) 21-Apr-2026 +* @date (last) 01-May-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -42,11 +42,12 @@ static F32 dialysatePressure; ///< Current dialysate pressure reported by DD. static BOOL ddStartCommandSent; ///< Flag indicates command to start DD has been sent. static BOOL ddStarted; ///< Flag indicates whether we have commanded the DD to start or stop. +static BOOL isDialysateGoodtoDeliver; ///< Flag indicating whether dialysate is good to deliver. static BOOL ddOpModeDataFreshFlag; ///< Flag to signal the handleDDOpMode() to process fresh dd op mode data. static BOOL ddDialysatePressureFreshFlag; ///< Flag to signal -static BOOL dialysateGoodToDeliver; ///< Flag indicates dialysate readiness (from GEN_DIALYSATE_MODE_DATA_T broadcast). +static PRE_GEN_DIALYSATE_REQ_PAYLOAD_T preGenDialysateCmdSet; ///< Set of pre-generate dialysate parameters to send to the DD static DIALYSATE_DELIVERY_REQ_PAYLOAD_T dialysateDeliveryCmdSet; ///< Set of dialysate delivery parameters to send to the DD during treatment. // DD command response @@ -71,10 +72,10 @@ ddCurrentOpMode = DD_MODE_INIT; ddSubMode = 0; dialysatePressure = 0.0F; + isDialysateGoodtoDeliver = FALSE; ddOpModeDataFreshFlag = FALSE; ddDialysatePressureFreshFlag = FALSE; - dialysateGoodToDeliver = FALSE; resetDDInterface(); @@ -102,6 +103,14 @@ ddStarted = FALSE; ddStartCommandSent = FALSE; + preGenDialysateCmdSet.start = FALSE; + preGenDialysateCmdSet.dialRate = 0.0F; + preGenDialysateCmdSet.dialTemp = 0.0F; + preGenDialysateCmdSet.acidConvFactor = 0.0F; + preGenDialysateCmdSet.bicarbConvFactor = 0.0F; + preGenDialysateCmdSet.sodium = 0; + preGenDialysateCmdSet.bicarbonate = 0; + dialysateDeliveryCmdSet.start = FALSE; dialysateDeliveryCmdSet.dialRate = 0.0F; dialysateDeliveryCmdSet.ufRate = 0.0F; @@ -239,6 +248,38 @@ /*********************************************************************//** * @brief + * The setDialysateData function sets the latest DD dialysate data reported by + * the DD (called by DD published message handler). + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if message is invalid. + * @details \b Inputs: none + * @details \b Outputs: isDialysateGoodtoDeliver + * @param message Pointer to the DD dialysate mode data broadcast message + * @return TRUE if message handled successfully, FALSE if not + *************************************************************************/ +BOOL setDialysateData( MESSAGE_T *message ) +{ + BOOL result = FALSE; + GEN_DIALYSATE_MODE_DATA_T payload; + + // parse message payload + memcpy( &payload, &message->payload[ 0 ], sizeof( GEN_DIALYSATE_MODE_DATA_T ) ); + + if ( message->hdr.payloadLen == sizeof( GEN_DIALYSATE_MODE_DATA_T ) ) + { + isDialysateGoodtoDeliver = payload.isDialysateGoodtoDeliver; + result = TRUE; + } + else + { +#ifndef TEST_UI_ONLY + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DD_DIALYSATE_DATA, (U32)message->hdr.payloadLen ); +#endif + } + return result; +} + +/*********************************************************************//** + * @brief * The getDialysatePressure function gets the latest reported dialysate * pressure. * @details \b Inputs: dialysatePressure @@ -252,6 +293,20 @@ /*********************************************************************//** * @brief + * The getDialysateGoodToDeliverStatus function gets the status + * whether dialysate is good to deliver + * pressure. + * @details \b Inputs: isDialysateGoodtoDeliver + * @details \b Outputs: none + * @return Latest dialysate good to delivery status. + *************************************************************************/ +BOOL getDialysateGoodToDeliverStatus( void ) +{ + return isDialysateGoodtoDeliver; +} + +/*********************************************************************//** + * @brief * The setDialysatePressure function sets the latest dialysate pressure * reported by the DD sub-system. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if message invalid. @@ -288,14 +343,45 @@ /*********************************************************************//** * @brief + * The cmdStartPreGenerateDialysate function sends a pre generate dialysate command + * to the DD with a given set of details. DD will transition to pre generate + * dialysate mode if it hasn't already. + * @details \b Inputs: none + * @details \b Outputs: preGenDialysateCmdSet + * @details \b Message \b Sent: Start/continue pre-generate dialysate command. + * @param qd Target dialysate flow rate (Qd). + * @param dialTemp Target dialysate temperature in deg C. + * @param acidConvFactor Conversion factor for the acid used. + * @param bicarbConvFactor Conversion factor for the bicarbonate used. + * @param sodium Level of sodium used in mEq/L. + * @param bicarbonate Level of bicarbonate used in mEq/L. + * @return none + *************************************************************************/ +void cmdStartPreGenerateDialysate( F32 qd, F32 dialTemp, F32 acidConvFactor, F32 bicarbConvFactor, U32 sodium, U32 bicarbonate ) +{ + preGenDialysateCmdSet.start = TRUE; + preGenDialysateCmdSet.dialRate = qd; + preGenDialysateCmdSet.dialTemp = dialTemp; + preGenDialysateCmdSet.acidConvFactor = acidConvFactor; + preGenDialysateCmdSet.bicarbConvFactor = bicarbConvFactor; + preGenDialysateCmdSet.sodium = sodium; + preGenDialysateCmdSet.bicarbonate = bicarbonate; + +#ifndef TEST_UI_ONLY + sendMessage( MSG_ID_DD_PRE_GEN_DIALYSATE_REQUEST_DATA, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*)(&preGenDialysateCmdSet), sizeof( PRE_GEN_DIALYSATE_REQ_PAYLOAD_T ) ); +#endif +} + +/*********************************************************************//** + * @brief * The cmdStartGenerateDialysate function sends a generate dialysate command * to the DD with a given set of details. DD will transition to dialysate * delivery mode if it hasn't already. * @details \b Inputs: none * @details \b Outputs: dialysateDeliveryCmdSet * @details \b Message \b Sent: Start/continue generate dialysate command. * @param qd Target dialysate flow rate (Qd). - * @param quf Target ultrafiltration rate (Quf). + * @param quf Target ultrafiltration rate (Quf) (in mL/min). * @param dialTemp Target dialysate temperature in deg C. * @param bypass Flag indicating whether dialyzer should be bypassed. * @param acidConvFactor Conversion factor for the acid used. @@ -355,7 +441,7 @@ * @details \b Inputs: none * @details \b Outputs: dialysateDeliveryCmdSet * @details \b Message \b Sent: Continue generate dialysate command w/ new Quf. - * @param quf Target ultrafiltration flow rate (in L/hr). + * @param quf Target ultrafiltration flow rate (in mL/min). * @return none *************************************************************************/ void cmdChangeQuf( F32 quf ) @@ -539,53 +625,7 @@ } } -/*********************************************************************//** - * @brief - * The isDialysateGoodToDeliver function returns the latest DD-reported - * dialysate readiness flag, cached from the DD gen-dialysate state - * broadcast. Used by the fluid bolus service to gate substitution bolus - * start and to monitor during delivery. - * @details \b Inputs: dialysateGoodToDeliver - * @details \b Outputs: none - * @return TRUE if dialysate is ready to deliver per DD, FALSE otherwise. -**************************************************************************/ -BOOL isDialysateGoodToDeliver( void ) -{ - return dialysateGoodToDeliver; -} -/*********************************************************************//** - * @brief - * The setGenDialysateModeData function processes the DD generate-dialysate - * mode data broadcast and caches the dialysate readiness flag. - * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if message payload invalid. - * @details \b Inputs: none - * @details \b Outputs: dialysateGoodToDeliver - * @param message Pointer to DD generate-dialysate state broadcast message. - * @return TRUE if message handled successfully, FALSE if not. - *************************************************************************/ -BOOL setGenDialysateModeData( MESSAGE_T *message ) -{ - BOOL result = FALSE; - GEN_DIALYSATE_MODE_DATA_T payload; - - if ( sizeof( GEN_DIALYSATE_MODE_DATA_T ) == message->hdr.payloadLen ) - { - memcpy( &payload, &message->payload[0], sizeof( GEN_DIALYSATE_MODE_DATA_T ) ); - dialysateGoodToDeliver = payload.isDialysateGoodtoDeliver; - result = TRUE; - } - else - { -#ifndef TEST_UI_ONLY - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DD_GEN_DIALYSATE_DATA, (U32)message->hdr.payloadLen ); -#endif - } - - return result; -} - - /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Services/DDInterface.h =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file DDInterface.h * * @author (last) Raghu Kallala -* @date (last) 17-Apr-2026 +* @date (last) 30-Apr-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -51,10 +51,13 @@ DD_OP_MODE_T getDDOpMode( void ); U32 getDDSubMode( void ); F32 getDialysatePressure( void ); +BOOL getDialysateGoodToDeliverStatus( void ); BOOL setDDOpMode( MESSAGE_T *message ); +BOOL setDialysateData( MESSAGE_T *message ); BOOL setDialysatePressure( MESSAGE_T *message ); +void cmdStartPreGenerateDialysate( F32 qd, F32 dialTemp, F32 acidConvFactor, F32 bicarbConvFactor, U32 sodium, U32 bicarbonate ); void cmdStartGenerateDialysate( F32 qd, F32 quf, F32 dialTemp, BOOL bypass, F32 acidConvFactor, F32 bicarbConvFactor, U32 sodium, U32 bicarbonate ); void cmdChangeQd( F32 qd ); void cmdChangeQuf( F32 quf ); @@ -65,9 +68,6 @@ void handleDDCommandResponse( DD_CMD_RESPONSE_T *ddCmdRespPtr ); BOOL getDDCommandResponse( U32 commandID, DD_CMD_RESPONSE_T *cmdRespPtr ); -BOOL isDialysateGoodToDeliver( void ); -BOOL setGenDialysateModeData( MESSAGE_T *message ); - /**@}*/ #endif Index: firmware/App/Services/FluidBolus.c =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/FluidBolus.c (.../FluidBolus.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Services/FluidBolus.c (.../FluidBolus.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -15,12 +15,17 @@ * ***************************************************************************/ +#include "AlarmMgmt.h" #include "AlarmMgmtTD.h" #include "BloodFlow.h" #include "DDInterface.h" #include "FluidBolus.h" #include "Messaging.h" #include "Pressures.h" +#include "ModeTreatment.h" +#include "StateTxBloodPrime.h" +#include "StateTxDialysis.h" +#include "StateTxPaused.h" #include "TaskGeneral.h" #include "Timers.h" #include "TxParams.h" @@ -33,6 +38,8 @@ // ********** private definitions ********** +#define NUM_OF_FLUID_BOLUS_PERMITTED_ALARMS 6U ///< Number of permitted alarms for fluid bolus from paused state. + static const U32 FLUID_BOLUS_DATA_PUB_INTERVAL = ( MS_PER_SECOND / TASK_GENERAL_INTERVAL); ///< Saline bolus data broadcast interval (ms/task time) count. @@ -43,20 +50,25 @@ static U32 fluidBolusBroadCastTimerCtr; ///< Broadcast Timer counter static BOOL fluidBolusStartRequested; ///< Flag indicates a fluid bolus start has been requested by user. static BOOL fluidBolusAbortRequested; ///< Flag indicates a fluid bolus abort has been requested by user. +static BOOL pubBolusPermitted; ///< Flag indicates a bolus is permitted or not to UI (used to broadcast). +static U32 targetBloodFlowMLPM; ///< Blood pump flow rate (mL/min) to use for current bolus delivery. static F32 totalFluidVolumeDelivered_mL; ///< Volume (mL) in total of fluid delivered so far (cumulative for all boluses including current one). static F32 bolusFluidVolumeDelivered_mL; ///< Volume (mL) of current bolus delivered so far (calculated from measured blood flow rate). static U32 bolusVolumeLastUpdateTimeStamp; ///< Time stamp for last bolus volume update. +// TODO: replace TRUE with getDialysateGoodToDeliverStatus() when we are ready +BOOL isDialysateGoodToDeliver = TRUE; ///< Flag indicating dialysate is good to deliver to the patient. + ///< Permitted alarm list-bolus allowed from paused state -static const ALARM_ID_T FLUID_BOLUS_PERMITTED_PAUSED_ALARMS[] = +static const ALARM_ID_T FLUID_BOLUS_PERMITTED_PAUSED_ALARMS[ NUM_OF_FLUID_BOLUS_PERMITTED_ALARMS ] = { ALARM_ID_TD_TREATMENT_STOPPED_BY_USER, ALARM_ID_TD_ARTERIAL_PRESSURE_HIGH, ALARM_ID_TD_ARTERIAL_PRESSURE_LOW, ALARM_ID_TD_VENOUS_PRESSURE_HIGH, ALARM_ID_TD_TMP_PRESSURE_HIGH, - ALARM_ID_TD_TMP_PRESSURE_LOW, + ALARM_ID_TD_TMP_PRESSURE_LOW }; // ********** private function prototypes ********** @@ -76,21 +88,23 @@ * and therefore should only be called when a new treatment is due to begin. * @details \b Inputs: none * @details \b Outputs: currentFluidBolusState, currentFluidBolusMedium, - * fluidBolusBroadCastTimerCtr, totalFluidVolumeDelivered_mL, + * fluidBolusBroadCastTimerCtr, targetBloodFlowMLPM, totalFluidVolumeDelivered_mL, * bolusFluidVolumeDelivered_mL, fluidBolusStartRequested, - * fluidBolusAbortRequested, bolusVolumeLastUpdateTimeStamp + * fluidBolusAbortRequested, bolusVolumeLastUpdateTimeStamp, pubBolusPermitted * @return none *************************************************************************/ void initFluidBolus( void ) { currentFluidBolusState = FLUID_BOLUS_IDLE_STATE; currentFluidBolusMedium = getFluidBolusMedium(); - fluidBolusBroadCastTimerCtr = 0; + fluidBolusBroadCastTimerCtr = FLUID_BOLUS_DATA_PUB_INTERVAL - 10; // setup to stagger publish from other broadcasters + targetBloodFlowMLPM = 0; totalFluidVolumeDelivered_mL = 0.0F; bolusFluidVolumeDelivered_mL = 0.0F; fluidBolusStartRequested = FALSE; fluidBolusAbortRequested = FALSE; bolusVolumeLastUpdateTimeStamp = getMSTimerCount(); + pubBolusPermitted = TRUE; } /*********************************************************************//** @@ -133,6 +147,9 @@ SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_STATE_CHANGE, priorState, currentFluidBolusState ); } + // Publish fluid bolus data at set interval (whether we are delivering one or not) + publishFluidBolusData(); + return currentFluidBolusState; } @@ -161,18 +178,6 @@ /*********************************************************************//** * @brief - * The getFluidBolusState function gets the current fluid bolus state. - * @details \b Inputs: currentFluidBolusState - * @details \b Outputs: none - * @return currentFluidBolusState - *************************************************************************/ -FLUID_BOLUS_STATE_T getFluidBolusState( void ) -{ - return currentFluidBolusState; -} - -/*********************************************************************//** - * @brief * The isFluidBolusActive function determines whether a fluid bolus is * currently being delivered. * @details \b Inputs: currentFluidBolusState @@ -199,32 +204,20 @@ /*********************************************************************//** * @brief - * The getCurrentFluidBolusVolumeDelivered function gets the volume - * delivered for the currently active bolus. - * @details \b Inputs: bolusFluidVolumeDelivered_mL - * @details \b Outputs: none - * @return current bolus volume delivered in mL. - *************************************************************************/ -F32 getCurrentFluidBolusVolumeDelivered( void ) -{ - return bolusFluidVolumeDelivered_mL; -} - -/*********************************************************************//** - * @brief * The signalStartFluidBolus function is called by a parent treatment state * to initiate a fluid bolus. * @details \b Inputs: currentFluidBolusState - * @details \b Outputs: fluidBolusStartRequested - * @return TRUE if state is IDLE, FALSE otherwise. + * @details \b Outputs: fluidBolusStartRequested, targetBloodFlowMLPM + * @return none *************************************************************************/ -BOOL signalStartFluidBolus( void ) +BOOL signalStartFluidBolus( U32 flowRate ) { BOOL result = FALSE; if ( ( FLUID_BOLUS_IDLE_STATE == currentFluidBolusState ) && ( FALSE == fluidBolusStartRequested ) ) { fluidBolusStartRequested = TRUE; + targetBloodFlowMLPM = flowRate; result = TRUE; } @@ -249,10 +242,25 @@ /*********************************************************************//** * @brief + * The setBolusPermitted function sets the fluid bolus permitted flag, + * which is broadcast to the UI to enable or disable the fluid bolus + * button on screen. + * @details \b Inputs: none + * @details \b Outputs: pubBolusPermitted + * @param permitted TRUE if a fluid bolus is currently permitted, FALSE otherwise. + * @return none + *************************************************************************/ +void setBolusPermitted( BOOL permitted ) +{ + pubBolusPermitted = permitted; +} + +/*********************************************************************//** + * @brief * The publishFluidBolusData function publishes the fluid bolus data * at the set time interval. * @details \b Inputs: fluidBolusBroadCastTimerCtr, currentFluidBolusState, - * bolusFluidVolumeDelivered_mL, totalFluidVolumeDelivered_mL + * bolusFluidVolumeDelivered_mL, totalFluidVolumeDelivered_mL, pubBolusPermitted * @details \b Outputs: fluidBolusBroadCastTimerCtr * @return none *************************************************************************/ @@ -266,6 +274,7 @@ data.bolFluidVolumeMl = bolusFluidVolumeDelivered_mL; data.cumFluidVolumeMl = totalFluidVolumeDelivered_mL; data.fluidBolusState = currentFluidBolusState; + data.bolusPermitted = pubBolusPermitted; broadcastData( MSG_ID_TD_FLUID_BOLUS_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( FLUID_BOLUS_DATA_PAYLOAD_T ) ); @@ -290,7 +299,7 @@ { fluidBolusStartRequested = FALSE; // Stop blood pump - setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + signalBloodPumpHardStop(); // Stop substitution pump cmdSubstitutionRate( 0.0F ); bolusVolumeLastUpdateTimeStamp = getMSTimerCount(); @@ -325,23 +334,23 @@ bolusFluidVolumeDelivered_mL = 0.0; bolusVolumeLastUpdateTimeStamp = getMSTimerCount(); + // Set arterial & venous valves setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); if ( FLUID_BOLUS_MEDIUM_SALINE == currentFluidBolusMedium ) { - setBloodPumpTargetFlowRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ), MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + setBloodPumpTargetFlowRate( targetBloodFlowMLPM, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); state = FLUID_BOLUS_SALINE_IN_PROGRESS_STATE; } - else if ( TRUE == isDialysateGoodToDeliver() ) + else if ( TRUE == isDialysateGoodToDeliver ) { // set D92 flow rate - cmdSubstitutionRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ); + cmdSubstitutionRate( (F32)targetBloodFlowMLPM ); state = FLUID_BOLUS_SUBSITUTE_IN_PROGRESS_STATE; } else { - // No actuator action required. state = FLUID_BOLUS_IDLE_STATE; } } @@ -356,13 +365,13 @@ * volume from measured blood flow, fires an alarm if the saline bag is empty, * and completes the bolus when the target volume is reached or an abort is requested. * @details \b Inputs: bolusFluidVolumeDelivered_mL, fluidBolusAbortRequested - * @details \b Outputs: fluidBolusAbortRequested, + * @details \b Outputs: fluidBolusAbortRequested * @return next fluid bolus state *************************************************************************/ static FLUID_BOLUS_STATE_T handleFluidBolusSalineInProgressState( void ) { - FLUID_BOLUS_STATE_T state = FLUID_BOLUS_SALINE_IN_PROGRESS_STATE; - F32 bolusTargetVolume = (F32)getTreatmentParameterU32( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); + FLUID_BOLUS_STATE_T state = FLUID_BOLUS_SALINE_IN_PROGRESS_STATE; + F32 bolusTargetVolume = (F32)getTreatmentParameterU32( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); updateFluidBolusVolumeDelivered(); @@ -373,11 +382,15 @@ state = FLUID_BOLUS_IDLE_STATE; } // Determine if bolus is complete or stopped by user - else if ( ( bolusFluidVolumeDelivered_mL >= bolusTargetVolume ) || ( TRUE == fluidBolusAbortRequested ) ) + if ( ( bolusFluidVolumeDelivered_mL >= bolusTargetVolume ) || ( TRUE == fluidBolusAbortRequested ) ) { fluidBolusAbortRequested = FALSE; state = FLUID_BOLUS_IDLE_STATE; } + else + { + // No action required + } // complete or abort or alarm if ( state != FLUID_BOLUS_SALINE_IN_PROGRESS_STATE ) @@ -410,10 +423,9 @@ updateFluidBolusVolumeDelivered(); // Check for dialysate, target volume delivered or abort from user - if ( ( FALSE == isDialysateGoodToDeliver() ) || ( bolusFluidVolumeDelivered_mL >= bolusTargetVolume ) || ( TRUE == fluidBolusAbortRequested ) ) + if ( ( FALSE == isDialysateGoodToDeliver ) || ( bolusFluidVolumeDelivered_mL >= bolusTargetVolume ) || ( TRUE == fluidBolusAbortRequested ) ) { fluidBolusAbortRequested = FALSE; - // TODO: d92 to restore or turn off if modality is hd. cmdSubstitutionRate( 0.0F ); completeBolusToCumulative(); state = FLUID_BOLUS_IDLE_STATE; @@ -426,26 +438,15 @@ * @brief * The updateFluidBolusVolumeDelivered function integrates the volume * delivered for the active bolus. - * @details \b Inputs: currentFluidBolusMedium, bolusVolumeLastUpdateTimeStamp + * @details \b Inputs: bolusVolumeLastUpdateTimeStamp, targetBloodFlowMLPM * @details \b Outputs: bolusFluidVolumeDelivered_mL, bolusVolumeLastUpdateTimeStamp * @return none *************************************************************************/ static void updateFluidBolusVolumeDelivered( void ) { F32 timeSinceLastVolumeUpdateMin = (F32)calcTimeSince( bolusVolumeLastUpdateTimeStamp ) / (F32)( MS_PER_SECOND * SEC_PER_MIN ); - F32 rate_mL_min; - if ( FLUID_BOLUS_MEDIUM_SALINE == currentFluidBolusMedium ) - { - rate_mL_min = getMeasuredBloodFlowRate(); - } - else - { - //TODO - rate_mL_min = (F32)getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ); - } - - bolusFluidVolumeDelivered_mL += rate_mL_min * timeSinceLastVolumeUpdateMin; + bolusFluidVolumeDelivered_mL += (F32)targetBloodFlowMLPM * timeSinceLastVolumeUpdateMin; bolusVolumeLastUpdateTimeStamp = getMSTimerCount(); } @@ -466,37 +467,159 @@ /*********************************************************************//** * @brief - * The areAllActiveAlarmsPermittedForBolus function checks whether all - * currently active alarms are from permitted list. - * @details \b Inputs: FLUID_BOLUS_PERMITTED_PAUSED_ALARMS[] + * The isBolusAllowedByActiveAlarms function checks whether all + * currently active alarms permit a fluid bolus from the paused state. + * For saline medium, a non-permitted alarm blocks the bolus only if it is + * TD source. For substitute medium, any non-permitted alarm blocks the bolus. + * @details \b Inputs: FLUID_BOLUS_PERMITTED_PAUSED_ALARMS[], currentFluidBolusMedium * @details \b Outputs: none - * @return TRUE if all active alarms are from the permitted list and at - * least one permitted alarm is active. FALSE otherwise. + * @return TRUE if all active alarms permit the bolus, FALSE otherwise. *************************************************************************/ -BOOL areAllActiveAlarmsPermittedForBolus( void ) +BOOL isBolusAllowedByActiveAlarms( void ) { - U32 i; - U32 permittedCount = 0U; - U32 totalCount = getActiveAlarmCount(); - BOOL result = FALSE; + U32 alarm; + U32 permittedIndex; + BOOL permitted = FALSE; + BOOL result = TRUE; - if ( 0U == totalCount ) + for ( alarm = 0; alarm < NUM_OF_ALARM_IDS; alarm++ ) { - return FALSE; + if ( TRUE == isAlarmActive( alarm ) ) + { + for ( permittedIndex = 0; permittedIndex < NUM_OF_FLUID_BOLUS_PERMITTED_ALARMS; permittedIndex++ ) + { + if ( FLUID_BOLUS_PERMITTED_PAUSED_ALARMS[ permittedIndex ] == alarm ) + { + permitted = TRUE; + break; + } + } + + if ( FALSE == permitted ) + { + if ( FLUID_BOLUS_MEDIUM_SALINE == currentFluidBolusMedium ) + { + if ( ALM_SRC_TD == getAlarmSource( alarm ) ) + { + result = FALSE; + break; + } + } + else + { + result = FALSE; + break; + } + } + } } - for ( i = 0U; i < 6; i++ ) + return result; +} + +/*********************************************************************//** +* @brief +* The handleFluidBolusRequest function handles the UI fluid bolus request. +* @details \b Message \b Sent: MSG_ID_TD_FLUID_BOLUS_RESPONSE +* @details \b Inputs: none +* @details \b Outputs: none +* @return TRUE if request is accepted, FALSE if rejected. +*************************************************************************/ +BOOL handleFluidBolusRequest( MESSAGE_T *message ) +{ + BOOL result = FALSE; + U32 cmd = 0; + REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; + FLUID_BOLUS_RESPONSE_PAYLOAD_T response; + + if ( sizeof(U32) == message->hdr.payloadLen ) { - if ( TRUE == isAlarmActive( FLUID_BOLUS_PERMITTED_PAUSED_ALARMS[ i ] ) ) + memcpy( &cmd, message->payload, sizeof(U32) ); + + if ( FLUID_BOLUS_CMD_START == cmd ) { - permittedCount++; + if ( TRUE == isFluidBolusActive() ) + { + // TD Fluid Bolus Additional Bolus Prevention + rejReason = REQUEST_REJECT_REASON_FLUID_BOLUS_IN_PROGRESS; + } + else if ( TREATMENT_PAUSED_STATE == getTreatmentState() ) + { + if ( ( TRUE == isBolusAllowedByActiveAlarms() ) ) + { + result = signalPauseTreatFluidBolusRequest(); + rejReason = ( result == TRUE ) ? REQUEST_REJECT_REASON_NONE : REQUEST_REJECT_REASON_INVALID_TREATMENT_SUB_STATE; + } + else + { + rejReason = REQUEST_REJECT_REASON_ALARM_IS_ACTIVE; + } + } + else + { + // Route to whichever calling state is currently active + switch ( getTreatmentState() ) + { + case TREATMENT_BLOOD_PRIME_STATE: + result = signalBloodPrimeFluidBolusRequest(); + rejReason = ( result == TRUE ) ? REQUEST_REJECT_REASON_NONE : REQUEST_REJECT_REASON_INVALID_TREATMENT_SUB_STATE; + break; + + case TREATMENT_DIALYSIS_STATE: + result = signalDialysisFluidBolusRequest(); + rejReason = ( result == TRUE ) ? REQUEST_REJECT_REASON_NONE : REQUEST_REJECT_REASON_INVALID_TREATMENT_SUB_STATE; + break; + +// case TREATMENT_HDF_STATE: +// result = signalHdfFluidBolusRequest(); +// rejReason = ( result == TRUE ) ? REQUEST_REJECT_REASON_NONE : REQUEST_REJECT_REASON_INVALID_TREATMENT_SUB_STATE; +// break; +// +// case TREATMENT_ISO_UF_STATE: +// result = signalIsoUFFluidBolusRequest(); +// rejReason = ( result == TRUE ) ? REQUEST_REJECT_REASON_NONE : REQUEST_REJECT_REASON_INVALID_TREATMENT_SUB_STATE; +// break; +// +// case TREATMENT_END_STATE: +// result = signalTreatmentEndFluidBolusRequest(); +// rejReason = ( result == TRUE ) ? REQUEST_REJECT_REASON_NONE : REQUEST_REJECT_REASON_INVALID_TREATMENT_SUB_STATE; +// break; + + default: + rejReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; + break; + } + } } + else if ( FLUID_BOLUS_CMD_STOP == cmd ) + { + if ( TRUE == isFluidBolusActive() ) + { + signalAbortFluidBolus(); + result = TRUE; + rejReason = REQUEST_REJECT_REASON_NONE; + } + else + { + rejReason = REQUEST_REJECT_REASON_FLUID_BOLUS_NOT_IN_PROGRESS; + } + } + else + { + rejReason = REQUEST_REJECT_REASON_INVALID_COMMAND; + } } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_INVALID_PAYLOAD_LENGTH, (U32)message->hdr.payloadLen ); + } - result = ( permittedCount == totalCount ) ? TRUE: FALSE; + response.accepted = result; + response.rejectionReason = rejReason; + response.targetVolumeMl = getTreatmentParameterU32( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); + sendMessage( MSG_ID_TD_FLUID_BOLUS_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)&response, sizeof( FLUID_BOLUS_RESPONSE_PAYLOAD_T ) ); return result; } - /**@}*/ Index: firmware/App/Services/FluidBolus.h =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/FluidBolus.h (.../FluidBolus.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Services/FluidBolus.h (.../FluidBolus.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -22,9 +22,9 @@ #include "TDDefs.h" /** - * @defgroup FluidBolus, FluidBolus + * @defgroup FluidBolus FluidBolus * @brief Fluid Bolus unit provides bolus service to the - * Blood Prime, HD/HDF, ISO UF, End states of Treatment mode. + * Blood Prime, HD/HDF, ISO UF, Pause, End states of Treatment mode. * * @addtogroup FluidBolus * @{ @@ -45,29 +45,30 @@ /// Payload record structure for a fluid bolus data broadcast message. typedef struct { - U32 tgtFluidVolumeMl; ///< Target Fluid volume in mL. - F32 bolFluidVolumeMl; ///< Bolus Fluid volume in mL. - F32 cumFluidVolumeMl; ///< Cumulative Fluid volume in mL. - U32 fluidBolusState; ///< Current Fluid Bolus state. + U32 tgtFluidVolumeMl; ///< Target Fluid volume in mL. + F32 bolFluidVolumeMl; ///< Bolus Fluid volume in mL. + F32 cumFluidVolumeMl; ///< Cumulative Fluid volume in mL. + U32 fluidBolusState; ///< Current Fluid Bolus state. + BOOL bolusPermitted; ///< True if Bolus is permitted currently. } FLUID_BOLUS_DATA_PAYLOAD_T; #pragma pack(pop) // ********** public definitions ********** void initFluidBolus( void ); void publishFluidBolusData( void ); +void setBolusPermitted( BOOL permitted ); FLUID_BOLUS_STATE_T execFluidBolus( void ); -FLUID_BOLUS_STATE_T getFluidBolusState( void ); FLUID_BOLUS_MEDIUM_T getFluidBolusMedium( void ); BOOL isFluidBolusActive( void ); -BOOL signalStartFluidBolus( void ); +BOOL signalStartFluidBolus( U32 flowRate ); void signalAbortFluidBolus( void ); -F32 getCurrentFluidBolusVolumeDelivered( void ); F32 getTotalFluidBolusVolumeDelivered( void ); -BOOL areAllActiveAlarmsPermittedForBolus( void ); +BOOL handleFluidBolusRequest( MESSAGE_T *message ); +BOOL isBolusAllowedByActiveAlarms( void ); /**@}*/ Index: firmware/App/Services/Messaging.c =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file Messaging.c * * @author (last) Raghu Kallala -* @date (last) 06-Apr-2026 +* @date (last) 30-Apr-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -43,7 +43,6 @@ #include "Switches.h" #include "SystemCommTD.h" #include "Temperatures.h" -#include "TDDefs.h" #include "TxParams.h" #include "Utilities.h" #include "Valve3Way.h" @@ -109,6 +108,7 @@ { MSG_ID_FW_VERSIONS_REQUEST, &handleVersionRequestMessage }, { MSG_ID_UI_CHECK_IN, &handleUICheckIn }, { MSG_ID_DD_OP_MODE_DATA, &setDDOpMode }, + { MSG_ID_DD_GEN_DIALYSATE_MODE_DATA, &setDialysateData }, { MSG_ID_DD_PRESSURES_DATA, &setDialysatePressure }, { MSG_ID_UI_TREATMENT_PARAMS_TO_VALIDATE, &validateAndSetTreatmentParameters }, { MSG_ID_UI_INITIATE_TREATMENT_WORKFLOW, &signalUserInitiateTreatment }, @@ -118,7 +118,6 @@ { MSG_ID_UI_BLOOD_PRIME_CMD_REQUEST, &bloodPrimeHandleCmdRequest }, { MSG_ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_REQUEST, &bloodPrimeHandleBloodFlowChangeRequest }, { MSG_ID_UI_FLUID_BOLUS_REQUEST, &handleFluidBolusRequest }, - { MSG_ID_DD_GEN_DIALYSATE_MODE_DATA, &setGenDialysateModeData }, { MSG_ID_TD_SOFTWARE_RESET_REQUEST, &testTDSoftwareResetRequest }, { MSG_ID_TD_BUBBLE_OVERRIDE_REQUEST, &testBubbleDetectOverride }, { MSG_ID_TD_BUBBLE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testBubblesDataPublishIntervalOverride }, @@ -567,107 +566,7 @@ return result; } -/*********************************************************************//** -* @brief -* The handleFluidBolusRequest function handles the UI fluid bolus request. -* @details \b Message \b Sent: MSG_ID_TD_FLUID_BOLUS_RESPONSE -* @details \b Inputs: none -* @details \b Outputs: none -* @return TRUE if request is accepted, FALSE if rejected. -*************************************************************************/ -BOOL handleFluidBolusRequest( MESSAGE_T *message ) -{ - BOOL result = FALSE; - U32 cmd = 0; - REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; - FLUID_BOLUS_RESPONSE_PAYLOAD_T response; - if ( sizeof(U32) == message->hdr.payloadLen ) - { - memcpy( &cmd, message->payload, sizeof(U32) ); - - if ( FLUID_BOLUS_CMD_START == cmd ) - { - if ( TRUE == isFluidBolusActive() ) - { - // TD Fluid Bolus Additional Bolus Prevention - rejReason = REQUEST_REJECT_REASON_FLUID_BOLUS_IN_PROGRESS; - } - else if ( TREATMENT_PAUSED_STATE == getTreatmentState() ) - { - if ( ( TRUE == areAllActiveAlarmsPermittedForBolus() ) ) - { - signalPauseTreatFluidBolusRequest(); - result = TRUE; - } - else - { - rejReason = REQUEST_REJECT_REASON_ALARM_IS_ACTIVE; - } - } - else - { - // Route to whichever calling state is currently active - switch ( getTreatmentState() ) - { - case TREATMENT_BLOOD_PRIME_STATE: - signalBloodPrimeFluidBolusRequest(); - result = TRUE; - break; - -// case TREATMENT_DIALYSIS_STATE: -// signalDialysisFluidBolusRequest(); -// result = TRUE; -// break; -// -// case TREATMENT_ISO_UF_STATE: -// signalIsoUFFluidBolusRequest(); -// result = TRUE; -// break; -// -// case TREATMENT_END_STATE: -// signalTreatmentEndFluidBolusRequest(); -// result = TRUE; -// break; - - default: - rejReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; - break; - } - } - } - else if ( FLUID_BOLUS_CMD_STOP == cmd ) - { - if ( TRUE == isFluidBolusActive() ) - { - signalAbortFluidBolus(); - result = TRUE; - rejReason = REQUEST_REJECT_REASON_NONE; - } - else - { - rejReason = REQUEST_REJECT_REASON_FLUID_BOLUS_NOT_IN_PROGRESS; - } - } - else - { - rejReason = REQUEST_REJECT_REASON_INVALID_COMMAND; - } - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_INVALID_PAYLOAD_LENGTH, (U32)message->hdr.payloadLen ); - } - - response.accepted = result; - response.rejectionReason = rejReason; - response.targetVolumeMl = getTreatmentParameterU32( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); - sendMessage( MSG_ID_TD_FLUID_BOLUS_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)&response, sizeof( FLUID_BOLUS_RESPONSE_PAYLOAD_T ) ); - - return result; -} - - /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Services/Messaging.h =================================================================== diff -u -r6f876554db45a19590eaf2122ef47e33f7a7d69b -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/Messaging.h (.../Messaging.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) +++ firmware/App/Services/Messaging.h (.../Messaging.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -167,8 +167,6 @@ BOOL handleUICheckIn( MESSAGE_T *message ); BOOL handleTesterLogInRequest( MESSAGE_T *message ); -BOOL handleFluidBolusRequest( MESSAGE_T *message ); - BOOL testTDSoftwareResetRequest( MESSAGE_T *message ); // Test send message helper functions Index: firmware/App/Services/TxParams.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/TxParams.c (.../TxParams.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/TxParams.c (.../TxParams.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file TxParams.c * * @author (last) Raghu Kallala -* @date (last) 28-Apr-2026 +* @date (last) 01-May-2026 * * @author (original) Varshini Nagabooshanam * @date (original) 02-Dec-2025 @@ -190,8 +190,8 @@ static BOOL checkTreatmentParamsInRange( U32 *reasons ); static BOOL checkTreatmentParamsDependencies( U32 *reasons ); static BOOL checkUFDependencies( U32 *reasons ); -static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_PAYLOAD_T payload ); -//static void checkPressureParamsRange( TREATMENT_PARAMS_DATA_PAYLOAD_T* txParams ); +static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T payload ); +//static void checkPressureParamsRange( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T* txParams ); static void sendTreatmentParamsResponse( BOOL rejected, U32 *reasons ); //static void getInstitutionalRecordEdgeValue( TREATMENT_PARAM_T param, CRITICAL_DATAS_T* value, BOOL isMin ); @@ -438,7 +438,7 @@ BOOL paramsAreInRange, paramsAreConsistent, isUFValid; BOOL result = FALSE; BOOL paramsConfirmed = FALSE; - TREATMENT_PARAMS_DATA_PAYLOAD_T params; + TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T params; U32 rejReasons[ NUM_OF_TREATMENT_PARAMS ]; // Initialize reject reasons to zeroes @@ -448,7 +448,7 @@ if ( sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) == message->hdr.payloadLen ) { // copy only the treatment parameters excluding the confirmation payload field - memcpy( ¶ms, message->payload + sizeof(BOOL), sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) - sizeof(BOOL) ); + memcpy( ¶ms, message->payload + sizeof(BOOL), sizeof( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T ) ); // Flag indicating if the user have sent the tx params validation from pre-treatment create rx state, // so that if all params are valid, TD software will transition state to patient connection @@ -488,7 +488,7 @@ setCriticalData( &treatmentParameters[ param ], stagedParams[ param ] ); } // Send latest and final treatment parameters to UI - sendMessage( MSG_ID_TD_VALIDATED_TREATMENT_PARAMS, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&stagedParams), sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) ); + sendMessage( MSG_ID_TD_VALIDATED_TREATMENT_PARAMS, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&stagedParams), sizeof( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T ) ); } // Respond to set treatment parameters request message @@ -871,10 +871,10 @@ * @param payload message payload record containing received treatment parameters * @return none *************************************************************************/ -static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_PAYLOAD_T payload ) +static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T payload ) { // Pull treatment parameters into data array so we can more easily work with them - memcpy( &stagedParams[0], &payload, sizeof(TREATMENT_PARAMS_DATA_PAYLOAD_T) ); + memcpy( &stagedParams[0], &payload, sizeof(TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T) ); } /*********************************************************************//** @@ -894,7 +894,7 @@ TREATMENT_PARAMS_VAL_RESP_DATA_PAYLOAD_T payload; payload.accepted = ( TRUE == rejected ? FALSE : TRUE ); - memcpy( &payload.reason[0], &reasons[0], sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) ); + memcpy( &payload.reason[0], &reasons[0], sizeof( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T ) ); sendMessage( MSG_ID_TD_RESP_TREATMENT_PARAMS_TO_VALIDATE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&payload), sizeof( TREATMENT_PARAMS_VAL_RESP_DATA_PAYLOAD_T ) ); } @@ -1466,16 +1466,16 @@ // Verify payload length if ( 0 == message->hdr.payloadLen ) { - TREATMENT_PARAMS_DATA_PAYLOAD_T payload; + TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T payload; TREATMENT_PARAM_T param; // Build and publish current treatment parameters record for ( param = (TREATMENT_PARAM_T)0; param < NUM_OF_TREATMENT_PARAMS; param++ ) { stagedParams[ param ] = treatmentParameters[ param ].data; } - memcpy( (U08*)&payload, (U08*)&stagedParams[0], sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) ); - sendMessage( MSG_ID_TD_RSP_CURRENT_TREATMENT_PARAMETERS, COMM_BUFFER_OUT_CAN_PC, (U08*)&payload, sizeof( TREATMENT_PARAMS_DATA_PAYLOAD_T ) ); + memcpy( (U08*)&payload, (U08*)&stagedParams[0], sizeof( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T ) ); + sendMessage( MSG_ID_TD_RSP_CURRENT_TREATMENT_PARAMETERS, COMM_BUFFER_OUT_CAN_PC, (U08*)&payload, sizeof( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T ) ); result = TRUE; } Index: firmware/App/Services/TxParams.h =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Services/TxParams.h (.../TxParams.h) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/TxParams.h (.../TxParams.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -8,7 +8,7 @@ * @file TxParams.h * * @author (last) Raghu Kallala -* @date (last) 28-Apr-2026 +* @date (last) 01-May-2026 * * @author (original) Varshini Nagabooshanam * @date (original) 02-Dec-2025 @@ -68,6 +68,35 @@ F32 ufVolume; ///< User set ultrafiltration volume (in L) } TREATMENT_PARAMS_DATA_PAYLOAD_T; +/// Record structure for a treatment parameters payload to UI. +typedef struct +{ + U32 treatmentModality; ///< User set treatment modality option + U32 hdfDilution; ///< User set HDF dilution option + U32 bloodFlowRate_mL_min; ///< User set blood flow rate (in mL/min) + U32 dialysateFlowRate_mL_min; ///< User set dialysate flow rate (in mL/min) + U32 treatmentDuration_min; ///< User set treatment duration (in min) + U32 hepDeliveryDuration_min; ///< User set Heparin delivery duration (in min) + U32 hepType; ///< User set Heparin type option + U32 dryBicarbCartSize; ///< User set dry bicarb cart size option + U32 sodium_mEq_L; ///< User set sodium (in mEq/L) + U32 bicarbonate_mEq_L; ///< User set bicarbonate (in mEq/L) + U32 dialyzerType; ///< User set dialyzer type option + U32 fluidBolusVolume_mL; ///< User set fluid bolus volume (in mL) + U32 bpInterval_min; ///< User set blood pressure measurement interval (in min) + U32 rinsebackVolume_mL; ///< User set rinseback volume (in mL) + U32 hepatitisBStatus; ///< User set Hepatitis B status option + U32 acidConcentrate; ///< User set acid concentrate option + F32 substitutionFluidVolume_L; ///< User set substitution fluid volume (in L) + F32 hepBolusVolume_mL; ///< User set Heparin bolus volume (in mL) + F32 hepDeliveryRate_mL_hr; ///< User set Heparin delivery rate (in mL/hr) + F32 dialysateTemperature_degC; ///< User set dialysate temperature (in deg C) + F32 acidKConcentrateConvFactor; ///< User set acid concentrate conversion factor + F32 ufPreWeight; ///< User set patient pre weight prior to treatment (in Kilogram) + F32 ufEstimatedTargetWeight; ///< User set patient estimated target weight after the treatment (in Kilogram) + F32 ufVolume; ///< User set ultrafiltration volume (in L) +} TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T; + /// Record structure for reporting all current treatment parameters to Dialin typedef struct { Index: firmware/App/TDCommon.h =================================================================== diff -u -rd212465988292ce9cee4c1086371b88be46f8504 -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/TDCommon.h (.../TDCommon.h) (revision d212465988292ce9cee4c1086371b88be46f8504) +++ firmware/App/TDCommon.h (.../TDCommon.h) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -22,10 +22,10 @@ // ********** version ********** -#define TD_VERSION_MAJOR 0 -#define TD_VERSION_MINOR 0 -#define TD_VERSION_MICRO 0 -#define TD_VERSION_BUILD 42 +#define TD_VERSION_MAJOR 0 +#define TD_VERSION_MINOR 0 +#define TD_VERSION_MICRO 0 +#define TD_VERSION_BUILD 45 // ********** development build switches ********** Index: firmware/App/Tasks/TaskGeneral.c =================================================================== diff -u -r395522dffef1348e176564925656012f529c1910 -r1abc0349c736a70fb56db6895947abfbba0eee22 --- firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 395522dffef1348e176564925656012f529c1910) +++ firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 1abc0349c736a70fb56db6895947abfbba0eee22) @@ -7,8 +7,8 @@ * * @file TaskGeneral.c * -* @author (last) Dara Navaei -* @date (last) 31-Oct-2025 +* @author (last) Sean Nash +* @date (last) 01-May-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -132,222 +132,6 @@ execSystemCommTx(); } - // ****************** Start Air Trap Test Code ************************ - -#ifdef TEST_PINCH_VALVES -#if 0 - static U32 vlvCmd = 0; - S16 pos = getH19EncoderPosition(); - - readValves(); - // Get level sensor data - readAirTrapLevelSensors(); - if ( 1 == vlvCmd ) - { - setValveCmdChangePosition( H1_VALV, 896, MOTOR_DIR_FORWARD ); - setValveCmdChangePosition( H19_VALV, 1600, MOTOR_DIR_FORWARD ); - vlvCmd = 0; - } - if ( 2 == vlvCmd ) - { - setValveCmdChangePosition( H1_VALV, 0, MOTOR_DIR_FORWARD ); - setValveCmdChangePosition( H19_VALV, 0, MOTOR_DIR_FORWARD ); - vlvCmd = 0; - } -#endif -#if 1 - { - static BOOL homeValveCmd = FALSE; - static BOOL setValvePos = FALSE; - static BOOL homeBPCmd = FALSE; - static BOOL bpHomed = FALSE; - static BOOL bpRunCmd = FALSE; - static BOOL bpStopCmd = FALSE; - static U32 bpSetPt = 300; - static VALVE_POSITION_T setPos = VALVE_POSITION_A_INSERT_EJECT; // VALVE_POSITION_B_OPEN VALVE_POSITION_C_CLOSE VALVE_POSITION_A_INSERT_EJECT - - execValvesController(); - execBloodFlowMonitor(); - execBloodFlowController(); - - bpHomed = isPeristalticPumpHome(); - if ( TRUE == bpHomed ) - { - bpHomed = FALSE; - } - if ( TRUE == homeBPCmd ) - { - homeBloodPump(); - homeBPCmd = FALSE; - } - - if ( TRUE == bpRunCmd ) - { - setBloodPumpTargetFlowRate( bpSetPt, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); - bpRunCmd = FALSE; - } - else if ( TRUE == bpStopCmd ) - { - setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); - bpStopCmd = FALSE; - //signalBloodPumpHardStop(); - } - - if ( TRUE == homeValveCmd ) - { - homeValve( H1_VALV, FALSE, FALSE ); - homeValveCmd = FALSE; - } - if ( TRUE == setValvePos ) - { - setValvePosition( H1_VALV, setPos ); - setValvePos = FALSE; - } - } -#endif -#endif - -#ifdef TEST_AIR_TRAP_ALPHA_TESTING -#if 0 - { - static U32 tmpCtr = 0; - - ++tmpCtr; - if ( tmpCtr == ( 5 * 20 ) ) - { - setAirPumpMotorPower( 250 ); - set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); - } - else if ( tmpCtr == ( 10 * 20 ) ) - { - setAirPumpMotorPower( 0 ); - set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); - } - else if ( tmpCtr == ( 15 * 20 ) ) - { - setAirPumpMotorPower( 250 ); - set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); - } - else if ( tmpCtr >= ( 20 * 20 ) ) - { - setAirPumpMotorPower( 0 ); - set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); - tmpCtr = 0; - } - } -#endif -#if 1 - static U32 ctr = 0; - static U32 sta = 0; - static BOOL start = TRUE; - static BOOL bpStart = FALSE; - static BOOL bpStop = FALSE; - - if ( FALSE == bpStart ) - { -// setBloodPumpTargetRPM( 1200, MOTOR_DIR_FORWARD ); - homeEjector(); - retractEjector(); - bpStart = TRUE; - } - if ( TRUE == bpStop ) - { - signalBloodPumpHardStop(); -// setAirPumpState( AIR_PUMP_STATE_ON, AIR_PUMP_MOTOR_OFF ); -// set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); -// set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); - extendEjector(); - bpStop = FALSE; - } - - // Get level sensor data - readAirTrapLevelSensors(); - execSwitches(); - // Control blood pump - execBloodFlowMonitor(); - execBloodFlowController(); - execEjectorController(); - execAirPumpController(); - - switch ( sta ) - { - case 0: - set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); - set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); - setAirPumpState( AIR_PUMP_STATE_ON, AIR_PUMP_MOTOR_OFF ); - - if ( TRUE == start ) - { - sta = 1; - // lower the level - set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); - setAirPumpState( AIR_PUMP_STATE_ON, 250 ); - } - break; - case 1: - // look for air at low level and stop - if ( AIR_TRAP_LEVEL_AIR == getRawLevelSensorState( H16_LEVL ) ) - { - // stop lowering level - set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); - setAirPumpState( AIR_PUMP_STATE_OFF, AIR_PUMP_MOTOR_OFF ); - ctr = 0; - sta = 2; - } - break; - case 2: -#if 1 - // stay low for 5 sec - if ( ++ctr > ( 5 * 20 ) ) - { - // raise the level - set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); - setAirPumpState( AIR_PUMP_STATE_ON, 25 ); - sta = 3; - } -#endif - break; - case 3: - // look for fluid at high level and stop - if ( AIR_TRAP_LEVEL_FLUID == getRawLevelSensorState( H16_LEVL ) ) - { - // stop raising level - set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); - setAirPumpState( AIR_PUMP_STATE_OFF, AIR_PUMP_MOTOR_OFF ); - ctr = 0; - sta = 4; - } - break; - case 4: -#if 0 - // look for air at high level - if ( AIR_TRAP_LEVEL_AIR == getRawLevelSensorState( H16_LEVL ) ) - { - // start raising level - set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); - setAirPumpState( AIR_PUMP_STATE_ON, 100 ); - sta = 3; - } -#endif -#if 1 - // stay high for 5 sec - if ( ++ctr > ( 5 * 20 ) ) - { - // lower the level - set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_OPEN_STATE ); - setAirPumpState( AIR_PUMP_STATE_ON, 100 ); - sta = 1; - } -#endif - break; - default: - sta = 0; - break; - } -#endif -#endif - // ******************* End Air Trap Test Code ************************* - #ifdef TASK_TIMING_OUTPUT_ENABLED // Set GPIO low to indicate general task has finished executing setCPLDLampGreen( PIN_SIGNAL_LOW );