Index: firmware/App/Controllers/SyringePump.c =================================================================== diff -u -r9720002e46be11657ecdda735446c3f80165413b -r2036cf36abe7fe00d52b082d6dc86f8ee45f5bf8 --- firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision 9720002e46be11657ecdda735446c3f80165413b) +++ firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision 2036cf36abe7fe00d52b082d6dc86f8ee45f5bf8) @@ -7,8 +7,8 @@ * * @file SyringePump.c * -* @author (last) Dara Navaei -* @date (last) 31-Mar-2023 +* @author (last) Michael Garthwaite +* @date (last) 01-May-2023 * * @author (original) Sean Nash * @date (original) 04-Mar-2021 @@ -78,12 +78,12 @@ #define SYRINGE_PUMP_ADC_FULL_SCALE_BITS 1024.0F ///< Syringe pump ADC has 1024 full scale counts (10-bit) per channel. #define SYRINGE_PUMP_DAC_FULL_SCALE_BITS 4096.0F ///< Syringe pump DAC has has 4096 full scale counts (12-bit). -#define SYRINGE_FORCE_OCCLUSION_THRESHOLD_V 3.2F ///< Force sensor threshold (in V) above which an occlusion is detected. +#define SYRINGE_FORCE_OCCLUSION_THRESHOLD_V 2.5F ///< Force sensor threshold (in V) above which an occlusion is detected. #define SYRINGE_FORCE_OCCLUSION_DIFF_V 0.5F ///< Force sensor difference (in V) which an occlusion alarm is triggered. #define SYRINGE_FORCE_PLUNGER_THRESHOLD_V 0.25F ///< Force sensor threshold (in V) above which we have engaged with plunger. #define SYRINGE_PUMP_SYRINGE_DETECT_THRESHOLD_V 2.0F ///< Syringe pump syringe detected threshold (in V). #define SYRINGE_PUMP_HOME_DETECT_THRESHOLD_V 0.25F ///< Syringe pump home detected threshold (in V). -#define SYRINGE_PUMP_PRIME_VOLUME_ML 0.353F ///< Target syringe prime volume (in mL). +#define SYRINGE_PUMP_EMPTY_THRESHOLD_V 2.5F ///< Syringe pump empty detected threshold (in V). #define SYRINGE_PUMP_PRELOAD_MARGIN_VOLUME_ML 1.0F ///< Target syringe preload margin volume (in mL). Total to deliver plus this give syringe load position. #define SYRINGE_PUMP_PRELOAD_MAX_VOLUME_ML 10.0F ///< Target syringe preload max volume (in mL). Leave at home position above this value. #define SYRINGE_PUMP_MAX_VOL_ERROR_ML 0.1F ///< Maximum Heparin volume error (in mL). @@ -93,6 +93,10 @@ #define SYRINGE_PUMP_DAC_VOLTAGE_MAX_ERROR 0.05F ///< Force sensor POST check for DAC voltage - max delta. #define MIN_SYRINGE_PUMP_RATE_FOR_DIR_ALARM 0.5F ///< Minimum measured rate (in mL/hr) required before enforcing direction alarm. +/// HW volume variance in the syringe pump in mL. +#define SYRINGE_PUMP_HW_TOLERANCE_ML 0.65F +/// HW volume variance in the syringe pump in encoder counts. +#define SYRINGE_PUMP_HW_TOLERANCE_POS ( SYRINGE_ENCODER_COUNTS_PER_ML * SYRINGE_PUMP_HW_TOLERANCE_ML ) /// Expected position of empty in relation to home position. #define SYRINGE_PUMP_EMPTY_POS ( SYRINGE_ENCODER_COUNTS_PER_ML * 11.0F ) /// Over-travel (past empty) allowance for alarm. @@ -160,6 +164,8 @@ #define SYRINGE_PUMP_ADC_FPGA_ERROR_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Syringe pump ADC FPGA error timeout in milliseconds. #define SYRINGE_PUMP_DAC_MAX_RETRIES 5 ///< Syringe pump DAC retries to write. #define SYRINGE_PUMP_DAC_TIMER ( 200 / TASK_PRIORITY_INTERVAL ) ///< Syringe pump DAC timer between retries. +#define SYRINGE_PUMP_OCCLUSION_PERSISTENCE 50 ///< Syringe pump occlusion persistence timer in milliseconds. +#define SYRINGE_PUMP_EMPTY_FORCE_COUNT 5 ///< Syringe pump empty force voltage count persistence. /// Defined states for the syringe pump control state machine. typedef enum SyringePump_States { @@ -240,6 +246,8 @@ static U32 syringePumpDACRetryCount; static U32 syringePumpDACRetryTimer; +static U32 syringePumpEmptyForceCount; + // ********** private function prototypes ********** static void resetSyringePumpRequestFlags( void ); @@ -313,7 +321,7 @@ syringePumpPrimeCompleted = FALSE; syringePumpPreLoadCompleted = FALSE; syringePumpRampUpPct = 0.0; - + syringePumpEmptyForceCount = 0; // Zero pump position counts buffer syringePumpMotorSpeedCalcIdx = 0; for ( i = 0; i < SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN; i++ ) @@ -1459,8 +1467,8 @@ F32 txVolumeReq = SYRINGE_PUMP_PRIME_VOLUME_ML + bolusVol + ( hepDurHr * contRate ); F32 syringeVol = ( SYRINGE_PUMP_EMPTY_POS - (F32)pos ) / SYRINGE_ENCODER_COUNTS_PER_ML; - syringePumpVolumeRequired = txVolumeReq; - txVolumeReq = txVolumeReq + SYRINGE_PUMP_PRELOAD_MARGIN_VOLUME_ML; + syringePumpVolumeRequired = txVolumeReq + SYRINGE_PUMP_FILL_VOLUME_OFFSET_ML; + txVolumeReq = txVolumeReq + SYRINGE_PUMP_FILL_VOLUME_OFFSET_ML + SYRINGE_PUMP_PRELOAD_MARGIN_VOLUME_ML; // Handle ramp up rampSyringePump(); @@ -1683,6 +1691,9 @@ // Check for syringe pump empty stopPump = checkSyringeEmpty( stopPump ); + // Check for occlusion + stopPump = checkForSyringeOcclusion(); + // Check position > empty + 0.5 mL stopPump = checkMaxTravel( stopPump, SYRINGE_PUMP_EMPTY_POS + SYRINGE_PUMP_EMPTY_POS_MARGIN ); @@ -1813,8 +1824,18 @@ F32 force = getSyringePumpForceV(); S32 pos = getSyringePumpPosition(); + if ( force >= SYRINGE_PUMP_EMPTY_THRESHOLD_V ) + { + syringePumpEmptyForceCount++; + } + else + { + syringePumpEmptyForceCount = 0; + } // If near empty position, assume syringe is empty - if ( pos >= SYRINGE_PUMP_EMPTY_POS ) + // Check for force threshold over some time and within SYRINGE_PUMP_HW_TOLERANCE_POS of empty + if ( ( pos >= SYRINGE_PUMP_EMPTY_POS ) || + ( ( syringePumpEmptyForceCount >= SYRINGE_PUMP_EMPTY_FORCE_COUNT ) && ( pos >= ( SYRINGE_PUMP_EMPTY_POS - SYRINGE_PUMP_HW_TOLERANCE_POS ) ) ) ) { heparinDeliveryState = HEPARIN_STATE_EMPTY; SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SYRINGE_EMPTY, (F32)pos, force ) @@ -1832,19 +1853,33 @@ * @details Outputs: alarm triggered if max force detected * @return TRUE if pump should be stopped, FALSE if not *************************************************************************/ -BOOL checkForPrimeOcclusion( void ) +BOOL checkForSyringeOcclusion( void ) { BOOL result = FALSE; // Return FALSE if no occlusion is detected - F32 forceAtEndOfPriming = getSyringePumpForceV(); // Read the force sensor at the end of the priming - F32 forceDelta = forceAtEndOfPriming - forceAtEndOfSeek; // Occlusion is detected if force at end of prime is > than force at end of seek by 0.5 volts or more - BOOL occlusionDetected = ( forceDelta >= SYRINGE_FORCE_OCCLUSION_DIFF_V ? TRUE : FALSE ); + F32 currentForceV = getSyringePumpForceV(); // Read the force sensor at the end of the priming + F32 forceDelta = currentForceV - forceAtEndOfSeek; // Occlusion is detected if force at end of prime is > than force at end of seek by 0.5 volts or more + BOOL occlusionDetected = FALSE; - if ( TRUE == occlusionDetected ) + // Checking for occlusion in dry self tests without persistence + if ( MODE_PRET == getCurrentOperationMode() ) { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, forceAtEndOfSeek, forceAtEndOfPriming ) - result = TRUE; + occlusionDetected = ( forceDelta >= SYRINGE_FORCE_OCCLUSION_DIFF_V ? TRUE : FALSE ); + + if ( TRUE == occlusionDetected ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, forceAtEndOfSeek, currentForceV ) + result = TRUE; + } } + // Check with persistence during continuous state + if ( SYRINGE_PUMP_OP_CONTINUOUS == syringePumpState ) + { + occlusionDetected = ( currentForceV >= SYRINGE_FORCE_OCCLUSION_THRESHOLD_V ? TRUE : FALSE ); + + checkPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, occlusionDetected, forceAtEndOfSeek, currentForceV ); + } + return result; }