Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -rc92e2b5ae61f359e5633b32b2d5b691347d0d293 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision c92e2b5ae61f359e5633b32b2d5b691347d0d293) @@ -948,7 +948,7 @@ // Compute minimum UF volume F32 minUFVol = 0.0F; // TODO getUltrafiltrationReferenceVolume() + presUFRate; // current UF volume + 1 min at current rate // Compute maximum UF volume (considering from adjustment of UF rate and time perspectives) - F32 maxUFVol1 = minUFVol + ( (F32)( presTime - elapseTime ) * MAX_UF_RATE_ML_MIN ); + F32 maxUFVol1 = minUFVol + ( (F32)( presTime - elapseTime ) * MAX_UF_RATE_ML_MIN ); F32 maxUFVol2 = ( presUFRateLHr > 0.0F ? minUFVol + ( (F32)( MAX_TREATMENT_TIME_MINUTES - elapseTime - 1 ) * presUFRateLHr ) : minUFVol ); F32 maxUFVol = MAX( maxUFVol1, maxUFVol2 ); // Set minimum dialysate flow rate Index: firmware/App/Modes/ModeTreatment.h =================================================================== diff -u -r421336466eff4ba9fef0ca5416043e5d83c63841 -rc92e2b5ae61f359e5633b32b2d5b691347d0d293 --- firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision 421336466eff4ba9fef0ca5416043e5d83c63841) +++ firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision c92e2b5ae61f359e5633b32b2d5b691347d0d293) @@ -7,8 +7,8 @@ * * @file ModeTreatment.h * -* @author (last) Varshini Nagabooshanam -* @date (last) 09-Jan-2026 +* @author (last) Raghu Kallala +* @date (last) 06-Apr-2026 * * @author (original) Sean Nash * @date (original) 21-Apr-2025 @@ -85,13 +85,23 @@ U32 ufState; ///< Ultrafiltration state. } UF_DATA_PAYLOAD_T; +/// Payload record structure for the in-line pressure limits change response. +typedef struct +{ + BOOL accepted; ///< Accepted. + U32 rejReasonCode; ///< Rejection reason code number. + U32 artPresLimitWindowmmHg; ///< Arterial pressure limit window in mmHg. + U32 venPresLimitWindowmmHg; ///< Venous pressure limit window in mmHg. + U32 venPresLimitAsymmetricmmHg; ///< Venous pressure limit asymmetric in mmHg. + U32 tmpPresLimitWindowmmHg; ///< TMP pressure limit window in mmHg. +} PRESSURE_LIMIT_CHANGE_RESPONSE_T; +#pragma pack(pop) + /// Maximum time in this mode before blood sitting alarm given (in general task intervals). #define MAX_TIME_BLOOD_SITTING ( ( 5 * SEC_PER_MIN * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) /// Maximum time in this mode before blood sitting warning given (in general task intervals). #define WARN_TIME_BLOOD_SITTING ( ( 4 * SEC_PER_MIN * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) -#pragma pack(pop) - // ********** public function prototypes ********** void initTreatmentMode( void ); // Initialize this unit @@ -115,6 +125,9 @@ U32 getTreatmentStartTimeStamp( void ); // Get the treatment start time stamp U32 getTreatmentEndTimeStamp( void ); // Get the treatment end time stamp +// MSG_ID_TD_PRESSURE_LIMITS_CHANGE_RESPONSE +BOOL sendPressureLimitsChangeResponse( PRESSURE_LIMIT_CHANGE_RESPONSE_T *data ); + /**@}*/ #endif Index: firmware/App/Modes/StateTxDialysis.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -rc92e2b5ae61f359e5633b32b2d5b691347d0d293 --- firmware/App/Modes/StateTxDialysis.c (.../StateTxDialysis.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Modes/StateTxDialysis.c (.../StateTxDialysis.c) (revision c92e2b5ae61f359e5633b32b2d5b691347d0d293) @@ -233,17 +233,17 @@ } /*********************************************************************//** - * @brief - * The signalPauseResumeUF function handles a request to pause or resume - * ultrafiltration. - * @details \b Message \b Sent: MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE - * @details \b Message \b Sent: UF_START_PAUSE_EVENT / UF_START_RESUME_EVENT - * @details \b Inputs: currentDialysisState, setUFRateLHr - * @details \b Outputs: ufPauseRequested, ufResumeRequested - * @param message Message from UI which includes a flag indicating whether - * to pause or resume ultrafiltration. - * @return TRUE if pause - *************************************************************************/ +* @brief +* The signalPauseResumeUF function handles a request to pause or resume +* ultrafiltration. +* @details \b Message \b Sent: MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE +* @details \b Message \b Sent: UF_START_PAUSE_EVENT / UF_START_RESUME_EVENT +* @details \b Inputs: currentDialysisState, setUFRateLHr +* @details \b Outputs: ufPauseRequested, ufResumeRequested +* @param message Message from UI which includes a flag indicating whether +* to pause or resume ultrafiltration. +* @return TRUE if pause +*************************************************************************/ BOOL signalPauseResumeUF( MESSAGE_T *message ) { TREATMENT_STATE_T trtState = getTreatmentState(); Index: firmware/App/Services/Messaging.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -rc92e2b5ae61f359e5633b32b2d5b691347d0d293 --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision c92e2b5ae61f359e5633b32b2d5b691347d0d293) @@ -108,10 +108,16 @@ { MSG_ID_DD_OP_MODE_DATA, &setDDOpMode }, { MSG_ID_DD_PRESSURES_DATA, &setDialysatePressure }, { MSG_ID_UI_TREATMENT_PARAMS_TO_VALIDATE, &validateAndSetTreatmentParameters }, + { MSG_ID_UI_ULTRAFILTRATION_VOLUME_TO_VALIDATE, &validateAndSetUFVolume }, + { MSG_ID_UI_ULTRAFILTRATION_CHANGE_VALIDATE_REQUEST, &signalUserConfirmationOfUFVolume }, + { MSG_ID_UI_DURATION_VALIDATE_REQUEST, &validateAndSetTreatmentDuration }, + { MSG_ID_UI_DURATION_CONFIRM_REQUEST, &signalUserConfirmationOfTreatmentDuration }, + { MSG_ID_UI_BOLUS_VOLUME_CHANGE_REQUEST, &validateAndSetBolusVolume }, { MSG_ID_UI_INITIATE_TREATMENT_WORKFLOW, &signalUserInitiateTreatment }, { MSG_ID_UI_UF_PAUSE_RESUME_REQUEST, &signalPauseResumeUF }, { 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_BLOOD_PRIME_CMD_REQUEST, &bloodPrimeHandleCmdRequest }, { MSG_ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_REQUEST, &bloodPrimeHandleBloodFlowChangeRequest }, { MSG_ID_TD_SOFTWARE_RESET_REQUEST, &testTDSoftwareResetRequest }, Index: firmware/App/Services/TxParams.c =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -rc92e2b5ae61f359e5633b32b2d5b691347d0d293 --- firmware/App/Services/TxParams.c (.../TxParams.c) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/TxParams.c (.../TxParams.c) (revision c92e2b5ae61f359e5633b32b2d5b691347d0d293) @@ -181,6 +181,11 @@ static BOOL validTreatParamsReceived = FALSE; ///< Flag indicates user has provided treatment parameters. static BOOL treatParamsConfirmed = FALSE; ///< Flag indicates user has confirmed the treatment parameters. +static BOOL validTreatmentDurationReceived = FALSE; ///< Flag indicates valid treatment duration was validated. +static U32 validatedTreatmentDuration_min = 0U; ///< Last validated treatment duration in minutes. +static F32 validatedUFVolumeGoalL = 0.0F; ///< Last validated UF volume goal in L. +static F32 validatedUFRateLhr = 0.0F; ///< Last validated UF rate in L/hr. +static BOOL validUFVolumeReceived = FALSE; ///< Flag indicates valid UF volume was validated. // ********** private function prototypes ********** @@ -193,6 +198,12 @@ static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_PAYLOAD_T payload ); //static void checkPressureParamsRange( TREATMENT_PARAMS_DATA_PAYLOAD_T* txParams ); static void sendTreatmentParamsResponse( BOOL rejected, U32 *reasons ); +static BOOL isPressureLimitValueValid( S32 value, S32 minValue, S32 maxValue ); +static BOOL isArterialPressureLimitWindowValid( S32 value ); +static BOOL isVenousPressureLimitWindowValid( S32 value ); +static BOOL isVenousAsymmetricPressureLimitWindowValid( S32 value ); +static BOOL isTmpPressureLimitWindowValid( S32 value ); + //static void getInstitutionalRecordEdgeValue( TREATMENT_PARAM_T param, CRITICAL_DATAS_T* value, BOOL isMin ); /*********************************************************************//** @@ -1405,6 +1416,577 @@ /************************************************************************* + * 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), and calculated UF rate (L/hr). + * @details \b Inputs: + * message containing requested treatment duration (minutes). + * @details \b Outputs: + * validated treatment duration and UF rate stored for + * confirmation. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL validateAndSetTreatmentDuration( MESSAGE_T *message ) +{ + BOOL result = FALSE; + DURATION_VALIDATE_REQUEST_PAYLOAD_T request; + 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 ); + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.duration = 0U; + response.ufVolumeGoal = 0.0F; + response.ufRate = 0.0F; + + // Clear previously validated values. + validTreatmentDurationReceived = FALSE; + validatedTreatmentDuration_min = 0U; + validatedUFRateLhr = 0.0F; + + if ( message->hdr.payloadLen == sizeof( DURATION_VALIDATE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( 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 ) + { + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // Store validated values for confirmation step. + validTreatmentDurationReceived = TRUE; + validatedTreatmentDuration_min = response.duration; + 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_TREATMENT_TIME_OUT_OF_RANGE; + } + } + + result = sendMessage( MSG_ID_TD_DURATION_VALIDATE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( 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: + * message containing 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; + BOLUS_VOLUME_CHANGE_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( BOLUS_VOLUME_CHANGE_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @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 + * @details \b Inputs: message containing requested pressure limit + * window values. + * @details \b Outputs: response updated with acceptance status and + * per-parameter rejection reasons. When accepted, treatment + * parameters are updated and pressure limits recalculated. + * @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.accepted = FALSE; + 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.venousPressureLimitWindowMMHG ) ) + { + response.venousPressureLimitWindowRejectionReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + if ( FALSE == isVenousAsymmetricPressureLimitWindowValid( request.venousAsymmetricPressureLimitWindowMMHG ) ) + { + 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 ) + { + setTreatmentParameterU32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW, request.arterialPressureLimitWindowMMHG ); + + setTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW, request.venousPressureLimitWindowMMHG ); + + setTreatmentParameterU32( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC, request.venousAsymmetricPressureLimitWindowMMHG ); + + setTreatmentParameterU32( 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: value, minValue, maxValue. + * @details \b Outputs: none. + * @return TRUE if value is valid, FALSE otherwise. + *************************************************************************/ +static BOOL isPressureLimitValueValid( S32 value, S32 minValue, S32 maxValue ) +{ + return ( ( value >= minValue ) && ( value <= maxValue ) ); +} + +/*********************************************************************//** + * @brief + * Validates the arterial pressure limit window value. + * @details This function checks whether the provided arterial pressure + * limit window value is within the allowable range defined in + * treatment parameter limits. + * @param value Arterial pressure limit window value (mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isArterialPressureLimitWindowValid( S32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( + value, + (S32)getU32SysConfigTreatmentParamLowerRangeLimit( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ), + (S32)getU32SysConfigTreatmentParamUpperRangeLimit( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief + * Validates the venous pressure limit window value. + * @details This function checks whether the provided venous pressure + * limit window value is within the allowable range defined in + * treatment parameter limits. + * @param value Venous pressure limit window value (mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isVenousPressureLimitWindowValid( S32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( + value, + (S32)getU32SysConfigTreatmentParamLowerRangeLimit( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ), + (S32)getU32SysConfigTreatmentParamUpperRangeLimit( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief + * Validates the venous asymmetric pressure limit window value. + * @details This function checks whether the provided venous asymmetric + * pressure limit window value is within the allowable range + * defined in treatment parameter limits. + * @param value Venous asymmetric pressure limit window value (mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isVenousAsymmetricPressureLimitWindowValid( S32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( + value, + (S32)getU32SysConfigTreatmentParamLowerRangeLimit( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ), + (S32)getU32SysConfigTreatmentParamUpperRangeLimit( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief + * Validates the TMP pressure limit window value. + * @details This function checks whether the provided TMP pressure + * limit window value is within the allowable range defined in + * treatment parameter limits. + * @param value TMP pressure limit window value (mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isTmpPressureLimitWindowValid( S32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( + value, + (S32)getU32SysConfigTreatmentParamLowerRangeLimit( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ), + (S32)getU32SysConfigTreatmentParamUpperRangeLimit( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief + * The validateAndSetUFVolume function validates the received ultrafiltration + * volume treatment parameter. + * @details \b Message \b Sent: + * MSG_ID_TD_RESP_ULTRAFILTRATION_VOLUME_TO_VALIDATE including + * acceptance status, rejection reason, UF volume goal (L), + * duration (minutes), and UF rate (L/hr). + * @details \b Inputs: + * message containing requested UF volume in L. + * @details \b Outputs: + * validated UF volume and UF rate stored for confirmation. + * @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.duration = 0U; + 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; + response.duration = (U32)treatmentDurationMin; + + 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_RESP_ULTRAFILTRATION_VOLUME_TO_VALIDATE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UF_VOLUME_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, rejection reason, duration (minutes), UF volume goal + * (L), and UF rate (L/hr). + * @details \b Inputs: + * message containing confirmed treatment duration and UF rate. + * @details \b Outputs: + * validated duration and UF rate cleared after confirmation. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL signalUserConfirmationOfTreatmentDuration( MESSAGE_T *message ) +{ + BOOL result = FALSE; + DURATION_CONFIRM_REQUEST_PAYLOAD_T request; + DURATION_VALIDATE_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; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.duration = 0U; + response.ufVolumeGoal = 0.0F; + response.ufRate = 0.0F; + + if ( message->hdr.payloadLen == sizeof( DURATION_CONFIRM_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( DURATION_CONFIRM_REQUEST_PAYLOAD_T ) ); + + // Echo values for confirmation screen. + response.duration = request.duration; + response.ufVolumeGoal = presUFVolumeMl / (F32)ML_PER_LITER; + response.ufRate = validatedUFRateLhr; + + if ( ( TRUE == validTreatmentDurationReceived ) && ( request.duration == validatedTreatmentDuration_min ) && ( fabs( request.ufRate - validatedUFRateLhr ) < NEARLY_ZERO ) ) + { + setTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION, validatedTreatmentDuration_min ); + 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; + } + 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( DURATION_VALIDATE_RESPONSE_PAYLOAD_T ) ); + + return result; +} + +/*********************************************************************//** + * @brief + * The signalUserConfirmationOfUFVolume function handles the UI + * confirmation request for ultrafiltration (UF) volume change. + * @details \b Message \b Sent: + * MSG_ID_TD_ULTRAFILTRATION_CHANGE_VALIDATE_RESPONSE including + * acceptance status, rejection reason, UF volume goal (L), + * duration (minutes), and UF rate (L/hr). + * @details \b Inputs: + * message containing confirmed UF volume and UF rate. + * @details \b Outputs: + * validated UF volume and UF rate cleared after confirmation. + * @param message set message from UI which includes the confirmed + * ultrafiltration 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; + UF_VOLUME_RESPONSE_PAYLOAD_T response; + F32 validatedUFVolumeGoalMl = 0.0F; + F32 validatedUFRateMlMin = 0.0F; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.ufVolumeGoal = 0.0F; + response.duration = 0U; + response.ufRate = 0.0F; + + if ( message->hdr.payloadLen == sizeof( UF_VOLUME_CONFIRM_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( UF_VOLUME_CONFIRM_REQUEST_PAYLOAD_T ) ); + + // Echo values for confirmation screen. + response.ufVolumeGoal = request.ufVolume; + response.duration = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + response.ufRate = validatedUFRateLhr; + + validatedUFVolumeGoalMl = validatedUFVolumeGoalL * (F32)ML_PER_LITER; + validatedUFRateMlMin = ( validatedUFRateLhr * (F32)ML_PER_LITER ) / (F32)MIN_PER_HOUR; + + if ( ( TRUE == validUFVolumeReceived ) && ( fabs( request.ufVolume - validatedUFVolumeGoalL ) < NEARLY_ZERO ) && ( fabs( request.ufRate - validatedUFRateLhr ) < NEARLY_ZERO ) ) + { + setTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME, validatedUFVolumeGoalL ); + + 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_VALIDATE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( UF_VOLUME_RESPONSE_PAYLOAD_T ) ); + + return result; +} + + +/************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Services/TxParams.h =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -rc92e2b5ae61f359e5633b32b2d5b691347d0d293 --- firmware/App/Services/TxParams.h (.../TxParams.h) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Services/TxParams.h (.../TxParams.h) (revision c92e2b5ae61f359e5633b32b2d5b691347d0d293) @@ -86,6 +86,93 @@ U32 maxDialRate; ///< Maximum dialysate flow rate (in mL/min) } TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T; +/// Payload record structure for treatment duration validate request. +typedef struct +{ + U32 duration; ///< Requested treatment duration in minutes. +} DURATION_VALIDATE_REQUEST_PAYLOAD_T; + +/// Payload record structure for treatment duration confirm request. +typedef struct +{ + U32 duration; ///< Confirmed treatment duration in minutes. + F32 ufRate; ///< Confirmed UF rate in L/hr. +} 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. + F32 ufVolumeGoal; ///< UF volume goal in L. + F32 ufRate; ///< UF rate in L/hr. +} 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 bolus volume change response. +typedef struct +{ + BOOL accepted; ///< Accepted/Rejected + U32 rejectionReason; ///< Rejection reason if not accepted +} BOLUS_VOLUME_CHANGE_RESPONSE_PAYLOAD_T; + +/// Payload record structure for pressure limit change request. +typedef struct +{ + S32 arterialPressureLimitWindowMMHG; ///< Arterial pressure limit window in mmHg. + S32 venousPressureLimitWindowMMHG; ///< Venous pressure limit window in mmHg. + S32 venousAsymmetricPressureLimitWindowMMHG; ///< Venous asymmetric pressure limit window in mmHg. + S32 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. + U32 duration; ///< new Treatment duration in minutes. + F32 ufRate; ///< new UF rate in L/hr. +} UF_VOLUME_RESPONSE_PAYLOAD_T; + +/// Payload record structure for blood / dialysate rate change response. +typedef struct +{ + BOOL accepted; ///< Accepted/Rejected + U32 rejectionReason; ///< Rejection reason if not accepted. + U32 bloodRate; ///< new blood flow rate + U32 dialRate; ///< new dialysate flow rate +} BLOOD_DIAL_RATE_CHANGE_RESPONSE_PAYLOAD_T; + // ********** public function prototypes **************** BOOL setTreatmentParameterU32( TREATMENT_PARAM_T param, U32 value ); // Set a specified unsigned integer treatment parameter value @@ -94,10 +181,16 @@ 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 +// 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 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 signalUserConfirmationOfTreatmentDuration( MESSAGE_T *message ); // Process UI confirm/reject treatment duration +BOOL signalUserConfirmationOfUFVolume( MESSAGE_T *message ); // Process UI confirm/reject ultrafiltration volume change + void resetTreatmentParameters( void ); // Reset all parameters to defaults -//BOOL signalUserConfirmationOfTreatmentParameters( MESSAGE_T *message ); // Process UI confirm/reject Treatment parameters BOOL getValidTreatParamsReceived( void ); // Determine whether valid Treatment Parameters exist BOOL getTreatParamsConfirmed( void ); // Determine whether user confirmed the parameters