Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -rd3ae2d91603ae6d2d25b9abdb220cc144cf90692 -rfb4b4a4f9d16742bfb76f62970a43c97e1ac14f0 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision d3ae2d91603ae6d2d25b9abdb220cc144cf90692) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision fb4b4a4f9d16742bfb76f62970a43c97e1ac14f0) @@ -41,10 +41,19 @@ #define MAX_TREATMENT_TIME_MINUTES ( 8 * MIN_PER_HOUR ) ///< Maximum treatment time (in minutes). #define MAX_UF_RATE_ML_MIN ( (F32)2500 / (F32)MIN_PER_HOUR ) ///< Maximum ultrafiltration rate (in mL/min). +#define MAX_UF_VOLUME_ML ( 8 * ML_PER_LITER ) ///< Maximum ultrafiltration volume (in mL). #define MAX_DIALYSATE_VOLUME_ML ( 180 * ML_PER_LITER ) ///< Maximum dialysate volume (in mL). -#define TREATMENT_TIME_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the treatment time & state data is published on the CAN bus +#define USER_CONFIRM_CHANGE_TIMEOUT_MS ( 60 * MS_PER_SECOND ) ///< Require user to confirm UF volume change within this time. +#define PREVENT_UF_VOL_CHANGE_IF_NEARLY_DONE_SEC ( 10 * SEC_PER_MIN ) ///< Prevent UF volume change if treatment within this much time from end of treatment (in seconds). +#define TREATMENT_TIME_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the treatment time & state data is published on the CAN bus. +#define TREATMENT_SETTINGS_RANGES_PUB_INTERVAL ( ( 60 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which updated, valid treatment setting ranges are published on the CAN bus. + +#define CALC_ELAPSED_TREAT_TIME_IN_SECS() ( treatmentTimeMS / MS_PER_SECOND ) ///< Macro to calculate the elapsed treatment time in seconds. +#define CALC_ELAPSED_TREAT_TIME_IN_MIN() ( ( treatmentTimeMS / MS_PER_SECOND ) / SEC_PER_MIN ) ///< Macro to calculate the elapsed treatment time in minutes. +#define CALC_TREAT_TIME_REMAINING_IN_SECS() ( (S32)presTreatmentTimeSecs - (S32)( treatmentTimeMS / MS_PER_SECOND ) ) ///< Macro to calculate the remaining treatment time in seconds. + // ********** private data ********** static TREATMENT_STATE_T currentTreatmentState; ///< Current state (sub-mode) of treatment mode. @@ -58,15 +67,19 @@ static U32 treatmentTimeMS; ///< Elapsed treatment time (in ms). static U32 lastTreatmentTimeStamp; ///< Last time elapsed treatment time was recorded (a timestamp in ms). static U32 treatmentTimeBroadcastTimerCtr; ///< Treatment 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 BUTTON_STATE_T lastOffButtonState = BUTTON_STATE_RELEASED; // TODO - test code - remove later +static U32 pendingParamChangesTimer; ///< User required to confirm UF volume change within 1 minute. static F32 pendingUFVolumeChange; ///< An ultrafiltration volume change (mL) is pending user confirmation. static F32 pendingUFRateChange; ///< An ultrafiltration rate change (mL/min) is pending user confirmation. static U32 pendingTreatmentTimeChange; ///< A treatment time change (min) is pending user confirmation. // ********** private function prototypes ********** +static void broadcastTreatmentTimeAndState( void ); +static void broadcastTreatmentSettingsRanges( void ); static TREATMENT_STATE_T handleTreatmentStartState( void ); static TREATMENT_STATE_T handleTreatmentDialysisState( void ); static TREATMENT_STATE_T handleTreatmentStopState( void ); @@ -87,6 +100,18 @@ treatmentTimeMS = 0; lastTreatmentTimeStamp = 0; treatmentTimeBroadcastTimerCtr = 0; + treatmentParamsRangesBroadcastTimerCtr = TREATMENT_SETTINGS_RANGES_PUB_INTERVAL; // so we send ranges immediately + + presTreatmentTimeSecs = 0; + presBloodFlowRate = 0; + presDialysateFlowRate = 0; + presMaxUFVolumeML = 0.0; + presUFRate = 0.0; + + pendingParamChangesTimer = 0; + pendingUFVolumeChange = 0.0; + pendingUFRateChange = 0.0; + pendingTreatmentTimeChange = 0; } /*********************************************************************//** @@ -141,8 +166,6 @@ *************************************************************************/ void execTreatmentMode( void ) { - U32 elapsedTreatmentTimeInSecs; - #ifndef UF_TEST_ENABLED BOOL stop = isStopButtonPressed(); @@ -200,30 +223,13 @@ break; default: - // TODO - s/w fault + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_INVALID_STATE, currentTreatmentState ); + currentTreatmentState = TREATMENT_END_STATE; break; } - // update treatment time stats and broadcast - end treatment if time - elapsedTreatmentTimeInSecs = treatmentTimeMS / MS_PER_SECOND; - if ( elapsedTreatmentTimeInSecs >= presTreatmentTimeSecs ) - { - stopDialysis(); - elapsedTreatmentTimeInSecs = presTreatmentTimeSecs; - currentTreatmentState = TREATMENT_END_STATE; - } - // broadcast treatment time and state data at interval - if ( ++treatmentTimeBroadcastTimerCtr >= TREATMENT_TIME_DATA_PUB_INTERVAL ) - { - U32 timeRemaining = presTreatmentTimeSecs - elapsedTreatmentTimeInSecs; - DIALYSIS_STATE_T dialysisState = getDialysisState(); - UF_STATE_T uFState = getUltrafiltrationState(); - BOOL salineBolusInProgress = ( dialysisState == DIALYSIS_SOLUTION_INFUSION_STATE ? TRUE : FALSE ); - - broadcastTreatmentTime( presTreatmentTimeSecs, elapsedTreatmentTimeInSecs, timeRemaining ); - broadcastTreatmentState( currentTreatmentState, uFState, salineBolusInProgress ); - treatmentTimeBroadcastTimerCtr = 0; - } + broadcastTreatmentTimeAndState(); + broadcastTreatmentSettingsRanges(); #endif #ifdef RM46_EVAL_BOARD_TARGET // TODO - temporary test code for eval board - move to next mode after 10 sec @@ -345,69 +351,111 @@ /*********************************************************************//** * @brief - * The verifyTreatmentDurationSettingChange function verifies the user treatment \n - * duration setting change. + * The verifyTreatmentDurationSettingChange function verifies and responds to \n + * the user treatment duration setting change request. * @details - * Inputs : none - * Outputs : none + * Inputs : current operating mode, treatment states and parameters + * Outputs : response message sent * @param treatmentTime : Proposed new treatment duration (in min). * @return TRUE if new treatment duration setting valid, FALSE if not. *************************************************************************/ BOOL verifyTreatmentDurationSettingChange( U32 treatmentTime ) { BOOL result = FALSE; - S32 timeDiff = 0; - F32 rateDiff = 0.0; + REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; OP_MODE currMode = getCurrentOperationMode(); // check if we are in an appropriate treatment state for settings adjustment - if ( ( MODE_TREA == currMode ) && ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_DIALYSIS_END_STATE ) ) + if ( ( MODE_TREA == currMode ) && + ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_DIALYSIS_END_STATE ) && + ( CALC_ELAPSED_TREAT_TIME_IN_MIN() < treatmentTime ) ) { F32 uFVolume; U32 dialVolume = presDialysateFlowRate * treatmentTime; // in mL // always adjust UF volume to accommodate treatment time change (not UF rate) - uFVolume = (F32)treatmentTime * presUFRate; - if ( ( treatmentTime <= MAX_TREATMENT_TIME_MINUTES ) && ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) + uFVolume = ( (F32)( treatmentTime - CALC_ELAPSED_TREAT_TIME_IN_MIN() ) * presUFRate ) + getUltrafiltrationVolumeCollected(); + if ( ( treatmentTime <= MAX_TREATMENT_TIME_MINUTES ) && + ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) && + ( uFVolume <= MAX_UF_VOLUME_ML ) ) { result = TRUE; - pendingUFVolumeChange = uFVolume; // mL - pendingUFRateChange = presUFRate; // no UF rate change - pendingTreatmentTimeChange = treatmentTime; // min - timeDiff = treatmentTime - ( (U32)( (F32)presTreatmentTimeSecs / (F32)SEC_PER_MIN ) + 1 ); + presMaxUFVolumeML = uFVolume; + presTreatmentTimeSecs = treatmentTime * SEC_PER_MIN; + setDialysisParams( presBloodFlowRate, presDialysateFlowRate, presMaxUFVolumeML, presUFRate ); } + else + { + if ( treatmentTime > MAX_TREATMENT_TIME_MINUTES ) + { + rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; + } + else if ( uFVolume > MAX_UF_VOLUME_ML ) + { + rejectReason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; + } + else + { + rejectReason = REQUEST_REJECT_REASON_DIAL_VOLUME_OUT_OF_RANGE; + } + } } - sendChangeUFSettingsResponse( result, pendingUFVolumeChange, pendingTreatmentTimeChange, pendingUFRateChange, timeDiff, rateDiff ); + else + { + if ( MODE_TREA != currMode ) + { + rejectReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; + } + else if ( ( currentTreatmentState <= TREATMENT_START_STATE ) || + ( currentTreatmentState >= TREATMENT_DIALYSIS_END_STATE ) ) + { + rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; + } + else + { + rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; + } + } + // send response to request + sendChangeTreatmentDurationResponse( result, rejectReason, presTreatmentTimeSecs / SEC_PER_MIN, presMaxUFVolumeML ); return result; } /*********************************************************************//** * @brief - * The verifyUFSettingsChange function verifies new ultrafiltration settings \n - * from the user. + * The verifyUFSettingsChange function verifies and responds to a new \n + * ultrafiltration volume setting from the user. * @details - * Inputs : none - * Outputs : none - * @param uFVolume : . - * @param adjustment : . - * @return TRUE if new UF settings valid, FALSE if not. + * Inputs : current operating mode, treatment states and parameters + * Outputs : response message sent + * @param uFVolume : New ultrafiltration volume requested by the user. + * @return TRUE if new UF voluem is valid, FALSE if not. *************************************************************************/ -BOOL verifyUFSettingsChange( F32 uFVolume, UF_ADJ_T adjustment ) +BOOL verifyUFSettingsChange( F32 uFVolume ) { BOOL result = FALSE; + REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; S32 timeDiff = 0; F32 rateDiff = 0.0; OP_MODE currMode = getCurrentOperationMode(); + // reset pending UF/time settings changes to current values in case request is rejected + pendingUFVolumeChange = presMaxUFVolumeML; + pendingUFRateChange = presUFRate; + pendingTreatmentTimeChange = presTreatmentTimeSecs / SEC_PER_MIN; + // check if we are in an appropriate treatment state for settings adjustment - if ( ( MODE_TREA == currMode ) && ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_DIALYSIS_END_STATE ) ) + if ( ( MODE_TREA == currMode ) && + ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_DIALYSIS_END_STATE ) && + ( uFVolume <= MAX_UF_VOLUME_ML ) && + ( CALC_TREAT_TIME_REMAINING_IN_SECS() >= PREVENT_UF_VOL_CHANGE_IF_NEARLY_DONE_SEC ) ) { - // TODO - verify not too close to end of treatment for settings change DIALYSIS_STATE_T currDialysisState = getDialysisState(); UF_STATE_T currUFState = getUltrafiltrationState(); - F32 uFRate; - U32 trtTime; + F32 uFRate = uFVolume / ((F32)presTreatmentTimeSecs / (F32)SEC_PER_MIN); // what UF rate would be if user selected to adjust it + U32 trtTime = (S32)( uFVolume / presUFRate ) + 1; // what the treatment duration would be if user selected to adjust it + U32 dialVolume = presDialysateFlowRate * trtTime; // what dialysate volume would be if user selected to adjust time // UF should already be paused but let's make sure. if ( ( TREATMENT_DIALYSIS_STATE == currentTreatmentState ) && @@ -417,92 +465,247 @@ pauseUF(); } - // reset pending UF/time settings change - pendingUFVolumeChange = 0.0; - pendingUFRateChange = 0.0; - pendingTreatmentTimeChange = 0; + // start t/o timer - user must confirm UF changes within 1 minute from now + pendingParamChangesTimer = getMSTimerCount(); - // which setting does user want to adjust to accommodate the UF volume change? (treatment time or UF rate) - if ( UF_ADJ_TREATMENT_TIME == adjustment ) + // verify UF rate change would be valid (this should be as UI is getting regular UF volume range updates) + if ( uFRate <= (F32)MAX_UF_RATE_ML_MIN ) { - F32 uFRate = presUFRate; // no change in UF rate - U32 trtTime = (S32)( uFVolume / uFRate ) + 1; // in minutes - U32 dialVolume = presDialysateFlowRate * trtTime; // in mL + result = TRUE; + pendingUFVolumeChange = uFVolume; + pendingUFRateChange = uFRate; + rateDiff = ( uFRate - presUFRate ); - // verify new treatment duration is valid + // verify treatment duration change would be valid if ( ( trtTime <= MAX_TREATMENT_TIME_MINUTES ) && ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) { - result = TRUE; - pendingUFVolumeChange = uFVolume; - pendingUFRateChange = uFRate; pendingTreatmentTimeChange = trtTime; timeDiff = trtTime - ( (U32)( (F32)presTreatmentTimeSecs / (F32)SEC_PER_MIN ) + 1 ); } } else - { // UF Rate is adjusted then - trtTime = presTreatmentTimeSecs / SEC_PER_MIN; // in minutes - uFRate = uFVolume / (F32)trtTime; - if ( uFRate <= (F32)MAX_UF_RATE_ML_MIN ) - { - result = TRUE; - pendingUFVolumeChange = uFVolume; - pendingUFRateChange = uFRate; - pendingTreatmentTimeChange = trtTime; - rateDiff = ( uFRate - presUFRate ); - } + { + rejectReason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; } } + else + { + if ( MODE_TREA != currMode ) + { + rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; + } + else if ( ( currentTreatmentState <= TREATMENT_START_STATE ) || + ( currentTreatmentState >= TREATMENT_DIALYSIS_END_STATE ) ) + { + rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; + } + else if ( uFVolume > MAX_UF_VOLUME_ML ) + { + rejectReason = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; + } + else + { + rejectReason = REQUEST_REJECT_REASON_TREATMENT_TOO_CLOSE_TO_FINISHED; + } + } // respond to UF settings change request - sendChangeUFSettingsResponse( result, pendingUFVolumeChange, pendingTreatmentTimeChange, pendingUFRateChange, timeDiff, rateDiff ); + sendChangeUFSettingsResponse( result, rejectReason, pendingUFVolumeChange, pendingTreatmentTimeChange, pendingUFRateChange, timeDiff, rateDiff ); return result; } /*********************************************************************//** * @brief * The verifyUFSettingsConfirmation function verifies the user confirmed \n - * ultrafiltration settings change(s) and, if valid, implements the new settings. + * ultrafiltration settings change(s) and, if valid, accepts the new settings. * @details - * Inputs : none - * Outputs : none - * @param confirmed : . - * @param uFVolume : . - * @param treatmentTime : . - * @param uFRate : . - * @return next treatment mode state + * Inputs : current operating mode, treatment states and parameters + * Outputs : response message sent + * @param uFVolume : New ultrafiltration volume confirmed by the user. + * @param adjustment : The adjustment selected by the user. + * @return TRUE if new UF settings accepted, FALSE if not. *************************************************************************/ -BOOL verifyUFSettingsConfirmation( BOOL confirmed, F32 uFVolume, U32 treatmentTime, F32 uFRate ) +BOOL verifyUFSettingsConfirmation( F32 uFVolume, UF_ADJ_T adjustment ) { BOOL result = FALSE; + REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; OP_MODE currMode = getCurrentOperationMode(); // user confirmed UF settings change(s)? - if ( ( MODE_TREA == currMode ) && ( TRUE == confirmed ) ) + if ( ( MODE_TREA == currMode ) && ( FALSE == didTimeout( pendingParamChangesTimer, USER_CONFIRM_CHANGE_TIMEOUT_MS ) ) ) { - // user confirmed changes are same as verified pending changes? - if ( ( FABS( uFVolume - pendingUFVolumeChange ) < NEARLY_ZERO ) && - ( treatmentTime == pendingTreatmentTimeChange ) && - ( FABS( uFRate - pendingUFRateChange ) < NEARLY_ZERO ) ) - { - DIALYSIS_STATE_T currDialysisState = getDialysisState(); - UF_STATE_T currUFState = getUltrafiltrationState(); + DIALYSIS_STATE_T currDialysisState = getDialysisState(); + UF_STATE_T currUFState = getUltrafiltrationState(); - // set pending settings changes - presMaxUFVolumeML = pendingUFVolumeChange; + result = TRUE; + presMaxUFVolumeML = pendingUFVolumeChange; + + // which setting does user want to adjust to accommodate the UF volume change? (treatment time or UF rate) + if ( UF_ADJ_TREATMENT_TIME == adjustment ) + { + presTreatmentTimeSecs = pendingTreatmentTimeChange * SEC_PER_MIN; + } + else // must be adjusting UF rate then + { presUFRate = pendingUFRateChange; + } + setDialysisParams( presBloodFlowRate, presDialysateFlowRate, presMaxUFVolumeML, presUFRate ); + + // if UF paused, resume with new settings + if ( ( TREATMENT_DIALYSIS_STATE == currentTreatmentState ) && + ( DIALYSIS_UF_STATE == currDialysisState ) && + ( UF_PAUSED_STATE == currUFState ) ) + { + resumeUF(); + } + } + else + { + if ( currMode != MODE_TREA ) + { + rejectReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; + } + else + { + rejectReason = REQUEST_REJECT_REASON_TIMEOUT_WAITING_FOR_USER_CONFIRM; + } + } + // respond to UF settings change confirmation + sendChangeUFSettingsResponse( result, rejectReason, presMaxUFVolumeML, presTreatmentTimeSecs / SEC_PER_MIN, presUFRate, 0, 0 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The verifyBloodAndDialysateRateSettingsChange function verifies the \n + * user blood & dialysate flow rate settings change. + * @details + * Inputs : current operating mode, treatment states and parameters + * Outputs : response message sent + * @param bloodRate : Proposed new blood flow rate (in mL/min). + * @param dialRate : Proposed new dialysate flow rate (in mL/min). + * @return TRUE if new blood & dialysate rate settings are valid, FALSE if not. + *************************************************************************/ +BOOL verifyBloodAndDialysateRateSettingsChange( U32 bloodRate, U32 dialRate ) +{ + BOOL result = FALSE; + REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; + OP_MODE currMode = getCurrentOperationMode(); + + // check if we are in treatment mode for settings change + if ( MODE_TREA == currMode ) + { + U32 dialVolume = dialRate * ( (U32)( (F32)presTreatmentTimeSecs / (F32)SEC_PER_MIN ) + 1 ); // in mL + + // validate new rates + if ( ( bloodRate >= MIN_BLOOD_FLOW_RATE ) && ( bloodRate <= MAX_BLOOD_FLOW_RATE ) && + ( dialRate >= MIN_DIAL_IN_FLOW_RATE ) && ( dialRate <= MAX_DIAL_IN_FLOW_RATE ) && + ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) + { + result = TRUE; + // set to new rates + presBloodFlowRate = bloodRate; + presDialysateFlowRate = dialRate; setDialysisParams( presBloodFlowRate, presDialysateFlowRate, presMaxUFVolumeML, presUFRate ); - presTreatmentTimeSecs = pendingTreatmentTimeChange * SEC_PER_MIN; - // if UF paused, resume with new settings - if ( ( TREATMENT_DIALYSIS_STATE == currentTreatmentState ) && - ( DIALYSIS_UF_STATE == currDialysisState ) && - ( UF_PAUSED_STATE == currUFState ) ) + } + else + { + if ( ( bloodRate < MIN_BLOOD_FLOW_RATE ) || ( bloodRate > MAX_BLOOD_FLOW_RATE ) ) { - resumeUF(); + rejectReason = REQUEST_REJECT_REASON_BLOOD_FLOW_OUT_OF_RANGE; } - result = TRUE; + else if ( ( dialRate < MIN_DIAL_IN_FLOW_RATE ) || ( dialRate > MAX_DIAL_IN_FLOW_RATE ) ) + { + rejectReason = REQUEST_REJECT_REASON_DIAL_FLOW_OUT_OF_RANGE; + } + else + { + rejectReason = REQUEST_REJECT_REASON_DIAL_VOLUME_OUT_OF_RANGE; + } } } + else + { + rejectReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; + } + sendChangeBloodDialysateRateChangeResponse( result, (U32)rejectReason, presBloodFlowRate, presDialysateFlowRate ); return result; } + +/*********************************************************************//** + * @brief + * The broadcastTreatmentTimeAndState function broadcasts treatment time and \n + * state data during treatment. + * @details + * Inputs : treatment time and state data + * Outputs : treatment time and state messages sent on interval + * @return none + *************************************************************************/ +static void broadcastTreatmentTimeAndState( void ) +{ + U32 elapsedTreatmentTimeInSecs; + + // update treatment time stats and broadcast - end treatment if time + elapsedTreatmentTimeInSecs = treatmentTimeMS / MS_PER_SECOND; + if ( elapsedTreatmentTimeInSecs >= presTreatmentTimeSecs ) + { + stopDialysis(); + elapsedTreatmentTimeInSecs = presTreatmentTimeSecs; + currentTreatmentState = TREATMENT_DIALYSIS_END_STATE; + } + // broadcast treatment time and state data at interval + if ( ++treatmentTimeBroadcastTimerCtr >= TREATMENT_TIME_DATA_PUB_INTERVAL ) + { + U32 timeRemaining = presTreatmentTimeSecs - elapsedTreatmentTimeInSecs; + DIALYSIS_STATE_T dialysisState = getDialysisState(); + UF_STATE_T uFState = getUltrafiltrationState(); + BOOL salineBolusInProgress = ( dialysisState == DIALYSIS_SOLUTION_INFUSION_STATE ? TRUE : FALSE ); + + broadcastTreatmentTime( presTreatmentTimeSecs, elapsedTreatmentTimeInSecs, timeRemaining ); + broadcastTreatmentState( currentTreatmentState, uFState, salineBolusInProgress ); + treatmentTimeBroadcastTimerCtr = 0; + } +} + +/*********************************************************************//** + * @brief + * The broadcastTreatmentSettingsRanges function computes and broadcasts \n + * updated treatment parameter ranges that the user may change during treatment. + * @details + * Inputs : current operating mode, treatment states and parameters + * Outputs : valid ranges message sent on interval + * @return none + *************************************************************************/ +static void broadcastTreatmentSettingsRanges( void ) +{ + if ( ++treatmentParamsRangesBroadcastTimerCtr >= TREATMENT_SETTINGS_RANGES_PUB_INTERVAL ) + { + // compute minimum treatment duration + U32 minTime = CALC_ELAPSED_TREAT_TIME_IN_MIN() + 2; // add two minutes to cover rounding and ensure it's valid for next minute + // compute maximum treatment duration (from both UF and dialysate volume perspectives) + U32 maxTimeRem = ( MAX_UF_VOLUME_ML - (U32)getUltrafiltrationVolumeCollected() ) / ( presUFRate > 0.0 ? (U32)presUFRate : 1 ); + U32 maxTime1 = minTime + maxTimeRem; + U32 maxTime2 = MAX_DIALYSATE_VOLUME_ML / presDialysateFlowRate; + U32 maxTime = MIN( maxTime1, maxTime2 ); + // compute minimum UF volume + U32 minUFVol = (U32)(getUltrafiltrationVolumeCollected()); + // compute maximum UF volume (considering from adjustment of treatment duration or UF rate perspectives) + U32 maxUFVol1 = minUFVol + ( ( CALC_TREAT_TIME_REMAINING_IN_SECS() / SEC_PER_MIN ) * MAX_UF_RATE_ML_MIN ); + U32 maxUFVol2 = ( presUFRate > 0 ? minUFVol + (U32)( ( MAX_TREATMENT_TIME_MINUTES - CALC_ELAPSED_TREAT_TIME_IN_MIN() - 1 ) * presUFRate ) : MAX_UF_VOLUME_ML ); + U32 maxUFVol = MIN( maxUFVol1, maxUFVol2 ); + // compute minimum dialysate flow rate + U32 minDialRate = MIN_DIAL_IN_FLOW_RATE; + // compute maximum dialysate flow rate from max dialysate volume perspective + U32 maxDialRate = MAX_DIALYSATE_VOLUME_ML / ( presTreatmentTimeSecs / SEC_PER_MIN ); + + // now ensure maximums do not exceed the literal maximums + maxTime = MIN( maxTime, MAX_TREATMENT_TIME_MINUTES ); + maxUFVol = MIN( maxUFVol, MAX_UF_VOLUME_ML ); + maxDialRate = MIN( maxDialRate, MAX_DIAL_IN_FLOW_RATE ); + // send updated treatment parameter ranges to UI + sendTreatmentParamsRangesToUI( minTime, maxTime, minUFVol, maxUFVol, minDialRate, maxDialRate ); + treatmentParamsRangesBroadcastTimerCtr = 0; + } +}