Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -reef41b7363d82763095a1317f1757f360f0d9ec1 -rf0ea13c1a9908920793be07a946dc366d2ab5019 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision eef41b7363d82763095a1317f1757f360f0d9ec1) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision f0ea13c1a9908920793be07a946dc366d2ab5019) @@ -22,6 +22,7 @@ #include "DDInterface.h" #include "ModeService.h" #include "ModeTreatment.h" +#include "Messaging.h" //#include "NVDataMgmt.h" #include "OperationModes.h" #include "Pressures.h" @@ -43,6 +44,8 @@ #define MAX_TREATMENT_TIME_MINUTES ( 8 * MIN_PER_HOUR ) ///< Maximum treatment time (in minutes). #define MIN_TREATMENT_TIME_MINUTES ( 1 * MIN_PER_HOUR ) ///< Minimum treatment time (in minutes). +#define MAX_BOLUS_VOLUME_ML ( 300 ) ///< Minimum fluid bolus volume (in mL). +#define MIN_BOLUS_VOLUME_ML ( 100 ) ///< Maximum fluid bolus volume (in mL). /// Interval (ms/task time) at which the treatment time data is published on the CAN bus. #define TREATMENT_TIME_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) @@ -819,6 +822,229 @@ /*********************************************************************//** * @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, duration, UF volume goal, and UF rate. + * @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 elapsedTreatmentTimeMin = 0.0F; + F32 measuredUFVolumeL = 0.0F; + F32 remainingUFVolumeL = 0.0F; + F32 remainingTreatmentTimeHr = 0.0F; + F32 newUfRateLHr = 0.0F; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.duration = 0; + response.ufVolumeGoal = 0.0F; + response.ufRate = 0.0F; + + if ( message->hdr.payloadLen == sizeof( DURATION_VALIDATE_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( request ) ); + + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + response.duration = request.duration; + + if ( ( request.duration >= MIN_TREATMENT_TIME_MINUTES ) && + ( request.duration <= MAX_TREATMENT_TIME_MINUTES ) ) + { + elapsedTreatmentTimeMin = (F32)treatmentTimeMS / (F32)MS_PER_SECOND / (F32)SEC_PER_MIN; + + if ( (F32)request.duration <= elapsedTreatmentTimeMin ) + { + response.accepted = FALSE; + 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; + + response.ufVolumeGoal = presUFVolumeL; + response.ufRate = newUfRateLHr; + + if ( newUfRateLHr <= 2.0F ) + { + response.accepted = TRUE; + } + else + { + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; + } + } + else + { + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; + } + } + } + else + { + response.accepted = FALSE; + 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 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. + * @return TRUE if response message is sent successfully, FALSE otherwise. + *************************************************************************/ +BOOL signalUserConfirmationOfTreatmentDuration( MESSAGE_T *message ) +{ + BOOL result = FALSE; + DURATION_CONFIRM_REQUEST_PAYLOAD_T request; + TREATMENT_TIME_CHANGE_RESPONSE_PAYLOAD_T response; + F32 elapsedTreatmentTimeMin = 0.0F; + F32 measuredUFVolumeL = 0.0F; + F32 remainingUFVolumeL = 0.0F; + F32 remainingTreatmentTimeHr = 0.0F; + + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + response.duration = 0; + response.volume = 0.0F; + + if ( message->hdr.payloadLen == sizeof( DURATION_CONFIRM_REQUEST_PAYLOAD_T ) ) + { + memcpy( &request, &message->payload[ 0 ], sizeof( request ) ); + + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + response.duration = request.duration; + response.volume = presUFVolumeL; + + if ( ( request.duration >= MIN_TREATMENT_TIME_MINUTES ) && + ( request.duration <= MAX_TREATMENT_TIME_MINUTES ) ) + { + elapsedTreatmentTimeMin = (F32)treatmentTimeMS / (F32)MS_PER_SECOND / (F32)SEC_PER_MIN; + + if ( (F32)request.duration <= elapsedTreatmentTimeMin ) + { + response.accepted = FALSE; + 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 ) + { + presTreatmentTimeSecs = request.duration * SEC_PER_MIN; + presUFRateLHr = remainingUFVolumeL / remainingTreatmentTimeHr; + + setTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION, request.duration ); + + setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), + presUFVolumeL, + presUFRateLHr ); + + response.accepted = TRUE; + } + else + { + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; + } + } + } + else + { + response.accepted = FALSE; + response.rejectionReason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; + } + } + + result = sendMessage( MSG_ID_TD_DURATION_CONFIRM_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; + + 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; + + if ( ( request.bolusVolume >= MIN_BOLUS_VOLUME_ML ) && + ( request.bolusVolume <= MAX_BOLUS_VOLUME_ML ) ) + { + response.accepted = TRUE; + response.rejectionReason = REQUEST_REJECT_REASON_NONE; + + // TODO: Add state validation and apply bolus volume when saline bolus feature is integrated. + } + 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 broadcastTreatmentTimeAndState function broadcasts treatment time and * state data during treatment. * @details \b Inputs: treatmentTimeBroadcastTimerCtr, elapsedTreatmentTimeInSecs,