Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -rfb4b4a4f9d16742bfb76f62970a43c97e1ac14f0 -r3477dd649f67442ad4bdea810ce5a251c1b0a2bf --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision fb4b4a4f9d16742bfb76f62970a43c97e1ac14f0) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 3477dd649f67442ad4bdea810ce5a251c1b0a2bf) @@ -1,26 +1,27 @@ -/**********************************************************************//** - * - * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. - * - * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN - * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. - * - * @file ModeTreatment.c - * - * @date 19-Sep-2019 - * @author S. Nash - * - * @brief Top-level state machine for the treatment mode. - * - **************************************************************************/ +/************************************************************************** +* +* Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file ModeTreatment.c +* +* @author (last) Sean Nash +* @date (last) 02-Jul-2020 +* +* @author (original) Dara Navaei +* @date (original) 05-Nov-2019 +* +***************************************************************************/ #include "AlarmLamp.h" #include "BloodFlow.h" #include "Buttons.h" +#include "DGInterface.h" #include "DialInFlow.h" #include "DialOutFlow.h" #include "Dialysis.h" -#include "Buttons.h" #include "TaskGeneral.h" #include "OperationModes.h" #include "SystemCommMessages.h" @@ -33,16 +34,17 @@ #endif /** - * @addtogroup TreatmentMode + * @addtogroup HDTreatmentMode * @{ */ // ********** private definitions ********** #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_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 MAX_DIALYSATE_VOLUME_ML ( 150 * 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). @@ -127,6 +129,7 @@ { // initialize treatment mode each time we transition to it initTreatmentMode(); + initTreatmentReservoirMgmt(); // initialize treatment sub-modes each time we transition to treatment mode initDialysis(); initTreatmentStop(); @@ -162,9 +165,9 @@ * Inputs : none * Outputs : * @param none - * @return none + * @return current state (sub-mode) *************************************************************************/ -void execTreatmentMode( void ) +U32 execTreatmentMode( void ) { #ifndef UF_TEST_ENABLED BOOL stop = isStopButtonPressed(); @@ -223,21 +226,25 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_INVALID_STATE, currentTreatmentState ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_INVALID_STATE, currentTreatmentState ); currentTreatmentState = TREATMENT_END_STATE; break; } broadcastTreatmentTimeAndState(); broadcastTreatmentSettingsRanges(); + + execTreatmentReservoirMgmt(); #endif #ifdef RM46_EVAL_BOARD_TARGET - // TODO - temporary test code for eval board - move to next mode after 10 sec - if ( TRUE == didTimeout( start, 10000U ) ) + // TODO - temporary test code for eval board - move to next mode after 5 min + if ( TRUE == didTimeout( start, 300000U ) ) { -// requestNewOperationMode( MODE_POST ); + requestNewOperationMode( MODE_POST ); } #endif + + return currentTreatmentState; } /*********************************************************************//** @@ -262,7 +269,7 @@ presTreatmentTimeSecs = 3600; presBloodFlowRate = 300; presDialysateFlowRate = 300; - presMaxUFVolumeML = 300.0; + presMaxUFVolumeML = 600.0; presUFRate = 10.0; // kick dialysis sub-mode off @@ -302,6 +309,7 @@ { lastOffButtonState = BUTTON_STATE_PRESSED; stopDialysis(); + transitionToTreatmentStop(); result = TREATMENT_STOP_STATE; } } @@ -338,6 +346,7 @@ lastOffButtonState = BUTTON_STATE_PRESSED; lastTreatmentTimeStamp = getMSTimerCount(); startDialysis(); + transitionToDialysis(); result = TREATMENT_DIALYSIS_STATE; } } @@ -363,12 +372,12 @@ { BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; - OP_MODE currMode = getCurrentOperationMode(); + HD_OP_MODE_T 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 ) ) + ( CALC_ELAPSED_TREAT_TIME_IN_MIN() < treatmentTime ) && ( treatmentTime >= MIN_TREATMENT_TIME_MINUTES ) ) { F32 uFVolume; U32 dialVolume = presDialysateFlowRate * treatmentTime; // in mL @@ -411,13 +420,19 @@ { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } + else if ( treatmentTime < MIN_TREATMENT_TIME_MINUTES ) + { + rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_MINIMUM; + } else { rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; } } // send response to request sendChangeTreatmentDurationResponse( result, rejectReason, presTreatmentTimeSecs / SEC_PER_MIN, presMaxUFVolumeML ); + // send new ranges for settings + broadcastTreatmentSettingsRanges(); return result; } @@ -438,7 +453,7 @@ REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; S32 timeDiff = 0; F32 rateDiff = 0.0; - OP_MODE currMode = getCurrentOperationMode(); + HD_OP_MODE_T currMode = getCurrentOperationMode(); // reset pending UF/time settings changes to current values in case request is rejected pendingUFVolumeChange = presMaxUFVolumeML; @@ -468,23 +483,34 @@ // start t/o timer - user must confirm UF changes within 1 minute from now pendingParamChangesTimer = getMSTimerCount(); - // verify UF rate change would be valid (this should be as UI is getting regular UF volume range updates) + // verify UF rate change would be valid (leave zero if not valid - UI will disable option) if ( uFRate <= (F32)MAX_UF_RATE_ML_MIN ) { result = TRUE; pendingUFVolumeChange = uFVolume; pendingUFRateChange = uFRate; rateDiff = ( uFRate - presUFRate ); - - // 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 { + pendingUFRateChange = 0.0; + } + // verify treatment duration change would be valid (leave zero if not valid - UI will disable option) + if ( ( trtTime <= MAX_TREATMENT_TIME_MINUTES ) && ( trtTime >= MIN_TREATMENT_TIME_MINUTES ) && + ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) + { + result = TRUE; + pendingUFVolumeChange = uFVolume; + pendingTreatmentTimeChange = trtTime; + timeDiff = trtTime - ( (U32)( (F32)presTreatmentTimeSecs / (F32)SEC_PER_MIN ) + 1 ); + } + else + { + pendingTreatmentTimeChange = 0; + } + // if neither option works, reject for UF rate + if ( FALSE == result ) + { rejectReason = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; } } @@ -509,7 +535,7 @@ } } // respond to UF settings change request - sendChangeUFSettingsResponse( result, rejectReason, pendingUFVolumeChange, pendingTreatmentTimeChange, pendingUFRateChange, timeDiff, rateDiff ); + sendChangeUFSettingsResponse( result, rejectReason, pendingUFVolumeChange, pendingTreatmentTimeChange, pendingUFRateChange, timeDiff, rateDiff, presUFRate ); return result; } @@ -525,11 +551,11 @@ * @param adjustment : The adjustment selected by the user. * @return TRUE if new UF settings accepted, FALSE if not. *************************************************************************/ -BOOL verifyUFSettingsConfirmation( F32 uFVolume, UF_ADJ_T adjustment ) +BOOL verifyUFSettingsConfirmation( F32 uFVolume, U32 adjustment ) { BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; - OP_MODE currMode = getCurrentOperationMode(); + HD_OP_MODE_T currMode = getCurrentOperationMode(); // user confirmed UF settings change(s)? if ( ( MODE_TREA == currMode ) && ( FALSE == didTimeout( pendingParamChangesTimer, USER_CONFIRM_CHANGE_TIMEOUT_MS ) ) ) @@ -571,7 +597,9 @@ } } // respond to UF settings change confirmation - sendChangeUFSettingsResponse( result, rejectReason, presMaxUFVolumeML, presTreatmentTimeSecs / SEC_PER_MIN, presUFRate, 0, 0 ); + sendChangeUFSettingsOptionResponse( result, rejectReason, presMaxUFVolumeML, presTreatmentTimeSecs / SEC_PER_MIN, presUFRate ); + // send new ranges for settings + broadcastTreatmentSettingsRanges(); return result; } @@ -591,7 +619,7 @@ { BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; - OP_MODE currMode = getCurrentOperationMode(); + HD_OP_MODE_T currMode = getCurrentOperationMode(); // check if we are in treatment mode for settings change if ( MODE_TREA == currMode ) @@ -630,6 +658,8 @@ rejectReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } sendChangeBloodDialysateRateChangeResponse( result, (U32)rejectReason, presBloodFlowRate, presDialysateFlowRate ); + // send new ranges for settings + broadcastTreatmentSettingsRanges(); return result; } @@ -661,7 +691,7 @@ U32 timeRemaining = presTreatmentTimeSecs - elapsedTreatmentTimeInSecs; DIALYSIS_STATE_T dialysisState = getDialysisState(); UF_STATE_T uFState = getUltrafiltrationState(); - BOOL salineBolusInProgress = ( dialysisState == DIALYSIS_SOLUTION_INFUSION_STATE ? TRUE : FALSE ); + BOOL salineBolusInProgress = ( dialysisState == DIALYSIS_SALINE_BOLUS_STATE ? TRUE : FALSE ); broadcastTreatmentTime( presTreatmentTimeSecs, elapsedTreatmentTimeInSecs, timeRemaining ); broadcastTreatmentState( currentTreatmentState, uFState, salineBolusInProgress ); @@ -672,7 +702,9 @@ /*********************************************************************//** * @brief * The broadcastTreatmentSettingsRanges function computes and broadcasts \n - * updated treatment parameter ranges that the user may change during treatment. + * updated treatment parameter ranges that the user may change during treatment. \n + * It is assumed that prescription settings have already been set prior to calling \n + * this function. * @details * Inputs : current operating mode, treatment states and parameters * Outputs : valid ranges message sent on interval @@ -683,26 +715,28 @@ 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 + U32 presTime = ( presTreatmentTimeSecs / SEC_PER_MIN ); + U32 elapseTime = CALC_ELAPSED_TREAT_TIME_IN_MIN(); + U32 minTime = MAX( (elapseTime + 2), MIN_TREATMENT_TIME_MINUTES ); // treatment duration cannot be < 1 hour. 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 ); + U32 maxTime = MAX( 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 ); + F32 minUFVol = getUltrafiltrationVolumeCollected() + presUFRate; + // compute maximum UF volume (considering from adjustment of UF rate and time perspectives) + F32 maxUFVol1 = minUFVol + ( (F32)( presTime - elapseTime ) * MAX_UF_RATE_ML_MIN ); + F32 maxUFVol2 = ( presUFRate > 0.0 ? minUFVol + ( (F32)( MAX_TREATMENT_TIME_MINUTES - elapseTime - 1 ) * presUFRate ) : minUFVol ); + F32 maxUFVol = MAX( 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 ); + U32 maxDialRate = MAX_DIALYSATE_VOLUME_ML / presTime; // now ensure maximums do not exceed the literal maximums maxTime = MIN( maxTime, MAX_TREATMENT_TIME_MINUTES ); - maxUFVol = MIN( maxUFVol, MAX_UF_VOLUME_ML ); + maxUFVol = MIN( maxUFVol, (F32)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 );