/************************************************************************** * * Copyright (c) 2020-2023 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 PresOccl.c * * @author (last) Darren Cox * @date (last) 24-Aug-2023 * * @author (original) Sean * @date (original) 15-Jan-2020 * ***************************************************************************/ #include "PresOccl.h" #include "AirPump.h" #include "AlarmMgmt.h" #include "BloodFlow.h" #include "FPGA.h" #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "NVDataMgmt.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SystemCommMessages.h" #include "SelfTests.h" #include "TaskGeneral.h" #include "Temperatures.h" #include "Timers.h" #include "Valves.h" /** * @addtogroup PressureOcclusion * @{ */ // ********** private definitions ********** /// Default publication interval for pressure and occlusion data. #define PRES_OCCL_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the pressure/occlusion data is published on the CAN bus. #define PRES_LIMIT_STABILIZATION_TIME_MS ( 60 * MS_PER_SECOND ) ///< Duration of pressure limit stabilization period (in ms). #define PRES_LIMIT_SHORT_STABILIZE_TIME_MS ( 5 * MS_PER_SECOND ) ///< Duration of pressure limit short stabilization period (in ms). #define PRES_LIMIT_RESTABILIZE_TIME_MS ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Duration of pressure limit re-stabilize period (in ms). #define ARTERIAL_PRESSURE_CONVERSION_OFFSET 0x800000 ///< Arterial pressure conversion coefficient. #define ARTERIAL_PRESSURE_V_BIAS ( 3.0F ) ///< Bias voltage for arterial pressure sensor. #define ARTERIAL_PRESSURE_SENSITIVITY ( 0.000005F ) ///< Sensitivity for arterial pressure sensor is 5 uV / mmHg #define ARTERIAL_PRESSURE_V_PER_BIT ( ARTERIAL_PRESSURE_V_BIAS / \ (F32)ARTERIAL_PRESSURE_CONVERSION_OFFSET ) ///< Volts per bit in 24-bit arterial pressure sensor reading. #define VENOUS_PRESSURE_OFFSET ( 1638 ) ///< Offset for 14-bit venous pressure sensor reading. #define VENOUS_PRESSURE_SCALE ( 14745 - VENOUS_PRESSURE_OFFSET ) ///< Scale for venous pressure sensor. #define VENOUS_PRESSURE_MIN_PSI ( -30.0F ) ///< Minimum of scale for venous pressure sensor reading (in PSI). #define VENOUS_PRESSURE_MAX_PSI ( 30.0F ) ///< Maximum of scale for venous pressure sensor reading (in PSI). #define MIN_VENOUS_PRESSURE_FOR_RAMP_MMHG ( 0.0F ) ///< Minimum venous pressure during blood pump ramp up (in mmHg). #define VENOUS_OFFSET_WITH_AIRPUMP_MMHG ( 150.0F ) ///< Value to increase venous pressure high limit alarm when air pump is operating. #define ARTERIAL_PRESSURE_OFFSET ( 1638 ) ///< Offset for 14-bit arterial pressure sensor reading. #define ARTERIAL_PRESSURE_SCALE ( 14745 - VENOUS_PRESSURE_OFFSET ) ///< Scale for arterial pressure sensor. #define ARTERIAL_PRESSURE_MIN_PSI ( -30.0F ) ///< Minimum of scale for arterial pressure sensor reading (in PSI). #define ARTERIAL_PRESSURE_MAX_PSI ( 30.0F ) ///< Maximum of scale for arterial pressure sensor reading (in PSI). #define ARTERIAL_PRESSURE_SELF_TEST_MIN ( -100.0F ) ///< Minimum self-test value for arterial pressure sensor reading (in mmHg). #define ARTERIAL_PRESSURE_SELF_TEST_MAX ( 100.0F ) ///< Maximum self-test value for arterial pressure sensor reading (in mmHg). #define ARTERIAL_PRESSURE_MAX_MMHG ( 2000.0F ) ///< Maximum arterial pressure reading (in mmHg) for range check. #define ARTERIAL_PRESSURE_MIN_MMHG ( -1500.0F ) ///< Minimum arterial pressure reading (in mmHg) for range check. #define ARTERIAL_PRESSURE_LIMIT_MAX_MMHG ( 100.0F ) ///< Maximum arterial pressure limit (in mmHg). #define ARTERIAL_PRESSURE_LIMIT_MIN_MMHG ( -300.0F ) ///< Minimum arterial pressure limit (in mmHg). #define VENOUS_PRESSURE_SELF_TEST_MIN ( -100.0F ) ///< Minimum self-test value for venous pressure sensor reading (in mmHg). #define VENOUS_PRESSURE_SELF_TEST_MAX ( 100.0F ) ///< Maximum self-test value for venous pressure sensor reading (in mmHg). #define VENOUS_PRESSURE_MAX_MMHG ( 2000.0F ) ///< Maximum venous pressure reading (in mmHg) for range check. #define VENOUS_PRESSURE_MIN_MMHG ( -1500.0F ) ///< Minimum venous pressure reading (in mmHg) for range check. #define VENOUS_PRESSURE_LIMIT_MAX_MMHG ( 400.0F ) ///< Maximum venous pressure limit (in mmHg). #define VENOUS_PRESSURE_LIMIT_MIN_MMHG ( 20.0F ) ///< Minimum venous pressure limit (in mmHg). #define VENOUS_PRESSURE_OCCL_OFFSET_MMHG ( 50.0F ) ///< Venous pressure occlusion threshold offset from max alarm limit (in mmHg). #define VENOUS_PRES_AT_FILL_DELAY_MAX_BLOOD_VOL_ML ( 41.667F ) ///< Venous pressure low exemption delay after air trap fill maximum blood volume (in mL). /// Venous pressure low exemption period (in task intervals) conversion factor (from Qb in mL/min) following an air trap fill. static const U32 VENOUS_PRES_AT_FILL_DELAY_FACTOR = (U32)( VENOUS_PRES_AT_FILL_DELAY_MAX_BLOOD_VOL_ML * (F32)SEC_PER_MIN * ( (F32)MS_PER_SECOND / (F32)TASK_GENERAL_INTERVAL ) ); #define PSI_TO_MMHG ( 51.7149F ) ///< Conversion factor for converting PSI to mmHg. // The new arterial pressure sensor is the same as the venous pressure sensor #define VENOUS_PRESSURE_NORMAL_OP 0 ///< Venous pressure status bits indicate normal operation. #define VENOUS_PRESSURE_CMD_MODE 1 ///< Venous pressure status bits indicate sensor in command mode. #define VENOUS_PRESSURE_STALE_DATA 2 ///< Venous pressure status bits indicate data is stale (no new data since last fpga read). #define VENOUS_PRESSURE_DIAG_CONDITION 3 ///< Venous pressure status bits diagnostic condition (alarm). #define ARTERIAL_PRESSURE_NORMAL_OP 0 ///< Arterial pressure status bits indicate normal operation. #define ARTERIAL_PRESSURE_CMD_MODE 1 ///< Arterial pressure status bits indicate sensor in command mode. #define ARTERIAL_PRESSURE_STALE_DATA 2 ///< Arterial pressure status bits indicate data is stale (no new data since last fpga read). #define ARTERIAL_PRESSURE_DIAG_CONDITION 3 ///< Arterial pressure status bits diagnostic condition (alarm). #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 CARTRIDGE_LOADED_THRESHOLD 5000 ///< Threshold above which a cartridge is considered loaded. #define MIN_OCCLUSION_COUNTS 2000 ///< Minimum occlusion sensor reading for range check. #define OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX 24500 ///< Occlusion sensors maximum pressure reading limit when cartridge is considered loaded. #define MAX_ART_VEN_OFFSET_MMHG 15.0F ///< Maximum arterial/venous offset allowed. #define EMPTY_SALINE_BAG_THRESHOLD_MMHG -300.0F ///< Threshold below which the saline bag is considered empty (in mmHg). static const U32 EMPTY_SALINE_BAG_PERSISTENCE = ( 250 / TASK_GENERAL_INTERVAL ); ///< Time that saline bag looks empty before saying it is empty. #define PRES_ALARM_PERSISTENCE ( 1 * MS_PER_SECOND ) ///< Alarm persistence period for pressure alarms. #define PRES_OCCL_ALARM_PERSISTENCE ( 3 * MS_PER_SECOND ) ///< Alarm persistence period for occlusion alarms #define VEN_OCCL_ALARM_PERSISTENCE 100 ///< Alarm persistence period for venous occlusion alarm. #define AIR_PUMP_TOLERANCE_TIMEOUT_MS (1 * MS_PER_SECOND ) ///< Time to allow increased maximum venous high limit /// Measured arterial pressure is filtered w/ 10 second moving average for pressure compensation of flow. #define SIZE_OF_LONG_ART_ROLLING_AVG ( ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) * 10 ) /// Measured arterial pressure is filtered w/ 1 second moving average for inline pressure. #define SIZE_OF_SHORT_ART_ROLLING_AVG ( ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) * 1 ) /// Measured arterial pressure is filtered w/ 10 second moving average for pressure compensation of flow. #define SIZE_OF_LONG_VEN_ROLLING_AVG ( ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) * 10 ) /// 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 ) #define DATA_PUBLISH_COUNTER_START_COUNT 5 ///< Data publish counter start count. #define SHIFT_14_BITS 14 ///< Shift 14 bits. #define PRES_SENSORS_FPGA_ERROR_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Occlusion sensor FPGA error timeout in milliseconds. #ifndef _RELEASE_ #define MIN_OCCLUSION_COUNTS_V3 1500 ///< Minimum occlusion count for v3 hardware #endif /// Defined states for the pressure and occlusion monitor state machine. typedef enum PresOccl_States { PRESSURE_WAIT_FOR_POST_STATE = 0, ///< Wait for POST state. PRESSURE_CONTINUOUS_READ_STATE, ///< Continuous read sensors state. NUM_OF_PRESSURE_STATES ///< Number of pressure/occlusion monitor states. } PRESSURE_STATE_T; /// Defined states for the pressure and occlusion self-test state machine. typedef enum PresOccl_Self_Test_States { PRESSURE_SELF_TEST_STATE_START = 0, ///< Self test start state. PRESSURE_TEST_STATE_IN_PROGRESS, ///< Self test in progress state. PRESSURE_TEST_STATE_COMPLETE, ///< Self test completed state. NUM_OF_PRESSURE_SELF_TEST_STATES ///< Number of pressure/occlusion self-test states. } PRESSURE_SELF_TEST_STATE_T; // ********** private data ********** static PRESSURE_STATE_T presOcclState; ///< Current state of pressure monitor state machine. static U32 presOcclDataPublicationTimerCounter = 0; ///< Used to schedule pressure data publication to CAN bus. static U32 venLowPresExemptAfterAirTrapFillTimerCtr; ///< Exempt low ven pressure limit alarm for a time following an air trap fill. /// Interval (in ms) at which to publish pressure/occlusion data to CAN bus. static OVERRIDE_U32_T presOcclDataPublishInterval = { PRES_OCCL_DATA_PUB_INTERVAL, PRES_OCCL_DATA_PUB_INTERVAL, 0, 0 }; static OVERRIDE_F32_T arterialPressure = {0.0, 0.0, 0.0, 0 }; ///< Measured arterial pressure. static OVERRIDE_F32_T venousPressure = {0.0, 0.0, 0.0, 0 }; ///< Measured venous pressure. static OVERRIDE_U32_T bloodPumpOcclusion = {0, 0, 0, 0 }; ///< Measured blood pump occlusion pressure. static PRESSURE_LIMITS_STATES_T currPresLimitsState; ///< Current pressure limits state. static F32 arterialPressureOffset; ///< Arterial pressure sensor offset (in mmHg). static F32 venousPressureOffset; ///< Venous pressure sensor offset (in mmHg). static S32 stableArterialPressure; ///< Arterial pressure that limit window is based on (in mmHg). static S32 stableVenousPressure; ///< Venous pressure that limit window is based on (in mmHg). static S32 currentArterialMaxLimit; ///< Maximum arterial pressure limit (in mmHg). static S32 currentArterialMinLimit; ///< Minimum arterial pressure limit (in mmHg). static S32 currentVenousMaxLimit; ///< Maximum venous pressure limit (in mmHg). static S32 currentVenousMinLimit; ///< Minimum venous pressure limit (in mmHg). static BOOL pressureLimitsActive; ///< Flag indicates whether arterial and venous pressure alarm limits are active. static U32 stabilizationStartTimeMs; ///< Timestamp taken when pressure limit stabilization began (ms). static F32 longFilteredArterialPressure; ///< Measured arterial pressure after long (10 s) filter. static F32 shortFilteredArterialPressure; ///< Measured arterial pressure after short (1 s) filter. static F32 longFilteredVenousPressure; ///< Measured venous pressure after long (10 s) filter. static F32 shortFilteredVenousPressure; ///< Measured venous pressure after short (1 s) filter. static BOOL useShortStabilizeTime; ///< Flag to use short stabilize time. static U32 bloodPumpOcclusionAfterCartridgeInstall; ///< Measured blood pump occlusion reading taken after cartridge install. static U32 emptySalineBagCtr = 0; ///< Timer counter for empty bag detection. 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. static U32 artPressureReadingsLongCount = 0; ///< Number of samples in flow rolling average buffer. static F32 artPressureReadingsShort[ SIZE_OF_SHORT_ART_ROLLING_AVG ]; ///< Holds flow samples for long arterial pressure rolling average. static U32 artPressureReadingsShortIdx = 0; ///< Index for next sample in rolling average array. static F32 artPressureReadingsShortTotal = 0.0; ///< Rolling total - used to calc average. static U32 artPressureReadingsShortCount = 0; ///< Number of samples in flow rolling average buffer. static F32 venPressureReadingsLong[ SIZE_OF_LONG_VEN_ROLLING_AVG ]; ///< Holds flow samples for long venous pressure rolling average. static U32 venPressureReadingsLongIdx = 0; ///< Index for next sample in rolling average array. static F32 venPressureReadingsLongTotal = 0.0; ///< Rolling total - used to calc average. static U32 venPressureReadingsLongCount = 0; ///< Number of samples in flow rolling average buffer. static F32 venPressureReadingsShort[ SIZE_OF_SHORT_VEN_ROLLING_AVG ]; ///< Holds flow samples for long arterial pressure rolling average. static U32 venPressureReadingsShortIdx = 0; ///< Index for next sample in rolling average array. static F32 venPressureReadingsShortTotal = 0.0; ///< Rolling total - used to calc average. static U32 venPressureReadingsShortCount = 0; ///< Number of samples in flow rolling average buffer. static PRESSURE_SELF_TEST_STATE_T presOcclPostState; ///< Pressure self test post state. static HD_PRESSURE_SENSORS_CAL_RECORD_T pressureSensorsCalRecord; ///< Pressure sensors calibration record. static HD_OCCLUSION_SENSORS_CAL_RECORD_T occlusionSensorsCalRecord; ///< Occlusion sensors calibration record. // ********** private function prototypes ********** static PRESSURE_STATE_T handlePresOcclWaitForPOSTState( void ); static PRESSURE_STATE_T handlePresOcclContReadState( void ); static void execPressureLimits( void ); static void convertInlinePressures( void ); static void convertOcclusionPressures( void ); static void checkArterialPressureInRange( void ); static void checkVenousPressureInRange( void ); static void checkOcclusions( void ); static void publishPresOcclData( void ); static void determineArtVenPressureLimits( void ); static void filterInlinePressureReadings( F32 artPres, F32 venPres ); /*********************************************************************//** * @brief * The initPresOccl function initializes the PresOccl module. * @details Inputs: none * @details Outputs: PresOccl module initialized. * @return none *************************************************************************/ void initPresOccl( void ) { // Initialize persistent pressure alarms initPersistentAlarm( ALARM_ID_HD_ARTERIAL_PRESSURE_LOW, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_ARTERIAL_PRESSURE_HIGH, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_VENOUS_PRESSURE_LOW, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_VENOUS_PRESSURE_HIGH, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, 0, PRES_OCCL_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_VENOUS_LINE_OCCLUSION, 0, PRES_ALARM_PERSISTENCE ); // Initialize the FPGA persistent alarms initFPGAPersistentAlarm( FPGA_PERS_ERROR_OCCLUSION_PRESSURE_SENSOR, ALARM_ID_HD_OCCLUSION_SENSOR_FPGA_FAULT, PRES_SENSORS_FPGA_ERROR_TIMEOUT_MS, PRES_SENSORS_FPGA_ERROR_TIMEOUT_MS ); initFPGAPersistentAlarm( FPGA_PERS_ERROR_ARTERIAL_PRESSURE_SENSOR, ALARM_ID_HD_ARTERIAL_SENSOR_FPGA_FAULT, PRES_SENSORS_FPGA_ERROR_TIMEOUT_MS, PRES_SENSORS_FPGA_ERROR_TIMEOUT_MS ); initFPGAPersistentAlarm( FPGA_PERS_ERROR_VENOUS_PRESSURE_SESNOR, ALARM_ID_HD_VENOUS_SENSOR_FPGA_FAULT, PRES_SENSORS_FPGA_ERROR_TIMEOUT_MS, PRES_SENSORS_FPGA_ERROR_TIMEOUT_MS ); setPressureLimitsToOuterBounds(); currPresLimitsState = PRESSURE_LIMITS_STATE_OFF; pressureLimitsActive = FALSE; stabilizationStartTimeMs = 0; stableArterialPressure = 0; stableVenousPressure = 0; venLowPresExemptAfterAirTrapFillTimerCtr = 0; resetArtVenPressureOffsets(); longFilteredArterialPressure = 0.0F; shortFilteredArterialPressure = 0.0F; longFilteredVenousPressure = 0.0F; shortFilteredVenousPressure = 0.0F; presOcclDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; presOcclState = PRESSURE_WAIT_FOR_POST_STATE; presOcclPostState = PRESSURE_SELF_TEST_STATE_START; bloodPumpOcclusionAfterCartridgeInstall = 0; useShortStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; } /*********************************************************************//** * @brief * The resetArtVenPressureOffsets function resets the arterial and venous * offsets to zero. * @details Inputs: none * @details Outputs: arterialPressureOffset, venousPressureOffset * @return none *************************************************************************/ void resetArtVenPressureOffsets( void ) { arterialPressureOffset = 0.0F; venousPressureOffset = 0.0F; } /*********************************************************************//** * @brief * The setArtVenPressureOffsets function sets the arterial and venous * offsets to current readings. * @details Inputs: none * @details Outputs: arterialPressureOffset, venousPressureOffset * @return none *************************************************************************/ void setArtVenPressureOffsets( void ) { arterialPressureOffset = getMeasuredArterialPressure(); venousPressureOffset = getMeasuredVenousPressure(); if ( ( fabs( arterialPressureOffset ) > MAX_ART_VEN_OFFSET_MMHG ) || ( fabs( venousPressureOffset ) > MAX_ART_VEN_OFFSET_MMHG ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, arterialPressureOffset, venousPressureOffset ); } } /*********************************************************************//** * @brief * The isCartridgeLoaded function determines whether a cartridge has been * properly loaded by looking at the BP occlusion pressure sensor. * @details Inputs: BP occlusion pressure * @details Outputs: none * @return TRUE if BP occlusion sensor reads above loaded threshold, FALSE if not. *************************************************************************/ BOOL isCartridgeLoaded( void ) { BOOL result = FALSE; U32 bpOccl = getMeasuredBloodPumpOcclusion(); if ( bpOccl >= CARTRIDGE_LOADED_THRESHOLD ) { result = TRUE; } return result; } /*********************************************************************//** * @brief * The isCartridgeUnloaded function determines if a cartridge has been * unloaded by looking at the BP occlusion pressure sensor. * @details Inputs: BP occlusion pressure * @details Outputs: none * @return TRUE if occlusion sensor are below loaded threshold, FALSE if not. *************************************************************************/ BOOL isCartridgeUnloaded( void ) { BOOL const bpOcclBelowLoadedThreshold = ( getMeasuredBloodPumpOcclusion() <= CARTRIDGE_LOADED_THRESHOLD ? TRUE : FALSE ); return bpOcclBelowLoadedThreshold; } /*********************************************************************//** * @brief * The isSalineBagEmpty function determines whether the saline bag is empty. * It is assumed that this function will only be called from mode handling * (General Task) when pumping (BP) from the saline bag. * Determination is based on pressure going below a negative threshold. * @details Inputs: arterial line pressure * @details Outputs: none * @return TRUE if arterial line pressure is below threshold, FALSE if not. *************************************************************************/ BOOL isSalineBagEmpty( void ) { BOOL result = FALSE; if ( getMeasuredArterialPressure() < EMPTY_SALINE_BAG_THRESHOLD_MMHG ) { if ( ++emptySalineBagCtr >= EMPTY_SALINE_BAG_PERSISTENCE ) { result = TRUE; } } else { emptySalineBagCtr = 0; } return result; } /*********************************************************************//** * @brief * The setOcclusionInstallLevel function sets the occlusion sensor level * for an installed cartridge. This function should be called after a new * cartridge is installed. * @details Inputs: bloodPumpOcclusion * @details Outputs: bloodPumpOcclusionAfterCartridgeInstall * @return none *************************************************************************/ void setOcclusionInstallLevel( void ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif { bloodPumpOcclusionAfterCartridgeInstall = getMeasuredBloodPumpOcclusion(); SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_OCCLUSION_BASELINE, bloodPumpOcclusionAfterCartridgeInstall, 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 * @details Outputs: currentArterialMaxLimit, currentArterialMinLimit, * currentVenousMaxLimit, currentVenousMinLimit * @return none *************************************************************************/ void setPressureLimitsToOuterBounds( void ) { currentArterialMaxLimit = (S32)ARTERIAL_PRESSURE_LIMIT_MAX_MMHG; currentArterialMinLimit = (S32)ARTERIAL_PRESSURE_LIMIT_MIN_MMHG; currentVenousMaxLimit = (S32)VENOUS_PRESSURE_LIMIT_MAX_MMHG; currentVenousMinLimit = (S32)VENOUS_PRESSURE_LIMIT_MIN_MMHG; } /*********************************************************************//** * @brief * The updatePressureLimitWindows function updates the pressure limit * stable pressure levels when windows set/changed by user. * If treatment in progress, windowed limits around new stable pressures * will be in effect immediately (next monitor pass). If treatment paused, * resume will start a new stabilization period ending in another set of * stable pressures before windowed limits recalculated. * @details Inputs: useShortStabilizeTime * @details Outputs: stableArterialPressure, stableVenousPressure * @return none *************************************************************************/ void updatePressureLimitWindows( void ) { F32 filtArt; F32 filtVen; S32 curArtPres; S32 curVenPres; if ( USE_SHORT_STABILIZATION_PERIOD == useShortStabilizeTime ) { filtArt = getFilteredArterialPressure(); filtVen = getFilteredVenousPressure(); } else { filtArt = getLongFilteredArterialPressure(); filtVen = getLongFilteredVenousPressure(); } curArtPres = FLOAT_TO_INT_WITH_ROUND( filtArt ); curVenPres = FLOAT_TO_INT_WITH_ROUND( filtVen ); stableArterialPressure = curArtPres; stableVenousPressure = curVenPres; // want to broadcast new limits right away so UI can update tx screen presOcclDataPublicationTimerCounter = getU32OverrideValue( &presOcclDataPublishInterval ); } /*********************************************************************//** * @brief * The signalInitiatePressureStabilization function signals that user has * changed the blood and/or dialysate flow rate. If pressure limits state * was stable, a rate change will kick us back to stabilization state. * Else reset stabilize counter. * @details Inputs: currPresLimitsState * @details Outputs: currPresLimitsState, stabilizationStartTimeMs, useShortStabilizeTime * @param useShort Flag to use short stabilization period. Use defines: * USE_NORMAL_STABILIZATION_PERIOD, USE_SHORT_STABILIZATION_PERIOD * @return none *************************************************************************/ void signalInitiatePressureStabilization( BOOL useShort ) { useShortStabilizeTime = useShort; // User update of blood/dialysate flow rate or UF rate or initiates/resets a stabilization period (if we were in stabilization or stable state) if ( PRESSURE_LIMITS_STATE_STABILIZATION == currPresLimitsState ) { stabilizationStartTimeMs = getMSTimerCount(); } else if ( PRESSURE_LIMITS_STATE_STABLE == currPresLimitsState ) { currPresLimitsState = PRESSURE_LIMITS_STATE_STABILIZATION; stabilizationStartTimeMs = getMSTimerCount(); } } /*********************************************************************//** * @brief * The determineArtVenPressureLimits function determines current pressure * limits based on whether we are in stabilization or stable situation. * @details Inputs: currPresLimitsState * @details Outputs: currentArterialMaxLimit, currentArterialMinLimit, * currentVenousMaxLimit, currentVenousMinLimit * @return none *************************************************************************/ static void determineArtVenPressureLimits( void ) { if ( PRESSURE_LIMITS_STATE_STABLE == currPresLimitsState ) { // apply pressure windows when stable S32 artOffset = getTreatmentParameterS32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ) / 2; // Arterial is symmetric S32 venMinOffset = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ); // Venous is asymmetric S32 venMaxOffset = getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW ) - venMinOffset; currentArterialMinLimit = stableArterialPressure - artOffset; currentArterialMinLimit = MAX( currentArterialMinLimit, ARTERIAL_PRESSURE_LIMIT_MIN_MMHG ); currentArterialMaxLimit = stableArterialPressure + artOffset; currentArterialMaxLimit = MIN( currentArterialMaxLimit, ARTERIAL_PRESSURE_LIMIT_MAX_MMHG ); currentVenousMinLimit = stableVenousPressure - venMinOffset; currentVenousMinLimit = MAX( currentVenousMinLimit, VENOUS_PRESSURE_LIMIT_MIN_MMHG ); currentVenousMaxLimit = stableVenousPressure + venMaxOffset; currentVenousMaxLimit = MIN( currentVenousMaxLimit, VENOUS_PRESSURE_LIMIT_MAX_MMHG ); } else { // apply outer limits when not stable setPressureLimitsToOuterBounds(); } // set flag indicating whether pressure limits are active based on current current limits state pressureLimitsActive = ( currPresLimitsState > PRESSURE_LIMITS_STATE_IDLE ? TRUE : FALSE ); } /*********************************************************************//** * @brief * The execPresOccl function executes the pressure and occlusion monitor. * @details Inputs: presOcclState * @details Outputs: presOcclState * @return none *************************************************************************/ void execPresOccl( void ) { // State machine switch ( presOcclState ) { case PRESSURE_WAIT_FOR_POST_STATE: presOcclState = handlePresOcclWaitForPOSTState(); break; case PRESSURE_CONTINUOUS_READ_STATE: presOcclState = handlePresOcclContReadState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_PRES_OCCL_INVALID_STATE, presOcclState ) break; } // Publish pressure/occlusion data on interval publishPresOcclData(); } /*********************************************************************//** * @brief * The handlePresOcclWaitForPOSTState function handles the wait for POST * state. * @details Inputs: presOcclPostState * @details Outputs: none * @return next state *************************************************************************/ static PRESSURE_STATE_T handlePresOcclWaitForPOSTState( void ) { PRESSURE_STATE_T result = PRESSURE_WAIT_FOR_POST_STATE; if ( PRESSURE_TEST_STATE_COMPLETE == presOcclPostState ) { result = PRESSURE_CONTINUOUS_READ_STATE; } return result; } /*********************************************************************//** * @brief * The handlePresOcclContReadState function handles the continuous read state * of the pressure/occlusion monitor state machine. * @details Inputs: FPGA pressure/occlusion readings * @details Outputs: pressure sensor values updated * @return next state *************************************************************************/ static PRESSURE_STATE_T handlePresOcclContReadState( void ) { PRESSURE_STATE_T result = PRESSURE_CONTINUOUS_READ_STATE; // Read latest in-line (arterial and venous) pressures convertInlinePressures(); // Read latest occlusion pressures convertOcclusionPressures(); // Handle pressure limits state machine execPressureLimits(); // Set arterial/venous pressure limits according to current pressure limits state determineArtVenPressureLimits(); // Check in-line pressures are in range checkArterialPressureInRange(); checkVenousPressureInRange(); // Check for occlusions checkOcclusions(); return result; } /*********************************************************************//** * @brief * The execPressureLimits function executes the pressure limits state machine. * @details Inputs: currPresLimitsState, stabilizationStartTimeMs * @details Outputs: currPresLimitsState, stabilizationStartTimeMs * @return next pressure limits state *************************************************************************/ static void execPressureLimits( void ) { BOOL bpRunning = isBloodPumpRunning(); BOOL bpRampComplete = isBloodPumpRampComplete(); HD_OP_MODE_T currMode = getCurrentOperationMode(); TREATMENT_STATE_T currTxState = getTreatmentState(); U32 stabilizeTime = PRES_LIMIT_STABILIZATION_TIME_MS; if ( currMode != MODE_TREA ) { currPresLimitsState = PRESSURE_LIMITS_STATE_OFF; } switch ( currPresLimitsState ) { case PRESSURE_LIMITS_STATE_OFF: if ( ( MODE_TREA == currMode ) && ( currTxState != TREATMENT_RECIRC_STATE ) ) { // Tx mode starts in blood prime - want wide limits in that state currPresLimitsState = PRESSURE_LIMITS_STATE_WIDE; } break; case PRESSURE_LIMITS_STATE_IDLE: if ( TRUE == bpRampComplete ) { currPresLimitsState = PRESSURE_LIMITS_STATE_WIDE; } break; case PRESSURE_LIMITS_STATE_WIDE: if ( bpRunning != TRUE ) { currPresLimitsState = PRESSURE_LIMITS_STATE_IDLE; } else if ( ( TREATMENT_DIALYSIS_STATE == currTxState ) || ( TREATMENT_STOP_STATE == currTxState ) ) { stabilizationStartTimeMs = getMSTimerCount(); useShortStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; currPresLimitsState = PRESSURE_LIMITS_STATE_STABILIZATION; } else if ( currTxState == TREATMENT_RECIRC_STATE ) { currPresLimitsState = PRESSURE_LIMITS_STATE_OFF; } break; case PRESSURE_LIMITS_STATE_STABILIZATION: if ( USE_SHORT_STABILIZATION_PERIOD == useShortStabilizeTime ) { stabilizeTime = PRES_LIMIT_SHORT_STABILIZE_TIME_MS; } else { stabilizeTime = PRES_LIMIT_STABILIZATION_TIME_MS; } if ( bpRunning != TRUE ) { currPresLimitsState = PRESSURE_LIMITS_STATE_IDLE; } else if ( ( currTxState != TREATMENT_DIALYSIS_STATE ) && ( currTxState != TREATMENT_STOP_STATE ) ) { currPresLimitsState = PRESSURE_LIMITS_STATE_WIDE; } else if ( TRUE == didTimeout( stabilizationStartTimeMs, stabilizeTime ) ) { updatePressureLimitWindows(); stabilizationStartTimeMs = getMSTimerCount(); useShortStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; currPresLimitsState = PRESSURE_LIMITS_STATE_STABLE; } break; case PRESSURE_LIMITS_STATE_STABLE: if ( bpRunning != TRUE ) { currPresLimitsState = PRESSURE_LIMITS_STATE_IDLE; } else if ( ( currTxState != TREATMENT_DIALYSIS_STATE ) && ( currTxState != TREATMENT_STOP_STATE ) ) { currPresLimitsState = PRESSURE_LIMITS_STATE_WIDE; } else if ( TRUE == didTimeout( stabilizationStartTimeMs, PRES_LIMIT_RESTABILIZE_TIME_MS ) ) { stabilizationStartTimeMs = getMSTimerCount(); useShortStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; currPresLimitsState = PRESSURE_LIMITS_STATE_STABILIZATION; } break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_PRES_LIMITS_INVALID_STATE, currPresLimitsState ) break; } } /*********************************************************************//** * @brief * The convertInlinePressures function reads inline pressure sensor readings * and converts to mmHg. Sensor status/alarm is checked. * @details Inputs: none * @details Outputs: arterialPressure, venousPressure * @return none *************************************************************************/ static void convertInlinePressures( void ) { // Venous pressure sensor data U16 fpgaVenPres = getFPGAVenousPressure(); U08 venReadCtr = getFPGAVenousPressureReadCounter(); U08 venErrorCtr = getFPGAVenousPressureErrorCounter(); U16 venPres = fpgaVenPres & 0x3FFF; // 14-bit data U08 venPresStatus = (U08)( fpgaVenPres >> SHIFT_14_BITS ); // High 2 bits is status code for venous pressure // Arterial pressure sensor data U16 fpgaArtPres = getFPGADVTArterialPressure(); U08 artReadCtr = getFPGADVTArterialPressureReadCounter(); U08 artErrorCtr = getFPGATDVTArterialPressureErrorCounter(); U16 artPres = fpgaArtPres & 0x3FFF; U08 artPresStatus = (U08)( fpgaArtPres >> SHIFT_14_BITS ); checkFPGAPersistentAlarms( FPGA_PERS_ERROR_ARTERIAL_PRESSURE_SENSOR, artReadCtr ); checkFPGAPersistentAlarms( FPGA_PERS_ERROR_VENOUS_PRESSURE_SESNOR, venReadCtr ); if ( ARTERIAL_PRESSURE_NORMAL_OP == artPresStatus ) { F32 artPresPSI; // If the arterial pressure status is normal, convert the counts to pressure in mmHg artPresPSI = ( (F32)( artPres - ARTERIAL_PRESSURE_OFFSET ) * ( ARTERIAL_PRESSURE_MAX_PSI - ARTERIAL_PRESSURE_MIN_PSI ) / (F32)ARTERIAL_PRESSURE_SCALE ) + ARTERIAL_PRESSURE_MIN_PSI; artPresPSI = artPresPSI * PSI_TO_MMHG; arterialPressure.data = artPresPSI - arterialPressureOffset; } if ( VENOUS_PRESSURE_NORMAL_OP == venPresStatus ) { F32 venPresPSI; // Convert venous pressure to PSI and then mmHg venPresPSI = ( (F32)( venPres - VENOUS_PRESSURE_OFFSET ) * ( VENOUS_PRESSURE_MAX_PSI - VENOUS_PRESSURE_MIN_PSI ) / (F32)VENOUS_PRESSURE_SCALE ) + VENOUS_PRESSURE_MIN_PSI; venPresPSI = venPresPSI * PSI_TO_MMHG; venousPressure.data = venPresPSI - venousPressureOffset; } // Filter inline pressure readings filterInlinePressureReadings( getMeasuredArterialPressure(), getMeasuredVenousPressure() ); } /*********************************************************************//** * @brief * The convertOcclusionPressures function reads occlusion sensor readings. * @details Inputs: FPGA * @details Outputs: bloodPumpOcclusion, dialInPumpOcclusion, dialOutPumpOcclusion * @return none *************************************************************************/ static void convertOcclusionPressures( void ) { U08 bpReadCtr = getFPGABloodPumpOcclusionReadCounter(); U08 bpErrorCtr = getFPGABloodPumpOcclusionErrorCounter(); checkFPGAPersistentAlarms( FPGA_PERS_ERROR_OCCLUSION_PRESSURE_SENSOR, bpReadCtr ); // Record occlusion sensor readings bloodPumpOcclusion.data = (U32)getFPGABloodPumpOcclusion(); } /*********************************************************************//** * @brief * The checkArterialPressureInRange function checks that artieral pressure is * within the set alarm limits. Alarm is triggered if not. * @details Inputs: arterialPressure, pressureLimitsActive, currentArterialMinLimit, * currentArterialMaxLimit * @details Outputs: Alarm if out of range * @return none *************************************************************************/ static void checkArterialPressureInRange( void ) { F32 artPres = getFilteredArterialPressure(); #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ARTERIAL_PRESSURE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { // Check arterial pressure is in absolute max range if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, ( artPres > ARTERIAL_PRESSURE_MAX_MMHG || artPres < ARTERIAL_PRESSURE_MIN_MMHG ) ) ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, artPres ); } // Check arterial pressure when limits active if ( pressureLimitsActive != FALSE ) { BOOL artPresLow, artPresHigh; artPresLow = ( artPres < (F32)currentArterialMinLimit ? TRUE : FALSE ); artPresHigh = ( artPres > (F32)currentArterialMaxLimit ? TRUE : FALSE ); // Check arterial pressure is within alarm limits if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_LOW, artPresLow ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_LOW, artPres, (F32)currentArterialMinLimit ); } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_HIGH, artPresHigh ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_HIGH, artPres, (F32)currentArterialMaxLimit ); } } else { // Reset persistence if limits inactive isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_LOW, FALSE ); isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_HIGH, FALSE ); } } } /*********************************************************************//** * @brief * The checkVenousPressureInRange function checks that venous pressure is * within the set alarm limits. Alarm is triggered if not. * @details Inputs: venousPressure, pressureLimitsActive, currentVenousMinLimit * currentVenousMaxLimit, venLowPresExemptAfterAirTrapFillTimerCtr * @details Outputs: venLowPresExemptAfterAirTrapFillTimerCtr, alarm if out of range * @return none *************************************************************************/ static void checkVenousPressureInRange( void ) { F32 venPres = getFilteredVenousPressure(); OPN_CLS_STATE_T airTrapValveState = getValveAirTrapStatus(); // track time since last air trap fill if ( STATE_OPEN == airTrapValveState ) { venLowPresExemptAfterAirTrapFillTimerCtr = 0; } else { venLowPresExemptAfterAirTrapFillTimerCtr++; } #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_VENOUS_PRESSURE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { // Check venous pressure is in absolute max range if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, ( venPres > VENOUS_PRESSURE_MAX_MMHG || venPres < VENOUS_PRESSURE_MIN_MMHG ) ) ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres ); } // Check venous pressure when limits active if ( pressureLimitsActive != FALSE ) { BOOL venPresLow, venPresHigh; S32 qB = abs( getTargetBloodFlowRate() ); U32 qBx = ( 0 == qB ? MIN_SET_BLOOD_FLOW_RATE : (U32)qB ); // compute exemption period (in general task intervals) for low venous pressure alarms after air trap fills U32 exemptPeriod = VENOUS_PRES_AT_FILL_DELAY_FACTOR / qBx; venPresLow = ( venPres < (F32)currentVenousMinLimit ? TRUE : FALSE ); venPresHigh = ( venPres > (F32)currentVenousMaxLimit ? TRUE : FALSE ); // Check venous pressure is within alarm limits if ( ( airTrapValveState != STATE_OPEN ) && ( venLowPresExemptAfterAirTrapFillTimerCtr > exemptPeriod ) ) { if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_LOW, venPresLow ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_LOW, venPres, (F32)currentVenousMinLimit ); } } else { // clear persistence if air trap valve is open isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_LOW, FALSE ); } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_HIGH, venPresHigh ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_HIGH, venPres, (F32)currentVenousMaxLimit ); } } else { // Reset persistence if limits inactive isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_LOW, FALSE ); isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_HIGH, FALSE ); } } } /*********************************************************************//** * @brief * The checkPressureLimits function gets the pressure/occlusion data * publication interval. * @details Inputs: occlusion pressures for the pumps * @details Outputs: Alarm if occlusion limit exceeded * @return none *************************************************************************/ static void checkOcclusions( void ) { U32 bpOccl = getMeasuredBloodPumpOcclusion(); BOOL outOfRange = ( bpOccl < MIN_OCCLUSION_COUNTS ? TRUE : FALSE ); #ifndef _RELEASE_ if( HW_CONFIG_BETA == getHardwareConfigStatus() ) { outOfRange = ( bpOccl < MIN_OCCLUSION_COUNTS_V3 ? TRUE : FALSE ); } #endif #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif { F32 venPres = getMeasuredVenousPressure(); HD_OP_MODE_T hdMode = getCurrentOperationMode(); U32 hdSubMode = getCurrentSubMode(); BOOL ptxMode = ( MODE_PRET == hdMode && hdSubMode > HD_PRE_TREATMENT_CART_INSTALL_STATE ? TRUE : FALSE ); // Range check occlusion sensor (OB) if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, outOfRange ) ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, bpOccl, bloodPumpOcclusionAfterCartridgeInstall ) } // Check for occlusion in PreTreatment modes when the cartridge is installed // and setOcclusionInstallLevel has been called. if ( MODE_PRET == getCurrentOperationMode() ) { if ( ( TRUE == isBloodPumpRunning() ) && ( getPreTreatmentSubState() > HD_PRE_TREATMENT_CART_INSTALL_STATE ) && ( getDrySelfTestsState() > DRY_SELF_TESTS_START_STATE ) ) { // Check for occlusion if ( bpOccl > ( OCCLUSION_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) { signalBloodPumpHardStop(); // Stop pump immediately SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_OCCLUSION_BLOOD_PUMP, bpOccl, OCCLUSION_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) } } } // Check for occlusion in Treatment modes where pumps are moving else if ( MODE_TREA == getCurrentOperationMode() ) { if ( TRUE == isBloodPumpRunning() ) { // Check for occlusion if ( bpOccl > ( OCCLUSION_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) { signalBloodPumpHardStop(); // Stop pump immediately SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_OCCLUSION_BLOOD_PUMP, bpOccl, OCCLUSION_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) } } } // Clear alarm regardless of op mode once conditions are met. if ( bpOccl <= ( OCCLUSION_CLEAR_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) { clearAlarmCondition( ALARM_ID_HD_OCCLUSION_BLOOD_PUMP ); } // Check for venous occlusion #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_VENOUS_PRESSURE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { // only trigger alarm if BP is running if ( isBloodPumpRunning() != FALSE ) { // must be in pre-treatment mode to trigger this alarm if ( ( TRUE == ptxMode ) && ( venPres > VENOUS_PRESSURE_LIMIT_MAX_MMHG + VENOUS_PRESSURE_OCCL_OFFSET_MMHG ) ) { if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_LINE_OCCLUSION, TRUE ) ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_VENOUS_LINE_OCCLUSION, venPres ); } } else { isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_LINE_OCCLUSION, FALSE ); } } else { isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_LINE_OCCLUSION, FALSE ); } } } } /*********************************************************************//** * @brief * The getMeasuredArterialPressure function gets the current arterial pressure. * @details Inputs: arterialPressure * @details Outputs: none * @return the current arterial pressure (in mmHg). *************************************************************************/ F32 getMeasuredArterialPressure( void ) { F32 result = arterialPressure.data; if ( OVERRIDE_KEY == arterialPressure.override ) { result = arterialPressure.ovData; } return result; } /*********************************************************************//** * @brief * The getFilteredArterialPressure function gets the current filtered arterial pressure. * @details Inputs: shortFilteredArterialPressure * @details Outputs: none * @return the current filtered arterial pressure (in mmHg). *************************************************************************/ F32 getFilteredArterialPressure( void ) { return shortFilteredArterialPressure; } /*********************************************************************//** * @brief * The getLongFilteredArterialPressure function gets the current long filtered arterial pressure. * @details Inputs: longFilteredArterialPressure * @details Outputs: none * @return the current long filtered arterial pressure (in mmHg). *************************************************************************/ F32 getLongFilteredArterialPressure( void ) { return longFilteredArterialPressure; } /*********************************************************************//** * @brief * The getMeasuredVenousPressure function gets the measured venous pressure. * @details Inputs: venousPressure * @details Outputs: none * @return the current venous pressure (in mmHg). *************************************************************************/ F32 getMeasuredVenousPressure( void ) { F32 result = venousPressure.data; if ( OVERRIDE_KEY == venousPressure.override ) { result = venousPressure.ovData; } return result; } /*********************************************************************//** * @brief * The getFilteredVenousPressure function gets the measured filtered venous pressure. * @details Inputs: shortFilteredVenousPressure * @details Outputs: none * @return the current filtered venous pressure (in mmHg). *************************************************************************/ F32 getFilteredVenousPressure( void ) { return shortFilteredVenousPressure; } /*********************************************************************//** * @brief * The getLongFilteredVenousPressure function gets the current long filtered * venous pressure. * @details Inputs: longFilteredVenousPressure * @details Outputs: none * @return the current long filtered venous pressure (in mmHg). *************************************************************************/ F32 getLongFilteredVenousPressure( void ) { return longFilteredVenousPressure; } /*********************************************************************//** * @brief * The getMeasuredBloodPumpOcclusion function gets the measured blood pump * occlusion pressure. * @details Inputs: bloodPumpOcclusion * @details Outputs: none * @return the current blood pump occlusion pressure (in mmHg). *************************************************************************/ U32 getMeasuredBloodPumpOcclusion( void ) { U32 result = bloodPumpOcclusion.data; if ( OVERRIDE_KEY == bloodPumpOcclusion.override ) { result = bloodPumpOcclusion.ovData; } return result; } /*********************************************************************//** * @brief * The filterInlinePressureReadings function adds a new arterial and venous * pressure sample to the filters. * @details Inputs: none * @details Outputs: artPressureReadingsLong[], artPressureReadingsLongIdx, artPressureReadingsLongTotal, artPressureReadingsLongCount, * artPressureReadingsShort, artPressureReadingsShortIdx, artPressureReadingsShortTotal, artPressureReadingsShortCount, * venPressureReadingsShort, venPressureReadingsShortIdx, venPressureReadingsShortTotal, venPressureReadingsShortCount, * longFilteredArterialPressure, shortFilteredArterialPressure, shortFilteredVenousPressure * @param artPres newest arterial pressure sample to add to filters * @param venPres newest venous pressure sample to add to filter * @return none *************************************************************************/ static void filterInlinePressureReadings( F32 artPres, F32 venPres ) { // Long filter for arterial pressure. if ( artPressureReadingsLongCount >= SIZE_OF_LONG_ART_ROLLING_AVG ) { artPressureReadingsLongTotal -= artPressureReadingsLong[ artPressureReadingsLongIdx ]; } artPressureReadingsLong[ artPressureReadingsLongIdx ] = artPres; artPressureReadingsLongTotal += artPres; artPressureReadingsLongIdx = INC_WRAP( artPressureReadingsLongIdx, 0, SIZE_OF_LONG_ART_ROLLING_AVG - 1 ); artPressureReadingsLongCount = INC_CAP( artPressureReadingsLongCount, SIZE_OF_LONG_ART_ROLLING_AVG ); longFilteredArterialPressure = artPressureReadingsLongTotal / (F32)artPressureReadingsLongCount; // Short filter for arterial pressure. if ( artPressureReadingsShortCount >= SIZE_OF_SHORT_ART_ROLLING_AVG ) { artPressureReadingsShortTotal -= artPressureReadingsShort[ artPressureReadingsShortIdx ]; } artPressureReadingsShort[ artPressureReadingsShortIdx ] = artPres; artPressureReadingsShortTotal += artPres; artPressureReadingsShortIdx = INC_WRAP( artPressureReadingsShortIdx, 0, SIZE_OF_SHORT_ART_ROLLING_AVG - 1 ); artPressureReadingsShortCount = INC_CAP( artPressureReadingsShortCount, SIZE_OF_SHORT_ART_ROLLING_AVG ); shortFilteredArterialPressure = artPressureReadingsShortTotal / (F32)artPressureReadingsShortCount; // Long filter for venous pressure. if ( venPressureReadingsLongCount >= SIZE_OF_LONG_VEN_ROLLING_AVG ) { venPressureReadingsLongTotal -= venPressureReadingsLong[ venPressureReadingsLongIdx ]; } venPressureReadingsLong[ venPressureReadingsLongIdx ] = venPres; venPressureReadingsLongTotal += venPres; venPressureReadingsLongIdx = INC_WRAP( venPressureReadingsLongIdx, 0, SIZE_OF_LONG_VEN_ROLLING_AVG - 1 ); venPressureReadingsLongCount = INC_CAP( venPressureReadingsLongCount, SIZE_OF_LONG_VEN_ROLLING_AVG ); longFilteredVenousPressure = venPressureReadingsLongTotal / (F32)venPressureReadingsLongCount; // Short filter for venous pressure. if ( venPressureReadingsShortCount >= SIZE_OF_SHORT_VEN_ROLLING_AVG ) { venPressureReadingsShortTotal -= venPressureReadingsShort[ venPressureReadingsShortIdx ]; } venPressureReadingsShort[ venPressureReadingsShortIdx ] = venPres; venPressureReadingsShortTotal += venPres; venPressureReadingsShortIdx = INC_WRAP( venPressureReadingsShortIdx, 0, SIZE_OF_SHORT_VEN_ROLLING_AVG - 1 ); venPressureReadingsShortCount = INC_CAP( artPressureReadingsShortCount, SIZE_OF_SHORT_VEN_ROLLING_AVG ); shortFilteredVenousPressure = venPressureReadingsShortTotal / (F32)venPressureReadingsShortCount; } /*********************************************************************//** * @brief * The publishPresOcclData function publishes pressure/occlusion data at the * set interval. * @details Inputs: latest pressure and occlusion readings * @details Outputs: Pressure/occlusion data are published to CAN bus. * @return none *************************************************************************/ static void publishPresOcclData( void ) { // Publish pressure/occlusion data on interval if ( ++presOcclDataPublicationTimerCounter >= getU32OverrideValue( &presOcclDataPublishInterval ) ) { PRESSURE_OCCLUSION_DATA_T data; data.arterialPressure = shortFilteredArterialPressure; data.venousPressure = shortFilteredVenousPressure; data.bldPumpOcclusion = getMeasuredBloodPumpOcclusion(); data.presLimitState = currPresLimitsState; data.artMinLimit = currentArterialMinLimit; data.artMaxLimit = currentArterialMaxLimit; data.venMinLimit = currentVenousMinLimit; data.venMaxLimit = currentVenousMaxLimit; data.arterialLongFilterPres = longFilteredArterialPressure; data.venousLongFilterPres = longFilteredVenousPressure; broadcastData( MSG_ID_PRESSURE_OCCLUSION_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( PRESSURE_OCCLUSION_DATA_T ) ); presOcclDataPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The execPresOcclTest function executes the PresOccl self-test. * @details Inputs: none * @details Outputs: Triggers fault when test case fails * @return none *************************************************************************/ void execPresOcclTest( void ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif { U32 bpPressure = getMeasuredBloodPumpOcclusion(); F32 arterialPressure = getFilteredArterialPressure(); F32 venousPressure = getFilteredVenousPressure(); if ( bpPressure > CARTRIDGE_LOADED_THRESHOLD ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_SELF_TEST_FAILURE, bpPressure ); } if ( ( arterialPressure < ARTERIAL_PRESSURE_SELF_TEST_MIN ) || ( arterialPressure > ARTERIAL_PRESSURE_SELF_TEST_MAX ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_SELF_TEST_FAILURE, arterialPressure ); } if ( ( venousPressure < VENOUS_PRESSURE_SELF_TEST_MIN ) || ( venousPressure > VENOUS_PRESSURE_SELF_TEST_MAX ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_SELF_TEST_FAILURE, venousPressure ); } } } /*********************************************************************//** * @brief * The execPresOcclDryTest function executes the PresOccl dry self-test. * @details Inputs: none * @details Outputs: Triggers no cartridge loaded alarm if no cartridge detected. * @return the result of the PresOccl dry self-test. *************************************************************************/ SELF_TEST_STATUS_T execPresOcclDryTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_OCCLUSION_SELF_TEST ) != SW_CONFIG_ENABLE_VALUE ) #endif { U32 bpPressure = getMeasuredBloodPumpOcclusion(); if ( ( bpPressure < CARTRIDGE_LOADED_THRESHOLD ) || ( bpPressure > OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_NO_CARTRIDGE_LOADED, bpPressure ); result = SELF_TEST_STATUS_FAILED; } } return result; } /*********************************************************************//** * @brief * The execPresOcclSelfTest function executes the PresOccl self-test. * @details Inputs: none * @details Outputs: pressureSensorsCalRecord, occlusionSensorsCalRecord * @return the result of the PresOccl self-test. *************************************************************************/ SELF_TEST_STATUS_T execPresOcclSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; BOOL calStatus = FALSE; // Get the pressure sensors and occlusion sensors calibration records calStatus |= getNVRecord2Driver( GET_CAL_PRESSURE_SENSORS, (U08*)&pressureSensorsCalRecord, sizeof( HD_PRESSURE_SENSORS_CAL_RECORD_T ), NUM_OF_CAL_DATA_HD_PRESSURE_SESNSORS, ALARM_ID_NO_ALARM ); calStatus |= getNVRecord2Driver( GET_CAL_OCCLUSION_SESNSORS, (U08*)&occlusionSensorsCalRecord, sizeof( HD_OCCLUSION_SENSORS_CAL_RECORD_T ), NUM_OF_CAL_DATA_OCCLUSION_SENSORS, ALARM_ID_NO_ALARM ); presOcclPostState = PRESSURE_TEST_STATE_COMPLETE; if ( TRUE == calStatus ) { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; } return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetPresOcclDataPublishIntervalOverride function overrides the * pressure and occlusion data publish interval. * @details Inputs: none * @details Outputs: presOcclDataPublishInterval * @param value override pressure and occlusion data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetPresOcclDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_GENERAL_INTERVAL; result = TRUE; presOcclDataPublishInterval.ovData = intvl; presOcclDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetPresOcclDataPublishIntervalOverride function resets the override * of the pressure and occlusion data publish interval. * @details Inputs: none * @details Outputs: presOcclDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetPresOcclDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; presOcclDataPublishInterval.override = OVERRIDE_RESET; presOcclDataPublishInterval.ovData = presOcclDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetArterialPressureOverride function overrides the measured arterial * pressure. * @details Inputs: none * @details Outputs: arterialPressure * @param value override arterial pressure (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetArterialPressureOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; arterialPressure.ovData = value; arterialPressure.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetArterialPressureOverride function resets the override of the * arterial pressure. * @details Inputs: none * @details Outputs: arterialPressure * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetArterialPressureOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; arterialPressure.override = OVERRIDE_RESET; arterialPressure.ovData = arterialPressure.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetVenousPressureOverride function overrides the measured venous * pressure. * @details Inputs: none * @details Outputs: venousPressure * @param value override measured venous pressure with (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetVenousPressureOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; venousPressure.ovData = value; venousPressure.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetVenousPressureOverride function resets the override of the * venous pressure. * @details Inputs: none * @details Outputs: venousPressure * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetVenousPressureOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; venousPressure.override = OVERRIDE_RESET; venousPressure.ovData = venousPressure.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetBloodPumpOcclusionOverride function overrides the measured * blood pump occlusion pressure. * @details Inputs: none * @details Outputs: bloodPumpOcclusion * @param value override measured blood pump occlusion pressure with * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBloodPumpOcclusionOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bloodPumpOcclusion.ovData = value; bloodPumpOcclusion.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetBloodPumpOcclusionOverride function resets the override of the * measured blood pump occlusion pressure. * @details Inputs: none * @details Outputs: bloodPumpOcclusion * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetBloodPumpOcclusionOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bloodPumpOcclusion.override = OVERRIDE_RESET; bloodPumpOcclusion.ovData = bloodPumpOcclusion.ovInitData; } return result; } /**@}*/