/************************************************************************** * * Copyright (c) 2019-2021 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 SyringePump.c * * @author (last) Sean Nash * @date (last) 15-Nov-2021 * * @author (original) Sean Nash * @date (original) 04-Mar-2021 * ***************************************************************************/ #include #include "AlarmMgmt.h" #include "FPGA.h" #include "ModeTreatmentParams.h" #include "NVDataMgmt.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SafetyShutdown.h" #include "SyringePump.h" #include "SystemCommMessages.h" #include "TaskPriority.h" #include "Timers.h" /** * @addtogroup SyringePump * @{ */ // ********** private definitions ********** /// Default publication interval for syringe pump data. #define SYRINGE_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) #define BD_SYRINGE_ID_RADIUS_CM ( 1.402 / 2.0 ) ///< Radius from inner diameter (in cm) of supported BD syringe. /// Milliliters per mm of syringe plunger travel. #define SYRINGE_ML_PER_MM ( ( BD_SYRINGE_ID_RADIUS_CM * BD_SYRINGE_ID_RADIUS_CM ) * PI * 0.1 ) #define SYRINGE_MM_PER_REV 0.635 ///< Travel (in mm) per revolution. #define SYRINGE_ENCODER_COUNTS_PER_REV 4000.0 ///< Number of encoder counts per revolution. #define SYRINGE_STEPS_PER_REV 200.0 ///< Number of steps per revolution. #define MICRO_SECONDS_PER_SECOND 1000000.0 ///< Microseconds per second conversion. #define SYRINGE_TOGGLES_PER_STEP 2.0 ///< Stepper motor driver toggles per step or microstep. #define SYRINGE_MICRO_STEPS_PER_STEP 32.0 ///< Number of micro-steps per step. /// Number of micro steps per revolution. #define SYRINGE_MICRO_STEPS_PER_REV ( SYRINGE_STEPS_PER_REV * SYRINGE_MICRO_STEPS_PER_STEP ) /// Number of encoder counts per mm. #define SYRINGE_ENCODER_COUNTS_PER_MM ( SYRINGE_ENCODER_COUNTS_PER_REV / SYRINGE_MM_PER_REV ) /// Number of encoder counts per mL. #define SYRINGE_ENCODER_COUNTS_PER_ML ( SYRINGE_ENCODER_COUNTS_PER_MM / SYRINGE_ML_PER_MM ) /// Number of micro steps per mL. #define SYRINGE_MICRO_STEPS_PER_ML ( ( SYRINGE_MICRO_STEPS_PER_REV / SYRINGE_MM_PER_REV ) / SYRINGE_ML_PER_MM ) #define MIN_HEPARIN_CONTINUOUS_RATE 0.1 ///< Minimum continuous Heparin flow rate (in mL/hr). #define MAX_HEPARIN_CONTINUOUS_RATE 1.0 ///< Maximum continuous Heparin flow rate (in mL/hr). #define MIN_HEPARIN_BOLUS_RATE 1.2 ///< Minimum Heparin bolus flow rate (in mL/hr). #define MAX_HEPARIN_BOLUS_RATE 24.0 ///< Maximum Heparin bolus flow rate (in mL/hr). #define HEPARIN_BOLUS_TIME_HR ( 5.0 / MIN_PER_HOUR ) ///< Duration (in hours) of Heparin bolus. #define SYRINGE_PUMP_RETRACT_RATE 3600.0 ///< Retract rate is 5 mL/ 5 s = 1 mL/s = 3,600 mL/hr. #define SYRINGE_PUMP_SEEK_RATE 3600.0 ///< Seek plunger rate is 5 mL/ 5 s = 1 mL/s = 3,600 mL/hr. #define SYRINGE_PUMP_PRIME_RATE 635.0 ///< Prime rate is 0.5 mm ^ 2 x PI x 450 mm = 0.353 mL / 2s = 635 mL/hr. #define SYRINGE_PUMP_MAX_RATE 11000.0 ///< Maximum rate of the syringe pump (in mL/hr). #define SYRINGE_PUMP_RATE_ALARM_PERSISTENCE 2000 ///< Alarm persistence period (in ms) for syringe pump speed check alarms. #define SYRINGE_PUMP_DIR_ALARM_PERSISTENCE 1000 ///< Alarm persistence period (in ms) for syringe pump direction check alarms. #define SYRINGE_PUMP_OFF_ALARM_PERSISTENCE 500 ///< Alarm persistence period (in ms) for syringe pump off check alarms. #define SYRINGE_PUMP_OCCLUSION_ALARM_PERSISTENCE 30 ///< Alarm persistence period (in ms) for syringe pump occlusion alarms. #define SYRINGE_PUMP_ADC_READ_PERSISTENCE 100 ///< Syringe pump ADC stale read alarm persistence time (in ms). #define STEPS_TO_MICROSTEPS( s ) ( (s) * 32.0 ) ///< Macro conversion from steps to microsteps. #define MICROSTEPS_TO_STEPS( m ) ( (m) / 32.0 ) ///< Macro conversion from microsteps to steps. #define SYRINGE_PUMP_ADC_REF_V 3.3 ///< Syringe pump ADC reference voltage. #define SYRINGE_PUMP_ADC_FULL_SCALE_BITS 1024.0 ///< Syringe pump ADC has 1024 full scale counts (10-bit) per channel. #define SYRINGE_PUMP_DAC_FULL_SCALE_BITS 4096.0 ///< Syringe pump DAC has has 4096 full scale counts (12-bit). #define SYRINGE_FORCE_OCCLUSION_THRESHOLD_V 3.2 ///< Force sensor threshold (in V) above which an occlusion is detected. #define SYRINGE_FORCE_PLUNGER_THRESHOLD_V 0.25 ///< Force sensor threshold (in V) above which we have engaged with plunger. #define SYRINGE_PUMP_SYRINGE_DETECT_THRESHOLD_V 2.0 ///< Syringe pump syringe detected threshold (in V). #define SYRINGE_PUMP_HOME_DETECT_THRESHOLD_V 0.25 ///< Syringe pump home detected threshold (in V). #define SYRINGE_PUMP_PRIME_VOLUME_ML 0.353 ///< Target syringe prime volume (in mL). #define SYRINGE_PUMP_MAX_VOL_ERROR_ML 0.1 ///< Maximum Heparin volume error (in mL). #define SYRINGE_PUMP_MAX_RATE_ERROR_ML_HR 0.1 ///< Maximum Heparin delivery rate error (in mL/hr). #define TEN_PCT_OVER_ALLOWANCE 1.1 ///< Allow 10 percent over target before alarming on over travel. #define FIVE_PCT_OVER_ALLOWANCE 1.05 ///< Allow 5 percent over target before alarming on over travel. /// Expected position of empty in relation to home postion. #define SYRINGE_PUMP_EMPTY_POS ( SYRINGE_ENCODER_COUNTS_PER_ML * 11.0 ) // TODO - get syringe volume from home to empty (11 mL is placeholder) /// Margin of error for empty position determination. #define SYRINGE_PUMP_EMPTY_POS_MARGIN ( SYRINGE_ENCODER_COUNTS_PER_ML * 0.5 ) /// Minimum retract position. #define SYRINGE_PUMP_RETRACT_POS_MIN ( SYRINGE_ENCODER_COUNTS_PER_ML * -0.5 ) #define SYRINGE_PUMP_START_RAMP_SPEED 300000 ///< Starting speed for all syringe pump operations to ramp up from. #define SYRINGE_PUMP_RAMP_DIVISOR 5 ///< Used for ramping profile. #define SYRINGE_PUMP_RATE_CHECK_MARGIN 0.05 ///< 5 pct margin on commanded vs. measured rate check. #define SYRINGE_PUMP_VOLUME_CHECK_MARGIN 0.05 ///< 5 pct margin on commanded vs. encoder based volume check. // Bit definitions for syringe pump control register #define SYRINGE_PUMP_CONTROL_SLEEP_OFF 0x40 ///< Syringe pump control register bit for sleep mode (active low). #define SYRINGE_PUMP_CONTROL_NOT_RESET 0x20 ///< Syringe pump control register bit for resetting stepper motor (active low). #define SYRINGE_PUMP_CONTROL_ENABLE 0x00 ///< Syringe pump control register bit mask for enable. #define SYRINGE_PUMP_CONTROL_DISABLE 0x10 ///< Syringe pump control register bit for enable (active low). #define SYRINGE_PUMP_CONTROL_REVERSE_DIR 0x08 ///< Syringe pump control register bit for direction (0=fwd, 1=rev). #define SYRINGE_PUMP_CONTROL_FORWARD_DIR 0x00 ///< Syringe pump control register bit mask for forward direction. #define SYRINGE_PUMP_CONTROL_32TH_STEP 0x03 ///< Syringe pump control register bits for 1/32 micro-stepping mode. // Bit definitions for syringe pump ADC/DAC control register #define SYRINGE_PUMP_ADC_DAC_CONTROL_WR_ADC_SETUP 0x04 ///< Syringe pump ADC/DAC control bit for re-write ADC setup registers to ADC. #define SYRINGE_PUMP_ADC_DAC_CONTROL_RD_DAC_ON_ADC 0x02 ///< Syringe pump ADC/DAC control bit for reading (once) DAC setting from device. #define SYRINGE_PUMP_ADC_DAC_CONTROL_ENABLE_DAC 0x01 ///< Syringe pump ADC/DAC control bit for write DAC setting to device (ADC reads are off). #define SYRINGE_PUMP_ADC_DAC_CONTROL_ENABLE_ADC 0x00 ///< Syringe pump ADC/DAC control bit mask for enable ADC reads. // Bit definitions for syringe pump ADC/DAC status register #define SYRINGE_PUMP_ADC_DAC_ERROR_COUNT_DAC_WR_DONE 0x80 ///< Syringe pump ADC/DAC error status bit for DAC write done. #define SYRINGE_PUMP_ADC_DAC_ERROR_COUNT_DAC_WR_ERROR 0x40 ///< Syringe pump ADC/DAC error status bit for DAC write error. #define SYRINGE_PUMP_ADC_DAC_ERROR_COUNT_MASK 0x3F ///< Syringe pump ADC/DAC error status count bit-mask. // Bit definitions for syringe pump encoder status register #define SYRINGE_PUMP_ENCODER_STATUS_DIRECTION 0x80 ///< Syringe pump encoder status direction bit (0-Fwd, 1=Rev). #define SYRINGE_PUMP_ENCODER_STATUS_ERROR_COUNT_MASK 0x3F ///< Syringe pump encoder status error count bit-mask. // Stepper motor toggle time for zero speed (stopped) #define SYRINGE_PUMP_MICROSTEP_TOGGLE_TIME_FOR_STOP 0xFFFFFFFF ///< Syringe pump microstep toggle time setting to indicate zero speed (stopped). /// Control bits to run syringe pump in reverse direction static const U08 SYRINGE_PUMP_CONTROL_RUN_REVERSE = SYRINGE_PUMP_CONTROL_SLEEP_OFF | SYRINGE_PUMP_CONTROL_NOT_RESET | SYRINGE_PUMP_CONTROL_ENABLE | SYRINGE_PUMP_CONTROL_REVERSE_DIR | SYRINGE_PUMP_CONTROL_32TH_STEP; /// Control bits to run syringe pump in forward direction static const U08 SYRINGE_PUMP_CONTROL_RUN_FORWARD = SYRINGE_PUMP_CONTROL_SLEEP_OFF | SYRINGE_PUMP_CONTROL_NOT_RESET | SYRINGE_PUMP_CONTROL_ENABLE | SYRINGE_PUMP_CONTROL_FORWARD_DIR | SYRINGE_PUMP_CONTROL_32TH_STEP; #define SYRINGE_PUMP_DAC_WRITE_ERROR_BIT 0x40 ///< Syringe pump DAC write error bit flag in FPGA register. #define SYRINGE_PUMP_ENCODER_DIRECTION_ERROR_BITS 0x3F ///< Syringe pump encoder direction error counter bits in FPGA register. #define SYRINGE_PUMP_ENCODER_DIRECTION_BIT 0x80 ///< Syringe pump encoder direction bit in FPGA register. /// Interval (ms/task time) at which the syringe pump speed is calculated (every 40 ms). #define SYRINGE_PUMP_SPEED_CALC_INTERVAL ( 40 / TASK_PRIORITY_INTERVAL ) /// Number of syringe pump encoder positions kept in buffer to hold last 1 second of position data. #define SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN ( MS_PER_SECOND / SYRINGE_PUMP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) #define SYRINGE_PUMP_RAMP_STALL_TIME ( 500 / TASK_PRIORITY_INTERVAL ) ///< Syringe pump ramp stall timeout. #define SYRINGE_PUMP_RAMP_STALL_RETRIES 3 ///< Syringe pump ramp stall retries allowed. #define SYRINGE_PUMP_STALL_SPEED_THRESHOLD 0.05 ///< Minimum syringe pump speed to be considered not stalled. /// Defined states for the syringe pump control state machine. typedef enum SyringePump_States { SYRINGE_PUMP_INIT_STATE = 0, ///< Syringe pump initialize state SYRINGE_PUMP_OFF_STATE, ///< Syringe pump off state SYRINGE_PUMP_RETRACT_STATE, ///< Syringe pump retract state SYRINGE_PUMP_SEEK_STATE, ///< Syringe pump seek plunger state SYRINGE_PUMP_PRIME_STATE, ///< Syringe pump prime state SYRINGE_PUMP_HEP_BOLUS_STATE, ///< Syringe pump bolus delivery of Heparin state SYRINGE_PUMP_HEP_CONTINUOUS_STATE, ///< Syringe pump continuous delivery of Heparin state SYRINGE_PUMP_CONFIG_FORCE_SENSOR_STATE, ///< Syringe pump configure DAC gain for force sensor state NUM_OF_SYRINGE_PUMP_STATES ///< Number of syringe pump control states } SYRINGE_PUMP_STATE_T; // ********** private data ********** static SYRINGE_PUMP_STATE_T syringePumpState; ///< Current state of syringe pump control state machine. static U32 syringePumpDataPublicationTimerCounter; ///< Used to schedule syringe pump data publication to CAN bus. static U32 syringePumpRampTimerCtr; ///< Used to track ramp up time. static HEPARIN_STATE_T heparinDeliveryState; ///< Current state of Heparin delivery. /// Interval (in ms) at which to publish syringe pump data to CAN bus. static OVERRIDE_U32_T syringePumpDataPublishInterval = { SYRINGE_PUMP_DATA_PUB_INTERVAL, SYRINGE_PUMP_DATA_PUB_INTERVAL, 0, 0 }; static OVERRIDE_F32_T syringePumpMeasRate = { 0.0, 0.0, 0.0, 0 }; ///< Measured rate for syringe pump (in mL/hr). static OVERRIDE_F32_T syringePumpMeasForce = { 0.0, 0.0, 0.0, 0 }; ///< Measured driver force (in V). static OVERRIDE_F32_T syringePumpMeasSyringeDetectionSwitch = { 0, 0, 0, 0 }; ///< Measured syringe detect switch (in V). static OVERRIDE_F32_T syringePumpMeasHome = { 0.0, 0.0, 0.0, 0 }; ///< Measured optical home (in V). static OVERRIDE_S32_T syringePumpPosition = { 0, 0, 0, 0 }; ///< Encoder based position (in steps). static OVERRIDE_F32_T syringePumpVolumeDelivered = { 0.0, 0.0, 0.0, 0 }; ///< Measured volume delivered (in mL). static OVERRIDE_U32_T syringePumpStatus = {0, 0, 0, 0}; ///< Syringe pump status reported by FPGA. static OVERRIDE_U32_T syringePumpEncoderStatus = {0, 0, 0, 0}; ///< Syringe pump encoder status reported by FPGA. static OVERRIDE_U32_T syringePumpADCandDACStatus = {0, 0, 0, 0}; ///< Syringe pump ADC and DAC status reported by FPGA. static OVERRIDE_U32_T syringePumpADCReadCtr = {0, 0, 0, 0}; ///< Syringe pump ADC read counter reported by FPGA. static F32 syringePumpSetRate; ///< Set rate for syringe pump (in mL/hr). static U32 syringePumpSetToggleTime; ///< Set rate for syringe pump (in uSec/toggle). static U32 syringePumpRampUpToggleTime; ///< Current ramp rate for syringe pump (in uSec/toggle). static F32 syringePumpSafetyVolumeDelivered; ///< Calculated volume (in mL) (from set rate over time). static S32 syringePumpVolumeStartPosition; ///< Start position for the current volume calculation. static S32 syringePumpHomePositionOffset; ///< FPGA reported position when at home postion. static S32 syringePumpLastPosition; ///< Position previously recorded. static S32 syringePumpLastPositions[ SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN ]; ///< Last encoder positions for the syringe pump. static U32 syringePumpMotorSpeedCalcIdx; ///< Index into 1 second buffer of syringe pump encoder positions. static U32 syringePumpSpeedCalcTimerCounter; ///< Used to calculate measured rate from change in position over time. #ifndef DISABLE_SYRINGE_PUMP_ALARMS static MOTOR_DIR_T syringePumpControllerMeasuredDirection; ///< Measured direction of syringe pump per controller. static MOTOR_DIR_T syringePumpEncoderMeasuredDirection; ///< Measured direction of syringe pump per encoder position relative to previous. #endif static BOOL syringePumpRetractRequested; ///< Flag indicates a retract operation is requested. static BOOL syringePumpSeekRequested; ///< Flag indicates a plunger seek operation is requested. static BOOL syringePumpPrimeRequested; ///< Flag indicates a Heparin prime operation is requested. static BOOL syringePumpBolusRequested; ///< Flag indicates start or resume of a Heparin bolus operation is requested. static BOOL syringePumpContinuousRequested; ///< Flag indicates start or resume of a Heparin continuous delivery operation is requested. static BOOL syringePumpDACVrefSetRequested; ///< Flag indicates request to set DAC Vref for force sensor. static BOOL syringePumpPositionKnown; ///< Flag indicates we know position from a prior retract to home. static BOOL syringePumpPlungerFound; ///< Flag indicates plunger was found. static BOOL syringeVolumeAdequate; ///< Flag indicates whether Heparin volume is sufficient to complete treatment. static BOOL syringePumpPrimeCompleted; ///< Flag indicates prime operation was completed. static BOOL syringePumpDACVrefWriteInProgress; ///< Flag indicates DAC Vref write is in progress. static F32 syringePumpDACVref; ///< DAC Vref setting for force sensor. static U08 lastSyringePumpADCReadCtr; ///< Remember last ADC read counter to check new reads are fresh. static U32 syringePumpStallCtr; ///< Counts time when position is not changing during ramp. static U32 syringePumpStallRetryCount; ///< Counts pump ramp up stall retries. static HD_HEPARIN_FORCE_SENSOR_CAL_RECORD_T forceSensorCalRecord; ///< HD heparin force sensor calibration record. // ********** private function prototypes ********** static void resetSyringePumpRequestFlags( void ); static void execSyringePumpMonitor( void ); static S32 getSyringePumpPosition( void ); static F32 getSyringePumpMeasRate( void ); static F32 getSyringePumpSyringeDetectorV( void ); static F32 getSyringePumpHomeDetectorV( void ); static F32 getSyringePumpForceV( void ); static U08 getSyringePumpStatus( void ); static U08 getSyringePumpEncoderStatus( void ); static U08 getSyringePumpADCReadCounter( void ); static U08 getSyringePumpADCandDACStatus( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpInitState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpOffState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpRetractState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpSeekState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpPrimeState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpBolusState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpContinuousState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpCalibrateForceSensorState( void ); static void rampSyringePump( void ); static void calcStepperToggleTimeForTargetRate( F32 rate ); static void calcMeasRate( void ); static void calcSafetyVolumeDelivered( void ); static BOOL checkDirection( BOOL stopPump, MOTOR_DIR_T expDir ); static BOOL checkOcclusionOrEmpty( BOOL stopPump ); static BOOL checkSyringeRemoved( BOOL stopPump ); static BOOL checkMaxTravel( BOOL stopPump, S32 maxPos ); static BOOL checkMeasRate( BOOL stopPump, F32 pctMargin ); static BOOL checkVolumeVsSafetyVolume( BOOL stopPump, F32 pctMargin ); static BOOL checkForStall( BOOL stopPump ); static void publishSyringePumpData( void ); static BOOL processCalibrationData( void ); /*********************************************************************//** * @brief * The initSyringePump function initializes the syringe pump module. * @details Inputs: none * @details Outputs: syringe pump module initialized. * @return none *************************************************************************/ void initSyringePump( void ) { U32 i; syringePumpState = SYRINGE_PUMP_INIT_STATE; heparinDeliveryState = HEPARIN_STATE_OFF; syringePumpSetRate = 0.0; syringePumpSetToggleTime = 0; syringePumpSafetyVolumeDelivered = 0.0; syringePumpVolumeStartPosition = 0; syringePumpHomePositionOffset = 0; syringePumpLastPosition = 0; #ifndef DISABLE_SYRINGE_PUMP_ALARMS syringePumpControllerMeasuredDirection = MOTOR_DIR_FORWARD; syringePumpEncoderMeasuredDirection = MOTOR_DIR_FORWARD; #endif syringePumpDataPublicationTimerCounter = 0; syringePumpSpeedCalcTimerCounter = 0; syringePumpRampTimerCtr = 0; syringePumpPositionKnown = FALSE; syringePumpPlungerFound = FALSE; syringeVolumeAdequate = FALSE; syringePumpPrimeCompleted = FALSE; lastSyringePumpADCReadCtr = 0; // Zero pump position counts buffer syringePumpMotorSpeedCalcIdx = 0; for ( i = 0; i < SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN; i++ ) { syringePumpLastPositions[ i ] = 0; } syringePumpStallCtr = 0; syringePumpStallRetryCount = 0; // Initialize persistent alarms initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR, 0, SYRINGE_PUMP_ADC_READ_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_ENCODER_DIRECTION_ERROR, 0, SYRINGE_PUMP_DIR_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_CONTROLLER_DIRECTION_ERROR, 0, SYRINGE_PUMP_DIR_ALARM_PERSISTENCE ); 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_ALARM_PERSISTENCE ); // Reset request flags resetSyringePumpRequestFlags(); } /*********************************************************************//** * @brief * The resetSyringePumpRequestFlags function resets request flags. * @details Inputs: none * @details Outputs: request flags reset * @return TRUE if request accepted, FALSE if not *************************************************************************/ static void resetSyringePumpRequestFlags( void ) { syringePumpRetractRequested = FALSE; syringePumpSeekRequested = FALSE; syringePumpPrimeRequested = FALSE; syringePumpBolusRequested = FALSE; syringePumpContinuousRequested = FALSE; syringePumpDACVrefSetRequested = FALSE; } /*********************************************************************//** * @brief * The userHeparinRequest function handles a command request from the user * to pause or resume Heparin delivery. * @details Inputs: none * @details Outputs: heparinDeliveryState, syringePumpState, syringePumpContinuousRequested * @param cmd command from user * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL userHeparinRequest( HEPARIN_CMD_T cmd ) { BOOL accepted = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; if ( MODE_TREA == getCurrentOperationMode() ) { if ( ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) && ( getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) ) { if ( HEPARIN_CMD_PAUSE == cmd ) { if ( HEPARIN_STATE_DISPENSING == heparinDeliveryState ) { accepted = TRUE; heparinDeliveryState = HEPARIN_STATE_PAUSED; stopSyringePump(); sendTreatmentLogEventData( HEPARIN_PAUSE_RESUME_EVENT, HEPARIN_STATE_DISPENSING, HEPARIN_STATE_PAUSED ); } else { rejReason = REQUEST_REJECT_REASON_HEPARIN_PAUSE_INVALID_IN_THIS_STATE; } } else if ( HEPARIN_CMD_RESUME == cmd ) { if ( HEPARIN_STATE_PAUSED == heparinDeliveryState ) { accepted = TRUE; startHeparinContinuous(); sendTreatmentLogEventData( HEPARIN_PAUSE_RESUME_EVENT, HEPARIN_STATE_PAUSED, HEPARIN_STATE_DISPENSING ); } else { rejReason = REQUEST_REJECT_REASON_HEPARIN_NOT_PAUSED; } } else { rejReason = REQUEST_REJECT_REASON_INVALID_COMMAND; } } else { rejReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } } else { rejReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } sendHeparinCommandResponse( (U32)accepted, (U32)rejReason ); return accepted; } /*********************************************************************//** * @brief * The setHeparinOff function requests Heparin state be set to off - * indicates syringe pump will not be needed in this treatment. * @details Inputs: none * @details Outputs: heparinDeliveryState * @return none *************************************************************************/ void setHeparinOff( void ) { heparinDeliveryState = HEPARIN_STATE_OFF; } /*********************************************************************//** * @brief * The setHeparinStopped function requests Heparin state be set to stopped - * indicates syringe pump will be needed in this treatment. * @details Inputs: none * @details Outputs: heparinDeliveryState * @return none *************************************************************************/ void setHeparinStopped( void ) { heparinDeliveryState = HEPARIN_STATE_STOPPED; } /*********************************************************************//** * @brief * The setHeparinCompleted function requests Heparin state be set to completed - * indicates we have entered the Heparin pre-stop period of this treatment. * @details Inputs: none * @details Outputs: heparinDeliveryState * @return none *************************************************************************/ void setHeparinCompleted( void ) { heparinDeliveryState = HEPARIN_STATE_COMPLETED; } /*********************************************************************//** * @brief * The getHeparinState function returns the current Heparin state. * @details Inputs: heparinDeliveryState * @details Outputs: none * @return heparinDeliveryState *************************************************************************/ HEPARIN_STATE_T getHeparinState( void ) { return heparinDeliveryState; } /*********************************************************************//** * @brief * The stopSyringePump function requests syringe pump be stopped. * @details Inputs: none * @details Outputs: syringePumpSetRate, syringePumpRetractRequested, syringePumpState * @return TRUE if request accepted, FALSE if not *************************************************************************/ void stopSyringePump( void ) { syringePumpSetRate = 0.0; setFPGASyringePumpStepToggleTime( SYRINGE_PUMP_MICROSTEP_TOGGLE_TIME_FOR_STOP ); syringePumpState = SYRINGE_PUMP_OFF_STATE; if ( ( HEPARIN_STATE_INITIAL_BOLUS == heparinDeliveryState ) || ( HEPARIN_STATE_DISPENSING == heparinDeliveryState ) ) { heparinDeliveryState = HEPARIN_STATE_STOPPED; } } /*********************************************************************//** * @brief * The retractSyringePump function requests retract operation. * @details Inputs: syringePumpState * @details Outputs: syringePumpSetRate, syringePumpRetractRequested * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL retractSyringePump( void ) { #ifndef ALWAYS_ALLOW_SYRINGE_PUMP_CMDS if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( heparinDeliveryState != HEPARIN_STATE_OFF ) ) #else heparinDeliveryState = HEPARIN_STATE_STOPPED; if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) ) #endif { syringePumpSetRate = SYRINGE_PUMP_RETRACT_RATE; syringePumpRetractRequested = TRUE; } return syringePumpRetractRequested; } /*********************************************************************//** * @brief * The seekSyringePlunger function requests plunger seek operation. * @details Inputs: syringePumpState * @details Outputs: syringePumpSetRate, syringePumpSeekRequested * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL seekSyringePlunger( void ) { if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( TRUE == isSyringeDetected() ) && ( TRUE == syringePumpPositionKnown ) && ( heparinDeliveryState != HEPARIN_STATE_OFF ) ) { syringePumpSetRate = SYRINGE_PUMP_SEEK_RATE; syringePumpSeekRequested = TRUE; } return syringePumpSeekRequested; } /*********************************************************************//** * @brief * The primeSyringePump function requests a prime operation. * @details Inputs: syringePumpState * @details Outputs: syringePumpSetRate, syringePumpPrimeRequested * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL primeSyringePump( void ) { if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( TRUE == isSyringeDetected() ) && ( heparinDeliveryState != HEPARIN_STATE_OFF ) && ( TRUE == syringePumpPlungerFound ) ) { syringePumpSetRate = SYRINGE_PUMP_PRIME_RATE; syringePumpPrimeRequested = TRUE; resetHeparinVolumeDelivered(); } return syringePumpPrimeRequested; } /*********************************************************************//** * @brief * The resetHeparinVolumeDelivered function resets the Heparin volume delivered. * @details Inputs: none * @details Outputs: syringePumpVolumeDelivered, syringePumpSafetyVolumeDelivered, * syringePumpVolumeStartPosition * @return none *************************************************************************/ void resetHeparinVolumeDelivered( void ) { syringePumpVolumeDelivered.data = 0.0; syringePumpSafetyVolumeDelivered = 0.0; syringePumpVolumeStartPosition = getSyringePumpPosition(); } /*********************************************************************//** * @brief * The startHeparinBolus function requests Heparin bolus delivery. * @details Inputs: syringePumpState * @details Outputs: syringePumpSetRate, syringePumpBolusRequested * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL startHeparinBolus( void ) { F32 tgtRate = 0.0; // Get set Heparin bolus volume (mL) and convert to target rate (mL/hr) tgtRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ) / HEPARIN_BOLUS_TIME_HR; // If valid to start a bolus, kick it off if ( ( tgtRate >= MIN_HEPARIN_BOLUS_RATE ) && ( tgtRate <= MAX_HEPARIN_BOLUS_RATE ) && ( FALSE == isSyringePumpHome() ) ) { if ( ( TRUE == isSyringeDetected() ) && ( TRUE == syringePumpPrimeCompleted ) && ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( HEPARIN_STATE_STOPPED == heparinDeliveryState ) ) { syringePumpSetRate = tgtRate; syringePumpBolusRequested = TRUE; } } else { #ifndef DISABLE_SYRINGE_PUMP SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (F32)SW_FAULT_ID_HD_SYRINGE_INVALID_BOLUS_CMD, tgtRate ) #endif } return syringePumpBolusRequested; } /*********************************************************************//** * @brief * The startHeparinContinuous function requests Heparin continuous delivery. * @details Inputs: syringePumpState * @details Outputs: syringePumpSetRate, syringePumpContinuousRequested * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL startHeparinContinuous( void ) { F32 flowRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ); if ( ( flowRate >= MIN_HEPARIN_CONTINUOUS_RATE ) && ( flowRate <= MAX_HEPARIN_CONTINUOUS_RATE ) && ( FALSE == isSyringePumpHome() ) ) { if ( ( TRUE == isSyringeDetected() ) && ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( ( HEPARIN_STATE_STOPPED == heparinDeliveryState ) || ( HEPARIN_STATE_PAUSED == heparinDeliveryState ) ) ) { syringePumpSetRate = flowRate; syringePumpContinuousRequested = TRUE; } } else { #ifndef DISABLE_SYRINGE_PUMP SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (F32)SW_FAULT_ID_HD_SYRINGE_INVALID_CONT_CMD, flowRate ) #endif } return syringePumpContinuousRequested; } /*********************************************************************//** * @brief * The setSyringePumpDACVref function requests to set the DAC Vref setting. * @details Inputs: none * @details Outputs: syringePumpDACVrefSetRequested, syringePumpDACVref * @param vRef voltage to set DAC Vref to (in V) * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL setSyringePumpDACVref( F32 vRef ) { if ( ( vRef >= 0.0 ) && ( vRef <= 3.3 ) ) { if ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) { syringePumpDACVref = vRef; syringePumpDACVrefSetRequested = TRUE; } } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (F32)SW_FAULT_ID_HD_SYRINGE_INVALID_VREF, vRef ) } return syringePumpDACVrefSetRequested; } /*********************************************************************//** * @brief * The getSyringePumpVolumeDelivered function gets the current syringe pump * volume delivered. * @details Inputs: syringePumpVolumeDelivered * @details Outputs: none * @return the current syringe pump volume delivered (in mL). *************************************************************************/ F32 getSyringePumpVolumeDelivered( void ) { F32 result = syringePumpVolumeDelivered.data; if ( OVERRIDE_KEY == syringePumpVolumeDelivered.override ) { result = syringePumpVolumeDelivered.ovData; } return result; } /*********************************************************************//** * @brief * The getSyringePumpMeasRate function gets the current syringe pump measured * rate. * @details Inputs: syringePumpMeasRate * @details Outputs: none * @return the current syringe pump measured rate (in mL/hr). *************************************************************************/ static F32 getSyringePumpMeasRate( void ) { F32 result = syringePumpMeasRate.data; if ( OVERRIDE_KEY == syringePumpMeasRate.override ) { result = syringePumpMeasRate.ovData; } return result; } /*********************************************************************//** * @brief * The getSyringePumpPosition function gets the current syringe pump * position. * @details Inputs: syringePumpPosition * @details Outputs: none * @return the current syringe pump syringe position (in steps). *************************************************************************/ static S32 getSyringePumpPosition( void ) { S32 result = syringePumpPosition.data; if ( OVERRIDE_KEY == syringePumpPosition.override ) { result = syringePumpPosition.ovData; } return result; } /*********************************************************************//** * @brief * The getSyringePumpSyringeDetectorV function gets the current syringe pump * syringe detect signal. * @details Inputs: syringePumpMeasSyringeDetectionSwitch * @details Outputs: none * @return the current syringe pump syringe detect signal (in V). *************************************************************************/ static F32 getSyringePumpSyringeDetectorV( void ) { F32 result = syringePumpMeasSyringeDetectionSwitch.data; if ( OVERRIDE_KEY == syringePumpMeasSyringeDetectionSwitch.override ) { result = syringePumpMeasSyringeDetectionSwitch.ovData; } return result; } /*********************************************************************//** * @brief * The getSyringePumpHomeDetectorV function gets the current syringe pump * home detect signal. * @details Inputs: syringePumpMeasHome * @details Outputs: none * @return the current syringe pump home detect signal (in V). *************************************************************************/ static F32 getSyringePumpHomeDetectorV( void ) { F32 result = syringePumpMeasHome.data; if ( OVERRIDE_KEY == syringePumpMeasHome.override ) { result = syringePumpMeasHome.ovData; } return result; } /*********************************************************************//** * @brief * The getSyringePumpForceV function gets the current syringe pump force. * @details Inputs: syringePumpMeasForce * @details Outputs: none * @return the current syringe pump force (in V). *************************************************************************/ static F32 getSyringePumpForceV( void ) { F32 result = syringePumpMeasForce.data; if ( OVERRIDE_KEY == syringePumpMeasForce.override ) { result = syringePumpMeasForce.ovData; } return result; } /*********************************************************************//** * @brief * The getSyringePumpStatus function gets the current syringe pump status. * @details Inputs: syringePumpStatus * @details Outputs: none * @return the current syringe pump status. *************************************************************************/ static U08 getSyringePumpStatus() { U08 result = (U08)(syringePumpStatus.data & MASK_OFF_U32_MSBS); if ( OVERRIDE_KEY == syringePumpStatus.override ) { result = (U08)(syringePumpStatus.ovData & MASK_OFF_U32_MSBS); } return result; } /*********************************************************************//** * @brief * The getSyringePumpEncoderStatus function gets the current syringe pump * encoder status. * @details Inputs: syringePumpEncoderStatus * @details Outputs: none * @return the current syringe pump encoder status. *************************************************************************/ static U08 getSyringePumpEncoderStatus() { U08 result = (U08)(syringePumpEncoderStatus.data & MASK_OFF_U32_MSBS); if ( OVERRIDE_KEY == syringePumpEncoderStatus.override ) { result = (U08)(syringePumpEncoderStatus.ovData & MASK_OFF_U32_MSBS); } return result; } /*********************************************************************//** * @brief * The getSyringePumpADCReadCounter function gets the current syringe pump * ADC read counter. * @details Inputs: syringePumpADCReadCtr * @details Outputs: none * @return the current syringe pump ADC read counter. *************************************************************************/ static U08 getSyringePumpADCReadCounter() { U08 result = (U08)(syringePumpADCReadCtr.data & MASK_OFF_U32_MSBS); if ( OVERRIDE_KEY == syringePumpADCReadCtr.override ) { result = (U08)(syringePumpADCReadCtr.ovData & MASK_OFF_U32_MSBS); } return result; } /*********************************************************************//** * @brief * The getSyringePumpADCandDACStatus function gets the current syringe pump * ADC and DAC status reported by the FPGA. * @details Inputs: syringePumpADCandDACStatus * @details Outputs: none * @return the current syringe pump ADC and DAC status. *************************************************************************/ static U08 getSyringePumpADCandDACStatus() { U08 result = (U08)(syringePumpADCandDACStatus.data & MASK_OFF_U32_MSBS); if ( OVERRIDE_KEY == syringePumpADCandDACStatus.override ) { result = (U08)(syringePumpADCandDACStatus.ovData & MASK_OFF_U32_MSBS); } return result; } /*********************************************************************//** * @brief * The isSyringeDetected function determines whether a syringe is currently * detected. * @details Inputs: syringePumpMeasSyringeDetectionSwitch * @details Outputs: none * @return TRUE if syringe detected, FALSE if not *************************************************************************/ BOOL isSyringeDetected( void ) { BOOL result = FALSE; if ( getSyringePumpSyringeDetectorV() >= SYRINGE_PUMP_SYRINGE_DETECT_THRESHOLD_V ) { result = TRUE; } return result; } /*********************************************************************//** * @brief * The isSyringePumpHome function determines whether the syringe drive position * is at the home position. * @details Inputs: syringePumpMeasHome * @details Outputs: none * @return TRUE if home detected, FALSE if not *************************************************************************/ BOOL isSyringePumpHome( void ) { BOOL result = FALSE; if ( getSyringePumpHomeDetectorV() <= SYRINGE_PUMP_HOME_DETECT_THRESHOLD_V ) { result = TRUE; } return result; } /*********************************************************************//** * @brief * The isSyringePumpStopped function determines whether the syringe pump * is currently stopped. * @details Inputs: syringePumpState * @details Outputs: none * @return TRUE if syringe pump is currently stopped, FALSE if running. *************************************************************************/ BOOL isSyringePumpStopped( void ) { BOOL result = FALSE; if ( ( syringePumpState <= SYRINGE_PUMP_OFF_STATE ) || ( syringePumpState >= SYRINGE_PUMP_CONFIG_FORCE_SENSOR_STATE ) ) { result = TRUE; } return result; } /*********************************************************************//** * @brief * The isSyringePlungerFound function determines whether the syringe pump * plunger seek operation was completed. * @details Inputs: syringePumpPlungerFound * @details Outputs: none * @return TRUE if syringe plunger was found, FALSE if not. *************************************************************************/ BOOL isSyringePlungerFound( void ) { return syringePumpPlungerFound; } /*********************************************************************//** * @brief * The isSyringeVolumeAdequate function determines whether the syringe has * sufficient Heparin volume to complete the treatment per user settings. * Call this function after seek operation. * @details Inputs: syringeVolumeAdequate * @details Outputs: none * @return TRUE if syringe volume is sufficient to complete the treatment, FALSE if not. *************************************************************************/ BOOL isSyringeVolumeAdequate( void ) { return syringeVolumeAdequate; } /*********************************************************************//** * @brief * The isSyringePumpPrimed function determines whether the syringe pump * prime operation was completed. * @details Inputs: syringePumpPrimeCompleted * @details Outputs: none * @return TRUE if syringe pump prime is completed, FALSE if not. *************************************************************************/ BOOL isSyringePumpPrimed( void ) { return syringePumpPrimeCompleted; } /*********************************************************************//** * @brief * The execSyringePumpMonitor function executes the syringe pump monitor. * @details Inputs: FPGA syringe pump readings * @details Outputs: Alarm(s) may be triggered * @return none *************************************************************************/ static void execSyringePumpMonitor( void ) { F32 forceSensorBeforCal = 0.0; BOOL prevSyringeDetected = isSyringeDetected(); // Check if a new calibration is available if ( TRUE == isNewCalibrationRecordAvailable() ) { // Get the new calibration data and check its validity processCalibrationData(); } S32 encPosition = getFPGASyringePumpEncoderPosition(); // Get latest FPGA status syringePumpStatus.data = (U32)getFPGASyringePumpStatus(); syringePumpEncoderStatus.data = (U32)getFPGASyringePumpEncoderStatus(); syringePumpADCandDACStatus.data = (U32)getFPGASyringePumpADCandDACStatus(); syringePumpADCReadCtr.data = (U32)getFPGASyringePumpADCReadCounter(); // Get latest ADC data and convert to V syringePumpMeasHome.data = ( (F32)getFPGASyringePumpADCChannel2() * SYRINGE_PUMP_ADC_REF_V ) / SYRINGE_PUMP_ADC_FULL_SCALE_BITS; syringePumpMeasSyringeDetectionSwitch.data = ( (F32)getFPGASyringePumpADCChannel1() * SYRINGE_PUMP_ADC_REF_V ) / SYRINGE_PUMP_ADC_FULL_SCALE_BITS; // On transition from not detected to detected - clear syringe removed alarm condition if ( ( prevSyringeDetected != TRUE ) && ( TRUE == isSyringeDetected() ) ) { clearAlarmCondition( ALARM_ID_HD_SYRINGE_PUMP_SYRINGE_REMOVED ); } forceSensorBeforCal = ( (F32)getFPGASyringePumpADCChannel0() * SYRINGE_PUMP_ADC_REF_V ) / SYRINGE_PUMP_ADC_FULL_SCALE_BITS; syringePumpMeasForce.data = pow(forceSensorBeforCal, 4) * forceSensorCalRecord.hdHeparinForceSensor.fourthOrderCoeff + pow(forceSensorBeforCal, 3) * forceSensorCalRecord.hdHeparinForceSensor.thirdOrderCoeff + pow(forceSensorBeforCal, 2) * forceSensorCalRecord.hdHeparinForceSensor.secondOrderCoeff + forceSensorBeforCal * forceSensorCalRecord.hdHeparinForceSensor.gain + forceSensorCalRecord.hdHeparinForceSensor.offset; // Apply home offset to encoder position syringePumpLastPosition = getSyringePumpPosition(); syringePumpPosition.data = encPosition - syringePumpHomePositionOffset; // Calculate volume delivered from position syringePumpVolumeDelivered.data = (F32)(syringePumpPosition.data - syringePumpVolumeStartPosition) / SYRINGE_ENCODER_COUNTS_PER_ML; calcSafetyVolumeDelivered(); // Calculate measured rate (mL/hr) calcMeasRate(); #ifndef DISABLE_SYRINGE_PUMP_ALARMS // Get measured direction syringePumpControllerMeasuredDirection = ( ( getSyringePumpEncoderStatus() & SYRINGE_PUMP_ENCODER_DIRECTION_BIT ) != 0 ? MOTOR_DIR_REVERSE : MOTOR_DIR_FORWARD ); // Calculate direction from encoder position relative to last syringePumpEncoderMeasuredDirection = ( getSyringePumpPosition() - syringePumpLastPosition >= 0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); #endif // Check if syringe pump is on while BP is off { BOOL runWhileOff = ( ( ( SYRINGE_PUMP_HEP_BOLUS_STATE == syringePumpState ) || ( SYRINGE_PUMP_HEP_CONTINUOUS_STATE == syringePumpState ) ) && ( isBloodPumpRunning() != TRUE ) ); if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_RUNNING_WHILE_BP_OFF_ERROR, runWhileOff ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_RUNNING_WHILE_BP_OFF_ERROR, (U32)syringePumpState ); } } if ( syringePumpDACVrefWriteInProgress != TRUE ) { // Check ADC read is fresh (takes FPGA a while to configure ADC so don't check until after init/POST mode if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR, ( ( getCurrentOperationMode() > MODE_INIT ) && ( lastSyringePumpADCReadCtr == getSyringePumpADCReadCounter() ) ) ) ) { #ifndef DISABLE_SYRINGE_PUMP_ALARMS activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR ); #endif } lastSyringePumpADCReadCtr = getSyringePumpADCReadCounter(); // Check pump status if ( getSyringePumpStatus() != 0 ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_FAULT, (U32)getSyringePumpStatus() ); } } } /*********************************************************************//** * @brief * The execSyringePump function executes the syringe pump control state machine. * @details Inputs: syringePumpState * @details Outputs: syringePumpState * @return none *************************************************************************/ void execSyringePump( void ) { // Execute syringe pump monitor execSyringePumpMonitor(); // Execute syringe pump control state machine switch ( syringePumpState ) { case SYRINGE_PUMP_INIT_STATE: syringePumpState = handleSyringePumpInitState(); break; case SYRINGE_PUMP_OFF_STATE: syringePumpState = handleSyringePumpOffState(); break; case SYRINGE_PUMP_RETRACT_STATE: syringePumpState = handleSyringePumpRetractState(); break; case SYRINGE_PUMP_SEEK_STATE: syringePumpState = handleSyringePumpSeekState(); break; case SYRINGE_PUMP_PRIME_STATE: syringePumpState = handleSyringePumpPrimeState(); break; case SYRINGE_PUMP_HEP_BOLUS_STATE: syringePumpState = handleSyringePumpBolusState(); break; case SYRINGE_PUMP_HEP_CONTINUOUS_STATE: syringePumpState = handleSyringePumpContinuousState(); break; case SYRINGE_PUMP_CONFIG_FORCE_SENSOR_STATE: syringePumpState = handleSyringePumpCalibrateForceSensorState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_SYRINGE_INVALID_STATE, syringePumpState ) break; } resetSyringePumpRequestFlags(); // Publish syringe pump data on interval publishSyringePumpData(); } /*********************************************************************//** * @brief * The execSyringePumpSelfTest function executes the state machine for the * syringe pump self-test. * @details Inputs: none * @details Outputs: none * @return the current state of the BloodFlow self-test. *************************************************************************/ SELF_TEST_STATUS_T execSyringePumpSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; BOOL calStatus = processCalibrationData(); if ( TRUE == calStatus ) { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_SELF_TEST_FAILURE ); } return result; } /*********************************************************************//** * @brief * The handleSyringePumpInitState function handles the initialize state * of the syringe pump control state machine. * @details Inputs: none * @details Outputs: pump speed set to zero, ADC enabled, direction set to reverse * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpInitState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_OFF_STATE; // Set FPGA rate to zero setFPGASyringePumpStepToggleTime( SYRINGE_PUMP_MICROSTEP_TOGGLE_TIME_FOR_STOP ); // Set FPGA control bits for ADC/DAC setFPGASyringePumpADCandDACControlFlags( SYRINGE_PUMP_ADC_DAC_CONTROL_RD_DAC_ON_ADC | SYRINGE_PUMP_ADC_DAC_CONTROL_ENABLE_ADC ); // Set FPGA control bits for stepper motor (enable, no sleep, dir=FWD, ...) setFPGASyringePumpControlFlags( SYRINGE_PUMP_CONTROL_RUN_REVERSE ); return result; } /*********************************************************************//** * @brief * The handleSyringePumpOffState function handles the off state * of the syringe pump control state machine. * @details Inputs: syringePumpRetractRequested, syringePumpSeekRequested, * syringePumpPrimeRequested, syringePumpBolusRequested, syringePumpContinuousRequested, * syringePumpDACVrefSetRequested * @details Outputs: Pump speed and direction set if pump command initiated * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpOffState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_OFF_STATE; #ifndef DISABLE_SYRINGE_PUMP_ALARMS // Check position is not changing while stopped if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR, ( syringePumpLastPosition != getSyringePumpPosition() ) ) ) { activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR ); activateSafetyShutdown(); } #endif // Check for request flags if ( TRUE == syringePumpRetractRequested ) { result = SYRINGE_PUMP_RETRACT_STATE; } else if ( TRUE == syringePumpSeekRequested ) { result = SYRINGE_PUMP_SEEK_STATE; } else if ( TRUE == syringePumpPrimeRequested ) { result = SYRINGE_PUMP_PRIME_STATE; } else if ( TRUE == syringePumpBolusRequested ) { heparinDeliveryState = HEPARIN_STATE_INITIAL_BOLUS; result = SYRINGE_PUMP_HEP_BOLUS_STATE; } else if ( TRUE == syringePumpContinuousRequested ) { heparinDeliveryState = HEPARIN_STATE_DISPENSING; result = SYRINGE_PUMP_HEP_CONTINUOUS_STATE; } else if ( TRUE == syringePumpDACVrefSetRequested ) { U16 vRef = (U16)( ( syringePumpDACVref / SYRINGE_PUMP_ADC_REF_V ) * SYRINGE_PUMP_DAC_FULL_SCALE_BITS ); setFPGASyringePumpDACOutputLevel( vRef ); setFPGASyringePumpADCandDACControlFlags( SYRINGE_PUMP_ADC_DAC_CONTROL_ENABLE_DAC ); syringePumpDACVrefWriteInProgress = TRUE; result = SYRINGE_PUMP_CONFIG_FORCE_SENSOR_STATE; } // If we are starting an active pump state, set direction and calculate target toggle time to achieve desired rate if ( ( result != SYRINGE_PUMP_OFF_STATE ) && ( result != SYRINGE_PUMP_CONFIG_FORCE_SENSOR_STATE ) ) { if ( SYRINGE_PUMP_RETRACT_STATE == result ) { // Set fpga direction to reverse setFPGASyringePumpControlFlags( SYRINGE_PUMP_CONTROL_RUN_REVERSE ); } else { // Set fpga direction to forward setFPGASyringePumpControlFlags( SYRINGE_PUMP_CONTROL_RUN_FORWARD ); } // Calculate target FPGA rate from set rate in mL/hr converted to microstep toggle interval in uSec calcStepperToggleTimeForTargetRate( syringePumpSetRate ); setFPGASyringePumpStepToggleTime( syringePumpRampUpToggleTime ); // Reset stall detect variables syringePumpStallRetryCount = 0; syringePumpStallCtr = 0; } // Reset ramp up timer syringePumpRampTimerCtr = 1; return result; } /*********************************************************************//** * @brief * The handleSyringePumpRetractState function handles the retract state * of the syringe pump control state machine. * @details Inputs: syringePumpMeasHome.data * @details Outputs: Syringe pump ramped up to retract rate, alarm conditions checked * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpRetractState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_RETRACT_STATE; BOOL stopPump = FALSE; // Handle ramp up rampSyringePump(); // Stop retract when home position is detected if ( TRUE == isSyringePumpHome() ) { stopPump = TRUE; // Set position to zero after retract reaches home position syringePumpHomePositionOffset = getFPGASyringePumpEncoderPosition(); syringePumpPosition.data = 0; syringePumpVolumeStartPosition = 0; syringePumpPositionKnown = TRUE; // Zero volumes after retract syringePumpVolumeDelivered.data = 0.0; syringePumpSafetyVolumeDelivered = 0.0; // Reset flags syringePumpPlungerFound = FALSE; syringeVolumeAdequate = FALSE; syringePumpPrimeCompleted = FALSE; // Clear insufficient volume alarm condition in case we're retracting to allow user to resolve alarm clearAlarmCondition( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM ); } // If position known from prior retract, ensure we don't retract beyond minimum position else if ( ( TRUE == syringePumpPositionKnown ) && ( getSyringePumpPosition() < SYRINGE_PUMP_RETRACT_POS_MIN ) ) { stopPump = TRUE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_OVER_TRAVEL_ERROR, (U32)getSyringePumpPosition(), (U32)SYRINGE_PUMP_RETRACT_STATE ); } stopPump = checkForStall( stopPump ); stopPump = checkDirection( stopPump, MOTOR_DIR_REVERSE ); // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { stopSyringePump(); result = SYRINGE_PUMP_OFF_STATE; } return result; } /*********************************************************************//** * @brief * The handleSyringePumpSeekState function handles the seek plunger state * of the syringe pump control state machine. * @details Inputs: syringePumpMeasForce.data * @details Outputs: Syringe pump ramped up to seek rate, alarm conditions checked * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpSeekState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_SEEK_STATE; BOOL stopPump = FALSE; // Handle ramp up rampSyringePump(); // Is plunger contact detected? if ( getSyringePumpForceV() >= SYRINGE_FORCE_PLUNGER_THRESHOLD_V ) { S32 pos = getSyringePumpPosition(); F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); F32 contRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ); 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 ) - HEPARIN_BOLUS_TIME_HR; F32 txVolume = bolusVol + ( hepDurHr * contRate ); F32 syringeVol = ( SYRINGE_PUMP_EMPTY_POS - (F32)pos ) / SYRINGE_MICRO_STEPS_PER_ML; stopPump = TRUE; syringePumpPlungerFound = TRUE; syringePumpVolumeDelivered.data = 0.0; syringePumpSafetyVolumeDelivered = 0.0; syringePumpVolumeStartPosition = pos; // Check estimated syringe volume needed for treatment vs. volume detected - if insufficient for treatment needs, alarm if ( syringeVol >= txVolume ) { syringeVolumeAdequate = TRUE; } else { #ifndef DISABLE_SYRINGE_PUMP_ALARMS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM, syringeVol, txVolume ); #endif } } // Has syringe been removed? stopPump = checkSyringeRemoved( stopPump ); // Check max position > empty + 0.5 mL stopPump = checkMaxTravel( stopPump, SYRINGE_PUMP_EMPTY_POS + SYRINGE_PUMP_EMPTY_POS_MARGIN ); // Check pump direction stopPump = checkDirection( stopPump, MOTOR_DIR_FORWARD ); // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { stopSyringePump(); retractSyringePump(); result = SYRINGE_PUMP_OFF_STATE; } return result; } /*********************************************************************//** * @brief * The handleSyringePumpPrimeState function handles the prime state * of the syringe pump control state machine. * @details Inputs: syringePumpVolumeDelivered.data * @details Outputs: Syringe pump ramped up to prime rate, alarm conditions checked * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpPrimeState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_PRIME_STATE; BOOL stopPump = FALSE; // Handle ramp up rampSyringePump(); // Has prime volume been delivered? if ( getSyringePumpVolumeDelivered() >= SYRINGE_PUMP_PRIME_VOLUME_ML ) { stopPump = TRUE; syringePumpPrimeCompleted = TRUE; syringePumpVolumeDelivered.data = 0.0; syringePumpSafetyVolumeDelivered = 0.0; syringePumpVolumeStartPosition = syringePumpPosition.data; } // Has syringe been removed? stopPump = checkSyringeRemoved( stopPump ); // Check for occlusion stopPump = checkOcclusionOrEmpty( stopPump ); // Check position > max travel stopPump = checkMaxTravel( stopPump, syringePumpVolumeStartPosition + ( SYRINGE_PUMP_PRIME_VOLUME_ML * TEN_PCT_OVER_ALLOWANCE * SYRINGE_ENCODER_COUNTS_PER_ML ) ); // Check pump direction stopPump = checkDirection( stopPump, MOTOR_DIR_FORWARD ); // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { stopSyringePump(); result = SYRINGE_PUMP_OFF_STATE; } return result; } /*********************************************************************//** * @brief * The handleSyringePumpBolusState function handles the bolus delivery state * of the syringe pump control state machine. * @details Inputs: set bolus volume, syringePumpVolumeDelivered.data * @details Outputs: Syringe pump ramped up to set bolus rate, alarm conditions checked * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpBolusState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_HEP_BOLUS_STATE; BOOL stopPump = FALSE; F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); // Handle ramp up rampSyringePump(); // Is bolus completed? if ( getSyringePumpVolumeDelivered() >= bolusVol ) { stopPump = TRUE; } // Has syringe been removed? stopPump = checkSyringeRemoved( stopPump ); // Check volume vs. safety volume stopPump = checkVolumeVsSafetyVolume( stopPump, SYRINGE_PUMP_VOLUME_CHECK_MARGIN ); // Check for occlusion stopPump = checkOcclusionOrEmpty( stopPump ); // Check for commanded vs. meas. rate stopPump = checkMeasRate( stopPump, SYRINGE_PUMP_RATE_CHECK_MARGIN ); // Check position > max travel stopPump = checkMaxTravel( stopPump, syringePumpVolumeStartPosition + ( bolusVol * FIVE_PCT_OVER_ALLOWANCE * SYRINGE_ENCODER_COUNTS_PER_ML ) ); // Check pump direction stopPump = checkDirection( stopPump, MOTOR_DIR_FORWARD ); // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { stopSyringePump(); result = SYRINGE_PUMP_OFF_STATE; } return result; } /*********************************************************************//** * @brief * The handleSyringePumpContinuousState function handles the continuous state * of the syringe pump control state machine. * @details Inputs: none * @details Outputs: Syringe pump ramped up to set rate, alarm conditions checked * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpContinuousState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_HEP_CONTINUOUS_STATE; BOOL stopPump = FALSE; // Handle ramp up rampSyringePump(); // Has syringe been removed? stopPump = checkSyringeRemoved( stopPump ); // Check for occlusion stopPump = checkOcclusionOrEmpty( stopPump ); // Check position > empty + 0.5 mL stopPump = checkMaxTravel( stopPump, SYRINGE_PUMP_EMPTY_POS + SYRINGE_PUMP_EMPTY_POS_MARGIN ); // Check for commanded vs. meas. rate stopPump = checkMeasRate( stopPump, SYRINGE_PUMP_RATE_CHECK_MARGIN ); // Check volume vs. safety volume stopPump = checkVolumeVsSafetyVolume( stopPump, SYRINGE_PUMP_VOLUME_CHECK_MARGIN ); // Check pump direction stopPump = checkDirection( stopPump, MOTOR_DIR_FORWARD ); // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { stopSyringePump(); result = SYRINGE_PUMP_OFF_STATE; } return result; } /*********************************************************************//** * @brief * The handleSyringePumpCalibrateForceSensorState function handles the * calibrate force sensor state of the syringe pump control state machine. * of the syringe pump control state machine. * @details Inputs: DAC status * @details Outputs: syringePumpDACVrefWriteInProgress, ADC read mode restored * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpCalibrateForceSensorState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_CONFIG_FORCE_SENSOR_STATE; U08 adcDACStatus= getSyringePumpADCandDACStatus(); // Wait for DAC setting write to EEPROM to complete if ( ( adcDACStatus & SYRINGE_PUMP_ADC_DAC_ERROR_COUNT_DAC_WR_DONE ) != 0 ) { syringePumpDACVrefWriteInProgress = FALSE; // Switch back from DAC to ADC control setFPGASyringePumpADCandDACControlFlags( SYRINGE_PUMP_ADC_DAC_CONTROL_RD_DAC_ON_ADC | SYRINGE_PUMP_ADC_DAC_CONTROL_ENABLE_ADC ); // Back to off state result = SYRINGE_PUMP_OFF_STATE; } // Check DAC write error else if ( ( adcDACStatus & SYRINGE_PUMP_DAC_WRITE_ERROR_BIT ) != 0 ) { activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_DAC_WRITE_ERROR ); } return result; } /*********************************************************************//** * @brief * The checkDirection function checks the measured direction of the syringe * pump vs. the given expected direction. * @details Inputs: syringePumpMeasForce.data, syringePumpPosition.data * @details Outputs: alarm triggered if max force detected * @param stopPump flag passed in by caller indicating whether pump should be stopped * @param expDir expected direction of syringe pump * @return TRUE if pump should be stopped, FALSE if not *************************************************************************/ static BOOL checkDirection( BOOL stopPump, MOTOR_DIR_T expDir ) { BOOL result = stopPump; #ifndef DISABLE_SYRINGE_PUMP_ALARMS if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_ENCODER_DIRECTION_ERROR, ( syringePumpEncoderMeasuredDirection != expDir ) ) ) { result = TRUE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_ENCODER_DIRECTION_ERROR, (U32)syringePumpEncoderMeasuredDirection, (U32)syringePumpState ); } if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_CONTROLLER_DIRECTION_ERROR, ( syringePumpControllerMeasuredDirection != expDir ) ) ) { result = TRUE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_CONTROLLER_DIRECTION_ERROR, (U32)syringePumpControllerMeasuredDirection, (U32)syringePumpState ); } #endif return result; } /*********************************************************************//** * @brief * The checkOcclusionOrEmpty function checks the force sensor for excessive * pressure. Would indicate occlusion or jam or empty syringe. * @details Inputs: syringePumpMeasForce.data, syringePumpPosition.data * @details Outputs: alarm triggered if max force detected * @param stopPump flag passed in by caller indicating whether pump should be stopped * @return TRUE if pump should be stopped, FALSE if not *************************************************************************/ static BOOL checkOcclusionOrEmpty( BOOL stopPump ) { BOOL result = stopPump; F32 force = getSyringePumpForceV(); if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, ( force >= SYRINGE_FORCE_OCCLUSION_THRESHOLD_V ) ) ) { S32 pos = getSyringePumpPosition(); if ( fabs( pos - SYRINGE_PUMP_EMPTY_POS ) < SYRINGE_PUMP_EMPTY_POS_MARGIN ) { heparinDeliveryState = HEPARIN_STATE_EMPTY; SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SYRINGE_EMPTY, (F32)pos, force ) } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, (F32)pos, force ) } result = TRUE; } return result; } /*********************************************************************//** * @brief * The checkSyringeRemoved function checks whether the syringe has been removed. * This function should only be called from states that require the syringe to * be installed. * @details Inputs: syringePumpMeasSyringeDetectionSwitch.data * @details Outputs: alarm triggered if syringe not detected * @param stopPump flag passed in by caller indicating whether pump should be stopped * @return TRUE if pump should be stopped, FALSE if not *************************************************************************/ static BOOL checkSyringeRemoved( BOOL stopPump ) { BOOL result = stopPump; if ( FALSE == isSyringeDetected() ) { result = TRUE; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SYRINGE_REMOVED, (U32)syringePumpState ) } return result; } /*********************************************************************//** * @brief * The checkMaxTravel function checks whether a maximum travel (position) * has been exceeded. This threshold is state dependent so the calling function * must provide the maximum position to apply. * @details Inputs: syringePumpPosition.data * @details Outputs: alarm triggered if beyond given max position * @param stopPump flag passed in by caller indicating whether pump should be stopped * @param maxPos maximum position allowed in current state * @return TRUE if pump should be stopped, FALSE if not *************************************************************************/ static BOOL checkMaxTravel( BOOL stopPump, S32 maxPos ) { BOOL result = stopPump; S32 pos = getSyringePumpPosition(); if ( pos > ( SYRINGE_PUMP_EMPTY_POS - SYRINGE_PUMP_EMPTY_POS_MARGIN ) ) { result = TRUE; heparinDeliveryState = HEPARIN_STATE_EMPTY; SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SYRINGE_EMPTY, (F32)pos, getSyringePumpForceV() ) } else if ( pos > maxPos ) { result = TRUE; if ( syringePumpState != SYRINGE_PUMP_PRIME_STATE ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_OVER_TRAVEL_ERROR, (U32)pos, (U32)syringePumpState ); } } return result; } /*********************************************************************//** * @brief * The checkMeasRate function checks whether the measured rate is within a * given margin of the set rate (in mL/hr). * @details Inputs: syringePumpMeasRate.data, syringePumpSetRate * @details Outputs: alarm triggered if measured and set rates deviate too much * @param stopPump flag passed in by caller indicating whether pump should be stopped * @param pctMargin percent tolerance allowed between set and measured rate * @return TRUE if pump should be stopped, FALSE if not *************************************************************************/ static BOOL checkMeasRate( BOOL stopPump, F32 pctMargin ) { BOOL result = stopPump; #ifndef DISABLE_SYRINGE_PUMP_ALARMS F32 rate = getSyringePumpMeasRate(); F32 max = MAX( rate, syringePumpSetRate ); F32 min = MIN( rate, syringePumpSetRate ); F32 error = ( max > 0.0 ? ( 1.0 - fabs( min / max ) ) : 0.0 ); F32 delta = max - min; // Alarm on rate if off by more than 5% or 0.1 mL/hr, whichever is greater if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, ( ( error > pctMargin ) && ( delta > SYRINGE_PUMP_MAX_RATE_ERROR_ML_HR ) ) ) ) { result = TRUE; SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, syringePumpSetRate, rate ) } #endif return result; } /*********************************************************************//** * @brief * The checkVolumeVsSafetyVolume function checks whether the volume delivered * and the safety volume delivered have diverged too much. The threshold * is state dependent so the calling function must provide the tolerance (in +/- %) * to apply. * @details Inputs: syringePumpVolumeDelivered.data, syringePumpSafetyVolumeDelivered * @details Outputs: alarm triggered if measured and expected volume deviate too much * @param stopPump flag passed in by caller indicating whether pump should be stopped * @param pctMargin percent tolerance allowed between volume and safety volume * @return TRUE if pump should be stopped, FALSE if not *************************************************************************/ static BOOL checkVolumeVsSafetyVolume( BOOL stopPump, F32 pctMargin ) { BOOL result = stopPump; F32 vol = getSyringePumpVolumeDelivered(); F32 max = MAX( vol, syringePumpSafetyVolumeDelivered ); F32 min = MIN( vol, syringePumpSafetyVolumeDelivered ); F32 delta = max - min; F32 error = ( fabs( max ) < NEARLY_ZERO ? 0.0 : ( 1.0 - fabs( min / max ) ) ); // Alarm if volume delivered off by more than 5% or 0.1 mL, whichever is greater if ( ( error > pctMargin ) && ( delta > SYRINGE_PUMP_MAX_VOL_ERROR_ML ) ) { result = TRUE; SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_VOLUME_ERROR, vol, syringePumpSafetyVolumeDelivered ) } return result; } /*********************************************************************//** * @brief * The checkForStall function checks whether the syringe pump has stalled. * If stall detected, the ramp up will be restarted up to 3 times. * If cannot resolve the stall within 3 retries, a stall fault is triggered. * @details Inputs: syringePumpMeasRate.data, syringePumpStallCtr, syringePumpStallRetryCount * @details Outputs: syringePumpStallCtr, syringePumpStallRetryCount * @param stopPump flag passed in by caller indicating whether pump should be stopped * @return TRUE if pump should be stopped, FALSE if not *************************************************************************/ static BOOL checkForStall( BOOL stopPump ) { BOOL result = stopPump; // Check for stall if ( fabs( getSyringePumpMeasRate() ) < SYRINGE_PUMP_STALL_SPEED_THRESHOLD ) { if ( ++syringePumpStallCtr >= SYRINGE_PUMP_RAMP_STALL_TIME ) { if ( ++syringePumpStallRetryCount <= SYRINGE_PUMP_RAMP_STALL_RETRIES ) { syringePumpSetToggleTime++; // lower target rate (by increasing time between steps) syringePumpRampTimerCtr = 0; // restart ramp syringePumpRampUpToggleTime = SYRINGE_PUMP_START_RAMP_SPEED; syringePumpStallCtr = 0; // reset stall counter } else { result = TRUE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_STALL, (U32)getSyringePumpPosition(), (U32)syringePumpState ); } } } else { syringePumpStallCtr = 0; } return result; } /*********************************************************************//** * @brief * The rampSyringePump function handles the ramp-up for the syringe pump. * @details Inputs: syringePumpRampTimerCtr, syringePumpSetToggleTime * @details Outputs: syringePumpRampUpToggleTime * @return none *************************************************************************/ static void rampSyringePump( void ) { // Ramp up syringe pump toward target speed syringePumpRampTimerCtr++; if ( syringePumpRampUpToggleTime > syringePumpSetToggleTime ) { syringePumpRampUpToggleTime = (U32)((F32)SYRINGE_PUMP_START_RAMP_SPEED / (F32)( ( syringePumpRampTimerCtr * syringePumpRampTimerCtr * syringePumpRampTimerCtr ) / SYRINGE_PUMP_RAMP_DIVISOR ) ); if ( syringePumpRampUpToggleTime > syringePumpSetToggleTime ) { setFPGASyringePumpStepToggleTime( syringePumpRampUpToggleTime ); } else { setFPGASyringePumpStepToggleTime( syringePumpSetToggleTime ); } } } /*********************************************************************//** * @brief * The calcStepperToggleTimeForTargetRate function calculates the stepper * toggle period for a given rate. * @details Inputs: none * @details Outputs: syringePumpSetToggleTime, syringePumpRampUpToggleTime * @param rate the rate (in mL/hr) to calculate stepper toggle period for * @return none *************************************************************************/ static void calcStepperToggleTimeForTargetRate( F32 rate ) { F64 temp; F32 conv; // Convert given rate to stepper toggle period temp = (F64)rate * SYRINGE_MICRO_STEPS_PER_ML; // = uSteps/hr temp /= (F64)( MIN_PER_HOUR * SEC_PER_MIN); // = uSteps/sec temp /= MICRO_SECONDS_PER_SECOND; // = uSteps/uSec conv = (F32)temp * SYRINGE_TOGGLES_PER_STEP; // = toggles/uSec conv = 1.0 / conv; // = uSec/toggle // Set stepper toggle time to calculated value syringePumpSetToggleTime = FLOAT_TO_INT_WITH_ROUND( conv ); // Set stepper ramp toggle time to initial ramp up speed initially syringePumpRampUpToggleTime = SYRINGE_PUMP_START_RAMP_SPEED; // Reset ramp stall timer and retry counters syringePumpStallCtr = 0; syringePumpStallRetryCount = 0; } /*********************************************************************//** * @brief * The calcMeasRate function calculates the measured rate from a given delta * position in last 1 second. * @details Inputs: syringePumpLastPositions[], syringePumpSpeedCalcTimerCounter * @details Outputs: syringePumpMeasRate, syringePumpSpeedCalcTimerCounter * @return none *************************************************************************/ static void calcMeasRate( void ) { if ( ++syringePumpSpeedCalcTimerCounter >= SYRINGE_PUMP_SPEED_CALC_INTERVAL ) { S32 pos = getSyringePumpPosition(); U32 nextIdx = INC_WRAP( syringePumpMotorSpeedCalcIdx, 0, SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN - 1 ); S32 countsPerSec = pos - syringePumpLastPositions[ syringePumpMotorSpeedCalcIdx ]; // Calc delta between pos 1 second ago and pos now S32 countsPerHr = countsPerSec * ( MIN_PER_HOUR * SEC_PER_MIN); F32 mLPerHr = (F32)((F64)countsPerHr / (F64)SYRINGE_ENCODER_COUNTS_PER_ML); // Set latest measured rate syringePumpMeasRate.data = mLPerHr; // Update last position for next time syringePumpLastPositions[ syringePumpMotorSpeedCalcIdx ] = pos; syringePumpMotorSpeedCalcIdx = nextIdx; syringePumpSpeedCalcTimerCounter = 0; } } /*********************************************************************//** * @brief * The calcSafetyVolumeDelivered function calculates the safety volume from * commanded rate over time (last 10 ms). * @details Inputs: syringePumpSetRate * @details Outputs: syringePumpSafetyVolumeDelivered * @return none *************************************************************************/ static void calcSafetyVolumeDelivered( void ) { syringePumpSafetyVolumeDelivered += ( syringePumpSetRate / ( MIN_PER_HOUR * SEC_PER_MIN * ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ) ); } /*********************************************************************//** * @brief * The publishSyringePumpData function publishes syringe pump data at the * set interval. * @details Inputs: latest syringe pump data, syringePumpDataPublicationTimerCounter * @details Outputs: Syringe pump data are published to CAN bus. * @return none *************************************************************************/ static void publishSyringePumpData( void ) { // Publish syringe pump data on interval if ( ++syringePumpDataPublicationTimerCounter >= getU32OverrideValue( &syringePumpDataPublishInterval ) ) { SYRINGE_PUMP_DATA_PAYLOAD_T data; data.syringePumpMeasForce = getSyringePumpForceV(); data.syringePumpMeasHome = getSyringePumpHomeDetectorV(); data.syringePumpMeasRate = getSyringePumpMeasRate(); data.syringePumpMeasSwitch = getSyringePumpSyringeDetectorV(); data.syringePumpPosition = getSyringePumpPosition(); data.syringePumpSetRate = syringePumpSetRate; data.syringePumpState = (U32)syringePumpState; data.heparinDeliveryState = (U32)heparinDeliveryState; data.syringePumpVolumeDelivered = getSyringePumpVolumeDelivered(); data.syringePumpSafetyVolume = syringePumpSafetyVolumeDelivered; data.syringePumpStatus = ( (U32)getSyringePumpStatus() << SHIFT_24_BITS ) | ( (U32)getSyringePumpEncoderStatus() << SHIFT_16_BITS_FOR_WORD_SHIFT ) | ( (U32)getSyringePumpADCandDACStatus() << SHIFT_8_BITS_FOR_BYTE_SHIFT ) | ( (U32)getSyringePumpADCReadCounter() ); broadcastData( MSG_ID_HD_SYRINGE_PUMP_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( SYRINGE_PUMP_DATA_PAYLOAD_T ) ); broadcastData( MSG_ID_HD_HEPARIN_DATA_BROADCAST, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data.syringePumpVolumeDelivered, sizeof( F32 ) ); syringePumpDataPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The processCalibrationData function gets the calibration data and makes * sure it is valid by checking the calibration date. The calibration date * should not be 0. * @details Inputs: none * @details Outputs: forceSensorCalRecord * @return TRUE if the calibration record is valid, otherwise FALSE *************************************************************************/ static BOOL processCalibrationData( void ) { BOOL status = TRUE; // Get the calibration record from NVDataMgmt HD_HEPARIN_FORCE_SENSOR_CAL_RECORD_T calData = getHDHeparinForceSensorCalibrationRecord(); // Check if the calibration data that was received from NVDataMgmt is legitimate // The calibration date item should not be zero. If the calibration date is 0, // then the heparin force sensors data is not stored in the NV memory or it was corrupted. if ( 0 == calData.hdHeparinForceSensor.calibrationTime ) { #ifndef SKIP_CAL_CHECK activateAlarmNoData( ALARM_ID_HD_HEPARIN_FORCE_SENSOR_INVALID_CAL_RECORD ); status = FALSE; #endif } // The calibration data was valid, update the local copy forceSensorCalRecord.hdHeparinForceSensor.fourthOrderCoeff = calData.hdHeparinForceSensor.fourthOrderCoeff; forceSensorCalRecord.hdHeparinForceSensor.thirdOrderCoeff = calData.hdHeparinForceSensor.thirdOrderCoeff; forceSensorCalRecord.hdHeparinForceSensor.secondOrderCoeff = calData.hdHeparinForceSensor.secondOrderCoeff; forceSensorCalRecord.hdHeparinForceSensor.gain = calData.hdHeparinForceSensor.gain; forceSensorCalRecord.hdHeparinForceSensor.offset = calData.hdHeparinForceSensor.offset; return status; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetSyringePumpDataPublishIntervalOverride function overrides the * syringe pump data publish interval. * @details Inputs: none * @details Outputs: syringePumpDataPublishInterval * @param value override syringe pump data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_PRIORITY_INTERVAL; result = TRUE; syringePumpDataPublishInterval.ovData = intvl; syringePumpDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpDataPublishIntervalOverride function resets the override * of the syringe pump data publish interval. * @details Inputs: none * @details Outputs: syringePumpDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpDataPublishInterval.override = OVERRIDE_RESET; syringePumpDataPublishInterval.ovData = syringePumpDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSyringePumpOperationRequest function requests a given syringe pump * operation. * @details Inputs: none * @details Outputs: pump operation request is handled * @param opParams record containing the requested operation and its parameters * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSyringePumpOperationRequest( SYRINGE_PUMP_OP_PAYLOAD_T opParams ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { SYRINGE_PUMP_OPERATION_T op = (SYRINGE_PUMP_OPERATION_T)(opParams.syringePumpOp); switch ( op ) { case SYRINGE_PUMP_OP_STOP: stopSyringePump(); result = TRUE; break; case SYRINGE_PUMP_OP_RETRACT: result = retractSyringePump(); break; case SYRINGE_PUMP_OP_SEEK: result = seekSyringePlunger(); break; case SYRINGE_PUMP_OP_PRIME: result = primeSyringePump(); break; case SYRINGE_PUMP_OP_BOLUS: setTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME, opParams.volume ); result = startHeparinBolus(); break; case SYRINGE_PUMP_OP_CONTINUOUS: setTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE, opParams.rate ); result = startHeparinContinuous(); break; default: // Ok, just ignore and we will return FALSE rejecting request break; } } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpMeasuredRateOverride function overrides the measured * rate of the syringe pump. * @details Inputs: none * @details Outputs: syringePumpMeasRate * @param value override syringe pump measured rate with this value (in mL/hr) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpMeasuredRateOverride( F32 value ) { BOOL result = FALSE; if ( ( TRUE == isTestingActivated() ) && ( value <= SYRINGE_PUMP_MAX_RATE ) ) { result = TRUE; syringePumpMeasRate.ovData = value; syringePumpMeasRate.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpMeasuredRateOverride function resets the override * of the syringe pump measured rate. * @details Inputs: none * @details Outputs: syringePumpMeasRate * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpMeasuredRateOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpMeasRate.override = OVERRIDE_RESET; syringePumpMeasRate.ovData = syringePumpMeasRate.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpMeasuredForceOverride function overrides the measured * force analog signal of the syringe pump. * @details Inputs: none * @details Outputs: syringePumpMeasForce * @param value override syringe pump measured force signal with this value (in V) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpMeasuredForceOverride( F32 value ) { BOOL result = FALSE; if ( ( TRUE == isTestingActivated() ) && ( value >= 0.0 ) && ( value <= SYRINGE_PUMP_ADC_REF_V ) ) { result = TRUE; syringePumpMeasForce.ovData = value; syringePumpMeasForce.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpMeasuredForceOverride function resets the override * of the syringe pump measured force analog signal. * @details Inputs: none * @details Outputs: syringePumpMeasForce * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpMeasuredForceOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpMeasForce.override = OVERRIDE_RESET; syringePumpMeasForce.ovData = syringePumpMeasForce.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpMeasuredSyringeDetectOverride function overrides the measured * syringe detect analog signal of the syringe pump. * @details Inputs: none * @details Outputs: syringePumpMeasSyringeDetectionSwitch * @param value override syringe pump measured syringe detection signal with this value (in V) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpMeasuredSyringeDetectOverride( F32 value ) { BOOL result = FALSE; if ( ( TRUE == isTestingActivated() ) && ( value >= 0.0 ) && ( value <= SYRINGE_PUMP_ADC_REF_V ) ) { result = TRUE; syringePumpMeasSyringeDetectionSwitch.ovData = value; syringePumpMeasSyringeDetectionSwitch.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpMeasuredSyringeDetectOverride function resets the override * of the syringe pump measured syringe detect analog signal. * @details Inputs: none * @details Outputs: syringePumpMeasSyringeDetectionSwitch * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpMeasuredSyringeDetectOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpMeasSyringeDetectionSwitch.override = OVERRIDE_RESET; syringePumpMeasSyringeDetectionSwitch.ovData = syringePumpMeasSyringeDetectionSwitch.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpMeasuredHomeOverride function overrides the measured * home analog signal of the syringe pump. * @details Inputs: none * @details Outputs: syringePumpMeasHome * @param value override syringe pump measured home signal with this value (in V) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpMeasuredHomeOverride( F32 value ) { BOOL result = FALSE; if ( ( TRUE == isTestingActivated() ) && ( value >= 0.0 ) && ( value <= SYRINGE_PUMP_ADC_REF_V ) ) { result = TRUE; syringePumpMeasHome.ovData = value; syringePumpMeasHome.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpMeasuredHomeOverride function resets the override * of the syringe pump measured home analog signal. * @details Inputs: none * @details Outputs: syringePumpMeasHome * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpMeasuredHomeOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpMeasHome.override = OVERRIDE_RESET; syringePumpMeasHome.ovData = syringePumpMeasHome.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpMeasuredPositionOverride function overrides the measured * position of the syringe pump. * @details Inputs: none * @details Outputs: syringePumpPosition * @param value override syringe pump measured position with this value (in encoder counts) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpMeasuredPositionOverride( S32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpPosition.ovData = value; syringePumpPosition.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpMeasuredPositionOverride function resets the override * of the syringe pump measured position. * @details Inputs: none * @details Outputs: syringePumpPosition * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpMeasuredPositionOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpPosition.override = OVERRIDE_RESET; syringePumpPosition.ovData = syringePumpPosition.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpMeasuredVolumeOverride function overrides the measured * rate of the syringe pump measured volume delivered. * @details Inputs: none * @details Outputs: syringePumpVolumeDelivered * @param value override syringe pump measured volume with this value (in mL) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpMeasuredVolumeOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpVolumeDelivered.ovData = value; syringePumpVolumeDelivered.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpMeasuredVolumeOverride function resets the override * of the syringe pump measured volume delivered. * @details Inputs: none * @details Outputs: syringePumpVolumeDelivered * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpMeasuredVolumeOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpVolumeDelivered.override = OVERRIDE_RESET; syringePumpVolumeDelivered.ovData = syringePumpVolumeDelivered.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpStatus function overrides the syringe pump * status. * @details Inputs: none * @details Outputs: syringePumpStatus * @param status override syringe pump status with this value * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpStatus( U32 status ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpStatus.ovData = status; syringePumpStatus.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpStatus function resets the override of the * syringe pump status. * @details Inputs: none * @details Outputs: syringePumpStatus * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpStatus( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpStatus.override = OVERRIDE_RESET; syringePumpStatus.ovData = syringePumpStatus.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpEncoderStatus function overrides the syringe * pump encoder status. * @details Inputs: none * @details Outputs: syringePumpEncoderStatus * @param status override syringe pump encoder status with this value * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpEncoderStatus( U32 status ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpEncoderStatus.ovData = status; syringePumpEncoderStatus.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpEncoderStatus function resets the override * of the syringe pump encoder status. * @details Inputs: none * @details Outputs: syringePumpEncoderStatus * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpEncoderStatus( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpEncoderStatus.override = OVERRIDE_RESET; syringePumpEncoderStatus.ovData = syringePumpEncoderStatus.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpADCandDACStatus function overrides the syringe * pump ADC and DAC status. * @details Inputs: none * @details Outputs: syringePumpADCandDACStatus * @param status override syringe pump ADC and DAC status with this value * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpADCandDACStatus( U32 status ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpADCandDACStatus.ovData = status; syringePumpADCandDACStatus.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpADCandDACStatus function resets the override * of the syringe pump ADC and DAC status. * @details Inputs: none * @details Outputs: syringePumpADCandDACStatus * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpADCandDACStatus( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpADCandDACStatus.override = OVERRIDE_RESET; syringePumpADCandDACStatus.ovData = syringePumpADCandDACStatus.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetSyringePumpADCReadCounter function overrides the syringe * pump ADC read counter. * @details Inputs: none * @details Outputs: syringePumpADCReadCtr * @param ctr override syringe pump ADC read counter with this value * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetSyringePumpADCReadCounter( U32 ctr ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpADCReadCtr.ovData = ctr; syringePumpADCReadCtr.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetSyringePumpADCReadCounter function resets the override * of the syringe pump ADC read counter. * @details Inputs: none * @details Outputs: syringePumpADCReadCtr * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetSyringePumpADCReadCounter( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; syringePumpADCReadCtr.override = OVERRIDE_RESET; syringePumpADCReadCtr.ovData = syringePumpADCReadCtr.ovInitData; } return result; } /**@}*/