Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -rd86855d12f5103fc16e2e06e267da237c8d549d7 -r744b177ec4114c62303e976aed1677b820f7a281 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision d86855d12f5103fc16e2e06e267da237c8d549d7) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 744b177ec4114c62303e976aed1677b820f7a281) @@ -41,8 +41,10 @@ #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 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 @@ -67,6 +69,7 @@ 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. @@ -93,6 +96,11 @@ treatmentTimeMS = 0; lastTreatmentTimeStamp = 0; treatmentTimeBroadcastTimerCtr = 0; + + pendingParamChangesTimer = 0; + pendingUFVolumeChange = 0.0; + pendingUFRateChange = 0.0; + pendingTreatmentTimeChange = 0; } /*********************************************************************//** @@ -351,46 +359,49 @@ /*********************************************************************//** * @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; REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; - S32 timeDiff = 0; - F32 rateDiff = 0.0; 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 ) && ( CALC_ELAPSED_TREAT_TIME_IN_MIN() < treatmentTime ) ) - { // TODO - reject if proposed time is < current time REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT + { F32 uFVolume; U32 dialVolume = presDialysateFlowRate * treatmentTime; // in mL // always adjust UF volume to accommodate treatment time change (not UF rate) uFVolume = ( (F32)( treatmentTime - CALC_ELAPSED_TREAT_TIME_IN_MIN() ) * presUFRate ) + getUltrafiltrationVolumeCollected(); - if ( ( treatmentTime <= MAX_TREATMENT_TIME_MINUTES ) && ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) + 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; @@ -403,7 +414,8 @@ { rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; } - else if ( ( currentTreatmentState <= TREATMENT_START_STATE ) || ( currentTreatmentState >= TREATMENT_DIALYSIS_END_STATE ) ) + else if ( ( currentTreatmentState <= TREATMENT_START_STATE ) || + ( currentTreatmentState >= TREATMENT_DIALYSIS_END_STATE ) ) { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } @@ -412,41 +424,41 @@ rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; } } - sendChangeUFSettingsResponse( result, rejectReason, pendingUFVolumeChange, pendingTreatmentTimeChange, pendingUFRateChange, timeDiff, rateDiff ); + // send response to request + sendChangeTreatmentDurationResponse( result, rejectReason, treatmentTime, 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(); - // check if we are in an appropriate treatment state for settings adjustment // TODO - we cannot be within TBD min from end of treatment in order to allow UF volume change + // 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 ) && + ( 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 would UF rate be if user selected to adjust it? + U32 trtTime = (S32)( uFVolume / uFRate ) + 1; // what would the treatment duration be if user selected to adjust it? + U32 dialVolume = presDialysateFlowRate * trtTime; // what would dialysate volume be if user selected to adjust time? // UF should already be paused but let's make sure. if ( ( TREATMENT_DIALYSIS_STATE == currentTreatmentState ) && @@ -456,57 +468,33 @@ pauseUF(); } + // start t/o timer - user must confirm UF changes within 1 minute from now + pendingParamChangesTimer = getMSTimerCount(); + // reset pending UF/time settings change pendingUFVolumeChange = 0.0; pendingUFRateChange = 0.0; pendingTreatmentTimeChange = 0; - // 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 - - // verify new treatment duration is 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 - { - if ( trtTime > MAX_TREATMENT_TIME_MINUTES ) - { - rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; - } - else - { - rejectReason = REQUEST_REJECT_REASON_DIAL_VOLUME_OUT_OF_RANGE; - } - - } + result = TRUE; + pendingUFVolumeChange = uFVolume; + pendingUFRateChange = uFRate; + rateDiff = ( uFRate - presUFRate ); } 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 ); - } - else - { - rejectReason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; - } + { + rejectReason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; } + + // verify treatment duration change would be valid + if ( ( trtTime <= MAX_TREATMENT_TIME_MINUTES ) && ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) + { + pendingTreatmentTimeChange = trtTime; + timeDiff = trtTime - ( (U32)( (F32)presTreatmentTimeSecs / (F32)SEC_PER_MIN ) + 1 ); + } } else { @@ -519,61 +507,79 @@ { 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, rejectReason, pendingUFVolumeChange, pendingTreatmentTimeChange, pendingUFRateChange, timeDiff, rateDiff ); + sendChangeUFSettingsResponse( result, rejectReason, pendingUFVolumeChange, pendingTreatmentTimeChange, timeDiff, pendingUFRateChange, 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; - presUFRate = pendingUFRateChange; - setDialysisParams( presBloodFlowRate, presDialysateFlowRate, presMaxUFVolumeML, presUFRate ); + 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; - // if UF paused, resume with new settings - if ( ( TREATMENT_DIALYSIS_STATE == currentTreatmentState ) && - ( DIALYSIS_UF_STATE == currDialysisState ) && - ( UF_PAUSED_STATE == currUFState ) ) - { - resumeUF(); - } - result = TRUE; } + 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, pendingUFVolumeChange, pendingTreatmentTimeChange, 0, pendingUFRateChange, 0 ); return result; } @@ -583,8 +589,8 @@ * The verifyBloodAndDialysateRateSettingsChange function verifies the \n * user blood & dialysate flow rate settings change. * @details - * Inputs : none - * Outputs : none + * 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. @@ -627,6 +633,10 @@ } } } + else + { + rejectReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; + } sendChangeBloodDialysateRateChangeResponse( result, (U32)rejectReason, bloodRate, dialRate ); return result;