Index: firmware/App/Controllers/PresOccl.c =================================================================== diff -u -rd336db3909e3c5865ede9da2da640e7df6743b11 -rc71ff8d9b1c3efea8649e11d12da472f06a5a511 --- firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision d336db3909e3c5865ede9da2da640e7df6743b11) +++ firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision c71ff8d9b1c3efea8649e11d12da472f06a5a511) @@ -1,27 +1,32 @@ /************************************************************************** * -* Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +* Copyright (c) 2020-2022 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 +* @file PresOccl.c * -* @author (last) Sean Nash -* @date (last) 08-Sep-2020 +* @author (last) Darren Cox +* @date (last) 10-Mar-2022 * -* @author (original) Sean -* @date (original) 15-Jan-2020 +* @author (original) Sean +* @date (original) 15-Jan-2020 * ***************************************************************************/ #include "PresOccl.h" #include "AlarmMgmt.h" -#include "FPGA.h" -#include "OperationModes.h" +#include "FPGA.h" +#include "ModeTreatmentParams.h" +#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "PersistentAlarm.h" #include "SystemCommMessages.h" -#include "TaskGeneral.h" -#include "Timers.h" +#include "TaskGeneral.h" +#include "Temperatures.h" +#include "Timers.h" +#include "Valves.h" /** * @addtogroup PressureOcclusion @@ -31,127 +36,292 @@ // ********** 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_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 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 ARTERIAL_PRESSURE_V_BIAS ( 3.0 ) ///< Bias voltage for arterial pressure sensor. -#define ARTERIAL_PRESSURE_SENSITIVITY ( 0.000005 ) ///< Sensitivity for arterial pressure sensor is 5 uV / mmHg -#define ARTERIAL_PRESSURE_V_PER_BIT ( ARTERIAL_PRESSURE_V_BIAS / (F32)0x800000 ) ///< 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 ( 30.0 ) ///< Minimum of scale for venous pressure sensor reading (in TBD u/m). -#define VENOUS_PRESSURE_MAX ( 90.0 ) ///< Maximum of scale for venous pressure sensor reading (in TBD u/m). +#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 PSI_TO_MMHG ( 51.7149 ) ///< Conversion factor for converting PSI to mmHg. +#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 ( -300.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_ND_MIN_MMHG ( -250.0F ) ///< Minimum arterial pressure reading (in mmHg) when not dialyzing. + +#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 ( 600.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_ND_MAX_MMHG ( 300.0F ) ///< Maximum venous pressure reading (in mmHg) when not dialyzing. + +#define PSI_TO_MMHG ( 51.7149F ) ///< Conversion factor for converting PSI to mmHg. + +#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). + +// The new arterial pressure sensor is the same as the venous pressure sensor +#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 5500 ///< 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 MAX_OCCLUSION_COUNTS 32766 ///< Maximum 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 EMPTY_SALINE_BAG_THRESHOLD_MMHG -300.0F ///< Threshold below which the saline bag is considered empty (in mmHg). TODO - get real threshold from Systems +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. + +/// 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 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. /// Defined states for the pressure and occlusion monitor state machine. typedef enum PresOccl_States { - PRESSURE_INIT_STATE = 0, ///< Initialization state. - PRESSURE_CONTINUOUS_READ_STATE, ///< Continuous read sensors state. - NUM_OF_PRESSURE_STATES ///< Number of pressure/occlusion monitor 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_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 = PRESSURE_INIT_STATE; ///< current state of pressure monitor state machine. -static U32 presOcclDataPublicationTimerCounter = 0; ///< used to schedule pressure data publication to CAN bus. +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 OVERRIDE_F32_T measuredBloodFlowRate = { 0.0, 0.0, 0.0, 0 }; ///< measured blood flow rate +/// 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 arterialPressureOffset = {0.0, 0.0, 0.0, 0 }; ///< Calculated arterial pressure offset. +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 F32 longFilteredArterialPressure; ///< Measured arterial pressure after long (10 s) filter. +static F32 shortFilteredArterialPressure; ///< Measured arterial pressure after short (1 s) filter. +static F32 shortFilteredVenousPressure; ///< Measured venous pressure after short (1 s) filter. + +static U32 bloodPumpOcclusionAfterCartridgeInstall; ///< Measured blood pump occlusion reading taken after cartridge install. + +static U32 emptySalineBagCtr = 0; ///< Timer counter for empty bag detection. + +static U08 lastArterialPressureReadCtr; ///< Previous arterial pressure sensor read count. +static U08 lastVenousPressureReadCtr; ///< Previous venous pressure sensor read count. +static U08 lastBPOcclReadCtr; ///< Previous BP occlusion sensor read count. +static U08 lastBPErrorCtr; ///< Previous BP error count. -static OVERRIDE_U32_T presOcclDataPublishInterval = { PRES_OCCL_DATA_PUB_INTERVAL, PRES_OCCL_DATA_PUB_INTERVAL, 0, 0 }; ///< interval (in ms) at which to publish pressure/occlusion data to CAN bus. -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_F32_T bloodPumpOcclusion = {0.0, 0.0, 0.0, 0 }; ///< measured blood pump occlusion pressure. -static OVERRIDE_F32_T dialInPumpOcclusion = {0.0, 0.0, 0.0, 0 }; ///< measured dialysate inlet pump occlusion pressure. -static OVERRIDE_F32_T dialOutPumpOcclusion = {0.0, 0.0, 0.0, 0 }; ///< measured dialysate outlet pump occlusion pressure. - -static PRESSURE_SELF_TEST_STATE_T presOcclSelfTestState = PRESSURE_SELF_TEST_STATE_START; ///< current pressure self-test state. -static U32 bloodPumpSelfTestTimerCount = 0; ///< timer counter for pressure self-test. - -// TODO - set thresholds for occlusions -static F32 bloodPumpOcclusionPressureThresholdmmHG = 50.0; ///< pressure threshold for blood pump occlusion. -static F32 dialInPumpOcclusionPressureThresholdmmHG = 50.0; ///< pressure threshold for dialysate inlet pump occlusion. -static F32 dialOutPumpOcclusionPressureThresholdmmHG = 50.0; ///< pressure threshold for dialysate outlet pump occlusion. - +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 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 handlePresOcclInitState( void ); -static PRESSURE_STATE_T handlePresOcclContReadState( void ); + +static PRESSURE_STATE_T handlePresOcclWaitForPOSTState( void ); +static PRESSURE_STATE_T handlePresOcclContReadState( 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 DATA_GET_PROTOTYPE( U32, getPublishPresOcclDataInterval ); +static void filterInlinePressureReadings( F32 artPres, F32 venPres ); /*********************************************************************//** * @brief - * The initPresOccl function initializes the initPresOccl module. - * @details - * Inputs : none - * Outputs : initPresOccl module initialized. + * The initPresOccl function initializes the PresOccl module. + * @details Inputs: none + * @details Outputs: PresOccl module initialized. * @return none *************************************************************************/ void initPresOccl( void ) { - // TODO - anything to initialize? + // Initialize persistent pressure alarms + initPersistentAlarm( ALARM_ID_HD_VENOUS_PRESSURE_READ_TIMEOUT_ERROR, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_ARTERIAL_PRESSURE_READ_TIMEOUT_ERROR, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_ARTERIAL_PRESSURE_LOW, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_ARTERIAL_PRESSURE_HIGH, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_VENOUS_PRESSURE_LOW, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_VENOUS_PRESSURE_HIGH, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_BP_OCCLUSION_SENSOR_ERROR, 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_ALARM_PERSISTENCE ); + + lastArterialPressureReadCtr = 0; + lastVenousPressureReadCtr = 0; + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + lastBPOcclReadCtr = 0; + lastBPErrorCtr = 0; + } + + longFilteredArterialPressure = 0.0; + shortFilteredArterialPressure = 0.0; + shortFilteredVenousPressure = 0.0; + presOcclDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + presOcclState = PRESSURE_WAIT_FOR_POST_STATE; + presOcclPostState = PRESSURE_SELF_TEST_STATE_START; + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + bloodPumpOcclusionAfterCartridgeInstall = 0; + } } +/*********************************************************************//** + * @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(); + } +} + /*********************************************************************//** * @brief - * The setOcclusionThreshold function sets the occlusion pressure threshold - * for a given occlusion sensor. - * @details - * Inputs : none - * Outputs : pressure threshold - * @param sensor occlusion sensor we are setting threshold for - * @param threshold pressure threshold above which indicates an occlusion (mmHg) - * @return none - *************************************************************************/ -void setOcclusionThreshold( OCCLUSION_SENSORS_T sensor, F32 threshold ) -{ - switch ( sensor ) // TODO - will threshold be range checked by caller or should we do it here? what is valid range? - { - case OCCLUSION_SENSOR_BLOOD_PUMP: - bloodPumpOcclusionPressureThresholdmmHG = threshold; - break; - - case OCCLUSION_SENSOR_DIAL_IN_PUMP: - dialInPumpOcclusionPressureThresholdmmHG = threshold; - break; - - case OCCLUSION_SENSOR_DIAL_OUT_PUMP: - dialOutPumpOcclusionPressureThresholdmmHG = threshold; - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_PRES_OCCL_INVALID_OCCL_SENSOR, sensor ) - break; - } -} - -/*********************************************************************//** - * @brief * The execPresOccl function executes the pressure and occlusion monitor. - * @details - * Inputs : presOcclState - * Outputs : presOcclState + * @details Inputs: presOcclState + * @details Outputs: presOcclState * @return none *************************************************************************/ void execPresOccl( void ) { - // state machine + // State machine switch ( presOcclState ) { - case PRESSURE_INIT_STATE: - presOcclState = handlePresOcclInitState(); + case PRESSURE_WAIT_FOR_POST_STATE: + presOcclState = handlePresOcclWaitForPOSTState(); break; case PRESSURE_CONTINUOUS_READ_STATE: @@ -163,206 +333,674 @@ break; } - // publish pressure/occlusion data on interval + // 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 handlePresOcclInitState function handles the pres/occl initialize state - * of the pressure/occlusion monitor state machine. - * @details - * Inputs : TBD - * Outputs : TBD - * @return next state - *************************************************************************/ -static PRESSURE_STATE_T handlePresOcclInitState( void ) -{ - PRESSURE_STATE_T 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 : TBD - * Outputs : pressure sensor values updated + * @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; - - S32 artPres = getFPGAArterialPressure(); - U16 venPres = getFPGAVenousPressure(); - U16 bldOccl = getFPGABloodPumpOcclusion(); - U16 dliOccl = getFPGADialInPumpOcclusion(); - U16 dloOccl = getFPGADialOutPumpOcclusion(); - F32 venPresPSI; - - // TODO - convert ADC counts to mmHg for each sensor - arterialPressure.data = ARTERIAL_PRESSURE_V_PER_BIT * ( (F32)(artPres) / ( ARTERIAL_PRESSURE_SENSITIVITY / ARTERIAL_PRESSURE_V_BIAS ) ); - venPresPSI = ( (F32)(venPres - VENOUS_PRESSURE_OFFSET) * (VENOUS_PRESSURE_MAX - VENOUS_PRESSURE_MIN) / (F32)VENOUS_PRESSURE_SCALE ) - VENOUS_PRESSURE_MIN; - venousPressure.data = venPresPSI * PSI_TO_MMHG; - bloodPumpOcclusion.data = (F32)bldOccl; - dialInPumpOcclusion.data = (F32)dliOccl; - dialOutPumpOcclusion.data = (F32)dloOccl; - - // TODO - any filtering required??? - - // check for occlusions - checkOcclusions(); - - // TODO - any other checks - + PRESSURE_STATE_T result = PRESSURE_CONTINUOUS_READ_STATE; + + // Read latest in-line (arterial and venous) pressures + convertInlinePressures(); + + // Read latest occlusion pressures + convertOcclusionPressures(); + + // Check in-line pressures are in range + checkArterialPressureInRange(); + checkVenousPressureInRange(); + + // Check for occlusions + checkOcclusions(); + return result; } - + +/*********************************************************************//** + * @brief + * The convertInlinePressures function reads inline pressure sensor readings + * and converts to mmHg. Sensor status/alarm is checked. + * @details Inputs: FPGA + * @details Outputs: arterialPressure, venousPressure + * @return none + *************************************************************************/ +static void convertInlinePressures( void ) +{ + F32 rawArterialPres = 0.0; + U08 artPresAlarm = 0; + U08 artPresStatus = 0; + F32 venPresPSI = 0.0; + U16 fpgaVenPres = getFPGAVenousPressure(); + U16 venPres = fpgaVenPres & 0x3FFF; // 14-bit data + U08 venPresStatus = (U08)( fpgaVenPres >> SHIFT_14_BITS ); // High 2 bits is status code for venous pressure + U08 venReadCtr = getFPGAVenousPressureReadCounter(); + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) ) + { + U16 fpgaArtPres = getFPGADVTArterialPressure(); + U16 artPres = fpgaArtPres & 0x3FFF; + rawArterialPres = (F32)artPres; + artPresStatus = (U08)( fpgaArtPres >> SHIFT_14_BITS ); + } + else +#endif + { + U32 fpgaArtPres = getFPGAArterialPressure(); + S32 artPres = (S32)( fpgaArtPres & MASK_OFF_U32_MSB ) - ARTERIAL_PRESSURE_CONVERSION_OFFSET; // Subtract 2^23 from low 24 bits to get signed reading + rawArterialPres = (F32)artPres; + artPresAlarm = (U08)( fpgaArtPres >> SHIFT_24_BITS ); // High byte is alarm code for arterial pressure + } + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) ) + { +#endif + if ( ARTERIAL_PRESSURE_NORMAL_OP == artPresStatus ) + { + U08 artReadCtr = getFPGADVTArterialPressureReadCounter(); + + // Check for stale venous pressure reading + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_READ_TIMEOUT_ERROR, ( lastArterialPressureReadCtr == artReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_ARTERIAL_PRESSURE_READ_TIMEOUT_ERROR ); + } + // Record arterial pressure sensor read counter for next time around + lastArterialPressureReadCtr = artReadCtr; + + arterialPressure.data = ( (F32)(rawArterialPres - ARTERIAL_PRESSURE_OFFSET) * + (ARTERIAL_PRESSURE_MAX_PSI - ARTERIAL_PRESSURE_MIN_PSI) / (F32)ARTERIAL_PRESSURE_SCALE ) + ARTERIAL_PRESSURE_MIN_PSI; + arterialPressure.data = arterialPressure.data * PSI_TO_MMHG; + } + else if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT, TRUE ) ) + { + activateAlarmNoData( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT ); + } + else + { + resetPersistentAlarmTimer( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT ); + } + } + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) != SW_CONFIG_ENABLE_VALUE ) + { +#endif + if ( 0 == artPresAlarm ) + { + U08 artReadCtr = getFPGAArterialPressureReadCounter(); + U08 artErrorCtr = getFPGAArterialPressureErrorCounter(); + + // Check for stale arterial pressure reading + // TODO I think we should check the change of the error count not if it is greater than 0? + if ( FALSE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_READ_TIMEOUT_ERROR, ( lastArterialPressureReadCtr == artReadCtr || artErrorCtr > 0 ) ) ) + { + arterialPressure.data = ARTERIAL_PRESSURE_V_PER_BIT * ( rawArterialPres / ( ARTERIAL_PRESSURE_SENSITIVITY * ARTERIAL_PRESSURE_V_BIAS ) ) + + getF32OverrideValue( &arterialPressureOffset ); + } + else + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_READ_TIMEOUT_ERROR, (U32)artErrorCtr ); + } + // Record arterial pressure sensor read counter for next time around + lastArterialPressureReadCtr = artReadCtr; + } + else + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT, (U32)artPresAlarm ) + } + } + } + + // Check for stale venous pressure reading + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_READ_TIMEOUT_ERROR, ( lastVenousPressureReadCtr == venReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_VENOUS_PRESSURE_READ_TIMEOUT_ERROR ); + } + // Record venous pressure sensor read counter for next time around + lastVenousPressureReadCtr = venReadCtr; + + // 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; + + // Convert venous pressure from PSI to mmHg if sensor status is normal + if ( VENOUS_PRESSURE_NORMAL_OP == venPresStatus ) + { + venousPressure.data = venPresPSI * PSI_TO_MMHG; + } + // If venous pressure sensor status is not normal, fault +#ifndef _RELEASE_ + else if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) + { + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, TRUE ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, (U32)venPresStatus ) + } + } +#endif + else + { + resetPersistentAlarmTimer( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT ); + } + + // 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(); + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + // Check for sensor errors + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_SENSOR_ERROR, ( bpErrorCtr != lastBPErrorCtr ) ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_SENSOR_ERROR, (U32)bpErrorCtr ) + } + + // Check for stale occlusion reads + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR, ( bpReadCtr == lastBPOcclReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR ); + } + } + + // Record occlusion sensor readings + bloodPumpOcclusion.data = (U32)getFPGABloodPumpOcclusion(); + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + // Record occlusion read and error counters for next time around + lastBPOcclReadCtr = bpReadCtr; + lastBPErrorCtr = bpErrorCtr; + } +} + +/*********************************************************************//** + * @brief + * The checkArterialPressureInRange function checks that artieral pressure is + * within the set alarm limits. Alarm is triggered if not. + * @details Inputs: arterialPressure + * @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 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 during treatment mode + if ( ( MODE_TREA == getCurrentOperationMode() ) && + ( getTreatmentState() <= TREATMENT_DIALYSIS_STATE && getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) ) + { + F32 artLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ); + F32 artHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); + + // If BP is ramping up, extend range to outer limits as pressure may not yet have reached expected range. + if ( isBloodPumpRampComplete() != TRUE ) + { + artLowLimit = (F32)getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ); + artHighLimit = (F32)getS32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); + } + + // Check arterial pressure is within user set alarm limits + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres < artLowLimit ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres, artLowLimit ); + } + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres > artHighLimit ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres, artHighLimit ); + } + } + else if (( MODE_TREA == getCurrentOperationMode() ) && ( TREATMENT_STOP_STATE == getTreatmentState() || + TREATMENT_RINSEBACK_STATE == getTreatmentState() || TREATMENT_RECIRC_STATE == getTreatmentState() || + TREATMENT_END_STATE == getTreatmentState())) + { + // Check arterial pressure is within non-treatment alarm limits + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres < ARTERIAL_PRESSURE_ND_MIN_MMHG ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres, ARTERIAL_PRESSURE_ND_MIN_MMHG ); + } + } + else + { // Reset persistence if alarm is out of scope + isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_LOW, FALSE ); + isPersistentAlarmTriggered( ALARM_ID_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 + * @details Outputs: Alarm if out of range + * @return none + *************************************************************************/ +static void checkVenousPressureInRange( void ) +{ + F32 venPres = getFilteredVenousPressure(); + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_VENOUS_PRESSURE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + // Check venous pressure is in range + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres > VENOUS_PRESSURE_MAX_MMHG ) || + TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres < VENOUS_PRESSURE_MIN_MMHG ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres ); + } + + // Check venous pressure during treatment mode + if ( ( MODE_TREA == getCurrentOperationMode() ) && + ( getTreatmentState() <= TREATMENT_DIALYSIS_STATE && getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) ) + { + F32 venLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ); + F32 venHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); + + // If BP is ramping up, extend range to outer limits as pressure may not yet have reached expected range. + if ( isBloodPumpRampComplete() != TRUE ) + { + venLowLimit = MIN_VENOUS_PRESSURE_FOR_RAMP_MMHG; + venHighLimit = (F32)getS32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); + } + + // Cannot monitor for low venous pressure while venting air trap + if ( getValveAirTrapStatus() != STATE_OPEN ) + { + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, venPres < venLowLimit ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_LOW, venPres, venLowLimit ); + } + } + else + { // clear persistence if air trap valve is open + isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, FALSE ); + } + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres > venHighLimit ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres, venHighLimit ); + } + } + else if ( ( MODE_TREA == getCurrentOperationMode() ) && ( TREATMENT_STOP_STATE == getTreatmentState() || + TREATMENT_RINSEBACK_STATE == getTreatmentState() || TREATMENT_RECIRC_STATE == getTreatmentState() || + TREATMENT_END_STATE == getTreatmentState())) + { + // Check venous pressure is less than non-treatment alarm limit + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres > VENOUS_PRESSURE_ND_MAX_MMHG ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres, VENOUS_PRESSURE_ND_MAX_MMHG ); + } + } + else + { // Reset persistence if alarm is out of scope + isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, FALSE ); + isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_HIGH, FALSE ); + } + } +} + /*********************************************************************//** * @brief * The checkPressureLimits function gets the pressure/occlusion data * publication interval. - * @details - * Inputs : occlusion pressures for the pumps - * Outputs : + * @details Inputs: occlusion pressures for the pumps + * @details Outputs: Alarm if occlusion limit exceeded * @return none *************************************************************************/ static void checkOcclusions( void ) { - F32 bpOccl = getMeasuredBloodPumpOcclusion(); - F32 diOccl = getMeasuredDialInPumpOcclusion(); - F32 doOccl = getMeasuredDialOutPumpOcclusion(); - -#ifndef DISABLE_PRESSURE_CHECKS - if ( bpOccl > bloodPumpOcclusionPressureThresholdmmHG ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_OCCLUSION_BLOOD_PUMP, bpOccl ) - // TODO - stop blood pump immediately, ... + U32 bpOccl = getMeasuredBloodPumpOcclusion(); + BOOL outOfRange = ( bpOccl < MIN_OCCLUSION_COUNTS || bpOccl > MAX_OCCLUSION_COUNTS ? TRUE : FALSE ); + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + // Range check occlusion sensor + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, outOfRange ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, bpOccl ); + } + + // Check for occlusion + if ( bpOccl > ( OCCLUSION_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) + { + signalBloodPumpHardStop(); // Stop pump immediately + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_OCCLUSION_BLOOD_PUMP, bpOccl ) + } + else if ( bpOccl <= ( OCCLUSION_CLEAR_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) + { + clearAlarmCondition( ALARM_ID_OCCLUSION_BLOOD_PUMP ); + } } - if ( diOccl > dialInPumpOcclusionPressureThresholdmmHG ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_OCCLUSION_DIAL_IN_PUMP, diOccl ) - // TODO - stop dialysate inlet pump immediately, ... - } - if ( doOccl > dialOutPumpOcclusionPressureThresholdmmHG ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_OCCLUSION_DIAL_OUT_PUMP, doOccl ) - // TODO - stop dialysate outlet pump immediately, ... - } -#endif } /*********************************************************************//** * @brief - * The getPublishPresOcclDataInterval function gets the pressure/occlusion data - * publication interval. - * @details - * Inputs : presOcclDataPublishInterval - * Outputs : none - * @return the current pressure/occlusion data publication interval (in task intervals). - *************************************************************************/ -DATA_GET( U32, getPublishPresOcclDataInterval, presOcclDataPublishInterval ) - -/*********************************************************************//** - * @brief * The getMeasuredArterialPressure function gets the current arterial pressure. - * @details - * Inputs : arterialPressure - * Outputs : none + * @details Inputs: arterialPressure + * @details Outputs: none * @return the current arterial pressure (in mmHg). *************************************************************************/ -DATA_GET( F32, getMeasuredArterialPressure, arterialPressure ) +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 - * Outputs : none + * @details Inputs: venousPressure + * @details Outputs: none * @return the current venous pressure (in mmHg). *************************************************************************/ -DATA_GET( F32, getMeasuredVenousPressure, venousPressure ) +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 getMeasuredBloodPumpOcclusion function gets the measured blood pump * occlusion pressure. - * @details - * Inputs : bloodPumpOcclusion - * Outputs : none + * @details Inputs: bloodPumpOcclusion + * @details Outputs: none * @return the current blood pump occlusion pressure (in mmHg). *************************************************************************/ -DATA_GET( F32, getMeasuredBloodPumpOcclusion, bloodPumpOcclusion ) +U32 getMeasuredBloodPumpOcclusion( void ) +{ + U32 result = bloodPumpOcclusion.data; + + if ( OVERRIDE_KEY == bloodPumpOcclusion.override ) + { + result = bloodPumpOcclusion.ovData; + } + + return result; +} -/*********************************************************************//** - * @brief - * The getMeasuredDialInPumpOcclusion function gets the measured dialysate - * inlet pump occlusion pressure. - * @details - * Inputs : dialInPumpOcclusion - * Outputs : none - * @return the current dialysis inlet pump occlusion pressure (in mmHg). - *************************************************************************/ -DATA_GET( F32, getMeasuredDialInPumpOcclusion, dialInPumpOcclusion ) +/*********************************************************************//** + * @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; + + // 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 getMeasuredDialOutPumpOcclusion function gets the measured dialysate - * outlet pump occlusion pressure. - * @details - * Inputs : dialOutPumpOcclusion - * Outputs : none - * @return the current dialysis outlet pump occlusion pressure (in mmHg). - *************************************************************************/ -DATA_GET( F32, getMeasuredDialOutPumpOcclusion, dialOutPumpOcclusion ) - -/*********************************************************************//** - * @brief * The publishPresOcclData function publishes pressure/occlusion data at the * set interval. - * @details - * Inputs : TBD - * Outputs : Pressure/occlusion data are published to CAN bus. + * @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 >= getPublishPresOcclDataInterval() ) - { - F32 artPres = getMeasuredArterialPressure(); - F32 venPres = getMeasuredVenousPressure(); - F32 bpOccl = getMeasuredBloodPumpOcclusion(); - F32 diOccl = getMeasuredDialInPumpOcclusion(); - F32 doOccl = getMeasuredDialOutPumpOcclusion(); + // Publish pressure/occlusion data on interval + if ( ++presOcclDataPublicationTimerCounter >= getU32OverrideValue( &presOcclDataPublishInterval ) ) + { + PRESSURE_OCCLUSION_DATA_T data; - broadcastPresOcclData( artPres, venPres, bpOccl, diOccl, doOccl ); + data.arterialPressure = shortFilteredArterialPressure; + data.venousPressure = shortFilteredVenousPressure; + data.bldPumpOcclusion = getMeasuredBloodPumpOcclusion(); + data.diPumpOcclusion = 0; // TODO - remove unused fields + data.doPumpOcclusion = 0; + + 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 state machine for the - * PresOccl self-test. - * @details - * Inputs : none - * Outputs : none - * @return the current state of the PresOccl self-test. + * The execPresOcclTest function executes the PresOccl self-test. + * @details Inputs: none + * @details Outputs: Triggers fault when test case fails + * @return none *************************************************************************/ -SELF_TEST_STATUS_T execPresOcclTest( void ) -{ - SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; - - // TODO - implement self-test(s) - - return result; +void execPresOcclTest( void ) +{ +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + U32 const bpPressure = getMeasuredBloodPumpOcclusion(); + F32 const arterialPressure = getFilteredArterialPressure(); + F32 const 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 const bpPressure = getMeasuredBloodPumpOcclusion(); + + if ( ( bpPressure <= CARTRIDGE_LOADED_THRESHOLD ) || ( bpPressure >= OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX ) ) + { + activateAlarmNoData( ALARM_ID_NO_CARTRIDGE_LOADED ); + 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 *************************************************************************/ @@ -372,9 +1010,8 @@ * @brief * The testSetPresOcclDataPublishIntervalOverride function overrides the * pressure and occlusion data publish interval. - * @details - * Inputs : none - * Outputs : presOcclDataPublishInterval + * @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 *************************************************************************/ @@ -398,9 +1035,8 @@ * @brief * The testResetPresOcclDataPublishIntervalOverride function resets the override * of the pressure and occlusion data publish interval. - * @details - * Inputs : none - * Outputs : presOcclDataPublishInterval + * @details Inputs: none + * @details Outputs: presOcclDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetPresOcclDataPublishIntervalOverride( void ) @@ -421,9 +1057,8 @@ * @brief * The testSetArterialPressureOverride function overrides the measured arterial * pressure. - * @details - * Inputs : none - * Outputs : arterialPressure + * @details Inputs: none + * @details Outputs: arterialPressure * @param value override arterial pressure (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ @@ -445,9 +1080,8 @@ * @brief * The testResetArterialPressureOverride function resets the override of the * arterial pressure. - * @details - * Inputs : none - * Outputs : arterialPressure + * @details Inputs: none + * @details Outputs: arterialPressure * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetArterialPressureOverride( void ) @@ -468,9 +1102,8 @@ * @brief * The testSetVenousPressureOverride function overrides the measured venous * pressure. - * @details - * Inputs : none - * Outputs : venousPressure + * @details Inputs: none + * @details Outputs: venousPressure * @param value override measured venous pressure with (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ @@ -492,9 +1125,8 @@ * @brief * The testResetVenousPressureOverride function resets the override of the * venous pressure. - * @details - * Inputs : none - * Outputs : venousPressure + * @details Inputs: none + * @details Outputs: venousPressure * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetVenousPressureOverride( void ) @@ -514,14 +1146,13 @@ /*********************************************************************//** * @brief * The testSetBloodPumpOcclusionOverride function overrides the measured - * blood pump occlusion pressure.n - * @details - * Inputs : none - * Outputs : bloodPumpOcclusion - * @param value override measured blood pump occlusion pressure with (in mmHg) + * 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( F32 value ) +BOOL testSetBloodPumpOcclusionOverride( U32 value ) { BOOL result = FALSE; @@ -539,9 +1170,8 @@ * @brief * The testResetBloodPumpOcclusionOverride function resets the override of the * measured blood pump occlusion pressure. - * @details - * Inputs : none - * Outputs : bloodPumpOcclusion + * @details Inputs: none + * @details Outputs: bloodPumpOcclusion * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetBloodPumpOcclusionOverride( void ) @@ -556,100 +1186,51 @@ } return result; -} +} + +/*********************************************************************//** + * @brief + * The testSetBloodPumpOcclusionOverride function overrides the arterial + * pressure offset. + * @details Inputs: none + * @details Outputs: arterialPressureOffset + * @param value override arterial pressure offset with + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetArterialPressureOffsetOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + arterialPressureOffset.ovData = value; + arterialPressureOffset.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetArterialPressureOffsetOverride function resets the override of the + * arterial pressure offset. + * @details Inputs: none + * @details Outputs: arterialPressureOffset + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetArterialPressureOffsetOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + arterialPressureOffset.override = OVERRIDE_RESET; + arterialPressureOffset.ovData = arterialPressureOffset.ovInitData; + } + + return result; +} -/*********************************************************************//** - * @brief - * The testSetDialInPumpOcclusionOverride function overrides the measured - * dialysate inlet pump occlusion pressure.n - * @details - * Inputs : none - * Outputs : dialInPumpOcclusion - * @param value override measured dialysate inlet pump occlusion pressure (in mmHg) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetDialInPumpOcclusionOverride( F32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - dialInPumpOcclusion.ovData = value; - dialInPumpOcclusion.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetDialInPumpOcclusionOverride function resets the override of the - * measured dialysate inlet pump occlusion pressure. - * @details - * Inputs : none - * Outputs : dialInPumpOcclusion - * @return TRUE if reset successful, FALSE if not - *************************************************************************/ -BOOL testResetDialInPumpOcclusionOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - dialInPumpOcclusion.override = OVERRIDE_RESET; - dialInPumpOcclusion.ovData = dialInPumpOcclusion.ovInitData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetDialOutPumpOcclusionOverride function overrides the measured - * dialysate outlet pump occlusion pressure. - * @details - * Inputs : none - * Outputs : dialOutPumpOcclusion - * @param value override measured dialysate outlet pump occlusion pressure (in mmHg) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetDialOutPumpOcclusionOverride( F32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - dialOutPumpOcclusion.ovData = value; - dialOutPumpOcclusion.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetDialOutPumpOcclusionOverride function resets the override of the - * measured dialysate outlet pump occlusion pressure. - * @details - * Inputs : none - * Outputs : dialOutPumpOcclusion - * @return TRUE if reset successful, FALSE if not - *************************************************************************/ -BOOL testResetDialOutPumpOcclusionOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - dialOutPumpOcclusion.override = OVERRIDE_RESET; - dialOutPumpOcclusion.ovData = dialOutPumpOcclusion.ovInitData; - } - - return result; -} - /**@}*/