/************************************************************************** * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file SyringePump.c * * @author (last) Sean Nash * @date (last) 02-Mar-2021 * * @author (original) Sean Nash * @date (original) 02-Mar-2021 * ***************************************************************************/ #include "AlarmMgmt.h" #include "FPGA.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" #include "PersistentAlarm.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_MM 14.02 ///< Inner diameter (in mm) of supported BD syringe. #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 SYRINGE_PUMP_RETRACT_RATE 10800.0 ///< Retract rate is 15 mL/ 5 s = 3 mL/s = 10,800 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 MAX_SYRINGE_PUMP_RAMP_RATE 10000.0 ///< Maximum ramp rate (micro steps per second) for syringe pump. TODO - get from Systems #define SYRINGE_OCCLUSION_THRESHOLD_V 2.5 ///< Force sensor threshold (in V) above which an occlusion is detected. TODO - get from Systems #define SYRINGE_PUMP_RATE_ALARM_PERSISTENCE ( 1 * MS_PER_SECOND ) ///< Alarm persistence period for syringe pump speed check alarms. #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 ///< Syringe pump DAC has has 4096 full scale counts (12-bit). #define SYRINGE_PUMP_SYRINGE_DETECT_THRESHOLD_V 2.0 ///< Syringe pump syringe detected threshold (in V). #define SYRINGE_PUMP_HOME_DETECT_THRESHOLD_V 2.5 ///< Syringe pump home detected threshold (in V). #define SYRINGE_PUMP_PLUNGER_DETECT_THRESHOLD_V 2.0 ///< Syringe pump plunger detection force threshold (in V). #define SYRINGE_PUMP_PRIME_VOLUME_ML 0.353 ///< Target syringe prime volume (in mL). // 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; /// 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; /// Defined states for the pressure and occlusion self-test state machine. typedef enum Syringe_Pump_Self_Test_States { SYRINGE_PUMP_SELF_TEST_STATE_START = 0, ///< Self test start state. SYRINGE_PUMP_TEST_STATE_IN_PROGRESS, ///< Self test in progress state. SYRINGE_PUMP_TEST_STATE_COMPLETE, ///< Self test completed state. NUM_OF_SYRINGE_PUMP_SELF_TEST_STATES ///< Number of syringe pump self-test states. } SYRINGE_PUMP_SELF_TEST_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. /// 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 F32 syringePumpSetRate; ///< Set rate for syringe pump (in mL/hr). static F32 syringePumpSetSpeed; ///< Set speed for syringe pump (in steps/sec). static F32 syringePumpMeasSpeed; ///< Measured speed for syringe pump (in steps/sec). static F32 syringePumpSafetyVolumeDelivered; ///< Calculated volume (in mL) (from set rate over time). static S32 syringePumpHomePositionOffset; ///< FPGA reported position when at home postion. static BOOL syringePumpHasBeenHomed; ///< Flag indicates whether syringe pump has been homed at least once (indicates position is known). static BOOL syringePumpRetractRequested; ///< Flag indicates a retract operation is requested. static BOOL syringePumpPrimeRequested; ///< Flag indicates plunger seek and Heparin prime operations are requested. static BOOL syringePumpSeekToPrimeRequested; ///< Flag indicates plunger seek finished, pump stopped, now requesting prime operation. 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 U08 lastSyringePumpADCReadCtr; ///< Remember last ADC read counter to check new reads are fresh. static SYRINGE_PUMP_SELF_TEST_STATE_T syringePumpSelfTestState; ///< Current syringe pump self-test state. static U32 syringePumpSelfTestTimerCount; ///< Timer counter for syringe pump self-test. // TODO - test code static U32 xTimerCtr; // ********** private function prototypes ********** static void resetSyringePumpRequestFlags( void ); static void execSyringePumpMonitor( 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 publishSyringePumpData( void ); static U32 getPublishSyringePumpDataInterval( void ); static S32 getSyringePumpPosition( void ); static F32 getSyringePumpVolumeDelivered( void ); static F32 getSyringePumpMeasRate( void ); static F32 getSyringePumpSyringeDetectorV( void ); static F32 getSyringePumpHomeDetectorV( void ); static F32 getSyringePumpForceV( void ); /*********************************************************************//** * @brief * The initSyringePump function initializes the syringe pump module. * @details Inputs: none * @details Outputs: syringe pump module initialized. * @return none *************************************************************************/ void initSyringePump( void ) { syringePumpState = SYRINGE_PUMP_INIT_STATE; syringePumpSelfTestState = SYRINGE_PUMP_SELF_TEST_STATE_START; syringePumpSetRate = 0.0; syringePumpSetSpeed = 0.0; syringePumpMeasSpeed = 0.0; syringePumpSafetyVolumeDelivered = 0.0; syringePumpHomePositionOffset = 0; syringePumpHasBeenHomed = FALSE; syringePumpDataPublicationTimerCounter = 0; syringePumpSelfTestTimerCount = 0; lastSyringePumpADCReadCtr = 0; // Reset request flags resetSyringePumpRequestFlags(); } /*********************************************************************//** * @brief * The resetSyringePumpRequestFlags function resets request flags. * @details Inputs: none * @details Outputs: syringePumpSetRate, syringePumpRetractRequested * @return TRUE if request accepted, FALSE if not *************************************************************************/ static void resetSyringePumpRequestFlags( void ) { syringePumpRetractRequested = FALSE; syringePumpPrimeRequested = FALSE; syringePumpSeekToPrimeRequested = FALSE; syringePumpBolusRequested = FALSE; syringePumpContinuousRequested = FALSE; } /*********************************************************************//** * @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; } /*********************************************************************//** * @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 ) { if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( FALSE == isSyringeDetected() ) ) { syringePumpSetRate = 0.1; // SYRINGE_PUMP_RETRACT_RATE; syringePumpRetractRequested = TRUE; } return syringePumpRetractRequested; } /*********************************************************************//** * @brief * The primeSyringePump function requests plunger seek and prime operations. * @details Inputs: syringePumpState * @details Outputs: syringePumpSetRate, syringePumpBolusRequested * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL primeSyringePump( void ) { if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( TRUE == isSyringeDetected() ) && ( TRUE == isSyringePumpHome() ) ) { syringePumpSetRate = 0.1; //SYRINGE_PUMP_SEEK_RATE; syringePumpPrimeRequested = TRUE; } return syringePumpPrimeRequested; } /*********************************************************************//** * @brief * The startHeparinBolus function requests Heparin bolus delivery. * @details Inputs: syringePumpState * @details Outputs: syringePumpSetRate, syringePumpBolusRequested * @param flowRate desired bolus flow rate (in mL/hr) * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL startHeparinBolus( F32 flowRate ) { if ( ( flowRate >= MIN_HEPARIN_BOLUS_RATE ) && ( flowRate <= MAX_HEPARIN_BOLUS_RATE ) && ( TRUE == isSyringeDetected() ) && ( FALSE == isSyringePumpHome() ) ) { if ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) { syringePumpSetRate = flowRate; syringePumpBolusRequested = TRUE; } } else { // TODO - s/w fault } return syringePumpBolusRequested; } /*********************************************************************//** * @brief * The startHeparinContinuous function requests Heparin continuous delivery. * @details Inputs: syringePumpState * @details Outputs: syringePumpSetRate, syringePumpContinuousRequested * @param flowRate desired flow rate (in mL/hr) * @return TRUE if request accepted, FALSE if not *************************************************************************/ BOOL startHeparinContinuous( F32 flowRate ) { if ( ( flowRate >= MIN_HEPARIN_CONTINUOUS_RATE ) && ( flowRate <= MAX_HEPARIN_CONTINUOUS_RATE ) && ( TRUE == isSyringeDetected() ) && ( FALSE == isSyringePumpHome() ) ) { if ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) { syringePumpSetRate = flowRate; syringePumpContinuousRequested = TRUE; } } else { // TODO - s/w fault } return syringePumpContinuousRequested; } /*********************************************************************//** * @brief * The getPublishSyringePumpDataInterval function gets the syringe pump data * publication interval. * @details Inputs: syringePumpDataPublishInterval * @details Outputs: none * @return the current syringe pump data publication interval (in task intervals). *************************************************************************/ static U32 getPublishSyringePumpDataInterval( void ) { U32 result = syringePumpDataPublishInterval.data; if ( OVERRIDE_KEY == syringePumpDataPublishInterval.override ) { result = syringePumpDataPublishInterval.ovData; } return result; } /*********************************************************************//** * @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). *************************************************************************/ static 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 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 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 ) { S32 encPosition = getFPGASyringePumpEncoderPosition(); U08 pmpStatus = getFPGASyringePumpStatus(); U08 encStatus = getFPGASyringePumpEncoderStatus(); U08 adcReadCtr = getFPGASyringePumpADCReadCounter(); U08 adcDACStatus= getFPGASyringePumpADCandDACStatus(); // 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; syringePumpMeasForce.data = ( (F32)getFPGASyringePumpADCChannel0() * SYRINGE_PUMP_ADC_REF_V ) / SYRINGE_PUMP_ADC_FULL_SCALE_BITS; // apply home offset to encoder position syringePumpPosition.data = encPosition - syringePumpHomePositionOffset; // check ADC read is fresh if ( lastSyringePumpADCReadCtr == adcReadCtr ) { // TODO - fault } lastSyringePumpADCReadCtr = adcReadCtr; } /*********************************************************************//** * @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, 0, syringePumpState ) // TODO - replace 0 with appropriate enum break; } // Publish syringe pump data on interval publishSyringePumpData(); } /*********************************************************************//** * @brief * The handleSyringePumpInitState function handles the pres/occl initialize state * of the syringe pump control state machine. * @details Inputs: TBD * @details Outputs: TBD * @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 pres/occl initialize state * of the syringe pump control state machine. * @details Inputs: TBD * @details Outputs: TBD * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpOffState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_OFF_STATE; // TODO - check position is not changing while stopped // Check for request flags if ( TRUE == syringePumpRetractRequested ) { result = SYRINGE_PUMP_RETRACT_STATE; } else if ( TRUE == syringePumpPrimeRequested ) { result = SYRINGE_PUMP_SEEK_STATE; } else if ( TRUE == syringePumpSeekToPrimeRequested ) { result = SYRINGE_PUMP_PRIME_STATE; syringePumpSetRate = SYRINGE_PUMP_PRIME_RATE; } else if ( TRUE == syringePumpBolusRequested ) { result = SYRINGE_PUMP_HEP_BOLUS_STATE; } else if ( TRUE == syringePumpContinuousRequested ) { result = SYRINGE_PUMP_HEP_CONTINUOUS_STATE; } if ( result != SYRINGE_PUMP_OFF_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 ); } // Set fpga rate to set rate converted to microstep interval in uSec/2 setFPGASyringePumpStepToggleTime( syringePumpSetRate ); // TODO - convert set rate (mL/hr) to miscrostep toggle time } // TODO - test code xTimerCtr = 0; return result; } /*********************************************************************//** * @brief * The handleSyringePumpRetractState function handles the pres/occl initialize state * of the syringe pump control state machine. * @details Inputs: TBD * @details Outputs: TBD * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpRetractState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_RETRACT_STATE; // TODO - timer is test code, 3.0 is placeholder for home threshold, 1.0 is placeholder for syringe detected threshold if ( ( ++xTimerCtr > 100 ) || ( getSyringePumpHomeDetectorV() > 3.0 ) || ( getSyringePumpSyringeDetectorV() < 1.0 ) ) { // Retract reached home setFPGASyringePumpStepToggleTime( SYRINGE_PUMP_MICROSTEP_TOGGLE_TIME_FOR_STOP ); if ( TRUE == isSyringePumpHome() ) { syringePumpHomePositionOffset = getFPGASyringePumpEncoderPosition(); syringePumpPosition.data = 0; syringePumpVolumeDelivered.data = 0.0; syringePumpHasBeenHomed = TRUE; } else { // TODO - alarm } result = SYRINGE_PUMP_OFF_STATE; } else if ( TRUE == isSyringeDetected() ) { stopSyringePump(); } return result; } /*********************************************************************//** * @brief * The handleSyringePumpSeekState function handles the pres/occl initialize state * of the syringe pump control state machine. * @details Inputs: TBD * @details Outputs: TBD * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpSeekState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_SEEK_STATE; if ( getSyringePumpForceV() <= SYRINGE_PUMP_PLUNGER_DETECT_THRESHOLD_V ) { stopSyringePump(); syringePumpVolumeDelivered.data = 0.0; syringePumpSeekToPrimeRequested = TRUE; result = SYRINGE_PUMP_OFF_STATE; } return result; } /*********************************************************************//** * @brief * The handleSyringePumpPrimeState function handles the pres/occl initialize state * of the syringe pump control state machine. * @details Inputs: TBD * @details Outputs: TBD * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpPrimeState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_PRIME_STATE; if ( getSyringePumpVolumeDelivered() >= SYRINGE_PUMP_PRIME_VOLUME_ML ) { stopSyringePump(); syringePumpVolumeDelivered.data = 0.0; result = SYRINGE_PUMP_OFF_STATE; } return result; } /*********************************************************************//** * @brief * The handleSyringePumpBolusState function handles the pres/occl initialize state * of the syringe pump control state machine. * @details Inputs: TBD * @details Outputs: TBD * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpBolusState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_HEP_BOLUS_STATE; return result; } //static S32 getSyringePumpPosition( void ); //static F32 getSyringePumpVolumeDelivered( void ); //static F32 getSyringePumpMeasRate( void ); //static F32 getSyringePumpSyringeDetectorV( void ); //static F32 getSyringePumpHomeDetectorV( void ); //static F32 getSyringePumpForceV( void ); //void setFPGASyringePumpControlFlags( U08 bitFlags ); //void setFPGASyringePumpADCandDACControlFlags( U08 bitFlags ); //void setFPGASyringePumpDACOutputLevel( U16 counts ); //void setFPGASyringePumpStepToggleTime( U32 microSeconds ); //U08 getFPGASyringePumpStatus( void ); //U08 getFPGASyringePumpADCReadCounter( void ); //U08 getFPGASyringePumpADCandDACStatus( void ); //U08 getFPGASyringePumpEncoderStatus( void ); //U32 getFPGASyringePumpEncoderPosition( void ); //U16 getFPGASyringePumpADCChannel0( void ); //U16 getFPGASyringePumpADCChannel1( void ); //U16 getFPGASyringePumpADCChannel2( void ); //U16 getFPGASyringePumpADCChannel3( void ); //// 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. /*********************************************************************//** * @brief * The handleSyringePumpContinuousState function handles the continuous state * of the syringe pump control state machine. * @details Inputs: TBD * @details Outputs: TBD * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpContinuousState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_HEP_CONTINUOUS_STATE; return result; } /*********************************************************************//** * @brief * The handleSyringePumpCalibrateForceSensorState function handles the * calibrate force sensor state of the syringe pump control state machine. * of the pressure/occlusion monitor state machine. * @details Inputs: TBD * @details Outputs: TBD * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpCalibrateForceSensorState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_CONFIG_FORCE_SENSOR_STATE; return result; } /*********************************************************************//** * @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 >= getPublishSyringePumpDataInterval() ) { 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.syringePumpVolumeDelivered = getSyringePumpVolumeDelivered(); broadcastSyringePumpData( data ); syringePumpDataPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The execSyringePumpTest function executes the state machine for the * syringe pump self-test. * @details Inputs: none * @details Outputs: none * @return the current state of the syringe pump self-test. *************************************************************************/ SELF_TEST_STATUS_T execSyringePumpTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; // TODO - implement self-test(s) return result; } /************************************************************************* * 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; } /**@}*/