/************************************************************************** * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file PresOccl.c * * @author (last) Sean Nash * @date (last) 24-Sep-2020 * * @author (original) Sean * @date (original) 15-Jan-2020 * ***************************************************************************/ #include "PresOccl.h" #include "AlarmMgmt.h" #include "FPGA.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Temperatures.h" #include "Timers.h" /** * @addtogroup PressureOcclusion * @{ */ // ********** private definitions ********** /// Default publication interval for pressure and occlusion data. #define PRES_OCCL_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the pressure/occlusion data is published on the CAN bus. #define 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 PSI). #define VENOUS_PRESSURE_MAX ( 30.0 ) ///< Maximum of scale for venous pressure sensor reading (in PSI). #define ARTERIAL_PRESSURE_SELF_TEST_MIN ( -300.0 ) ///< Minimum self-test value for arterial pressure sensor reading (in mmHg). #define ARTERIAL_PRESSURE_SELF_TEST_MAX ( 100.0 ) ///< Maximum self-test value for arterial pressure sensor reading (in mmHg). #define VENOUS_PRESSURE_SELF_TEST_MIN ( -100.0 ) ///< Minimum self-test value for venous pressure sensor reading (in mmHg). #define VENOUS_PRESSURE_SELF_TEST_MAX ( 600.0 ) ///< Maximum self-test value for venous pressure sensor reading (in mmHg). #define VENOUS_PRESSURE_MIN_TEMP ( 0.0 ) ///< Minimum venous pressure sensor temperature. TODO - get from Systems #define VENOUS_PRESSURE_MAX_TEMP ( 50.0 ) ///< Maximum venous pressure sensor temperature. TODO - get from Systems #define PSI_TO_MMHG ( 51.7149 ) ///< 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). #define OCCLUSION_THRESHOLD 25000 ///< Threshold above which an occlusion is detected. #define CARTRIDGE_LOADED_THRESHOLD 5000 ///< Threshold above which a cartridge is considered loaded. #define EMPTY_SALINE_BAG_THRESHOLD_MMHG -300.0 ///< 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. /// Occlusion sensors minimum pressure reading limit when no cartridge is loaded. #define OCCLUSION_NO_CARTRIDGE_PRESSURE_READING_MIN 2000 /// Occlusion sensors maximum pressure reading limit when cartridge is considered loaded. #define OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX 20000 #define PRES_ALARM_PERSISTENCE ( 1 * MS_PER_SECOND ) ///< Alarm persistence period for pressure alarms. /// 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_STATE_T; /// Defined states for the pressure and occlusion self-test state machine. typedef enum PresOccl_Self_Test_States { PRESSURE_SELF_TEST_STATE_START = 0, ///< Self test start state. PRESSURE_TEST_STATE_IN_PROGRESS, ///< Self test in progress state. PRESSURE_TEST_STATE_COMPLETE, ///< Self test completed state. NUM_OF_PRESSURE_SELF_TEST_STATES ///< Number of pressure/occlusion self-test states. } PRESSURE_SELF_TEST_STATE_T; // ********** private data ********** static PRESSURE_STATE_T presOcclState = PRESSURE_INIT_STATE; ///< Current state of pressure monitor state machine. static U32 presOcclDataPublicationTimerCounter = 0; ///< Used to schedule pressure data publication to CAN bus. /// Interval (in ms) at which to publish pressure/occlusion data to CAN bus. static OVERRIDE_U32_T presOcclDataPublishInterval = { PRES_OCCL_DATA_PUB_INTERVAL, PRES_OCCL_DATA_PUB_INTERVAL, 0, 0 }; static OVERRIDE_F32_T arterialPressure = {0.0, 0.0, 0.0, 0 }; ///< Measured arterial pressure. static OVERRIDE_F32_T venousPressure = {0.0, 0.0, 0.0, 0 }; ///< Measured venous pressure. static OVERRIDE_U32_T bloodPumpOcclusion = {0, 0, 0, 0 }; ///< Measured blood pump occlusion pressure. static OVERRIDE_U32_T dialInPumpOcclusion = {0, 0, 0, 0 }; ///< Measured dialysate inlet pump occlusion pressure. static OVERRIDE_U32_T dialOutPumpOcclusion = {0, 0, 0, 0 }; ///< Measured dialysate outlet pump occlusion pressure. static U32 emptySalineBagCtr = 0; ///< Timer counter for empty bag detection. static U08 lastVenousPressureReadCtr; ///< Previous venous pressure read count. static U08 lastBPOcclReadCtr; ///< Previous BP occlusion read count. static U08 lastDPiOcclReadCtr; ///< Previous DPi occlusion read count. static U08 lastDPoOcclReadCtr; ///< Previous DPo occlusion read count. static U08 lastBPErrorCtr; ///< Previous BP error count. static U08 lastDPIErrorCtr; ///< Previous DPi error count. static U08 lastDPOErrorCtr; ///< Previous DPo error count. // ********** private function prototypes ********** 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 U32 getPublishPresOcclDataInterval( void ); /*********************************************************************//** * @brief * The initPresOccl function initializes the PresOccl module. * @details Inputs: none * @details Outputs: PresOccl module initialized. * @return none *************************************************************************/ void initPresOccl( void ) { // Initialize persistent pressure alarms initPersistentAlarm( ALARM_ID_ARTERIAL_PRESSURE_LOW, PRES_ALARM_PERSISTENCE, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_ARTERIAL_PRESSURE_HIGH, PRES_ALARM_PERSISTENCE, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_VENOUS_PRESSURE_LOW, PRES_ALARM_PERSISTENCE, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_VENOUS_PRESSURE_HIGH, PRES_ALARM_PERSISTENCE, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_VENOUS_PRESSURE_READ_TIMEOUT_ERROR, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_VENOUS_PRESSURE_SENSOR_TEMP_OUT_OF_RANGE, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_DPI_OCCLUSON_READ_TIMEOUT_ERROR, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_DPO_OCCLUSION_READ_TIMEOUT_ERROR, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_BP_OCCLUSION_SENSOR_ERROR, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_DPI_OCCLUSION_SENSOR_ERROR, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_DPO_OCCLUSION_SENSOR_ERROR, 0, PRES_ALARM_PERSISTENCE ); lastVenousPressureReadCtr = 0; lastBPOcclReadCtr = 0; lastDPiOcclReadCtr = 0; lastDPoOcclReadCtr = 0; lastBPErrorCtr = 0; lastDPIErrorCtr = 0; lastDPOErrorCtr = 0; } /*********************************************************************//** * @brief * The isCartridgeLoaded function determines whether a cartridge has been * properly loaded by looking at the 3 occlusion pressure sensors. * @details Inputs: occlusion pressures for the pumps * @details Outputs: none * @return TRUE if all 3 occlusion sensors read above loaded threshold, FALSE if not. *************************************************************************/ BOOL isCartridgeLoaded( void ) { BOOL result = FALSE; U32 bpOccl = getMeasuredBloodPumpOcclusion(); U32 diOccl = getMeasuredDialInPumpOcclusion(); U32 doOccl = getMeasuredDialOutPumpOcclusion(); if ( ( bpOccl >= CARTRIDGE_LOADED_THRESHOLD ) && ( diOccl >= CARTRIDGE_LOADED_THRESHOLD ) && ( doOccl >= CARTRIDGE_LOADED_THRESHOLD ) ) { result = TRUE; } return result; } /*********************************************************************//** * @brief * The isCartridgeUnloaded function determines if a cartridge has been * unloaded by looking at the 3 occlusion pressure sensors. * @details Inputs: occlusion pressures for the pumps * @details Outputs: none * @return TRUE if all 3 occlusion sensors read below loaded threshold, FALSE if not. *************************************************************************/ BOOL isCartridgeUnloaded( void ) { BOOL const bpOcclBelowLoadedThreshold = getMeasuredBloodPumpOcclusion() <= CARTRIDGE_LOADED_THRESHOLD; BOOL const diOcclBelowLoadedThreshold = getMeasuredDialInPumpOcclusion() <= CARTRIDGE_LOADED_THRESHOLD; BOOL const doOcclBelowLoadedThreshold = getMeasuredDialOutPumpOcclusion() <= CARTRIDGE_LOADED_THRESHOLD; return ( bpOcclBelowLoadedThreshold && diOcclBelowLoadedThreshold && doOcclBelowLoadedThreshold ); } /*********************************************************************//** * @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 execPresOccl function executes the pressure and occlusion monitor. * @details Inputs: presOcclState * @details Outputs: presOcclState * @return none *************************************************************************/ void execPresOccl( void ) { // State machine switch ( presOcclState ) { case PRESSURE_INIT_STATE: presOcclState = PRESSURE_CONTINUOUS_READ_STATE; break; case PRESSURE_CONTINUOUS_READ_STATE: presOcclState = handlePresOcclContReadState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_PRES_OCCL_INVALID_STATE, presOcclState ) break; } // Publish pressure/occlusion data on interval publishPresOcclData(); } /*********************************************************************//** * @brief * The handlePresOcclContReadState function handles the continuous read state * of the pressure/occlusion monitor state machine. * @details Inputs: FPGA pressure/occlusion readings * @details Outputs: pressure sensor values updated * @return next state *************************************************************************/ static PRESSURE_STATE_T handlePresOcclContReadState( void ) { PRESSURE_STATE_T result = PRESSURE_CONTINUOUS_READ_STATE; // Read latest in-line (arterial and venous) pressures convertInlinePressures(); // Read latest occlusion pressures convertOcclusionPressures(); // 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 ) { U32 fpgaArtPres = getFPGAArterialPressure(); S32 artPres = (S32)( fpgaArtPres & MASK_OFF_U32_MSB ) - 0x800000; // Subtract 2^23 from low 24 bits to get signed reading U08 artPresAlarm = (U08)( fpgaArtPres >> SHIFT_24_BITS ); // High byte is alarm code for arterial pressure U16 fpgaVenPres = getFPGAVenousPressure(); U16 venPres = fpgaVenPres & 0x3FFF; // 14-bit data U08 venPresStatus = (U08)( fpgaVenPres >> 14 ); // High 2 bits is status code for venous pressure F32 venPresPSI; F32 venTemp = getTemperatureValue( TEMPSENSOR_VENOUS_PRESSURE_SENSOR ); U08 venReadCtr = getFPGAVenousPressureReadCounter(); // TODO - any filtering required??? // Convert arterial pressure to mmHg if no fault if ( 0 == artPresAlarm ) { arterialPressure.data = ARTERIAL_PRESSURE_V_PER_BIT * ( (F32)(artPres) / ( ARTERIAL_PRESSURE_SENSITIVITY * ARTERIAL_PRESSURE_V_BIAS ) ); } else { #ifndef DISABLE_PRESSURE_CHECKS SET_ALARM_WITH_1_U32_DATA( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT, (U32)artPresAlarm ) #endif } // 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 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 - VENOUS_PRESSURE_MIN) / (F32)VENOUS_PRESSURE_SCALE ) + VENOUS_PRESSURE_MIN; // 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 else { #ifndef DISABLE_PRESSURE_CHECKS // SET_ALARM_WITH_1_U32_DATA( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, (U32)venPresStatus ) // TODO - persistence? YES, need persistence - getting a stale data status. OR maybe speed up ADC in FPGA. #endif } // Check venous pressure sensor temperature if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_SENSOR_TEMP_OUT_OF_RANGE, ( venTemp > VENOUS_PRESSURE_MAX_TEMP || venTemp < VENOUS_PRESSURE_MIN_TEMP ) ) ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, venTemp ) } } /*********************************************************************//** * @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 dpiReadCtr = getFPGADialInPumpOcclusionReadCounter(); U08 dpoReadCtr = getFPGADialOutPumpOcclusionReadCounter(); U08 bpErrorCtr = getFPGABloodPumpOcclusionErrorCounter(); U08 dpiErrorCtr = getFPGADialInPumpOcclusionErrorCounter(); U08 dpoErrorCtr = getFPGADialOutPumpOcclusionErrorCounter(); #ifndef DISABLE_PRESSURE_CHECKS // 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 ) } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_DPI_OCCLUSION_SENSOR_ERROR, ( dpiErrorCtr != lastDPIErrorCtr ) ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DPI_OCCLUSION_SENSOR_ERROR, (U32)dpiErrorCtr ) } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_DPO_OCCLUSION_SENSOR_ERROR, ( dpoErrorCtr != lastDPOErrorCtr ) ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DPO_OCCLUSION_SENSOR_ERROR, (U32)dpoErrorCtr ) } // 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 ); } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR, ( dpiReadCtr == lastDPiOcclReadCtr ) ) ) { activateAlarmNoData( ALARM_ID_HD_DPI_OCCLUSON_READ_TIMEOUT_ERROR ); } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR, ( dpoReadCtr == lastDPoOcclReadCtr ) ) ) { activateAlarmNoData( ALARM_ID_HD_DPO_OCCLUSION_READ_TIMEOUT_ERROR ); } #endif // Record occlusion sensor readings bloodPumpOcclusion.data = (U32)getFPGABloodPumpOcclusion(); dialInPumpOcclusion.data = (U32)getFPGADialInPumpOcclusion(); dialOutPumpOcclusion.data = (U32)getFPGADialOutPumpOcclusion(); // Record occlusion read and error counters for next time around lastBPOcclReadCtr = bpReadCtr; lastDPiOcclReadCtr = dpiReadCtr; lastDPoOcclReadCtr = dpoReadCtr; lastBPErrorCtr = bpErrorCtr; lastDPIErrorCtr = dpiErrorCtr; lastDPOErrorCtr = dpoErrorCtr; } /*********************************************************************//** * @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 = getMeasuredArterialPressure(); // Check arterial pressure during treatment mode if ( MODE_TREA == getCurrentOperationMode() ) { F32 artLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ); F32 artHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); #ifndef DISABLE_PRESSURE_CHECKS 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 == isPersistentAlarmConditionCleared( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres < artLowLimit ) ) { clearAlarmCondition( ALARM_ID_ARTERIAL_PRESSURE_LOW ); } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres > artHighLimit ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres, artHighLimit ); } if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres > artHighLimit ) ) { clearAlarmCondition( ALARM_ID_ARTERIAL_PRESSURE_HIGH ); } #endif } } /*********************************************************************//** * @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 = getMeasuredVenousPressure(); // Check arterial pressure during treatment mode if ( MODE_TREA == getCurrentOperationMode() ) { F32 venLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ); F32 venHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); #ifndef DISABLE_PRESSURE_CHECKS if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, venPres < venLowLimit ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_LOW, venPres, venLowLimit ); } if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_VENOUS_PRESSURE_LOW, venPres < venLowLimit ) ) { clearAlarmCondition( ALARM_ID_VENOUS_PRESSURE_LOW ); } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres > venHighLimit ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres, venHighLimit ); } if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres > venHighLimit ) ) { clearAlarmCondition( ALARM_ID_VENOUS_PRESSURE_HIGH ); } #endif } } /*********************************************************************//** * @brief * The checkPressureLimits function gets the pressure/occlusion data * publication interval. * @details Inputs: occlusion pressures for the pumps * @details Outputs: Alarm if occlusion limit exceeded * @return none *************************************************************************/ static void checkOcclusions( void ) { U32 bpOccl = getMeasuredBloodPumpOcclusion(); U32 diOccl = getMeasuredDialInPumpOcclusion(); U32 doOccl = getMeasuredDialOutPumpOcclusion(); #ifndef DISABLE_PRESSURE_CHECKS if ( bpOccl > OCCLUSION_THRESHOLD ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_OCCLUSION_BLOOD_PUMP, bpOccl ) // TODO - stop blood pump immediately, ... } if ( diOccl > OCCLUSION_THRESHOLD ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_OCCLUSION_DIAL_IN_PUMP, diOccl ) // TODO - stop dialysate inlet pump immediately, ... } if ( doOccl > OCCLUSION_THRESHOLD ) { SET_ALARM_WITH_1_U32_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 * @details Outputs: none * @return the current pressure/occlusion data publication interval (in task intervals). *************************************************************************/ static U32 getPublishPresOcclDataInterval( void ) { U32 result = presOcclDataPublishInterval.data; if ( OVERRIDE_KEY == presOcclDataPublishInterval.override ) { result = presOcclDataPublishInterval.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredArterialPressure function gets the current arterial pressure. * @details Inputs: arterialPressure * @details Outputs: none * @return the current arterial pressure (in mmHg). *************************************************************************/ F32 getMeasuredArterialPressure( void ) { F32 result = arterialPressure.data; if ( OVERRIDE_KEY == arterialPressure.override ) { result = arterialPressure.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredVenousPressure function gets the measured venous pressure. * @details Inputs: venousPressure * @details Outputs: none * @return the current venous pressure (in mmHg). *************************************************************************/ F32 getMeasuredVenousPressure( void ) { F32 result = venousPressure.data; if ( OVERRIDE_KEY == venousPressure.override ) { result = venousPressure.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredBloodPumpOcclusion function gets the measured blood pump * occlusion pressure. * @details Inputs: bloodPumpOcclusion * @details Outputs: none * @return the current blood pump occlusion pressure (in mmHg). *************************************************************************/ U32 getMeasuredBloodPumpOcclusion( void ) { U32 result = bloodPumpOcclusion.data; if ( OVERRIDE_KEY == bloodPumpOcclusion.override ) { result = bloodPumpOcclusion.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredDialInPumpOcclusion function gets the measured dialysate * inlet pump occlusion pressure. * @details Inputs: dialInPumpOcclusion * @details Outputs: none * @return the current dialysis inlet pump occlusion pressure (in mmHg). *************************************************************************/ U32 getMeasuredDialInPumpOcclusion( void ) { U32 result = dialInPumpOcclusion.data; if ( OVERRIDE_KEY == dialInPumpOcclusion.override ) { result = dialInPumpOcclusion.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredDialOutPumpOcclusion function gets the measured dialysate * outlet pump occlusion pressure. * @details Inputs: dialOutPumpOcclusion * @details Outputs: none * @return the current dialysis outlet pump occlusion pressure (in mmHg). *************************************************************************/ U32 getMeasuredDialOutPumpOcclusion( void ) { U32 result = dialOutPumpOcclusion.data; if ( OVERRIDE_KEY == dialOutPumpOcclusion.override ) { result = dialOutPumpOcclusion.ovData; } return result; } /*********************************************************************//** * @brief * The publishPresOcclData function publishes pressure/occlusion data at the * set interval. * @details Inputs: latest pressure and occlusion readings * @details Outputs: Pressure/occlusion data are published to CAN bus. * @return none *************************************************************************/ static void publishPresOcclData( void ) { // Publish pressure/occlusion data on interval if ( ++presOcclDataPublicationTimerCounter >= getPublishPresOcclDataInterval() ) { PRESSURE_OCCLUSION_DATA_T data; data.arterialPressure = getMeasuredArterialPressure(); data.venousPressure = getMeasuredVenousPressure(); data.bldPumpOcclusion = getMeasuredBloodPumpOcclusion(); data.diPumpOcclusion = getMeasuredDialInPumpOcclusion(); data.doPumpOcclusion = getMeasuredDialOutPumpOcclusion(); broadcastPresOcclData( data ); presOcclDataPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The execPresOcclTest function executes the PresOccl self-test. * @details Inputs: none * @details Outputs: Triggers fault when test case fails * @return none *************************************************************************/ void execPresOcclTest( void ) { #ifndef DISABLE_PRESSURE_CHECKS U32 const bpPressure = getMeasuredBloodPumpOcclusion(); U32 const dialysateInPressure = getMeasuredDialInPumpOcclusion(); U32 const dialysateOutPressure = getMeasuredDialOutPumpOcclusion(); F32 const arterialPressure = getMeasuredArterialPressure(); F32 const venousPressure = getMeasuredVenousPressure(); if ( ( bpPressure <= OCCLUSION_NO_CARTRIDGE_PRESSURE_READING_MIN ) || ( bpPressure >= OCCLUSION_THRESHOLD ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_SELF_TEST_FAILURE, bpPressure ); } if ( ( dialysateInPressure <= OCCLUSION_NO_CARTRIDGE_PRESSURE_READING_MIN ) || ( dialysateInPressure >= OCCLUSION_THRESHOLD ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DIP_OCCLUSION_SELF_TEST_FAILURE, dialysateInPressure ); } if ( ( dialysateOutPressure <= OCCLUSION_NO_CARTRIDGE_PRESSURE_READING_MIN ) || ( dialysateOutPressure >= OCCLUSION_THRESHOLD ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DOP_OCCLUSION_SELF_TEST_FAILURE, dialysateOutPressure ); } 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 ); } #endif } /*********************************************************************//** * @brief * The execPresOcclDryTest function executes the PresOccl dry self-test. * @details Inputs: none * @details Outputs: none * @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 DISABLE_OCCLUSION_SELF_TEST U32 const bpPressure = getMeasuredBloodPumpOcclusion(); U32 const dialysateInPressure = getMeasuredDialInPumpOcclusion(); U32 const dialysateOutPressure = getMeasuredDialOutPumpOcclusion(); if ( ( bpPressure <= CARTRIDGE_LOADED_THRESHOLD ) || ( bpPressure >= OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX ) ) { result = SELF_TEST_STATUS_FAILED; } if ( ( dialysateInPressure <= CARTRIDGE_LOADED_THRESHOLD ) || ( dialysateInPressure >= OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX ) ) { result = SELF_TEST_STATUS_FAILED; } if ( ( dialysateOutPressure <= CARTRIDGE_LOADED_THRESHOLD ) || ( dialysateOutPressure >= OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX ) ) { result = SELF_TEST_STATUS_FAILED; } if ( SELF_TEST_STATUS_FAILED == result ) { if ( ( bpPressure <= CARTRIDGE_LOADED_THRESHOLD ) && ( dialysateInPressure <= CARTRIDGE_LOADED_THRESHOLD ) && ( dialysateOutPressure <= CARTRIDGE_LOADED_THRESHOLD ) ) { activateAlarmNoData( ALARM_ID_NO_CARTRIDGE_LOADED ); } else { activateAlarmNoData( ALARM_ID_CARTRIDGE_INSTALLED_IMPROPERLY ); } } #endif return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetPresOcclDataPublishIntervalOverride function overrides the * pressure and occlusion data publish interval. * @details Inputs: none * @details Outputs: presOcclDataPublishInterval * @param value override pressure and occlusion data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetPresOcclDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_GENERAL_INTERVAL; result = TRUE; presOcclDataPublishInterval.ovData = intvl; presOcclDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetPresOcclDataPublishIntervalOverride function resets the override * of the pressure and occlusion data publish interval. * @details Inputs: none * @details Outputs: presOcclDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetPresOcclDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; presOcclDataPublishInterval.override = OVERRIDE_RESET; presOcclDataPublishInterval.ovData = presOcclDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetArterialPressureOverride function overrides the measured arterial * pressure. * @details Inputs: none * @details Outputs: arterialPressure * @param value override arterial pressure (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetArterialPressureOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; arterialPressure.ovData = value; arterialPressure.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetArterialPressureOverride function resets the override of the * arterial pressure. * @details Inputs: none * @details Outputs: arterialPressure * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetArterialPressureOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; arterialPressure.override = OVERRIDE_RESET; arterialPressure.ovData = arterialPressure.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetVenousPressureOverride function overrides the measured venous * pressure. * @details Inputs: none * @details Outputs: venousPressure * @param value override measured venous pressure with (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetVenousPressureOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; venousPressure.ovData = value; venousPressure.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetVenousPressureOverride function resets the override of the * venous pressure. * @details Inputs: none * @details Outputs: venousPressure * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetVenousPressureOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; venousPressure.override = OVERRIDE_RESET; venousPressure.ovData = venousPressure.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetBloodPumpOcclusionOverride function overrides the measured * blood pump occlusion pressure. * @details Inputs: none * @details Outputs: bloodPumpOcclusion * @param value override measured blood pump occlusion pressure with * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBloodPumpOcclusionOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bloodPumpOcclusion.ovData = value; bloodPumpOcclusion.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetBloodPumpOcclusionOverride function resets the override of the * measured blood pump occlusion pressure. * @details Inputs: none * @details Outputs: bloodPumpOcclusion * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetBloodPumpOcclusionOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bloodPumpOcclusion.override = OVERRIDE_RESET; bloodPumpOcclusion.ovData = bloodPumpOcclusion.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetDialInPumpOcclusionOverride function overrides the measured * dialysate inlet pump occlusion pressure.n * @details Inputs: none * @details Outputs: dialInPumpOcclusion * @param value override measured dialysate inlet pump occlusion pressure * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetDialInPumpOcclusionOverride( U32 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 * @details 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 * @details Outputs: dialOutPumpOcclusion * @param value override measured dialysate outlet pump occlusion pressure * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetDialOutPumpOcclusionOverride( U32 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 * @details 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; } /**@}*/