Index: firmware/App/Modes/Dialysis.c =================================================================== diff -u -ra9c1eee2bed2b569a6f32cbc5e80c4631559d683 -r0ef0dc2039726fd956ea74102ec7ff0e42bd2aab --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision a9c1eee2bed2b569a6f32cbc5e80c4631559d683) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 0ef0dc2039726fd956ea74102ec7ff0e42bd2aab) @@ -39,12 +39,11 @@ // ********** private definitions ********** -#define MAX_UF_RATE_ML_PER_HOUR 2750.0F ///< Maximum ultrafiltration rate in mL/hour -#define MAX_UF_ACCURACY_ERROR_ML 50.0F ///< Maximum ultrafiltration accuracy error in mL over the entire treatment. +#define MAX_UF_VOLUME_ACCURACY_ERROR_ML 50.0F ///< Maximum ultrafiltration volume accuracy error in mL over the entire treatment. +#define MAX_UF_RATE_ACCURACY_ERROR_ML_MIN 5.0F ///< Maximum ultrafiltration rate accuracy error in mL/min over use of single reservoir during treatment. + /// Saline bolus data broadcast interval (ms/task time) count. static const U32 SALINE_BOLUS_DATA_PUB_INTERVAL = ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); -/// Ultrafiltration rate accuracy check interval count. -static const U32 UF_ACCURACY_CHECK_INTERVAL = ((1 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND) / TASK_GENERAL_INTERVAL); #define MAX_SALINE_VOLUME_DELIVERED 800 ///< Maximum saline volume delivered for a treatment. #define SALINE_BOLUS_RATE_ML_MIN 300 ///< Fixed rate for saline bolus delivery. @@ -70,8 +69,10 @@ 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 resStartRefVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Starting ultrafiltration reference volume for reservoirs. +static F32 resFinalRefVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Final ultrafiltration reference volume for reservoirs. static F32 resCurrVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir current volume. -static F32 resLastVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir previous volume. +static F32 resLastVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Previous reading of reservoir volume. static F32 measUFVolumeFromPriorReservoirs; ///< Current total ultrafiltration volume from previous reservoirs in current treatment. static F32 lcLastSteadyWeight[NUM_OF_RESERVOIR_STEADY_CYCLES][NUM_OF_LOAD_CELLS]; ///< Load Cell Last Steady Weight for drift test Start/Final cycle @@ -85,22 +86,18 @@ static U32 salineBolusBroadcastTimerCtr; ///< Saline bolus data broadcast timer counter used to schedule when to transmit data. static BOOL salineBolusStartRequested; ///< Flag indicates a saline bolus start has been requested by user. -static BOOL salineBolusAbortRequested; ///< Flag indicates a salien bolus abort has been requested by user. +static BOOL salineBolusAbortRequested; ///< Flag indicates a saline bolus abort has been requested by user. static BOOL salineBolusAutoResumeUF = FALSE; ///< Flag indicates UF should be auto-resumed after saline bolus completes. static F32 totalSalineVolumeDelivered_mL; ///< Volume (mL) in total of saline delivered so far (cumulative for all boluses including current one). static F32 bolusSalineVolumeDelivered_mL; ///< Volume (mL) of current bolus delivered so far (calculated from measured blood flow rate). static F32 expectedSalineBolusVolume_mL; ///< Volume (mL) of current bolus delivered so far (calculated from target blood flow rate). static U32 bolusSalineLastVolumeTimeStamp; ///< Time stamp for last saline volume update. -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( DIALYSIS_STATE_T *dialysisState ); static UF_STATE_T handleUFPausedState( DIALYSIS_STATE_T *dialysisState ); static UF_STATE_T handleUFRunningState( DIALYSIS_STATE_T *dialysisState ); @@ -109,7 +106,7 @@ static SALINE_BOLUS_STATE_T handleSalineBolusInProgressState( DIALYSIS_STATE_T *dialysisState ); static SALINE_BOLUS_STATE_T handleSalineBolusMaxDeliveredState( DIALYSIS_STATE_T *dialysisState ); -static void checkUFAccuracyAndVolume( void ); +static void checkUFControl( void ); static void updateUFVolumes( void ); static void publishSalineBolusData( void ); @@ -151,15 +148,23 @@ salineBolusBroadcastTimerCtr = 0; totalSalineVolumeDelivered_mL = 0.0; - uFAccuracyCheckTimerCtr = 0; - lastUFVolumeChecked = 0.0; - for ( i = 0; i < NUM_OF_LOAD_CELLS; i++ ) { lcLastSteadyWeight[RESERVOIR_STEADY_CYCLE_START][i] = LOAD_CELL_ILLEGAL_WEIGHT_VALUE; lcLastSteadyWeight[RESERVOIR_STEADY_CYCLE_FINAL][i] = LOAD_CELL_ILLEGAL_WEIGHT_VALUE; } + for ( i = 0; i < NUM_OF_DG_RESERVOIRS; i++ ) + { + resStartVolume[ i ] = 0.0F; + resFinalVolume[ i ] = 0.0F; + resStartRefVolume[ i ] = 0.0F; + resFinalRefVolume[ i ] = 0.0F; + resCurrVolume[ i ] = 0.0F; + resLastVolume[ i ] = 0.0F; + + } + resetSalineBolus(); } @@ -622,8 +627,8 @@ { DIALYSIS_STATE_T priorSubState = currentDialysisState; - // Check ultrafiltration max rate and accuracy during dialysis (even when ultrafiltration is paused). - checkUFAccuracyAndVolume(); + // Check ultrafiltration control during dialysis (even when ultrafiltration is paused). + checkUFControl(); // Dialysis state machine switch ( currentDialysisState ) @@ -798,6 +803,7 @@ // Update UF ref volume in UF running state only refUFVolume += ( ( (F32)msSinceLast / MS_PER_SECOND ) / SEC_PER_MIN ) * setUFRate; + updateReservoirUFTime(); // If we have reached target UF volume, UF is complete - set UF rate to zero for remainder of treatment if ( refUFVolume >= maxUFVolumeML ) @@ -1032,36 +1038,17 @@ /*********************************************************************//** * @brief - * The checkUF function checks ultrafiltration accuracy for the last - * hour and checks total UF volume. Triggers an alarm if out of spec. - * @details Inputs: uFAccuracyCheckTimerCtr, lastUFVolumeChecked, measUFVolume - * @details Outputs: uFAccuracyCheckTimerCtr, lastUFVolumeChecked + * The checkUFControl function checks ultrafiltration control to ensure measured + * UF volume does not deviate too far from the UF reference volume (indicating + * poor UF control). + * @details Inputs: none + * @details Outputs: none * @return none *************************************************************************/ -static void checkUFAccuracyAndVolume( void ) +static void checkUFControl( void ) { - F32 uFMeasRate = measUFVolume - lastUFVolumeChecked; // Volumes are at start/end of 1 hour period, so implied rate is per hour - - // Check UF rate over last hour - if ( uFMeasRate > MAX_UF_RATE_ML_PER_HOUR ) - { -#ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) -#endif - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_UF_RATE_TOO_HIGH_ERROR, uFMeasRate ); - } - } - // Increment timer and see if time to start another 1 hour check period - if ( ++uFAccuracyCheckTimerCtr >= UF_ACCURACY_CHECK_INTERVAL ) - { - // Reset for next check interval - lastUFVolumeChecked = measUFVolume; - uFAccuracyCheckTimerCtr = 0; - } - // Check total UF volume error - if ( ( fabs( refUFVolume - measUFVolume ) ) > MAX_UF_ACCURACY_ERROR_ML ) + if ( ( fabs( refUFVolume - measUFVolume ) ) > MAX_UF_VOLUME_ACCURACY_ERROR_ML ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) @@ -1127,6 +1114,7 @@ // Set starting baseline volume for next reservoir before we switch to it resStartVolume[ reservoirID ] = resVolume; resFinalVolume[ reservoirID ] = resVolume; + resStartRefVolume[ reservoirID ] = refUFVolume; checkLoadCellsStablePrimaryBackupDriftOutOfRange( reservoirID, RESERVOIR_STEADY_CYCLE_START ); } @@ -1146,6 +1134,9 @@ // Update UF volume from prior reservoirs per tentative res volume for last reservoir measUFVolumeFromPriorReservoirs += ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); + + // Record final UF ref volume for the spent reservoir + resFinalRefVolume[ inactiveRes ] = refUFVolume; } /*********************************************************************//** @@ -1161,12 +1152,33 @@ { DG_RESERVOIR_ID_T inactiveRes = getDGInactiveReservoir(); F32 resVolume = getReservoirWeightLargeFilter( inactiveRes ); + F32 resUFTimeInMs = (F32)getLastReservoirUFTimeInMs(); + F32 resUFTimeInMin = ( resUFTimeInMs / (F32)( SEC_PER_MIN * MS_PER_SECOND ) ); + F32 resExpUFVolumeInMl = resFinalRefVolume[ inactiveRes ] - resStartRefVolume[ inactiveRes ]; + F32 resExpUFRate = resExpUFVolumeInMl / resUFTimeInMin; + F32 uFResVolumeInMl; + F32 uFMeasRate; // Update UF volume from prior reservoirs per final res volume for last reservoir a bit after we have switched and reservoir has settled measUFVolumeFromPriorReservoirs -= ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); resFinalVolume[ inactiveRes ] = resVolume; - measUFVolumeFromPriorReservoirs += ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); + uFResVolumeInMl = ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); + measUFVolumeFromPriorReservoirs += uFResVolumeInMl; + // Check UF rate + uFMeasRate = uFResVolumeInMl / resUFTimeInMin; + + if ( fabs( resExpUFRate - uFMeasRate ) > MAX_UF_RATE_ACCURACY_ERROR_ML_MIN ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_UF_RATE_TOO_HIGH_ERROR, uFMeasRate ); + } + } + + // Check redundant load cells checkLoadCellsStablePrimaryBackupDriftOutOfRange( inactiveRes, RESERVOIR_STEADY_CYCLE_FINAL ); } Index: firmware/App/Modes/Dialysis.h =================================================================== diff -u -rf760ffc4b10556e5186e9ceb90294262063440ca -r0ef0dc2039726fd956ea74102ec7ff0e42bd2aab --- firmware/App/Modes/Dialysis.h (.../Dialysis.h) (revision f760ffc4b10556e5186e9ceb90294262063440ca) +++ firmware/App/Modes/Dialysis.h (.../Dialysis.h) (revision 0ef0dc2039726fd956ea74102ec7ff0e42bd2aab) @@ -75,7 +75,6 @@ void setStartReservoirVolume( DG_RESERVOIR_ID_T reservoirID ); void signalReservoirsSwitched( void ); void setFinalReservoirVolume( void ); -void updateReservoirVolumes( F32 res1Vol, F32 res2Vol ); F32 getReservoirUltrafiltrationVol( DG_RESERVOIR_ID_T reservoirID ); /**@}*/ Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r0035cfb9a3fa89a8f9c3e0b589a327ed9c1d9470 -r0ef0dc2039726fd956ea74102ec7ff0e42bd2aab --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 0035cfb9a3fa89a8f9c3e0b589a327ed9c1d9470) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 0ef0dc2039726fd956ea74102ec7ff0e42bd2aab) @@ -75,7 +75,9 @@ static F32 dilutionLevelPct; ///< Reservoir dilution level. static DG_OP_MODE_T dgOpMode; ///< DG operation mode. static U32 dgSubMode; ///< DG operation submode. -static U32 timeReservoirInUse; ///< Reservoir time in use in milliseconds. +static U32 timeReservoirInUse; ///< Reservoir time in use in general task intervals. +static U32 timeReservoirInUF; ///< Reservoir time in ultrafiltration (in ms). +static U32 lastTimeReservoirInUF; ///< Reservoir time in ultrafiltration from prior reservoir (in ms). static F32 volSpentUFML; ///< Ultrafiltration volume in milliliters. static DG_RESERVOIR_ID_T activeReservoir; ///< Active reservoir. static F32 recirculationLevelPct; ///< Recirculation level in percent. @@ -129,6 +131,8 @@ dgOpMode = DG_MODE_INIT; dgSubMode = 0; timeReservoirInUse = 0; + timeReservoirInUF = 0; + lastTimeReservoirInUF = 0; volSpentUFML = 0.0F; activeReservoir = DG_RESERVOIR_1; recirculationLevelPct = 0.0F; @@ -160,7 +164,7 @@ * The execReservoirs function executes the state machine for the treatment * reservoir management during treatment mode. * @details Inputs: reservoirsState - * @details Outputs: reservoirsState, timeReservoirInUse, volSpentML + * @details Outputs: reservoirsState, timeReservoirInUse, timeReservoirInUF, volSpentML * @return none *************************************************************************/ void execReservoirs( void ) @@ -182,11 +186,7 @@ if ( ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) && ( getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) ) { volSpentML += ( flowRateMLPerMS * msSinceLastVolumeCalc ); - - if ( TREATMENT_DIALYSIS_STATE == getTreatmentState()) - { - ++timeReservoirInUse; - } + timeReservoirInUse++; } // Update the reservoir start time @@ -241,6 +241,32 @@ calculateActiveReservoirCycleTime(); } +/*********************************************************************//** + * @brief + * The getLastReservoirUFTimeInMs function returns the reservoir ultrafiltration + * time (in ms) for the last reservoir used in treatment. + * @details Inputs: none + * @details Outputs: none + * @return lastTimeReservoirInUF + *************************************************************************/ +U32 getLastReservoirUFTimeInMs( void ) +{ + return lastTimeReservoirInUF; +} + +/*********************************************************************//** + * @brief + * The updateReservoirUFTime function updates the reservoir ultrafiltration + * time (in ms) for currently active reservoir used in treatment. + * @details Inputs: timeReservoirInUF + * @details Outputs: timeReservoirInUF + * @return lastTimeReservoirInUF + *************************************************************************/ +void updateReservoirUFTime( void ) +{ + timeReservoirInUF += TASK_GENERAL_INTERVAL; +} + // ********** private functions ********** /*********************************************************************//** @@ -658,6 +684,8 @@ setFinalReservoirVolume(); // Switched the active reservoir so reset the reservoir in use timer + lastTimeReservoirInUF = timeReservoirInUF; + timeReservoirInUF = 0; timeReservoirInUse = 0; // Reset to start state to restart drain, fill, switch process. Index: firmware/App/Services/Reservoirs.h =================================================================== diff -u -rf3c8ef49b4bef41b606325e3db0e053a7a72d98f -r0ef0dc2039726fd956ea74102ec7ff0e42bd2aab --- firmware/App/Services/Reservoirs.h (.../Reservoirs.h) (revision f3c8ef49b4bef41b606325e3db0e053a7a72d98f) +++ firmware/App/Services/Reservoirs.h (.../Reservoirs.h) (revision 0ef0dc2039726fd956ea74102ec7ff0e42bd2aab) @@ -35,14 +35,14 @@ // ********** public function prototypes ********** -void initReservoirs( void ); +void initReservoirs( void ); // Initialize reservoirs module +void resetReservoirsVariables( void ); // Reset reservoir variables (call when starting a new treatment) +void execReservoirs( void ); // Execute reservoir management during treatment -void resetReservoirsVariables( void ); +void setDialysateHeatingParams( void ); // Calculate and set current dialysate heating parameters and send to DG +void updateReservoirUFTime( void ); // Update time spent doing ultrafiltration for currently active reservoir +U32 getLastReservoirUFTimeInMs( void ); // Get the time spent doing ultrafiltration on the previously active reservoir -void execReservoirs( void ); - -void setDialysateHeatingParams( void ); - /**@}*/ #endif