Index: firmware/App/Services/TxParams.c =================================================================== diff -u -r6f02ff4686ec9dfc60247e9ed3fc9c5cc7771543 -r421336466eff4ba9fef0ca5416043e5d83c63841 --- firmware/App/Services/TxParams.c (.../TxParams.c) (revision 6f02ff4686ec9dfc60247e9ed3fc9c5cc7771543) +++ firmware/App/Services/TxParams.c (.../TxParams.c) (revision 421336466eff4ba9fef0ca5416043e5d83c63841) @@ -146,6 +146,9 @@ 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 validatedUFRateLHr = 0.0F; ///< Last validated UF rate in L/hr. // ********** private function prototypes ********** @@ -155,6 +158,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 ); /*********************************************************************//** @@ -650,6 +659,311 @@ /*********************************************************************//** * @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 + * @details \b Inputs: message containing requested treatment duration. + * @details \b Outputs: response updated with acceptance status, rejection + * reason, requested duration, proposed UF volume goal, and + * proposed UF rate. When accepted, validated values are stored + * for use during 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 presUFVolumeL = 0.0F; + F32 elapsedTreatmentTimeMin = 0.0F; + F32 measuredUFVolumeL = 0.0F; + F32 remainingUFVolumeL = 0.0F; + F32 remainingTreatmentTimeHr = 0.0F; + F32 newUfRateLHr = 0.0F; + F32 newUfRateMlMin = 0.0F; + U32 minDuration = 0U; + U32 maxDuration = 0U; + + 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( request ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( request ) ); + + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + response.duration = request.duration; + + presUFVolumeL = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); + + minDuration = getU32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ); + maxDuration = getU32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ); + + if ( ( request.duration >= minDuration ) && + ( request.duration <= maxDuration ) ) + { + elapsedTreatmentTimeMin = (F32)getActualTreatmentTimeSecs() / (F32)SEC_PER_MIN; + + if ( (F32)request.duration <= elapsedTreatmentTimeMin ) + { + response.rejectionReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; + } + else + { + measuredUFVolumeL = getUltrafiltrationVolumeDrawn(); + remainingUFVolumeL = presUFVolumeL - measuredUFVolumeL; + + if ( remainingUFVolumeL < 0.0F ) + { + remainingUFVolumeL = 0.0F; + } + + remainingTreatmentTimeHr = ( (F32)request.duration - elapsedTreatmentTimeMin ) / (F32)MIN_PER_HOUR; + + if ( remainingTreatmentTimeHr > 0.0F ) + { + newUfRateLHr = remainingUFVolumeL / remainingTreatmentTimeHr; + newUfRateMlMin = newUfRateLHr * (F32)ML_PER_LITER / (F32)MIN_PER_HOUR; + + response.ufVolumeGoal = presUFVolumeL; + response.ufRate = newUfRateLHr; + + if ( newUfRateMlMin <= MAX_UF_RATE_ML_MIN ) + { + response.accepted = TRUE; + + // Store validated values for confirmation. + validTreatmentDurationReceived = TRUE; + validatedTreatmentDuration_min = request.duration; + validatedUFRateLHr = newUfRateLHr; + } + 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( response ) ); + + 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 + * @details \b Inputs: message containing requested bolus volume. + * @details \b Outputs: response updated with acceptance status, + * rejection reason, and 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 = 0U; + U32 maxBolusVolume_mL = 0U; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.bolusVolume = 0U; + + if ( message->hdr.payloadLen == sizeof( BOLUS_VOLUME_CHANGE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( request ) ); + + response.bolusVolume = request.bolusVolume; + + minBolusVolume_mL = getU32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); + maxBolusVolume_mL = getU32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); + + if ( ( request.bolusVolume >= minBolusVolume_mL ) && + ( request.bolusVolume <= maxBolusVolume_mL ) ) + { + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + setTreatmentParameterU32( TREATMENT_PARAM_SALINE_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( response ) ); + + 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, rejection + * reason, and pressure limit window values. 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 pressureLimitsValid = FALSE; + REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + PRESSURE_LIMIT_CHANGE_REQUEST_T request = { 0 }; + PRESSURE_LIMIT_CHANGE_RESPONSE_T response = { 0 }; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( message->hdr.payloadLen == sizeof( request ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( request ) ); + + pressureLimitsValid = isArterialPressureLimitWindowValid( request.arterialPressureLimitWindowMMHG ) && + isVenousPressureLimitWindowValid( request.venousPressureLimitWindowMMHG ) && + isVenousAsymmetricPressureLimitWindowValid( request.venousAsymmetricPressureLimitWindowMMHG ) && + isTmpPressureLimitWindowValid( request.tmpPressureLimitWindowMMHG ); + + if ( TRUE == pressureLimitsValid ) + { + setTreatmentParameterS32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW, + request.arterialPressureLimitWindowMMHG ); + + setTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW, + request.venousPressureLimitWindowMMHG ); + + setTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC, + request.venousAsymmetricPressureLimitWindowMMHG ); + + setTreatmentParameterS32( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW, + request.tmpPressureLimitWindowMMHG ); + + updatePressureLimitWindows(); + + result = TRUE; + rejReason = REQUEST_REJECT_REASON_NONE; + } + else + { + rejReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + } + + response.accepted = result; + response.rejectionReason = rejReason; + response.arterialPressureLimitWindowMMHG = request.arterialPressureLimitWindowMMHG; + response.venousPressureLimitWindowMMHG = request.venousPressureLimitWindowMMHG; + response.venousAsymmetricPressureLimitWindowMMHG = request.venousAsymmetricPressureLimitWindowMMHG; + response.tmpPressureLimitWindowMMHG = request.tmpPressureLimitWindowMMHG; + + sendMessage( MSG_ID_TD_PRESSURE_LIMITS_CHANGE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( response ) ); + + 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 (in mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isArterialPressureLimitWindowValid( S32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( value, getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ), getS32TreatmentParamUpperRangeLimit( 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 (in mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isVenousPressureLimitWindowValid( S32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( value, getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ), getS32TreatmentParamUpperRangeLimit( 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 (in mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isVenousAsymmetricPressureLimitWindowValid( S32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( value, getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ), getS32TreatmentParamUpperRangeLimit( 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 (in mmHg). + * @return TRUE if the value is within valid range, FALSE otherwise. + *************************************************************************/ +static BOOL isTmpPressureLimitWindowValid( S32 value ) +{ + BOOL pressureValid; + + pressureValid = isPressureLimitValueValid( value, getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ), getS32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_TMP_PRES_LIMIT_WINDOW ) ); + + return pressureValid; +} + +/*********************************************************************//** + * @brief * The resetTreatmentParameters function resets the Treatment Parameters * session flags and parameter values. * @details Inputs: none @@ -733,6 +1047,120 @@ /*********************************************************************//** * @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 + * @details \b Inputs: message containing confirmed treatment duration. + * @details \b Outputs: response updated with acceptance status, rejection + * reason, duration, and UF volume. The confirmed duration is applied + * only when it matches the previously validated duration. + * @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 presUFVolumeL = 0.0F; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.duration = 0U; + response.ufRate = 0.0F; + + if ( message->hdr.payloadLen == sizeof( request ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( request ) ); + + response.duration = request.duration; + response.ufVolumeGoal = presUFVolumeL; + response.ufRate = validatedUFRateLHr; + + if ( ( TRUE == validTreatmentDurationReceived ) && + ( request.duration == validatedTreatmentDuration_min ) ) + { + + setTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION, validatedTreatmentDuration_min ); + setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFVolumeL , validatedUFRateLHr ); + + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // Clear validated values after successful apply. + validTreatmentDurationReceived = FALSE; + validatedTreatmentDuration_min = 0U; + validatedUFRateLHr = 0.0F; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } + } + + result = sendMessage( MSG_ID_TD_DURATION_CONFIRM_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08 *)&response, sizeof( response ) ); + + 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 + * @details \b Inputs: message containing requested UF volume (mL). + * @details \b Outputs: response updated with acceptance status and + * rejection reason. + * @param message set message from UI which includes the user set + * ultrafiltration volume. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL signalUserConfirmationOfUFVolume( MESSAGE_T *message ) +{ + BOOL result = FALSE; + UI_RESPONSE_PAYLOAD_T response; + F32 requestedUFVolumeMl = 0.0F; + F32 requestedUFVolumeL = 0.0F; + F32 storedUFVolumeL = 0.0F; + F32 treatmentDurationMin = 0.0F; + F32 newUFRateLHr = 0.0F; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + + if ( sizeof( F32 ) == message->hdr.payloadLen ) + { + memcpy( &requestedUFVolumeMl, message->payload, sizeof( requestedUFVolumeMl ) ); + + requestedUFVolumeL = requestedUFVolumeMl / (F32)ML_PER_LITER; + storedUFVolumeL = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ); + + if ( requestedUFVolumeL == storedUFVolumeL ) + { + treatmentDurationMin = (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + + if ( treatmentDurationMin > 0.0F ) + { + newUFRateLHr = storedUFVolumeL / ( treatmentDurationMin / (F32)MIN_PER_HOUR ); + + setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), storedUFVolumeL, newUFRateLHr ); + + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + } + else + { + response.rejectionReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_MINIMUM; + } + } + } + + result = sendMessage( MSG_ID_TD_ULTRAFILTRATION_CHANGE_VALIDATE_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)&response, sizeof( response ) ); + + return result; +} + +/*********************************************************************//** + * @brief * The extractTreatmentParamsFromPayload function extracts the individual * treatment parameters received from the UI into a staging array where * they will be validated and stay until user confirms them.