Index: firmware/App/Controllers/SyringePump.c =================================================================== diff -u -r25ede6f944eb53b68c8073404663c99d3ce158b0 -rfed8ef4f0540818dfb7ca670a65eac39c12cb25a --- firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision 25ede6f944eb53b68c8073404663c99d3ce158b0) +++ firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision fed8ef4f0540818dfb7ca670a65eac39c12cb25a) @@ -81,7 +81,7 @@ #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). @@ -91,6 +91,8 @@ #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 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. @@ -158,6 +160,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. +#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 { @@ -237,6 +241,8 @@ static U32 syringePumpDACRetryCount; static U32 syringePumpDACRetryTimer; +static U32 syringePumpEmptyForceCount; + // ********** private function prototypes ********** static void resetSyringePumpRequestFlags( void ); @@ -309,7 +315,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++ ) @@ -328,7 +334,7 @@ initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_RUNNING_WHILE_BP_OFF_ERROR, 0, SYRINGE_PUMP_OFF_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR, 0, SYRINGE_PUMP_OFF_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, 0, SYRINGE_PUMP_RATE_ALARM_PERSISTENCE ); - + initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, 0, SYRINGE_PUMP_OCCLUSION_PERSISTENCE); initFPGAPersistentAlarm( FPGA_PERS_ERROR_SYRINGE_PUMP_ADC, ALARM_ID_HD_SYRINGE_PUMP_FPGA_ADC_FAULT, SYRINGE_PUMP_ADC_FPGA_ERROR_TIMEOUT_MS, SYRINGE_PUMP_ADC_FPGA_ERROR_TIMEOUT_MS ); @@ -1457,7 +1463,7 @@ U32 preStop = getTreatmentParameterU32( TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME ); U32 setTxDur = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); F32 hepDurHr = ( (F32)( setTxDur - preStop ) / (F32)MIN_PER_HOUR ); - F32 txVolumeReq = SYRINGE_PUMP_PRIME_VOLUME_ML + bolusVol + ( hepDurHr * contRate ); + F32 txVolumeReq = SYRINGE_PUMP_PRIME_VOLUME_ML + bolusVol + ( hepDurHr * contRate ) + SYRINGE_PUMP_HW_TOLERANCE_ML; F32 syringeVol = ( SYRINGE_PUMP_EMPTY_POS - (F32)pos ) / SYRINGE_ENCODER_COUNTS_PER_ML; syringePumpVolumeRequired = txVolumeReq; @@ -1681,6 +1687,8 @@ // Has syringe been removed? stopPump = checkSyringeRemoved( stopPump ); + stopPump = checkForSyringeOcclusion(); + // Check for syringe pump empty stopPump = checkSyringeEmpty( stopPump ); @@ -1814,8 +1822,20 @@ 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 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 ) || + 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 ) @@ -1833,19 +1853,29 @@ * @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 ); - 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; + if ( TRUE == occlusionDetected ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, forceAtEndOfSeek, forceAtEndOfPriming ) + result = TRUE; + } } + // Check with persistence during continuous state + if ( SYRINGE_PUMP_OP_CONTINUOUS == syringePumpState ) + { + checkPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, occlusionDetected, forceAtEndOfSeek, forceAtEndOfPriming ); + } + return result; } Index: firmware/App/Controllers/SyringePump.h =================================================================== diff -u -rceeba51c01b896855eb03ab81281a2b0f48c75d2 -rfed8ef4f0540818dfb7ca670a65eac39c12cb25a --- firmware/App/Controllers/SyringePump.h (.../SyringePump.h) (revision ceeba51c01b896855eb03ab81281a2b0f48c75d2) +++ firmware/App/Controllers/SyringePump.h (.../SyringePump.h) (revision fed8ef4f0540818dfb7ca670a65eac39c12cb25a) @@ -32,6 +32,9 @@ // ********** public definitions ********** +#define SYRINGE_PUMP_PRIME_VOLUME_ML 0.353F ///< Target syringe prime volume (in mL). +#define SYRINGE_PUMP_HW_TOLERANCE_ML 1.0F ///< HW volume variance of the syringe pump in mL. TBD value. + /// Enumeration of syringe pump operations. typedef enum SyringePumpOperations { @@ -93,7 +96,7 @@ BOOL preloadSyringePlunger( void ); BOOL seekSyringePlunger( void ); BOOL primeSyringePump( void ); -BOOL checkForPrimeOcclusion( void ); +BOOL checkForSyringeOcclusion( void ); BOOL startHeparinBolus( void ); BOOL startHeparinContinuous( void ); BOOL setSyringePumpDACVref( void ); Index: firmware/App/Modes/ModeTreatmentParams.c =================================================================== diff -u -rc1b9ac0dbf2196280895d2e440dd7ac288ac8424 -rfed8ef4f0540818dfb7ca670a65eac39c12cb25a --- firmware/App/Modes/ModeTreatmentParams.c (.../ModeTreatmentParams.c) (revision c1b9ac0dbf2196280895d2e440dd7ac288ac8424) +++ firmware/App/Modes/ModeTreatmentParams.c (.../ModeTreatmentParams.c) (revision fed8ef4f0540818dfb7ca670a65eac39c12cb25a) @@ -37,6 +37,7 @@ // ********** private definitions ********** #define MAX_DIALYSATE_VOLUME_ML ( 150 * ML_PER_LITER ) ///< Maximum dialysate volume (in mL) +#define MAX_HEPARIN_VOLUME_ML 10 ///< Maximum heparin volume ( in mL ) #define NO_HEPARIN_PRE_STOP_TIME_SET 0 ///< Zero value indicates no Heparin pre-stop time was set by user @@ -557,7 +558,11 @@ stagedParams[ TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ].sInt; S32 venousPresLimitDelta = stagedParams[ TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ].sInt - \ stagedParams[ TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ].sInt; + F32 heparinVolume_mL = ( stagedParams[ TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ].sFlt * \ + ( stagedParams[ TREATMENT_PARAM_TREATMENT_DURATION ].uInt - stagedParams[ TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME ].uInt ) ) + \ + stagedParams[ TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ].sFlt + SYRINGE_PUMP_PRIME_VOLUME_ML + SYRINGE_PUMP_HW_TOLERANCE_ML; + // Check max dialysate volume dependency if ( dialysateVolume_mL > MAX_DIALYSATE_VOLUME_ML ) { @@ -582,6 +587,12 @@ result = FALSE; } + // Check max heparin volume dependency + if (heparinVolume_mL > MAX_HEPARIN_VOLUME_ML ) + { + reasons[ TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME ] = REQUEST_REJECT_REASON_EXCEEDS_MAXIMUM_HEPARIN_VOLUME; + result = FALSE; + } // Check arterial alarm limits dependency if ( arterialPresLimitDelta < MIN_PRESSURE_ALARM_LIMIT_DELTA_MMHG ) { Index: firmware/App/Modes/SelfTests.c =================================================================== diff -u -rc1b9ac0dbf2196280895d2e440dd7ac288ac8424 -rfed8ef4f0540818dfb7ca670a65eac39c12cb25a --- firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision c1b9ac0dbf2196280895d2e440dd7ac288ac8424) +++ firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision fed8ef4f0540818dfb7ca670a65eac39c12cb25a) @@ -1574,7 +1574,7 @@ if ( TRUE == didTimeout( syringeOcclusionDelayStartTime, SYRINGE_PUMP_OCCLUSION_CHECK_DELAY ) ) { - if ( FALSE == checkForPrimeOcclusion() ) // transition to complete state only when occlusion is removed + if ( FALSE == checkForSyringeOcclusion() ) // transition to complete state only when occlusion is removed { state = DRY_SELF_TESTS_COMPLETE_STATE; }