Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -rda59fa4a98dbc11c37677e92a66aa940d251678f -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision da59fa4a98dbc11c37677e92a66aa940d251678f) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) @@ -28,6 +28,7 @@ #include "Pressures.h" #include "StateTxBloodPrime.h" #include "StateTxDialysis.h" +#include "StateTxIsolatedUF.h" #include "StateTxPaused.h" //#include "Switches.h" #include "TaskGeneral.h" @@ -81,6 +82,7 @@ static U32 treatmentStateBroadcastTimerCtr; ///< Treatment state data broadcast timer counter used to schedule when to transmit data. static U32 treatmentParamsRangesBroadcastTimerCtr; ///< Treatment parameter ranges broadcast timer counter used to schedule when to transmit updated ranges. static U32 ultrafiltrationBroadcastTimerCtr; ///< Ultrafiltration data broadcast timer counter used to schedule when to transmit data. +static U32 isolatedUFBroadcastTimerCtr; ///< Isolated UF data broadcast timer counter used to schedule when to transmit data. static U32 salineBolusBroadcastTimerCtr; ///< Saline bolus data broadcast timer counter used to schedule when to transmit data. /// Interval (in task intervals) at which to publish alarm status to CAN bus. @@ -96,6 +98,12 @@ 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 U32 treatmentStartTimeStamp; ///< Treatment start timestamp for logging purpose. static U32 treatmentEndTimeStamp; ///< Treatment end timestamp for logging purpose. @@ -106,6 +114,7 @@ static void broadcastTreatmentPeriodicData(); static void publishSalineBolusData( void ); // TODO - move to StateTxSalineBolus.c when implemented static void publishUltrafiltrationData( void ); +static void publishIsolatedUFData( void ); static U32 getMinTreatmentTimeInMinutes( void ); static TREATMENT_STATE_T handleTreatmentStartState( void ); static TREATMENT_STATE_T handleTreatmentBloodPrimeState( void ); @@ -117,8 +126,10 @@ static TREATMENT_STATE_T handleTreatmentRinsebackState( void ); static TREATMENT_STATE_T handleTreatmentRecircState( void ); static TREATMENT_STATE_T handleTreatmentEndState( void ); +static TREATMENT_STATE_T enterTreatmentPausedState( void ); static void resetSignalFlags( void ); static void resetAlarmSignalFlags( void ); +static void resumeDialysisAfterIsolatedUF( void ); /*********************************************************************//** * @brief @@ -135,6 +146,8 @@ treatmentCompleted = FALSE; rinsebackDone = FALSE; resumeBlockedByAlarm = FALSE; + isolatedUFStartRequested = FALSE; + isolatedUFMidTreatment = FALSE; treatmentTimePublishInterval.data = TREATMENT_TIME_DATA_PUB_INTERVAL; treatmentTimePublishInterval.ovData = TREATMENT_TIME_DATA_PUB_INTERVAL; @@ -155,11 +168,15 @@ treatmentStateBroadcastTimerCtr = TREATMENT_STATE_DATA_PUB_INTERVAL; // So we send state data immediately when we begin treatment mode treatmentParamsRangesBroadcastTimerCtr = TREATMENT_SETTINGS_RANGES_PUB_INTERVAL; // So we send ranges immediately when we begin treatment mode ultrafiltrationBroadcastTimerCtr = ULTRAFILTRATION_DATA_PUB_INTERVAL; // So we send ultrafiltration immediately when we begin treatment mode + isolatedUFBroadcastTimerCtr = ULTRAFILTRATION_DATA_PUB_INTERVAL; // So we send isolated UF immediately when we enter isolated UF salineBolusBroadcastTimerCtr = SALINE_BOLUS_DATA_PUB_INTERVAL; // So we send saline bolus data immediately when we begin treatment mode presTreatmentTimeSecs = 0; presUFVolumeMl = 0.0F; presUFRateMlMin = 0.0F; + isolatedUFDurationMin = 0; + isolatedUFSetVolumeMl = 0.0F; + isolatedUFRateMlMin = 0.0F; resetSignalFlags(); resetAlarmSignalFlags(); @@ -170,6 +187,22 @@ /*********************************************************************//** * @brief + * The enterTreatmentPausedState function saves the current treatment sub-state + * and transitions to the treatment paused sub-mode. + * @details \b Inputs: currentTreatmentState + * @details \b Outputs: treatmentStateBeforePause, treatment paused sub-mode entered + * @return TREATMENT_PAUSED_STATE + *************************************************************************/ +static TREATMENT_STATE_T enterTreatmentPausedState( void ) +{ + treatmentStateBeforePause = currentTreatmentState; + transitionToTreatmentPaused(); + + return TREATMENT_PAUSED_STATE; +} + +/*********************************************************************//** + * @brief * The transitionToTreatmentMode function prepares for transition to treatment * mode. * @details \b Inputs: none @@ -189,6 +222,7 @@ // Initialize treatment sub-modes each time we transition to treatment mode initBloodPrime(); initDialysis(); + initIsolatedUF(); initTreatmentPaused(); // initRinseback(); // initTreatmentRecirc(); @@ -212,8 +246,15 @@ setDialysisDDParams( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFVolumeMl, presUFRateMlMin ); bicarbConvFactor = BICARBONATE_CONVERSION_FACTOR; - // Direct DD to generate dialysate and bypass while priming blood - cmdStartGenerateDialysate( (F32)getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presUFRateMlMin, + 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 ), getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ), TRUE, getTreatmentParameterF32( TREATMENT_PARAM_ACID_CONCENTRATE_CONV_FACTOR ), bicarbConvFactor, @@ -324,6 +365,123 @@ /*********************************************************************//** * @brief + * The setIsolatedUFSettings function sets isolated UF duration, volume goal, + * and rate without changing the normal treatment UF prescription. + * @details \b Inputs: durationMin, ufVolumeMl + * @details \b Outputs: isolatedUFDurationMin, isolatedUFSetVolumeMl, + * isolatedUFRateMlMin + * @param durationMin Isolated UF duration in minutes. + * @param ufVolumeMl Isolated UF volume goal in mL. + * @return TRUE if the isolated UF settings were updated, FALSE otherwise. + *************************************************************************/ +BOOL setIsolatedUFSettings( U32 durationMin, F32 ufVolumeMl ) +{ + BOOL result = FALSE; + + if ( durationMin > 0U ) + { + isolatedUFDurationMin = durationMin; + isolatedUFSetVolumeMl = ufVolumeMl; + isolatedUFRateMlMin = calculateIsolatedUFRateMlMin( durationMin, ufVolumeMl ); + + if ( TREATMENT_ISO_UF_STATE == currentTreatmentState ) + { + if ( ISOLATED_UF_PAUSED_STATE == getCurrentIsolatedUFState() ) + { + cmdChangeQuf( 0.0F ); + } + else + { + cmdChangeQuf( isolatedUFRateMlMin ); + } + } + + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * 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. + * @return none + *************************************************************************/ +void signalStartIsolatedUF( BOOL midTreatment ) +{ + isolatedUFMidTreatment = midTreatment; + isolatedUFStartRequested = TRUE; +} + +/*********************************************************************//** + * @brief + * The isIsolatedUFMidTreatment function determines whether isolated UF was + * started during an active HD/HDF treatment session. + * @details \b Inputs: isolatedUFMidTreatment + * @details \b Outputs: none + * @return TRUE if isolated UF was started mid-treatment, FALSE otherwise. + *************************************************************************/ +BOOL isIsolatedUFMidTreatment( void ) +{ + return isolatedUFMidTreatment; +} + +/*********************************************************************//** + * @brief + * The getIsolatedUFDurationMin function gets isolated UF duration. + * @details \b Inputs: isolatedUFDurationMin + * @details \b Outputs: none + * @return isolated UF duration in minutes. + *************************************************************************/ +U32 getIsolatedUFDurationMin( void ) +{ + return isolatedUFDurationMin; +} + +/*********************************************************************//** + * @brief + * The getIsolatedUFSetVolumeMl function gets isolated UF set volume. + * @details \b Inputs: isolatedUFSetVolumeMl + * @details \b Outputs: none + * @return isolated UF set volume in mL. + *************************************************************************/ +F32 getIsolatedUFSetVolumeMl( void ) +{ + return isolatedUFSetVolumeMl; +} + +/*********************************************************************//** + * @brief + * The getIsolatedUFRateMlMin function gets isolated UF rate. + * @details \b Inputs: isolatedUFRateMlMin + * @details \b Outputs: none + * @return isolated UF rate in mL/min. + *************************************************************************/ +F32 getIsolatedUFRateMlMin( void ) +{ + return isolatedUFRateMlMin; +} + +/*********************************************************************//** + * @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. + * @details \b Inputs: setDialysateFlowRate, setUFRateMlMin from setDialysisDDParams + * @details \b Outputs: isolatedUFMidTreatment cleared, DD returned to dialysis mode + * @return none + *************************************************************************/ +static void resumeDialysisAfterIsolatedUF( void ) +{ + isolatedUFMidTreatment = FALSE; + transitionToDialysis(); +} + +/*********************************************************************//** + * @brief * The setBloodIsPrimed function sets that flag indicating whether the * blood-side circuit has been primed with blood. Call this function with * TRUE when blood prime operation is completed. Call this function with @@ -463,10 +621,10 @@ currentTreatmentState = handleTreatmentDialysisState(); break; -// case TREATMENT_ISO_UF_STATE: -// currentTreatmentState = handleTreatmentIsoUFState(); -// break; -// + case TREATMENT_ISO_UF_STATE: + currentTreatmentState = handleTreatmentIsoUFState(); + break; + // case TREATMENT_SALINE_BOLUS_STATE: // currentTreatmentState = handleTreatmentSalineBolusState(); // break; @@ -507,6 +665,8 @@ broadcastTreatmentPeriodicData(); // Publish ultrafiltration data at set interval (whether we are performing UF or not) publishUltrafiltrationData(); + // Publish isolated UF data only while isolated UF is active + publishIsolatedUFData(); // Publish saline bolus data at set interval (whether we are delivering one or not) publishSalineBolusData(); @@ -593,18 +753,28 @@ if ( TRUE == bloodPrimeToDialysisRequest ) { lastTreatmentTimeStamp = getMSTimerCount(); - // Kick dialysis sub-mode off - setDialysisBloodPumpFlowRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ); -// setDialysisDialInFlowAndUFRate( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presMaxUFVolumeML, presUFRate ); + + 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 ) ); +// setDialysisDialInFlowAndUFRate( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ), presMaxUFVolumeML, presUFRate ); // -// if ( presUFRate > 0.0 ) -// { -// sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, presUFRate ); -// } - transitionToDialysis(); -// // To update partial blood pump occlusion baseline - start of treatment -// signalBloodPumpPressureOcclBaseline(); - result = TREATMENT_DIALYSIS_STATE; +// if ( presUFRate > 0.0 ) +// { +// sendTreatmentLogEventData( UF_START_RESUME_EVENT, 0.0, presUFRate ); +// } + transitionToDialysis(); +// // To update partial blood pump occlusion baseline - start of treatment +// signalBloodPumpPressureOcclBaseline(); + result = TREATMENT_DIALYSIS_STATE; + } } } @@ -637,17 +807,93 @@ treatmentCompleted = TRUE; // sendLastTreatmentPeriodicData = TRUE; // treatmentEndTimeStamp = getRTCTimestamp(); - pauseDialysis(); - requestNewOperationMode( MODE_STAN ); // TODO transitionToTreatmentEnd(); - //SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_END_OF_TREATMENT_WARNING, presTreatmentTimeSecs ); + cmdBypassDialyzer( TRUE ); + cmdChangeQuf( 0.0F ); + cmdChangeQd( 0.0F ); + + // Post-treatment iso UF (partial): stay in END and wait for UI 0x9F confirm or decline. + // Decline calls signalEndTreatment() -> MODE_POST. Full treatment-end sub-mode (rinseback + // etc. in handleTreatmentEndState) is not implemented yet — uncomment that block when ready. + // Until UI post-treatment flow is complete, previous behavior was: + // pauseDialysis(); + // requestNewOperationMode( MODE_STAN ); result = TREATMENT_END_STATE; } // Otherwise, execute state machine for treatment dialysis sub-mode else { - execDialysis(); + if ( TRUE == isolatedUFStartRequested ) + { + isolatedUFStartRequested = FALSE; + transitionToIsolatedUF(); + result = TREATMENT_ISO_UF_STATE; + } + else + { + execDialysis(); + // Handle alarm page + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + transitionToTreatmentPaused(); + result = TREATMENT_PAUSED_STATE; + } + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentIsoUFState function handles isolated ultrafiltration. + * @details \b Inputs: treatmentTimeMS, lastTreatmentTimeStamp + * @details \b Outputs: treatmentTimeMS, isolated UF sub-mode executed + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentIsoUFState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_ISO_UF_STATE; + U32 newTime = getMSTimerCount(); + U32 msSinceLast = calcTimeBetween( lastTreatmentTimeStamp, newTime ); + + // Update treatment time + treatmentTimeMS += msSinceLast; + lastTreatmentTimeStamp = newTime; + + // Prescribed HD/HDF time elapsed during mid-treatment iso UF: end iso UF and wait in END for post-treatment iso UF or POST. + if ( ( TRUE == isIsolatedUFMidTreatment() ) && + ( CALC_ELAPSED_TREAT_TIME_IN_SECS() >= presTreatmentTimeSecs ) ) + { + treatmentCompleted = TRUE; + endIsolatedUFOnUserStop(); + isolatedUFMidTreatment = FALSE; + cmdBypassDialyzer( TRUE ); + cmdChangeQuf( 0.0F ); + cmdChangeQd( 0.0F ); + result = TREATMENT_END_STATE; + } + else + { + execIsolatedUF(); + + if ( TRUE == isIsolatedUFCompleted() ) + { + if ( TRUE == isIsolatedUFMidTreatment() ) + { + resumeDialysisAfterIsolatedUF(); + result = TREATMENT_DIALYSIS_STATE; + } + else + { + treatmentCompleted = TRUE; + cmdBypassDialyzer( TRUE ); + cmdChangeQuf( 0.0F ); + requestNewOperationMode( MODE_POST ); + result = TREATMENT_END_STATE; + } + } // Handle alarm page - if ( TRUE == doesAlarmStatusIndicateStop() ) + else if ( TRUE == doesAlarmStatusIndicateStop() ) { transitionToTreatmentPaused(); result = TREATMENT_PAUSED_STATE; @@ -678,10 +924,39 @@ if ( TRUE == getBloodIsPrimed() ) { lastTreatmentTimeStamp = getMSTimerCount(); - transitionToDialysis(); - result = TREATMENT_DIALYSIS_STATE; + + switch ( treatmentStateBeforePause ) + { + case TREATMENT_ISO_UF_STATE: + transitionToIsolatedUF(); + result = TREATMENT_ISO_UF_STATE; + break; + + case TREATMENT_DIALYSIS_STATE: + transitionToDialysis(); + result = TREATMENT_DIALYSIS_STATE; + 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; + } + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_INVALID_STATE, (U32)treatmentStateBeforePause ); + result = TREATMENT_PAUSED_STATE; + break; + } } - else + else { transitionToBloodPrime(); result = TREATMENT_BLOOD_PRIME_STATE; @@ -823,6 +1098,20 @@ { TREATMENT_STATE_T result = TREATMENT_END_STATE; + if ( TRUE == isolatedUFStartRequested ) + { + isolatedUFStartRequested = FALSE; + transitionToIsolatedUF(); + result = TREATMENT_ISO_UF_STATE; + } +// else if ( TRUE == endTreatmentRequest ) +// { +// endTreatmentRequest = FALSE; +// cmdBypassDialyzer( TRUE ); +// cmdChangeQuf( 0.0F ); +// requestNewOperationMode( MODE_POST ); +// } + // // Handle final rinseback alarm response from user // if ( TRUE == initiateRinsebackAlarmResponseRequest ) // { @@ -910,7 +1199,7 @@ payload.treatmentSubMode = (U32)currentTreatmentState; payload.bldPrimeState = getCurrentBloodPrimeState(); payload.dialysisState = getDialysisState(); - payload.isoUFState = 0; + payload.isoUFState = getCurrentIsolatedUFState(); payload.txPausedState = getCurrentTreatmentPausedState(); payload.rinsebackState = 0; // getCurrentRinsebackState(); payload.txRecircState = 0; // getCurrentTreatmentRecircState(); @@ -935,7 +1224,7 @@ { if ( ++treatmentParamsRangesBroadcastTimerCtr >= getU32OverrideValue( &treatmentParamRangesPublishInterval ) ) { - TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T payload; + TREATMENT_PARAM_BROADCAST_PAYLOAD_T payload; // Compute minimum treatment duration U32 presTime = ( presTreatmentTimeSecs / SEC_PER_MIN ); U32 elapseTime = CALC_ELAPSED_TREAT_TIME_IN_MIN(); @@ -969,7 +1258,7 @@ payload.maxUFVolume = maxUFVol; payload.minDialRate = minDialRate; payload.maxDialRate = maxDialRate; - sendMessage( MSG_ID_TD_TREATMENT_PARAM_RANGES, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&payload), sizeof( TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T ) ); + sendMessage( MSG_ID_TD_TREATMENT_PARAM_RANGES, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&payload), sizeof( TREATMENT_PARAM_BROADCAST_PAYLOAD_T ) ); } } @@ -1151,7 +1440,40 @@ } } +/*********************************************************************//** + * @brief + * The publishIsolatedUFData function publishes isolated ultrafiltration data + * at the set time interval while isolated UF is active. + * @details \b Inputs: currentTreatmentState, treatmentTimeMS + * @details \b Outputs: none + * @return none + *************************************************************************/ +static void publishIsolatedUFData( void ) +{ + if ( TREATMENT_ISO_UF_STATE == currentTreatmentState ) + { + if ( ++isolatedUFBroadcastTimerCtr >= ULTRAFILTRATION_DATA_PUB_INTERVAL ) + { + ISOLATED_UF_DATA_PAYLOAD_T data; + U32 durationInMinutes = getIsolatedUFDurationMin(); + F32 volumeGoalMl = getIsolatedUFSetVolumeMl(); + data.mDuration = durationInMinutes; + data.mSetVolume = (U32)volumeGoalMl; + data.mVolumeDelivered = (U32)( getIsolatedUFVolumeDrawn() * (F32)ML_PER_LITER ); + data.mRate = (U32)getIsolatedUFRateMlMin(); + + sendMessage( MSG_ID_TD_ISOLATED_UF_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)(&data), sizeof( ISOLATED_UF_DATA_PAYLOAD_T ) ); + isolatedUFBroadcastTimerCtr = 0; + } + } + else + { + isolatedUFBroadcastTimerCtr = ULTRAFILTRATION_DATA_PUB_INTERVAL; + } +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Modes/ModeTreatment.h =================================================================== diff -u -re9e339870c5ed01230963f00d400331ab879c91f -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e --- firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision e9e339870c5ed01230963f00d400331ab879c91f) +++ firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) @@ -85,6 +85,15 @@ U32 ufState; ///< Ultrafiltration state. } UF_DATA_PAYLOAD_T; +/// Payload record structure for isolated UF data broadcast messages. +typedef struct +{ + U32 mDuration; ///< Isolated UF duration in minutes. + U32 mSetVolume; ///< Isolated UF set volume in mL. + U32 mVolumeDelivered; ///< Isolated UF volume delivered in mL. + U32 mRate; ///< Isolated UF rate in mL/min. +} ISOLATED_UF_DATA_PAYLOAD_T; + /// Payload record structure for the in-line pressure limits change response. typedef struct { @@ -125,6 +134,13 @@ U32 getTreatmentStartTimeStamp( void ); // Get the treatment start time stamp U32 getTreatmentEndTimeStamp( void ); // Get the treatment end time stamp +BOOL setIsolatedUFSettings( U32 durationMin, F32 ufVolumeMl ); // Set isolated UF duration, goal, and rate +void signalStartIsolatedUF( BOOL midTreatment ); // Request transition to isolated UF (F = post-treatment or standalone entry path) +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 + // MSG_ID_TD_PRESSURE_LIMITS_CHANGE_RESPONSE BOOL sendPressureLimitsChangeResponse( PRESSURE_LIMIT_CHANGE_RESPONSE_T *data ); Index: firmware/App/Services/Messaging.c =================================================================== diff -u -rda59fa4a98dbc11c37677e92a66aa940d251678f -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision da59fa4a98dbc11c37677e92a66aa940d251678f) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) @@ -37,6 +37,7 @@ #include "RotaryValve.h" #include "StateTxBloodPrime.h" #include "StateTxDialysis.h" +#include "StateTxIsolatedUF.h" #include "StateTxPaused.h" #include "Switches.h" #include "SystemCommTD.h" @@ -110,11 +111,14 @@ { MSG_ID_DD_PRESSURES_DATA, &setDialysatePressure }, { MSG_ID_UI_TREATMENT_PARAMS_TO_VALIDATE, &validateAndSetTreatmentParameters }, { MSG_ID_UI_INITIATE_TREATMENT_WORKFLOW, &signalUserInitiateTreatment }, - { MSG_ID_UI_UF_PAUSE_RESUME_REQUEST, &signalPauseResumeUF }, + { MSG_ID_UI_UF_PAUSE_RESUME_REQUEST, &handleUFPauseResumeRequest }, { MSG_ID_TESTER_LOGIN_REQUEST, &handleTesterLogInRequest }, { MSG_ID_UI_PRESSURE_LIMIT_WIDEN_REQUEST, &pressureLimitHandleWidenRequest }, { MSG_ID_UI_BLOOD_PRIME_CMD_REQUEST, &bloodPrimeHandleCmdRequest }, { MSG_ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_REQUEST, &bloodPrimeHandleBloodFlowChangeRequest }, + { MSG_ID_UI_ISOLATED_UF_DURATION_CHANGE_REQUEST, &handleIsolatedUFDurationChangeRequest }, + { MSG_ID_UI_ISOLATED_UF_VOLUME_GOAL_CHANGE_REQUEST, &handleIsolatedUFVolumeGoalChangeRequest }, + { MSG_ID_UI_ISOLATED_UF_CONFIRM_REQUEST, &handleIsolatedUFConfirmRequest }, { MSG_ID_TD_SOFTWARE_RESET_REQUEST, &testTDSoftwareResetRequest }, { MSG_ID_TD_BUBBLE_OVERRIDE_REQUEST, &testBubbleDetectOverride }, { MSG_ID_TD_BUBBLE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testBubblesDataPublishIntervalOverride }, Index: firmware/App/Services/TxParams.c =================================================================== diff -u -rda59fa4a98dbc11c37677e92a66aa940d251678f -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e --- firmware/App/Services/TxParams.c (.../TxParams.c) (revision da59fa4a98dbc11c37677e92a66aa940d251678f) +++ firmware/App/Services/TxParams.c (.../TxParams.c) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) @@ -181,15 +181,22 @@ 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 isolatedUFSettingsPending = FALSE; ///< Flag indicates isolated UF settings are staged for confirmation. +static U32 isolatedUFDurationPendingMin = 0; ///< Staged isolated UF duration in minutes. +static F32 isolatedUFVolumePendingMl = 0.0F; ///< Staged isolated UF volume goal in mL. // ********** private function prototypes ********** static void resetAllTreatmentParameters( void ); +static void resetIsolatedUFSettingsPending( void ); static BOOL isTreatmentParamNotApplicable( TREATMENT_PARAM_T param ); static BOOL isNotApplicableTreatmentParamZero( TREATMENT_PARAM_T param ); static BOOL checkTreatmentParamsInRange( U32 *reasons ); static BOOL checkTreatmentParamsDependencies( U32 *reasons ); static BOOL checkUFDependencies( U32 *reasons ); +static REQUEST_REJECT_REASON_CODE_T validateIsolatedUFSettings( U32 durationMin, F32 volumeGoalMl ); +static U32 calculateIsolatedUFMaxVolumeMl( U32 durationMin ); +static BOOL isPostTreatmentIsolatedUFRequest( void ); static void extractTreatmentParamsFromPayload( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T payload ); //static void checkPressureParamsRange( TREATMENT_PARAMS_DATA_RESPONSE_PAYLOAD_T* txParams ); static void sendTreatmentParamsResponse( BOOL rejected, U32 *reasons ); @@ -240,10 +247,27 @@ origTreatmentParams.venousPressureLimitAsymmetric_mmHg = 0; origTreatmentParams.tmpLimitWindow_mmHg = 0; origTreatmentParams.uFVolume_L = 0.0F; + + resetIsolatedUFSettingsPending(); } /*********************************************************************//** * @brief + * The resetIsolatedUFSettingsPending function clears staged isolated UF + * settings awaiting user confirmation. + * @details \b Inputs: none + * @details \b Outputs: isolatedUFSettingsPending cleared + * @return none + *************************************************************************/ +static void resetIsolatedUFSettingsPending( void ) +{ + isolatedUFSettingsPending = FALSE; + isolatedUFDurationPendingMin = 0; + isolatedUFVolumePendingMl = 0.0F; +} + +/*********************************************************************//** + * @brief * The setTreatmentParameterU32 function sets a given unsigned integer * treatment parameter to a given value. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given param is invalid @@ -497,15 +521,15 @@ if ( TRUE == treatParamsConfirmed ) { U32 setTxDuration = stagedParams[ TREATMENT_PARAM_TREATMENT_DURATION ].uInt; - TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T payload; + TREATMENT_PARAM_BROADCAST_PAYLOAD_T payload; payload.minTreatmentTime = treatmentParameters[ TREATMENT_PARAM_TREATMENT_DURATION ].minimum.uInt; payload.maxTreatmentTime = treatmentParameters[ TREATMENT_PARAM_TREATMENT_DURATION ].maximum.uInt; payload.minUFVolume = 0.0F; payload.maxUFVolume = MIN( (F32)setTxDuration * MAX_UF_RATE_ML_MIN, (F32)MAX_UF_VOLUME_ML ); payload.minDialRate = treatmentParameters[ TREATMENT_PARAM_DIALYSATE_FLOW ].minimum.uInt; payload.maxDialRate = treatmentParameters[ TREATMENT_PARAM_DIALYSATE_FLOW ].maximum.uInt; - sendMessage( MSG_ID_TD_TREATMENT_PARAM_RANGES, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&payload), sizeof( TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T ) ); + sendMessage( MSG_ID_TD_TREATMENT_PARAM_RANGES, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&payload), sizeof( TREATMENT_PARAM_BROADCAST_PAYLOAD_T ) ); } result = ( TRUE == paramsAreInvalid ? FALSE : TRUE ); @@ -537,30 +561,27 @@ result = ( ( ( param == TREATMENT_PARAM_HDF_DILUTION ) || ( param == TREATMENT_PARAM_SUBST_FLUID_VOLUME ) ) ? TRUE : FALSE ); break; - // TODO uncomment in phase 3 when ISO UF feature is required -// case TREATMENT_MODALITY_ISOLATED_UF: -// switch ( param ) -// { -// // Treatment parameters that are not applicable for isolated UF -// 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; -// -// // Treatment parameters applicable for isolated UF -// default: -// result = FALSE; -// break; -// } -// 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; + 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; @@ -819,6 +840,285 @@ /*********************************************************************//** * @brief + * The calculateIsolatedUFRateMlMin function calculates isolated UF rate. + * @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 UF rate in mL/min. + *************************************************************************/ +F32 calculateIsolatedUFRateMlMin( U32 durationMin, F32 volumeGoalMl ) +{ + F32 ufRate = 0.0F; + + if ( durationMin > 0U ) + { + ufRate = volumeGoalMl / (F32)durationMin; + } + + return ufRate; +} + +/*********************************************************************//** + * @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 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; +} + +/*********************************************************************//** + * @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 = 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; + + 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 ) + { + reason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; + } + else if ( ( durationMin < getU32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ) ) || + ( durationMin > getU32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_TREATMENT_DURATION ) ) ) + { + reason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; + } + else if ( ( FALSE == postTreatmentRequest ) && ( durationMin <= elapsedTreatmentMin ) ) + { + reason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; + } + else if ( ( volumeGoalL < getF32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_UF_VOLUME ) ) || + ( volumeGoalL > getF32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_UF_VOLUME ) ) ) + { + 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; +} + +/*********************************************************************//** + * @brief + * The calculateIsolatedUFMaxVolumeMl function calculates the maximum isolated + * UF volume for a given duration based on max UF rate and configured UF max. + * @details \b Inputs: durationMin + * @details \b Outputs: none + * @param durationMin Isolated UF duration in minutes. + * @return Maximum isolated UF volume in mL. + *************************************************************************/ +static U32 calculateIsolatedUFMaxVolumeMl( U32 durationMin ) +{ + F32 maxVolumeMl = MIN( (F32)durationMin * MAX_UF_RATE_ML_MIN, (F32)MAX_UF_VOLUME_ML ); + + return (U32)maxVolumeMl; +} + +/*********************************************************************//** + * @brief + * The handleIsolatedUFDurationChangeRequest function handles a UI isolated UF + * duration change request. + * @details \b Message \b Sent: MSG_ID_TD_ISOLATED_UF_DURATION_CHANGE_RESPONSE + * @details \b Inputs: message + * @details \b Outputs: isolatedUFDurationPendingMin + * @param message Duration change request message from UI. + * @return TRUE if the request is valid and staged, 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 ); + + 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 ); + + if ( REQUEST_REJECT_REASON_NONE == reason ) + { + isolatedUFSettingsPending = TRUE; + isolatedUFDurationPendingMin = durationMin; + isolatedUFVolumePendingMl = volumeGoalMl; + accepted = TRUE; + } + } + + 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 ) ); + + return accepted; +} + +/*********************************************************************//** + * @brief + * The handleIsolatedUFVolumeGoalChangeRequest function handles a UI isolated + * UF volume goal change request. + * @details \b Message \b Sent: MSG_ID_TD_ISOLATED_UF_VOLUME_GOAL_CHANGE_RESPONSE + * @details \b Inputs: message + * @details \b Outputs: isolatedUFVolumePendingMl + * @param message Volume goal change request message from UI. + * @return TRUE if the request is valid and staged, FALSE otherwise. + *************************************************************************/ +BOOL handleIsolatedUFVolumeGoalChangeRequest( MESSAGE_T *message ) +{ + 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; + + if ( sizeof( ISOLATED_UF_VOLUME_GOAL_CHANGE_REQUEST_PAYLOAD_T ) == message->hdr.payloadLen ) + { + ISOLATED_UF_VOLUME_GOAL_CHANGE_REQUEST_PAYLOAD_T request; + + memcpy( &request, message->payload, sizeof( ISOLATED_UF_VOLUME_GOAL_CHANGE_REQUEST_PAYLOAD_T ) ); + durationMin = request.mDuration; + volumeGoalMl = (F32)request.mVolume; + reason = validateIsolatedUFSettings( durationMin, volumeGoalMl ); + + if ( REQUEST_REJECT_REASON_NONE == reason ) + { + isolatedUFSettingsPending = TRUE; + isolatedUFDurationPendingMin = durationMin; + isolatedUFVolumePendingMl = volumeGoalMl; + accepted = TRUE; + } + } + + response.mAccepted = (U32)accepted; + response.mReason = (U32)reason; + response.mVolume = (U32)volumeGoalMl; + response.mDuration = durationMin; + 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; +} + +/*********************************************************************//** + * @brief + * The handleIsolatedUFConfirmRequest function handles UI confirmation of + * staged isolated UF settings. + * @details \b Message \b Sent: MSG_ID_TD_ISOLATED_UF_CONFIRM_RESPONSE + * @details \b Inputs: isolatedUFSettingsPending + * @details \b Outputs: treatment parameters updated if confirmed + * @param message Confirmation request message from UI. + * @return TRUE if confirmation is accepted, FALSE otherwise. + *************************************************************************/ +BOOL handleIsolatedUFConfirmRequest( MESSAGE_T *message ) +{ + BOOL accepted = FALSE; + REQUEST_REJECT_REASON_CODE_T reason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + BOOL confirmed = TRUE; + ISOLATED_UF_CONFIRM_RESPONSE_PAYLOAD_T response; + + if ( sizeof( ISOLATED_UF_CONFIRM_REQUEST_PAYLOAD_T ) == message->hdr.payloadLen ) + { + ISOLATED_UF_CONFIRM_REQUEST_PAYLOAD_T request; + + memcpy( &request, message->payload, sizeof( ISOLATED_UF_CONFIRM_REQUEST_PAYLOAD_T ) ); + confirmed = ( request.mConfirmed != 0U ? TRUE : FALSE ); + } + + if ( ( 0U == message->hdr.payloadLen ) || ( sizeof( ISOLATED_UF_CONFIRM_REQUEST_PAYLOAD_T ) == message->hdr.payloadLen ) ) + { + if ( TRUE == confirmed ) + { + if ( TRUE == isolatedUFSettingsPending ) + { + reason = validateIsolatedUFSettings( isolatedUFDurationPendingMin, isolatedUFVolumePendingMl ); + + if ( REQUEST_REJECT_REASON_NONE == reason ) + { + BOOL activeUpdated = setIsolatedUFSettings( isolatedUFDurationPendingMin, isolatedUFVolumePendingMl ); + + if ( TRUE == activeUpdated ) + { + signalStartIsolatedUF( ( TRUE == isPostTreatmentIsolatedUFRequest() ? FALSE : TRUE ) ); + accepted = TRUE; + resetIsolatedUFSettingsPending(); + } + else + { + reason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + } + } + } + else + { + accepted = TRUE; + reason = REQUEST_REJECT_REASON_NONE; + resetIsolatedUFSettingsPending(); + + // Post-treatment: UI decline (0x9F mConfirmed=0) is the exit to POST until full END workflow exists. + if ( TRUE == isPostTreatmentIsolatedUFRequest() ) + { + signalEndTreatment(); + } + } + } + + response.mAccepted = (U32)accepted; + response.mReason = (U32)reason; + sendMessage( MSG_ID_TD_ISOLATED_UF_CONFIRM_RESPONSE, COMM_BUFFER_OUT_CAN_TD_2_UI, (U08*)(&response), sizeof( ISOLATED_UF_CONFIRM_RESPONSE_PAYLOAD_T ) ); + + return accepted; +} + +/*********************************************************************//** + * @brief * The resetTreatmentParameters function resets the Treatment Parameters * session flags and parameter values. * @details Inputs: none Index: firmware/App/Services/TxParams.h =================================================================== diff -u -rda59fa4a98dbc11c37677e92a66aa940d251678f -rd387dc3cd21e6f1fb7e161032f30eb49a9c1b48e --- firmware/App/Services/TxParams.h (.../TxParams.h) (revision da59fa4a98dbc11c37677e92a66aa940d251678f) +++ firmware/App/Services/TxParams.h (.../TxParams.h) (revision d387dc3cd21e6f1fb7e161032f30eb49a9c1b48e) @@ -104,17 +104,54 @@ F32 uFVolume_L; ///< Current ultrafiltration volume (in L). } CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T; -/// Payload record structure for treatment parameter range broadcast messages. +#pragma pack(push, 1) + +/// Payload record structure for requesting an isolated UF duration change. typedef struct { - U32 minTreatmentTime; ///< Minimum treatment duration (in minutes) - U32 maxTreatmentTime; ///< Maximum treatment duration (in minutes) - F32 minUFVolume; ///< Minimum ultrafiltration volume (in mL) - F32 maxUFVolume; ///< Maximum ultrafiltration volume (in mL) - U32 minDialRate; ///< Minimum dialysate flow rate (in mL/min) - U32 maxDialRate; ///< Maximum dialysate flow rate (in mL/min) -} TREATMENT_PARAM_RANGE_BROADCAST_PAYLOAD_T; + U32 mDuration; ///< Requested isolated UF duration in minutes. +} ISOLATED_UF_DURATION_CHANGE_REQUEST_PAYLOAD_T; +/// Payload record structure for requesting an isolated UF volume goal change. +typedef struct +{ + U32 mDuration; ///< Requested isolated UF duration in minutes. + U32 mVolume; ///< Requested isolated UF volume goal in mL. +} ISOLATED_UF_VOLUME_GOAL_CHANGE_REQUEST_PAYLOAD_T; + +/// Payload record structure for confirming an isolated UF settings change. +typedef struct +{ + U32 mConfirmed; ///< TRUE if user confirms the staged isolated UF settings. +} ISOLATED_UF_CONFIRM_REQUEST_PAYLOAD_T; + +/// Payload record structure for isolated UF duration change responses. +typedef struct +{ + U32 mAccepted; ///< Accepted/Rejected. + U32 mReason; ///< Rejection reason if not accepted. + U32 mVolumeMax; ///< Maximum isolated UF volume in mL for the requested duration. +} ISOLATED_UF_DURATION_CHANGE_RESPONSE_PAYLOAD_T; + +/// Payload record structure for isolated UF volume goal change responses. +typedef struct +{ + U32 mAccepted; ///< Accepted/Rejected. + U32 mReason; ///< Rejection reason if not accepted. + U32 mVolume; ///< Isolated UF volume goal in mL. + U32 mDuration; ///< Isolated UF duration in minutes. + U32 mRate; ///< Isolated UF rate in mL/min. +} ISOLATED_UF_VOLUME_GOAL_CHANGE_RESPONSE_PAYLOAD_T; + +/// Payload record structure for isolated UF confirmation responses. +typedef struct +{ + U32 mAccepted; ///< Accepted/Rejected. + U32 mReason; ///< Rejection reason if not accepted. +} ISOLATED_UF_CONFIRM_RESPONSE_PAYLOAD_T; + +#pragma pack(pop) + // ********** public function prototypes **************** BOOL setTreatmentParameterU32( TREATMENT_PARAM_T param, U32 value ); // Set a specified unsigned integer treatment parameter value @@ -124,6 +161,10 @@ 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 +F32 calculateIsolatedUFRateMlMin( U32 durationMin, F32 volumeGoalMl ); // Calculate isolated UF rate (mL/min) from duration and volume goal +BOOL handleIsolatedUFDurationChangeRequest( MESSAGE_T *message ); // User requested isolated UF duration change +BOOL handleIsolatedUFVolumeGoalChangeRequest( MESSAGE_T *message ); // User requested isolated UF volume goal change +BOOL handleIsolatedUFConfirmRequest( MESSAGE_T *message ); // User confirmed/rejected isolated UF settings change void resetTreatmentParameters( void ); // Reset all parameters to defaults //BOOL signalUserConfirmationOfTreatmentParameters( MESSAGE_T *message ); // Process UI confirm/reject Treatment parameters