Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -20,6 +20,7 @@ #include "Bubbles.h" #include "Buttons.h" #include "DDInterface.h" +#include "FluidBolus.h" #include "Messaging.h" #include "ModeService.h" #include "ModeTreatment.h" @@ -53,8 +54,6 @@ #define TREATMENT_SETTINGS_RANGES_PUB_INTERVAL ( ( 60 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) /// Ultrafiltration data broadcast interval (ms/task time) count. #define ULTRAFILTRATION_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) -/// Saline bolus data broadcast interval (ms/task time) count. // TODO - move to StateTxSalineBolus.c when implemented -#define SALINE_BOLUS_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) /// Macro to calculate the elapsed treatment time in seconds. #define CALC_ELAPSED_TREAT_TIME_IN_SECS() ( treatmentTimeMS / MS_PER_SECOND ) @@ -81,7 +80,6 @@ static U32 treatmentStateBroadcastTimerCtr; ///< Treatment state data broadcast timer counter used to schedule when to transmit data. static U32 treatmentParamsRangesBroadcastTimerCtr; ///< Treatment parameter ranges broadcast timer counter used to schedule when to transmit updated ranges. static U32 ultrafiltrationBroadcastTimerCtr; ///< Ultrafiltration data broadcast timer counter used to schedule when to transmit data. -static U32 salineBolusBroadcastTimerCtr; ///< Saline bolus data broadcast timer counter used to schedule when to transmit data. /// Interval (in task intervals) at which to publish alarm status to CAN bus. static OVERRIDE_U32_T treatmentTimePublishInterval; @@ -104,7 +102,6 @@ static void broadcastTreatmentSettingsRanges( void ); static void broadcastTreatmentPeriodicData(); -static void publishSalineBolusData( void ); // TODO - move to StateTxSalineBolus.c when implemented static void publishUltrafiltrationData( void ); static U32 getMinTreatmentTimeInMinutes( void ); static TREATMENT_STATE_T handleTreatmentStartState( void ); @@ -155,7 +152,6 @@ treatmentStateBroadcastTimerCtr = TREATMENT_STATE_DATA_PUB_INTERVAL; // So we send state data immediately when we begin treatment mode treatmentParamsRangesBroadcastTimerCtr = TREATMENT_SETTINGS_RANGES_PUB_INTERVAL; // So we send ranges immediately when we begin treatment mode ultrafiltrationBroadcastTimerCtr = ULTRAFILTRATION_DATA_PUB_INTERVAL; // So we send ultrafiltration immediately when we begin treatment mode - salineBolusBroadcastTimerCtr = SALINE_BOLUS_DATA_PUB_INTERVAL; // So we send saline bolus data immediately when we begin treatment mode presTreatmentTimeSecs = 0; presUFVolumeL = 0.0F; @@ -193,6 +189,7 @@ // initRinseback(); // initTreatmentRecirc(); // initTreatmentEnd(); + initFluidBolus(); // Started the treatment - set the start time in epoch // setTxLastStartTimeEpoch( getRTCTimestamp() ); @@ -436,6 +433,13 @@ activateAlarmNoData( ALARM_ID_TD_TREATMENT_STOPPED_BY_USER ); } + // If alarm fires while bolus is active, abort the bolus + if ( ( TRUE == doesAlarmStatusIndicateStop() ) && ( TRUE == isFluidBolusActive() ) ) + { + signalAbortFluidBolus(); + execFluidBolus(); + } + // Check if resume treatment blocked by alarm if ( TRUE == doesAlarmIndicateNoResume() ) { @@ -507,8 +511,8 @@ broadcastTreatmentPeriodicData(); // Publish ultrafiltration data at set interval (whether we are performing UF or not) publishUltrafiltrationData(); - // Publish saline bolus data at set interval (whether we are delivering one or not) - publishSalineBolusData(); + // Publish fluid bolus data at set interval (whether we are delivering one or not) + publishFluidBolusData(); // Manage air trap control execAirTrapMonitorTreatment(); @@ -1102,30 +1106,6 @@ /*********************************************************************//** * @brief - * The publishSalineBolusData function publishes the saline bolus data - * at the set time interval. - * @details \b Inputs: none - * @details \b Outputs: none - * @param dialysisState next dialysis state - * @return next saline bolus state - *************************************************************************/ -static void publishSalineBolusData( void ) -{ - if ( ++salineBolusBroadcastTimerCtr >= SALINE_BOLUS_DATA_PUB_INTERVAL ) - { - SALINE_BOLUS_DATA_PAYLOAD_T data; - - data.tgtSalineVolumeMl = getTreatmentParameterU32( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); - data.cumSalineVolumeMl = 0.0F; // TODO - data.bolSalineVolumeMl = 0.0F; // TODO - - sendMessage( MSG_ID_TD_SALINE_BOLUS_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)(&data), sizeof( SALINE_BOLUS_DATA_PAYLOAD_T ) ); - salineBolusBroadcastTimerCtr = 0; - } -} - -/*********************************************************************//** - * @brief * The publishUltrafiltrationData function publishes the ultrafiltration data * at the set time interval. * @details \b Inputs: presUFVolumeL, presUFRate Index: firmware/App/Modes/StateTxBloodPrime.c =================================================================== diff -u -rce58760d9ec26a8ddc4d2462671d7f3db961f621 -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Modes/StateTxBloodPrime.c (.../StateTxBloodPrime.c) (revision ce58760d9ec26a8ddc4d2462671d7f3db961f621) +++ firmware/App/Modes/StateTxBloodPrime.c (.../StateTxBloodPrime.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -19,6 +19,7 @@ #include "BloodFlow.h" #include "Buttons.h" #include "DDInterface.h" +#include "FluidBolus.h" #include "Messaging.h" #include "ModeTreatment.h" #include "TxParams.h" @@ -96,6 +97,7 @@ static BLOOD_PRIME_STATE_T handleBloodPrimePausedState( void ); static void handleBloodPrimePauseTimer( void ); static void publishBloodPrimeData( void ); +static BLOOD_PRIME_STATE_T handleBloodPrimeFluidBolusState( void ); /*********************************************************************//** * @brief @@ -234,6 +236,10 @@ bloodPrimeState = handleBloodPrimePausedState(); break; + case BLOOD_PRIME_FLUID_BOLUS_STATE: + bloodPrimeState = handleBloodPrimeFluidBolusState(); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_PRIME_INVALID_STATE, bloodPrimeState ); break; @@ -543,6 +549,56 @@ /*********************************************************************//** * @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 + *************************************************************************/ +void signalBloodPrimeFluidBolusRequest( void ) +{ + if ( ( BLOOD_PRIME_RAMP_STATE == bloodPrimeState ) || ( BLOOD_PRIME_RUN_STATE == bloodPrimeState ) ) + { + bloodPrimeResumeState = bloodPrimeState; + lastBloodPrimeFlowRate_mL_min = (U32)getTargetBloodFlowRate(); + bloodPrimeState = BLOOD_PRIME_FLUID_BOLUS_STATE; + } +} + +/*********************************************************************//** + * @brief * The publishBloodPrimeData function publishes blood prime data * at interval. * @details \b Message \b Sent: MSG_ID_TD_BLOOD_PRIME_PROGRESS_DATA Index: firmware/App/Modes/StateTxBloodPrime.h =================================================================== diff -u -rce58760d9ec26a8ddc4d2462671d7f3db961f621 -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Modes/StateTxBloodPrime.h (.../StateTxBloodPrime.h) (revision ce58760d9ec26a8ddc4d2462671d7f3db961f621) +++ firmware/App/Modes/StateTxBloodPrime.h (.../StateTxBloodPrime.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -54,6 +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 testBloodPrimePublishIntervalOverride( MESSAGE_T *message ); BOOL testBloodPrimeVolumeOverride( MESSAGE_T *message ); Index: firmware/App/Modes/StateTxPaused.c =================================================================== diff -u -r6f02ff4686ec9dfc60247e9ed3fc9c5cc7771543 -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Modes/StateTxPaused.c (.../StateTxPaused.c) (revision 6f02ff4686ec9dfc60247e9ed3fc9c5cc7771543) +++ firmware/App/Modes/StateTxPaused.c (.../StateTxPaused.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -20,6 +20,7 @@ #include "Buttons.h" #include "Common.h" #include "DDInterface.h" +#include "FluidBolus.h" #include "Messaging.h" #include "ModeTreatment.h" //#include "NVDataMgmt.h" @@ -48,6 +49,7 @@ static U32 bloodSittingTimerCtr; ///< Timer counter tracks time in this mode while blood is sitting. 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. // ********** private function prototypes ********** @@ -56,6 +58,7 @@ static TREATMENT_PAUSED_STATE_T handleTreatmentPausedBloodRecircState( void ); static TREATMENT_PAUSED_STATE_T handleTreatmentPausedNoRecircState( void ); static TREATMENT_PAUSED_STATE_T handleTreatmentPausedRecoverBloodDetectState( void ); +static TREATMENT_PAUSED_STATE_T handleTreatmentPausedFluidBolusState( void ); static void handleTreatmentPausedBloodSittingTimer( void ); static TREATMENT_PAUSED_STATE_T handleTreatmentPausedAlarmsAndSignals( TREATMENT_PAUSED_STATE_T state ); static void transitionToTxPausedState( TREATMENT_PAUSED_STATE_T newState ); @@ -112,9 +115,6 @@ // TODO figure out the code // signalInitiatePressureStabilization( USE_NORMAL_STABILIZATION_PERIOD ); - // Reset saline bolus state in case alarm interrupted one -// resetSalineBolus(); - // Reset blood leak zeroing params // resetBloodLeakZeroingVariables(); @@ -169,6 +169,10 @@ currentTxPausedState = handleTreatmentPausedRecoverBloodDetectState(); break; + case TREATMENT_PAUSED_FLUID_BOLUS_STATE: + currentTxPausedState = handleTreatmentPausedFluidBolusState(); + break; + default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TREATMENT_STOP_INVALID_STATE, currentTxPausedState ); break; @@ -290,6 +294,64 @@ /*********************************************************************//** * @brief + * The handleTreatmentPausedFluidBolusState function handles the fluid + * bolus sub-state of the Treatment Paused state machine. Entered either + * when an alarm fires during an active bolus in a calling state, or when + * 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 + * @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() ) ) + { + signalAbortFluidBolus(); + } + + // Run the bolus service every tick + execFluidBolus(); + + // Bolus complete or aborted — return to appropriate paused recirc sub-state + if ( FALSE == isFluidBolusActive() ) + { + state = pauseBolusResumeState; + transitionToTxPausedState( state ); + } + + return state; +} + +/*********************************************************************//** + * @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 + *************************************************************************/ +void signalPauseTreatFluidBolusRequest( void ) +{ + if ( ( TREATMENT_PAUSED_RECIRC_STATE == currentTxPausedState ) || ( TREATMENT_PAUSED_RECIRC_BLOOD_ONLY_STATE == currentTxPausedState ) ) + { + pauseBolusResumeState = currentTxPausedState; + currentTxPausedState = TREATMENT_PAUSED_FLUID_BOLUS_STATE; + } +} + +/*********************************************************************//** + * @brief * The handleTreatmentPausedBloodSittingTimer function handles the no re-circ * blood timer. It should only be called when Blood is NOT circulating. * Increments and checks for warning and alarm timeouts. Index: firmware/App/Modes/StateTxPaused.h =================================================================== diff -u -r395522dffef1348e176564925656012f529c1910 -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Modes/StateTxPaused.h (.../StateTxPaused.h) (revision 395522dffef1348e176564925656012f529c1910) +++ firmware/App/Modes/StateTxPaused.h (.../StateTxPaused.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -46,6 +46,8 @@ TREATMENT_PAUSED_STATE_T getCurrentTreatmentPausedState( void );// Get current treatment paused state +void signalPauseTreatFluidBolusRequest( void ); // Fluid Bolus request from UI + /**@}*/ #endif Index: firmware/App/Monitors/Pressures.h =================================================================== diff -u -rb017f10001f67282ab6622e34d629ae2f884cdc9 -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Monitors/Pressures.h (.../Pressures.h) (revision b017f10001f67282ab6622e34d629ae2f884cdc9) +++ firmware/App/Monitors/Pressures.h (.../Pressures.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -100,6 +100,8 @@ BOOL pressureLimitHandleWidenRequest( MESSAGE_T *message ); +BOOL isSalineBagEmpty( void ); + BOOL testPressuresDataPublishIntervalOverride( MESSAGE_T *message ); BOOL testTMPOverride( MESSAGE_T *message ); BOOL testBaroPressureOverride( MESSAGE_T * message ); Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -14,21 +14,21 @@ * @date (original) 01-Aug-2024 * ***************************************************************************/ - -#ifndef __ALARM_MGMT_SW_FAULTS_H__ -#define __ALARM_MGMT_SW_FAULTS_H__ - -/** - * @addtogroup AlarmManagement - * @{ - */ - -// ********** public definitions ********** - -/// Listing of specific software faults for logging purposes. -typedef enum -{ - SW_FAULT_ID_NONE = 0, + +#ifndef __ALARM_MGMT_SW_FAULTS_H__ +#define __ALARM_MGMT_SW_FAULTS_H__ + +/** + * @addtogroup AlarmManagement + * @{ + */ + +// ********** public definitions ********** + +/// Listing of specific software faults for logging purposes. +typedef enum +{ + SW_FAULT_ID_NONE = 0, SW_FAULT_ID_ALARM_LAMP_INVALID_PATTERN_REQUESTED = 1, SW_FAULT_ID_ALARM_LAMP_INVALID_SELF_TEST_STATE = 2, SW_FAULT_ID_MODE_INIT_POST_INVALID_POST_STATE = 3, @@ -186,9 +186,12 @@ 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, - NUM_OF_SW_FAULT_IDS -} SW_FAULT_ID_T; - + SW_FAULT_ID_INVALID_FLUID_BOLUS_STATE = 158, + SW_FAULT_ID_INVALID_DD_GEN_DIALYSATE_DATA = 159, + SW_FAULT_INVALID_PAYLOAD_LENGTH =160, + NUM_OF_SW_FAULT_IDS +} SW_FAULT_ID_T; + /**@}*/ -#endif +#endif Index: firmware/App/Services/DDInterface.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -45,6 +45,7 @@ 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 DIALYSATE_DELIVERY_REQ_PAYLOAD_T dialysateDeliveryCmdSet; ///< Set of dialysate delivery parameters to send to the DD during treatment. @@ -73,6 +74,7 @@ ddOpModeDataFreshFlag = FALSE; ddDialysatePressureFreshFlag = FALSE; + dialysateGoodToDeliver = FALSE; resetDDInterface(); @@ -109,6 +111,7 @@ dialysateDeliveryCmdSet.bicarbConvFactor = 0.0F; dialysateDeliveryCmdSet.sodium = 0; dialysateDeliveryCmdSet.bicarbonate = 0; + dialysateDeliveryCmdSet.substitutionRate = 0.0F; } /**********************************************************************//** @@ -312,6 +315,7 @@ dialysateDeliveryCmdSet.bicarbConvFactor = bicarbConvFactor; dialysateDeliveryCmdSet.sodium = sodium; dialysateDeliveryCmdSet.bicarbonate = bicarbonate; + dialysateDeliveryCmdSet.substitutionRate = 0.0F; #ifndef TEST_UI_ONLY sendMessage( MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*)(&dialysateDeliveryCmdSet), sizeof( DIALYSATE_DELIVERY_REQ_PAYLOAD_T ) ); @@ -509,7 +513,79 @@ // } } +/*********************************************************************//** + * @brief + * The cmdSubstitutionRate function sends a generate dialysate command to + * the DD with a given substitution (D92) pump rate for HDF / HD-online + * fluid bolus delivery. + * @details \b Message \b Sent: MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA + * @details \b Inputs: none + * @details \b Outputs: dialysateDeliveryCmdSet + * @param qs Target substitution flow rate (mL/min) + * @return none + *************************************************************************/ +void cmdSubstitutionRate( F32 qs ) +{ + if ( TRUE == dialysateDeliveryCmdSet.start ) + { + dialysateDeliveryCmdSet.substitutionRate = qs; +#ifndef TEST_UI_ONLY + sendMessage( MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA, COMM_BUFFER_OUT_CAN_TD_2_DD, (U08*)(&dialysateDeliveryCmdSet), sizeof( DIALYSATE_DELIVERY_REQ_PAYLOAD_T ) ); +#endif + } + else + { + // TODO - s/w fault? + } +} +/*********************************************************************//** + * @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 -re9e339870c5ed01230963f00d400331ab879c91f -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -59,11 +59,15 @@ void cmdChangeQd( F32 qd ); void cmdChangeQuf( F32 quf ); void cmdBypassDialyzer( BOOL bypass ); -void cmdStopGenerateDialysate( void ); +void cmdStopGenerateDialysate( void ); +void cmdSubstitutionRate (F32 qs ); 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 --- firmware/App/Services/FluidBolus.c (revision 0) +++ firmware/App/Services/FluidBolus.c (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -0,0 +1,502 @@ +/************************************************************************** +* +* Copyright (c) 2025-2026 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file FluidBolus.c +* +* @author (last) Praneeth Bunne +* @date (last) 01-May-2026 +* +* @author (original) Praneeth Bunne +* @date (original) 01-May-2026 +* +***************************************************************************/ + +#include "AlarmMgmtTD.h" +#include "BloodFlow.h" +#include "DDInterface.h" +#include "FluidBolus.h" +#include "Messaging.h" +#include "Pressures.h" +#include "TaskGeneral.h" +#include "Timers.h" +#include "TxParams.h" +#include "Valves.h" + +/** + * @addtogroup FluidBolus + * @{ + */ + +// ********** private definitions ********** + +static const U32 FLUID_BOLUS_DATA_PUB_INTERVAL = ( MS_PER_SECOND + / TASK_GENERAL_INTERVAL); ///< Saline bolus data broadcast interval (ms/task time) count. + +// ********** private data ********** + +static FLUID_BOLUS_STATE_T currentFluidBolusState; ///< Current fluid bolus state +static FLUID_BOLUS_MEDIUM_T currentFluidBolusMedium; ///< Current fluid bolus medium +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 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. + +///< Permitted alarm list-bolus allowed from paused state +static const ALARM_ID_T FLUID_BOLUS_PERMITTED_PAUSED_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, +}; + +// ********** private function prototypes ********** + +static void updateFluidBolusVolumeDelivered( void ); +static void completeBolusToCumulative( void ); + +static FLUID_BOLUS_STATE_T handleFluidBolusIdleState( void ); +static FLUID_BOLUS_STATE_T handleFluidBolusWait4Pumps2Stop( void ); +static FLUID_BOLUS_STATE_T handleFluidBolusSalineInProgressState( void ); +static FLUID_BOLUS_STATE_T handleFluidBolusSubstituteInProgressState( void ); + +/*********************************************************************//** + * @brief + * The initFluidBolus function initializes the Fluid Bolus module. + * Calling this function resets all bolus state and cumulative volume, + * 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, + * bolusFluidVolumeDelivered_mL, fluidBolusStartRequested, + * fluidBolusAbortRequested, bolusVolumeLastUpdateTimeStamp + * @return none + *************************************************************************/ +void initFluidBolus( void ) +{ + currentFluidBolusState = FLUID_BOLUS_IDLE_STATE; + currentFluidBolusMedium = getFluidBolusMedium(); + fluidBolusBroadCastTimerCtr = 0; + totalFluidVolumeDelivered_mL = 0.0F; + bolusFluidVolumeDelivered_mL = 0.0F; + fluidBolusStartRequested = FALSE; + fluidBolusAbortRequested = FALSE; + bolusVolumeLastUpdateTimeStamp = getMSTimerCount(); +} + +/*********************************************************************//** + * @brief + * The execFluidBolus function executes the fluid bolus state machine. + * @details \b Inputs: currentFluidBolusState + * @details \b Outputs: currentFluidBolusState + * @return Current fluid bolus state machine. + *************************************************************************/ +FLUID_BOLUS_STATE_T execFluidBolus( void ) +{ + FLUID_BOLUS_STATE_T priorState = currentFluidBolusState; + + switch ( currentFluidBolusState ) + { + case FLUID_BOLUS_IDLE_STATE: + currentFluidBolusState = handleFluidBolusIdleState(); + break; + + case FLUID_BOLUS_WAIT_FOR_PUMPS_STOP_STATE: + currentFluidBolusState = handleFluidBolusWait4Pumps2Stop(); + break; + + case FLUID_BOLUS_SALINE_IN_PROGRESS_STATE: + currentFluidBolusState = handleFluidBolusSalineInProgressState(); + break; + + case FLUID_BOLUS_SUBSITUTE_IN_PROGRESS_STATE: + currentFluidBolusState = handleFluidBolusSubstituteInProgressState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_FLUID_BOLUS_STATE, currentFluidBolusState ) + currentFluidBolusState = FLUID_BOLUS_IDLE_STATE; + break; + } + + if ( priorState != currentFluidBolusState ) + { + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_STATE_CHANGE, priorState, currentFluidBolusState ); + } + + return currentFluidBolusState; +} + +/*********************************************************************//** + * @brief + * The getFluidBolusMedium function determines the fluid bolus medium based + * on the current treatment modality and online fluid configuration. + * Substitution fluid applies to HDF treatment, or HD treatment with online + * fluid enabled. Saline applies to standard HD without online fluid. + * @details \b Inputs: none + * @details \b Outputs: none + * @return FLUID_BOLUS_MEDIUM_SUBSTITUTE for HDF or HD-online, FLUID_BOLUS_MEDIUM_SALINE otherwise. + *************************************************************************/ +FLUID_BOLUS_MEDIUM_T getFluidBolusMedium( void ) +{ + FLUID_BOLUS_MEDIUM_T medium = FLUID_BOLUS_MEDIUM_SALINE; + U32 modality = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_MODALITY ); + + if ( ( modality == TREATMENT_MODALITY_HDF ) ) // || ( modality == TREATMENT_MODALITY_HD ) && ( check online fluid enabled ) + { + medium = FLUID_BOLUS_MEDIUM_SUBSTITUTE; + } + + return medium; +} + +/*********************************************************************//** + * @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 + * @details \b Outputs: none + * @return TRUE if bolus state is not IDLE, FALSE otherwise. + *************************************************************************/ +BOOL isFluidBolusActive( void ) +{ + return ( FLUID_BOLUS_IDLE_STATE != currentFluidBolusState ) ? TRUE : FALSE; +} + +/*********************************************************************//** + * @brief + * The getTotalFluidBolusVolumeDelivered function gets the current total + * fluid volume delivered. + * @details \b Inputs: totalFluidVolumeDelivered + * @details \b Outputs: none + * @return totalFluidVolumeDelivered + *************************************************************************/ +F32 getTotalFluidBolusVolumeDelivered( void ) +{ + return totalFluidVolumeDelivered_mL; +} + +/*********************************************************************//** + * @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. + *************************************************************************/ +BOOL signalStartFluidBolus( void ) +{ + BOOL result = FALSE; + + if ( ( FLUID_BOLUS_IDLE_STATE == currentFluidBolusState ) && ( FALSE == fluidBolusStartRequested ) ) + { + fluidBolusStartRequested = TRUE; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The signalAbortFluidBolus function signals an external abort to the + * fluid bolus service. Called by user-stop or the global alarm-stop hook. + * @details \b Inputs: currentFluidBolusState + * @details \b Outputs: fluidBolusAbortRequested + * @return none + *************************************************************************/ +void signalAbortFluidBolus( void ) +{ + if ( FLUID_BOLUS_IDLE_STATE != currentFluidBolusState ) + { + fluidBolusAbortRequested = TRUE; + } +} + +/*********************************************************************//** + * @brief + * The publishFluidBolusData function publishes the fluid bolus data + * at the set time interval. + * @details \b Inputs: fluidBolusBroadCastTimerCtr, currentFluidBolusState, + * bolusFluidVolumeDelivered_mL, totalFluidVolumeDelivered_mL + * @details \b Outputs: fluidBolusBroadCastTimerCtr + * @return none + *************************************************************************/ +void publishFluidBolusData( void ) +{ + if ( ++fluidBolusBroadCastTimerCtr >= FLUID_BOLUS_DATA_PUB_INTERVAL ) + { + FLUID_BOLUS_DATA_PAYLOAD_T data; + + data.tgtFluidVolumeMl = getTreatmentParameterU32( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); + data.bolFluidVolumeMl = bolusFluidVolumeDelivered_mL; + data.cumFluidVolumeMl = totalFluidVolumeDelivered_mL; + data.fluidBolusState = currentFluidBolusState; + + broadcastData( MSG_ID_TD_FLUID_BOLUS_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( FLUID_BOLUS_DATA_PAYLOAD_T ) ); + + fluidBolusBroadCastTimerCtr = 0; + } +} + +/*********************************************************************//** + * @brief + * The handleFluidBolusIdleState function handles the idle state of the + * fluid bolus state machine. + * @details \b Inputs: fluidBolusStartRequested + * @details \b Outputs: fluidBolusStartRequested, bolusVolumeLastUpdateTimeStamp + * @return next fluid bolus state + *************************************************************************/ +static FLUID_BOLUS_STATE_T handleFluidBolusIdleState( void ) +{ + FLUID_BOLUS_STATE_T state = FLUID_BOLUS_IDLE_STATE; + + // Handle fluid bolus start request + if ( TRUE == fluidBolusStartRequested ) + { + fluidBolusStartRequested = FALSE; + // Stop blood pump + setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + // Stop substitution pump + cmdSubstitutionRate( 0.0F ); + bolusVolumeLastUpdateTimeStamp = getMSTimerCount(); + state = FLUID_BOLUS_WAIT_FOR_PUMPS_STOP_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFluidBolusWait4Pumps2Stop function handles the wait for pumps + * to stop state of the fluid bolus state machine. + * @details \b Inputs: fluidBolusAbortRequested, currentFluidBolusMedium + * @details \b Outputs: fluidBolusAbortRequested, bolusFluidVolumeDelivered_mL, + * bolusVolumeLastUpdateTimeStamp + * @return next fluid bolus state + *************************************************************************/ +static FLUID_BOLUS_STATE_T handleFluidBolusWait4Pumps2Stop( void ) +{ + FLUID_BOLUS_STATE_T state = FLUID_BOLUS_WAIT_FOR_PUMPS_STOP_STATE; + + if( TRUE == fluidBolusAbortRequested ) + { + fluidBolusAbortRequested = FALSE; + signalBloodPumpHardStop(); + state = FLUID_BOLUS_IDLE_STATE; + } + else if ( FALSE == isBloodPumpRunning() ) // TODO: Write condition to check D92 when HDF is implemented + { + // Reset bolus data before we start + bolusFluidVolumeDelivered_mL = 0.0; + bolusVolumeLastUpdateTimeStamp = getMSTimerCount(); + + 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 ); + state = FLUID_BOLUS_SALINE_IN_PROGRESS_STATE; + } + else if ( TRUE == isDialysateGoodToDeliver() ) + { + // set D92 flow rate + cmdSubstitutionRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ); + state = FLUID_BOLUS_SUBSITUTE_IN_PROGRESS_STATE; + } + else + { + // No actuator action required. + state = FLUID_BOLUS_IDLE_STATE; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFluidBolusSalineInProgressState function handles the saline + * in-progress state of the fluid bolus state machine. Integrates delivered + * 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, + * @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 ); + + updateFluidBolusVolumeDelivered(); + + // Check for empty saline bag per arterial line pressure + if ( TRUE == isSalineBagEmpty() ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_TD_EMPTY_SALINE_BAG, getFilteredArterialPressure() ); + state = FLUID_BOLUS_IDLE_STATE; + } + // Determine if bolus is complete or stopped by user + else if ( ( bolusFluidVolumeDelivered_mL >= bolusTargetVolume ) || ( TRUE == fluidBolusAbortRequested ) ) + { + fluidBolusAbortRequested = FALSE; + state = FLUID_BOLUS_IDLE_STATE; + } + + // complete or abort or alarm + if ( state != FLUID_BOLUS_SALINE_IN_PROGRESS_STATE ) + { + // Hard stop blood + signalBloodPumpHardStop(); + completeBolusToCumulative(); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleFluidBolusSubstituteInProgressState function handles the + * substitute in-progress state state of the fluid bolus state machine. + * Integrates delivered volume from measured blood flow. Monitors dialysate + * readiness every tick, aborts if dialysate is no longer good to deliver. + * Completes the bolus when target is reached or an abort is requested. + * @details \b Inputs: bolusFluidVolumeDelivered_mL, fluidBolusAbortRequested + * @details \b Outputs: fluidBolusAbortRequested, + * totalFluidVolumeDelivered_mL via completeBolusToCumulative() + * @return next fluid bolus state. + *************************************************************************/ +static FLUID_BOLUS_STATE_T handleFluidBolusSubstituteInProgressState( void ) +{ + FLUID_BOLUS_STATE_T state = FLUID_BOLUS_SUBSITUTE_IN_PROGRESS_STATE; + F32 bolusTargetVolume = (F32)getTreatmentParameterU32( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); + + updateFluidBolusVolumeDelivered(); + + // Check for dialysate, target volume delivered or abort from user + 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; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The updateFluidBolusVolumeDelivered function integrates the volume + * delivered for the active bolus. + * @details \b Inputs: currentFluidBolusMedium, bolusVolumeLastUpdateTimeStamp + * @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; + bolusVolumeLastUpdateTimeStamp = getMSTimerCount(); +} + +/*********************************************************************//** + * @brief + * The completeBolusToCumulative function rolls the per-bolus delivered + * volume into the cumulative counter and emits a treatment log event. + * @details \b Inputs: bolusFluidVolumeDelivered_mL + * @details \b Outputs: totalFluidVolumeDelivered_mL, bolusFluidVolumeDelivered_mL, + * @return none + *************************************************************************/ +static void completeBolusToCumulative( void ) +{ + totalFluidVolumeDelivered_mL += bolusFluidVolumeDelivered_mL; + SEND_EVENT_WITH_2_F32_DATA( FLUID_BOLUSES_CHANGE_EVENT, bolusFluidVolumeDelivered_mL, totalFluidVolumeDelivered_mL ); + bolusFluidVolumeDelivered_mL = 0.0F; +} + +/*********************************************************************//** + * @brief + * The areAllActiveAlarmsPermittedForBolus function checks whether all + * currently active alarms are from permitted list. + * @details \b Inputs: FLUID_BOLUS_PERMITTED_PAUSED_ALARMS[] + * @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. + *************************************************************************/ +BOOL areAllActiveAlarmsPermittedForBolus( void ) +{ + U32 i; + U32 permittedCount = 0U; + U32 totalCount = getActiveAlarmCount(); + BOOL result = FALSE; + + if ( 0U == totalCount ) + { + return FALSE; + } + + for ( i = 0U; i < 6; i++ ) + { + if ( TRUE == isAlarmActive( FLUID_BOLUS_PERMITTED_PAUSED_ALARMS[ i ] ) ) + { + permittedCount++; + } + } + + result = ( permittedCount == totalCount ) ? TRUE: FALSE; + + return result; +} + + +/**@}*/ Index: firmware/App/Services/FluidBolus.h =================================================================== diff -u --- firmware/App/Services/FluidBolus.h (revision 0) +++ firmware/App/Services/FluidBolus.h (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -0,0 +1,74 @@ +/************************************************************************** +* +* Copyright (c) 2025-2026 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file FluidBolus.h +* +* @author (last) Praneeth Bunne +* @date (last) 01-May-2026 +* +* @author (original) Praneeth Bunne +* @date (original) 01-May-2026 +* +***************************************************************************/ + +#ifndef __FLUID_BOLUS_H__ +#define __FLUID_BOLUS_H__ + +#include "TDCommon.h" +#include "TDDefs.h" + +/** + * @defgroup FluidBolus, FluidBolus + * @brief Fluid Bolus unit provides bolus service to the + * Blood Prime, HD/HDF, ISO UF, End states of Treatment mode. + * + * @addtogroup FluidBolus + * @{ + */ + +// ********** public definitions ********** + +// Enumeration of fluid bolus medium types +enum Fluid_Bolus_Medium +{ + FLUID_BOLUS_MEDIUM_SALINE = 0, ///< Saline bolus (HD modality). + FLUID_BOLUS_MEDIUM_SUBSTITUTE, ///< Substitution bolus (HDF / HD-online modality). + NUM_OF_FLUID_BOLUS_MEDIUMS ///< Number of fluid bolus medium types. +}; +typedef enum Fluid_Bolus_Medium FLUID_BOLUS_MEDIUM_T; + +#pragma pack(push,1) +/// 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. +} FLUID_BOLUS_DATA_PAYLOAD_T; +#pragma pack(pop) + +// ********** public definitions ********** + +void initFluidBolus( void ); +void publishFluidBolusData( void ); + +FLUID_BOLUS_STATE_T execFluidBolus( void ); +FLUID_BOLUS_STATE_T getFluidBolusState( void ); +FLUID_BOLUS_MEDIUM_T getFluidBolusMedium( void ); + +BOOL isFluidBolusActive( void ); +BOOL signalStartFluidBolus( void ); +void signalAbortFluidBolus( void ); +F32 getCurrentFluidBolusVolumeDelivered( void ); +F32 getTotalFluidBolusVolumeDelivered( void ); + +BOOL areAllActiveAlarmsPermittedForBolus( void ); + +/**@}*/ + +#endif Index: firmware/App/Services/Messaging.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -27,10 +27,12 @@ #include "CpldInterface.h" #include "DDInterface.h" #include "Ejector.h" +#include "FluidBolus.h" #include "FpgaTD.h" #include "LevelSensors.h" #include "Messaging.h" #include "ModeStandby.h" +#include "ModeTreatment.h" #include "OperationModes.h" #include "PAL.h" #include "Pressures.h" @@ -41,6 +43,7 @@ #include "Switches.h" #include "SystemCommTD.h" #include "Temperatures.h" +#include "TDDefs.h" #include "TxParams.h" #include "Utilities.h" #include "Valve3Way.h" @@ -114,6 +117,8 @@ { MSG_ID_UI_PRESSURE_LIMIT_WIDEN_REQUEST, &pressureLimitHandleWidenRequest }, { 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 }, @@ -562,7 +567,107 @@ 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 -r395522dffef1348e176564925656012f529c1910 -r6f876554db45a19590eaf2122ef47e33f7a7d69b --- firmware/App/Services/Messaging.h (.../Messaging.h) (revision 395522dffef1348e176564925656012f529c1910) +++ firmware/App/Services/Messaging.h (.../Messaging.h) (revision 6f876554db45a19590eaf2122ef47e33f7a7d69b) @@ -110,8 +110,16 @@ U32 maxDialRate; ///< Maximum dialysate flow rate (in mL/min) } TREATMENT_PARAM_BROADCAST_PAYLOAD_T; +/// Payload record structure for Fluid Bolus response. typedef struct { + U32 accepted; ///< Accepted/Rejected + U32 rejectionReason; ///< Rejection reason if not accepted. + U32 targetVolumeMl; ///< Target fluid bolus volume in mL. +} FLUID_BOLUS_RESPONSE_PAYLOAD_T; + +typedef struct +{ U32 minBloodFlowMLPM; ///< Min blood flow in mL/min. U32 maxBloodFlowMLPM; ///< Max blood flow in mL/min. U32 minDialysateFlowMLPM; ///< Min dialysate flow in mL/min. @@ -159,6 +167,8 @@ 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