Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -re1b010909170d0656a7b87400f295387423fd383 -r764d85698b625d8b8fc1f53d60b6c0f10dad82b8 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision e1b010909170d0656a7b87400f295387423fd383) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 764d85698b625d8b8fc1f53d60b6c0f10dad82b8) @@ -759,6 +759,18 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_INVALID_BLOOD_PUMP_DIRECTION, dir ) break; } +} + +/*********************************************************************//** + * @brief + * The getTargetBloodFlowRate function gets the target blood flow rate. + * @details Inputs: targetBloodFlowRate + * @details Outputs: none + * @return the current target blood flow rate (in mL/min). + *************************************************************************/ +S32 getTargetBloodFlowRate( void ) +{ + return targetBloodFlowRate; } /*********************************************************************//** Index: firmware/App/Controllers/BloodFlow.h =================================================================== diff -u -r8cebc7f282f403c99f712d422454c15414b6fc73 -r764d85698b625d8b8fc1f53d60b6c0f10dad82b8 --- firmware/App/Controllers/BloodFlow.h (.../BloodFlow.h) (revision 8cebc7f282f403c99f712d422454c15414b6fc73) +++ firmware/App/Controllers/BloodFlow.h (.../BloodFlow.h) (revision 764d85698b625d8b8fc1f53d60b6c0f10dad82b8) @@ -67,7 +67,8 @@ void resetBloodPumpRotorCount( void ); SELF_TEST_STATUS_T execBloodFlowTest( void ); - + +S32 getTargetBloodFlowRate( void ); F32 getMeasuredBloodFlowRate( void ); F32 getMeasuredBloodPumpRotorSpeed( void ); F32 getMeasuredBloodPumpSpeed( void ); Index: firmware/App/Modes/BloodPrime.c =================================================================== diff -u -re45524455c005d4fa1734efcbaf7ed0499302670 -r764d85698b625d8b8fc1f53d60b6c0f10dad82b8 --- firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision e45524455c005d4fa1734efcbaf7ed0499302670) +++ firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision 764d85698b625d8b8fc1f53d60b6c0f10dad82b8) @@ -37,7 +37,8 @@ // ********** private definitiions *********** #define TARGET_BLOOD_PRIME_VOLUME_ML 300.0 ///< Target blood prime volume to prime the blood side circuit (in mL). -#define MIN_RAMP_TIME_SEC 60 ///< Minimum ramp time for blood prime (in seconds). +#define MAX_BLOOD_PRIME_VOLUME_ERROR_ML 60.0 ///< Maximum error in total additional blood prime volume (20% of total). +#define MIN_RAMP_TIME_SEC 60 ///< Minimum ramp time for blood prime (in seconds). /// Initial flow rate for blood pump when starting blood prime operation. #define BLOOD_PRIME_INIT_BP_FLOW_RATE_ML_MIN 100 @@ -63,7 +64,8 @@ /// Interval (in task intervals) at which to publish blood prime data to CAN bus. static OVERRIDE_U32_T bloodPrimePublishInterval = { BLOOD_PRIME_DATA_PUBLISH_INTERVAL, BLOOD_PRIME_DATA_PUBLISH_INTERVAL, BLOOD_PRIME_DATA_PUBLISH_INTERVAL, 0 }; -static OVERRIDE_F32_T cumulativeBloodPrimeVolume_mL = { 0.0, 0.0, 0.0, 0 }; ///< Total cumulative blood prime volume (in mL). +static OVERRIDE_F32_T cumulativeBloodPrimeVolume_mL = { 0.0, 0.0, 0.0, 0 }; ///< Total cumulative blood prime volume (in mL) from measured blood flow rate. +static F32 expectedBloodPrimeVolume_mL = 0.0; ///< Total cumulative blood prime volume (in mL) expected based on target blood flow rate. // ********** private function prototypes ********** @@ -88,6 +90,7 @@ bloodPrimeRampControlTimerCtr = 0; bloodPrimePublishTimerCtr = BLOOD_PRIME_DATA_PUBLISH_INTERVAL; cumulativeBloodPrimeVolume_mL.data = 0.0; + expectedBloodPrimeVolume_mL = 0.0; resetBloodPrimeFlags(); bloodPrimeRampFlowRate_mL_min = (F32)BLOOD_PRIME_INIT_BP_FLOW_RATE_ML_MIN; @@ -218,6 +221,7 @@ // Update blood prime volume delivered so far cumulativeBloodPrimeVolume_mL.data += ( getMeasuredBloodFlowRate() * BLOOD_PRIME_FLOW_INTEGRATOR ); + expectedBloodPrimeVolume_mL += ( (F32)getTargetBloodFlowRate() * BLOOD_PRIME_FLOW_INTEGRATOR ); // Has blood prime completed? if ( getBloodPrimeVolume() >= TARGET_BLOOD_PRIME_VOLUME_ML ) @@ -229,7 +233,7 @@ } #ifndef DISABLE_PUMP_FLOW_CHECKS // Is blood prime taking too long based on set BP rate? - else if ( TBD ) + else if ( fabs( expectedBloodPrimeVolume_mL - getBloodPrimeVolume() ) > MAX_BLOOD_PRIME_VOLUME_ERROR_ML ) { activateAlarmNoData( ALARM_ID_BLOOD_PRIME_VOLUME_CHECK_FAILURE ); } Index: firmware/App/Modes/Dialysis.c =================================================================== diff -u -r5a7466b55633b0c439a2ca8ed6d4c4f4356feae9 -r764d85698b625d8b8fc1f53d60b6c0f10dad82b8 --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 5a7466b55633b0c439a2ca8ed6d4c4f4356feae9) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 764d85698b625d8b8fc1f53d60b6c0f10dad82b8) @@ -47,8 +47,7 @@ #define MAX_SALINE_VOLUME_DELIVERED 800 ///< Maximum saline volume delivered for a treatment. #define SALINE_BOLUS_RATE_ML_MIN 150 ///< Fixed rate for saline bolus delivery. -#define MIN_SALINE_BOLUS_VOLUME_PCT 0.8 ///< Minimum saline bolus volume measured by independent means (as % of target). -#define MAX_SALINE_BOLUS_VOLUME_PCT 1.2 ///< Maximum saline bolus volume measured by independent means (as % of target). +#define MAX_BOLUS_ERROR_PCT 0.2 ///< Maximum error in saline bolus volume delivered (as a percentage of target). #define MAX_ACTIVE_LOAD_CELL_CHANGE_G 50.0 ///< Maximum delta between new and previous measured UF volume. @@ -78,8 +77,9 @@ 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 salineBolusAutoResumeUF = FALSE; ///< Flag indicates UF should be auto-resumed after saline bolus completes. -static F32 totalSalineVolumeDelivered; ///< Volume (mL) in total of saline delivered so far (cumulative for all boluses including current one). -static F32 bolusSalineVolumeDelivered; ///< Volume (mL) of current bolus delivered so far. +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. @@ -136,7 +136,7 @@ setUFRate = 0.0; salineBolusBroadcastTimerCtr = 0; - totalSalineVolumeDelivered = 0.0; + totalSalineVolumeDelivered_mL = 0.0; uFAccuracyCheckTimerCtr = 0; lastUFVolumeChecked = 0.0; @@ -157,7 +157,8 @@ { salineBolusStartRequested = FALSE; salineBolusAbortRequested = FALSE; - bolusSalineVolumeDelivered = 0.0; + bolusSalineVolumeDelivered_mL = 0.0; + expectedSalineBolusVolume_mL = 0.0; if ( currentSalineBolusState != SALINE_BOLUS_STATE_MAX_DELIVERED ) { currentSalineBolusState = SALINE_BOLUS_STATE_IDLE; @@ -356,7 +357,7 @@ { rejReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } - else if ( totalSalineVolumeDelivered >= (F32)MAX_SALINE_VOLUME_DELIVERED ) + else if ( totalSalineVolumeDelivered_mL >= (F32)MAX_SALINE_VOLUME_DELIVERED ) { rejReason = REQUEST_REJECT_REASON_SALINE_MAX_VOLUME_REACHED; } @@ -486,7 +487,7 @@ *************************************************************************/ F32 getTotalSalineBolusVolumeDelivered( void ) { - return totalSalineVolumeDelivered; + return totalSalineVolumeDelivered_mL; } /*********************************************************************//** @@ -868,7 +869,7 @@ if ( ( FALSE == isBloodPumpRunning() ) && ( FALSE == isDialInPumpRunning() ) && ( FALSE == isDialOutPumpRunning() ) ) { // Reset bolus data before we start - bolusSalineVolumeDelivered = 0.0; + bolusSalineVolumeDelivered_mL = 0.0; bolusSalineLastVolumeTimeStamp = getMSTimerCount(); // Bypass dialyzer @@ -910,13 +911,16 @@ BOOL errorFound = FALSE; F32 timeSinceLastVolumeUpdateMin = (F32)calcTimeSince( bolusSalineLastVolumeTimeStamp ) / (F32)( MS_PER_SECOND * SEC_PER_MIN ); F32 bolusTargetVolume = (F32)getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); + F32 maxBolusErrorMl = bolusTargetVolume * MAX_BOLUS_ERROR_PCT; F32 bldFlowRate = getMeasuredBloodFlowRate(); // TODO - should I use raw flow instead of filtered here??? F32 volSinceLastUpdateMl = bldFlowRate * timeSinceLastVolumeUpdateMin; + F32 expVolSinceLastUpdateMl = (F32)getTargetBloodFlowRate() * timeSinceLastVolumeUpdateMin; // Update saline bolus volumes bolusSalineLastVolumeTimeStamp = getMSTimerCount(); - bolusSalineVolumeDelivered += volSinceLastUpdateMl; - totalSalineVolumeDelivered += volSinceLastUpdateMl; + bolusSalineVolumeDelivered_mL += volSinceLastUpdateMl; + totalSalineVolumeDelivered_mL += volSinceLastUpdateMl; + expectedSalineBolusVolume_mL += expVolSinceLastUpdateMl; // Check for empty saline bag per arterial line pressure if ( TRUE == isSalineBagEmpty() ) @@ -927,14 +931,14 @@ } // Determine if we have reached maximum saline delivery volume - if ( ( totalSalineVolumeDelivered >= (F32)MAX_SALINE_VOLUME_DELIVERED ) ) + if ( ( totalSalineVolumeDelivered_mL >= (F32)MAX_SALINE_VOLUME_DELIVERED ) ) { result = SALINE_BOLUS_STATE_MAX_DELIVERED; } else { // Determine if bolus is complete - if ( bolusSalineVolumeDelivered >= bolusTargetVolume ) + if ( bolusSalineVolumeDelivered_mL >= bolusTargetVolume ) { result = SALINE_BOLUS_STATE_IDLE; } @@ -945,8 +949,8 @@ result = SALINE_BOLUS_STATE_IDLE; } #ifndef DISABLE_PUMP_FLOW_CHECKS - // Determine if saline bolus delivery is taking too long to complete - else if ( TBD ) + // Determine if saline bolus is under/over delivering + else if ( fabs( expectedSalineBolusVolume_mL - bolusSalineVolumeDelivered_mL ) > maxBolusErrorMl ) { activateAlarmNoData( ALARM_ID_SALINE_BOLUS_VOLUME_CHECK_FAILURE ); errorFound = TRUE; @@ -964,8 +968,8 @@ // Send last saline bolus data salineBolusBroadcastTimerCtr = SALINE_BOLUS_DATA_PUB_INTERVAL; publishSalineBolusData(); - sendTreatmentLogEventData( SALINE_BOLUSES_CHANGE_EVENT, bolusSalineVolumeDelivered, totalSalineVolumeDelivered ); - bolusSalineVolumeDelivered = 0.0; + sendTreatmentLogEventData( SALINE_BOLUSES_CHANGE_EVENT, bolusSalineVolumeDelivered_mL, totalSalineVolumeDelivered_mL ); + bolusSalineVolumeDelivered_mL = 0.0; // Dialysis back to UF state *dialysisState = DIALYSIS_UF_STATE; // End dialyzer bypass and resume dialysis if no alarms triggered @@ -1021,8 +1025,8 @@ SALINE_BOLUS_DATA_PAYLOAD_T data; data.tgtSalineVolumeMl = getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); - data.cumSalineVolumeMl = totalSalineVolumeDelivered; - data.bolSalineVolumeMl = bolusSalineVolumeDelivered; + data.cumSalineVolumeMl = totalSalineVolumeDelivered_mL; + data.bolSalineVolumeMl = bolusSalineVolumeDelivered_mL; broadcastData( MSG_ID_SALINE_BOLUS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( SALINE_BOLUS_DATA_PAYLOAD_T ) ); salineBolusBroadcastTimerCtr = 0; } Index: firmware/App/Modes/Rinseback.c =================================================================== diff -u -re45524455c005d4fa1734efcbaf7ed0499302670 -r764d85698b625d8b8fc1f53d60b6c0f10dad82b8 --- firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision e45524455c005d4fa1734efcbaf7ed0499302670) +++ firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 764d85698b625d8b8fc1f53d60b6c0f10dad82b8) @@ -39,6 +39,7 @@ #define TARGET_RINSEBACK_VOLUME_ML 300.0 ///< Target rinseback volume to deliver back to the patient (in mL). TODO - get from Systems when available #define MAX_TOTAL_ADDITIONAL_RINSEBACK_VOLUME_ML 300.0 ///< Maximum total additional rinseback volume allowed : all additionals (in mL). +#define MAX_RINSEBACK_VOLUME_ERROR_ML 60.0 ///< Maximum error in total additional rinseback volume (20% of total). #define TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML 10.0 ///< Target rinseback volume for an additional volume request (in mL). #define RINSEBACK_FLOW_RATE_ADJ_ML_MIN 25 ///< Adjustment amount (in mL/min) to apply when user requests increase/decrease in flow rate. #define MIN_RINSEBACK_FLOW_RATE_ML_MIN 50 ///< Minimum rinseback flow rate (in mL/min). @@ -63,12 +64,11 @@ static U32 rinsebackRate_mL_min; ///< Rinseback rate to use/adjust for this current rinseback only. static U32 rinsebackTimerCtr; ///< Timer counter for time spent in rinseback sub-mode. -static OVERRIDE_F32_T cumulativeRinsebackVolume_mL = { 0.0, 0.0, 0.0, 0 }; ///< Total cumulative rinseback volume (in mL). +static OVERRIDE_F32_T cumulativeRinsebackVolume_mL = { 0.0, 0.0, 0.0, 0 }; ///< Total cumulative rinseback volume (in mL) from measured blood flow rate. +static F32 expectedRinsebackVolume_mL = 0.0; ///< Total cumulative rinseback volume (in mL) expected based on target blood flow rate. static F32 targetRinsebackVolumePlusAdditional_mL; ///< Target rinseback volume w/ additional volume(s) added (in mL). static F32 additionalRinsebackVolume_mL; ///< Total volume (in mL) delivered so far for additional volume request. static F32 totalAdditionalRinsebackVolume_mL; ///< Total accumulated volume (in mL) delivered so far for all additional volumes combined. -static S32 rinsebackMotorCount; ///< The cumulative sum of BP motor encoder counts used for independent rinseback volume check. -static U32 rinsebackLastMotorCount; ///< The last BP motor encoder count read for independent rinseback volume check. static U32 rinsebackAdditionalTimerCtr; ///< Timer counter for duration of an additional rinseback delivery. static U32 rinsebackPublishTimerCtr; ///< Timer counter for determining interval for rinseback status to be published. /// Interval (in task intervals) at which to publish rinseback data to CAN bus. @@ -128,10 +128,9 @@ targetRinsebackVolumePlusAdditional_mL = TARGET_RINSEBACK_VOLUME_ML; rinsebackTimerCtr = 0; cumulativeRinsebackVolume_mL.data = 0.0; + expectedRinsebackVolume_mL = 0.0; additionalRinsebackVolume_mL = 0.0; totalAdditionalRinsebackVolume_mL = 0.0; - rinsebackMotorCount = 0; - rinsebackLastMotorCount = getBloodPumpMotorCount(); rinsebackAdditionalTimerCtr = 0; rinsebackPublishTimerCtr = 0; resetRinsebackFlags(); @@ -326,7 +325,6 @@ // Has user requested rinseback start? if ( TRUE == startRinsebackRequested ) { - rinsebackLastMotorCount = getBloodPumpMotorCount(); setupForRinsebackDelivery( rinsebackRate_mL_min ); // From moment we start rinseback, we consider blood side of dialyzer no longer fully primed setBloodIsPrimed( FALSE ); @@ -370,6 +368,7 @@ // Update rinseback volume delivered so far cumulativeRinsebackVolume_mL.data += ( getMeasuredBloodFlowRate() * RINSEBACK_FLOW_INTEGRATOR ); + expectedRinsebackVolume_mL += ( (F32)getTargetBloodFlowRate() * RINSEBACK_FLOW_INTEGRATOR ); // Has user requested to end rinseback? if ( TRUE == endRinsebackRequested ) @@ -401,7 +400,7 @@ } #ifndef DISABLE_PUMP_FLOW_CHECKS // Is rinseback taking too long? - else if ( TBD ) + else if ( fabs( expectedRinsebackVolume_mL - getRinsebackVolume() ) > MAX_RINSEBACK_VOLUME_ERROR_ML ) { setRinsebackIsCompleted( TRUE ); setupForRinsebackStopOrPause();