/************************************************************************** * * Copyright (c) 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 BloodFlow.c * * @date 15-Jan-2020 * @author S. Nash * * @brief Monitor for pressure and occlusion sensors. * **************************************************************************/ #include "PresOccl.h" #include "AlarmMgmt.h" #include "FPGA.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" // ********** private definitions ********** #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 typedef enum PresOccl_States { PRESSURE_INIT_STATE = 0, PRESSURE_CONTINUOUS_READ_STATE, NUM_OF_PRESSURE_STATES } PRESSURE_STATE_T; typedef enum PresOccl_Self_Test_States { PRESSURE_SELF_TEST_STATE_START = 0, PRESSURE_TEST_STATE_IN_PROGRESS, PRESSURE_FLOW_TEST_STATE_COMPLETE, NUM_OF_PRESSURE_SELF_TEST_STATES } PRESSURE_SELF_TEST_STATE_T; // ********** private data ********** static PRESSURE_STATE_T presOcclState = PRESSURE_INIT_STATE; // current state of blood flow controller state machine static U32 presOcclDataPublicationTimerCounter = 0; // used to schedule blood flow data publication to CAN bus DATA_DECL( U32, PresOcclDataPub, presOcclDataPublishInterval, PRES_OCCL_DATA_PUB_INTERVAL, PRES_OCCL_DATA_PUB_INTERVAL ); // interval (in ms) at which to publish pressure/occlusion data to CAN bus DATA_DECL( F32, ArterialPressure, arterialPressure, 0, 0 ); // requested blood flow rate DATA_DECL( F32, VenousPressure, venousPressure, 0.0, 0.0 ); // measured blood flow rate DATA_DECL( F32, BloodPumpOcclusion, bloodPumpOcclusion, 0.0, 0.0 ); // measured blood pump rotor speed DATA_DECL( F32, DialInPumpOcclusion, dialInPumpOcclusion, 0.0, 0.0 ); // measured blood pump motor speed DATA_DECL( F32, DialOutPumpOcclusion, dialOutPumpOcclusion, 0.0, 0.0 ); // measured blood pump motor controller speed static PRESSURE_SELF_TEST_STATE_T presOcclSelfTestState = PRESSURE_SELF_TEST_STATE_START; // current blood pump self test state static U32 bloodPumpSelfTestTimerCount = 0; // timer counter for blood pump self test static F32 arterialPressureLowLimitmmHG = 0.0; // lower alarm limit for arterial pressure static F32 arterialPressureHighLimitmmHG = 0.0; // upper alarm limit for arterial pressure static F32 venousPressureLowLimitmmHG = 0.0; // lower alarm limit for venous pressure static F32 venousPressureHighLimitmmHG = 0.0; // upper alarm limit for venous pressure static F32 bloodPumpOcclusionPressureThresholdmmHG = 50.0; // pressure threshold for blood pump occlusion // TODO - set thresholds for occlusions static F32 dialInPumpOcclusionPressureThresholdmmHG = 50.0; // pressure threshold for dialysate inlet pump occlusion static F32 dialOutPumpOcclusionPressureThresholdmmHG = 50.0; // pressure threshold for dialysate outlet pump occlusion // ********** private function prototypes ********** static PRESSURE_STATE_T handlePresOcclInitState( void ); static PRESSURE_STATE_T handlePresOcclContReadState( void ); static void checkOcclusions( void ); static void publishPresOcclData( void ); static DATA_GET_PROTOTYPE( U32, getPublishPresOcclDataInterval ); /************************************************************************* * @brief initPresOccl * The initPresOccl function initializes the initPresOccl module. * @details * Inputs : none * Outputs : initPresOccl module initialized. * @param none * @return none *************************************************************************/ void initPresOccl( void ) { // TODO - anything to initialize? } /************************************************************************* * @brief setPressureLimits * The setPressureLimits function sets the lower and upper alarm limits \n * for a given pressure sensor. * @details * Inputs : none * Outputs : pressure limits * @param sensor : pressure sensor we are setting limits for * @param low : lower alarm limit (mmHg) * @param high : upper alarm limit (mmHg) * @return none *************************************************************************/ void setPressureLimits( PRESSURE_SENSORS_T sensor, F32 low, F32 high ) { switch ( sensor ) // TODO - will low/high limits be range checked by caller or should we do it here? what are valid ranges? { case PRESSURE_SENSOR_ARTERIAL: arterialPressureLowLimitmmHG = low; arterialPressureHighLimitmmHG = high; break; case PRESSURE_SENSOR_VENOUS: venousPressureLowLimitmmHG = low; venousPressureHighLimitmmHG = high; break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_PRES_OCCL_INVALID_PRES_SENSOR, sensor ) break; } } /************************************************************************* * @brief setOcclusionThreshold * The setOcclusionThreshold function sets the occlusion pressure threshold \n * for a given occlusion sensor. * @details * Inputs : none * Outputs : pressure threshold * @param sensor : occlusion sensor we are setting threshold for * @param threshold : pressure threshold above which indicates an occlusion (mmHg) * @return none *************************************************************************/ void setOcclusionThreshold( OCCLUSION_SENSORS_T sensor, F32 threshold ) { switch ( sensor ) // TODO - will threshold be range checked by caller or should we do it here? what is valid range? { case OCCLUSION_SENSOR_BLOOD_PUMP: bloodPumpOcclusionPressureThresholdmmHG = threshold; break; case OCCLUSION_SENSOR_DIAL_IN_PUMP: dialInPumpOcclusionPressureThresholdmmHG = threshold; break; case OCCLUSION_SENSOR_DIAL_OUT_PUMP: dialOutPumpOcclusionPressureThresholdmmHG = threshold; break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_PRES_OCCL_INVALID_OCCL_SENSOR, sensor ) break; } } /************************************************************************* * @brief execPresOccl * The execPresOccl function executes the pressure and occlusion monitor. * @details * Inputs : presOcclState * Outputs : presOcclState * @param none * @return none *************************************************************************/ void execPresOccl( void ) { // state machine switch ( presOcclState ) { case PRESSURE_INIT_STATE: presOcclState = handlePresOcclInitState(); break; case PRESSURE_CONTINUOUS_READ_STATE: presOcclState = handlePresOcclContReadState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_PRES_OCCL_INVALID_STATE, presOcclState ) break; } // publish pressure/occlusion data on interval publishPresOcclData(); } /************************************************************************* * @brief handlePresOcclInitState * The handlePresOcclInitState function handles the pres/occl initialize state \n * of the pressure/occlusion monitor state machine. * @details * Inputs : TBD * Outputs : TBD * @param none * @return next state *************************************************************************/ static PRESSURE_STATE_T handlePresOcclInitState( void ) { PRESSURE_STATE_T result = PRESSURE_CONTINUOUS_READ_STATE; return result; } /************************************************************************* * @brief handlePresOcclContReadState * The handlePresOcclContReadState function handles the continuous read state \n * of the pressure/occlusion monitor state machine. * @details * Inputs : TBD * Outputs : pressure sensor values updated * @param none * @return next state *************************************************************************/ static PRESSURE_STATE_T handlePresOcclContReadState( void ) { PRESSURE_STATE_T result = PRESSURE_CONTINUOUS_READ_STATE; U16 artPres = getFPGAArterialPressure(); U16 venPres = getFPGAVenousPressure(); U16 bldOccl = getFPGABloodPumpOcclusion(); U16 dliOccl = getFPGADialInPumpOcclusion(); U16 dloOccl = getFPGADialOutPumpOcclusion(); // TODO - convert ADC counts to mmHg for each sensor arterialPressure.data = (F32)artPres; venousPressure.data = (F32)venPres; bloodPumpOcclusion.data = (F32)bldOccl; dialInPumpOcclusion.data = (F32)dliOccl; dialOutPumpOcclusion.data = (F32)dloOccl; // TODO - any filtering required??? // check for occlusions checkOcclusions(); // TODO - any other checks return result; } /************************************************************************* * @brief checkPressureLimits * The checkPressureLimits function gets the pressure/occlusion data \n * publication interval. * @details * Inputs : occlusion pressures for the pumps * Outputs : * @param none * @return none *************************************************************************/ static void checkOcclusions( void ) { F32 bpOccl = getMeasuredBloodPumpOcclusion(); F32 diOccl = getMeasuredDialInPumpOcclusion(); F32 doOccl = getMeasuredDialOutPumpOcclusion(); if ( bpOccl > bloodPumpOcclusionPressureThresholdmmHG ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_OCCLUSION_BLOOD_PUMP, bpOccl ) // TODO - stop blood pump immediately, ... } if ( diOccl > dialInPumpOcclusionPressureThresholdmmHG ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_OCCLUSION_DIAL_IN_PUMP, diOccl ) // TODO - stop dialysate inlet pump immediately, ... } if ( doOccl > dialOutPumpOcclusionPressureThresholdmmHG ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_OCCLUSION_DIAL_OUT_PUMP, doOccl ) // TODO - stop dialysate outlet pump immediately, ... } } /************************************************************************* * @brief getPublishPresOcclDataInterval * The getPublishPresOcclDataInterval function gets the pressure/occlusion data \n * publication interval. * @details * Inputs : presOcclDataPublishInterval * Outputs : none * @param none * @return the current pressure/occlusion data publication interval (in ms). *************************************************************************/ DATA_GET( U32, getPublishPresOcclDataInterval, presOcclDataPublishInterval ) /************************************************************************* * @brief getMeasuredArterialPressure * The getMeasuredArterialPressure function gets the current arterial pressure. * @details * Inputs : arterialPressure * Outputs : none * @param none * @return the current arterial pressure (in mmHg). *************************************************************************/ DATA_GET( F32, getMeasuredArterialPressure, arterialPressure ) /************************************************************************* * @brief getMeasuredVenousPressure * The getMeasuredVenousPressure function gets the measured venous pressure. * @details * Inputs : venousPressure * Outputs : none * @param none * @return the current venous pressure (in mmHg). *************************************************************************/ DATA_GET( F32, getMeasuredVenousPressure, venousPressure ) /************************************************************************* * @brief getMeasuredBloodPumpOcclusion * The getMeasuredBloodPumpOcclusion function gets the measured blood pump \n * occlusion pressure. * @details * Inputs : bloodPumpOcclusion * Outputs : none * @param none * @return the current blood pump occlusion pressure (in mmHg). *************************************************************************/ DATA_GET( F32, getMeasuredBloodPumpOcclusion, bloodPumpOcclusion ) /************************************************************************* * @brief getMeasuredDialInPumpOcclusion * The getMeasuredDialInPumpOcclusion function gets the measured dialysate \n * inlet pump occlusion pressure. * @details * Inputs : dialInPumpOcclusion * Outputs : none * @param none * @return the current dialysis inlet pump occlusion pressure (in mmHg). *************************************************************************/ DATA_GET( F32, getMeasuredDialInPumpOcclusion, dialInPumpOcclusion ) /************************************************************************* * @brief getMeasuredDialOutPumpOcclusion * The getMeasuredDialOutPumpOcclusion function gets the measured dialysate \n * outlet pump occlusion pressure. * @details * Inputs : dialOutPumpOcclusion * Outputs : none * @param none * @return the current dialysis outlet pump occlusion pressure (in mmHg). *************************************************************************/ DATA_GET( F32, getMeasuredDialOutPumpOcclusion, dialOutPumpOcclusion ) /************************************************************************* * @brief publishPresOcclData * The publishPresOcclData function publishes pressure/occlusion data at the \n * set interval. * @details * Inputs : TBD * Outputs : Pressure/occlusion data are published to CAN bus. * @param none * @return none *************************************************************************/ static void publishPresOcclData( void ) { // publish pressure/occlusion data on interval if ( ++presOcclDataPublicationTimerCounter > getPublishPresOcclDataInterval() ) { F32 artPres = getMeasuredArterialPressure(); F32 venPres = getMeasuredVenousPressure(); F32 bpOccl = getMeasuredBloodPumpOcclusion(); F32 diOccl = getMeasuredDialInPumpOcclusion(); F32 doOccl = getMeasuredDialOutPumpOcclusion(); broadcastPresOcclData( artPres, venPres, bpOccl, diOccl, doOccl ); presOcclDataPublicationTimerCounter = 0; } } /************************************************************************* * @brief execPresOcclTest * The execPresOcclTest function executes the state machine for the \n * PresOccl self test. * @details * Inputs : none * Outputs : none * @param none * @return the current state of the PresOccl self test. *************************************************************************/ SELF_TEST_STATUS_T execPresOcclTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; // TODO - implement self test(s) return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /************************************************************************* * @brief testSetPresOcclDataPublishIntervalOverride * The testSetPresOcclDataPublishIntervalOverride function overrides the \n * pressure and occlusion data publish interval. * @details * Inputs : none * 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 testResetPresOcclDataPublishIntervalOverride * The testResetPresOcclDataPublishIntervalOverride function resets the override \n * of the pressure and occlusion data publish interval. * @details * Inputs : none * 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 testSetArterialPressureOverride and testResetArterialPressureOverride * The testSetArterialPressureOverride function overrides the measured arterial \n * pressure. * The testResetArterialPressureOverride function resets the override of the \n * arterial pressure. * @details * Inputs : none * Outputs : arterialPressure * @param value : override arterial pressure (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ DATA_OVERRIDE_FUNC( F32, testSetArterialPressureOverride, testResetArterialPressureOverride, arterialPressure ) /************************************************************************* * @brief testSetVenousPressureOverride and testResetVenousPressureOverride * The testSetVenousPressureOverride function overrides the measured venous \n * pressure. * The testResetVenousPressureOverride function resets the override of the \n * venous pressure. * @details * Inputs : none * Outputs : venousPressure * @param value : override measured vensous pressure with (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ DATA_OVERRIDE_FUNC( F32, testSetVenousPressureOverride, testResetVenousPressureOverride, venousPressure ) /************************************************************************* * @brief testSetBloodPumpOcclusionOverride and testResetBloodPumpOcclusionOverride * The testSetBloodPumpOcclusionOverride function overrides the measured \n * blood pump occlusion pressure. \n * The testResetBloodPumpOcclusionOverride function resets the override of the \n * measured blood pump occlusion pressure. * @details * Inputs : none * Outputs : bloodPumpOcclusion * @param value : override measured blood pump occlusion pressure with (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ DATA_OVERRIDE_FUNC( F32, testSetBloodPumpOcclusionOverride, testResetBloodPumpOcclusionOverride, bloodPumpOcclusion ) /************************************************************************* * @brief testSetDialInPumpOcclusionOverride and testResetDialInPumpOcclusionOverride * The testSetDialInPumpOcclusionOverride function overrides the measured \n * dialysate inlet pump occlusion pressure. \n * The testResetDialInPumpOcclusionOverride function resets the override of the \n * measured dialysate inlet pump occlusion pressure. * @details * Inputs : none * Outputs : dialInPumpOcclusion * @param value : override measured dialysate inlet pump occlusion pressure (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ DATA_OVERRIDE_FUNC( F32, testSetDialInPumpOcclusionOverride, testResetDialInPumpOcclusionOverride, dialInPumpOcclusion ) /************************************************************************* * @brief testSetDialOutPumpOcclusionOverride and testResetDialOutPumpOcclusionOverride * The testSetDialOutPumpOcclusionOverride function overrides the measured \n * dialysate outlet pump occlusion pressure. \n * The testResetDialOutPumpOcclusionOverride function resets the override of the \n * measured dialysate outlet pump occlusion pressure. * @details * Inputs : none * Outputs : dialOutPumpOcclusion * @param value : override measured dialysate outlet pump occlusion pressure (in mmHg) * @return TRUE if override successful, FALSE if not *************************************************************************/ DATA_OVERRIDE_FUNC( F32, testSetDialOutPumpOcclusionOverride, testResetDialOutPumpOcclusionOverride, dialOutPumpOcclusion )