Index: firmware/App/Drivers/PressureSensor.c =================================================================== diff -u -r3a8cf075eb6f0d255f516ac26bac7fbaacfde14a -ra91074d04b607deabe4fbf714d40e9d191590359 --- firmware/App/Drivers/PressureSensor.c (.../PressureSensor.c) (revision 3a8cf075eb6f0d255f516ac26bac7fbaacfde14a) +++ firmware/App/Drivers/PressureSensor.c (.../PressureSensor.c) (revision a91074d04b607deabe4fbf714d40e9d191590359) @@ -36,7 +36,7 @@ static OVERRIDE_F32_T currentPresTempReadings[ NUM_OF_PRESSURE_SENSORS ]; ///< Current pressure sensor temperature readings (overrideable). static OVERRIDE_U32_T lastPressureReadCounter[ NUM_OF_PRESSURE_SENSORS ]; ///< Last pressure sensor read count (Overrideable). static OVERRIDE_U32_T lastPressureErrorCounter[ NUM_OF_PRESSURE_SENSORS ]; ///< Last pressure sensor error count (Overrideable). - + // ********** private function prototypes ********** static void checkPressureSensors( void ); Index: firmware/App/Monitors/Pressures.c =================================================================== diff -u --- firmware/App/Monitors/Pressures.c (revision 0) +++ firmware/App/Monitors/Pressures.c (revision a91074d04b607deabe4fbf714d40e9d191590359) @@ -0,0 +1,1070 @@ +/************************************************************************** +* +* Copyright (c) 2020-2024 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 Pressure.c +* +* @author (last) Vinayakam Mani +* @date (last) 06-May-2024 +* +* @author (original) Sean +* @date (original) 15-Jan-2020 +* +***************************************************************************/ + +#include "AirPump.h" +#include "AlarmMgmtTD.h" +//#include "BloodFlow.h" +#include "FpgaTD.h" +#include "Messaging.h" +//#include "ModeTreatment.h" +//#include "ModeTreatmentParams.h" +//#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "PersistentAlarm.h" +#include "Pressures.h" +//#include "SelfTests.h" +#include "TaskGeneral.h" +//#include "Temperatures.h" +#include "Timers.h" +#include "Utilities.h" +//#include "Valves.h" + +/** + * @addtogroup Pressures + * @{ + */ + +// ********** private definitions ********** + +#define PRESSURE_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_OFF ( 0 ) ///< pressure limit stabilization period off +#define PRES_LIMIT_STABILIZATION_2_TIME_MS ( 60 * MS_PER_SECOND ) ///< Duration of pressure limit second stage stabilization period (in ms) +#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 ( 10 * MS_PER_SECOND ) ///< Duration of pressure limit short stabilization period (in ms). +#define PRES_LIMIT_RESTABILIZE_TIME_MS ( 15 * SEC_PER_MIN * MS_PER_SECOND ) ///< Duration of pressure limit re-stabilize period (in ms). + +/// Pressure Limit minimum stabilization time before short stabilization time activation +static const U32 PRES_LIMIT_MIN_STABILIZATION_TIME_IN_MS = ( PRES_LIMIT_STABILIZATION_TIME_MS - PRES_LIMIT_SHORT_STABILIZE_TIME_MS ); + +#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_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_EXEMPTION_PERIOD ( ( 2 * MS_PER_SECOND ) / \ + TASK_GENERAL_INTERVAL ) ///< Venous pressure low exemption period (in task interval) after fill for all blood flow rate + +#define MIN_TIME_BETWEEN_AIR_TRAP_FILL_EXEMPTIONS_MS ( 1200 ) ///< To monitor low Venous pressure in the defined interval in a case where continuous air fill event happens followed by exemption period to stabilize the pressure +#define MIN_TIME_BETWEEN_AIR_TRAP_FILL_EXEMPTIONS_WINDOW ( MIN_TIME_BETWEEN_AIR_TRAP_FILL_EXEMPTIONS_MS / \ + TASK_GENERAL_INTERVAL ) ///< Low Venous pressure monitoring window between air fill events based on the task interval time + +#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 HIGH_VEN_PRES_ALARM_PERSISTENCE 500 ///< Alarm persistence period for high venous pressure alarm +#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. + +/// Defined states for the pressure monitor state machine. +typedef enum Pressure_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 monitor states. +} PRESSURE_STATE_T; + +/// Defined states for the pressure self-test state machine. +typedef enum Pressure_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 pressureState; ///< Current state of pressure monitor state machine. +static U32 pressureDataPublicationTimerCounter; ///< 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. +static U32 prevVenLowPresExemptAfterAirTrapFillTimerCtr; ///< previous venous low pressure exempt fill time counter + +static OVERRIDE_U32_T pressuresDataPublishInterval; ///< Interval (in ms) at which to publish pressure/occlusion data to CAN bus. +static PRESSURE_LIMITS_STATES_T currPresLimitsState; ///< Current pressure limits state. +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 OVERRIDE_F32_T shortFilteredArterialPressure; ///< Measured arterial pressure after short (1 s) filter. +static F32 longFilteredVenousPressure; ///< Measured venous pressure after long (10 s) filter. +static OVERRIDE_F32_T shortFilteredVenousPressure; ///< Measured venous pressure after short (1 s) filter. +static STABILIZATION_PERIODS_T pressureStabilizeTime; ///< Pressure stabilization time based on system events such as airpump, treatment param changes etc., +static BOOL resetFillExemptPeriod; ///< Flag to reset the exempt period after defined time expire. +static BOOL lowVenousPressureExemptCheck; ///< low venous pressure exempt check flag based on the air trap valve status + +static F32 arterialPressureOffset; ///< Arterial pressure sensor offset (in mmHg). +static F32 venousPressureOffset; ///< Venous pressure sensor offset (in mmHg). + +static U32 emptySalineBagCtr; ///< 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; ///< Index for next sample in rolling average array. +static F32 artPressureReadingsLongTotal; ///< Rolling total - used to calc average. +static U32 artPressureReadingsLongCount; ///< 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; ///< Index for next sample in rolling average array. +static F32 artPressureReadingsShortTotal; ///< Rolling total - used to calc average. +static U32 artPressureReadingsShortCount; ///< 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; ///< Index for next sample in rolling average array. +static F32 venPressureReadingsLongTotal; ///< Rolling total - used to calc average. +static U32 venPressureReadingsLongCount; ///< 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; ///< Index for next sample in rolling average array. +static F32 venPressureReadingsShortTotal; ///< Rolling total - used to calc average. +static U32 venPressureReadingsShortCount; ///< Number of samples in flow rolling average buffer. + +static PRESSURE_SELF_TEST_STATE_T pressurePostState; ///< Pressure self test post state. +//static HD_PRESSURE_SENSORS_CAL_RECORD_T pressureSensorsCalRecord; ///< Pressure sensors calibration record. + +// ********** private function prototypes ********** + +static PRESSURE_STATE_T handlePressureWaitForPOSTState( void ); +static PRESSURE_STATE_T handlePressureContReadState( void ); +static void execPressureLimits( void ); +static void checkArterialPressureInRange( void ); +static void checkVenousPressureInRange( void ); +static void publishPressureData( void ); +static void determineArtVenPressureLimits( void ); +static void filterInlinePressureReadings( F32 artPres, F32 venPres ); + +/*********************************************************************//** + * @brief + * The initPressure function initializes the Pressure unit. + * @details \b Inputs: none + * @details \b Outputs: Pressure unit initialized. + * @return none + *************************************************************************/ +void initPressure( void ) +{ + // Initialize persistent pressure alarms + initPersistentAlarm( ALARM_ID_TD_ARTERIAL_PRESSURE_LOW, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_TD_ARTERIAL_PRESSURE_HIGH, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_TD_VENOUS_PRESSURE_LOW, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_TD_VENOUS_PRESSURE_HIGH, 0, HIGH_VEN_PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_TD_ARTERIAL_PRESSURE_OUT_OF_RANGE, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_TD_VENOUS_PRESSURE_OUT_OF_RANGE, 0, PRES_ALARM_PERSISTENCE ); + + setPressureLimitsToOuterBounds(); + + resetArtVenPressureOffsets(); + + currPresLimitsState = PRESSURE_LIMITS_STATE_OFF; + pressureLimitsActive = FALSE; + stabilizationStartTimeMs = 0; + stableArterialPressure = 0; + stableVenousPressure = 0; + venLowPresExemptAfterAirTrapFillTimerCtr = 0; + prevVenLowPresExemptAfterAirTrapFillTimerCtr = 0; + emptySalineBagCtr = 0; + + longFilteredArterialPressure = 0.0F; + shortFilteredArterialPressure.data = 0.0F; + shortFilteredArterialPressure.ovData = 0.0F; + shortFilteredArterialPressure.ovInitData = 0.0F; + shortFilteredArterialPressure.override = OVERRIDE_RESET; + longFilteredVenousPressure = 0.0F; + shortFilteredVenousPressure.data = 0.0F; + shortFilteredVenousPressure.ovData = 0.0F; + shortFilteredVenousPressure.ovInitData = 0.0F; + shortFilteredVenousPressure.override = OVERRIDE_RESET; + + pressureDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + pressureState = PRESSURE_WAIT_FOR_POST_STATE; + pressurePostState = PRESSURE_SELF_TEST_STATE_START; + pressureStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; + resetFillExemptPeriod = TRUE; + lowVenousPressureExemptCheck = TRUE; + + pressuresDataPublishInterval.data = PRESSURE_DATA_PUB_INTERVAL; + pressuresDataPublishInterval.ovData = PRESSURE_DATA_PUB_INTERVAL; + pressuresDataPublishInterval.ovInitData = PRESSURE_DATA_PUB_INTERVAL; + pressuresDataPublishInterval.override = OVERRIDE_RESET; + + artPressureReadingsLongIdx = 0; + artPressureReadingsLongTotal = 0.0F; + artPressureReadingsLongCount = 0; + + artPressureReadingsShortIdx = 0; + artPressureReadingsShortTotal = 0.0F; + artPressureReadingsShortCount = 0; + + venPressureReadingsLongIdx = 0; + venPressureReadingsLongTotal = 0.0F; + venPressureReadingsLongCount = 0; + + venPressureReadingsShortIdx = 0; + venPressureReadingsShortTotal = 0.0F; + venPressureReadingsShortCount = 0; +} + +/*********************************************************************//** + * @brief + * The resetArtVenPressureOffsets function resets the arterial and venous + * offsets to zero. + * @details \b Inputs: none + * @details \b 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. + * @note It is assumed that the caller will have reset the offsets prior + * to calling this function. + * @note The 1 second filtered readings are used so the caller should allow + * at least 2 seconds for pressure to settle (after changing a pump speed + * or valve position) and the filter to fill before calling this function. + * @details \b Alarm: ALARM_ID_TD_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE if + * offsets exceed maximums. + * @details \b Inputs: none + * @details \b Outputs: arterialPressureOffset, venousPressureOffset + * @return none + *************************************************************************/ +void setArtVenPressureOffsets( void ) +{ + // load latest readings into offsets + arterialPressureOffset = getFilteredArterialPressure(); + venousPressureOffset = getFilteredVenousPressure(); + + + if ( ( fabs( arterialPressureOffset ) > MAX_ART_VEN_OFFSET_MMHG ) || ( fabs( venousPressureOffset ) > MAX_ART_VEN_OFFSET_MMHG ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_TD_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, arterialPressureOffset, venousPressureOffset ); + } +} + +/*********************************************************************//** + * @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 \b Inputs: arterial line pressure + * @details \b Outputs: none + * @return TRUE if empty saline bag detected, FALSE if not. + *************************************************************************/ +BOOL isSalineBagEmpty( void ) +{ + BOOL result = FALSE; + + if ( getFilteredArterialPressure() < EMPTY_SALINE_BAG_THRESHOLD_MMHG ) + { + if ( ++emptySalineBagCtr >= EMPTY_SALINE_BAG_PERSISTENCE ) + { + result = TRUE; + } + } + else + { + emptySalineBagCtr = 0; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The setPressureLimitsToOuterBounds function sets the min/max pressure + * limits for arterial and venous pressure to their outer boundaries. + * @details \b Inputs: none + * @details \b 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 \b Inputs: pressureStabilizeTime + * @details \b Outputs: stableArterialPressure, stableVenousPressure + * @return none + *************************************************************************/ +void updatePressureLimitWindows( void ) +{ + F32 filtArt; + F32 filtVen; + S32 curArtPres; + S32 curVenPres; + + if ( USE_SHORT_STABILIZATION_PERIOD == pressureStabilizeTime ) + { + 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 + pressureDataPublicationTimerCounter = getU32OverrideValue( &pressuresDataPublishInterval ); +} + +/*********************************************************************//** + * @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 \b Inputs: currPresLimitsState + * @details \b Outputs: currPresLimitsState, stabilizationStartTimeMs, pressureStabilizeTime + * @param stabilizationPeriod stabilization periods. Use defines: + * STABILIZATION_PERIOD_OFF, USE_NORMAL_STABILIZATION_PERIOD, USE_SHORT_STABILIZATION_PERIOD + * @return none + *************************************************************************/ +void signalInitiatePressureStabilization( STABILIZATION_PERIODS_T stabilizationPeriod ) +{ + // 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 ) + { + U32 currentTime = getMSTimerCount(); + U32 expiredTime = u32DiffWithWrap( stabilizationStartTimeMs, currentTime ); + + // if pressure is already stabilized enough, assign the short stabilize time for the recent event ( air pump on). + // else,allow the ongoing stabilization to complete. + // allow Normal stabilization on a case when user updates flow rate or UF rate etc., + if ( ( expiredTime > PRES_LIMIT_MIN_STABILIZATION_TIME_IN_MS ) || + ( stabilizationPeriod == USE_NORMAL_STABILIZATION_PERIOD ) ) + { + pressureStabilizeTime = stabilizationPeriod; + stabilizationStartTimeMs = getMSTimerCount(); + } + } + else if ( ( PRESSURE_LIMITS_STATE_STABLE == currPresLimitsState ) || + ( PRESSURE_LIMITS_STATE_STABILIZATION_2 == currPresLimitsState ) ) + { + pressureStabilizeTime = stabilizationPeriod; + 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 \b Inputs: currPresLimitsState + * @details \b Outputs: currentArterialMaxLimit, currentArterialMinLimit, + * currentVenousMaxLimit, currentVenousMinLimit + * @return none + *************************************************************************/ +static void determineArtVenPressureLimits( void ) +{ + if ( ( PRESSURE_LIMITS_STATE_STABLE == currPresLimitsState ) || + ( PRESSURE_LIMITS_STATE_STABILIZATION_2 == currPresLimitsState ) ) + { + // apply pressure windows when stable + S32 artOffset = 120; //getTreatmentParameterS32( TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW ) / 2; + S32 venMinOffset = 100; //getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRES_LIMIT_ASYMMETRIC ); + S32 venMaxOffset = 20; //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 execPressure function executes the pressure monitor state machine. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if pressure state is invalid. + * @details \b Inputs: pressureState + * @details \b Outputs: pressureState + * @return none + *************************************************************************/ +void execPressure( void ) +{ + // State machine + switch ( pressureState ) + { + case PRESSURE_WAIT_FOR_POST_STATE: + pressureState = handlePressureWaitForPOSTState(); + break; + + case PRESSURE_CONTINUOUS_READ_STATE: + pressureState = handlePressureContReadState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_PRES_OCCL_INVALID_STATE, pressureState ) + break; + } + + // Publish pressure/occlusion data on interval + publishPressureData(); +} + +/*********************************************************************//** + * @brief + * The handlePressureWaitForPOSTState function handles the wait for POST + * state. + * @details \b Inputs: pressurePostState + * @details \b Outputs: none + * @return next state + *************************************************************************/ +static PRESSURE_STATE_T handlePressureWaitForPOSTState( void ) +{ + PRESSURE_STATE_T result = PRESSURE_WAIT_FOR_POST_STATE; + + if ( PRESSURE_TEST_STATE_COMPLETE == pressurePostState ) + { + result = PRESSURE_CONTINUOUS_READ_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handlePressureContReadState function handles the continuous read state + * of the pressure monitor state machine. + * @details \b Inputs: FPGA pressure readings + * @details \b Outputs: pressure sensor values updated + * @return next state + *************************************************************************/ +static PRESSURE_STATE_T handlePressureContReadState( void ) +{ + PRESSURE_STATE_T result = PRESSURE_CONTINUOUS_READ_STATE; + F32 fpgaArtPres = getPressure( PRESSURE_SENSOR_ARTERIAL ) - arterialPressureOffset; + F32 fpgaVenPres = getPressure( PRESSURE_SENSOR_VENOUS ) - venousPressureOffset; + + // Filter inline pressure readings + filterInlinePressureReadings( fpgaArtPres, fpgaVenPres ); + + // 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(); + + return result; +} + +/*********************************************************************//** + * @brief + * The execPressureLimits function executes the pressure limits state machine. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if presure limits state is invalid. + * @details \b Inputs: currPresLimitsState, stabilizationStartTimeMs + * @details \b Outputs: currPresLimitsState, stabilizationStartTimeMs + * @return next pressure limits state + *************************************************************************/ +static void execPressureLimits( void ) +{ + BOOL bpRunning = TRUE; //isBloodPumpRunning(); + BOOL bpRampComplete = TRUE; //isBloodPumpRampComplete(); + TD_OP_MODE_T currMode = getCurrentOperationMode(); + TREATMENT_STATE_T currTxState = TREATMENT_DIALYSIS_STATE; //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(); + pressureStabilizeTime = 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: + // update stabilization time + if ( USE_SHORT_STABILIZATION_PERIOD == pressureStabilizeTime ) + { + stabilizeTime = PRES_LIMIT_SHORT_STABILIZE_TIME_MS; + } + // Normal stabilization period + 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(); + currPresLimitsState = PRESSURE_LIMITS_STATE_STABILIZATION_2; + pressureStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; + } + break; + + case PRESSURE_LIMITS_STATE_STABILIZATION_2: + // zero stabilize time for 15 mins once pressure limits adjust scenario + if ( STABILIZATION_PERIOD_OFF == pressureStabilizeTime ) + { + stabilizeTime = PRES_LIMIT_STABILIZATION_OFF; + } + //60 sec second stage stabilization + else + { + stabilizeTime = PRES_LIMIT_STABILIZATION_2_TIME_MS; + } + + // second stage stabilization helps to re determine the pressure due to UF control change etc., + 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(); + currPresLimitsState = PRESSURE_LIMITS_STATE_STABLE; + // Reset to normal period as default. + pressureStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; + } + break; + + case PRESSURE_LIMITS_STATE_STABLE: + // Pressure is re determined after every 15 minutes once and be remain in limited pressure windows. + 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(); + pressureStabilizeTime = STABILIZATION_PERIOD_OFF; + currPresLimitsState = PRESSURE_LIMITS_STATE_STABILIZATION_2; + } + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_PRES_LIMITS_INVALID_STATE, currPresLimitsState ) + break; + } +} + +/*********************************************************************//** + * @brief + * The checkArterialPressureInRange function checks that artieral pressure is + * within the set alarm limits. + * @details \b Alarm: ALARM_ID_TD_ARTERIAL_PRESSURE_LOW if arterial pressure is low. + * @details \b Alarm: ALARM_ID_TD_ARTERIAL_PRESSURE_HIGH if arterial pressure is high. + * @details \b Alarm: ALARM_ID_TD_ARTERIAL_PRESSURE_OUT_OF_RANGE if arterial + * pressure is out of range. + * @details \b Inputs: arterialPressure, pressureLimitsActive, currentArterialMinLimit, + * currentArterialMaxLimit + * @details \b Outputs: none + * @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_TD_ARTERIAL_PRESSURE_OUT_OF_RANGE, + ( artPres > ARTERIAL_PRESSURE_MAX_MMHG || artPres < ARTERIAL_PRESSURE_MIN_MMHG ) ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_TD_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_TD_ARTERIAL_PRESSURE_LOW, artPresLow ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_TD_ARTERIAL_PRESSURE_LOW, artPres, (F32)currentArterialMinLimit ); + } + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_TD_ARTERIAL_PRESSURE_HIGH, artPresHigh ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_TD_ARTERIAL_PRESSURE_HIGH, artPres, (F32)currentArterialMaxLimit ); + } + } + else + { // Reset persistence if limits inactive + isPersistentAlarmTriggered( ALARM_ID_TD_ARTERIAL_PRESSURE_LOW, FALSE ); + isPersistentAlarmTriggered( ALARM_ID_TD_ARTERIAL_PRESSURE_HIGH, FALSE ); + } + } +} + +/*********************************************************************//** + * @brief + * The checkVenousPressureInRange function checks that venous pressure is + * within the set alarm limits. + * @details \b Alarm: ALARM_ID_TD_VENOUS_PRESSURE_LOW if venous pressure is low. + * @details \b Alarm: ALARM_ID_TD_VENOUS_PRESSURE_HIGH if venous pressure is high. + * @details \b Alarm: ALARM_ID_TD_VENOUS_PRESSURE_OUT_OF_RANGE if venous pressure + * is out of range. + * @details \b Inputs: venousPressure, pressureLimitsActive, currentVenousMinLimit, resetFillExemptPeriod + * currentVenousMaxLimit, venLowPresExemptAfterAirTrapFillTimerCtr, prevVenLowPresExemptAfterAirTrapFillTimerCtr + * @details \b Outputs: venLowPresExemptAfterAirTrapFillTimerCtr + * @return none + *************************************************************************/ +static void checkVenousPressureInRange( void ) +{ + F32 venPres = getFilteredVenousPressure(); + OPN_CLS_STATE_T airTrapValveState = STATE_CLOSED; //getValveAirTrapStatus(); + + // track time since last air trap fill + if ( ( STATE_OPEN == airTrapValveState ) && ( TRUE == resetFillExemptPeriod ) ) + { + venLowPresExemptAfterAirTrapFillTimerCtr = 0; + resetFillExemptPeriod = FALSE; + lowVenousPressureExemptCheck = FALSE; + } + else + { + // Increment counter on airtrap valve close state. Also, when next fill happens within exempt period, counter will be keep incremented irrespective of valve state. + if ( TRUE == lowVenousPressureExemptCheck ) + { + 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_TD_VENOUS_PRESSURE_OUT_OF_RANGE, ( venPres > VENOUS_PRESSURE_MAX_MMHG || venPres < VENOUS_PRESSURE_MIN_MMHG ) ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_TD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres ); + } + + // Check venous pressure when limits active + if ( pressureLimitsActive != FALSE ) + { + BOOL venPresLow, venPresHigh; + + // Fixed exemption period (in general task intervals) for low venous pressure alarms after air trap fills + U32 exemptPeriod = VENOUS_PRESSURE_EXEMPTION_PERIOD; + // minimumMonitoring Window helps to check and raise low venous pressure alarm on a case where repeated fill events occurrence. + // During this interval, if another airtrap fill occurs, there is no exemptions provided to stabilize the pressure and low venous pressure being raised when it goes below threshold value. + U32 minimumMonitoringWindow = exemptPeriod + MIN_TIME_BETWEEN_AIR_TRAP_FILL_EXEMPTIONS_WINDOW ; + + venPresLow = ( venPres < (F32)currentVenousMinLimit ? TRUE : FALSE ); + venPresHigh = ( venPres > (F32)currentVenousMaxLimit ? TRUE : FALSE ); + + // Check venous pressure is within alarm limits + // Low venous pressure is checked after exemption period and before end of reset period(minimum monitoring window) or until next air trap fill occurs + if ( ( venLowPresExemptAfterAirTrapFillTimerCtr > exemptPeriod ) && + ( ( venLowPresExemptAfterAirTrapFillTimerCtr <= minimumMonitoringWindow ) || + ( venLowPresExemptAfterAirTrapFillTimerCtr > prevVenLowPresExemptAfterAirTrapFillTimerCtr ) ) ) + { + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_TD_VENOUS_PRESSURE_LOW, venPresLow ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_TD_VENOUS_PRESSURE_LOW, venPres, (F32)currentVenousMinLimit ); + } + } + // during reset period, if airTrapValve open, still alarm needs to be raised , hence persistence clearance should happen before or after reset period. + if ( ( airTrapValveState == STATE_OPEN ) && + ( ( venLowPresExemptAfterAirTrapFillTimerCtr < exemptPeriod ) || + ( venLowPresExemptAfterAirTrapFillTimerCtr > minimumMonitoringWindow ) ) ) + { + isPersistentAlarmTriggered( ALARM_ID_TD_VENOUS_PRESSURE_LOW, FALSE ); + } + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_TD_VENOUS_PRESSURE_HIGH, venPresHigh ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_TD_VENOUS_PRESSURE_HIGH, venPres, (F32)currentVenousMaxLimit ); + } + + // Reset exempt flag only after exempt period for the last fill and after reset period (minimum monitoring window) + resetFillExemptPeriod = ( venLowPresExemptAfterAirTrapFillTimerCtr > minimumMonitoringWindow ? TRUE : FALSE ); + prevVenLowPresExemptAfterAirTrapFillTimerCtr = venLowPresExemptAfterAirTrapFillTimerCtr ; + } + else + { // Reset persistence if limits inactive + isPersistentAlarmTriggered( ALARM_ID_TD_VENOUS_PRESSURE_LOW, FALSE ); + isPersistentAlarmTriggered( ALARM_ID_TD_VENOUS_PRESSURE_HIGH, FALSE ); + } + } +} + +/*********************************************************************//** + * @brief + * The signalLowVenousPressureCheck function sets the low venous pressure Exempt check flag to increment the counter. + * @details \b Inputs: lowVenousPressureExemptCheck + * @details \b Outputs: lowVenousPressureExemptCheck + * @return none. + *************************************************************************/ +void signalLowVenousPressureCheck( void ) +{ + // When flag set, low venous pressure exempt counter increments. + lowVenousPressureExemptCheck = TRUE; +} + +/*********************************************************************//** + * @brief + * The getFilteredArterialPressure function gets the current filtered arterial pressure. + * @details \b Inputs: shortFilteredArterialPressure + * @details \b Outputs: none + * @return the current filtered arterial pressure (in mmHg). + *************************************************************************/ +F32 getFilteredArterialPressure( void ) +{ + return getF32OverrideValue( &shortFilteredArterialPressure ); +} + +/*********************************************************************//** + * @brief + * The getLongFilteredArterialPressure function gets the current long filtered arterial pressure. + * @details \b Inputs: longFilteredArterialPressure + * @details \b Outputs: none + * @return the current long filtered arterial pressure (in mmHg). + *************************************************************************/ +F32 getLongFilteredArterialPressure( void ) +{ + return longFilteredArterialPressure; +} + +/*********************************************************************//** + * @brief + * The getFilteredVenousPressure function gets the measured filtered venous pressure. + * @details \b Inputs: shortFilteredVenousPressure + * @details \b Outputs: none + * @return the current filtered venous pressure (in mmHg). + *************************************************************************/ +F32 getFilteredVenousPressure( void ) +{ + return getF32OverrideValue( &shortFilteredVenousPressure ); +} + +/*********************************************************************//** + * @brief + * The getLongFilteredVenousPressure function gets the current long filtered + * venous pressure. + * @details \b Inputs: longFilteredVenousPressure + * @details \b Outputs: none + * @return the current long filtered venous pressure (in mmHg). + *************************************************************************/ +F32 getLongFilteredVenousPressure( void ) +{ + return longFilteredVenousPressure; +} + +/*********************************************************************//** + * @brief + * The filterInlinePressureReadings function adds a new arterial and venous + * pressure sample to the filters. + * @details \b Inputs: none + * @details \b 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.data = 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.data = venPressureReadingsShortTotal / (F32)venPressureReadingsShortCount; +} + +/*********************************************************************//** + * @brief + * The publishPressureData function publishes pressure/occlusion data at the + * set interval. + * @details \b Message \b Sent: MSG_ID_PRESSURE_DATA + * @details \b Inputs: pressureDataPublicationTimerCounter, currPresLimitsState, + * currentArterialMinLimit, currentArterialMaxLimit, currentVenousMinLimit, + * currentVenousMaxLimit, longFilteredArterialPressure, longFilteredVenousPressure, + * shortFilteredArterialPressure, shortFilteredVenousPressure + * @details \b Outputs: Pressure/occlusion data are published to CAN bus. + * @return none + *************************************************************************/ +static void publishPressureData( void ) +{ + // Publish pressure/occlusion data on interval + if ( ++pressureDataPublicationTimerCounter >= getU32OverrideValue( &pressuresDataPublishInterval ) ) + { + PRESSURE_DATA_T data; + + data.arterialPressure = getFilteredArterialPressure(); + data.venousPressure = getFilteredVenousPressure(); + 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_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( PRESSURE_DATA_T ) ); + pressureDataPublicationTimerCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The execPressureTest function executes the Pressure self-test. Arterial + * and venous pressures must be within range while sensors are open to atmosphere. + * @details \b Alarm: ALARM_ID_TD_ARTERIAL_PRESSURE_SELF_TEST_FAILURE if + * arterial pressure is out of range during test. + * @details \b Alarm: ALARM_ID_TD_VENOUS_PRESSURE_SELF_TEST_FAILURE if + * venous pressure is out of range during test. + * @details \b Inputs: none + * @details \b Outputs: Triggers fault when test case fails + * @return none + *************************************************************************/ +void execPressureTest( void ) +{ +#ifndef _RELEASE_ +// if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + F32 arterialPressure = getFilteredArterialPressure(); + F32 venousPressure = getFilteredVenousPressure(); + + if ( ( arterialPressure < ARTERIAL_PRESSURE_SELF_TEST_MIN ) || ( arterialPressure > ARTERIAL_PRESSURE_SELF_TEST_MAX ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_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_TD_VENOUS_PRESSURE_SELF_TEST_FAILURE, venousPressure ); + } + } +} + +/*********************************************************************//** + * @brief + * The execPressurePOSTSelfTest function executes the pressure self-test to + * be run during power-on self-test on startup. Calibration constants are + * read in and their CRC is checked. + * @details \b Inputs: none + * @details \b Outputs: pressureSensorsCalRecord, occlusionSensorsCalRecord + * @return PASSED if self-test passes, FAILED if not. + *************************************************************************/ +SELF_TEST_STATUS_T execPressurePOSTSelfTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; + BOOL calStatus = TRUE; //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 ); + + pressurePostState = 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 testPressuresDataPublishIntervalOverride function overrides the interval + * at which the TD pressure data is published. + * @details \b \b Inputs: none + * @details \b \b Outputs: pressuresDataPublishInterval + * @param message Override message from Dialin which includes the interval + * (in ms) to override the pressure broadcast interval to. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testPressuresDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &pressuresDataPublishInterval, TASK_GENERAL_INTERVAL ); + + return result; +} + +/**@}*/ Index: firmware/App/Monitors/Pressures.h =================================================================== diff -u --- firmware/App/Monitors/Pressures.h (revision 0) +++ firmware/App/Monitors/Pressures.h (revision a91074d04b607deabe4fbf714d40e9d191590359) @@ -0,0 +1,95 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 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 Pressures.h +* +* @author (last) Sean +* @date (last) 23-Sep-2024 +* +* @author (original) Sean +* @date (original) 23-Sep-2024 +* +***************************************************************************/ + +#ifndef __PRESSURES_H__ +#define __PRESSURES_H__ + +#include "TDCommon.h" +#include "PressureSensor.h" + +/** + * @defgroup Pressures Pressures + * @brief The pressures monitor unit. Monitors the arterial and venous pressure + * sensors and manages the alarm windows for pressure range during treatment. + * + * @addtogroup Pressures + * @{ + */ + +// ********** public definitions ********** + +/// Enumeration of pressure stabilization periods. +typedef enum StabilizationPeriods +{ + STABILIZATION_PERIOD_OFF = 0, ///< Stabilization period off - 0 seconds + USE_SHORT_STABILIZATION_PERIOD, ///< Short stabilization period for air pump event - 10 seconds + USE_NORMAL_STABILIZATION_PERIOD, ///< Normal Stabilization period for system events, excluding airpump events ( treatment param change, resume treatment etc.,) - 60 seconds + NUM_OF_STABILIZATION_PERIODS ///< Number of stabilization periods +} STABILIZATION_PERIODS_T; + +/// Enumeration of arterial/venous pressure limits states. +typedef enum PressureLimitsStates +{ + PRESSURE_LIMITS_STATE_OFF = 0, ///< Off - not pressure low/high alarms will be detected) + PRESSURE_LIMITS_STATE_IDLE, ///< Idle - in Treatment mode state where BP is stopped - no pressure low/high alarms + PRESSURE_LIMITS_STATE_WIDE, ///< Wide - in Treatment mode state where BP is running but wide limits apply + PRESSURE_LIMITS_STATE_STABILIZATION, ///< Stabilization - in Treatment mode state where BP is running (dialysis or stop), but need to stabilize first + PRESSURE_LIMITS_STATE_STABILIZATION_2, ///< Second stage stabilization - re adjust the pressure that has been drifted due to UF control etc and limit windows apply + PRESSURE_LIMITS_STATE_STABLE, ///< Stable - in Treatment mode state where BP is running (dialysis or stop) and limit windows apply + NUM_OF_PRESSURE_LIMITS_STATES ///< Number of pressure limits states +} PRESSURE_LIMITS_STATES_T; + +/// Payload record structure for the pressure data message. +typedef struct +{ + F32 arterialPressure; ///< Latest arterial pressure (mmHg) + F32 venousPressure; ///< Latest venous pressure (mmHg) + U32 presLimitState; ///< Current pressure limits state (enum-stabilization or stable) + S32 artMinLimit; ///< Current arterial minimum pressure limit (mmHg) + S32 artMaxLimit; ///< Current arterial maximum pressure limit (mmHg) + S32 venMinLimit; ///< Current venous minimum pressure limit (mmHg) + S32 venMaxLimit; ///< Current venous maximum pressure limit (mmHg) + F32 arterialLongFilterPres; ///< Latest long filtered arterial pressure (mmHg) + F32 venousLongFilterPres; ///< Latest long filtered venous pressure (mmHg) +} PRESSURE_DATA_T; + +// ********** public function prototypes ********** + +void initPressure( void ); +void execPressure( void ); + +void execPressureTest( void ); +SELF_TEST_STATUS_T execPressurePOSTSelfTest( void ); + +void resetArtVenPressureOffsets( void ); +void setArtVenPressureOffsets( void ); + +void setPressureLimitsToOuterBounds( void ); +void updatePressureLimitWindows( void ); +void signalInitiatePressureStabilization( STABILIZATION_PERIODS_T stabilizationPeriod ); +void signalLowVenousPressureCheck( void ); + +F32 getFilteredArterialPressure( void ); +F32 getLongFilteredArterialPressure( void ); +F32 getFilteredVenousPressure( void ); +F32 getLongFilteredVenousPressure( void ); + +BOOL testPressuresDataPublishIntervalOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r3a8cf075eb6f0d255f516ac26bac7fbaacfde14a -ra91074d04b607deabe4fbf714d40e9d191590359 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 3a8cf075eb6f0d255f516ac26bac7fbaacfde14a) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision a91074d04b607deabe4fbf714d40e9d191590359) @@ -120,6 +120,8 @@ SW_FAULT_ID_TD_INVALID_SWITCH_ID = 89, SW_FAULT_ID_BUTTONS_INVALID_SELF_TEST_STATE = 90, SW_FAULT_ID_BUTTONS_STOP_BUTTON_NOT_CONSUMED = 91, + SW_FAULT_ID_PRES_OCCL_INVALID_STATE = 92, + SW_FAULT_ID_PRES_LIMITS_INVALID_STATE = 93, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/Messaging.c =================================================================== diff -u -ra0d405d152c0f451ebf3c25e3c2cfa49a4db17cd -ra91074d04b607deabe4fbf714d40e9d191590359 --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision a0d405d152c0f451ebf3c25e3c2cfa49a4db17cd) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision a91074d04b607deabe4fbf714d40e9d191590359) @@ -80,6 +80,7 @@ MSG_ID_TD_VOLTAGE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, MSG_ID_TD_VOLTAGE_OVERRIDE_REQUEST, MSG_ID_TD_PRESSURE_OVERRIDE_REQUEST, + MSG_ID_TD_PRESSURE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, MSG_ID_TD_AIR_PUMP_SET_STATE_REQUEST, MSG_ID_TD_AIR_PUMP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, MSG_ID_TD_SWITCHES_PUBLISH_INTERVAL_OVERRIDE_REQUEST, @@ -102,6 +103,7 @@ &testVoltageDataPublishIntervalOverride, &testVoltageOverride, &testPressureSensorOverride, + &testSwitchesDataPublishIntervalOverride, &testSetAirPump, &testAirPumpDataPublishIntervalOverride, &testSwitchesDataPublishIntervalOverride,