Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e -r96604b790636c66ef21980a4f13ee9f987f12fee --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) @@ -98,12 +98,14 @@ static BOOL endTreatmentRequest; ///< Flag indicates user has requested end of treatment from rinseback workflow. static BOOL bloodPrimeToDialysisRequest; ///< Flag indicates blood prime has completed and time to start dialysis. static BOOL resumeBlockedByAlarm; ///< Flag indicates an alarm has blocked resume of this treatment. -static TREATMENT_STATE_T treatmentStateBeforePause; ///< Treatment state to return to after treatment paused state. -static BOOL isolatedUFStartRequested; ///< Flag indicates isolated UF should start. -static BOOL isolatedUFMidTreatment; ///< Flag indicates isolated UF was started during HD/HDF treatment. -static U32 isolatedUFDurationMin; ///< Isolated UF duration in minutes. -static F32 isolatedUFSetVolumeMl; ///< Isolated UF set volume in mL. -static F32 isolatedUFRateMlMin; ///< Isolated UF rate in mL/min. +static TREATMENT_STATE_T treatmentStateBeforePause; ///< Treatment state to return to after treatment paused state. +static BOOL isolatedUFStartRequested; ///< Flag indicates isolated UF should start. +static BOOL isolatedUFMidTreatment; ///< Flag indicates isolated UF was started during HD/HDF treatment. +static U32 isolatedUFDurationMin; ///< Isolated UF duration in minutes. +static F32 isolatedUFSetVolumeMl; ///< Isolated UF set volume in mL. +static F32 isolatedUFRateMlMin; ///< Isolated UF rate in mL/min. +static U32 cumulativeIsolatedUFTimeMin; ///< Cumulative completed isolated UF time in minutes. +static F32 cumulativeIsolatedUFVolumeMl; ///< Cumulative completed isolated UF volume in mL. static U32 treatmentStartTimeStamp; ///< Treatment start timestamp for logging purpose. static U32 treatmentEndTimeStamp; ///< Treatment end timestamp for logging purpose. @@ -130,6 +132,7 @@ static void resetSignalFlags( void ); static void resetAlarmSignalFlags( void ); static void resumeDialysisAfterIsolatedUF( void ); +static void recordCompletedIsolatedUFSession( void ); /*********************************************************************//** * @brief @@ -177,6 +180,8 @@ isolatedUFDurationMin = 0; isolatedUFSetVolumeMl = 0.0F; isolatedUFRateMlMin = 0.0F; + cumulativeIsolatedUFTimeMin = 0; + cumulativeIsolatedUFVolumeMl = 0.0F; resetSignalFlags(); resetAlarmSignalFlags(); @@ -246,15 +251,8 @@ setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFVolumeMl, presUFRateMlMin ); bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; - if ( TREATMENT_MODALITY_ISOLATED_UF == getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_MODALITY ) ) - { - setIsolatedUFSettings( getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ), presUFVolumeMl ); - presUFRateMlMin = getIsolatedUFRateMlMin(); - } - // Direct DD to generate dialysate and bypass while priming blood. - cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), - ( TREATMENT_MODALITY_ISOLATED_UF == getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_MODALITY ) ? 0.0F : presUFRateMlMin ), + cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateMlMin, getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), bicarbConvFactor, @@ -407,7 +405,7 @@ * The signalStartIsolatedUF function requests transition to isolated UF. * @details \b Inputs: none * @details \b Outputs: isolatedUFStartRequested, isolatedUFMidTreatment - * @param midTreatment TRUE when resuming HD/HDF after iso UF; FALSE for post-treatment or standalone exit to POST. + * @param midTreatment TRUE when resuming HD/HDF after iso UF; FALSE for post-treatment entry (exit to POST). * @return none *************************************************************************/ void signalStartIsolatedUF( BOOL midTreatment ) @@ -467,6 +465,46 @@ /*********************************************************************//** * @brief + * The getCumulativeIsolatedUFTimeMin function gets cumulative completed + * isolated UF time for the current treatment session. + * @details \b Inputs: cumulativeIsolatedUFTimeMin + * @details \b Outputs: none + * @return cumulative completed isolated UF time in minutes. + *************************************************************************/ +U32 getCumulativeIsolatedUFTimeMin( void ) +{ + return cumulativeIsolatedUFTimeMin; +} + +/*********************************************************************//** + * @brief + * The getCumulativeIsolatedUFVolumeMl function gets cumulative completed + * isolated UF volume for the current treatment session. + * @details \b Inputs: cumulativeIsolatedUFVolumeMl + * @details \b Outputs: none + * @return cumulative completed isolated UF volume in mL. + *************************************************************************/ +F32 getCumulativeIsolatedUFVolumeMl( void ) +{ + return cumulativeIsolatedUFVolumeMl; +} + +/*********************************************************************//** + * @brief + * The recordCompletedIsolatedUFSession function accumulates elapsed time and + * delivered volume from a completed isolated UF session. + * @details \b Inputs: getIsolatedUFSessionElapsedTimeMin, getIsolatedUFVolumeDrawn + * @details \b Outputs: cumulativeIsolatedUFTimeMin, cumulativeIsolatedUFVolumeMl + * @return none + *************************************************************************/ +static void recordCompletedIsolatedUFSession( void ) +{ + cumulativeIsolatedUFTimeMin += getIsolatedUFSessionElapsedTimeMin(); + cumulativeIsolatedUFVolumeMl += getIsolatedUFVolumeDrawn() * (F32)ML_PER_LITER; +} + +/*********************************************************************//** + * @brief * The resumeDialysisAfterIsolatedUF function restores normal HD/HDF dialysis * after a mid-treatment isolated UF session. Prescribed UF rate and Qd stored * in the dialysis sub-mode are reapplied to the DD. @@ -742,8 +780,7 @@ // Handle alarm page if ( TRUE == doesAlarmStatusIndicateStop() ) { - transitionToTreatmentPaused(); - result = TREATMENT_PAUSED_STATE; + result = enterTreatmentPausedState(); } else { @@ -754,27 +791,18 @@ { lastTreatmentTimeStamp = getMSTimerCount(); - if ( TREATMENT_MODALITY_ISOLATED_UF == getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_MODALITY ) ) - { - isolatedUFMidTreatment = FALSE; - transitionToIsolatedUF(); - result = TREATMENT_ISO_UF_STATE; - } - else - { - // Kick dialysis sub-mode off - setDialysisBloodPumpFlowRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ); + // Kick dialysis sub-mode off + setDialysisBloodPumpFlowRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ); // setDialysisDialInFlowAndUFRate( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presMaxUFVolumeML, presUFRate ); // // if ( presUFRate > 0.0 ) // { // sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, presUFRate ); // } - transitionToDialysis(); + transitionToDialysis(); // // To update partial blood pump occlusion baseline - start of treatment // signalBloodPumpPressureOcclBaseline(); - result = TREATMENT_DIALYSIS_STATE; - } + result = TREATMENT_DIALYSIS_STATE; } } @@ -865,6 +893,7 @@ ( CALC_ELAPSED_TREAT_TIME_IN_SECS() >= presTreatmentTimeSecs ) ) { treatmentCompleted = TRUE; + recordCompletedIsolatedUFSession(); endIsolatedUFOnUserStop(); isolatedUFMidTreatment = FALSE; cmdBypassDialyzer( TRUE ); @@ -878,6 +907,8 @@ if ( TRUE == isIsolatedUFCompleted() ) { + recordCompletedIsolatedUFSession(); + if ( TRUE == isIsolatedUFMidTreatment() ) { resumeDialysisAfterIsolatedUF(); @@ -895,8 +926,7 @@ // Handle alarm page else if ( TRUE == doesAlarmStatusIndicateStop() ) { - transitionToTreatmentPaused(); - result = TREATMENT_PAUSED_STATE; + result = enterTreatmentPausedState(); } } @@ -938,16 +968,8 @@ break; case TREATMENT_BLOOD_PRIME_STATE: - if ( TREATMENT_MODALITY_ISOLATED_UF == getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_MODALITY ) ) - { - transitionToIsolatedUF(); - result = TREATMENT_ISO_UF_STATE; - } - else - { - transitionToDialysis(); - result = TREATMENT_DIALYSIS_STATE; - } + transitionToDialysis(); + result = TREATMENT_DIALYSIS_STATE; break; default: Index: firmware/App/Modes/ModeTreatment.h =================================================================== diff -u -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e -r96604b790636c66ef21980a4f13ee9f987f12fee --- firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) +++ firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) @@ -135,11 +135,13 @@ 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 (F = post-treatment or standalone entry path) +void signalStartIsolatedUF( BOOL midTreatment ); // Request transition to isolated UF BOOL isIsolatedUFMidTreatment( void ); // Determine whether isolated UF was started during HD/HDF U32 getIsolatedUFDurationMin( void ); // Get isolated UF duration F32 getIsolatedUFSetVolumeMl( void ); // Get isolated UF set volume F32 getIsolatedUFRateMlMin( void ); // Get isolated UF rate +U32 getCumulativeIsolatedUFTimeMin( void ); // Get cumulative completed isolated UF time in minutes +F32 getCumulativeIsolatedUFVolumeMl( void ); // Get cumulative completed isolated UF volume in mL // MSG_ID_TD_PRESSURE_LIMITS_CHANGE_RESPONSE BOOL sendPressureLimitsChangeResponse( PRESSURE_LIMIT_CHANGE_RESPONSE_T *data ); Index: firmware/App/Modes/StateTxIsolatedUF.c =================================================================== diff -u -r8a7e31d75c06444514b61870b61f8c8a1815a618 -r96604b790636c66ef21980a4f13ee9f987f12fee --- firmware/App/Modes/StateTxIsolatedUF.c (.../StateTxIsolatedUF.c) (revision 8a7e31d75c06444514b61870b61f8c8a1815a618) +++ firmware/App/Modes/StateTxIsolatedUF.c (.../StateTxIsolatedUF.c) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) @@ -99,7 +99,7 @@ setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); // Mid-treatment isolated UF keeps dialysate generation at the treatment rate - // while bypassing the dialyzer. Post-treatment and standalone isolated UF do not generate dialysate. + // while bypassing the dialyzer. Post-treatment isolated UF does not generate dialysate. if ( TRUE == isIsolatedUFMidTreatment() ) { setDialysateFlowMlMin = (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ); @@ -185,6 +185,21 @@ /*********************************************************************//** * @brief + * The getIsolatedUFSessionElapsedTimeMin function gets elapsed time for the + * current or most recently completed isolated UF session. + * @details \b Inputs: isolatedUFElapsedTimerCtr + * @details \b Outputs: none + * @return elapsed isolated UF session time in minutes. + *************************************************************************/ +U32 getIsolatedUFSessionElapsedTimeMin( void ) +{ + U32 elapsedTimeMin = ( isolatedUFElapsedTimerCtr * TASK_GENERAL_INTERVAL ) / ( MS_PER_SECOND * SEC_PER_MIN ); + + return elapsedTimeMin; +} + +/*********************************************************************//** + * @brief * The isIsolatedUFCompleted function determines whether isolated UF completed. * @details \b Inputs: isolatedUFCompleted * @details \b Outputs: none Index: firmware/App/Modes/StateTxIsolatedUF.h =================================================================== diff -u -r8a7e31d75c06444514b61870b61f8c8a1815a618 -r96604b790636c66ef21980a4f13ee9f987f12fee --- firmware/App/Modes/StateTxIsolatedUF.h (.../StateTxIsolatedUF.h) (revision 8a7e31d75c06444514b61870b61f8c8a1815a618) +++ firmware/App/Modes/StateTxIsolatedUF.h (.../StateTxIsolatedUF.h) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) @@ -22,10 +22,10 @@ /** * @defgroup StateTxIsolatedUF StateTxIsolatedUF - * @brief Treatment mode isolated ultrafiltration state unit. The isolated UF - * sub-mode removes fluid from the patient with the dialyzer bypassed. Dialysate + * @brief Isolated ultrafiltration sub-mode of treatment mode. The sub-mode + * removes fluid from the patient with the dialyzer bypassed. Dialysate * generation depends on whether isolated UF is started mid-treatment (Qd at - * treatment rate), post-treatment (Qd = 0), or as a standalone prescription (Qd = 0). + * treatment rate) or post-treatment (Qd = 0). * * @addtogroup StateTxIsolatedUF * @{ @@ -51,9 +51,10 @@ BOOL isIsolatedUFCompleted( void ); // Determines whether isolated UF has completed void endIsolatedUFOnUserStop( void ); // Ends active isolated UF session F32 getIsolatedUFVolumeDrawn( void ); // Gets current isolated UF volume drawn from patient +U32 getIsolatedUFSessionElapsedTimeMin( void ); // Gets elapsed isolated UF session time in minutes -BOOL handleUFPauseResumeRequest( MESSAGE_T *message ); // Routes UI pause/resume UF to dialysis or isolated UF -BOOL signalPauseResumeIsolatedUF( MESSAGE_T *message ); // Handles UI pause/resume UF request +BOOL handleUFPauseResumeRequest( MESSAGE_T *message ); // Routes UI pause/resume UF to dialysis or isolated UF +BOOL signalPauseResumeIsolatedUF( MESSAGE_T *message ); // Handles UI pause/resume UF request /**@}*/ Index: firmware/App/Services/Messaging.h =================================================================== diff -u -r395522dffef1348e176564925656012f529c1910 -r96604b790636c66ef21980a4f13ee9f987f12fee --- firmware/App/Services/Messaging.h (.../Messaging.h) (revision 395522dffef1348e176564925656012f529c1910) +++ firmware/App/Services/Messaging.h (.../Messaging.h) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) @@ -14,15 +14,15 @@ * @date (original) 01-Aug-2024 * ***************************************************************************/ - -#ifndef __MESSAGING_H__ -#define __MESSAGING_H__ +#ifndef __MESSAGING_H__ +#define __MESSAGING_H__ + #include "TDCommon.h" #include "TDDefs.h" #include "MessageSupport.h" #include "MsgQueues.h" - + /** * @defgroup Messaging Messaging * @brief The system communication messages unit provides helper functions @@ -35,7 +35,7 @@ // ********** public definitions ********** #define ACK_REQUIRED TRUE ///< Macro for functions that want to know if an outgoing message requires acknowledgement from receiver. -#define ACK_NOT_REQUIRED FALSE ///< Macro for functions that want to know if an outgoing message requires acknowledgement from receiver. +#define ACK_NOT_REQUIRED FALSE ///< Macro for functions that want to know if an outgoing message requires acknowledgement from receiver. #pragma pack(push, 1) /// Payload record structure for ACK response. @@ -138,13 +138,13 @@ F32 maxHeparinBolusVolumeML; ///< Max heparin bolus volume in mL. U32 enableChemicalDisinfect; ///< Enable/disable chemical disinfect. } HD_INSTITUTIONAL_LOCAL_RECORD_T; - -// ********** public function prototypes ********** -// Serialize message +// ********** public function prototypes ********** + +// Serialize message U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ); -// ACK MSG +// ACK MSG BOOL sendACKMsg( MESSAGE_T *message ); // Handle version request message @@ -171,4 +171,4 @@ /**@}*/ -#endif +#endif Index: firmware/App/Services/TxParams.c =================================================================== diff -u -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e -r96604b790636c66ef21980a4f13ee9f987f12fee --- firmware/App/Services/TxParams.c (.../TxParams.c) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) +++ firmware/App/Services/TxParams.c (.../TxParams.c) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) @@ -195,6 +195,7 @@ static BOOL checkTreatmentParamsDependencies( U32 *reasons ); static BOOL checkUFDependencies( U32 *reasons ); static REQUEST_REJECT_REASON_CODE_T validateIsolatedUFSettings( U32 durationMin, F32 volumeGoalMl ); +static REQUEST_REJECT_REASON_CODE_T validateIsolatedUFDuration( U32 durationMin ); static U32 calculateIsolatedUFMaxVolumeMl( U32 durationMin ); static BOOL isPostTreatmentIsolatedUFRequest( void ); static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T payload ); @@ -261,9 +262,9 @@ *************************************************************************/ static void resetIsolatedUFSettingsPending( void ) { - isolatedUFSettingsPending = FALSE; + isolatedUFSettingsPending = FALSE; isolatedUFDurationPendingMin = 0; - isolatedUFVolumePendingMl = 0.0F; + isolatedUFVolumePendingMl = 0.0F; } /*********************************************************************//** @@ -561,27 +562,27 @@ result = ( ( ( param == TREATMENT_PARAM_HDF_DILUTION ) || ( param == TREATMENT_PARAM_SUBST_FLUID_VOLUME ) ) ? TRUE : FALSE ); break; - case TREATMENT_MODALITY_ISOLATED_UF: - switch ( param ) - { - case TREATMENT_PARAM_HDF_DILUTION: - case TREATMENT_PARAM_SUBST_FLUID_VOLUME: - case TREATMENT_PARAM_DIALYSATE_FLOW: - case TREATMENT_PARAM_DIALYSATE_TEMPERATURE: - case TREATMENT_PARAM_ACID_CONCENTRATE: - case TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR: - case TREATMENT_PARAM_SODIUM: - case TREATMENT_PARAM_BICARBONATE: - case TREATMENT_PARAM_DRY_BICARB_CART_SIZE: - result = TRUE; - break; +// case TREATMENT_MODALITY_ISOLATED_UF: // TODO uncomment in phase 3 when ISO UF is a standalone modality +// switch ( param ) +// { +// case TREATMENT_PARAM_HDF_DILUTION: +// case TREATMENT_PARAM_SUBST_FLUID_VOLUME: +// case TREATMENT_PARAM_DIALYSATE_FLOW: +// case TREATMENT_PARAM_DIALYSATE_TEMPERATURE: +// case TREATMENT_PARAM_ACID_CONCENTRATE: +// case TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR: +// case TREATMENT_PARAM_SODIUM: +// case TREATMENT_PARAM_BICARBONATE: +// case TREATMENT_PARAM_DRY_BICARB_CART_SIZE: +// result = TRUE; +// break; +// +// default: +// result = FALSE; +// break; +// } +// break; - default: - result = FALSE; - break; - } - break; - default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_TREATMENT_MODALITY, (U32)txType ) break; @@ -863,77 +864,87 @@ * @brief * The isPostTreatmentIsolatedUFRequest function determines whether isolated UF * is being requested after prescribed HD/HDF treatment time has elapsed. - * @details \b Inputs: getTreatmentState, isTreatmentCompleted + * @details \b Inputs: getTreatmentState * @details \b Outputs: none * @return TRUE if post-treatment isolated UF entry applies, FALSE otherwise. *************************************************************************/ static BOOL isPostTreatmentIsolatedUFRequest( void ) { - BOOL result = FALSE; - - if ( ( TREATMENT_END_STATE == getTreatmentState() ) && - ( TRUE == isTreatmentCompleted() ) && - ( TREATMENT_MODALITY_ISOLATED_UF != getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_MODALITY ) ) ) - { - result = TRUE; - } - - return result; + return ( TREATMENT_END_STATE == getTreatmentState() ); } /*********************************************************************//** * @brief - * The validateIsolatedUFSettings function validates isolated UF duration, - * volume goal, and derived rate before UI confirmation. - * @details \b Inputs: durationMin, volumeGoalMl + * The validateIsolatedUFDuration function validates isolated UF duration + * before UI confirmation. + * @details \b Inputs: durationMin * @details \b Outputs: none * @param durationMin Isolated UF duration in minutes. - * @param volumeGoalMl Isolated UF volume goal in mL. * @return Rejection reason code, or REQUEST_REJECT_REASON_NONE if valid. *************************************************************************/ -static REQUEST_REJECT_REASON_CODE_T validateIsolatedUFSettings( U32 durationMin, F32 volumeGoalMl ) +static REQUEST_REJECT_REASON_CODE_T validateIsolatedUFDuration( U32 durationMin ) { REQUEST_REJECT_REASON_CODE_T reason = REQUEST_REJECT_REASON_NONE; - F32 volumeGoalL = volumeGoalMl / (F32)ML_PER_LITER; - F32 ufRateMlMin = calculateIsolatedUFRateMlMin( durationMin, volumeGoalMl ); - U32 elapsedTreatmentMin = getActualTreatmentTimeSecs() / SEC_PER_MIN; - BOOL postTreatmentRequest = isPostTreatmentIsolatedUFRequest(); - BOOL validTreatmentState = FALSE; + U32 prescribedDurationMin = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + U32 maxTreatmentDurationMin = getU32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ); + U32 cumulativeIsoUFTimeMin = getCumulativeIsolatedUFTimeMin(); + U32 totalDurationMin = prescribedDurationMin + cumulativeIsoUFTimeMin + durationMin; - if ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) - { - validTreatmentState = TRUE; - } - else if ( TRUE == postTreatmentRequest ) - { - validTreatmentState = TRUE; - } - if ( MODE_TREA != getCurrentOperationMode() ) { reason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } - else if ( FALSE == validTreatmentState ) + else if ( ( TREATMENT_DIALYSIS_STATE != getTreatmentState() ) && + ( FALSE == isPostTreatmentIsolatedUFRequest() ) ) { reason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } - else if ( ( durationMin < getU32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ) ) || - ( durationMin > getU32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ) ) ) + else if ( durationMin < MIN_ISOLATED_UF_DURATION_MIN ) { reason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; } - else if ( ( FALSE == postTreatmentRequest ) && ( durationMin <= elapsedTreatmentMin ) ) + else if ( durationMin > maxTreatmentDurationMin ) { - reason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; + reason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; } - else if ( ( volumeGoalL < getF32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_UF_VOLUME ) ) || - ( volumeGoalL > getF32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_UF_VOLUME ) ) ) + else if ( totalDurationMin > maxTreatmentDurationMin ) { - reason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; + reason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; } - else if ( ( ufRateMlMin < MIN_UF_RATE_ML_MIN ) || ( ufRateMlMin > MAX_UF_RATE_ML_MIN ) ) + + return reason; +} + +/*********************************************************************//** + * @brief + * The validateIsolatedUFSettings function validates isolated UF duration, + * volume goal, and derived rate before UI confirmation. + * @details \b Inputs: durationMin, volumeGoalMl + * @details \b Outputs: none + * @param durationMin Isolated UF duration in minutes. + * @param volumeGoalMl Isolated UF volume goal in mL. + * @return Rejection reason code, or REQUEST_REJECT_REASON_NONE if valid. + *************************************************************************/ +static REQUEST_REJECT_REASON_CODE_T validateIsolatedUFSettings( U32 durationMin, F32 volumeGoalMl ) +{ + REQUEST_REJECT_REASON_CODE_T reason = validateIsolatedUFDuration( durationMin ); + F32 ufRateMlMin = calculateIsolatedUFRateMlMin( durationMin, volumeGoalMl ); + F32 maxVolumeMl = (F32)calculateIsolatedUFMaxVolumeMl( durationMin ); + + if ( REQUEST_REJECT_REASON_NONE == reason ) { - reason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; + if ( volumeGoalMl < MIN_ISOLATED_UF_VOLUME_ML ) + { + reason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; + } + else if ( volumeGoalMl > maxVolumeMl ) + { + reason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; + } + else if ( ( ufRateMlMin < MIN_UF_RATE_ML_MIN ) || ( ufRateMlMin > MAX_UF_RATE_ML_MIN ) ) + { + reason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; + } } return reason; @@ -950,8 +961,17 @@ *************************************************************************/ static U32 calculateIsolatedUFMaxVolumeMl( U32 durationMin ) { - F32 maxVolumeMl = MIN( (F32)durationMin * MAX_UF_RATE_ML_MIN, (F32)MAX_UF_VOLUME_ML ); + F32 maxRateVolumeMl = (F32)durationMin * MAX_UF_RATE_ML_MIN; + F32 cumulativeIsoUFVolumeMl = getCumulativeIsolatedUFVolumeMl(); + F32 prescriptionUFVolumeMl = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ) * (F32)ML_PER_LITER; + F32 maxSessionVolumeMl = (F32)MAX_UF_VOLUME_ML - cumulativeIsoUFVolumeMl - prescriptionUFVolumeMl; + F32 maxVolumeMl = MIN( maxRateVolumeMl, maxSessionVolumeMl ); + if ( maxVolumeMl < 0.0F ) + { + maxVolumeMl = 0.0F; + } + return (U32)maxVolumeMl; } @@ -961,38 +981,37 @@ * duration change request. * @details \b Message \b Sent: MSG_ID_TD_ISOLATED_UF_DURATION_CHANGE_RESPONSE * @details \b Inputs: message - * @details \b Outputs: isolatedUFDurationPendingMin + * @details \b Outputs: none * @param message Duration change request message from UI. - * @return TRUE if the request is valid and staged, FALSE otherwise. + * @return TRUE if the duration is valid, FALSE otherwise. *************************************************************************/ BOOL handleIsolatedUFDurationChangeRequest( MESSAGE_T *message ) { BOOL accepted = FALSE; REQUEST_REJECT_REASON_CODE_T reason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; ISOLATED_UF_DURATION_CHANGE_RESPONSE_PAYLOAD_T response; - U32 durationMin = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); - F32 volumeGoalMl = ( TRUE == isolatedUFSettingsPending ? isolatedUFVolumePendingMl : - getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ) * (F32)ML_PER_LITER ); + U32 durationMin = 0U; if ( sizeof( ISOLATED_UF_DURATION_CHANGE_REQUEST_PAYLOAD_T ) == message->hdr.payloadLen ) { ISOLATED_UF_DURATION_CHANGE_REQUEST_PAYLOAD_T request; memcpy( &request, message->payload, sizeof( ISOLATED_UF_DURATION_CHANGE_REQUEST_PAYLOAD_T ) ); durationMin = request.mDuration; - reason = validateIsolatedUFSettings( durationMin, volumeGoalMl ); + reason = validateIsolatedUFDuration( durationMin ); if ( REQUEST_REJECT_REASON_NONE == reason ) { - isolatedUFSettingsPending = TRUE; - isolatedUFDurationPendingMin = durationMin; - isolatedUFVolumePendingMl = volumeGoalMl; accepted = TRUE; } } + else + { + reason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } - response.mAccepted = (U32)accepted; - response.mReason = (U32)reason; + response.mAccepted = (U32)accepted; + response.mReason = (U32)reason; response.mVolumeMax = calculateIsolatedUFMaxVolumeMl( durationMin ); sendMessage( MSG_ID_TD_ISOLATED_UF_DURATION_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&response), sizeof( ISOLATED_UF_DURATION_CHANGE_RESPONSE_PAYLOAD_T ) ); @@ -1002,7 +1021,7 @@ /*********************************************************************//** * @brief * The handleIsolatedUFVolumeGoalChangeRequest function handles a UI isolated - * UF volume goal change request. + * UF settings change request containing both duration and volume goal. * @details \b Message \b Sent: MSG_ID_TD_ISOLATED_UF_VOLUME_GOAL_CHANGE_RESPONSE * @details \b Inputs: message * @details \b Outputs: isolatedUFVolumePendingMl @@ -1014,9 +1033,8 @@ BOOL accepted = FALSE; REQUEST_REJECT_REASON_CODE_T reason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; ISOLATED_UF_VOLUME_GOAL_CHANGE_RESPONSE_PAYLOAD_T response; - U32 durationMin = ( TRUE == isolatedUFSettingsPending ? isolatedUFDurationPendingMin : - getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ) ); - F32 volumeGoalMl = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ) * (F32)ML_PER_LITER; + U32 durationMin = 0U; + F32 volumeGoalMl = 0.0F; if ( sizeof( ISOLATED_UF_VOLUME_GOAL_CHANGE_REQUEST_PAYLOAD_T ) == message->hdr.payloadLen ) { @@ -1029,18 +1047,22 @@ if ( REQUEST_REJECT_REASON_NONE == reason ) { - isolatedUFSettingsPending = TRUE; + isolatedUFSettingsPending = TRUE; isolatedUFDurationPendingMin = durationMin; - isolatedUFVolumePendingMl = volumeGoalMl; + isolatedUFVolumePendingMl = volumeGoalMl; accepted = TRUE; } } + else + { + reason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } response.mAccepted = (U32)accepted; - response.mReason = (U32)reason; - response.mVolume = (U32)volumeGoalMl; + response.mReason = (U32)reason; + response.mVolume = (U32)volumeGoalMl; response.mDuration = durationMin; - response.mRate = (U32)calculateIsolatedUFRateMlMin( durationMin, volumeGoalMl ); + response.mRate = (U32)calculateIsolatedUFRateMlMin( durationMin, volumeGoalMl ); sendMessage( MSG_ID_TD_ISOLATED_UF_VOLUME_GOAL_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&response), sizeof( ISOLATED_UF_VOLUME_GOAL_CHANGE_RESPONSE_PAYLOAD_T ) ); return accepted; @@ -1109,6 +1131,10 @@ } } } + else + { + reason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } response.mAccepted = (U32)accepted; response.mReason = (U32)reason; Index: firmware/App/Services/TxParams.h =================================================================== diff -u -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e -r96604b790636c66ef21980a4f13ee9f987f12fee --- firmware/App/Services/TxParams.h (.../TxParams.h) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) +++ firmware/App/Services/TxParams.h (.../TxParams.h) (revision 96604b790636c66ef21980a4f13ee9f987f12fee) @@ -37,6 +37,8 @@ #define MAX_UF_RATE_ML_MIN ( 2000.01F / (F32)MIN_PER_HOUR ) ///< Maximum ultrafiltration rate (in mL/min). Added small decimal to prevent float round off issues. #define MIN_UF_RATE_ML_MIN ( 0.0F ) ///< Minimum ultrafiltration rate (in mL/min). #define MAX_UF_VOLUME_ML ( 8 * ML_PER_LITER ) ///< Maximum ultrafiltration volume (in mL). +#define MIN_ISOLATED_UF_DURATION_MIN ( 30 ) ///< Minimum isolated UF session duration (in min). +#define MIN_ISOLATED_UF_VOLUME_ML ( 0.1F * (F32)ML_PER_LITER ) ///< Minimum isolated UF volume (in mL). /// Record structure for a treatment parameters payload from UI. typedef struct