Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -r222b05e39082f727dcfa2d144fa6e040501882f0 -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 222b05e39082f727dcfa2d144fa6e040501882f0) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -7,79 +7,104 @@ * * @file ModePreTreat.c * -* @author (last) Raghu Kallala -* @date (last) 08-May-2026 +* @author (last) Vijay Pamula +* @date (last) 14-Jul-2026 * * @author (original) Dara Navaei * @date (original) 25-Sep-2025 * ***************************************************************************/ +#include "AirPump.h" +#include "AirTrap.h" +#include "BloodFlow.h" #include "Buttons.h" #include "DDInterface.h" #include "ModePreTreat.h" #include "OperationModes.h" +#include "StatePreTxRecirculate.h" +#include "SyringePump.h" #include "Timers.h" +#include "TubeSetInstall.h" #include "TxParams.h" +#include "Valves.h" +#include "Valve3Way.h" /** * @addtogroup TDPreTreatmentMode * @{ */ -// ********** private definitions ********** - // ********** private data ********** static TD_PRE_TREATMENT_MODE_STATE_T currentPreTreatmentState; ///< Current Pre-Treatment sub-state +static BOOL goToInstallStateRequested; ///< Flag indicating a request to transition to Install state. +static BOOL continueFromRecirculateRequested; ///< Flag indicating a request to transition to Patient Connection state. // ********** private function prototypes ********** -static TD_PRE_TREATMENT_MODE_STATE_T handleRxState( void ); ///< Handle Confirm Rx state during Pre-Treatment +static void setPreTreatStateTransition( void ); ///< Configure actuators and variables for Pre-Treatment state transitions. +static TD_PRE_TREATMENT_MODE_STATE_T handleInstallState( void ); ///< Handle Install state during Pre-Treatment +static TD_PRE_TREATMENT_MODE_STATE_T handleSelfTestDryState( void ); ///< Handle Self Test Dry state during Pre-Treatment +static TD_PRE_TREATMENT_MODE_STATE_T handlePrimeState( void ); ///< Handle Prime state during Pre-Treatment +static TD_PRE_TREATMENT_MODE_STATE_T handleRecirculateState( void ); ///< Handle Recirculate state during Pre-Treatment +static TD_PRE_TREATMENT_MODE_STATE_T handleRxState( void ); ///< Handle Confirm Rx state during Pre-Treatment +static TD_PRE_TREATMENT_MODE_STATE_T handlePatientConnectionState( void ); ///< Handle Patient Connection state during Pre-Treatment /*********************************************************************//** * @brief * The initPreTreatmentMode function initializes the Pre-Treatment mode. * @details Inputs: none -* @details Outputs: Resets the Treatment Parameters session and sets the initial +* @details Outputs: Initializes the Treatment Parameters session and sets the initial * Pre-Treatment sub-state. * @return none **************************************************************************/ void initPreTreatmentMode( void ) { // Start a fresh Treatment Parameters session for this run. - resetTreatmentParameters(); - currentPreTreatmentState = TD_PRE_TREATMENT_CONFIRM_RX_STATE; + initTreatmentParameters(); + currentPreTreatmentState = TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE; + goToInstallStateRequested = FALSE; + continueFromRecirculateRequested = FALSE; } /*********************************************************************//** * @brief * The transitionToPreTreatmentMode function prepares the system for * entry into Pre-Treatment mode. -* @details Inputs: none -* @details Outputs: Initializes mode specific state and returns the starting +* @details \b Inputs: none +* @details \b Outputs: Initializes mode specific state and returns the starting * Pre-Treatment sub-state. * @return Initial Pre-Treatment sub-state **************************************************************************/ U32 transitionToPreTreatmentMode( void ) { initPreTreatmentMode(); + initTubeSetInstall(); + // TODO: remove after implementing blood pump homing in some state + homeBloodPump(); + + // TODO: remove these homeValve() when SELF_TEST_NO_CART_STATE is implemented (homing valves is handled over there). + homeValve(H1_VALV, FALSE, FALSE); + homeValve(H19_VALV, FALSE, FALSE); + return (U32)currentPreTreatmentState; } /*********************************************************************//** * @brief * The execPreTreatmentMode function executes the Pre-Treatment * mode state machine. - * @details Inputs: stop button status and system conditions via helpers. - * @details Outputs: Advances the Pre-Treatment sub-state and + * @details \b Inputs: stop button status and system conditions via helpers. + * @details \b Outputs: Advances the Pre-Treatment sub-state and * previously received user confirmations. * @return current Pre-Treatment sub-state. *************************************************************************/ U32 execPreTreatmentMode( void ) { BOOL stop = isStopButtonPressed(); + TD_PRE_TREATMENT_MODE_STATE_T prevPreTreatmentState = currentPreTreatmentState; if ( TRUE == stop ) { @@ -89,58 +114,194 @@ // Execute mode state machine switch ( currentPreTreatmentState ) { - case TD_PRE_TREATMENT_WATER_SAMPLE_STATE: - // currentPreTreatmentState = handleWaterSampleState(); + case TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE: + currentPreTreatmentState = handleInstallState(); break; - case TD_PRE_TREATMENT_SELF_TEST_CONSUMABLE_STATE: - // currentPreTreatmentState = handleSelfTestConsumableState(); + case TD_PRE_TREATMENT_SELF_TEST_DRY_STATE: + // currentPreTreatmentState = handleSelfTestDryState(); break; - case TD_PRE_TREATMENT_SELF_TEST_NO_CART_STATE: - // currentPreTreatmentState = handleSelfTestNoCartState(); + case TD_PRE_TREATMENT_PRIME_STATE: + // currentPreTreatmentState = handlePrimeState(); break; - case TD_PRE_TREATMENT_CART_INSTALL_STATE: - // currentPreTreatmentState = handleInstallState(); + case TD_PRE_TREATMENT_CONFIRM_RX_STATE: + // Confirm Rx state + currentPreTreatmentState = handleRxState(); break; + case TD_PRE_TREATMENT_RECIRCULATE_STATE: + currentPreTreatmentState = handleRecirculateState(); + break; + + case TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE: + // currentPreTreatmentState = handlePatientConnectionState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRE_TREATMENT_INVALID_STATE, (U32)currentPreTreatmentState ); + break; + } + + if ( prevPreTreatmentState != currentPreTreatmentState ) + { + setPreTreatStateTransition(); + } + + return (U32)currentPreTreatmentState; +} + +/*********************************************************************//** +* @brief +* The setPreTreatStateTransition function sets the actuators and variables +* for the state transition in Pre-Treatment mode. +* @details \b Inputs: currentPreTreatmentState +* @details \b Outputs: Actuate valves, pumps as desired +* @return none +**************************************************************************/ +static void setPreTreatStateTransition( void ) +{ + switch ( currentPreTreatmentState ) + { + case TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE: + // H4 and H5 are controlled by the Tube Set Install Service. + setValvePosition( H1_VALV, VALVE_POSITION_A_INSERT_EJECT ); + setValvePosition( H19_VALV, VALVE_POSITION_A_INSERT_EJECT ); + setAirPumpState( AIR_PUMP_STATE_OFF, AIR_PUMP_MOTOR_OFF ); + set3WayValveState( H13_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + set3WayValveState( H20_VALV, VALVE_3WAY_COMMON_TO_CLOSED_STATE ); + stopSyringePump(); + break; + case TD_PRE_TREATMENT_SELF_TEST_DRY_STATE: - // currentPreTreatmentState = handleSelfTestDryState(); + // TODO: actuator configuration break; case TD_PRE_TREATMENT_PRIME_STATE: - // currentPreTreatmentState = handlePrimeState(); + // TODO: actuator configuration break; - case TD_PRE_TREATMENT_RECIRCULATE_STATE: - // currentPreTreatmentState = handleRecirculateState(); + case TD_PRE_TREATMENT_CONFIRM_RX_STATE: + // No action required. break; - case TD_PRE_TREATMENT_CONFIRM_RX_STATE: - // Confirm Rx state - currentPreTreatmentState = handleRxState(); + case TD_PRE_TREATMENT_RECIRCULATE_STATE: + // No action required. break; case TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE: - // currentPreTreatmentState = handlePatientConnectionState(); + // TODO: actuator configuration break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_PRE_TREATMENT_INVALID_STATE, (U32)currentPreTreatmentState ); break; } +} - return (U32)currentPreTreatmentState; +/*********************************************************************//** + * @brief + * The handleInstallState function calls Tube Set Install Service and + * advances to Self Test Dry state once the service signals + * completion. + * @details \b Inputs: none + * @details \b Outputs: Advances Pre-Treatment state when install is complete. + * @return next Pre-Treatment mode state + *************************************************************************/ +static TD_PRE_TREATMENT_MODE_STATE_T handleInstallState( void ) +{ + TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE; + + // call tube set install service to auto-load tube set + execTubeSetInstall(); + + if ( TRUE == isTubeSetInstallComplete() ) + { + state = TD_PRE_TREATMENT_SELF_TEST_DRY_STATE; + } + + return state; } /*********************************************************************//** * @brief + * The handleSelfTestDryState function executes the Self Test Dry state + * of pre-treatment mode. + * @details \b Inputs: TODO fill up if any + * @details \b Outputs: TODO fill up if any + * @return next Pre-Treatment mode state. + *************************************************************************/ +static TD_PRE_TREATMENT_MODE_STATE_T handleSelfTestDryState( void ) +{ + TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_SELF_TEST_DRY_STATE; + + if ( TRUE == goToInstallStateRequested ) + { + goToInstallStateRequested = FALSE; + initTubeSetInstall(); + state = TD_PRE_TREATMENT_TUBING_SET_INSTALL_STATE; + } + + // TODO: Transition to Prime state on completion when implemented + // state = TD_PRE_TREATMENT_PRIME_STATE; + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePrimeState function executes the Prime state of + * pre-treatment mode. + * @details \b Inputs: TODO fill up if any + * @details \b Outputs: TODO fill up if any + * @return next Pre-Treatment mode state. + *************************************************************************/ +static TD_PRE_TREATMENT_MODE_STATE_T handlePrimeState( void ) +{ + TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_PRIME_STATE; + + // TODO: Transition to Recirculate state on completion when implemented + // state = TD_PRE_TREATMENT_RECIRCULATE_STATE; + + return state; +} + +/*********************************************************************//** + * @brief + * The handleRecirculateState function executes the Recirculate state of + * pre-treatment mode. + * @details \b Inputs: continueFromRecirculateRequested. + * @details \b Outputs: continueFromRecirculateRequested. + * @return next Pre-Treatment mode state. + *************************************************************************/ +static TD_PRE_TREATMENT_MODE_STATE_T handleRecirculateState( void ) +{ + TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_RECIRCULATE_STATE; + + execPreTxRecirculate(); + + if ( TRUE == continueFromRecirculateRequested ) + { + continueFromRecirculateRequested = FALSE; + + // TODO: Change to TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE + // when Patient Connection state is implemented. + // state = TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; + + requestNewOperationMode( MODE_TREA ); + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleRxState function executes the Confirm Rx pre-treatment step. - * @details Inputs: none - * @details Outputs: Requests transition to Treatment mode when the prescription + * @details \b Inputs: none + * @details \b Outputs: Requests transition to the next Pre-Treatment state when the prescription * is valid and confirmed otherwise remains in Confirm Rx. - * @return next Pre-Treatment mode sub-state. + * @return next Pre-Treatment mode state. *************************************************************************/ static TD_PRE_TREATMENT_MODE_STATE_T handleRxState( void ) { @@ -154,7 +315,7 @@ 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 + // Valid + confirmed – move to next state: Recirculate State if ( ( TRUE == paramsValid ) && ( TRUE == paramsConfirmed ) ) { // TODO this command of requesting dialysate delivery will move to appropriate state in pre-treatment once implemented @@ -170,22 +331,63 @@ 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; - if ( ( ddOpMode == DD_MODE_GEND ) && ( TRUE == isDialysateGoodToDeliver ) ) - { - requestNewOperationMode( MODE_TREA ); - } - } + state = TD_PRE_TREATMENT_RECIRCULATE_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handlePatientConnectionState function executes the Patient + * Connection state of pre-treatment mode. + * @details \b Inputs: TODO fill up if any + * @details \b Outputs: TODO fill up if any + * @return next Pre-Treatment mode state. + *************************************************************************/ +static TD_PRE_TREATMENT_MODE_STATE_T handlePatientConnectionState( void ) +{ + TD_PRE_TREATMENT_MODE_STATE_T state = TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE; + + // TODO : after implementing this state, place the transition in the right place + + //requestNewOperationMode( MODE_TREA ); + return state; } /*********************************************************************//** * @brief + * The PreTxRequestTubeSetInstall function signals a request to transition + * the Pre-Treatment mode state machine to Install state. + * @details \b Inputs: none + * @details \b Outputs: goToInstallStateRequested + * @return none + *************************************************************************/ +void PreTxRequestTubeSetInstall( void ) +{ + goToInstallStateRequested = TRUE; +} + +/*********************************************************************//** + * @brief + * The PreTxRequestContinueFromRecirculate function signals a request to + * transition the Pre-Treatment mode state machine to Patient Connection state. + * @details \b Inputs: none + * @details \b Outputs: continueFromRecirculateRequested + * @return none + *************************************************************************/ +void PreTxRequestContinueFromRecirculate( void ) +{ + continueFromRecirculateRequested = TRUE; +} + +/*********************************************************************//** + * @brief * The signalAlarmActionToPreTreatmentMode function executes the given alarm action * as appropriate while in Pre-Treatment Mode. - * @details \b Inputs: none + * @details \b Inputs: currentPreTreatmentState * @details \b Outputs: given alarm action executed * @param action ID of alarm action to execute * @return none @@ -198,6 +400,13 @@ // TODO add logic once we have pre-treatment mode developed break; + case ALARM_ACTION_RESUME: + if ( TD_PRE_TREATMENT_RECIRCULATE_STATE == currentPreTreatmentState ) + { + signalResumePreTxRecirculate(); + } + break; + default: // do not handle other actions in pre-treatment mode break; Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r222b05e39082f727dcfa2d144fa6e040501882f0 -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 222b05e39082f727dcfa2d144fa6e040501882f0) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -7,8 +7,8 @@ * * @file ModeTreatment.c * -* @author (last) Raghu Kallala -* @date (last) 04-May-2026 +* @author (last) Vijay Pamula +* @date (last) 26-Jun-2026 * * @author (original) Sean Nash * @date (original) 21-Apr-2025 @@ -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" @@ -54,8 +55,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 ) @@ -73,7 +72,7 @@ static BOOL treatmentCompleted; ///< Flag indicates whether the treatment has completed. static U32 presTreatmentTimeSecs; ///< Prescribed treatment time (in seconds). -static F32 presUFVolumeMl; ///< Prescribed ultrafiltration volume (in L). +static F32 presUFVolumeMl; ///< Prescribed ultrafiltration volume (in Ml). static F32 presUFRateMlMin; ///< Prescribed ultrafiltration rate (in mL/Min). static U32 treatmentTimeMS; ///< Elapsed treatment time (in ms). @@ -85,6 +84,7 @@ static U32 isolatedUFBroadcastTimerCtr; ///< Isolated UF 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; /// Interval (in task intervals) at which to publish alarm status to CAN bus. @@ -114,7 +114,6 @@ static void broadcastTreatmentSettingsRanges( void ); static void broadcastTreatmentPeriodicData(); -static void publishSalineBolusData( void ); // TODO - move to StateTxSalineBolus.c when implemented static void publishUltrafiltrationData( void ); static void publishIsolatedUFData( void ); static U32 getMinTreatmentTimeInMinutes( void ); @@ -123,7 +122,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 ); @@ -172,7 +170,6 @@ 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 isolatedUFBroadcastTimerCtr = ULTRAFILTRATION_DATA_PUB_INTERVAL; // So we send isolated UF immediately when we enter isolated UF - salineBolusBroadcastTimerCtr = SALINE_BOLUS_DATA_PUB_INTERVAL; // So we send saline bolus data immediately when we begin treatment mode presTreatmentTimeSecs = 0; presUFVolumeMl = 0.0F; @@ -232,6 +229,7 @@ // initRinseback(); // initTreatmentRecirc(); // initTreatmentEnd(); + initFluidBolus(); // Started the treatment - set the start time in epoch // setTxLastStartTimeEpoch( getRTCTimestamp() ); @@ -260,8 +258,8 @@ getTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE ) ); // Read back limits for transmit to UI. respRecord.artPresLimitWindowmmHg = getSysConfigTreatmentParameterU32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ); - respRecord.venPresLimitWindowmmHg = getSysConfigTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ); - respRecord.venPresLimitAsymmetricmmHg = getSysConfigTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ); + respRecord.venPresLimitWindowmmHg = getSysConfigTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_HIGH_LIMIT_WINDOW ); + respRecord.venPresLimitAsymmetricmmHg = getSysConfigTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_LOW_LIMIT_WINDOW ); respRecord.tmpPresLimitWindowmmHg = getSysConfigTreatmentParameterU32( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ); // Send response sendPressureLimitsChangeResponse( &respRecord ); @@ -707,12 +705,12 @@ publishUltrafiltrationData(); // Publish isolated UF data only while isolated UF is active publishIsolatedUFData(); - // Publish saline bolus data at set interval (whether we are delivering one or not) - publishSalineBolusData(); - // Manage air trap control execAirTrapMonitorTreatment(); + // Call fluid bolus + execFluidBolus(); + return currentTreatmentState; } @@ -827,10 +825,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 ) { @@ -1210,14 +1213,32 @@ payload.rinsebackState = 0; // getCurrentRinsebackState(); payload.txRecircState = 0; // getCurrentTreatmentRecircState(); payload.txEndState = 0; // getCurrentTreatmentEndState(); - payload.txSalBolusState = 0; // + payload.txFluidBolusState = getCurrentFluidBolusState(); payload.txHepState = 0; // broadcastData( MSG_ID_TD_TREATMENT_STATE_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)(&payload), sizeof( TREATMENT_STATE_DATA_T ) ); } } /*********************************************************************//** * @brief + * The updateTreatmentBroadcastData function updates treatment broadcast + * data values used for treatment time and ultrafiltration broadcasts. + * @details \b Inputs: none. + * @details \b Outputs: presTreatmentTimeSecs, presUFVolumeMl, presUFRateMlMin. + * @param ufRateLhr ultrafiltration rate in L/hr. + * @return none. + *************************************************************************/ +void updateTreatmentBroadcastData( F32 ufRateLhr ) +{ + presTreatmentTimeSecs = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ) * SEC_PER_MIN; + + presUFVolumeMl = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); + + presUFRateMlMin = ( ufRateLhr * (F32)ML_PER_LITER ) / (F32)MIN_PER_HOUR; +} + +/*********************************************************************//** + * @brief * The broadcastTreatmentSettingsRanges function computes and broadcasts * updated treatment parameter ranges that the user may change during treatment. * It is assumed that prescription settings have already been set prior to calling @@ -1286,7 +1307,7 @@ // F32 const arterialPres = getFilteredArterialPressure(); // F32 const venousPres = getFilteredVenousPressure(); // -// if ( ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) && ( getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) ) +// if ( ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) && ( getTreatmentState() != TREATMENT_SALINE_BOLUS_STATE ) ) // { // treatmentBloodFlowRateTotal_mL_min += getMeasuredBloodFlowRate(); // treatmentDialysateFlowRateTotal_mL_min += getMeasuredDialInFlowRate(); @@ -1397,30 +1418,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: none @@ -1437,7 +1434,7 @@ presUFRateLHr = presUFVolumeL / ( (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ) / (F32)MIN_PER_HOUR ); data.setUFVolumeL = presUFVolumeL; - data.tgtUFRateLHr = presUFRateLHr; + data.tgtUFRateLHr = ( presUFRateMlMin * (F32)MIN_PER_HOUR ) / (F32)ML_PER_LITER; data.ufVolumeDeliveredL = getUltrafiltrationVolumeDrawn(); data.ufState = (U32)getDialysisState(); Index: firmware/App/Modes/ModeTreatment.h =================================================================== diff -u -r96604b790636c66ef21980a4f13ee9f987f12fee -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) +++ firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -7,8 +7,8 @@ * * @file ModeTreatment.h * -* @author (last) Raghu Kallala -* @date (last) 06-Apr-2026 +* @author (last) Praneeth Bunne +* @date (last) 04-Jun-2026 * * @author (original) Sean Nash * @date (original) 21-Apr-2025 @@ -55,7 +55,7 @@ U32 rinsebackState; ///< Rinse back state. U32 txRecircState; ///< Treatment recirc state. U32 txEndState; ///< Treatment end state. - U32 txSalBolusState; ///< Saline bolus state. + U32 txFluidBolusState; ///< Fluid bolus state. U32 txHepState; ///< Heparin state. } TREATMENT_STATE_DATA_T; @@ -113,26 +113,27 @@ // ********** public function prototypes ********** -void initTreatmentMode( void ); // Initialize this unit -U32 transitionToTreatmentMode( void ); // Prepares for transition to treatment mode -U32 execTreatmentMode( void ); // Execute the treatment mode state machine (call from OperationModes) +void initTreatmentMode( void ); // Initialize this unit +U32 transitionToTreatmentMode( void ); // Prepares for transition to treatment mode +U32 execTreatmentMode( void ); // Execute the treatment mode state machine (call from OperationModes) -void signalAlarmActionToTreatmentMode( ALARM_ACTION_T action ); // Execute alarm action as appropriate for treatment mode -void signalEndTreatment( void ); // Requesting transition to post-treatment mode -void signalBloodPrimeToDialysis( void ); // Blood prime sub-mode is signaling to move on to dialysis sub-mode +void signalAlarmActionToTreatmentMode( ALARM_ACTION_T action ); // Execute alarm action as appropriate for treatment mode +void signalEndTreatment( void ); // Requesting transition to post-treatment mode +void signalBloodPrimeToDialysis( void ); // Blood prime sub-mode is signaling to move on to dialysis sub-mode -void broadcastTreatmentTimeAndState( void ); // Broadcast the times and states of this treatment +void broadcastTreatmentTimeAndState( void ); // Broadcast the times and states of this treatment +void updateTreatmentBroadcastData( F32 ufRateLhr ); // Update treatment broadcast data from current treatment parameters -TREATMENT_STATE_T getTreatmentState( void ); // Determine the current treatment sub-mode (state) -BOOL isTreatmentCompleted( void ); // Determine whether the treatment has completed -BOOL isTreatmentResumeBlocked( void ); // Determine whether the treatment is not allowed to be resumed. -U32 getTreatmentTimeRemainingSecs( void ); // Determine number of seconds remaining in the treatment -U32 getActualTreatmentTimeSecs( void ); // Determine the actual treatment duration in seconds -void setBloodIsPrimed( BOOL flag ); // Set whether the blood-side circuit of the dialyzer has been primed with blood (F causes Tx start/resume to do blood prime first) -BOOL getBloodIsPrimed( void ); // Determine whether the blood-side circuit of the dialyzer has been primed with blood +TREATMENT_STATE_T getTreatmentState( void ); // Determine the current treatment sub-mode (state) +BOOL isTreatmentCompleted( void ); // Determine whether the treatment has completed +BOOL isTreatmentResumeBlocked( void ); // Determine whether the treatment is not allowed to be resumed. +U32 getTreatmentTimeRemainingSecs( void ); // Determine number of seconds remaining in the treatment +U32 getActualTreatmentTimeSecs( void ); // Determine the actual treatment duration in seconds +void setBloodIsPrimed( BOOL flag ); // Set whether the blood-side circuit of the dialyzer has been primed with blood (F causes Tx start/resume to do blood prime first) +BOOL getBloodIsPrimed( void ); // Determine whether the blood-side circuit of the dialyzer has been primed with blood -U32 getTreatmentStartTimeStamp( void ); // Get the treatment start time stamp -U32 getTreatmentEndTimeStamp( void ); // Get the treatment end time stamp +U32 getTreatmentStartTimeStamp( void ); // Get the treatment start time stamp +U32 getTreatmentEndTimeStamp( void ); // Get the treatment end time stamp BOOL setIsolatedUFSettings( U32 durationMin, F32 ufVolumeMl ); // Set isolated UF duration, goal, and rate void signalStartIsolatedUF( BOOL midTreatment ); // Request transition to isolated UF Index: firmware/App/Modes/StateTxDialysis.c =================================================================== diff -u -r9c833ef5623ce842267e284d958820ac0dc3a7fc -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Modes/StateTxDialysis.c (.../StateTxDialysis.c) (revision 9c833ef5623ce842267e284d958820ac0dc3a7fc) +++ firmware/App/Modes/StateTxDialysis.c (.../StateTxDialysis.c) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -121,7 +121,7 @@ setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); // Set actuators as appropriate for state - cmdStartGenerateDialysate( setDialysateFlowRate, setUFRateMlMin, dialTemp, FALSE, + cmdStartGenerateDialysate( setDialysateFlowRate, setUFRateMlMin, dialTemp, DD_GEND_DIALYSATE_DELIVERY_STATE, acidConvFactor, bicarbConvFactor, sodium, bicarbonate ); transitionToDialysisState( currentDialysisState ); Index: firmware/App/Services/AlarmMgmtTD.c =================================================================== diff -u -r395522dffef1348e176564925656012f529c1910 -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Services/AlarmMgmtTD.c (.../AlarmMgmtTD.c) (revision 395522dffef1348e176564925656012f529c1910) +++ firmware/App/Services/AlarmMgmtTD.c (.../AlarmMgmtTD.c) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -7,77 +7,78 @@ * * @file AlarmMgmtTD.c * -* @author (last) Dara Navaei -* @date (last) 01-Aug-2025 +* @author (last) Santhosh Reddy +* @date (last) 06-Jul-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 * ***************************************************************************/ #define __ALARM_MGMT_TD_C__ - -#include "mibspi.h" - + +#include "mibspi.h" + #include "AlarmMgmtTD.h" #include "Bubbles.h" #include "CpldInterface.h" +#include "FluidBolus.h" #include "Messaging.h" #include "OperationModes.h" -#include "TaskGeneral.h" -#include "Timers.h" +#include "TaskGeneral.h" +#include "Timers.h" -/** - * @addtogroup AlarmManagementTD - * @{ - */ - -// ********** private definitions ********** +/** + * @addtogroup AlarmManagementTD + * @{ + */ -/// Interval to control lamp and audio and to publish alarm status data. -#define ALARM_STATUS_PUBLISH_INTERVAL ( ALARM_LAMP_AND_AUDIO_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) +// ********** private definitions ********** +/// Interval to control lamp and audio and to publish alarm status data. +#define ALARM_STATUS_PUBLISH_INTERVAL ( ALARM_LAMP_AND_AUDIO_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) + /// Interval (ms/task time) at which the alarm information is published on the CAN bus. #define ALARM_INFO_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) #define SUPERVISOR_ALARM_KEY 0xD2C3B4A5 ///< 32-bit key required for clear all alarms request. /// Interval (ms/task time) Alarms are blocked after the return of AC power. #define ALARM_BLOCKED_COUNT_AFTER_AC_RETURN ( 10*MS_PER_SECOND / TASK_GENERAL_INTERVAL ) - -#define ALARM_SILENCE_EXPIRES_IN_SECS (60) ///< Alarm silence expiration time in seconds. - + +#define ALARM_SILENCE_EXPIRES_IN_SECS (60) ///< Alarm silence expiration time in seconds. + #define LOWEST_ALARM_SUB_RANK 999 ///< Lowest alarm sub-rank that can be set. #define ALARM_NOT_BLOCKED 0 ///< Alarm blocked timer value that indicates no alarm block -#define MIN_TIME_BETWEEN_ALARM_ACTIONS_MS MS_PER_SECOND ///< Minimum time between user alarm actions (in ms). - -/// A blank alarm data record for alarms that do not include alarm data when triggered. -const ALARM_DATA_T BLANK_ALARM_DATA = { ALARM_DATA_TYPE_NONE, 0 }; - +#define MIN_TIME_BETWEEN_ALARM_ACTIONS_MS MS_PER_SECOND ///< Minimum time between user alarm actions (in ms). + +/// A blank alarm data record for alarms that do not include alarm data when triggered. +const ALARM_DATA_T BLANK_ALARM_DATA = { ALARM_DATA_TYPE_NONE, 0 }; + /// Alarm priority ranking record. typedef struct { ALARM_ID_T alarmID; ///< ID of highest priority alarm in this priority category U32 subRank; ///< Sub-rank of this alarm S32 timeSinceTriggeredMS; ///< Time (in ms) since this alarm was triggered } ALARM_PRIORITY_RANKS_T; - -// ********** private data ********** - -static OVERRIDE_U32_T alarmStartedAt[ NUM_OF_ALARM_IDS ]; ///< Table - when alarm became active for each alarm (if active) or zero (if inactive) + +// ********** private data ********** + +static OVERRIDE_U32_T alarmStartedAt[ NUM_OF_ALARM_IDS ]; ///< Table - when alarm became active for each alarm (if active) or zero (if inactive) static U32 alarmStatusPublicationTimerCounter = 0; ///< Used to schedule alarm status publication to CAN bus. -static U32 alarmInfoPublicationTimerCounter = 0; ///< Used to schedule alarm information publication to CAN bus. +static U32 alarmInfoPublicationTimerCounter = 0; ///< Used to schedule alarm information publication to CAN bus. static U32 alarmsBlockedTimer = 0; ///< Countdown timer used to temporarily block new alarms from being initiated static U32 lastUserAlarmActionReceivedTime = 0; ///< Time of last alarm action by user received from the UI (ms timestamp). - + /// Interval (in task intervals) at which to publish alarm status to CAN bus. static OVERRIDE_U32_T alarmStatusPublishInterval = { ALARM_STATUS_PUBLISH_INTERVAL, ALARM_STATUS_PUBLISH_INTERVAL, ALARM_STATUS_PUBLISH_INTERVAL, 0 }; /// Interval (in task intervals) at which to publish alarm information to CAN bus. static OVERRIDE_U32_T alarmInfoPublishInterval = { ALARM_INFO_PUB_INTERVAL, ALARM_INFO_PUB_INTERVAL, ALARM_INFO_PUB_INTERVAL, 0 }; -static COMP_ALARM_STATUS_T alarmStatus; ///< Record for the current composite alarm status. +static COMP_ALARM_STATUS_T alarmStatus; ///< Record for the current composite alarm status. static ALARM_PRIORITY_RANKS_T alarmPriorityFIFO[ NUM_OF_ALARM_PRIORITIES ]; ///< FIFO - first activated or highest sub-rank alarm in each alarm priority category. static BOOL alarmUserRecoveryActionEnabled[ NUMBER_OF_ALARM_USER_ACTIONS ]; ///< Alarm user recovery actions enabled flags. @@ -86,76 +87,76 @@ static BOOL resumeBlockedByAlarmProperty; ///< Flag indicates whether treatment resumption is currently blocked by alarm property. -// ********** private function prototypes ********** - -static void activateAlarmTD( ALARM_ID_T alarm ); +// ********** private function prototypes ********** -static void monitorAlarms( void ); -static void updateAlarmsState( void ); -static void setAlarmLamp( void ); -static void updateAlarmsSilenceStatus( void ); -static void updateAlarmsFlags( void ); +static void activateAlarmTD( ALARM_ID_T alarm ); -static BOOL clearAllRecoverableAlarms( ALARM_USER_ACTION_T action ); -static void resetAlarmPriorityFIFO( ALARM_PRIORITY_T priority ); - +static void monitorAlarms( void ); +static void updateAlarmsState( void ); +static void setAlarmLamp( void ); +static void updateAlarmsSilenceStatus( void ); +static void updateAlarmsFlags( void ); + +static BOOL clearAllRecoverableAlarms( ALARM_USER_ACTION_T action ); +static void resetAlarmPriorityFIFO( ALARM_PRIORITY_T priority ); + static U32 getAlarmStartTime( ALARM_ID_T alarmID ); static void publishAlarmInfo( void ); static BOOL broadcastAlarmStatus( COMP_ALARM_STATUS_T almStatus ); - -/*********************************************************************//** - * @brief - * The initAlarmMgmtTD function initializes the TD AlarmMgmt unit. - * @details \b Inputs: none - * @details \b Outputs: TD AlarmMgmt unit initialized. - * @return none - *************************************************************************/ -void initAlarmMgmtTD( void ) -{ - ALARM_PRIORITY_T p; + +/*********************************************************************//** + * @brief + * The initAlarmMgmtTD function initializes the TD AlarmMgmt unit. + * @details \b Inputs: none + * @details \b Outputs: TD AlarmMgmt unit initialized. + * @return none + *************************************************************************/ +void initAlarmMgmtTD( void ) +{ + ALARM_PRIORITY_T p; ALARM_ID_T a; ALARM_BUTTON_BLOCKER_T b; // Initialize common alarm mgmt unit - initAlarmMgmt(); - - // Initialize alarm states and start time stamps - for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) + initAlarmMgmt(); + + // Initialize alarm states and start time stamps + for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { - alarmStartedAt[ a ].data = 0; - alarmStartedAt[ a ].ovData = 0; - alarmStartedAt[ a ].ovInitData = 0; - alarmStartedAt[ a ].override = OVERRIDE_RESET; - } - // Initialize alarm FIFOs - for ( p = ALARM_PRIORITY_NONE; p < NUM_OF_ALARM_PRIORITIES; p++ ) - { + alarmStartedAt[ a ].data = 0; + alarmStartedAt[ a ].ovData = 0; + alarmStartedAt[ a ].ovInitData = 0; + alarmStartedAt[ a ].override = OVERRIDE_RESET; + } + // Initialize alarm FIFOs + for ( p = ALARM_PRIORITY_NONE; p < NUM_OF_ALARM_PRIORITIES; p++ ) + { alarmPriorityFIFO[ p ].alarmID = ALARM_ID_NO_ALARM; alarmPriorityFIFO[ p ].subRank = LOWEST_ALARM_SUB_RANK; - alarmPriorityFIFO[ p ].timeSinceTriggeredMS = 0; + alarmPriorityFIFO[ p ].timeSinceTriggeredMS = 0; } // Initialize alarm button blocker flags for ( b = (ALARM_BUTTON_BLOCKER_T)0; b < NUM_OF_ALARM_BUTTON_BLOCKERS; b++ ) { alarmButtonBlockers[ b ] = FALSE; - } - // Initialize composite alarm state - alarmStatus.alarmsState = ALARM_PRIORITY_NONE; - alarmStatus.alarmsSilenced = FALSE; - alarmStatus.alarmsSilenceStart = 0; + } + // Initialize composite alarm state + alarmStatus.alarmsState = ALARM_PRIORITY_NONE; + alarmStatus.alarmsSilenced = FALSE; + alarmStatus.alarmsSilenceStart = 0; alarmStatus.alarmsSilenceExpiresIn = 0; alarmStatus.alarmTop = ALARM_ID_NO_ALARM; - alarmStatus.topAlarmConditionDetected = FALSE; - alarmStatus.systemFault = FALSE; + alarmStatus.topAlarmConditionDetected = FALSE; + alarmStatus.systemFault = FALSE; alarmStatus.stop = FALSE; - alarmStatus.lampOn = FALSE; - alarmStatus.noClear = FALSE; - alarmStatus.noResume = FALSE; - alarmStatus.noRinseback = FALSE; + alarmStatus.lampOn = FALSE; + alarmStatus.noClear = FALSE; + alarmStatus.noResume = FALSE; + alarmStatus.noRinseback = FALSE; alarmStatus.noEndTreatment = FALSE; alarmStatus.noBloodRecirc = FALSE; - alarmStatus.noDialRecirc = FALSE; + alarmStatus.noDialRecirc = FALSE; alarmStatus.ok = FALSE; alarmsBlockedTimer = 0; @@ -165,24 +166,24 @@ // Initialize alarm audio and lamp initAlarmLamp(); initAlarmAudio(); -} - -/*********************************************************************//** - * @brief - * The execAlarmMgmt function executes the TD alarm management functions to be - * done periodically. The system alarm state is updated, alarm lamp and +} + +/*********************************************************************//** + * @brief + * The execAlarmMgmt function executes the TD alarm management functions to be + * done periodically. The system alarm state is updated, alarm lamp and * audio patterns are updated, and the state of the alarm system is sent out - * to the rest of the system. - * @details \b Inputs: alarmsBlockedTimer - * @details \b Outputs: alarmsBlockedTimer - * @return none - *************************************************************************/ -void execAlarmMgmt( void ) + * to the rest of the system. + * @details \b Inputs: alarmsBlockedTimer + * @details \b Outputs: alarmsBlockedTimer + * @return none + *************************************************************************/ +void execAlarmMgmt( void ) { monitorAlarms(); - updateAlarmsState(); - updateAlarmsFlags(); - updateAlarmsSilenceStatus(); + updateAlarmsState(); + updateAlarmsFlags(); + updateAlarmsSilenceStatus(); // Publish alarm status and information at interval publishAlarmInfo(); @@ -214,9 +215,9 @@ ALARM_T props = getAlarmProperties( alarm ); ALARM_T props_top = getAlarmProperties( alarmStatus.alarmTop ); - // No need to do anything if alarm is already active, but if condition was cleared then re-trigger alarm + // No need to do anything if alarm is already active, but if condition was cleared then re-trigger alarm if ( ( FALSE == isAlarmActive( alarm ) ) || - ( ( FALSE == isAlarmConditionDetected( alarm ) ) && ( FALSE == props.alarmConditionClearImmed ) ) ) + ( ( FALSE == isAlarmConditionDetected( alarm ) ) && ( FALSE == props.alarmConditionClearImmed ) ) ) { activateAlarm( alarm ); alarmStartedAt[ alarm ].data = getMSTimerCount(); @@ -231,31 +232,33 @@ if ( ALARM_ID_NO_ALARM == alarmStatus.alarmTop ) { alarmStatus.alarmTop = alarm; - } + } // If alarm stops, set that status immediately (don't wait for status update function) if ( TRUE == props.alarmStops ) { alarmStatus.stop = TRUE; + // Signal when alarm with stop property is triggered to fluid bolus + signalNewStopAlarmActivated(); } - // If alarm is a fault (and not in service mode), request transition to fault mode - if ( ( TRUE == props.alarmIsFault ) && ( getCurrentOperationMode() != MODE_SERV ) ) - { - requestNewOperationMode( MODE_FAUL ); - } + // If alarm is a fault (and not in service mode), request transition to fault mode + if ( ( TRUE == props.alarmIsFault ) && ( getCurrentOperationMode() != MODE_SERV ) ) + { + requestNewOperationMode( MODE_FAUL ); + } // If alarm has stop property, signal stop now if ( TRUE == props.alarmStops ) { initiateAlarmAction( ALARM_ACTION_STOP ); - } - } - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE1, alarm ) + } + } } -} - + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE1, alarm ) + } +} + /*********************************************************************//** * @brief * The clearAlarmTD function clears a given alarm if it is recoverable. @@ -289,51 +292,51 @@ } } -/*********************************************************************//** - * @brief +/*********************************************************************//** + * @brief * The activateAlarmNoData function activates a given alarm. The alarm - * data that gets logged with this alarm will be blank. - * @details \b Inputs: none - * @details \b Outputs: Alarm is activated - * @param alarm ID of alarm to activate - * @return none - *************************************************************************/ -void activateAlarmNoData( ALARM_ID_T alarm ) + * data that gets logged with this alarm will be blank. + * @details \b Inputs: none + * @details \b Outputs: Alarm is activated + * @param alarm ID of alarm to activate + * @return none + *************************************************************************/ +void activateAlarmNoData( ALARM_ID_T alarm ) { - activateAlarm2Data( alarm, BLANK_ALARM_DATA, BLANK_ALARM_DATA, FALSE ); -} - -/*********************************************************************//** - * @brief + activateAlarm2Data( alarm, BLANK_ALARM_DATA, BLANK_ALARM_DATA, FALSE ); +} + +/*********************************************************************//** + * @brief * The activateAlarm1Data function activates a given alarm. The one given * alarm data will be logged with this alarm as well as a second blank data. - * @details \b Inputs: none - * @details \b Outputs: Alarm is activated - * @param alarm ID of alarm to activate - * @param alarmData First supporting data to include in alarm message - * @return none - *************************************************************************/ -void activateAlarm1Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData ) -{ + * @details \b Inputs: none + * @details \b Outputs: Alarm is activated + * @param alarm ID of alarm to activate + * @param alarmData First supporting data to include in alarm message + * @return none + *************************************************************************/ +void activateAlarm1Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData ) +{ activateAlarm2Data( alarm, alarmData, BLANK_ALARM_DATA, FALSE ); -} - -/*********************************************************************//** - * @brief +} + +/*********************************************************************//** + * @brief * The activateAlarm2Data function activates a given alarm. The two given * alarm data will be logged with this alarm. * @details \b Message \b Sent: MSG_ID_ALARM_TRIGGERED - * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given alarm ID is invalid. - * @details \b Inputs: alarmsBlockedTimer, determines blocked alarm conditions - * @details \b Outputs: Alarm is activated - * @param alarm ID of alarm to activate - * @param alarmData1 First supporting data to include in alarm message + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given alarm ID is invalid. + * @details \b Inputs: alarmsBlockedTimer, determines blocked alarm conditions + * @details \b Outputs: Alarm is activated + * @param alarm ID of alarm to activate + * @param alarmData1 First supporting data to include in alarm message * @param alarmData2 Second supporting data to include in alarm message - * @param outside flag indicates whether alarm is originating from outside TD f/w - * @return none - *************************************************************************/ -void activateAlarm2Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData1, ALARM_DATA_T alarmData2, BOOL outside ) -{ + * @param outside flag indicates whether alarm is originating from outside TD f/w + * @return none + *************************************************************************/ +void activateAlarm2Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData1, ALARM_DATA_T alarmData2, BOOL outside ) +{ // Block if new alarms are occur during loss of AC power // if ( ( TRUE == getCPLDACPowerLossDetected() ) ) // { @@ -390,7 +393,7 @@ else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_TO_ACTIVATE2, alarm ) - } + } } /*********************************************************************//** @@ -679,7 +682,7 @@ ALARM_PRIORITY_T getCurrentAlarmStatePriority( void ) { return alarmStatus.alarmsState; -} +} /*********************************************************************//** * @brief @@ -889,16 +892,16 @@ } } } - -/*********************************************************************//** - * @brief + +/*********************************************************************//** + * @brief * The getAlarmStartTime function gets the start time of a given alarm. - * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given alarm ID is invalid. - * @details \b Inputs: alarmStartedAt[] - * @details \b Outputs: none - * @param alarmID ID of alarm to get start time for - * @return The start time stamp (seconds since power up) of given alarm ID - *************************************************************************/ + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given alarm ID is invalid. + * @details \b Inputs: alarmStartedAt[] + * @details \b Outputs: none + * @param alarmID ID of alarm to get start time for + * @return The start time stamp (seconds since power up) of given alarm ID + *************************************************************************/ static U32 getAlarmStartTime( ALARM_ID_T alarmID ) { U32 result = 0; @@ -945,35 +948,35 @@ // TODO - Check current vs. expected audio output } - -/*********************************************************************//** - * @brief + +/*********************************************************************//** + * @brief * The updateAlarmsState function re-evaluates the current alarm system state * and the "top" alarm to display (highest ranking active alarm). Some of - * the properties of alarm system status are re-evaluated as well. - * @details \b Inputs: alarmStatusTable[] - * @details \b Outputs: alarmStatus, alarmPriorityFIFO[] - * @return none - *************************************************************************/ -static void updateAlarmsState( void ) -{ - ALARM_PRIORITY_T highestPriority = ALARM_PRIORITY_NONE, p; - ALARM_ID_T a; + * the properties of alarm system status are re-evaluated as well. + * @details \b Inputs: alarmStatusTable[] + * @details \b Outputs: alarmStatus, alarmPriorityFIFO[] + * @return none + *************************************************************************/ +static void updateAlarmsState( void ) +{ + ALARM_PRIORITY_T highestPriority = ALARM_PRIORITY_NONE, p; + ALARM_ID_T a; BOOL faultsActive = FALSE; - BOOL dialysateRecircBlocked = FALSE; + BOOL dialysateRecircBlocked = FALSE; BOOL bloodRecircBlocked = FALSE; // Reset priority FIFOs so we can re-determine them below for ( p = ALARM_PRIORITY_NONE; p < NUM_OF_ALARM_PRIORITIES; p++ ) { resetAlarmPriorityFIFO( p ); } - - // Update FIFOs and sub-ranks per active alarms table - for alarm ranking purposes to determine "top" alarm - for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) - { - if ( TRUE == isAlarmActive( a ) ) - { + + // Update FIFOs and sub-ranks per active alarms table - for alarm ranking purposes to determine "top" alarm + for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) + { + if ( TRUE == isAlarmActive( a ) ) + { ALARM_T props = getAlarmProperties( a ); ALARM_PRIORITY_T almPriority = props.alarmPriority; U32 subRank = props.alarmSubRank; @@ -1000,87 +1003,87 @@ alarmPriorityFIFO[ almPriority ].timeSinceTriggeredMS = (S32)msSinceTriggered; } } - // Track highest priority alarm found so far of all priority categories + // Track highest priority alarm found so far of all priority categories highestPriority = MAX( almPriority, highestPriority ); - // Track whether any active faults have been found so far - if ( TRUE == props.alarmIsFault ) - { - faultsActive = TRUE; + // Track whether any active faults have been found so far + if ( TRUE == props.alarmIsFault ) + { + faultsActive = TRUE; } // Track whether any active alarms prevent dialysate re-circulation so far if ( TRUE == props.alarmNoDialysateRecirc ) { dialysateRecircBlocked = TRUE; - } + } // Track whether any active alarms prevent blood re-circulation so far if ( TRUE == props.alarmNoBloodRecirc ) { bloodRecircBlocked = TRUE; } - } - } - - // Update alarm to display per highest priority FIFO - alarmStatus.alarmsState = highestPriority; + } + } + + // Update alarm to display per highest priority FIFO + alarmStatus.alarmsState = highestPriority; alarmStatus.alarmTop = alarmPriorityFIFO[ highestPriority ].alarmID; - alarmStatus.topAlarmConditionDetected = isAlarmConditionDetected( alarmStatus.alarmTop ); + alarmStatus.topAlarmConditionDetected = isAlarmConditionDetected( alarmStatus.alarmTop ); alarmStatus.systemFault = faultsActive; alarmStatus.noBloodRecirc = bloodRecircBlocked; - alarmStatus.noDialRecirc = dialysateRecircBlocked; -} - -/*********************************************************************//** - * @brief + alarmStatus.noDialRecirc = dialysateRecircBlocked; +} + +/*********************************************************************//** + * @brief * The setAlarmLamp function sets the alarm lamp pattern according to the * current state of alarms. - * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if reported alarm state is invalid. - * @details \b Inputs: alarmStatus, ALARM_TABLE[] + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if reported alarm state is invalid. + * @details \b Inputs: alarmStatus, ALARM_TABLE[] * @details \b Outputs: alarmStatus, alarm lamp pattern set according to - * current alarms status. - * @return none - *************************************************************************/ -static void setAlarmLamp( void ) + * current alarms status. + * @return none + *************************************************************************/ +static void setAlarmLamp( void ) { - // Set alarm lamp pattern to appropriate pattern for current alarm state - if ( getCurrentAlarmLampPattern() != LAMP_PATTERN_MANUAL ) - { - switch ( alarmStatus.alarmsState ) - { - case ALARM_PRIORITY_NONE: - requestAlarmLampPattern( LAMP_PATTERN_OK ); - break; - - case ALARM_PRIORITY_LOW: - requestAlarmLampPattern( LAMP_PATTERN_LOW_ALARM ); - break; - - case ALARM_PRIORITY_MEDIUM: - requestAlarmLampPattern( LAMP_PATTERN_MED_ALARM ); - break; - + // Set alarm lamp pattern to appropriate pattern for current alarm state + if ( getCurrentAlarmLampPattern() != LAMP_PATTERN_MANUAL ) + { + switch ( alarmStatus.alarmsState ) + { + case ALARM_PRIORITY_NONE: + requestAlarmLampPattern( LAMP_PATTERN_OK ); + break; + + case ALARM_PRIORITY_LOW: + requestAlarmLampPattern( LAMP_PATTERN_LOW_ALARM ); + break; + + case ALARM_PRIORITY_MEDIUM: + requestAlarmLampPattern( LAMP_PATTERN_MED_ALARM ); + break; + case ALARM_PRIORITY_HIGH: - { + { ALARM_T propsTop = getAlarmProperties( alarmStatus.alarmTop ); - if ( TRUE == propsTop.alarmIsFault ) - { - requestAlarmLampPattern( LAMP_PATTERN_FAULT ); - } - else - { - requestAlarmLampPattern( LAMP_PATTERN_HIGH_ALARM ); + if ( TRUE == propsTop.alarmIsFault ) + { + requestAlarmLampPattern( LAMP_PATTERN_FAULT ); } - } - break; - - default: - requestAlarmLampPattern( LAMP_PATTERN_FAULT ); - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_LAMP_INVALID_ALARM_STATE, alarmStatus.alarmsState ) - break; + else + { + requestAlarmLampPattern( LAMP_PATTERN_HIGH_ALARM ); + } + } + break; + + default: + requestAlarmLampPattern( LAMP_PATTERN_FAULT ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_LAMP_INVALID_ALARM_STATE, alarmStatus.alarmsState ) + break; } } - // Execute alarm lamp controller + // Execute alarm lamp controller execAlarmLamp(); // Set lamp on flag to match current state of alarm lamp @@ -1091,69 +1094,69 @@ else { alarmStatus.lampOn = FALSE; - } -} - -/*********************************************************************//** - * @brief - * The updateAlarmsSilenceStatus function updates the alarms silence state. - * @details \b Inputs: alarmStatus - * @details \b Outputs: alarmStatus - * @return none - *************************************************************************/ -static void updateAlarmsSilenceStatus( void ) -{ - // If alarms not silenced, reset alarms silence related properties - if ( TRUE != alarmStatus.alarmsSilenced ) - { - alarmStatus.alarmsSilenceExpiresIn = 0; - alarmStatus.alarmsSilenceStart = 0; - } - else - { - U32 timeSinceAlarmSilenceStart = calcTimeSince( alarmStatus.alarmsSilenceStart ) / MS_PER_SECOND; - - if ( timeSinceAlarmSilenceStart >= ALARM_SILENCE_EXPIRES_IN_SECS ) - { - alarmStatus.alarmsSilenceExpiresIn = 0; - } - else - { - alarmStatus.alarmsSilenceExpiresIn = ALARM_SILENCE_EXPIRES_IN_SECS - timeSinceAlarmSilenceStart; - } - // If alarms silence expires, end it - if ( 0 == alarmStatus.alarmsSilenceExpiresIn ) - { - alarmStatus.alarmsSilenced = FALSE; - } - } -} + } +} -/*********************************************************************//** - * @brief +/*********************************************************************//** + * @brief + * The updateAlarmsSilenceStatus function updates the alarms silence state. + * @details \b Inputs: alarmStatus + * @details \b Outputs: alarmStatus + * @return none + *************************************************************************/ +static void updateAlarmsSilenceStatus( void ) +{ + // If alarms not silenced, reset alarms silence related properties + if ( TRUE != alarmStatus.alarmsSilenced ) + { + alarmStatus.alarmsSilenceExpiresIn = 0; + alarmStatus.alarmsSilenceStart = 0; + } + else + { + U32 timeSinceAlarmSilenceStart = calcTimeSince( alarmStatus.alarmsSilenceStart ) / MS_PER_SECOND; + + if ( timeSinceAlarmSilenceStart >= ALARM_SILENCE_EXPIRES_IN_SECS ) + { + alarmStatus.alarmsSilenceExpiresIn = 0; + } + else + { + alarmStatus.alarmsSilenceExpiresIn = ALARM_SILENCE_EXPIRES_IN_SECS - timeSinceAlarmSilenceStart; + } + // If alarms silence expires, end it + if ( 0 == alarmStatus.alarmsSilenceExpiresIn ) + { + alarmStatus.alarmsSilenced = FALSE; + } + } +} + +/*********************************************************************//** + * @brief * The updateAlarmsFlags function updates the alarms status flags of the - * alarms status record. + * alarms status record. * @details \b Inputs: alarmStatus, alarmIsActive, ALARM_TABLE[], - * alarmButtonBlockers[]. alarmUserRecoveryActionEnabled[] - * @details \b Outputs: alarmStatus, alarmButtonBlockers[] - * @return none - *************************************************************************/ -static void updateAlarmsFlags( void ) -{ - BOOL systemFault = FALSE; - BOOL stop = FALSE; - BOOL noClear = FALSE; + * alarmButtonBlockers[]. alarmUserRecoveryActionEnabled[] + * @details \b Outputs: alarmStatus, alarmButtonBlockers[] + * @return none + *************************************************************************/ +static void updateAlarmsFlags( void ) +{ + BOOL systemFault = FALSE; + BOOL stop = FALSE; + BOOL noClear = FALSE; BOOL noResume = FALSE; - BOOL noResumePerAlarmPropertyOnly = FALSE; - BOOL noRinseback = FALSE; + BOOL noResumePerAlarmPropertyOnly = FALSE; + BOOL noRinseback = FALSE; BOOL noEndTreatment = FALSE; - BOOL endTxOnlyAlarmActive = FALSE; + BOOL endTxOnlyAlarmActive = FALSE; BOOL usrAckReq = FALSE; BOOL noMinimize = TRUE; TD_OP_MODE_T currentMode = getCurrentOperationMode(); ALARM_T propsTop = getAlarmProperties( alarmStatus.alarmTop ); - ALARM_ID_T a; - + ALARM_ID_T a; + // Set user alarm recovery actions allowed by state flags alarmButtonBlockers[ ALARM_BUTTON_STATE_BLOCK_RESUME ] = ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_RESUME ] ? FALSE : TRUE ); alarmButtonBlockers[ ALARM_BUTTON_STATE_BLOCK_RINSEBACK ] = ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_RINSEBACK ] ? FALSE : TRUE ); @@ -1163,40 +1166,40 @@ alarmButtonBlockers[ ALARM_BUTTON_TABLE_BLOCK_RINSEBACK ] = FALSE; alarmButtonBlockers[ ALARM_BUTTON_TABLE_BLOCK_END_TREATMENT ] = FALSE; - // Determine alarm flags - for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) - { - if ( TRUE == isAlarmActive( a ) ) - { + // Determine alarm flags + for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) + { + if ( TRUE == isAlarmActive( a ) ) + { ALARM_T props = getAlarmProperties( a ); - systemFault = ( TRUE == props.alarmIsFault ? TRUE : systemFault ); - stop = ( TRUE == props.alarmStops ? TRUE : stop ); + systemFault = ( TRUE == props.alarmIsFault ? TRUE : systemFault ); + stop = ( TRUE == props.alarmStops ? TRUE : stop ); noClear = ( TRUE == props.alarmNoClear ? TRUE : noClear ); noResumePerAlarmPropertyOnly = ( props.alarmNoResume ? TRUE : noResumePerAlarmPropertyOnly ); // Set user alarm recovery actions allowed flags alarmButtonBlockers[ ALARM_BUTTON_TABLE_BLOCK_RESUME ] |= props.alarmNoResume; alarmButtonBlockers[ ALARM_BUTTON_TABLE_BLOCK_RINSEBACK ] |= props.alarmNoRinseback; alarmButtonBlockers[ ALARM_BUTTON_TABLE_BLOCK_END_TREATMENT ] |= props.alarmNoEndTreatment; if ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_RESUME ] ) - { + { noResume = ( TRUE == props.alarmNoResume ? TRUE : noResume ); } else { noResume = TRUE; - } + } if ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_RINSEBACK ] ) { noRinseback = ( TRUE == props.alarmNoRinseback ? TRUE : noRinseback ); } else { noRinseback = TRUE; - } + } if ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_END_TREATMENT ] ) { - noEndTreatment = ( TRUE == props.alarmNoEndTreatment ? TRUE : noEndTreatment ); + noEndTreatment = ( TRUE == props.alarmNoEndTreatment ? TRUE : noEndTreatment ); } else { @@ -1208,8 +1211,8 @@ ( FALSE == props.alarmNoEndTreatment ) ) { endTxOnlyAlarmActive = TRUE; - } - } // If alarm active + } + } // If alarm active } // Alarm table loop // If top alarm condition not cleared, block resume @@ -1252,16 +1255,16 @@ noMinimize = FALSE; } - // Set updated alarm flags - alarmStatus.systemFault = systemFault; - alarmStatus.stop = stop; - alarmStatus.noClear = noClear; - alarmStatus.noResume = noResume; - alarmStatus.noRinseback = noRinseback; - alarmStatus.noEndTreatment = noEndTreatment; - alarmStatus.ok = usrAckReq; + // Set updated alarm flags + alarmStatus.systemFault = systemFault; + alarmStatus.stop = stop; + alarmStatus.noClear = noClear; + alarmStatus.noResume = noResume; + alarmStatus.noRinseback = noRinseback; + alarmStatus.noEndTreatment = noEndTreatment; + alarmStatus.ok = usrAckReq; alarmStatus.noMinimize = noMinimize; - resumeBlockedByAlarmProperty = noResumePerAlarmPropertyOnly; + resumeBlockedByAlarmProperty = noResumePerAlarmPropertyOnly; } /*********************************************************************//** @@ -1302,32 +1305,32 @@ } return result; -} - -/*********************************************************************//** - * @brief - * The resetAlarmPriorityFIFO function resets a FIFO for a given alarm +} + +/*********************************************************************//** + * @brief + * The resetAlarmPriorityFIFO function resets a FIFO for a given alarm * priority. - * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given priority is invalid. - * @details \b Inputs: none - * @details \b Outputs: alarmPriorityFIFO[] - * @param priority Alarm priority associated with FIFO to reset - * @return none - *************************************************************************/ -static void resetAlarmPriorityFIFO( ALARM_PRIORITY_T priority ) -{ - // Verify priority - if ( priority < NUM_OF_ALARM_PRIORITIES ) - { + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given priority is invalid. + * @details \b Inputs: none + * @details \b Outputs: alarmPriorityFIFO[] + * @param priority Alarm priority associated with FIFO to reset + * @return none + *************************************************************************/ +static void resetAlarmPriorityFIFO( ALARM_PRIORITY_T priority ) +{ + // Verify priority + if ( priority < NUM_OF_ALARM_PRIORITIES ) + { alarmPriorityFIFO[ priority ].alarmID = ALARM_ID_NO_ALARM; alarmPriorityFIFO[ priority ].subRank = LOWEST_ALARM_SUB_RANK; - alarmPriorityFIFO[ priority ].timeSinceTriggeredMS = -1; - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_FIFO_TO_RESET, priority ) - } -} + alarmPriorityFIFO[ priority ].timeSinceTriggeredMS = -1; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_FIFO_TO_RESET, priority ) + } +} /*********************************************************************//** * @brief @@ -1412,23 +1415,23 @@ return result; } - -/************************************************************************* - * TEST SUPPORT FUNCTIONS - *************************************************************************/ - - -/*********************************************************************//** - * @brief - * The testSetAlarmStartTimeOverride function overrides the start time for a - * given alarm with a given start time. - * @details \b Inputs: msTimerCount - * @details \b Outputs: alarmStartedAt[] + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetAlarmStartTimeOverride function overrides the start time for a + * given alarm with a given start time. + * @details \b Inputs: msTimerCount + * @details \b Outputs: alarmStartedAt[] * @param message Override message from Dialin which includes an ID of * the alarm to override start time for and a number of milliseconds the * override is seeking to make the elapsed time since the given alarm was - * triggered. - * @return TRUE if override is successful, FALSE if not + * triggered. + * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL testSetAlarmStartTimeOverride( MESSAGE_T *message ) { @@ -1467,7 +1470,7 @@ return result; } - + /*********************************************************************//** * @brief * The testClearAllAlarms function clears all active alarms, even if they @@ -1563,4 +1566,56 @@ return result; } +/*********************************************************************//** + * @brief + * The testGetAlarmPropertiesRequest function processes a request + * to retrieve alarm properties and broadcasts the result. + * @details \b Inputs: None + * @details \b Outputs: None + * @param message Pointer to MESSAGE_T containing the alarm ID request + * @return TRUE if alarm properties were successfully broadcasted. + * FALSE if payload length is invalid or alarm ID + * is out of range + *************************************************************************/ +BOOL testGetAlarmPropertiesRequest( MESSAGE_T *message ) +{ + ALARM_ID_T alarmID; + BOOL result = FALSE; + + if ( message->hdr.payloadLen == sizeof( U32 ) ) + { + memcpy( &alarmID, message->payload, sizeof( ALARM_ID_T ) ); + + if ( alarmID < NUM_OF_ALARM_IDS ) + { + ALARM_PROP_T canMsg; + ALARM_T alarm = getAlarmProperties( alarmID ); + + canMsg.alarmPriority = (U08)alarm.alarmPriority; + canMsg.alarmSubRank = (U16)alarm.alarmSubRank; + canMsg.alarmSource = (U08)alarm.alarmSource; + canMsg.alarmIsFault = (U08)alarm.alarmIsFault; + canMsg.alarmIsDDFault = (U08)alarm.alarmIsDDFault; + canMsg.alarmStops = (U08)alarm.alarmStops; + canMsg.alarmConditionClearImmed = (U08)alarm.alarmConditionClearImmed; + canMsg.alarmNoClear = (U08)alarm.alarmNoClear; + canMsg.alarmNoResume = (U08)alarm.alarmNoResume; + canMsg.alarmNoRinseback = (U08)alarm.alarmNoRinseback; + canMsg.alarmNoEndTreatment = (U08)alarm.alarmNoEndTreatment; + canMsg.alarmBlockRinseback = (U08)alarm.alarmBlockRinseback; + canMsg.alarmBlockEndTx = (U08)alarm.alarmBlockEndTx; + canMsg.alarmNoBloodRecirc = (U08)alarm.alarmNoBloodRecirc; + canMsg.alarmNoDialysateRecirc = (U08)alarm.alarmNoDialysateRecirc; + canMsg.alarmAutoResume = (U08)alarm.alarmAutoResume; + canMsg.alarmClearOnly = (U08)alarm.alarmClearOnly; + canMsg.alarmTreatmentLog = (U08)alarm.alarmTreatmentLog; + canMsg.alarmID = (U16)alarm.alarmID; + + result = broadcastData( MSG_ID_TD_ALARM_PROPERTIES_RESPONSE, COMM_BUFFER_OUT_CAN_PC, (U08*)&canMsg, sizeof( ALARM_PROP_T ) ); + } + } + + return result; +} + /**@}*/ Index: firmware/App/Services/DDInterface.c =================================================================== diff -u -r222b05e39082f727dcfa2d144fa6e040501882f0 -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision 222b05e39082f727dcfa2d144fa6e040501882f0) +++ firmware/App/Services/DDInterface.c (.../DDInterface.c) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -7,8 +7,8 @@ * * @file DDInterface.c * -* @author (last) Raghu Kallala -* @date (last) 01-May-2026 +* @author (last) Varshini Nagabooshanam +* @date (last) 15-Jun-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -122,6 +122,7 @@ dialysateDeliveryCmdSet.bicarbConvFactor = 0.0F; dialysateDeliveryCmdSet.sodium = 0; dialysateDeliveryCmdSet.bicarbonate = 0; + dialysateDeliveryCmdSet.substitutionRate = 0.0F; } /**********************************************************************//** @@ -430,6 +431,7 @@ *************************************************************************/ void cmdStartGenerateDialysate( F32 qd, F32 quf, F32 dialTemp, U32 genDialysateState, F32 acidConvFactor, F32 bicarbConvFactor, U32 sodium, U32 bicarbonate ) { + dialysateDeliveryCmdSet.start = TRUE; dialysateDeliveryCmdSet.dialRate = qd; dialysateDeliveryCmdSet.ufRate = quf; @@ -439,6 +441,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 ) ); @@ -652,7 +655,33 @@ // } } +/*********************************************************************//** + * @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? + } +} + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Services/DDInterface.h =================================================================== diff -u -r9c833ef5623ce842267e284d958820ac0dc3a7fc -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision 9c833ef5623ce842267e284d958820ac0dc3a7fc) +++ firmware/App/Services/DDInterface.h (.../DDInterface.h) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -14,23 +14,23 @@ * @date (original) 01-Aug-2024 * ***************************************************************************/ - -#ifndef __DD_INTERFACE_H__ -#define __DD_INTERFACE_H__ - + +#ifndef __DD_INTERFACE_H__ +#define __DD_INTERFACE_H__ + #include "TDCommon.h" #include "TDDefs.h" -#include "DDDefs.h" - -/** - * @defgroup DDInterface DDInterface - * @brief DD interface & monitor unit. Interfaces with and monitors the - * DD (dialysate delivery) sub-system. - * - * @addtogroup DDInterface - * @{ - */ - +#include "DDDefs.h" + +/** + * @defgroup DDInterface DDInterface + * @brief DD interface & monitor unit. Interfaces with and monitors the + * DD (dialysate delivery) sub-system. + * + * @addtogroup DDInterface + * @{ + */ + // ********** public definitions ********** /// DD command response data record structure. @@ -41,33 +41,47 @@ U32 rejectCode; ///< Reason code for rejecting the command } DD_CMD_RESPONSE_T; -// ********** public function prototypes ********** - +/// DD ultrafiltration broadcast data (matches DD UF_DATA_T layout). +typedef struct +{ + U32 ufExecState; ///< Ultrafiltration execution state + F32 ufRate; ///< Ultrafiltration rate from TD + F32 compUFrate; ///< Compensated UF rate + U32 isUFRequested; ///< Ultrafiltration run or pause request + F32 ufVolumeDeliveredMl; ///< UF volume delivered in mL +} DD_UF_DATA_T; + +// ********** public function prototypes ********** + void initDDInterface( void ); void resetDDInterface( void ); void execDDInterfaceMonitor( void ); DD_OP_MODE_T getDDOpMode( void ); -U32 getDDSubMode( void ); +U32 getDDSubMode( void ); F32 getDialysatePressure( void ); BOOL getDialysateGoodToDeliverStatus( void ); +F32 getDDUFVolumeDeliveredLiters( void ); BOOL setDDOpMode( MESSAGE_T *message ); BOOL setDialysateData( MESSAGE_T *message ); +BOOL setUFData( 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 cmdStartGenerateDialysate( F32 qd, F32 quf, F32 dialTemp, U32 genDialysateState, F32 acidConvFactor, F32 bicarbConvFactor, U32 sodium, U32 bicarbonate ); void cmdChangeQd( F32 qd ); void cmdChangeQuf( F32 quf ); +void cmdSetGenDialysateState( U32 genDialysateState ); void cmdBypassDialyzer( BOOL bypass ); void cmdStopGenerateDialysate( void ); void cmdSubstitutionRate (F32 qs ); + void handleDDCommandResponse( DD_CMD_RESPONSE_T *ddCmdRespPtr ); BOOL getDDCommandResponse( U32 commandID, DD_CMD_RESPONSE_T *cmdRespPtr ); -/**@}*/ - -#endif +/**@}*/ + +#endif Index: firmware/App/Services/Messaging.c =================================================================== diff -u -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -7,8 +7,8 @@ * * @file Messaging.c * -* @author (last) Raghu Kallala -* @date (last) 30-Apr-2026 +* @author (last) Vijay Pamula +* @date (last) 14-Jul-2026 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 @@ -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" @@ -40,8 +42,11 @@ #include "StateTxIsolatedUF.h" #include "StateTxPaused.h" #include "Switches.h" +#include "SyringePump.h" #include "SystemCommTD.h" #include "Temperatures.h" +#include "TubeSetAutoEject.h" +#include "TubeSetInstall.h" #include "TxParams.h" #include "Utilities.h" #include "Valve3Way.h" @@ -110,15 +115,31 @@ { 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_TREATMENT_UF_VOLUME_VALIDATE_REQUEST, &validateAndSetUFVolume }, + { MSG_ID_UI_ULTRAFILTRATION_CHANGE_CONFIRM_REQUEST, &signalUserConfirmationOfUFVolume }, + { MSG_ID_UI_DURATION_VALIDATE_REQUEST, &validateAndSetTreatmentDuration }, + { MSG_ID_UI_DURATION_CONFIRM_REQUEST, &signalUserConfirmationOfTreatmentDuration }, + { MSG_ID_UI_VITALS_ADJUSTMENT_REQUEST, &vitalsAdjustmentHandleChangeRequest }, + { MSG_ID_UI_BOLUS_VOLUME_CHANGE_REQUEST, &validateAndSetBolusVolume }, { MSG_ID_UI_INITIATE_TREATMENT_WORKFLOW, &signalUserInitiateTreatment }, { MSG_ID_UI_UF_PAUSE_RESUME_REQUEST, &handleUFPauseResumeRequest }, { MSG_ID_TESTER_LOGIN_REQUEST, &handleTesterLogInRequest }, { MSG_ID_UI_PRESSURE_LIMIT_WIDEN_REQUEST, &pressureLimitHandleWidenRequest }, + { MSG_ID_UI_PRESSURE_LIMITS_CHANGE_REQUEST, &pressureLimitHandleChangeRequest }, + { MSG_ID_UI_TREATMENT_SET_POINTS_CHANGE_REQUEST, &validateAndSetTreatmentSetPoints }, + { MSG_ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_REQUEST, &validateAndSetBloodFlowRate }, + { MSG_ID_UI_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_REQUEST, &validateAndSetDialysateFlowRate }, + { MSG_ID_UI_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_REQUEST, &validateAndSetDialysateTemperature }, { MSG_ID_UI_BLOOD_PRIME_CMD_REQUEST, &bloodPrimeHandleCmdRequest }, { MSG_ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_REQUEST, &bloodPrimeHandleBloodFlowChangeRequest }, { MSG_ID_UI_ISOLATED_UF_DURATION_CHANGE_REQUEST, &handleIsolatedUFDurationChangeRequest }, { MSG_ID_UI_ISOLATED_UF_VOLUME_GOAL_CHANGE_REQUEST, &handleIsolatedUFVolumeGoalChangeRequest }, { MSG_ID_UI_ISOLATED_UF_CONFIRM_REQUEST, &handleIsolatedUFConfirmRequest }, + { MSG_ID_UI_ADJUST_DISPOSABLES_CONFIRM_REQUEST, &handleAutoLoadRequest }, + { MSG_ID_UI_SETUP_TUBING_SET_CONNECTIONS_CONFIRM_REQUEST, &handleSetupTubingSetConnectionConfirmRequest }, + { MSG_ID_UI_ADJUST_DISPOSABLES_REMOVAL_CONFIRM_REQUEST, &handleAutoEjectRequest }, + { MSG_ID_FFU_SIGNAL_TD_UPDATE_AVAILABLE, &handleUpdateAvailable }, + { MSG_ID_UI_FLUID_BOLUS_REQUEST, &handleFluidBolusRequest }, { MSG_ID_TD_SOFTWARE_RESET_REQUEST, &testTDSoftwareResetRequest }, { MSG_ID_TD_BUBBLE_OVERRIDE_REQUEST, &testBubbleDetectOverride }, { MSG_ID_TD_BUBBLE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testBubblesDataPublishIntervalOverride }, @@ -188,8 +209,23 @@ { MSG_ID_TD_BLOOD_PRIME_VOLUME_OVERRIDE, &testBloodPrimeVolumeOverride }, { MSG_ID_TD_BLOOD_PRIME_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testBloodPrimePublishIntervalOverride }, { MSG_ID_TD_ENABLE_VENOUS_BUBBLE_ALARM, &testEnableVenousBubbleAlarm }, + { MSG_ID_TD_SYRINGE_PUMP_OPERATION_REQUEST, &testSyringePumpOperationRequest }, + { MSG_ID_HD_SYRINGE_PUMP_PUBLISH_INTERVAL_OVERRIDE, &testSyringePumpDataPublishIntervalOverride }, + { MSG_ID_TD_SYRINGE_PUMP_RATE_OVERRIDE_REQUEST, &testSyringePumpMeasuredRateOverride }, + { MSG_ID_TD_SYRINGE_PUMP_FORCE_OVERRIDE_REQUEST, &testSyringePumpMeasuredForceOverride }, + { MSG_ID_TD_SYRINGE_PUMP_HOME_OVERRIDE_REQUEST, &testSyringePumpMeasuredHomeOverride }, + { MSG_ID_TD_SYRINGE_PUMP_POSITION_OVERRIDE_REQUEST, &testSyringePumpMeasuredPositionOverride }, + { MSG_ID_TD_SYRINGE_PUMP_VOLUME_OVERRIDE_REQUEST, &testSyringePumpMeasuredVolumeOverride }, + { MSG_ID_TD_SYRINGE_PUMP_STATUS_OVERRIDE_REQUEST, &testSyringePumpStatusOverride }, + { MSG_ID_TD_SYRINGE_PUMP_ENCODER_STATUS_OVERRIDE_REQUEST, &testSyringePumpEncoderStatusOverride }, + { MSG_ID_TD_SYRINGE_PUMP_ADC_DAC_STATUS_OVERRIDE_REQUEST, &testSyringePumpADCandDACStatusOverride }, + { MSG_ID_TD_SYRINGE_PUMP_ADC_READ_COUNTER_OVERRIDE_REQUEST, &testSyringePumpADCReadCounterOverride }, + { MSG_ID_TD_HEPARIN_BOLUS_TARGET_RATE_OVERRIDE_REQUEST, &testHeparinBolusTargetRateOverride }, + { MSG_ID_TD_SYRINGE_PUMP_FORCE_SENSOR_CALIBRATION_REQUEST, &testCalibrateForceSensor }, + { MSG_ID_TD_GET_ALARM_PROPERTIES_REQUEST, &testGetAlarmPropertiesRequest }, }; +/// Number of entries in the message handling function lookup table. #define NUM_OF_FUNCTION_HANDLERS (sizeof(MSG_FUNCTION_HANDLER_LOOKUP) / sizeof(MSG_HANDLER_LOOKUP_T)) // ********** private data ********** @@ -601,6 +637,18 @@ /*********************************************************************//** * @brief + * The resetMicroControllerUnit function resets the MCU. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +void resetMicroControllerUnit( void ) +{ + setSystemREG1_SYSECR( (0x2) << 14 ); // Reset processor +} + +/*********************************************************************//** + * @brief * The sendTestAckResponseMsg function constructs a simple response message * for a handled test message and queues it for transmit on the TD=>PC CAN * channel. @@ -669,6 +717,32 @@ /*********************************************************************//** * @brief + * The handleUpdateAvailable function handles a request from the + * Firmware FPGA Updater (FFU) to reset the TD firmware processor. + * @note If reset is successful, this function will not return. + * @details \b Inputs: none + * @details \b Outputs: TD processor soft reset if request is valid + * @param message Pointer to the reset request message + * @return FALSE if reset command rejected + *************************************************************************/ +BOOL handleUpdateAvailable( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify payload length + if ( 0 == message->hdr.payloadLen ) + { // S/w reset of processor + result = TRUE; // Reset will prevent this from getting transmitted though + requestNewOperationMode( MODE_UPDT ); + } + + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_TD_2_UI, result ); + + return result; +} + +/*********************************************************************//** + * @brief * The testTDSoftwareResetRequest function handles a request to reset the * TD firmware processor. * @note If reset is successful, this function will not return. @@ -685,7 +759,7 @@ if ( 0 == message->hdr.payloadLen ) { // S/w reset of processor result = TRUE; // Reset will prevent this from getting transmitted though - setSystemREG1_SYSECR( (0x2) << 14 ); // Reset processor + resetMicroControllerUnit(); } sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); Index: firmware/App/Services/TxParams.c =================================================================== diff -u -r96604b790636c66ef21980a4f13ee9f987f12fee -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Services/TxParams.c (.../TxParams.c) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) +++ firmware/App/Services/TxParams.c (.../TxParams.c) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -7,19 +7,21 @@ * * @file TxParams.c * -* @author (last) Raghu Kallala -* @date (last) 01-May-2026 +* @author (last) Vijay Pamula +* @date (last) 07-Jul-2026 * * @author (original) Varshini Nagabooshanam * @date (original) 02-Dec-2025 * ***************************************************************************/ +#include // Used for fabs() and roundf() functions for floating-point comparisons and rounding. #include "AirPump.h" #include "AirTrap.h" #include "BloodFlow.h" #include "Buttons.h" #include "Messaging.h" +#include "ModeStandby.h" #include "ModeTreatment.h" #include "ModePreTreat.h" #include "OperationModes.h" @@ -105,6 +107,7 @@ // ********** private data ********** +/// Treatment parameter properties including data type, range limits and default values. static const TREATMENT_PARAMS_PROPERTIES_T TREAT_PARAMS_PROPERTIES[ NUM_OF_TREATMENT_PARAMS ] = { // type min max default { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=2}, {.uInt=0} }, // TREATMENT_PARAM_TREATMENT_MODALITY @@ -133,13 +136,14 @@ { CRITICAL_DATA_TYPE_F32, {.sFlt=0.0}, {.sFlt=8.0}, {.sFlt=0.0} }, // TREATMENT_PARAM_UF_VOLUME }; +/// System configuration treatment parameter properties including data type, range limits and default values. static const TREATMENT_PARAMS_PROPERTIES_T SYS_CONFIG_TREAT_PARAMS_PROPERTIES[ NUM_OF_SYS_CONFIG_TREATMENT_PARAMS ] = { // type min max default - { CRITICAL_DATA_TYPE_U32, {.uInt=120}, {.uInt=200}, {.uInt=120} }, // TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW - { CRITICAL_DATA_TYPE_U32, {.uInt=100}, {.uInt=200}, {.uInt=100} }, // TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW - { CRITICAL_DATA_TYPE_U32, {.uInt=20}, {.uInt=35}, {.uInt=20} }, // TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC - { CRITICAL_DATA_TYPE_U32, {.uInt=40}, {.uInt=100}, {.uInt=40} }, // TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW + { CRITICAL_DATA_TYPE_U32, {.uInt=50}, {.uInt=100}, {.uInt=50} }, // TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW + { CRITICAL_DATA_TYPE_U32, {.uInt=50}, {.uInt=100}, {.uInt=50} }, // TREATMENT_PARAM_VEN_PRES_HIGH_LIMIT_WINDOW + { CRITICAL_DATA_TYPE_U32, {.uInt=20}, {.uInt=35}, {.uInt=35} }, // TREATMENT_PARAM_VEN_PRES_LOW_LIMIT_WINDOW + { CRITICAL_DATA_TYPE_U32, {.uInt=20}, {.uInt=50}, {.uInt=20} }, // TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW { CRITICAL_DATA_TYPE_U32, {.uInt=100}, {.uInt=500}, {.uInt=200} }, // TREATMENT_PARAM_RINSEBACK_FLOW_RATE { CRITICAL_DATA_TYPE_U32, {.uInt=300}, {.uInt=1000}, {.uInt=300} }, // TREATMENT_PARAM_PRIME_DISCARD_VOLUME { CRITICAL_DATA_TYPE_U32, {.uInt=70}, {.uInt=140}, {.uInt=90} }, // TREATMENT_PARAM_SYSTOLIC_BP_LOW_ALARM_LIMIT @@ -184,6 +188,12 @@ static BOOL isolatedUFSettingsPending = FALSE; ///< Flag indicates isolated UF settings are staged for confirmation. static U32 isolatedUFDurationPendingMin = 0; ///< Staged isolated UF duration in minutes. static F32 isolatedUFVolumePendingMl = 0.0F; ///< Staged isolated UF volume goal in mL. +static BOOL validTreatmentDurationReceived; ///< Flag indicates valid treatment duration was validated. +static U32 validatedTreatmentDuration_min; ///< Last validated treatment duration in minutes. +static U32 validatedHeparinDeliveryDuration_min; ///< Last validated Heparin delivery duration in minutes. +static F32 validatedUFVolumeGoalL; ///< Last validated UF volume goal in L. +static F32 validatedUFRateLhr; ///< Last validated UF rate in L/hr. +static BOOL validUFVolumeReceived; ///< Flag indicates valid UF volume was validated. // ********** private function prototypes ********** @@ -201,6 +211,14 @@ 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 BOOL isPressureLimitValueValid( U32 value, U32 minValue, U32 maxValue ); +static BOOL isArterialPressureLimitWindowValid( U32 value ); +static BOOL isVenousPressureLimitWindowValid( U32 value ); +static BOOL isVenousAsymmetricPressureLimitWindowValid( U32 value ); +static BOOL isTmpPressureLimitWindowValid( U32 value ); +static BOOL isVitalsAlarmLimitValueValid(U32 value, SYS_CONFIG_TREATMENT_PARAM_T param ); +static BOOL isVitalsMeasurementIntervalValid( U32 value, TREATMENT_PARAM_T param ); + //static void getInstitutionalRecordEdgeValue( TREATMENT_PARAM_T param, CRITICAL_DATAS_T* value, BOOL isMin ); /*********************************************************************//** @@ -417,7 +435,7 @@ U32 result = 1; // Validate parameter - if ( param <= NUM_OF_SYS_CONFIG_TREATMENT_PARAMS ) + if ( param < NUM_OF_SYS_CONFIG_TREATMENT_PARAMS ) { CRITICAL_DATAS_T data = getCriticalData( &sysConfigTreatmentParameters[ param ] ); @@ -447,6 +465,36 @@ /*********************************************************************//** * @brief + * The setSysConfigTreatmentParameterU32 function sets a given unsigned + * integer system configured treatment parameter. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid parameter ID is given. + * @details \b Inputs: none. + * @details \b Outputs: sysConfigTreatmentParameters[]. + * @param param ID of system configured treatment parameter to set. + * @param value unsigned integer value to set. + * @return TRUE if parameter updated successfully, FALSE otherwise. + *************************************************************************/ +BOOL setSysConfigTreatmentParameterU32( SYS_CONFIG_TREATMENT_PARAM_T param, U32 value ) +{ + BOOL result = FALSE; + + if ( param < NUM_OF_SYS_CONFIG_TREATMENT_PARAMS ) + { + CRITICAL_DATAS_T data = getCriticalData( &sysConfigTreatmentParameters[ param ] ); + + data.uInt = value; + result = setCriticalData( &sysConfigTreatmentParameters[ param ], data ); + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_SET_U32_PARAM, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief * The validateAndSetTreatmentParameters function validates received * treatment parameters. * @details \b Message \b Sent: MSG_ID_TD_RESP_TREATMENT_PARAMS_TO_VALIDATE @@ -485,7 +533,6 @@ // Extract treatment parameters from given payload to staging array so we can more easily work with them extractTreatmentParamsFromPayload( params ); - // Range check each treatment parameter paramsAreInRange = checkTreatmentParamsInRange( &rejReasons[0] ); @@ -554,11 +601,11 @@ switch ( txType ) { - case TREATMENT_MODALITY_HDF: + case TREATMENT_MODALITY_HDF_ONLINE_FLUID: result = FALSE; break; - case TREATMENT_MODALITY_HD: + case TREATMENT_MODALITY_HD_SALINE_FLUID: result = ( ( ( param == TREATMENT_PARAM_HDF_DILUTION ) || ( param == TREATMENT_PARAM_SUBST_FLUID_VOLUME ) ) ? TRUE : FALSE ); break; @@ -714,6 +761,7 @@ F32 hepDR = stagedParams[ TREATMENT_PARAM_HEPARIN_DELIVERY_RATE ].sFlt; F32 hepBV = stagedParams[ TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ].sFlt; F32 txVol = hepBV + ( hepDR * ( hepST / (F32)SEC_PER_MIN ) ) + SYRINGE_PUMP_PRIME_VOLUME_ML + SYRINGE_PUMP_FILL_VOLUME_OFFSET_ML; + TREATMENT_TYPE_T modality = (TREATMENT_TYPE_T)stagedParams[ TREATMENT_PARAM_TREATMENT_MODALITY ].uInt; // Variable to validate acid conversion factor consistency U32 acidType = stagedParams[ TREATMENT_PARAM_ACID_CONCENTRATE ].uInt; @@ -744,6 +792,13 @@ result = FALSE; } + // Verify Rx entered modality with the treatment initiation modality + if ( modality != getModality() ) + { + reasons[ TREATMENT_PARAM_TREATMENT_MODALITY ] = REQUEST_REJECT_REASON_MODALITY_MISMATCH; + result = FALSE; + } + return result; } @@ -841,6 +896,7 @@ /*********************************************************************//** * @brief +<<<<<<< HEAD * The calculateIsolatedUFRateMlMin function calculates isolated UF rate. * @details \b Inputs: durationMin, volumeGoalMl * @details \b Outputs: none @@ -1145,17 +1201,26 @@ /*********************************************************************//** * @brief - * The resetTreatmentParameters function resets the Treatment Parameters + * The initTreatmentParameters function initializes the Treatment Parameters * session flags and parameter values. - * @details Inputs: none - * @details Outputs: validTreatParamsReceived, treatParamsConfirmed, - * treatParamsRejected cleared and parameters reset. + * @details \b Inputs: none. + * @details \b Outputs: validTreatParamsReceived, treatParamsConfirmed, + * validTreatmentDurationReceived, validatedTreatmentDuration_min, + * validatedUFVolumeGoalL, validatedUFRateLhr, + * validUFVolumeReceived, validatedHeparinDeliveryDuration_min, + * treatment parameters reset. * @return none *************************************************************************/ -void resetTreatmentParameters( void ) +void initTreatmentParameters( void ) { - validTreatParamsReceived = FALSE; - treatParamsConfirmed = FALSE; + validTreatParamsReceived = FALSE; + treatParamsConfirmed = FALSE; + validTreatmentDurationReceived = FALSE; + validatedTreatmentDuration_min = 0U; + validatedUFVolumeGoalL = 0.0F; + validatedUFRateLhr = 0.0F; + validUFVolumeReceived = FALSE; + validatedHeparinDeliveryDuration_min = 0U; resetAllTreatmentParameters(); } @@ -1281,18 +1346,30 @@ * The isTreatmentParamInRange function determines whether a given treatment * parameter is in range. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given param is invalid - * @details \b Inputs: treatParamsRanges[], hdInstitutionalRecord - * @details \b Outputs: none + * @details \b Inputs: TREAT_PARAMS_PROPERTIES[]. + * @details \b Outputs: none. * @param param ID of parameter to check range for * @param value value of parameter to check range for * @return TRUE if given treatment parameter is in range, FALSE if not *************************************************************************/ BOOL isTreatmentParamInRange( TREATMENT_PARAM_T param, CRITICAL_DATAS_T value ) { - BOOL result = TRUE; // TODO FALSE; + BOOL result = FALSE; if ( param < NUM_OF_TREATMENT_PARAMS ) { + if ( CRITICAL_DATA_TYPE_U32 == TREAT_PARAMS_PROPERTIES[ param ].dataType ) + { + result = ( ( value.uInt >= TREAT_PARAMS_PROPERTIES[ param ].min.uInt ) && + ( value.uInt <= TREAT_PARAMS_PROPERTIES[ param ].max.uInt ) ? TRUE : FALSE ); + } + else + { + result = ( ( value.sFlt >= TREAT_PARAMS_PROPERTIES[ param ].min.sFlt ) && + ( value.sFlt <= TREAT_PARAMS_PROPERTIES[ param ].max.sFlt ) ? TRUE : FALSE ); + } + } + // switch( param ) // { // case TREATMENT_PARAM_TREATMENT_MODALITY: @@ -1422,7 +1499,7 @@ // } //#endif // } - } + else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_PARAM, (U32)param ) @@ -1731,6 +1808,981 @@ /************************************************************************* + * In-treatment treatment parameter edit function + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The validateAndSetTreatmentDuration function handles the UI treatment + * duration validation request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_DURATION_VALIDATE_RESPONSE including acceptance status, + * rejection reason, requested duration, UF volume goal (L), + * calculated UF rate (L/hr) and heparin delivery duration (minutes). + * @details \b Inputs: none. + * @details \b Outputs: validTreatmentDurationReceived, validatedTreatmentDuration_min, + * validatedUFRateLhr, validatedHeparinDeliveryDuration_min. + * @param message set message from UI which includes the requested treatment duration in minutes. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL validateAndSetTreatmentDuration( MESSAGE_T *message ) +{ + BOOL result = FALSE; + TREATMENT_DURATION_VALIDATE_REQUEST_PAYLOAD_T request; + TREATMENT_DURATION_VALIDATE_RESPONSE_PAYLOAD_T response; + + F32 presUFVolumeMl = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ) * (F32)ML_PER_LITER; + F32 elapsedTreatmentTimeMin = (F32)getActualTreatmentTimeSecs() / (F32)SEC_PER_MIN; + F32 measuredUFVolumeMl = getUltrafiltrationVolumeDrawn() * (F32)ML_PER_LITER; + F32 remainingUFVolumeMl = presUFVolumeMl - measuredUFVolumeMl; + + U32 minDuration = getU32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ); + U32 maxDuration = getU32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ); + + U32 currentTreatmentDuration_min = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + U32 currentHeparinDuration_min = getTreatmentParameterU32( TREATMENT_PARAM_HEPARIN_DELIVERY_DURATION ); + U32 treatmentHeparinDiff_min = 0U; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.duration = 0U; + response.ufVolumeGoal = 0.0F; + response.ufRate = 0.0F; + response.heparinDuration = 0U; + + // Clear previously validated values. + validTreatmentDurationReceived = FALSE; + validatedTreatmentDuration_min = 0U; + validatedUFRateLhr = 0.0F; + validatedHeparinDeliveryDuration_min = 0U; + + if ( message->hdr.payloadLen == sizeof( TREATMENT_DURATION_VALIDATE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( TREATMENT_DURATION_VALIDATE_REQUEST_PAYLOAD_T ) ); + + response.duration = request.duration; + + if ( ( request.duration >= minDuration ) && ( request.duration <= maxDuration ) ) + { + if ( (F32)request.duration > elapsedTreatmentTimeMin ) + { + if ( remainingUFVolumeMl < 0.0F ) + { + remainingUFVolumeMl = 0.0F; + } + + F32 remainingTreatmentTimeMin = (F32)request.duration - elapsedTreatmentTimeMin; + + // Calculate new UF rate (mL/min). + F32 newUfRateMlMin = remainingUFVolumeMl / remainingTreatmentTimeMin; + + // Convert UF values for UI response. + response.ufVolumeGoal = presUFVolumeMl / (F32)ML_PER_LITER; + response.ufRate = ( newUfRateMlMin * (F32)MIN_PER_HOUR ) / (F32)ML_PER_LITER; + + if ( newUfRateMlMin <= MAX_UF_RATE_ML_MIN ) + { + // Adjust Heparin delivery duration to maintain the previous difference from treatment duration. + if ( currentTreatmentDuration_min > currentHeparinDuration_min ) + { + treatmentHeparinDiff_min = currentTreatmentDuration_min - currentHeparinDuration_min; + } + + if ( response.duration > treatmentHeparinDiff_min ) + { + validatedHeparinDeliveryDuration_min = response.duration - treatmentHeparinDiff_min; + } + else + { + validatedHeparinDeliveryDuration_min = 0U; + } + + response.heparinDuration = validatedHeparinDeliveryDuration_min; + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // Store validated values for confirmation step. + validTreatmentDurationReceived = TRUE; + validatedTreatmentDuration_min = response.duration; + validatedUFRateLhr = response.ufRate; + validatedHeparinDeliveryDuration_min = response.heparinDuration; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; + } + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; + } + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; + } + } + + result = sendMessage( MSG_ID_TD_DURATION_VALIDATE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( TREATMENT_DURATION_VALIDATE_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The validateAndSetBolusVolume function handles the UI fluid bolus volume + * change request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_BOLUS_VOLUME_CHANGE_RESPONSE including acceptance status + * and rejection reason. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param message set message from UI which includes the requested bolus volume. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL validateAndSetBolusVolume( MESSAGE_T *message ) +{ + BOOL result = FALSE; + BOLUS_VOLUME_CHANGE_REQUEST_PAYLOAD_T request; + UI_RESPONSE_PAYLOAD_T response; + U32 minBolusVolume_mL = getU32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); + U32 maxBolusVolume_mL = getU32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_FLUID_BOLUS_VOLUME ); + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( message->hdr.payloadLen == sizeof( BOLUS_VOLUME_CHANGE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( BOLUS_VOLUME_CHANGE_REQUEST_PAYLOAD_T ) ); + + if ( ( request.bolusVolume >= minBolusVolume_mL ) && + ( request.bolusVolume <= maxBolusVolume_mL ) ) + { + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + setTreatmentParameterU32( TREATMENT_PARAM_FLUID_BOLUS_VOLUME, request.bolusVolume ); + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + } + + result = sendMessage( MSG_ID_TD_BOLUS_VOLUME_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The vitalsAdjustmentHandleChangeRequest function handles the UI vitals + * settings change request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_VITALS_ADJUSTMENT_RESPONSE + * including acceptance status and per-parameter rejection reasons. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param message set message from UI which includes the requested vitals + * alarm limits and measurement interval. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL vitalsAdjustmentHandleChangeRequest( MESSAGE_T *message ) +{ + BOOL result = FALSE; + BOOL accepted = FALSE; + VITALS_ADJUSTMENT_REQUEST_PAYLOAD_T request; + VITALS_ADJUSTMENT_RESPONSE_PAYLOAD_T response; + + if ( message->hdr.payloadLen == sizeof( VITALS_ADJUSTMENT_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( VITALS_ADJUSTMENT_REQUEST_PAYLOAD_T ) ); + + response.systolicBpLowAlarmLimitRejectionReason = REQUEST_REJECT_REASON_NONE; + response.systolicBpHighAlarmLimitRejectionReason = REQUEST_REJECT_REASON_NONE; + response.heartRateLowAlarmLimitRejectionReason = REQUEST_REJECT_REASON_NONE; + response.heartRateHighAlarmLimitRejectionReason = REQUEST_REJECT_REASON_NONE; + response.vitalsMeasurementIntervalRejectionReason = REQUEST_REJECT_REASON_NONE; + + if ( FALSE == isVitalsAlarmLimitValueValid( request.systolicBpLowAlarmLimit, + TREATMENT_PARAM_SYSTOLIC_BP_LOW_ALARM_LIMIT ) ) + { + response.systolicBpLowAlarmLimitRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + if ( FALSE == isVitalsAlarmLimitValueValid( request.systolicBpHighAlarmLimit, + TREATMENT_PARAM_SYSTOLIC_BP_HIGH_ALARM_LIMIT ) ) + { + response.systolicBpHighAlarmLimitRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + if ( FALSE == isVitalsAlarmLimitValueValid( request.heartRateLowAlarmLimit, + TREATMENT_PARAM_HEART_RATE_LOW_ALARM_LIMIT ) ) + { + response.heartRateLowAlarmLimitRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + if ( FALSE == isVitalsAlarmLimitValueValid( request.heartRateHighAlarmLimit, + TREATMENT_PARAM_HEART_RATE_HIGH_ALARM_LIMIT ) ) + { + response.heartRateHighAlarmLimitRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + if ( FALSE == isVitalsMeasurementIntervalValid( request.vitalsMeasurementInterval_min, + TREATMENT_PARAM_BP_MEAS_INTERVAL ) ) + { + response.vitalsMeasurementIntervalRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + accepted = ( REQUEST_REJECT_REASON_NONE == response.systolicBpLowAlarmLimitRejectionReason ) && + ( REQUEST_REJECT_REASON_NONE == response.systolicBpHighAlarmLimitRejectionReason ) && + ( REQUEST_REJECT_REASON_NONE == response.heartRateLowAlarmLimitRejectionReason ) && + ( REQUEST_REJECT_REASON_NONE == response.heartRateHighAlarmLimitRejectionReason ) && + ( REQUEST_REJECT_REASON_NONE == response.vitalsMeasurementIntervalRejectionReason ); + + if ( TRUE == accepted ) + { + setSysConfigTreatmentParameterU32( TREATMENT_PARAM_SYSTOLIC_BP_LOW_ALARM_LIMIT, request.systolicBpLowAlarmLimit ); + setSysConfigTreatmentParameterU32( TREATMENT_PARAM_SYSTOLIC_BP_HIGH_ALARM_LIMIT, request.systolicBpHighAlarmLimit ); + setSysConfigTreatmentParameterU32( TREATMENT_PARAM_HEART_RATE_LOW_ALARM_LIMIT, request.heartRateLowAlarmLimit ); + setSysConfigTreatmentParameterU32( TREATMENT_PARAM_HEART_RATE_HIGH_ALARM_LIMIT, request.heartRateHighAlarmLimit ); + setTreatmentParameterU32( TREATMENT_PARAM_BP_MEAS_INTERVAL, request.vitalsMeasurementInterval_min ); + } + } + else + { + response.systolicBpLowAlarmLimitRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.systolicBpHighAlarmLimitRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.heartRateLowAlarmLimitRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.heartRateHighAlarmLimitRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.vitalsMeasurementIntervalRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } + + response.accepted = accepted; + + result = sendMessage( MSG_ID_TD_VITALS_ADJUSTMENT_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( VITALS_ADJUSTMENT_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The isVitalsAlarmLimitValueValid function validates a vitals alarm + * limit value against the configured range for the specified parameter. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param value vitals alarm limit value to validate. + * @param param vitals alarm limit treatment parameter. + * @return TRUE if value is valid, FALSE otherwise. + *************************************************************************/ +static BOOL isVitalsAlarmLimitValueValid( U32 value, SYS_CONFIG_TREATMENT_PARAM_T param ) +{ + BOOL limitValid; + + limitValid = ( ( value >= getU32SysConfigTreatmentParamLowerRangeLimit( param ) ) && + ( value <= getU32SysConfigTreatmentParamUpperRangeLimit( param ) ) ) ? TRUE : FALSE; + + return limitValid; +} + +/*********************************************************************//** + * @brief + * The isVitalsMeasurementIntervalValid function validates the vitals + * measurement interval value against the configured range. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param value vitals measurement interval value (minutes). + * @param param treatment parameter associated with the interval. + * @return TRUE if value is valid, FALSE otherwise. + *************************************************************************/ +static BOOL isVitalsMeasurementIntervalValid( U32 value, TREATMENT_PARAM_T param ) +{ + BOOL intervalValid; + + intervalValid = ( ( value >= getU32TreatmentParamLowerRangeLimit( param ) ) && + ( value <= getU32TreatmentParamUpperRangeLimit( param ) ) ) ? TRUE : FALSE; + + return intervalValid; +} + +/*********************************************************************//** + * @brief + * The pressureLimitHandleChangeRequest function handles the UI pressure + * limit change request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_PRESSURE_LIMITS_CHANGE_RESPONSE including acceptance status + * and per-parameter rejection reasons. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param message set message from UI which includes the requested pressure limit windows. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL pressureLimitHandleChangeRequest( MESSAGE_T *message ) +{ + BOOL result = FALSE; + BOOL accepted = FALSE; + + PRESSURE_LIMIT_CHANGE_REQUEST_T request; + PRESSURE_LIMITS_CHANGE_RESPONSE_PAYLOAD_T response; + + memset( &request, 0, sizeof( request ) ); + memset( &response, 0, sizeof( response ) ); + + response.arterialPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.venousPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.venousAsymmetricPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.tmpPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( message->hdr.payloadLen == sizeof( PRESSURE_LIMIT_CHANGE_REQUEST_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( PRESSURE_LIMIT_CHANGE_REQUEST_T ) ); + + response.arterialPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_NONE; + response.venousPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_NONE; + response.venousAsymmetricPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_NONE; + response.tmpPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_NONE; + + if ( FALSE == isArterialPressureLimitWindowValid( request.arterialPressureLimitWindowMMHG ) ) + { + response.arterialPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + if ( FALSE == isVenousPressureLimitWindowValid( request.venousHighPressureLimitWindowMMHG ) ) + { + response.venousPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + if ( FALSE == isVenousAsymmetricPressureLimitWindowValid( request.venousLowPressureLimitWindowMMHG ) ) + { + response.venousAsymmetricPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + if ( FALSE == isTmpPressureLimitWindowValid( request.tmpPressureLimitWindowMMHG ) ) + { + response.tmpPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + // Accept request only when all pressure limit values are valid. + accepted = ( REQUEST_REJECT_REASON_NONE == response.arterialPressureLimitWindowRejectionReason ) && + ( REQUEST_REJECT_REASON_NONE == response.venousPressureLimitWindowRejectionReason ) && + ( REQUEST_REJECT_REASON_NONE == response.venousAsymmetricPressureLimitWindowRejectionReason ) && + ( REQUEST_REJECT_REASON_NONE == response.tmpPressureLimitWindowRejectionReason ); + + if ( TRUE == accepted ) + { + setSysConfigTreatmentParameterU32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW, request.arterialPressureLimitWindowMMHG ); + + setSysConfigTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_HIGH_LIMIT_WINDOW, request.venousHighPressureLimitWindowMMHG ); + + setSysConfigTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_LOW_LIMIT_WINDOW, request.venousLowPressureLimitWindowMMHG ); + + setSysConfigTreatmentParameterU32( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW, request.tmpPressureLimitWindowMMHG ); + + updatePressureLimitWindows(); + } + } + + response.accepted = accepted; + + result = sendMessage( MSG_ID_TD_PRESSURE_LIMITS_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( PRESSURE_LIMITS_CHANGE_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The isPressureLimitValueValid function checks whether a pressure limit + * value is within the specified range. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param value pressure limit value to validate. + * @param minValue minimum allowable pressure limit value. + * @param maxValue maximum allowable pressure limit value. + * @return TRUE if value is valid, FALSE otherwise. + *************************************************************************/ +static BOOL isPressureLimitValueValid( U32 value, U32 minValue, U32 maxValue ) +{ + return ( ( value >= minValue ) && ( value <= maxValue ) ); +} + +/*********************************************************************//** + * @brief + * The isArterialPressureLimitWindowValid function validates the arterial + * pressure limit window value. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param value arterial pressure limit window value (mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isArterialPressureLimitWindowValid( U32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( + value, + getU32SysConfigTreatmentParamLowerRangeLimit( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ), + getU32SysConfigTreatmentParamUpperRangeLimit( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief + * The isVenousPressureLimitWindowValid function validates the venous + * pressure limit window value. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param value venous pressure limit window value (mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isVenousPressureLimitWindowValid( U32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( + value, + getU32SysConfigTreatmentParamLowerRangeLimit( TREATMENT_PARAM_VEN_PRES_HIGH_LIMIT_WINDOW ), + getU32SysConfigTreatmentParamUpperRangeLimit( TREATMENT_PARAM_VEN_PRES_LOW_LIMIT_WINDOW ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief + * The isVenousAsymmetricPressureLimitWindowValid function validates the + * venous asymmetric pressure limit window value. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param value venous asymmetric pressure limit window value (mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isVenousAsymmetricPressureLimitWindowValid( U32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( + value, + getU32SysConfigTreatmentParamLowerRangeLimit( TREATMENT_PARAM_VEN_PRES_HIGH_LIMIT_WINDOW ), + getU32SysConfigTreatmentParamUpperRangeLimit( TREATMENT_PARAM_VEN_PRES_LOW_LIMIT_WINDOW ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief + * The isTmpPressureLimitWindowValid function validates the TMP pressure + * limit window value. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param value TMP pressure limit window value (mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isTmpPressureLimitWindowValid( U32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( + value, + getU32SysConfigTreatmentParamLowerRangeLimit( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ), + getU32SysConfigTreatmentParamUpperRangeLimit( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief + * The validateAndSetUFVolume function handles the UI ultrafiltration + * volume validation request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_TREATMENT_UF_VOLUME_VALIDATE_RESPONSE including acceptance status, + * rejection reason, UF volume goal (L), and UF rate (L/hr). + * @details \b Inputs: none. + * @details \b Outputs: validUFVolumeReceived, validatedUFVolumeGoalL, validatedUFRateLhr. + * @param message set message from UI which includes the requested UF volume in L. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL validateAndSetUFVolume( MESSAGE_T *message ) +{ + BOOL result = FALSE; + UF_VOLUME_VALIDATE_REQUEST_PAYLOAD_T request; + UF_VOLUME_RESPONSE_PAYLOAD_T response; + + F32 elapsedTreatmentTimeMin = (F32)getActualTreatmentTimeSecs() / (F32)SEC_PER_MIN; + F32 measuredUFVolumeMl = getUltrafiltrationVolumeDrawn() * (F32)ML_PER_LITER; + F32 treatmentDurationMin = (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + F32 requestedUFVolumeMl = 0.0F; + F32 requestedUFVolumeL = 0.0F; + F32 remainingUFVolumeMl = 0.0F; + F32 remainingTreatmentTimeMin = 0.0F; + F32 newUfRateMlMin = 0.0F; + F32 minUFVolumeL = getF32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_UF_VOLUME ); + F32 maxUFVolumeL = getF32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_UF_VOLUME ); + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.ufVolumeGoal = 0.0F; + response.ufRate = 0.0F; + + // Clear previously validated values. + validUFVolumeReceived = FALSE; + validatedUFVolumeGoalL = 0.0F; + validatedUFRateLhr = 0.0F; + + if ( message->hdr.payloadLen == sizeof( UF_VOLUME_VALIDATE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( UF_VOLUME_VALIDATE_REQUEST_PAYLOAD_T ) ); + + // Convert requested UF volume from L to mL for firmware calculations. + requestedUFVolumeL = request.ufVolume; + requestedUFVolumeMl = requestedUFVolumeL * (F32)ML_PER_LITER; + + // Send UF volume to UI in L. + response.ufVolumeGoal = requestedUFVolumeL; + + if ( ( requestedUFVolumeL >= minUFVolumeL ) && ( requestedUFVolumeL <= maxUFVolumeL ) ) + { + if ( requestedUFVolumeMl > measuredUFVolumeMl ) + { + if ( treatmentDurationMin > elapsedTreatmentTimeMin ) + { + remainingUFVolumeMl = requestedUFVolumeMl - measuredUFVolumeMl; + remainingTreatmentTimeMin = treatmentDurationMin - elapsedTreatmentTimeMin; + + // Calculate new UF rate in mL/min. + newUfRateMlMin = remainingUFVolumeMl / remainingTreatmentTimeMin; + + response.ufRate = ( newUfRateMlMin * (F32)MIN_PER_HOUR ) / (F32)ML_PER_LITER; + + if ( newUfRateMlMin <= MAX_UF_RATE_ML_MIN ) + { + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // Store validated values for confirmation step. + validUFVolumeReceived = TRUE; + validatedUFVolumeGoalL = response.ufVolumeGoal; + validatedUFRateLhr = response.ufRate; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; + } + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; + } + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; + } + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; + } + } + + result = sendMessage( MSG_ID_TD_TREATMENT_UF_VOLUME_VALIDATE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UF_VOLUME_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The validateAndSetTreatmentSetPoints function handles a UI prescription + * settings change request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_TREATMENT_SET_POINTS_CHANGE_RESPONSE including acceptance status + * and rejection reason for each prescription setting. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param message set message from UI which includes the requested prescription setting values. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL validateAndSetTreatmentSetPoints( MESSAGE_T *message ) +{ + BOOL result = FALSE; + BOOL isValid = TRUE; + CRITICAL_DATAS_T requestedValue; + TREATMENT_PRESCRIPTION_SETTINGS_EDIT_REQUEST_T request; + TREATMENT_PRESCRIPTION_SETTINGS_EDIT_RESPONSE_T response; + + memset( &requestedValue, 0, sizeof( requestedValue ) ); + memset( &request, 0, sizeof( request ) ); + memset( &response, 0, sizeof( response ) ); + + if ( message->hdr.payloadLen == sizeof( request ) ) + { + memcpy( &request, message->payload, sizeof( TREATMENT_PRESCRIPTION_SETTINGS_EDIT_REQUEST_T ) ); + + requestedValue.uInt = request.treatmentModality; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_TREATMENT_MODALITY, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_TREATMENT_MODALITY ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.uInt = request.bloodFlowRate; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_BLOOD_FLOW, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_BLOOD_FLOW ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.uInt = request.dialysateFlowRate; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_DIALYSATE_FLOW, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_DIALYSATE_FLOW ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.sFlt = request.dialysateTemperature; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_DIALYSATE_TEMPERATURE, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_DIALYSATE_TEMPERATURE ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.uInt = request.hepatitis; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_HEPATITIS_B, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_HEPATITIS_STATUS ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.uInt = request.acidConcentrate; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_ACID_CONCENTRATE, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_ACID_CONCENTRATE ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.sFlt = request.acidConcentrateConversionFactor; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_ACID_CONVERSION_FACTOR ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.uInt = request.bicarbonateConcentrate; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_DRY_BICARB_CART_SIZE, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_BICARB_CONCENTRATE ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.uInt = request.sodium; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_SODIUM, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_SODIUM ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + requestedValue.uInt = request.bicarbonate; + if ( FALSE == isTreatmentParamInRange( TREATMENT_PARAM_BICARBONATE, requestedValue ) ) + { + response.rejectionReason[ TREATMENT_SETPOINT_BICARBONATE ] = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + isValid = FALSE; + } + + if ( TRUE == isValid ) + { + setTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_MODALITY, request.treatmentModality ); + setTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW, request.bloodFlowRate ); + setTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW, request.dialysateFlowRate ); + setTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE, request.dialysateTemperature ); + setTreatmentParameterU32( TREATMENT_PARAM_HEPATITIS_B, request.hepatitis ); + setTreatmentParameterU32( TREATMENT_PARAM_ACID_CONCENTRATE, request.acidConcentrate ); + setTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR, request.acidConcentrateConversionFactor ); + setTreatmentParameterU32( TREATMENT_PARAM_DRY_BICARB_CART_SIZE, request.bicarbonateConcentrate ); + setTreatmentParameterU32( TREATMENT_PARAM_SODIUM, request.sodium ); + setTreatmentParameterU32( TREATMENT_PARAM_BICARBONATE, request.bicarbonate ); + + response.accepted = TRUE; + } + } + else + { + response.rejectionReason[ TREATMENT_SETPOINT_BLOOD_FLOW ] = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } + + result = sendMessage( MSG_ID_TD_TREATMENT_SET_POINTS_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( TREATMENT_PRESCRIPTION_SETTINGS_EDIT_RESPONSE_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The validateAndSetBloodFlowRate function handles a UI treatment set point + * blood flow rate change request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RESPONSE + * including acceptance status and rejection reason. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param message set message from UI which includes the requested blood flow rate. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL validateAndSetBloodFlowRate( MESSAGE_T *message ) +{ + BOOL result = FALSE; + CRITICAL_DATAS_T requestedValue; + BLOOD_FLOW_RATE_CHANGE_REQUEST_PAYLOAD_T request; + UI_RESPONSE_PAYLOAD_T response; + + memset( &requestedValue, 0, sizeof( requestedValue ) ); + memset( &request, 0, sizeof( request ) ); + memset( &response, 0, sizeof( response ) ); + + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( message->hdr.payloadLen == sizeof( BLOOD_FLOW_RATE_CHANGE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( BLOOD_FLOW_RATE_CHANGE_REQUEST_PAYLOAD_T ) ); + + requestedValue.uInt = request.flowRate; + + if ( TRUE == isTreatmentParamInRange( TREATMENT_PARAM_BLOOD_FLOW, requestedValue ) ) + { + setTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW, request.flowRate ); + setDialysisBloodPumpFlowRate( request.flowRate ); + + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + } + + result = sendMessage( MSG_ID_TD_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The validateAndSetDialysateFlowRate function handles a UI treatment set point + * dialysate flow rate change request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_RESPONSE + * including acceptance status and rejection reason. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param message set message from UI which includes the requested dialysate flow rate. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL validateAndSetDialysateFlowRate( MESSAGE_T *message ) +{ + BOOL result = FALSE; + CRITICAL_DATAS_T requestedValue; + DIALYSATE_FLOW_RATE_CHANGE_REQUEST_PAYLOAD_T request; + UI_RESPONSE_PAYLOAD_T response; + + memset( &requestedValue, 0, sizeof( requestedValue ) ); + memset( &request, 0, sizeof( request ) ); + memset( &response, 0, sizeof( response ) ); + + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( message->hdr.payloadLen == sizeof( DIALYSATE_FLOW_RATE_CHANGE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( DIALYSATE_FLOW_RATE_CHANGE_REQUEST_PAYLOAD_T ) ); + + requestedValue.uInt = request.flowRate; + + if ( TRUE == isTreatmentParamInRange( TREATMENT_PARAM_DIALYSATE_FLOW, requestedValue ) ) + { + setTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW, request.flowRate ); + + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + } + + result = sendMessage( MSG_ID_TD_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The validateAndSetDialysateTemperature function handles a UI treatment + * set point dialysate temperature change request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_RESPONSE + * including acceptance status and rejection reason. + * @details \b Inputs: none. + * @details \b Outputs: none. + * @param message set message from UI which includes the requested dialysate temperature. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL validateAndSetDialysateTemperature( MESSAGE_T *message ) +{ + BOOL result = FALSE; + CRITICAL_DATAS_T requestedValue; + DIALYSATE_TEMPERATURE_CHANGE_REQUEST_PAYLOAD_T request; + UI_RESPONSE_PAYLOAD_T response; + + memset( &requestedValue, 0, sizeof( requestedValue ) ); + memset( &request, 0, sizeof( request ) ); + memset( &response, 0, sizeof( response ) ); + + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( message->hdr.payloadLen == sizeof( DIALYSATE_TEMPERATURE_CHANGE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( DIALYSATE_TEMPERATURE_CHANGE_REQUEST_PAYLOAD_T ) ); + + requestedValue.sFlt = request.temperature; + + if ( TRUE == isTreatmentParamInRange( TREATMENT_PARAM_DIALYSATE_TEMPERATURE, requestedValue ) ) + { + setTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE, request.temperature ); + + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + } + + result = sendMessage( MSG_ID_TD_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The signalUserConfirmationOfTreatmentDuration function handles the UI + * treatment duration confirmation request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_DURATION_CONFIRM_RESPONSE including acceptance status + * and rejection reason. + * @details \b Inputs: validTreatmentDurationReceived, validatedTreatmentDuration_min, + * validatedUFRateLhr, validatedHeparinDeliveryDuration_min. + * @details \b Outputs: validTreatmentDurationReceived, validatedTreatmentDuration_min, + * validatedUFRateLhr, validatedHeparinDeliveryDuration_min. + * @param message set message from UI which includes the confirmed treatment duration, + * UF rate and heparin delivery duration. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL signalUserConfirmationOfTreatmentDuration( MESSAGE_T *message ) +{ + BOOL result = FALSE; + TREATMENT_DURATION_CONFIRM_REQUEST_PAYLOAD_T request; + UI_RESPONSE_PAYLOAD_T response; + F32 presUFVolumeMl = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ) * (F32)ML_PER_LITER; + F32 validatedUFRateMlMin = ( validatedUFRateLhr * (F32)ML_PER_LITER ) / (F32)MIN_PER_HOUR; + F32 roundedValidatedUFRateLhr = 0.0F; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( message->hdr.payloadLen == sizeof( TREATMENT_DURATION_CONFIRM_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( TREATMENT_DURATION_CONFIRM_REQUEST_PAYLOAD_T ) ); + + roundedValidatedUFRateLhr = roundf( validatedUFRateLhr * 100.0F ) / 100.0F; + + // Verify confirmed duration and UF rate match previously validated values. + if ( ( TRUE == validTreatmentDurationReceived ) && ( request.duration == validatedTreatmentDuration_min ) && + ( fabs( request.ufRate - roundedValidatedUFRateLhr ) < NEARLY_ZERO ) && + ( request.heparinDuration == validatedHeparinDeliveryDuration_min ) ) + { + setTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION, validatedTreatmentDuration_min ); + setTreatmentParameterU32( TREATMENT_PARAM_HEPARIN_DELIVERY_DURATION, validatedHeparinDeliveryDuration_min ); + updateTreatmentBroadcastData( validatedUFRateLhr ); + setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFVolumeMl, validatedUFRateMlMin ); + + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // Clear stored validated values. + validTreatmentDurationReceived = FALSE; + validatedTreatmentDuration_min = 0U; + validatedUFRateLhr = 0.0F; + validatedHeparinDeliveryDuration_min = 0U; + } + else if ( FALSE == validTreatmentDurationReceived ) + { + response.rejectionReason = REQUEST_REJECT_REASON_CONFIRMATION_NOT_EXPECTED; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_CONFIRMATION_MISMATCH; + } + } + + result = sendMessage( MSG_ID_TD_DURATION_CONFIRM_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The signalUserConfirmationOfUFVolume function handles the UI + * ultrafiltration volume confirmation request during Treatment mode. + * @details \b Message \b Sent: MSG_ID_TD_ULTRAFILTRATION_CHANGE_CONFIRM_RESPONSE + * including acceptance status and rejection reason. + * @details \b Inputs: validUFVolumeReceived, validatedUFVolumeGoalL, validatedUFRateLhr. + * @details \b Outputs: validUFVolumeReceived, validatedUFVolumeGoalL, validatedUFRateLhr. + * @param message set message from UI which includes the confirmed UF volume and UF rate. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL signalUserConfirmationOfUFVolume( MESSAGE_T *message ) +{ + BOOL result = FALSE; + UF_VOLUME_CONFIRM_REQUEST_PAYLOAD_T request; + UI_RESPONSE_PAYLOAD_T response; + F32 validatedUFVolumeGoalMl = 0.0F; + F32 validatedUFRateMlMin = 0.0F; + F32 roundedValidatedUFRateLhr = 0.0F; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( message->hdr.payloadLen == sizeof( UF_VOLUME_CONFIRM_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( UF_VOLUME_CONFIRM_REQUEST_PAYLOAD_T ) ); + + validatedUFVolumeGoalMl = validatedUFVolumeGoalL * (F32)ML_PER_LITER; + validatedUFRateMlMin = ( validatedUFRateLhr * (F32)ML_PER_LITER ) / (F32)MIN_PER_HOUR; + roundedValidatedUFRateLhr = roundf( validatedUFRateLhr * 100.0F ) / 100.0F; + + // Verify confirmed UF volume and UF rate match previously validated values. + if ( ( TRUE == validUFVolumeReceived ) && ( fabs( request.ufVolume - validatedUFVolumeGoalL ) < NEARLY_ZERO ) && + ( fabs( request.ufRate - roundedValidatedUFRateLhr ) < NEARLY_ZERO ) ) + { + setTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME, validatedUFVolumeGoalL ); + updateTreatmentBroadcastData( validatedUFRateLhr ); + setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), validatedUFVolumeGoalMl, validatedUFRateMlMin ); + + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // Clear stored validated values. + validUFVolumeReceived = FALSE; + validatedUFVolumeGoalL = 0.0F; + validatedUFRateLhr = 0.0F; + } + else if ( FALSE == validUFVolumeReceived ) + { + response.rejectionReason = REQUEST_REJECT_REASON_CONFIRMATION_NOT_EXPECTED; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_CONFIRMATION_MISMATCH; + } + } + + result = sendMessage( MSG_ID_TD_ULTRAFILTRATION_CHANGE_CONFIRM_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return result; +} + + +/************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Services/TxParams.h =================================================================== diff -u -r96604b790636c66ef21980a4f13ee9f987f12fee -r52787cd53986cfd0abb7e674bf096898e5070f9a --- firmware/App/Services/TxParams.h (.../TxParams.h) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) +++ firmware/App/Services/TxParams.h (.../TxParams.h) (revision 52787cd53986cfd0abb7e674bf096898e5070f9a) @@ -7,8 +7,8 @@ * * @file TxParams.h * -* @author (last) Raghu Kallala -* @date (last) 01-May-2026 +* @author (last) Vijay Pamula +* @date (last) 07-Jul-2026 * * @author (original) Varshini Nagabooshanam * @date (original) 02-Dec-2025 @@ -154,6 +154,139 @@ #pragma pack(pop) +/// Payload record structure for treatment duration validate request. +typedef struct +{ + U32 duration; ///< Requested treatment duration in minutes. +} TREATMENT_DURATION_VALIDATE_REQUEST_PAYLOAD_T; + +/// Payload record structure for treatment duration confirm request. +typedef struct +{ + U32 duration; ///< Confirmed treatment duration in minutes. + U32 heparinDuration; ///< Confirmed heparin delivery duration in minutes. + F32 ufRate; ///< Confirmed UF rate in L/hr. +} TREATMENT_DURATION_CONFIRM_REQUEST_PAYLOAD_T; + +/// Payload record structure for treatment duration validate response. +typedef struct +{ + BOOL accepted; ///< Accepted/Rejected. + U32 rejectionReason; ///< Rejection reason if not accepted. + U32 duration; ///< Treatment duration in minutes. + U32 heparinDuration; ///< Heparin delivery duration in minutes. + F32 ufVolumeGoal; ///< UF volume goal in L. + F32 ufRate; ///< UF rate in L/hr. +} TREATMENT_DURATION_VALIDATE_RESPONSE_PAYLOAD_T; + +/// Payload record structure for bolus volume change request. +typedef struct +{ + U32 bolusVolume; ///< Requested bolus volume (in mL). +} BOLUS_VOLUME_CHANGE_REQUEST_PAYLOAD_T; + +/// Payload record structure for vitals settings change request. +typedef struct +{ + U32 systolicBpLowAlarmLimit; ///< Requested systolic BP low alarm limit in mmHg. + U32 systolicBpHighAlarmLimit; ///< Requested systolic BP high alarm limit in mmHg. + U32 heartRateLowAlarmLimit; ///< Requested heart rate low alarm limit in BPM. + U32 heartRateHighAlarmLimit; ///< Requested heart rate high alarm limit in BPM. + U32 vitalsMeasurementInterval_min; ///< Requested vitals measurement interval in minutes. +} VITALS_ADJUSTMENT_REQUEST_PAYLOAD_T; + +/// Payload record structure for vitals settings change response. +typedef struct +{ + BOOL accepted; ///< Accepted/Rejected. + U32 systolicBpLowAlarmLimitRejectionReason; ///< Rejection reason for systolic BP low alarm limit. + U32 systolicBpHighAlarmLimitRejectionReason; ///< Rejection reason for systolic BP high alarm limit. + U32 heartRateLowAlarmLimitRejectionReason; ///< Rejection reason for heart rate low alarm limit. + U32 heartRateHighAlarmLimitRejectionReason; ///< Rejection reason for heart rate high alarm limit. + U32 vitalsMeasurementIntervalRejectionReason; ///< Rejection reason for vitals measurement interval. +} VITALS_ADJUSTMENT_RESPONSE_PAYLOAD_T; + +/// Payload record structure for pressure limit change request. +typedef struct +{ + U32 arterialPressureLimitWindowMMHG; ///< Arterial pressure limit window in mmHg. + U32 venousHighPressureLimitWindowMMHG; ///< Venous high pressure limit window in mmHg. + U32 venousLowPressureLimitWindowMMHG; ///< Venous low pressure limit window in mmHg. + U32 tmpPressureLimitWindowMMHG; ///< TMP pressure limit window in mmHg. +} PRESSURE_LIMIT_CHANGE_REQUEST_T; + +/// Payload record structure for in-treatment pressure limit change response. +typedef struct +{ + BOOL accepted; ///< Accepted/Rejected. + U32 arterialPressureLimitWindowRejectionReason; ///< Rejection reason for arterial pressure limit window. + U32 venousPressureLimitWindowRejectionReason; ///< Rejection reason for venous pressure limit window. + U32 venousAsymmetricPressureLimitWindowRejectionReason; ///< Rejection reason for venous asymmetric pressure limit window. + U32 tmpPressureLimitWindowRejectionReason; ///< Rejection reason for TMP pressure limit window. +} PRESSURE_LIMITS_CHANGE_RESPONSE_PAYLOAD_T; + +/// Payload record structure for UF volume validate request. +typedef struct +{ + F32 ufVolume; ///< Requested UF volume in L. +} UF_VOLUME_VALIDATE_REQUEST_PAYLOAD_T; + +/// Payload record structure for UF volume confirm request. +typedef struct +{ + F32 ufVolume; ///< Confirmed UF volume in L. + F32 ufRate; ///< Confirmed UF rate in L/hr. +} UF_VOLUME_CONFIRM_REQUEST_PAYLOAD_T; + +/// Payload record structure for UF change response. +typedef struct +{ + BOOL accepted; ///< Accepted/Rejected. + U32 rejectionReason; ///< Rejection reason if not accepted. + F32 ufVolumeGoal; ///< UF Volume in L. + F32 ufRate; ///< new UF rate in L/hr. +} UF_VOLUME_RESPONSE_PAYLOAD_T; + +/// Payload record structure for blood flow rate change request. +typedef struct +{ + U32 flowRate; ///< Blood flow rate in mL/min. +} BLOOD_FLOW_RATE_CHANGE_REQUEST_PAYLOAD_T; + +/// Payload record structure for dialysate flow rate change request. +typedef struct +{ + U32 flowRate; ///< Dialysate flow rate in mL/min. +} DIALYSATE_FLOW_RATE_CHANGE_REQUEST_PAYLOAD_T; + +/// Payload record structure for dialysate temperature change request. +typedef struct +{ + F32 temperature; ///< Dialysate temperature in degrees Celsius. +} DIALYSATE_TEMPERATURE_CHANGE_REQUEST_PAYLOAD_T; + +/// Payload record structure for prescription settings change request. +typedef struct +{ + U32 bloodFlowRate; ///< Blood flow rate. + U32 dialysateFlowRate; ///< Dialysate flow rate. + F32 dialysateTemperature; ///< Dialysate temperature. + U32 acidConcentrate; ///< Acid concentrate. + F32 acidConcentrateConversionFactor; ///< Acid concentrate conversion factor. + U32 bicarbonateConcentrate; ///< Dry bicarbonate cartridge size. + U32 treatmentModality; ///< Treatment modality. + U32 hepatitis; ///< Hepatitis status. + U32 sodium; ///< Sodium concentration. + U32 bicarbonate; ///< Bicarbonate concentration (mEq/L). +} TREATMENT_PRESCRIPTION_SETTINGS_EDIT_REQUEST_T; + +/// Payload record structure for prescription settings change response. +typedef struct +{ + BOOL accepted; ///< Accepted/Rejected. + U32 rejectionReason[ NUM_OF_TREATMENT_SETPOINT_PARAMS ]; ///< Rejection reason for each prescription setting. +} TREATMENT_PRESCRIPTION_SETTINGS_EDIT_RESPONSE_T; + // ********** public function prototypes **************** BOOL setTreatmentParameterU32( TREATMENT_PARAM_T param, U32 value ); // Set a specified unsigned integer treatment parameter value @@ -162,15 +295,27 @@ F32 getTreatmentParameterF32( TREATMENT_PARAM_T param ); // Get a specified floating point treatment parameter BOOL validateAndSetTreatmentParameters( MESSAGE_T *message ); // User provided treatment params to be set and validated -//BOOL validateAndSetUFVolume( MESSAGE_T *message ); // User provided ultrafiltration volume to be set and validated +//BOOL validateAndSetUFVolume( MESSAGE_T *message ); // User provided ultrafiltration volume to be set and validated F32 calculateIsolatedUFRateMlMin( U32 durationMin, F32 volumeGoalMl ); // Calculate isolated UF rate (mL/min) from duration and volume goal BOOL handleIsolatedUFDurationChangeRequest( MESSAGE_T *message ); // User requested isolated UF duration change BOOL handleIsolatedUFVolumeGoalChangeRequest( MESSAGE_T *message ); // User requested isolated UF volume goal change BOOL handleIsolatedUFConfirmRequest( MESSAGE_T *message ); // User confirmed/rejected isolated UF settings change -void resetTreatmentParameters( void ); // Reset all parameters to defaults -//BOOL signalUserConfirmationOfTreatmentParameters( MESSAGE_T *message ); // Process UI confirm/reject Treatment parameters +// Edit Treatment parameter handlers +BOOL validateAndSetTreatmentDuration( MESSAGE_T *message ); // User provided treatment duration to be set and validated +BOOL validateAndSetBolusVolume( MESSAGE_T *message ); // User provided bolus volume to be set and validated +BOOL vitalsAdjustmentHandleChangeRequest( MESSAGE_T *message ); // User provided vitals settings to be validated and applied +BOOL pressureLimitHandleChangeRequest( MESSAGE_T *message ); // User provided pressure limit window values to be validated and applied +BOOL validateAndSetUFVolume( MESSAGE_T *message ); // User provided ultrafiltration volume to be set and validated +BOOL validateAndSetTreatmentSetPoints( MESSAGE_T *message ); // User provided prescription setting values to be validated and applied +BOOL validateAndSetBloodFlowRate( MESSAGE_T *message ); // Validates and applies blood flow rate change from UI button request +BOOL validateAndSetDialysateFlowRate( MESSAGE_T *message ); // Validates and applies dialysate flow rate change from UI button request +BOOL validateAndSetDialysateTemperature( MESSAGE_T *message ); // Validates and applies temperature change from UI button request +BOOL signalUserConfirmationOfTreatmentDuration( MESSAGE_T *message ); // Process UI confirm/reject treatment duration +BOOL signalUserConfirmationOfUFVolume( MESSAGE_T *message ); // Process UI confirm/reject ultrafiltration volume change +void initTreatmentParameters( void ); // Initialize treatment parameters and session state + BOOL getValidTreatParamsReceived( void ); // Determine whether valid Treatment Parameters exist BOOL getTreatParamsConfirmed( void ); // Determine whether user confirmed the parameters @@ -188,6 +333,7 @@ U32 getU32DefaultSysConfigTreatmentParamEdge( SYS_CONFIG_TREATMENT_PARAM_T param, BOOL isMin ); // Get default min/max edge for unsigned integer system configured treatment parameter U32 getSysConfigTreatmentParameterU32( SYS_CONFIG_TREATMENT_PARAM_T param ); // Get a specified unsigned integer system configured treatment parameter U32 getSysConfigTreatmentParameterU32DefaultValue( SYS_CONFIG_TREATMENT_PARAM_T param ); // Get the default value for a specified unsigned integer system configured treatment parameter +BOOL setSysConfigTreatmentParameterU32( SYS_CONFIG_TREATMENT_PARAM_T param, U32 value ); // Set a specified unsigned integer system configured treatment parameter U32 getDialyzerBloodVolume( DIALYZER_TYPE_T dialyzer ); // Get the blood side volume for a given dialyzer type U32 getDialyzerDialysateVolume( DIALYZER_TYPE_T dialyzer ); // Get the dialysate side volume for a given dialyzer type