Index: firmware/App/Controllers/PresOccl.c =================================================================== diff -u -r30f049651877229042e3f8700c8596e5b9a1e0f4 -rb4bc2e0337b358ee180650101d98e18346bf7c22 --- firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision 30f049651877229042e3f8700c8596e5b9a1e0f4) +++ firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision b4bc2e0337b358ee180650101d98e18346bf7c22) @@ -40,22 +40,35 @@ #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_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 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 MAX_TIME_BETWEEN_VENOUS_READINGS ( 500 / TASK_GENERAL_INTERVAL ) ///< Maximum time without fresh inline venous pressure reading. +static const U32 MAX_TIME_BETWEEN_VENOUS_READINGS = ( 500 / TASK_GENERAL_INTERVAL ); ///< Maximum time without fresh inline venous pressure reading. #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. @@ -88,15 +101,11 @@ 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. -/// Current pressure self-test state. -static PRESSURE_SELF_TEST_STATE_T presOcclSelfTestState = PRESSURE_SELF_TEST_STATE_START; -static U32 bloodPumpSelfTestTimerCount = 0; ///< Timer counter for pressure self-test. - static U32 staleVenousPressureCtr = 0; ///< Timer counter for stale venous pressure reading. +static U32 emptySalineBagCtr = 0; ///< Timer counter for empty bag detection. // ********** private function prototypes ********** -static PRESSURE_STATE_T handlePresOcclInitState( void ); static PRESSURE_STATE_T handlePresOcclContReadState( void ); static void convertInlinePressures( void ); static void convertOcclusionPressures( void ); @@ -108,22 +117,18 @@ /*********************************************************************//** * @brief - * The initPresOccl function initializes the initPresOccl module. + * The initPresOccl function initializes the PresOccl module. * @details Inputs: none - * @details Outputs: initPresOccl module initialized. + * @details Outputs: PresOccl module initialized. * @return none *************************************************************************/ void initPresOccl( void ) { // Initialize persistent pressure alarms - initPersistentAlarm( PERSISTENT_ALARM_ARTERIAL_PRESSURE_LOW, ALARM_ID_ARTERIAL_PRESSURE_LOW, - isAlarmRecoverable( ALARM_ID_ARTERIAL_PRESSURE_LOW ), PRES_ALARM_PERSISTENCE, PRES_ALARM_PERSISTENCE ); - initPersistentAlarm( PERSISTENT_ALARM_ARTERIAL_PRESSURE_HIGH, ALARM_ID_ARTERIAL_PRESSURE_HIGH, - isAlarmRecoverable( ALARM_ID_ARTERIAL_PRESSURE_HIGH ), PRES_ALARM_PERSISTENCE, PRES_ALARM_PERSISTENCE ); - initPersistentAlarm( PERSISTENT_ALARM_VENOUS_PRESSURE_LOW, ALARM_ID_VENOUS_PRESSURE_LOW, - isAlarmRecoverable( ALARM_ID_VENOUS_PRESSURE_LOW ), PRES_ALARM_PERSISTENCE, PRES_ALARM_PERSISTENCE ); - initPersistentAlarm( PERSISTENT_ALARM_VENOUS_PRESSURE_HIGH, ALARM_ID_VENOUS_PRESSURE_HIGH, - isAlarmRecoverable( ALARM_ID_VENOUS_PRESSURE_HIGH ), PRES_ALARM_PERSISTENCE, PRES_ALARM_PERSISTENCE ); + 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 ); } /*********************************************************************//** @@ -141,8 +146,7 @@ U32 diOccl = getMeasuredDialInPumpOcclusion(); U32 doOccl = getMeasuredDialOutPumpOcclusion(); - if ( ( bpOccl >= CARTRIDGE_LOADED_THRESHOLD ) && - ( diOccl >= CARTRIDGE_LOADED_THRESHOLD ) && + if ( ( bpOccl >= CARTRIDGE_LOADED_THRESHOLD ) && ( diOccl >= CARTRIDGE_LOADED_THRESHOLD ) && ( doOccl >= CARTRIDGE_LOADED_THRESHOLD ) ) { result = TRUE; @@ -151,6 +155,52 @@ 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. @@ -164,7 +214,7 @@ switch ( presOcclState ) { case PRESSURE_INIT_STATE: - presOcclState = handlePresOcclInitState(); + presOcclState = PRESSURE_CONTINUOUS_READ_STATE; break; case PRESSURE_CONTINUOUS_READ_STATE: @@ -182,21 +232,6 @@ /*********************************************************************//** * @brief - * The handlePresOcclInitState function handles the pres/occl initialize state - * of the pressure/occlusion monitor state machine. - * @details Inputs: TBD - * @details Outputs: TBD - * @return next state - *************************************************************************/ -static PRESSURE_STATE_T handlePresOcclInitState( void ) -{ - PRESSURE_STATE_T result = PRESSURE_CONTINUOUS_READ_STATE; - - return result; -} - -/*********************************************************************//** - * @brief * The handlePresOcclContReadState function handles the continuous read state * of the pressure/occlusion monitor state machine. * @details Inputs: FPGA pressure/occlusion readings @@ -292,8 +327,6 @@ *************************************************************************/ static void convertOcclusionPressures( void ) { - // TODO - any filtering required??? - // Occlusion sensor values have no unit - take as is bloodPumpOcclusion.data = (U32)getFPGABloodPumpOcclusion(); dialInPumpOcclusion.data = (U32)getFPGADialInPumpOcclusion(); @@ -319,8 +352,25 @@ F32 artHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); #ifndef DISABLE_PRESSURE_CHECKS - checkPersistentAlarm( PERSISTENT_ALARM_ARTERIAL_PRESSURE_LOW, artPres < artLowLimit, artPres, artLowLimit ); - checkPersistentAlarm( PERSISTENT_ALARM_ARTERIAL_PRESSURE_HIGH, artPres > artHighLimit, artPres, artHighLimit ); + 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 } } @@ -344,8 +394,25 @@ F32 venHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); #ifndef DISABLE_PRESSURE_CHECKS - checkPersistentAlarm( PERSISTENT_ALARM_VENOUS_PRESSURE_LOW, venPres < venLowLimit, venPres, venLowLimit ); - checkPersistentAlarm( PERSISTENT_ALARM_VENOUS_PRESSURE_HIGH, venPres > venHighLimit, venPres, venHighLimit ); + 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 } } @@ -364,7 +431,6 @@ U32 diOccl = getMeasuredDialInPumpOcclusion(); U32 doOccl = getMeasuredDialOutPumpOcclusion(); - // TODO - add persistence #ifndef DISABLE_PRESSURE_CHECKS if ( bpOccl > OCCLUSION_THRESHOLD ) { @@ -392,7 +458,7 @@ * @details Outputs: none * @return the current pressure/occlusion data publication interval (in task intervals). *************************************************************************/ -U32 getPublishPresOcclDataInterval( void ) +static U32 getPublishPresOcclDataInterval( void ) { U32 result = presOcclDataPublishInterval.data; @@ -530,22 +596,93 @@ /*********************************************************************//** * @brief - * The execPresOcclTest function executes the state machine for the - * PresOccl self-test. + * The execPresOcclTest function executes the PresOccl self-test. * @details Inputs: none - * @details Outputs: none - * @return the current state of the PresOccl self-test. + * @details Outputs: Triggers fault when test case fails + * @return none *************************************************************************/ -SELF_TEST_STATUS_T execPresOcclTest( void ) +void execPresOcclTest( void ) { - SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; - - // TODO - implement self-test(s) - - return result; + 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 ); + } } + +/*********************************************************************//** + * @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 *************************************************************************/