EPICS Motor Record Device and Driver Support
March 11, 2012
Mark Rivers
University of Chicago
Table of Contents
Introduction
This document describes the device and driver support for the EPICS motors. It briefly
describes the older APIs for such support (referred to as Model 1 and Model 2),
but focuses mainly on the newer Model 3 API, which is the API which should be used
for new motor drivers.
The APIs described here are mainly intended to be used with the EPICS motor record.
However, the Model 2 and Model 3 drivers are actually independent of the motor record.
They implement standard EPICS asyn interfaces, and can in principle be used with
any EPICS records, and do not require the motor record. However, the motor record
currently provides the only "state machine" logic that keeps track of backlash,
enforcing soft limits, etc. Model 2 and 3 drivers permit access to controller-specific
features that the motor record does not support, and this is typically implemented
using standard EPICS records (ao, ai, bo, bi, etc.).
Model 1 device and driver support
Model 1 is the API that was used for all motor drivers prior to 2006, when Model
2 was introduced. Model 1 drivers have the following characteristics:
- Each controller type requires both device-dependent device support and device-dependent
driver support.
- The communication channel between device support and driver is custom for the
motor record, and is very limited.
- The communication between device support and the driver is assumed to be via device-dependent
strings. Thus, it is not suited to register-based controllers, or controllers where
the driver calls a vendor library rather than just sending strings to the controller.
- Cannot use other records with the driver, only the motor record. Cannot take
advantage of controller-specific features not supported by the motor record.
- There is no provision for multi-axis coordination.
- There is only a single thread per controller type. This means that if a
system has, for example, many controllers of a given type, then there is only one
polling thread for all of these controllers. This is because the poller must wait
for each response before sending the next query. This can lead to significantly
poorer performance compared to the Model 2 and Model 3 drivers, which have a separate
thread per controller.
Because this API was the only one supported prior to 2006, the majority of existing
motor drivers are written using this Model 1 API.
Model 2 device and driver support
Because of the recognized deficiencies in the Model 1 API, in 2006 Diamond Light
Source and APS collaborated in developing a new API, now called Model 2. The Model
2 API has the following characteristics:
- Uses standard asyn interfaces to communicate between device support and driver.
- There is only a single device-independent device support file (devMotorAsyn.c).
- There is a single device-independent driver support file for asyn interfaces (drvMotorAsyn.c).
- There is a device-dependent driver file below the asyn one. This driver must implement
a set of functions that the device-independent driver file calls.
- Can use other records to talk to driver via asyn interfaces. This allows support
for controller-specific features.
- However, this is not as easy as it should be, because the drivers do not directly
expose asyn interfaces.
- One must write an asyn interposeInterface driver to support controller-specific
parameters.
- There is no provision for multi-axis coordination.
- There is one polling thread per controller, which is more efficient than Model
1.
There are Model 2 drivers in the motor module for the simulation motor, Newport
MM4000, Newport XPS, Pro-Dex MAXnet, Attocube ANC150, and Aerotech Ensemble.
Model 3 device and driver support
In 2011 the Model 3 API was introduced. This API is based in part on the ideas and
infrastructure that were developed for the areaDetector module. The Model 3 API
has the following characteristics:
- Uses the asynPortDriver C++ class from asyn.
- Uses the same single device-independent device support file (devMotorAsyn.c) as
Model 2 API.
- Model 3 drivers are written in C++ by implementing the methods from the new asynMotorController
and asynMotorAxis base classes.
- The base classes take care of much of the work that one needed to write in the
device-dependent driver in Model 2.
- Can use other records with the driver via asyn interfaces. This allows support
for controller-specific features. This is now very easy to do, compared to the Model
2 driver.
- The API includes support for multi-axis coordination.
- There is one polling thread per controller, which is more efficient than Model
1.
The Model 3 C++ API is based on the concept of two types of objects: a motor controller
and one or more motor axes. The controller object supports the functions that apply
to the entire controller. The controller supports one or more axes. The axis objects
support the functions for a specific axis. These objects are implemented in the
device-dependent driver. There is a base class for each of these objects, asynMotorController
and asynMotorAxis.
The asynMotorController base class has methods that handle much of the work in writing
a driver, including implementing the asyn interfaces and calling the appropriate
methods in the axis classes. A basic motor driver derived class will often only
need to implement the constructor for the controller class, and can just use
the base class implementation of all other methods in the asynMotorController class.
The asynMotorAxis base class on the other hand mainly provides dummy methods (asynMotorAxis::move(),
asynMotorAxis::stop(), etc.). The main work in writing a Model 3 driver consists
of implementing these methods in the derived class.
There are Model 3 drivers in the motor module for the simulation motor, Hytec 8601,
Newport XPS, Parker ACR series controllers (e.g. Aires), and the ACS MCB-4B.
The ACS MCB-4B is the simplest Model 3 driver, consisting of only 336 lines of well-commented
C++ code (ACSSrc/MCB4BDriver.h and MCB4BDriver.cpp). It does not implement any controller-specific
features, it only implements support for standard motor record features. It is a
very good starting point for writing a new driver with basic motor record support.
asynMotorController base class
The asynMotorController base class defines the following methods:
asynMotorController(const char *portName, int numAxes, int numParams, int
interfaceMask, int interruptMask, int asynFlags, int autoConnect, int priority,
int stackSize)
This is the constructor for the class. The parameters correspond to the parameters
in the constructor for the asynPortDriver base class. The parameters are:
portName
The name of the asynPort for this controller. This port name is used to identify
the controller in EPICS record links.
numAxes
The number of axes on this controller.
numParams
The number of controller-specific parameters for this controller. If the driver
only implements the standard motor record parameters, then this is set to 0.
interfaceMask
A bit mask for extra asyn interfaces supported by this controller. It is not necessary
to specify the interfaces that the base class implements, which includes asynOctet,
asynInt32, asynFloat64, asynFloat64Array, asynDrvUser, and asynGenericPointer. Normally
set to 0.
interruptMask
A bit mask for extra asyn interfaces supported by this controller that will do callbacks
to device support. It is not necessary to specify the interfaces that the base class
implements, which include asynOctet, asynInt32, asynFloat64, asynFloat64Array,
and asynGenericPointer. Normally set to 0.
asynFlags
asyn flags to use when creating the asyn port. This is normally (ASYN_CANBLOCK |
ASYN_MULTIDEVICE). ASYN_CANBLOCK means that the driver is "slow" and asynchronous
device support must be used. ASYN_MULTIDEVICE means that the device supports more
than one asyn address, i.e. more than one motor axis.
autoConnect
This is normally set to 1, which means that asynManager will automatically call
the connect() method in the driver if the controller is not connected.
priority
This is normally set to 0, which means that asynManager will use a default priority
for the port thread.
stackSize
This is normally set to 0, which means that asynManager will use a default stack
size for the port thread.
asynMotorAxis base class
The asynMotorAxis base class defines the following methods:
NOTE: This documentation file is incomplete. It needs to be completed.