Index: firmware/App/Controllers/PresOccl.c =================================================================== diff -u -rf284ba9abf19a9bdc01e56805875125778d14229 -rb9831092e46ca9147e360a49655eb7dc26ec498c --- firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision f284ba9abf19a9bdc01e56805875125778d14229) +++ firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision b9831092e46ca9147e360a49655eb7dc26ec498c) @@ -102,6 +102,7 @@ #define OCCLUSION_THRESHOLD_OFFSET 5500 ///< Threshold offset. Combined with initial reading after cartridge install, a threshold is derived above which an occlusion is detected. #define OCCLUSION_CLEAR_THRESHOLD_OFFSET 5000 ///< Threshold offset. Combined with initial reading after cartridge install, a threshold is derived below which an occlusion is cleared. +#define PARTIAL_OCCLUSION_THRESHOLD_OFFSET 1000 ///< Threshold offset. Combined with during treatment occlusion reading, a threshold is derived above which a partial occlusion is detected. #define CARTRIDGE_LOADED_THRESHOLD 5000 ///< Threshold above which a cartridge is considered loaded. #define MIN_OCCLUSION_COUNTS 2000 ///< Minimum occlusion sensor reading for range check. @@ -127,6 +128,11 @@ /// Measured venous pressure is filtered w/ 1 second moving average for inline pressure and unfiltered for occlusion detection. #define SIZE_OF_SHORT_VEN_ROLLING_AVG ( ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) * 1 ) +/// Measured blood pump occlusion is filtered w/ 10 second moving average for partial occlusions check. +#define SIZE_OF_BLOODPUMP_OCCL_ROLLING_AVG ( ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) * 10 ) +/// Interval (15 minutes in task time) at which the partial blood pump occlusion baseline update happens during dialysis state. +#define PERIODIC_PARTIAL_BLOODPUMP_OCCL_BASELINE_UPDATE ( ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) * SEC_PER_MIN * 15 ) + #define DATA_PUBLISH_COUNTER_START_COUNT 5 ///< Data publish counter start count. #define SHIFT_14_BITS 14 ///< Shift 14 bits. @@ -179,14 +185,23 @@ static OVERRIDE_F32_T shortFilteredArterialPressure = { 0.0, 0.0, 0.0, 0 }; ///< Measured arterial pressure after short (1 s) filter. static F32 longFilteredVenousPressure; ///< Measured venous pressure after long (10 s) filter. static OVERRIDE_F32_T shortFilteredVenousPressure = { 0.0, 0.0, 0.0, 0 }; ///< Measured venous pressure after short (1 s) filter. -static STABILIZATION_PERIODS_T pressureStabilizeTime; ///< Pressure stabilization time based on system events such as airpump, treatment param changes etc., +static OVERRIDE_F32_T filteredBloodPumpOccl = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump occlusion after 10s filter. +static STABILIZATION_PERIODS_T pressureStabilizeTime; ///< Pressure stabilization time based on system events such as airpump, treatment param changes etc., static BOOL resetFillExemptPeriod; ///< Flag to reset the exempt period after defined time expire. static BOOL lowVenousPressureExemptCheck; ///< low venous pressure exempt check flag based on the air trap valve status static U32 bloodPumpOcclusionAfterCartridgeInstall; ///< Measured blood pump occlusion reading taken after cartridge install. +static OVERRIDE_F32_T bloodPumpPartialOcclusionBaseline = { 0.0, 0.0, 0.0, 0 }; ///< Measured filtered blood pump occlusion baseline taken during treatment. +static BOOL partialBloodPumpOcclBaselineUpdate; ///< Flag to update partial occlusion baseline in events such as start of treatment,resume from partial BP occlusion alarm occurrence. +static U32 partialBloodPumpOcclBaselineUpdateTimerCounter = 0; ///< Used to update partial occlusion base line periodically during dialysis. static U32 emptySalineBagCtr = 0; ///< Timer counter for empty bag detection. +static U32 bloodPumpOcclReadings[ SIZE_OF_BLOODPUMP_OCCL_ROLLING_AVG ]; ///< Holds blood pump occlusion rolling average. +static U32 bloodPumpOcclReadingsIdx = 0; ///< Index for next sample in rolling average array. +static U32 bloodPumpOcclReadingsTotal = 0; ///< Rolling total - used to calc average. +static U32 bloodPumpOcclReadingsCount = 0; ///< Number of samples in blood pump occl rolling average buffer. + static F32 artPressureReadingsLong[ SIZE_OF_LONG_ART_ROLLING_AVG ]; ///< Holds flow samples for long arterial pressure rolling average. static U32 artPressureReadingsLongIdx = 0; ///< Index for next sample in rolling average array. static F32 artPressureReadingsLongTotal = 0.0; ///< Rolling total - used to calc average. @@ -224,6 +239,8 @@ static void publishPresOcclData( void ); static void determineArtVenPressureLimits( void ); static void filterInlinePressureReadings( F32 artPres, F32 venPres ); +static void setOcclusionBaselineDuringTreatement( void ); +static void filterBloodPumpOcclReadings( U32 bloodPumpOccl ); /*********************************************************************//** * @brief @@ -266,10 +283,14 @@ shortFilteredArterialPressure.data = 0.0F; longFilteredVenousPressure = 0.0F; shortFilteredVenousPressure.data = 0.0F; + filteredBloodPumpOccl.data = 0.0F; + bloodPumpPartialOcclusionBaseline.data = 0.0F; + partialBloodPumpOcclBaselineUpdateTimerCounter = 0; presOcclDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; presOcclState = PRESSURE_WAIT_FOR_POST_STATE; presOcclPostState = PRESSURE_SELF_TEST_STATE_START; bloodPumpOcclusionAfterCartridgeInstall = 0; + partialBloodPumpOcclBaselineUpdate = FALSE; pressureStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; resetFillExemptPeriod = TRUE; lowVenousPressureExemptCheck = TRUE; @@ -394,6 +415,22 @@ /*********************************************************************//** * @brief + * The setOcclusionBaselineDuringTreatement function sets the partial occlusion sensor level + * during treatment. This function called at start of treatment, periodic interval during + * treatment. + * @details Inputs: filteredBloodPumpOccl + * @details Outputs: bloodPumpPartialOcclusionBaseline + * @return none + *************************************************************************/ +static void setOcclusionBaselineDuringTreatement( void ) +{ + bloodPumpPartialOcclusionBaseline.data = getFilteredBloodPumpOccl(); + partialBloodPumpOcclBaselineUpdateTimerCounter = 0; + SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_PARTIAL_OCCLUSION_BASELINE, getBloodPumpPartialOcclBaseline(), PARTIAL_OCCLUSION_THRESHOLD_OFFSET ); +} + +/*********************************************************************//** + * @brief * The setPressureLimitsToOuterBounds function sets the min/max pressure * limits for arterial and venous pressure to their outer boundaries. * @details Inputs: none @@ -526,6 +563,18 @@ /*********************************************************************//** * @brief + * The signalBloodPumpPressureOcclBaseline function sets the flag. + * @details Inputs: partialBloodPumpOcclBaselineUpdate + * @details Outputs: partialBloodPumpOcclBaselineUpdate + * @return none + *************************************************************************/ +void signalBloodPumpPressureOcclBaseline( void ) +{ + partialBloodPumpOcclBaselineUpdate = TRUE; +} + +/*********************************************************************//** + * @brief * The execPresOccl function executes the pressure and occlusion monitor. * @details Inputs: presOcclState * @details Outputs: presOcclState @@ -627,6 +676,12 @@ currPresLimitsState = PRESSURE_LIMITS_STATE_OFF; } + // Increment the partial occlusion baseline update counter only in Dialysis state + if ( ( MODE_TREA == currMode ) && ( currTxState == TREATMENT_DIALYSIS_STATE ) ) + { + partialBloodPumpOcclBaselineUpdateTimerCounter++; + } + switch ( currPresLimitsState ) { case PRESSURE_LIMITS_STATE_OFF: @@ -686,6 +741,13 @@ stabilizationStartTimeMs = getMSTimerCount(); currPresLimitsState = PRESSURE_LIMITS_STATE_STABILIZATION_2; pressureStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; + + //Update partial blood pump occlusion baseline only in dialysis state + if ( ( TRUE == partialBloodPumpOcclBaselineUpdate ) && ( TREATMENT_DIALYSIS_STATE == currTxState ) ) + { + partialBloodPumpOcclBaselineUpdate = FALSE; + setOcclusionBaselineDuringTreatement(); + } } break; @@ -718,6 +780,12 @@ // Reset to normal period as default. pressureStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; } + else if ( ( currTxState == TREATMENT_DIALYSIS_STATE ) && + ( partialBloodPumpOcclBaselineUpdateTimerCounter >= PERIODIC_PARTIAL_BLOODPUMP_OCCL_BASELINE_UPDATE ) ) + { + //Periodical Update of partial blood pump occlusion baseline + setOcclusionBaselineDuringTreatement(); + } break; case PRESSURE_LIMITS_STATE_STABLE: @@ -736,6 +804,12 @@ pressureStabilizeTime = STABILIZATION_PERIOD_OFF; currPresLimitsState = PRESSURE_LIMITS_STATE_STABILIZATION_2; } + else if ( ( currTxState == TREATMENT_DIALYSIS_STATE ) && + ( partialBloodPumpOcclBaselineUpdateTimerCounter >= PERIODIC_PARTIAL_BLOODPUMP_OCCL_BASELINE_UPDATE ) ) + { + //Periodical Update of partial blood pump occlusion baseline + setOcclusionBaselineDuringTreatement(); + } break; default: @@ -812,6 +886,9 @@ // Record occlusion sensor readings bloodPumpOcclusion.data = (U32)getFPGABloodPumpOcclusion(); + + // Filter blood pump occlusion readings + filterBloodPumpOcclReadings( getMeasuredBloodPumpOcclusion() ); } /*********************************************************************//** @@ -965,6 +1042,7 @@ static void checkOcclusions( void ) { U32 bpOccl = getMeasuredBloodPumpOcclusion(); + F32 filteredBpOccl = getFilteredBloodPumpOccl(); BOOL outOfRange = ( bpOccl < MIN_OCCLUSION_COUNTS ? TRUE : FALSE ); #ifndef _RELEASE_ @@ -983,6 +1061,7 @@ U32 hdSubMode = getCurrentSubMode(); BOOL ptxMode = ( MODE_PRET == hdMode && hdSubMode > HD_PRE_TREATMENT_CART_INSTALL_STATE ? TRUE : FALSE ); BOOL txModeRecirc = ( ( MODE_TREA == hdMode ) && ( TREATMENT_RECIRC_STATE == getTreatmentState() ) ? TRUE : FALSE ); + BOOL txModeDialysis = ( ( MODE_TREA == hdMode ) && ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) ? TRUE : FALSE ); // Range check occlusion sensor (OB) if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, outOfRange ) ) @@ -1026,6 +1105,21 @@ clearAlarmCondition( ALARM_ID_HD_OCCLUSION_BLOOD_PUMP ); } + // Partial Occlusion check during treatment dialysis state and pressure stable or stabilization_2 state + if ( ( TRUE == txModeDialysis ) && + ( ( PRESSURE_LIMITS_STATE_STABLE == currPresLimitsState ) || + ( PRESSURE_LIMITS_STATE_STABILIZATION_2 == currPresLimitsState ) ) ) + { + // Check for partial occlusion + if ( filteredBpOccl > ( PARTIAL_OCCLUSION_THRESHOLD_OFFSET + getBloodPumpPartialOcclBaseline() ) ) + { + signalBloodPumpHardStop(); // Stop pump immediately + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PARTIAL_OCCLUSION_BLOOD_PUMP, filteredBpOccl, PARTIAL_OCCLUSION_THRESHOLD_OFFSET + getBloodPumpPartialOcclBaseline() ) + // Update partial occlusion baseline + signalBloodPumpPressureOcclBaseline(); + } + } + // Check for venous occlusion #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_VENOUS_PRESSURE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) @@ -1131,6 +1225,30 @@ /*********************************************************************//** * @brief + * The getFilteredBloodPumpOccl function gets the measured filtered blood pump occlusion. + * @details Inputs: filteredBloodPumpOccl + * @details Outputs: none + * @return the current filtered blood pump occlusion. + *************************************************************************/ +F32 getFilteredBloodPumpOccl( void ) +{ + return getF32OverrideValue( &filteredBloodPumpOccl ); +} + +/*********************************************************************//** + * @brief + * The getBloodPumpPartialOcclBaseline function gets the blood pump partial occlusion baseline. + * @details Inputs: bloodPumpPartialOcclusionBaseline + * @details Outputs: none + * @return the blood pump occlusion base line. + *************************************************************************/ +F32 getBloodPumpPartialOcclBaseline( void ) +{ + return getF32OverrideValue( &bloodPumpPartialOcclusionBaseline ); +} + +/*********************************************************************//** + * @brief * The getFilteredVenousPressure function gets the measured filtered venous pressure. * @details Inputs: shortFilteredVenousPressure * @details Outputs: none @@ -1236,6 +1354,29 @@ /*********************************************************************//** * @brief + * The filterBloodPumpOcclReadings function adds a new blood pump occlusion + * sample to the filters. + * @details Inputs: none + * @details Outputs: bloodPumpOcclReadings[], bloodPumpOcclReadingsIdx, bloodPumpOcclReadingsTotal, bloodPumpOcclReadingsCount, + * filteredBloodPumpOccl + * @param bloodPumpOccl newest blood pump occlusion sample to add to filters + * @return none + *************************************************************************/ +static void filterBloodPumpOcclReadings( U32 bloodPumpOccl ) +{ + if ( bloodPumpOcclReadingsCount >= SIZE_OF_BLOODPUMP_OCCL_ROLLING_AVG ) + { + bloodPumpOcclReadingsTotal -= bloodPumpOcclReadings[ bloodPumpOcclReadingsIdx ]; + } + bloodPumpOcclReadings[ bloodPumpOcclReadingsIdx ] = bloodPumpOccl; + bloodPumpOcclReadingsTotal += bloodPumpOccl; + bloodPumpOcclReadingsIdx = INC_WRAP( bloodPumpOcclReadingsIdx, 0, SIZE_OF_BLOODPUMP_OCCL_ROLLING_AVG - 1 ); + bloodPumpOcclReadingsCount = INC_CAP( bloodPumpOcclReadingsCount, SIZE_OF_BLOODPUMP_OCCL_ROLLING_AVG ); + filteredBloodPumpOccl.data = (F32)bloodPumpOcclReadingsTotal / (F32)bloodPumpOcclReadingsCount; +} + +/*********************************************************************//** + * @brief * The publishPresOcclData function publishes pressure/occlusion data at the * set interval. * @details Inputs: latest pressure and occlusion readings @@ -1249,16 +1390,18 @@ { PRESSURE_OCCLUSION_DATA_T data; - data.arterialPressure = getFilteredArterialPressure(); - data.venousPressure = getFilteredVenousPressure(); - data.bldPumpOcclusion = getMeasuredBloodPumpOcclusion(); - data.presLimitState = currPresLimitsState; - data.artMinLimit = currentArterialMinLimit; - data.artMaxLimit = currentArterialMaxLimit; - data.venMinLimit = currentVenousMinLimit; - data.venMaxLimit = currentVenousMaxLimit; - data.arterialLongFilterPres = longFilteredArterialPressure; - data.venousLongFilterPres = longFilteredVenousPressure; + data.arterialPressure = getFilteredArterialPressure(); + data.venousPressure = getFilteredVenousPressure(); + data.bldPumpOcclusion = getMeasuredBloodPumpOcclusion(); + data.presLimitState = currPresLimitsState; + data.artMinLimit = currentArterialMinLimit; + data.artMaxLimit = currentArterialMaxLimit; + data.venMinLimit = currentVenousMinLimit; + data.venMaxLimit = currentVenousMaxLimit; + data.arterialLongFilterPres = longFilteredArterialPressure; + data.venousLongFilterPres = longFilteredVenousPressure; + data.bldPumpOcclusionLongFilter = getFilteredBloodPumpOccl(); + data.partialOcclBaseline = getBloodPumpPartialOcclBaseline(); broadcastData( MSG_ID_PRESSURE_OCCLUSION_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( PRESSURE_OCCLUSION_DATA_T ) ); presOcclDataPublicationTimerCounter = 0; @@ -1581,4 +1724,94 @@ return result; } +/*********************************************************************//** + * @brief + * The testSetFilteredBloodPumpOcclusionOverride function overrides the measured + * filtered blood pump occlusion pressure. + * @details Inputs: none + * @details Outputs: filteredBloodPumpOccl + * @param value override measured filtered blood pump occlusion pressure with + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetFilteredBloodPumpOcclusionOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + filteredBloodPumpOccl.ovData = value; + filteredBloodPumpOccl.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetFilteredBloodPumpOcclusionOverride function resets the override of the + * measured filtered blood pump occlusion pressure. + * @details Inputs: none + * @details Outputs: filteredBloodPumpOccl + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetFilteredBloodPumpOcclusionOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + filteredBloodPumpOccl.override = OVERRIDE_RESET; + filteredBloodPumpOccl.ovData = filteredBloodPumpOccl.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetBloodPumpPartialOcclusionOverride function overrides the + * blood pump partial occlusion pressure baseline. + * @details Inputs: none + * @details Outputs: bloodPumpPartialOcclusionBaseline + * @param value override blood pump occlusion baseline + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetBloodPumpPartialOcclusionBaselineOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpPartialOcclusionBaseline.ovData = value; + bloodPumpPartialOcclusionBaseline.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetBloodPumpPartialOcclusionBaselineOverride function resets the override of the + * blood pump partial occlusion baseline. + * @details Inputs: none + * @details Outputs: bloodPumpPartialOcclusionBaseline + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetBloodPumpPartialOcclusionBaselineOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpPartialOcclusionBaseline.override = OVERRIDE_RESET; + bloodPumpPartialOcclusionBaseline.ovData = bloodPumpPartialOcclusionBaseline.ovInitData; + } + + return result; +} + /**@}*/