/************************************************************************** * * 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 Dialysis.c * * @author (last) Sean Nash * @date (last) 24-Jun-2020 * * @author (original) Sean * @date (original) 15-Jan-2020 * ***************************************************************************/ #include #include "BloodFlow.h" #include "Buttons.h" #include "DGInterface.h" #include "Dialysis.h" #include "DialInFlow.h" #include "DialOutFlow.h" #include "OperationModes.h" #include "TaskGeneral.h" #include "Timers.h" #include "ModeTreatment.h" /** * @addtogroup Dialysis * @{ */ // ********** private definitions ********** #define MAX_UF_RATE_ML_PER_MIN 45.83 ///< Maximum ultrafiltration rate in mL/min (2750 mL/hr). #define MAX_UF_ACCURACY_ERROR_ML 250.0 ///< Maximum ultrafiltration accuracy error in mL over the entire treatment. #define UF_ACCURACY_CHECK_INTERVAL ((1 * SEC_PER_MIN * MS_PER_SECOND) / TASK_GENERAL_INTERVAL) ///< Ultrafiltration rate accuracy check interval count // ********** private data ********** static DIALYSIS_STATE_T currentDialysisState; ///< Current state of the dialysis sub-mode state machine. static UF_STATE_T currentUFState; ///< Current state of the ultrafiltration state machine. static SALINE_BOLUS_STATE_T currentSalineBolusState; ///< Current state of the saline bolus state machine. static F32 refUFVolume; ///< Current reference volume for ultrafiltration (Where should we be w/r/t ultrafiltration). static F32 measUFVolume; ///< Current total measured volume for ultrafiltration (Where are we w/r/t ultrafiltration). static F32 resStartVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir start volume for ultrafiltration (i.e. where did we start with each reservoir). static F32 resFinalVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir final volume for ultrafiltration (i.e. where did we end after switch with each reservoir). static F32 measUFVolumeFromPriorReservoirs; ///< Current total ultrafiltration volume from previous reservoirs in current treatment. static U32 uFTimeMS; ///< Current elapsed ultrafiltration time (in ms). Used for calculating UF reference volume. static U32 lastUFTimeStamp; ///< HD timer value when we last took stock of ultrafiltration time (so we can determine how much time has elapsed since). static U32 setBloodFlowRate; ///< Currently set blood flow rate (from prescription). static U32 setDialysateFlowRate; ///< Currently set dialysate flow rate (from prescription). static F32 maxUFVolumeML; ///< Currently set total ultrafiltration volume for treatment (from prescription). static F32 setUFRate; ///< Currently set ultrafiltration rate (from prescription). static U32 uFAccuracyCheckTimerCtr; ///< Timer counter to determine when next to check ultrafiltration accuracy. static F32 lastUFVolumeChecked; ///< Starting ultrafiltration volume for accuracy check. // ********** private function prototypes ********** static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ); static DIALYSIS_STATE_T handleDialysisSalineBolusState( void ); static UF_STATE_T handleUFStartState( void ); static UF_STATE_T handleUFPausedState( void ); static UF_STATE_T handleUFRunningState( void ); static UF_STATE_T handleUFOffState( void ); static UF_STATE_T handleUFCompletedState( void ); static void checkUFAccuracyAndVolume( void ); static void updateUFVolumes( void ); /*********************************************************************//** * @brief * The initDialysis function initializes the Dialysis sub-mode module. * Calling this function will reset dialysis and therefore should only * be called when a new treatment is due to begin. * @details * Inputs : none * Outputs : Dialysis sub-mode module initialized. * @return none *************************************************************************/ void initDialysis( void ) { currentDialysisState = DIALYSIS_START_STATE; currentUFState = UF_START_STATE; currentSalineBolusState = SALINE_BOLUS_STATE_IDLE; refUFVolume = 0.0; measUFVolume = 0.0; // resStartVolume[ DG_RESERVOIR_1 ] = 0.0; // resStartVolume[ DG_RESERVOIR_2 ] = 0.0; resFinalVolume[ DG_RESERVOIR_1 ] = 0.0; resFinalVolume[ DG_RESERVOIR_2 ] = 0.0; measUFVolumeFromPriorReservoirs = 0.0; uFTimeMS = 0; lastUFTimeStamp = 0; setBloodFlowRate = 0; setDialysateFlowRate = 0; maxUFVolumeML = 0.0; setUFRate = 0.0; uFAccuracyCheckTimerCtr = 0; lastUFVolumeChecked = 0.0; } /*********************************************************************//** * @brief * The transitionToDialysis function prepares for transition to dialysis sub-mode. * This function will reset anything required for resuming dialysis in a * treatment that has already begun. It does not reset everything as dialysis * may be stopped and resumed multiple times due to alarms or user intervention * and we don't want to start the treatment all over again. * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ void transitionToDialysis( void ) { // TODO - anything needed here? } /*********************************************************************//** * @brief * The setDialysisParams function sets the dialysis treatment parameters. * This function should be called prior to beginning dialysis treatment * and when the user changes one or more parameters during treatment. * @details * Inputs : none * Outputs : dialysis treatment parameters are set. * @param bPFlow target blood pump flow rate (in mL/min) * @param dPFlow target dialysate inlet pump flow rate (in mL/min) * @param maxUFVol maximum ultrafiltration volume (in mL) * @param uFRate target ultrafiltration rate (in mL/min) * @return none *************************************************************************/ void setDialysisParams( U32 bPFlow, U32 dPFlow, F32 maxUFVol, F32 uFRate ) { setBloodFlowRate = bPFlow; setDialysateFlowRate = dPFlow; maxUFVolumeML = maxUFVol; setUFRate = uFRate; if ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) { #ifndef RUN_PUMPS_OPEN_LOOP setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); #else setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); #endif setDialOutPumpTargetRate( setDialysateFlowRate + (S32)setUFRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); } } /*********************************************************************//** * @brief * The startDialysis function starts/resumes dialysis. This function * will be called by Treatment Mode when beginning or resuming dialysis * treatment. * @details * Inputs : none * Outputs : Dialysis module prepared for immediate resumption. * @return none *************************************************************************/ void startDialysis( void ) { // set last UF timestamp so UF ref is resumed from this time lastUFTimeStamp = getMSTimerCount(); // send dialysate outlet pump latest UF volumes setDialOutUFVolumes( refUFVolume, measUFVolume ); // restart pumps #ifndef RUN_PUMPS_OPEN_LOOP setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); #else setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); #endif setDialOutPumpTargetRate( setDialysateFlowRate + (S32)setUFRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // TODO - Heparin pump // tell DG to start heating dialysate cmdStartDGTrimmerHeater(); } /*********************************************************************//** * @brief * The stopDialysis function stops dialysis. This function will be called * by Treatment Mode when an alarm occurs or the user pressed the stop button. * Dialysis may be resumed later. * @details * Inputs : none * Outputs : Blood and dialysate pumps stopped. Heparin pump stopped. * @return none *************************************************************************/ void stopDialysis( void ) { // stop pumps setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); setDialInPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); setDialOutPumpTargetRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // TODO - stop Heparin pump // tell DG to stop heating dialysate cmdStopDGTrimmerHeater(); } /*********************************************************************//** * @brief * The getDialysisState function gets the current dialysis state (sub-mode). * @details * Inputs : currentDialysisState * Outputs : none * @return currentDialysisState *************************************************************************/ DIALYSIS_STATE_T getDialysisState( void ) { return currentDialysisState; } /*********************************************************************//** * @brief * The getUltrafiltrationState function gets the current ultrafiltration state. * @details * Inputs : currentUFState * Outputs : none * @return currentUFState *************************************************************************/ UF_STATE_T getUltrafiltrationState( void ) { return currentUFState; } /*********************************************************************//** * @brief * The getSalineBolusState function gets the current saline bolus state. * @details * Inputs : currentSalineBolusState * Outputs : none * @return currentSalineBolusState *************************************************************************/ SALINE_BOLUS_STATE_T getSalineBolusState( void ) { return currentSalineBolusState; } /*********************************************************************//** * @brief * The getUltrafiltrationVolumeCollected function gets the current ultrafiltration * volume collected so far for current treatment. * @details * Inputs : measUFVolume, measUFVolumeFromPriorReservoirs * Outputs : none * @return currentUFState *************************************************************************/ F32 getUltrafiltrationVolumeCollected( void ) { F32 result = measUFVolume; return result; } /*********************************************************************//** * @brief * The pauseUF function pauses ultrafiltration. * @details * Inputs : currentDialysisState, currentUFState * Outputs : currentUFState, outlet pump set point * @return TRUE if pause successful, FALSE if not *************************************************************************/ BOOL pauseUF( void ) { BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; TREATMENT_STATE_T trtState = getTreatmentState(); HD_OP_MODE_T currMode = getCurrentOperationMode(); if ( ( MODE_TREA == currMode ) && ( TREATMENT_DIALYSIS_STATE == trtState ) && ( DIALYSIS_UF_STATE == currentDialysisState ) && ( UF_RUNNING_STATE == currentUFState ) ) { result = TRUE; // set outlet pump to dialysate rate setDialOutPumpTargetRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // go to UF paused state currentUFState = UF_PAUSED_STATE; } else { if ( MODE_TREA != currMode ) { rejectReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } else if ( TREATMENT_DIALYSIS_STATE != trtState ) { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } else if ( DIALYSIS_UF_STATE != currentDialysisState ) { rejectReason = REQUEST_REJECT_REASON_SALINE_BOLUS_IN_PROGRESS; } else { rejectReason = REQUEST_REJECT_REASON_UF_NOT_IN_PROGESS; } } // TODO - send response w/ reason code if rejected return result; } /*********************************************************************//** * @brief * The resumeUF function resumes ultrafiltration. * @details * Inputs : currentDialysisState, currentUFState * Outputs : currentUFState, outlet pump set point * @return TRUE if resume successful, FALSE if not *************************************************************************/ BOOL resumeUF( void ) { BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T rejectReason = REQUEST_REJECT_REASON_NONE; TREATMENT_STATE_T trtState = getTreatmentState(); HD_OP_MODE_T currMode = getCurrentOperationMode(); if ( ( MODE_TREA == currMode ) && ( TREATMENT_DIALYSIS_STATE == trtState ) && ( DIALYSIS_UF_STATE == currentDialysisState ) && ( UF_PAUSED_STATE == currentUFState ) ) { result = TRUE; // set outlet pump to dialysate rate + set UF rate setDialOutPumpTargetRate( setDialysateFlowRate + FLOAT_TO_INT_WITH_ROUND( setUFRate ), MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // restart UF time accumulation for reference volume calculation lastUFTimeStamp = getMSTimerCount(); // go to UF paused state currentUFState = UF_RUNNING_STATE; } else { if ( MODE_TREA != currMode ) { rejectReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } else if ( TREATMENT_DIALYSIS_STATE != trtState ) { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } else if ( DIALYSIS_UF_STATE != currentDialysisState ) { rejectReason = REQUEST_REJECT_REASON_SALINE_BOLUS_IN_PROGRESS; } else { rejectReason = REQUEST_REJECT_REASON_UF_NOT_PAUSED; } } // TODO - send response w/ reason code if rejected return result; } /*********************************************************************//** * @brief * The execDialysis function executes the Dialysis sub-mode state machine. * @details * Inputs : currentDialysisState * Outputs : currentDialysisState * @return none *************************************************************************/ void execDialysis( void ) { // check ultrafiltration max rate and accuracy during dialysis (even when ultrafiltration is paused). checkUFAccuracyAndVolume(); // dialysis state machine switch ( currentDialysisState ) { case DIALYSIS_START_STATE: currentDialysisState = DIALYSIS_UF_STATE; break; case DIALYSIS_UF_STATE: currentDialysisState = handleDialysisUltrafiltrationState(); break; case DIALYSIS_SALINE_BOLUS_STATE: currentDialysisState = handleDialysisSalineBolusState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSIS_INVALID_STATE, currentDialysisState ) break; } } /*********************************************************************//** * @brief * The handleDialysisUltrafiltrationState function handles the ultrafiltration * state of the Dialysis state machine. * @details * Inputs : currentUFState * Outputs : currentUFState * @return next Dialysis state. *************************************************************************/ static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ) { DIALYSIS_STATE_T result = DIALYSIS_UF_STATE; switch ( currentUFState ) { case UF_START_STATE: currentUFState = handleUFStartState(); break; case UF_PAUSED_STATE: currentUFState = handleUFPausedState(); break; case UF_RUNNING_STATE: currentUFState = handleUFRunningState(); break; case UF_OFF_STATE: currentUFState = handleUFOffState(); break; case UF_COMPLETED_STATE: currentUFState = handleUFCompletedState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSIS_INVALID_UF_STATE, currentUFState ) break; } return result; } /*********************************************************************//** * @brief * The handleDialysisSolutionInfusionState function handles the solution * infustion state of the Dialysis state machine. * @details * Inputs : currentSalineBolusState * Outputs : currentSalineBolusState * @return next Dialysis state. *************************************************************************/ static DIALYSIS_STATE_T handleDialysisSalineBolusState( void ) { DIALYSIS_STATE_T result = DIALYSIS_SALINE_BOLUS_STATE; // TODO - return result; } /*********************************************************************//** * @brief * The handleUFStartState function handles the Start state of the * ultrafiltration state machine. * @details * Inputs : maxUFVolumeML * Outputs : if ultrafiltration prescribed, ultrafiltration time is * initialized. * @return next ultrafiltration state. *************************************************************************/ static UF_STATE_T handleUFStartState( void ) { UF_STATE_T result; if ( maxUFVolumeML < NEARLY_ZERO ) { result = UF_OFF_STATE; } else { lastUFTimeStamp = getMSTimerCount(); uFTimeMS = 0; result = UF_RUNNING_STATE; } return result; } /*********************************************************************//** * @brief * The handleUFPausedState function handles the Paused state of the * ultrafiltration state machine. * @details * Inputs : none * Outputs : if ultrafiltration resumption requested, UF time is set to resume. * @return next ultrafiltration state. *************************************************************************/ static UF_STATE_T handleUFPausedState( void ) { UF_STATE_T result = UF_PAUSED_STATE; // calculate UF volumes and provide to dialysate outlet pump controller updateUFVolumes(); // TODO - test code - remove later if ( TRUE == isStopButtonPressed() ) { resumeUF(); result = UF_RUNNING_STATE; } return result; } /*********************************************************************//** * @brief * The handleUFRunningState function handles the Running state of the * ultrafiltration state machine. * @details * Inputs : ms timer, lastUFTimeStamp * Outputs : UF timer incremented, UF volumes updated and provided to DPo * pump controller. * @return next ultrafiltration state. *************************************************************************/ static UF_STATE_T handleUFRunningState( void ) { UF_STATE_T result = UF_RUNNING_STATE; U32 newTime = getMSTimerCount(); U32 msSinceLast = calcTimeBetween( lastUFTimeStamp, newTime ); // update UF time uFTimeMS += msSinceLast; lastUFTimeStamp = newTime; // update UF ref volume in UF running state only refUFVolume += ( ( (F32)msSinceLast / MS_PER_SECOND ) / SEC_PER_MIN ) * setUFRate; // calculate UF volumes and provide to dialysate outlet pump controller updateUFVolumes(); // if we've reached target UF volume, UF is complete if ( measUFVolume >= maxUFVolumeML ) { result = UF_COMPLETED_STATE; } // TODO - test code - remove later if ( TRUE == isStopButtonPressed() ) { pauseUF(); result = UF_PAUSED_STATE; } return result; } /*********************************************************************//** * @brief * The handleUFCompletedOrOffState function handles the UF Off state * of the ultrafiltration state machine. * @details * Inputs : none * Outputs : UF volumes updated and provided to DPo pump controller. * @return next ultrafiltration state *************************************************************************/ static UF_STATE_T handleUFOffState( void ) { UF_STATE_T result = UF_OFF_STATE; // calculate UF volumes and provide to dialysate outlet pump controller updateUFVolumes(); return result; } /*********************************************************************//** * @brief * The handleUFCompletedState function handles the UF Completed * state of the ultrafiltration state machine. This is a terminal state. * @details * Inputs : none * Outputs : UF volumes updated and provided to DPo pump controller. * @return next ultrafiltration state *************************************************************************/ static UF_STATE_T handleUFCompletedState( void ) { UF_STATE_T result = UF_COMPLETED_STATE; // calculate UF volumes and provide to dialysate outlet pump controller updateUFVolumes(); return result; } /*********************************************************************//** * @brief * The checkUF function checks ultrafiltration accuracy for the last * minute and checks total UF volume. Triggers an alarm if out of spec. * @details * Inputs : uFAccuracyCheckTimerCtr, lastUFVolumeChecked, measUFVolume * Outputs : uFAccuracyCheckTimerCtr, lastUFVolumeChecked * @return none *************************************************************************/ static void checkUFAccuracyAndVolume( void ) { // check UF accuracy at 1 minute intervals if ( ++uFAccuracyCheckTimerCtr >= UF_ACCURACY_CHECK_INTERVAL ) { F32 uFMeasRate = measUFVolume - lastUFVolumeChecked; // check UF max rate if ( uFMeasRate > MAX_UF_RATE_ML_PER_MIN ) { #ifndef DISABLE_UF_ALARMS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_UF_RATE_TOO_HIGH_ERROR, uFMeasRate ); #endif } // reset for next check lastUFVolumeChecked = measUFVolume; uFAccuracyCheckTimerCtr = 0; } // check total UF volume error if ( ( fabs( refUFVolume - measUFVolume ) ) >= (F32)MAX_UF_ACCURACY_ERROR_ML ) { #ifndef DISABLE_UF_ALARMS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_UF_VOLUME_ACCURACY_ERROR, refUFVolume, measUFVolume ); #endif } } /*********************************************************************//** * @brief * The updateUFVolumes function updates the ultrafiltration volumes based on * set UF rate, latest UF elapsed time, and the latest load cell weight for the * currently used reservoir. Updated UF volumes are then sent to the dialysate * outlet pump controller. * @details * Inputs : setUFRate, uFTimeMS, load cell weight * Outputs : refUFVolume, measUFVolume * @return none *************************************************************************/ static void updateUFVolumes( void ) { DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); F32 latestResVolume; // get volume of active reservoir if ( DG_RESERVOIR_1 == activeRes ) { latestResVolume = getLoadCellWeightInGrams( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else { latestResVolume = getLoadCellWeightInGrams( LOAD_CELL_RESERVOIR_2_PRIMARY ); } // calculate UF volumes and provide to dialysate outlet pump controller measUFVolume = measUFVolumeFromPriorReservoirs + ( latestResVolume - resStartVolume[ activeRes ] ); resFinalVolume[ activeRes ] = latestResVolume; setDialOutUFVolumes( refUFVolume, measUFVolume ); } /*********************************************************************//** * @brief * The setStartReservoirVolume function updates the baseline volume of the * next reservoir to be drawn from before it is switched to (i.e. while it * is the inactive reservoir) in order to get a more stable volume. * @details * Inputs : active reservoir, load cell reading from inactive reservoir * Outputs : resStartVolume[] * @return none *************************************************************************/ void setStartReservoirVolume( void ) { DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); DG_RESERVOIR_ID_T inactiveRes; F32 resVolume; // get volume of inactive reservoir if ( DG_RESERVOIR_2 == activeRes ) { inactiveRes = DG_RESERVOIR_1; resVolume = getLoadCellWeightInGrams( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else { inactiveRes = DG_RESERVOIR_2; resVolume = getLoadCellWeightInGrams( LOAD_CELL_RESERVOIR_2_PRIMARY ); } // set starting baseline volume for next reservoir before we switch to it resStartVolume[ inactiveRes ] = resVolume; } /*********************************************************************//** * @brief * The signalReservoirsSwitched function informs this module that the * reservoirs have been switched. The UF volume from prior reservoirs is * tentatively added to with a load cell reading of the inactive reservoir. * @details * Inputs : resFinalVolume[], resStartVolume[] * Outputs : measUFVolumeFromPriorReservoirs * @return none *************************************************************************/ void signalReservoirsSwitched( void ) { DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); DG_RESERVOIR_ID_T inactiveRes = ( activeRes == DG_RESERVOIR_1 ? DG_RESERVOIR_2 : DG_RESERVOIR_1 ); // update UF volume from prior reservoirs per tentative res volume for last reservoir measUFVolumeFromPriorReservoirs += ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); } /*********************************************************************//** * @brief * The setFinalReservoirVolume function updates the UF volume from prior reservoirs * with a more stable final reservoir volume of the prior reservoir after it's * had a moment to settle. * @details * Inputs : active reservoir, load cell reading from inactive reservoir * Outputs : measUFVolumeFromPriorReservoirs, resFinalVolume[], resStartVolume[] * @return none *************************************************************************/ void setFinalReservoirVolume( void ) { DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); DG_RESERVOIR_ID_T inactiveRes; F32 resVolume; // get volume of inactive reservoir if ( DG_RESERVOIR_2 == activeRes ) { inactiveRes = DG_RESERVOIR_1; resVolume = getLoadCellWeightInGrams( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else { inactiveRes = DG_RESERVOIR_2; resVolume = getLoadCellWeightInGrams( LOAD_CELL_RESERVOIR_2_PRIMARY ); } // update UF volume from prior reservoirs per final res volume for last reservoir a bit after we've switched and reservoir has settled measUFVolumeFromPriorReservoirs -= ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); resFinalVolume[ inactiveRes ] = resVolume; measUFVolumeFromPriorReservoirs += ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); } /**@}*/