The areaDetector module provides a general-purpose interface for area (2-D) detectors in EPICS. It is intended to be used with a wide variety of detectors and cameras, ranging from high frame rate CCD and CMOS cameras, pixel-array detectors such as the Pilatus, and large format detectors like the MAR-345 online imaging plate.
The goals of this module are:
The architecture of the areaDetector module is shown below.

From the bottom to the top this architecture consists of the following:
The code in Layers 1-3 is essentially independent of EPICS. There are only 2 EPICS dependencies in this code.
In particular it is possible to eliminate layers 4-6 in the architecture shown in Figure 1, providing there is a programs such as the high-performance GUI shown in Layer 3. This means that it is not necessary to run an EPICS IOC or to use EPICS Channel Access when using the drivers and plugins at Layers 2 and 3.
The plugin architecture is very powerful, because new plugins can be written for application-specific purposes. For example, a plugin could be written to analyze images and find the center of the beam, and such a plugin would then work with any detector driver. Plugins are also powerful because they can be reconfigured at run-time. For example the NDPluginStdArrays can switch from getting its array data from a detector driver to an NDPluginROI plugin. That way it will switch from displaying the entire detector to whatever sub-region the ROI driver has selected. Any Channel Access clients connected to the NDPluginStdArrays driver will automatically switch to displaying this subregion. Similarly, the NDPluginFile plugin can be switched at run-time from saving the entire image to saving a selected ROI, just by changing its input source. Plugins can be used to form an image processing pipeline, for example with a detector providing data to a color convert plugin, which feeds an ROI plugin, which feeds a file saving plugin. Each plugin can run in its own thread, and hence in its own core on a modern multi-core CPU.
The use of plugins is optional, and it is only plugins that require the driver to make callbacks with image data. If there are no plugins being used then EPICS can be used simply to control the detector, without accessing the data itself. This is most useful when the vendor provides an API has the ability to save the data to a file and an application to display the images.
What follows is a detailed description of the software, working from the bottom up. Most of the code is object oriented, and written in C++.
The areaDetector module depends heavily on asyn. It is the software that is used for interthread communication, using the standard asyn interfaces (e.g. asynInt32, asynOctet, etc.), and callbacks. In order to minimize the amount of redundant code in drivers, areaDetector has been implemented using C++ classes. The base classes, from which drivers and plugins are derived, take care of many of the details of asyn and other common code.
Detector drivers and plugins are asyn port drivers, meaning that they implement one or more of the standard asyn interfaces. They register themselves as interrupt sources, so that they do callbacks to registered asyn clients when values change. They inherit from the asynPortDriver base C++ class that is provided in the asyn module. That base class handles all of the details of registering the port driver, registering the supported interfaces, and registering the required interrupt sources. The asynPortDriver class documentation describes this class in detail.
The NDArray (N-Dimensional array) is the class that is used for passing detector data from drivers to plugins. An NDArray is a general purpose class for handling array data. An NDArray object is self-describing, meaning it contains enough information to describe the data itself. It can optionally contain "attributes" (class NDAttribute) which contain meta-data describing how the data was collected, etc.
An NDArray can have up to ND_ARRAY_MAX_DIMS dimensions, currently 10. A fixed maximum number of dimensions is used to significantly simplify the code compared to unlimited number of dimensions. Each dimension of the array is described by an NDDimension structure. The NDArray class documentation describes this class in detail.
The NDArrayPool class manages a free list (pool) of NDArray objects. Drivers allocate NDArray objects from the pool, and pass these objects to plugins. Plugins increase the reference count on the object when they place the object on their queue, and decrease the reference count when they are done processing the array. When the reference count reaches 0 again the NDArray object is placed back on the free list. This mechanism minimizes the copying of array data in plugins. The NDArrayPool class documentation describes this class in detail.
The NDAttribute is a class for linking metadata to an NDArray. An NDattribute has a name, description, data type, value, source type and source information. Attributes are identified by their names, which are case-insensitive. There are methods to set and get the information for an attribute. The NDAttribute class documentation describes this class in detail.
The NDAttributeList implements a linked list of NDAttribute objects. NDArray objects contain an NDAttributeList which is how attributes are associated with an NDArray. There are methods to add, delete and search for NDAttribute objects in an NDAttributeList. Each attribute in the list must have a unique name, which is case-insensitive. The NDAttributeList class documentation describes this class in detail.
The PVAttribute class is derived from NDAttribute. It obtains its value by monitor callbacks from an EPICS PV, and is thus used to associate current the value of any EPICS PV with an NDArray. The PVAttribute class documentation describes this class in detail.
The paramAttribute class is derived from NDAttribute. It obtains its value from the current value of a driver or plugin parameter. The paramAttribute class is typically used when it is important to have the current value of the parameter and the value of a corresponding PVAttribute might not be current because the EPICS PV has not yet updated. The paramAttribute class documentation describes this class in detail.
asynNDArrayDriver inherits from asynPortDriver. It implements the asynGenericPointer functions, for NDArray objects. This is the class from which both plugins and area detector drivers are indirectly derived. The asynNDArrayDriver class documentation describes this class in detail.
The file asynNDArrayDriver.h defines a number of enumerations, including NDStdDriverParam_t, which are the parameters that all NDArray drivers and plugins should implement if possible. These parameters are defined by enum values with an associated asyn interface, and access (read-only or read-write). The EPICS database ADBase.template provides access to these standard driver parameters. The following table lists the standard driver parameters. The columns are defined as follows:
Note that for parameters whose values are defined by enum values (e.g NDDataType, NDColorMode, etc.), drivers can use a different set of enum values for these parameters. They can override the enum menu in ADBase.template with driver-specific choices by loading a driver-specific template file that redefines that record field after loading ADBase.template.
| Parameter Definitions in asynNDArrayDriver.h and EPICS Record Definitions in ADBase.template (file-related records are in NDFile.template) | ||||||
| Enum name | asyn interface | Access | Description | drvUser string | EPICS record name | EPICS record type |
|---|---|---|---|---|---|---|
| Information about the asyn port | ||||||
| NDPortNameSelf | asynOctet | r/o | asyn port name | PORT_NAME_SELF | $(P)$(R)PortName_RBV | stringin |
| Data type | ||||||
| NDDataType | asynInt32 | r/w | Data type (NDDataType_t). | DATA_TYPE |
$(P)$(R)DataType $(P)$(R)DataType_RBV |
mbbo mbbi |
| Color mode | ||||||
| NDColorMode | asynInt32 | r/w | Color mode (NDColorMode_t). | COLOR_MODE |
$(P)$(R)ColorMode $(P)$(R)ColorMode_RBV |
mbbo mbbi |
| Actual dimensions of array data | ||||||
| NDArraySizeX | asynInt32 | r/o | Size of the array data in the X direction | ARRAY_SIZE_X | $(P)$(R)ArraySizeX_RBV | longin |
| NDArraySizeY | asynInt32 | r/o | Size of the array data in the Y direction | ARRAY_SIZE_Y | $(P)$(R)ArraySizeY_RBV | longin |
| NDArraySizeZ | asynInt32 | r/o | Size of the array data in the Z direction | ARRAY_SIZE_Z | $(P)$(R)ArraySizeZ_RBV | longin |
| NDArraySize | asynInt32 | r/o | Total size of the array data in bytes | ARRAY_SIZE | $(P)$(R)ArraySize_RBV | longin |
| File saving parameters (records are defined in NDFile.template) | ||||||
| NDFilePath | asynOctet | r/w | File path | FILE_PATH |
$(P)$(R)FilePath $(P)$(R)FilePath_RBV |
waveform waveform |
| NDFileName | asynOctet | r/w | File name | FILE_NAME |
$(P)$(R)FileName $(P)$(R)FileName_RBV |
waveform waveform |
| NDFileNumber | asynInt32 | r/w | File number | FILE_NUMBER |
$(P)$(R)FileNumber $(P)$(R)FileNumber_RBV |
longout longin |
| NDFileTemplate | asynOctet | r/w |
Format string for constructing NDFullFileName from NDFilePath, NDFileName, and NDFileNumber.
The final file name (which is placed in NDFullFileName) is created with the following
code:
epicsSnprintf(
FullFilename,
sizeof(FullFilename),
FileFormat, FilePath,
Filename, FileNumber);
FilePath, Filename, FileNumber are converted in that order with FileFormat. An example
file format is "%s%s%4.4d.tif". The first %s converts the FilePath,
followed immediately by another %s for Filename. FileNumber is formatted with %4.4d,
which results in a fixed field with of 4 digits, with leading zeros as required.
Finally, the .tif extension is added to the file name. This mechanism for creating
file names is very flexible. Other characters, such as _ can be put in Filename
or FileFormat as desired. If one does not want to have FileNumber in the file name
at all, then just omit the %d format specifier from FileFormat. If the client wishes
to construct the complete file name itself, then it can just put that file name
into NDFileFormat with no format specifiers at all, in which case NDFilePath, NDFileName,
and NDFileNumber will be ignored. |
FILE_TEMPLATE |
$(P)$(R)FileTemplate $(P)$(R)FileTemplate_RBV |
waveform waveform |
| NDFullFileName | asynOctet | r/o | Full file name constructed using the algorithm described in NDFileTemplate | FULL_FILE_NAME | $(P)$(R)FullFileName_RBV |
waveform waveform |
| NDAutoIncrement | asynInt32 | r/w | Auto-increment flag. Controls whether FileNumber is automatically incremented by 1 each time a file is saved (0=No, 1=Yes) | AUTO_INCREMENT |
$(P)$(R)AutoIncrement $(P)$(R)AutoIncrement_RBV |
bo bi |
| NDAutoSave | asynInt32 | r/w | Auto-save flag (0=No, 1=Yes) controlling whether a file is automatically saved each time acquisition completes. | AUTO_SAVE |
$(P)$(R)AutoSave $(P)$(R)AutoSave_RBV |
bo bi |
| NDFileFormat | asynInt32 | r/w | File format. The format to write/read data in (e.g. TIFF, netCDF, etc.) | FILE_FORMAT |
$(P)$(R)FileFormat $(P)$(R)FileFormat_RBV |
mbbo mbbi |
| NDWriteFile | asynInt32 | r/w | Manually save the most recent array to a file when value=1 | WRITE_FILE |
$(P)$(R)WriteFile $(P)$(R)WriteFile_RBV |
busy bi |
| NDReadFile | asynInt32 | r/w | Manually read a file when value=1 | READ_FILE |
$(P)$(R)ReadFile $(P)$(R)ReadFile_RBV |
busy bi |
| NDFileWriteMode | asynInt32 | r/w | File saving mode (Single, Capture, Stream)(NDFileMode_t) | WRITE_MODE |
$(P)$(R)FileWriteMode $(P)$(R)FileWriteMode_RBV |
mbbo mbbi |
| NDFileCapture | asynInt32 | r/w | Start (1) or stop (0) file capture or streaming | CAPTURE |
$(P)$(R)Capture $(P)$(R)Capture_RBV |
busy bi |
| NDFileNumCapture | asynInt32 | r/w | Number of frames to acquire in capture or streaming mode | NUM_CAPTURE |
$(P)$(R)NumCapture $(P)$(R)NumCapture_RBV |
longout longin |
| NDFileNumCaptured | asynInt32 | r/o | Number of arrays currently acquired capture or streaming mode | NUM_CAPTURED | $(P)$(R)NumCaptured_RBV | longin |
| Array data | ||||||
| NDArrayCallbacks | asynInt32 | r/w | Controls whether the driver does callbacks with the array data to registered plugins. 0=No, 1=Yes. Setting this to 0 can reduce overhead in the case that the driver is being used only to control the device, and not to make the data available to plugins or to EPICS clients. | ARRAY_CALLBACKS |
$(P)$(R)ArrayCallbacks $(P)$(R)ArrayCallbacks_RBV |
bo bi |
| NDArrayData | asynGenericPointer | r/w | The array data as an NDArray object | NDARRAY_DATA | N/A. EPICS access to array data is through NDStdArrays plugin. | N/A |
| NDArrayCounter | asynInt32 | r/w | Counter that increments by 1 each time an array is acquired. Can be reset by writing a value to it. | ARRAY_COUNTER |
$(P)$(R)ArrayCounter $(P)$(R)ArrayCounter_RBV |
longout longin |
| N/A | N/A | r/o | Rate at which arrays are being acquired. Computed in the ADBase.template database. | N/A | $(P)$(R)ArrayRate_RBV | calc |
| Array attributes | ||||||
| NDAttributesFile | asynOctet | r/w | The name of an XML file defining the PVAttributes and paramAttributes to be added to each NDArray by this driver or plugin. The format of the XML file is described in the documentation for asynNDArrayDriver::readNDAttributesFile(). | ND_ATTRIBUTES_FILE | $(P)$(R)NDAttributesFile | waveform |
| Debugging control | ||||||
| N/A | N/A | N/A | asyn record to control debugging (asynTrace) | N/A | $(P)$(R)AsynIO | asyn |
ADDriver inherits from asynNDArrayDriver. This is the class from which area detector drivers are directly derived. The ADDriver class documentation describes this class in detail.
The file ADDriver.h defines a number of enumerations, including ADStdDriverParam_t, which are the parameters that all areaDetector drivers should implement if possible.
| Parameter Definitions in ADDriver.h and EPICS Record Definitions in ADBase.template | ||||||
| Enum name | asyn interface | Access | Description | drvUser string | EPICS record name | EPICS record type |
|---|---|---|---|---|---|---|
| Information about the detector | ||||||
| ADManufacturer | asynOctet | r/o | Detector manufacturer name | MANUFACTURER | $(P)$(R)Manufacturer_RBV | stringin |
| ADModel | asynOctet | r/o | Detector model name | MODEL | $(P)$(R)Model_RBV | stringin |
| ADMaxSizeX | asynInt32 | r/o | Maximum (sensor) size in the X direction | MAX_SIZE_X | $(P)$(R)MaxSizeX_RBV | longin |
| ADMaxSizeY | asynInt32 | r/o | Maximum (sensor) size in the Y direction | MAX_SIZE_Y | $(P)$(R)MaxSizeY_RBV | longin |
| ADTemperature | asynFloat64 | r/w | Detector temperature | TEMPERATURE |
$(P)$(R)Temperature $(P)$(R)Temperature_RBV |
ao ai |
| Detector readout control including gain, binning, region start and size, reversal | ||||||
| ADGain | asynFloat64 | r/w | Detector gain | GAIN |
$(P)$(R)Gain $(P)$(R)Gain_RBV |
ao ai |
| ADBinX | asynInt32 | r/w | Binning in the X direction | BIN_X |
$(P)$(R)BinX $(P)$(R)BinX_RBV |
longout longin |
| ADBinY | asynInt32 | r/w | Binning in the Y direction | BIN_Y |
$(P)$(R)BinY $(P)$(R)BinY_RBV |
longout longin |
| ADMinX | asynInt32 | r/w |
First pixel to read in the X direction.
0 is the first pixel on the detector. |
MIN_X |
$(P)$(R)MinX $(P)$(R)MinX_RBV |
longout longin |
| ADMinY | asynInt32 | r/w |
First pixel to read in the Y direction. 0 is the first pixel on the detector. |
MIN_Y |
$(P)$(R)MinY $(P)$(R)MinY_RBV |
longout longin |
| ADSizeX | asynInt32 | r/w | Size of the region to read in the X direction | SIZE_X |
$(P)$(R)SizeX $(P)$(R)SizeX_RBV |
longout longin |
| ADSizeY | asynInt32 | r/w | Size of the region to read in the Y direction | SIZE_Y |
$(P)$(R)SizeY $(P)$(R)SizeY_RBV |
longout longin |
| ADReverseX | asynInt32 | r/w |
Reverse array in the X direction (0=No, 1=Yes) |
REVERSE_X |
$(P)$(R)ReverseX $(P)$(R)ReverseX_RBV |
longout longin |
| ADReverseY | asynInt32 | r/w |
Reverse array in the Y direction (0=No, 1=Yes) |
REVERSE_Y |
$(P)$(R)ReverseY $(P)$(R)ReverseY_RBV |
longout longin |
| Image and trigger modes | ||||||
| ADImageMode | asynInt32 | r/w | Image mode (ADImageMode_t). | IMAGE_MODE |
$(P)$(R)ImageMode $(P)$(R)ImageMode_RBV |
mbbo mbbi |
| ADTriggerMode | asynInt32 | r/w | Trigger mode (ADTriggerMode_t). | TRIGGER_MODE |
$(P)$(R)TriggerMode $(P)$(R)TriggerMode_RBV |
mbbo mbbi |
| Frame type | ||||||
| ADFrameType | asynInt32 | r/w | Frame type (ADFrameType_t). | FRAME_TYPE |
$(P)$(R)FrameType $(P)$(R)FrameType_RBV |
mbbo mbbi |
| Acquisition time and period | ||||||
| ADAcquireTime | asynFloat64 | r/w | Acquisition time per image | ACQ_TIME |
$(P)$(R)AcquireTime $(P)$(R)AcquireTime_RBV |
ao ai |
| ADAcquirePeriod | asynFloat64 | r/w | Acquisition period between images | ACQ_PERIOD |
$(P)$(R)AcquirePeriod $(P)$(R)AcquirePeriod_RBV |
ao ai |
| Number of exposures and number of images | ||||||
| ADNumExposures | asynInt32 | r/w | Number of exposures per image to acquire | NEXPOSURES |
$(P)$(R)NumExposures $(P)$(R)NumExposures_RBV |
longout longin |
| ADNumImages | asynInt32 | r/w | Number of images to acquire in one acquisition sequence | NIMAGES |
$(P)$(R)NumImages $(P)$(R)NumImages_RBV |
longout longin |
| Acquisition control | ||||||
| ADAcquire | asynInt32 | r/w | Start (1) or stop (0) image acquisition. This is an EPICS busy record that does not process its forward link until acquisition is complete. Clients should write 1 to the Acquire record to start acquisition, and wait for Acquire to go to 0 to know that acquisition is complete. | ACQUIRE |
$(P)$(R)Acquire $(P)$(R)Acquire_RBV |
busy bi |
| Status information | ||||||
| ADStatus | asynInt32 | r/o | Acquisition status (ADStatus_t) | STATUS | $(P)$(R)DetectorState_RBV | mbbi |
| ADStatusMessage | asynOctet | r/o | Status message string | STATUS_MESSAGE | $(P)$(R)StatusMessage_RBV | waveform |
| ADStringToServer | asynOctet | r/o | String from driver to string-based vendor server | STRING_TO_SERVER | $(P)$(R)StringToServer_RBV | waveform |
| ADStringFromServer | asynOctet | r/o | String from string-based vendor server to driver | STRING_FROM_SERVER | $(P)$(R)StringFromServer_RBV | waveform |
| ADNumExposuresCounter | asynInt32 | r/o | Counter that increments by 1 each time an exposure is acquired for the current image. Driver resets to 0 when acquisition is started. | NUM_EXPOSURES_COUNTER | $(P)$(R)NumExposuresCounter_RBV | longin |
| ADNumImagesCounter | asynInt32 | r/o | Counter that increments by 1 each time an image is acquired in the current acquisition sequence. Driver resets to 0 when acquisition is started. Drivers can use this as the loop counter when ADImageMode=ADImageMultiple. | NUM_IMAGES_COUNTER | $(P)$(R)NumImagesCounter_RBV | longin |
| ADTimeRemaining | asynFloat64 | r/o | Time remaining for current image. Drivers should update this value if they are doing the exposure timing internally, rather than in the detector hardware. | TIME_REMAINING | $(P)$(R)TimeRemaining_RBV | ai |
| ADReadStatus | asynInt32 | r/w | Write a 1 to this parameter to force a read of the detector status. Detector drivers normally read the status as required, so this is usually not necessary, but there may be some circumstances under which forcing a status read may be needed. | READ_STATUS | $(P)$(R)ReadStatus | bo |
| Shutter control | ||||||
| ADShutterMode | asynInt32 | r/w | Shutter mode (None, detector-controlled or EPICS-controlled) (ADShutterMode_t) | SHUTTER_MODE |
$(P)$(R)ShutterMode $(P)$(R)ShutterMode_RBV |
mbbo mbbi |
| ADShutterControl | asynInt32 | r/w | Shutter control for the selected (detector or EPICS) shutter (ADShutterStatus_t) | SHUTTER_CONTROL |
$(P)$(R)ShutterControl $(P)$(R)ShutterControl_RBV |
bo bi |
| ADShutterControlEPICS | asynInt32 | r/w | This record processes when it receives a callback from the driver to open or close the EPICS shutter. It triggers the records below to actually open or close the EPICS shutter. | SHUTTER_CONTROL_EPICS | $(P)$(R)ShutterControlEPICS | bi |
| N/A | N/A | r/w | This record writes its OVAL field to its OUT field when the EPICS shutter is told to open. The OCAL (and hence OVAL) and OUT fields are user-configurable, so any EPICS-controllable shutter can be used. | N/A | $(P)$(R)ShutterOpenEPICS | calcout |
| N/A | N/A | r/w | This record writes its OVAL field to its OUT field when the EPICS shutter is told to close. The OCAL (and hence OVAL) and OUT fields are user-configurable, so any EPICS-controllable shutter can be used. | N/A | $(P)$(R)ShutterCloseEPICS | calcout |
| ADShutterStatus | asynInt32 | r/o | Status of the detector-controlled shutter (ADShutterStatus_t) | SHUTTER_STATUS | $(P)$(R)ShutterStatus_RBV | bi |
| N/A | N/A | r/o | Status of the EPICS-controlled shutter. This record should have its input link (INP) set to a record that contains the open/close status information for the shutter. The link should have the "CP" attribute, so this record processes when the input changes. The ZRVL field should be set to the value of the input link when the shutter is closed, and the ONVL field should be set to the value of the input link when the shutter is open. | N/A | $(P)$(R)ShutterStatusEPICS_RBV | mbbi |
| ADShutterOpenDelay | asynFloat64 | r/w | Time required for the shutter to actually open (ADShutterStatus_t) | SHUTTER_OPEN_DELAY |
$(P)$(R)ShutterOpenDelay $(P)$(R)ShutterOpenDelay_RBV |
ao ai |
| ADShutterCloseDelay | asynFloat64 | r/w | Time required for the shutter to actually close (ADShutterStatus_t) | SHUTTER_CLOSE_DELAY |
$(P)$(R)ShutterCloseDelay $(P)$(R)ShutterCloseDelay_RBV |
ao ai |
The following are guidelines and rules for writing areaDetector drivers
The following is the MEDM screen that provides access to the parameters in asynNDArrayDriver.h and ADDriver.h through records in ADBase.template. This is a top-level MEDM screen that will work with any areaDetector driver. Note however that many drivers will not implement all of these parameters, and there will usually be detector-specific parameters not shown in this screen, so detector-specific MEDM screens should generally be created that display the EPICS PVs for the features implemented for that detector.
ADBase.adl

The following is the MEDM screen that provides access to the file-related parameters in ADStdDriverParams through records in NDFile.template. This screen is for use with detector drivers that directly implement file I/O.
NDFile.adl

The following is the MEDM screen that provides access to the EPICS shutter parameters in ADStdDriverParams through records in ADBase.template. This screen allows one to define the EPICS PVs to open the shutter, close the shutter, and determine the shutter status. The values of these PVs for open and close drive and status can also be defined. Note that in many cases the same PV will be used for open and close drive, but in some cases (e.g. APS safety shutters) different PVs are used for open and close.
ADEpicsShutter.adl
