Index: firmware/App/Controllers/Ultrafiltration.c =================================================================== diff -u -r7278aeac8fdd894067a05c3bd3a177d38c0b0803 -r3f88f2878bfb58d9b67e05ed0717f6fbff136232 --- firmware/App/Controllers/Ultrafiltration.c (.../Ultrafiltration.c) (revision 7278aeac8fdd894067a05c3bd3a177d38c0b0803) +++ firmware/App/Controllers/Ultrafiltration.c (.../Ultrafiltration.c) (revision 3f88f2878bfb58d9b67e05ed0717f6fbff136232) @@ -18,6 +18,7 @@ #include "BalancingChamber.h" #include "ConcentratePumps.h" #include "Messaging.h" +#include "ModeGenDialysate.h" #include "OperationModes.h" #include "TaskGeneral.h" #include "Temperature.h" @@ -36,6 +37,7 @@ #define UF_COMPENSATION_PERIOD ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Interval at which the ultrafiltration compenstaion executed. #define UF_COMP_INTERVAL ( UF_COMPENSATION_PERIOD / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the peroidic ultrafiltration compensation calculated. #define ZERO_RATE 0.0F ///< Zero value. +#define UF_VOL_ML_PER_TASK_INTERVAL ( (F32)TASK_GENERAL_INTERVAL / ( (F32)MS_PER_SECOND * (F32)SEC_PER_MIN ) ) ///< UF volume (mL) delivered per task interval at 1 mL/min. // ********** private data ********** @@ -45,6 +47,7 @@ static U32 ufDataPublicationTimerCounter; ///< Used to schedule ultrafiltration data publication to CAN bus. static BOOL isUFRateUpdated; ///< flag indicating to update UF rate needed. static OVERRIDE_U32_T ufDataPublishInterval; ///< Ultrafiltration data publish interval. +static F32 ufVolumeDeliveredMl; ///< Accumulated UF volume since last reset (mL); shared by delivery and isolated UF. // ********** private function prototypes ********** @@ -69,6 +72,7 @@ compUFrate = getTDUFRate(); ufDataPublicationTimerCounter = 0; isUFRateUpdated = TRUE; + ufVolumeDeliveredMl = 0.0F; } /*********************************************************************//** @@ -127,6 +131,7 @@ { setConcentratePumpTargetSpeed( D76_PUMP, compUFrate, DOSING_CONT_VOLUME ); requestConcentratePumpOn( D76_PUMP ); + ufVolumeDeliveredMl += ( compUFrate * UF_VOL_ML_PER_TASK_INTERVAL ); } else { @@ -139,6 +144,27 @@ /*********************************************************************//** * @brief + * The stopUltrafiltration function stops the UF pump and clears the run + * request flag. + * @details \b Inputs: isUltrafiltrationRequested + * @details \b Outputs: isUltrafiltrationRequested, D76 pump off + * @return none + *************************************************************************/ +void stopUltrafiltration( void ) +{ + BOOL prevUFState = isUltrafiltrationRequested; + + isUltrafiltrationRequested = FALSE; + requestConcentratePumpOff( D76_PUMP, FALSE ); + + if ( prevUFState != isUltrafiltrationRequested ) + { + SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_UF_PUMP_ON_OFF, prevUFState, isUltrafiltrationRequested ); + } +} + +/*********************************************************************//** + * @brief * The updateUFRequest function updates the ultrafiltration requested * flag to true or false based on the compensated UF rate. * @details \b Inputs: compensated UF @@ -148,13 +174,21 @@ static void updateUFRequest( void ) { F32 qd = getTDDialysateFlowrate(); - BOOL bypass = getTDDialyzerBypass(); BOOL prevUFState = isUltrafiltrationRequested; + BOOL allowUF = FALSE; - // update latest UF run/pause request - // if qd is zero or dialyzer is bypassed, UF pump should be turn off - if ( ( compUFrate > ZERO_RATE ) && ( qd > ZERO_RATE ) && ( FALSE == bypass ) ) + // Isolated UF may run with Qd = 0; delivery UF requires Qd > 0 + if ( DD_GEND_ISOLATED_UF_STATE == getCurrentGenDialysateState() ) { + allowUF = TRUE; + } + else if ( qd > ZERO_RATE ) + { + allowUF = TRUE; + } + + if ( ( compUFrate > ZERO_RATE ) && ( TRUE == allowUF ) ) + { isUltrafiltrationRequested = TRUE; } else @@ -184,6 +218,31 @@ /*********************************************************************//** * @brief + * The resetUFVolumeDelivered function clears the accumulated UF volume. + * @details \b Inputs: none + * @details \b Outputs: ufVolumeDeliveredMl + * @return none + *************************************************************************/ +void resetUFVolumeDelivered( void ) +{ + ufVolumeDeliveredMl = 0.0F; +} + +/*********************************************************************//** + * @brief + * The getUFVolumeDeliveredLiters function returns the accumulated UF volume + * delivered in liters. + * @details \b Inputs: ufVolumeDeliveredMl + * @details \b Outputs: none + * @return Accumulated UF volume delivered in L. + *************************************************************************/ +F32 getUFVolumeDeliveredLiters( void ) +{ + return ( ufVolumeDeliveredMl / (F32)ML_PER_LITER ); +} + +/*********************************************************************//** + * @brief * The publishUltrafiltrationData function broadcasts the ultrafiltration * data at defined interval. * @details \b Inputs: ufDataPublicationTimerCounter @@ -201,6 +260,7 @@ data.ufRate = getTDUFRate(); data.compUFrate = compUFrate; data.isUFRequested = (U32)isUltrafiltrationRequested; + data.ufVolumeDeliveredMl = ufVolumeDeliveredMl; broadcastData( MSG_ID_DD_UF_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( UF_DATA_T ) ); Index: firmware/App/Controllers/Ultrafiltration.h =================================================================== diff -u -r60e6185c2c5df195ccb6b603f30548779b4f05c4 -r3f88f2878bfb58d9b67e05ed0717f6fbff136232 --- firmware/App/Controllers/Ultrafiltration.h (.../Ultrafiltration.h) (revision 60e6185c2c5df195ccb6b603f30548779b4f05c4) +++ firmware/App/Controllers/Ultrafiltration.h (.../Ultrafiltration.h) (revision 3f88f2878bfb58d9b67e05ed0717f6fbff136232) @@ -7,8 +7,8 @@ * * @file Ultrafiltration.h * -* @author (last) Vinayakam Mani -* @date (last) 30-Jul-2025 +* @author (last) Jashwant Gantyada +* @date (last) 30-Jun-2026 * * @author (original) Vinayakam Mani * @date (original) 28-Jul-2025 @@ -34,19 +34,18 @@ /// ultrafiltration data structure typedef struct { - U32 ufExecState; ///< Ultrafiltration execution state F32 ufRate; ///< Ultrafiltration rate from TD F32 compUFrate; ///< Compensated UF rate U32 isUFRequested; ///< Ultrafiltration run or puase request - F32 ufVolumeDeliveredMl; ///< UF volume delivered in mL + F32 ufVolumeDeliveredMl; ///< Accumulated UF volume since last reset (mL) } UF_DATA_T; // ********** public function prototypes ********** void initUltrafiltration( void ); // Initialize ultrafiltration unit void transitionToUltrafiltration( void ); // Prepares for transition to ultrafiltration execution -U32 execUFControl( void ); // Execute the ultrafiltration state machine -UF_EXEC_STATE_T getCurrentUFExecState( void ); // Get the current state of the balancing chamber execution +void handleUFControl( void ); // Handle ultrafiltration control +void stopUltrafiltration( void ); // Stop UF pump and clear run request void signalUFRateUpdate( void ); // Update UF rate when there is a change in rate void resetUFVolumeDelivered( void ); // Reset accumulated UF volume delivered F32 getUFVolumeDeliveredLiters( void ); // Get accumulated UF volume delivered in L Index: firmware/App/Modes/ModeGenDialysate.c =================================================================== diff -u -r4237cbced773b985ff69a8c2af8287dbd5457f24 -r3f88f2878bfb58d9b67e05ed0717f6fbff136232 --- firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 4237cbced773b985ff69a8c2af8287dbd5457f24) +++ firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 3f88f2878bfb58d9b67e05ed0717f6fbff136232) @@ -94,18 +94,22 @@ static BOOL delayBypassStateFlag; ///< To indicate change in treatment parameters static F32 dialysateToDialyzerFlowRate; ///< Current dialysate to dialyzer flow rate (ml/min) static U32 d48PumpSpeed; ///< Initial D48 pump speed based on the Qd. +static DD_GEND_ISO_UF_SUB_STATE_T isolatedUFSubState; ///< Isolated UF run/pause sub-state. +static BOOL isolatedUFVolumeSessionActive; ///< Flag indicating if an isolated UF volume session is in progress. // ********** private function prototypes ********** static void setModeGenDStateTransition( DD_GEND_MODE_STATE_T state ); static DD_GEND_MODE_STATE_T handleGenDDialysateBypassState( void ); static DD_GEND_MODE_STATE_T handleGenDDialysateDeliveryState( void ); static DD_GEND_MODE_STATE_T handleGenDDialysateDeliveryPauseState( void ); -static DD_GEND_MODE_STATE_T handleGenDSpentChamberFillState(void); +static DD_GEND_MODE_STATE_T handleGenDSpentChamberFillState( void ); static DD_GEND_MODE_STATE_T handleGenDBicarbChamberFillState( void ); static DD_GEND_MODE_STATE_T handleGenDIsolatedUFState( void ); static F32 getGenDialysateTargetTemperature( void ); static void updateDialysateToDialyzerFlowRate( void ); +static DD_GEND_MODE_STATE_T applyTDRequestedGenDialysateState( DD_GEND_MODE_STATE_T state ); +static DD_GEND_ISO_UF_SUB_STATE_T getIsolatedUFSubStateForUFRate( void ); static void checkDialysateTemperature( void ); static void monitorChamberLevelStatus( void ); static void publishGenDialysateModeData( void ); @@ -148,6 +152,8 @@ bypassStateDelayStartTimeMS = 0; delayBypassStateFlag = TRUE; dialysateToDialyzerFlowRate = 0.0F; + isolatedUFSubState = DD_GEND_ISO_UF_PAUSE_STATE; + isolatedUFVolumeSessionActive = FALSE; //Initialize balancing chamber module initBalanceChamber(); @@ -478,9 +484,66 @@ break; case DD_GEND_ISOLATED_UF_STATE: - // Deactivate Balancing Chamber Switching - requestBalChamberSwitching( FALSE ); - //TODO : define actuators states + isolatedUFSubState = getIsolatedUFSubStateForUFRate(); + + if ( FALSE == isolatedUFVolumeSessionActive ) + { + resetUFVolumeDelivered(); + isolatedUFVolumeSessionActive = TRUE; + } + + transitionToBalChamberFill(); + // Activate Balancing Chamber Switching + requestBalChamberSwitching( TRUE ); + + setValveState( D8_VALV, VALVE_STATE_CLOSED ); + setValveState( D14_VALV, VALVE_STATE_OPEN ); + setValveState( D31_VALV, VALVE_STATE_CLOSED ); + setValveState( D34_VALV, VALVE_STATE_CLOSED ); + setValveState( D91_VALV, VALVE_STATE_OPEN ); + setValveState( D35_VALV, VALVE_STATE_CLOSED ); + setValveState( D40_VALV, VALVE_STATE_OPEN ); + setValveState( D47_VALV, VALVE_STATE_CLOSED ); + setValveState( D52_VALV, VALVE_STATE_CLOSED ); + setValveState( D54_VALV, VALVE_STATE_CLOSED ); + setValveState( D100_VALV, VALVE_STATE_CLOSED ); + setValveState( D53_VALV, VALVE_STATE_OPEN ); // Drain valve (same as bypass/delivery during gen dialysate) + setValveState( D81_VALV, VALVE_STATE_CLOSED ); + setValveState( D85_VALV, VALVE_STATE_CLOSED ); + + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_DRY_BICARB ) == FALSE ) + { + setValveState( D80_VALV, VALVE_STATE_OPEN ); + setValveState( D64_VALV, VALVE_STATE_CLOSED ); + } + + calculateTargetDialysateTemp(); + setHeaterTargetTemperature( D5_HEAT, getGenDialysateTargetTemperature() ); + setD28TempFeedbackControl( TRUE ); + startHeater( D5_HEAT ); + + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) == TRUE ) + { + setHeaterTargetTemperature( D45_HEAT, getFilteredTemperatureValue( D4_TEMP ) ); + } + else + { + setHeaterTargetTemperature( D45_HEAT, getFilteredTemperatureValue( D99_TEMP ) ); + } + startHeater( D45_HEAT ); + + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); + + if ( getTDDialysateFlowrate() > ZERO_DIAL_FLOW_RATE ) + { + setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); + } + else + { + signalDialysatePumpHardStop( D48_PUMP ); + } + + setRinsePumpState( RINSE_PUMP_STATE_ON ); break; default: @@ -718,18 +781,138 @@ /*********************************************************************//** * @brief - * The handleGenDDialysateIsolatedUFState function performs the - * Isolated ultrafiltration operations. - * @details \b Inputs: none. + * The applyTDRequestedGenDialysateState function transitions the gen dialysate + * sub-state to match the latest TD request when allowed. + * @details \b Inputs: getTDRequestedGenDState, getDialGoodToDeliverStatus + * @details \b Outputs: isDialDeliveryInProgress + * @param state Current gen dialysate sub-state. + * @return Updated gen dialysate sub-state (unchanged if TD request not applied). + *************************************************************************/ +static DD_GEND_MODE_STATE_T applyTDRequestedGenDialysateState( DD_GEND_MODE_STATE_T state ) +{ + DD_GEND_MODE_STATE_T requested = (DD_GEND_MODE_STATE_T)getTDRequestedGenDState(); + DD_GEND_MODE_STATE_T priorState = state; + + if ( state != requested ) + { + switch ( requested ) + { + case DD_GEND_DIALYSATE_BYPASS_STATE: + setModeGenDStateTransition( DD_GEND_DIALYSATE_BYPASS_STATE ); + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_DIALYSATE_BYPASS_STATE; + break; + + case DD_GEND_DIALYSATE_DELIVERY_STATE: + if ( TRUE == getDialGoodToDeliverStatus() ) + { + setModeGenDStateTransition( DD_GEND_DIALYSATE_DELIVERY_STATE ); + isDialDeliveryInProgress.data = TRUE; + state = DD_GEND_DIALYSATE_DELIVERY_STATE; + } + else if ( DD_GEND_ISOLATED_UF_STATE == state ) + { + setModeGenDStateTransition( DD_GEND_DIALYSATE_BYPASS_STATE ); + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_DIALYSATE_BYPASS_STATE; + } + break; + + case DD_GEND_ISOLATED_UF_STATE: + setModeGenDStateTransition( DD_GEND_ISOLATED_UF_STATE ); + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_ISOLATED_UF_STATE; + break; + + default: + break; + } + } + + if ( ( DD_GEND_ISOLATED_UF_STATE == priorState ) && + ( DD_GEND_ISOLATED_UF_STATE != state ) ) + { + isolatedUFVolumeSessionActive = FALSE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The getIsolatedUFSubStateForUFRate function maps the latest TD UF rate to + * the required isolated UF run/pause sub-state. + * @details \b Inputs: getTDUFRate * @details \b Outputs: none + * @return isolated UF run sub-state when Quf > 0, pause otherwise. + *************************************************************************/ +static DD_GEND_ISO_UF_SUB_STATE_T getIsolatedUFSubStateForUFRate( void ) +{ + DD_GEND_ISO_UF_SUB_STATE_T subState = DD_GEND_ISO_UF_PAUSE_STATE; + + if ( getTDUFRate() > ZERO_DIAL_FLOW_RATE ) + { + subState = DD_GEND_ISO_UF_RUN_STATE; + } + + return subState; +} + +/*********************************************************************//** + * @brief + * The handleGenDIsolatedUFState function performs the + * isolated ultrafiltration operations. + * @details \b Inputs: none + * @details \b Outputs: none * @return the current state of gen dialysate mode *************************************************************************/ static DD_GEND_MODE_STATE_T handleGenDIsolatedUFState( void ) { - DD_GEND_MODE_STATE_T state = DD_GEND_ISOLATED_UF_STATE; + DD_GEND_MODE_STATE_T state = DD_GEND_ISOLATED_UF_STATE; + BOOL balancingChambFillInProgress = getBalancingChamberFillinProgressStatus(); - //TODO: define isoalted ultrafiltration. + // if TD asks for a different sub-state, transition out of isolated UF + if ( DD_GEND_ISOLATED_UF_STATE != getTDRequestedGenDState() ) + { + state = applyTDRequestedGenDialysateState( state ); + } + else if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_SPENT_CHAMBER_H_FILL ) == TRUE ) + { + if ( ( TRUE == pendingSpentChamberFill ) && ( FALSE == balancingChambFillInProgress ) ) + { + setModeGenDStateTransition( DD_GEND_SPENT_CHAMBER_FILL_STATE ); + pendingSpentChamberFill = FALSE; + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_SPENT_CHAMBER_FILL_STATE; + } + } +#ifdef __BICARB_CHAMBER_FILL__ + else if ( ( TRUE == pendingBicarbChamberFill ) && ( FALSE == balancingChambFillInProgress ) ) + { + setModeGenDStateTransition( DD_GEND_BICARB_CHAMBER_FILL_STATE ); + pendingBicarbChamberFill = FALSE; + isDialDeliveryInProgress.data = FALSE; + state = DD_GEND_BICARB_CHAMBER_FILL_STATE; + } +#endif + if ( DD_GEND_ISOLATED_UF_STATE == state ) + { + DD_GEND_ISO_UF_SUB_STATE_T desiredSubState = getIsolatedUFSubStateForUFRate(); + + if ( desiredSubState != isolatedUFSubState ) + { + isolatedUFSubState = desiredSubState; + } + + // Perform ultrafiltration + handleUFControl(); + } + else + { + stopUltrafiltration(); + } + return state; } @@ -780,12 +963,7 @@ #endif //if the produced dialysate is good and TD asks for dialysate delivery //move to next state - if ( ( TRUE == getDialGoodToDeliverStatus() ) && ( FALSE == getTDDialyzerBypass() ) ) - { - setModeGenDStateTransition( DD_GEND_DIALYSATE_DELIVERY_STATE ); - isDialDeliveryInProgress.data = TRUE; - state = DD_GEND_DIALYSATE_DELIVERY_STATE; - } + state = applyTDRequestedGenDialysateState( state ); return state; } @@ -805,14 +983,18 @@ LEVEL_STATE_T bicarbChamberLevel = getLevelStatus( D63_LEVL ); BOOL balancingChambFillInProgress = getBalancingChamberFillinProgressStatus(); - // if TD asks for bypass or dialysate is not good to deliver - //transition to bypass dialystate state - if ( ( FALSE == getDialGoodToDeliverStatus() ) || ( TRUE == getTDDialyzerBypass() ) ) + // if TD asks for a different sub-state or dialysate is not good to deliver, + // transition out of delivery + if ( FALSE == getDialGoodToDeliverStatus() ) { setModeGenDStateTransition( DD_GEND_DIALYSATE_BYPASS_STATE ); isDialDeliveryInProgress.data = FALSE; state = DD_GEND_DIALYSATE_BYPASS_STATE; } + else if ( DD_GEND_DIALYSATE_DELIVERY_STATE != getTDRequestedGenDState() ) + { + state = applyTDRequestedGenDialysateState( state ); + } else if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_SPENT_CHAMBER_H_FILL ) == TRUE ) { if ( ( TRUE == pendingSpentChamberFill ) && ( FALSE == balancingChambFillInProgress ) ) @@ -975,6 +1157,19 @@ /*********************************************************************//** * @brief + * The getCurrentIsolatedUFSubState function returns the current isolated UF + * run/pause sub-state. + * @details \b Inputs: isolatedUFSubState + * @details \b Outputs: none + * @return current isolated UF sub-state. + *************************************************************************/ +DD_GEND_ISO_UF_SUB_STATE_T getCurrentIsolatedUFSubState( void ) +{ + return isolatedUFSubState; +} + +/*********************************************************************//** + * @brief * The setTreatmentParamUpdate function sets the flag to indicate one or more * treatement parameters updated. * gen dialysate mode. @@ -1034,6 +1229,18 @@ setD48PumpSpeedForBCFill( initialPumpSpeed ); setDialysatePumpTargetRPM( D48_PUMP, (U32)initialPumpSpeed, TRUE ); + if ( DD_GEND_ISOLATED_UF_STATE == genDialysateState ) + { + if ( getTDDialysateFlowrate() > ZERO_DIAL_FLOW_RATE ) + { + setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); + } + else + { + signalDialysatePumpHardStop( D48_PUMP ); + } + } + //reset the flag isTreatmentParamUpdated = FALSE; } @@ -1343,11 +1550,10 @@ case DD_GEND_STATE_START: case DD_GEND_DIALYSATE_BYPASS_STATE: case DD_GEND_DIALYSATE_DELIVERY_STATE: + case DD_GEND_ISOLATED_UF_STATE: case DD_GEND_SPENT_CHAMBER_FILL_STATE: result = TRUE; break; - - case DD_GEND_ISOLATED_UF_STATE: case DD_GEND_BICARB_CHAMBER_FILL_STATE: case DD_GEND_DIALYSATE_DELIVERY_PAUSE: default: @@ -1386,13 +1592,16 @@ isDialDeliveryInProgress.data = TRUE; break; + case DD_GEND_ISOLATED_UF_STATE: + isDialDeliveryInProgress.data = FALSE; + break; + case DD_GEND_SPENT_CHAMBER_FILL_STATE: pendingSpentChamberFill = FALSE; isDialDeliveryInProgress.data = FALSE; break; case DD_GEND_STATE_START: - case DD_GEND_ISOLATED_UF_STATE: case DD_GEND_BICARB_CHAMBER_FILL_STATE: case DD_GEND_DIALYSATE_DELIVERY_PAUSE: default: Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r5f1b50a1d9a7bd6ea17bb666e28ccfeafe56432c -r3f88f2878bfb58d9b67e05ed0717f6fbff136232 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 5f1b50a1d9a7bd6ea17bb666e28ccfeafe56432c) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 3f88f2878bfb58d9b67e05ed0717f6fbff136232) @@ -7,8 +7,8 @@ * * @file AlarmMgmtSWFaults.h * -* @author (last) Dara Navaei -* @date (last) 03-May-2026 +* @author (last) Jashwant Gantyada +* @date (last) 30-Jun-2026 * * @author (original) Vinayakam Mani * @date (original) 07-Aug-2024 @@ -137,7 +137,7 @@ SW_FAULT_ID_POST_GEND_MODE_INVALID_EXEC_STATE = 106, SW_FAULT_ID_PRE_GEND_WET_SELF_TEST_INVALID_EXEC_STATE = 107, SW_FAULT_ID_PRE_GEND_WET_SELF_TEST_INVALID_EXEC_STATE1 = 108, - SW_FAULT_ID_UF_INVALID_EXEC_STATE = 109, + SW_FAULT_ID_AVAILABLE_TO_USE = 109, SW_FAULT_ID_SPENT_CHAMBER_FILL_INVALID_EXEC_STATE = 110, SW_FAULT_ID_TD_INVALID_BLOOD_LEAK_STATE = 111, SW_FAULT_ID_BLOOD_LEAK_EMBEDDED_MODE_INVALID_STATE = 112, @@ -158,6 +158,10 @@ SW_FAULT_ID_INVALID_TEMPERATURE_SENSOR_SELECTED3 = 127, SW_FAULT_ID_DIALYSATE_MIX_EXEC_INVALID_STATE = 128, SW_FAULT_ID_MODE_UPDATE_INVALID_STATE = 129, + SW_FAULT_ID_SUBSTITUTION_PUMP_INVALID_ID = 130, + SW_FAULT_ID_SUBSTITUTION_PUMP_EXEC_INVALID_STATE = 131, + SW_FAULT_ID_DRY_BICART_DEPRESURIZE_INVALID_EXEC_STATE = 132, + SW_FAULT_ID_INVALID_TD_GEND_STATE_REQUEST = 133, NUM_OF_SW_FAULT_IDS } DD_SW_FAULT_ID_T; Index: firmware/App/Services/TDInterface.c =================================================================== diff -u -r60e6185c2c5df195ccb6b603f30548779b4f05c4 -r3f88f2878bfb58d9b67e05ed0717f6fbff136232 --- firmware/App/Services/TDInterface.c (.../TDInterface.c) (revision 60e6185c2c5df195ccb6b603f30548779b4f05c4) +++ firmware/App/Services/TDInterface.c (.../TDInterface.c) (revision 3f88f2878bfb58d9b67e05ed0717f6fbff136232) @@ -7,8 +7,8 @@ * * @file TDInterface.c * -* @author (last) Raghu Kallala -* @date (last) 11-May-2026 +* @author (last) Sameer Kalliadan Poyil +* @date (last) 16-Jun-2026 * * @author (original) Vinayakam Mani * @date (original) 06-Nov-2024 @@ -20,13 +20,15 @@ #include "FPOperationModes.h" #include "Messaging.h" #include "MessagePayloads.h" +#include "MixingControl.h" #include "ModeGenDialysate.h" #include "ModeInitPOST.h" #include "ModePreGenDialysate.h" #include "ModeStandby.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SystemCommDD.h" +#include "SubstitutionPump.h" #include "TaskGeneral.h" #include "TDInterface.h" #include "Timers.h" @@ -55,6 +57,8 @@ #define TD_SODIUM_MIN ( 130U ) ///< TD Min acid type index #define TD_SODIUM_MAX ( 155U ) ///< TD Max acid type index + + #define TD_BICARBONATE_MIN ( 20U ) ///< TD Min acid type index #define TD_BICARBONATE_MAX ( 40U ) ///< TD Max acid type index @@ -82,6 +86,7 @@ TD_TREATMENT_OVERRIDE_DIALYSATE_TEMP, ///< TD Target Dialysate Temperature TD_TREATMENT_OVERRIDE_ACID_TYPE, ///< TD Acid type TD_TREATMENT_OVERRIDE_BICARB_TYPE, ///< TD Bicarb type + TD_TREATMENT_OVERRIDE_SUB_FLOWRATE, ///< TD Substitution flow rate NUM_OF_TD_TREATMENT_OVERRIDES, ///< Number of TD override treatment parameters } TD_TREATMENT_OVERRIDE_INDEX_T; @@ -100,6 +105,7 @@ static OVERRIDE_F32_T tdBicarbConvFactor; ///< TD Bicarb conversion factor static OVERRIDE_U32_T tdSodium; ///< TD Sodium concentrate static OVERRIDE_U32_T tdBicarbonate; ///< TD Bicarbonate concentrate +static OVERRIDE_F32_T tdSubstitutionFlowRate; ///< TD Subsitution flow rate // ********** private function prototypes ********** @@ -122,40 +128,45 @@ tdOpModeDataFreshFlag = FALSE; // Initialize treatment parameters from TD - tdDialysateFlowrate.data = 0.0F; - tdDialysateFlowrate.ovData = 0.0F; - tdDialysateFlowrate.ovInitData = TD_DIALYSATE_FLOWRATE_MIN_ML_MIN; - tdDialysateFlowrate.override = OVERRIDE_RESET; + tdDialysateFlowrate.data = 0.0F; + tdDialysateFlowrate.ovData = 0.0F; + tdDialysateFlowrate.ovInitData = TD_DIALYSATE_FLOWRATE_MIN_ML_MIN; + tdDialysateFlowrate.override = OVERRIDE_RESET; - tdUFRate.data = 0.0F; - tdUFRate.ovData = 0.0F; - tdUFRate.ovInitData = TD_UF_RATE_MIN_ML_MIN; - tdUFRate.override = OVERRIDE_RESET; + tdUFRate.data = 0.0F; + tdUFRate.ovData = 0.0F; + tdUFRate.ovInitData = TD_UF_RATE_MIN_ML_MIN; + tdUFRate.override = OVERRIDE_RESET; - tdDialysateTemp.data = 0.0F; - tdDialysateTemp.ovData = 0.0F; - tdDialysateTemp.ovInitData = TD_DIALYSATE_TEMP_MIN_DEGC; - tdDialysateTemp.override = OVERRIDE_RESET; + tdDialysateTemp.data = 0.0F; + tdDialysateTemp.ovData = 0.0F; + tdDialysateTemp.ovInitData = TD_DIALYSATE_TEMP_MIN_DEGC; + tdDialysateTemp.override = OVERRIDE_RESET; - tdAcidConvFactor.data = 0.0F; - tdAcidConvFactor.ovData = 0.0F; - tdAcidConvFactor.ovInitData = ACID_CONVERSION_FACTOR[ TD_ACID_TYPE_MIN ]; - tdAcidConvFactor.override = OVERRIDE_RESET; + tdAcidConvFactor.data = 0.0F; + tdAcidConvFactor.ovData = 0.0F; + tdAcidConvFactor.ovInitData = ACID_CONVERSION_FACTOR[ TD_ACID_TYPE_MIN ]; + tdAcidConvFactor.override = OVERRIDE_RESET; - tdBicarbConvFactor.data = 0.0F; - tdBicarbConvFactor.ovData = 0.0F; - tdBicarbConvFactor.ovInitData = BICARBONATE_CONVERSION_FACTOR; - tdBicarbConvFactor.override = OVERRIDE_RESET; + tdBicarbConvFactor.data = 0.0F; + tdBicarbConvFactor.ovData = 0.0F; + tdBicarbConvFactor.ovInitData = BICARBONATE_CONVERSION_FACTOR; + tdBicarbConvFactor.override = OVERRIDE_RESET; - tdSodium.data = 0.0F; - tdSodium.ovData = 0.0F; - tdSodium.ovInitData = TD_SODIUM_MIN; - tdSodium.override = OVERRIDE_RESET; + tdSodium.data = DIALYSATE_TARGET_STD_NA_SETTINGS; + tdSodium.ovData = 0.0F; + tdSodium.ovInitData = TD_SODIUM_MIN; + tdSodium.override = OVERRIDE_RESET; - tdBicarbonate.data = 0.0F; - tdBicarbonate.ovData = 0.0F; - tdBicarbonate.ovInitData = TD_BICARBONATE_MIN; - tdBicarbonate.override = OVERRIDE_RESET; + tdBicarbonate.data = DIALYSATE_TARGET_STD_BICARB_SETTING; + tdBicarbonate.ovData = 0.0F; + tdBicarbonate.ovInitData = TD_BICARBONATE_MIN; + tdBicarbonate.override = OVERRIDE_RESET; + + tdSubstitutionFlowRate.data = 0.0F; + tdSubstitutionFlowRate.ovData = 0.0F; + tdSubstitutionFlowRate.ovInitData = TD_BICARBONATE_MIN; + tdSubstitutionFlowRate.override = OVERRIDE_RESET; } /**********************************************************************//** @@ -198,12 +209,14 @@ * @details \b Inputs: genDialysateState * @details \b Outputs: none * @param genDialysateState Requested DD gen dialysate sub-state. - * @return TRUE if the request is a supported treatment sub-state. + * @return TRUE if the request is a TD-commandable treatment sub-state + * (bypass, delivery, or isolated UF). Internal DD states such as spent/ + * bicarb chamber fill and delivery pause are not TD-requestable. *************************************************************************/ static BOOL isValidTDGenDStateRequest( U32 genDialysateState ) { BOOL result = FALSE; - + if ( ( DD_GEND_DIALYSATE_BYPASS_STATE == genDialysateState ) || ( DD_GEND_DIALYSATE_DELIVERY_STATE == genDialysateState ) || ( DD_GEND_ISOLATED_UF_STATE == genDialysateState ) ) @@ -323,14 +336,23 @@ * @brief * The setTDRequestedGenDState function sets the latest TD-requested gen * dialysate sub-state. + * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if requested state is not + * a TD-commandable gen dialysate sub-state. * @details \b Inputs: none * @details \b Outputs: tdRequestedGenDState * @param genDialysateState Requested DD gen dialysate sub-state. * @return none. *************************************************************************/ void setTDRequestedGenDState( U32 genDialysateState ) { - tdRequestedGenDState = genDialysateState; + if ( TRUE == isValidTDGenDStateRequest( genDialysateState ) ) + { + tdRequestedGenDState = genDialysateState; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_TD_GEND_STATE_REQUEST, genDialysateState ); + } } /*********************************************************************//** @@ -392,6 +414,18 @@ /*********************************************************************//** * @brief + * The getTDSubstitutionFlowRate function gets the latest TD + * substitution flow rate. + * @details \b Inputs: tdSubstitutionFlowRate + * @details \b Outputs: none + * @return Latest target substitution flow rate + *************************************************************************/ +F32 getTDSubstitutionFlowRate( void ) +{ + return getF32OverrideValue( &tdSubstitutionFlowRate ); +} +/*********************************************************************//** + * @brief * The getTDRequestedGenDState function gets the latest TD-requested gen * dialysate sub-state. * @details \b Inputs: tdRequestedGenDState @@ -565,10 +599,7 @@ // Set concentrate types and requested gen dialysate sub-state setTDAcidAndBicarbType( startTxRequest.acidConvFactor, startTxRequest.bicarbConvFactor, startTxRequest.sodium, startTxRequest.bicarbonate ); - if ( TRUE == isValidTDGenDStateRequest( startTxRequest.genDialysateState ) ) - { - setTDRequestedGenDState( startTxRequest.genDialysateState ); - } + setTDRequestedGenDState( startTxRequest.genDialysateState ); // start dialysate generation result = requestDDGenDialStart(); @@ -597,10 +628,7 @@ // Set concentrate types and requested gen dialysate sub-state setTDAcidAndBicarbType( startTxRequest.acidConvFactor, startTxRequest.bicarbConvFactor, startTxRequest.sodium, startTxRequest.bicarbonate ); - if ( TRUE == isValidTDGenDStateRequest( startTxRequest.genDialysateState ) ) - { - setTDRequestedGenDState( startTxRequest.genDialysateState ); - } + setTDRequestedGenDState( startTxRequest.genDialysateState ); // Signal to update treatement parameters setTreatmentParamUpdate(); @@ -662,6 +690,11 @@ result = f32Override( message, &tdBicarbConvFactor); break; + case TD_TREATMENT_OVERRIDE_SUB_FLOWRATE: + result = f32Override( message, &tdSubstitutionFlowRate); + setSubstitutionPumpTargetRate( D92_PUMP, getTDSubstitutionFlowRate() ); + break; + default: result = FALSE; break;