areaDetector: EPICS Area Detector Support

September 19, 2008

Mark Rivers

University of Chicago

Contents

 

Overview

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:

 

Architecture

The architecture of the areaDetector module is shown below.

areaDetectorArchitecture.png

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.

  1. libCom. libCom from EPICS base provides operating-system independent functions for threads, mutexes, etc.
  2. asyn. asyn is a module that provides interthread messaging services, including queueing and callbacks.

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.

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 parts of the code that depend on anything from EPICS except libCom and asyn have been kept in in separate C files, so that it should be easy to build applications that do not run as part of an EPICS IOC.

Implementation details

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.

asynPortDriver

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. asynPortDriver is a base C++ class that handles all of the details of registering the port driver, registering the supported interfaces, and registering the required interrupt sources.

Drivers and plugins each need to support a number of parameters that control their operation and provide status information. Most of these can be treated as 32-bit integers, 64-bit floats, or strings. When the new value of a parameter is sent to a driver, (e.g. detector binning in the X direction) from an asyn client (e.g. an EPICS record), then the driver will need to take some action. It may change some other parameters in response to this new value (e.g. image size in the X direction). The sequence of operations in the driver can be summarized as

  1. New parameter value arrives, or new data arrives from detector.
  2. Change values of one or more parameters.
  3. For each parameter whose value changes set a flag noting that it changed.
  4. When operation is complete, call the registered callbacks for each changed parameter.

asynPortDriver provides methods to simplify the above sequence, which must be implemented for each of the many parameters that the driver supports. Each parameter is assigned a number, which is the value in the pasynUser-> reason field that asyn clients pass to the driver when reading or writing that parameter. asynPortDriver maintains a table of parameter values, associating each parameter number with a data type (integer, double, or string), caching the current value, and maintaining a flag indicating if a value has changed. Drivers use asynPortDriver methods to read the current value from the table, and to set new values in the table. There is a method to call all registered callbacks for values that have changed since callbacks were last done.

The following are the public definitions in the asynPortDriver class:

#define asynCommonMask          0x00000001
#define asynDrvUserMask         0x00000002
#define asynOptionMask          0x00000004
#define asynInt32Mask           0x00000008
#define asyUInt32DigitalMask    0x00000010
#define asynFloat64Mask         0x00000020
#define asynOctetMask           0x00000040
#define asynInt8ArrayMask       0x00000080
#define asynInt16ArrayMask      0x00000100
#define asynInt32ArrayMask      0x00000200
#define asynFloat32ArrayMask    0x00000400
#define asynFloat64ArrayMask    0x00000800
#define asynGenericPointerMask  0x00001000

class asynPortDriver {
public:
    asynPortDriver(const char *portName, int maxAddr, int paramTableSize, int interfaceMask, int interruptMask);
    virtual asynStatus getAddress(asynUser *pasynUser, const char *functionName, int *address); 
    virtual asynStatus findParam(asynParamString_t *paramTable, int numParams, const char *paramName, int *param);
    virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
    virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
    virtual asynStatus getBounds(asynUser *pasynUser, epicsInt32 *low, epicsInt32 *high);
    virtual asynStatus readFloat64(asynUser *pasynUser, epicsFloat64 *value);
    virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
    virtual asynStatus readOctet(asynUser *pasynUser, char *value, size_t maxChars,
                         size_t *nActual, int *eomReason);
    virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars,
                          size_t *nActual);
    virtual asynStatus readInt8Array(asynUser *pasynUser, epicsInt8 *value, 
                                        size_t nElements, size_t *nIn);
    virtual asynStatus writeInt8Array(asynUser *pasynUser, epicsInt8 *value,
                                        size_t nElements);
    virtual asynStatus doCallbacksInt8Array(epicsInt8 *value,
                                        size_t nElements, int reason, int addr);
    virtual asynStatus readInt16Array(asynUser *pasynUser, epicsInt16 *value,
                                        size_t nElements, size_t *nIn);
    virtual asynStatus writeInt16Array(asynUser *pasynUser, epicsInt16 *value,
                                        size_t nElements);
    virtual asynStatus doCallbacksInt16Array(epicsInt16 *value,
                                        size_t nElements, int reason, int addr);
    virtual asynStatus readInt32Array(asynUser *pasynUser, epicsInt32 *value,
                                        size_t nElements, size_t *nIn);
    virtual asynStatus writeInt32Array(asynUser *pasynUser, epicsInt32 *value,
                                        size_t nElements);
    virtual asynStatus doCallbacksInt32Array(epicsInt32 *value,
                                        size_t nElements, int reason, int addr);
    virtual asynStatus readFloat32Array(asynUser *pasynUser, epicsFloat32 *value,
                                        size_t nElements, size_t *nIn);
    virtual asynStatus writeFloat32Array(asynUser *pasynUser, epicsFloat32 *value,
                                        size_t nElements);
    virtual asynStatus doCallbacksFloat32Array(epicsFloat32 *value,
                                        size_t nElements, int reason, int addr);
    virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value,
                                        size_t nElements, size_t *nIn);
    virtual asynStatus writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value,
                                        size_t nElements);
    virtual asynStatus doCallbacksFloat64Array(epicsFloat64 *value,
                                        size_t nElements, int reason, int addr);
    virtual asynStatus readGenericPointer(asynUser *pasynUser, void *pointer);
    virtual asynStatus writeGenericPointer(asynUser *pasynUser, void *pointer);
    virtual asynStatus doCallbacksGenericPointer(void *pointer, int reason, int addr);
    virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo, 
                                     const char **pptypeName, size_t *psize);
    virtual asynStatus drvUserGetType(asynUser *pasynUser,
                                        const char **pptypeName, size_t *psize);
    virtual asynStatus drvUserDestroy(asynUser *pasynUser);
    virtual void report(FILE *fp, int details);
    virtual asynStatus connect(asynUser *pasynUser);
    virtual asynStatus disconnect(asynUser *pasynUser);
   
    virtual asynStatus setIntegerParam(int index, int value);
    virtual asynStatus setIntegerParam(int list, int index, int value);
    virtual asynStatus setDoubleParam(int index, double value);
    virtual asynStatus setDoubleParam(int list, int index, double value);
    virtual asynStatus setStringParam(int index, const char *value);
    virtual asynStatus setStringParam(int list, int index, const char *value);
    virtual asynStatus getIntegerParam(int index, int * value);
    virtual asynStatus getIntegerParam(int list, int index, int * value);
    virtual asynStatus getDoubleParam(int index, double * value);
    virtual asynStatus getDoubleParam(int list, int index, double * value);
    virtual asynStatus getStringParam(int index, int maxChars, char *value);
    virtual asynStatus getStringParam(int list, int index, int maxChars, char *value);
    virtual asynStatus callParamCallbacks();
    virtual asynStatus callParamCallbacks(int list, int addr);
    virtual void reportParams();

    /* asynUser connected to ourselves for asynTrace */
    asynUser *pasynUser;
};

A brief explanation of the methods and data in this class is provided here. Users should look at the example driver (simDetector) and plugins provided with areaDetector for examples of how this class is used.

    asynPortDriver(const char *portName, int maxAddr, int paramTableSize, int interfaceMask, int interruptMask);

This is the constructor for the class.

    virtual asynStatus getAddress(asynUser *pasynUser, const char *functionName, int *address); 

Returns the value from pasynManager-> getAddr(pasynUser,...). Returns an error if the address is not valid, e.g. >= this-> maxAddr.

    virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
    virtual asynStatus readFloat64(asynUser *pasynUser, epicsFloat64 *value);
    virtual asynStatus readOctet(asynUser *pasynUser, char *value, size_t maxChars,
                             size_t *nActual, int *eomReason);

These methods are called by asyn clients to return the current cached value for the parameter indexed by pasynUser-> reason in the parameter table defined by getAddress(). Derived classed typically do not need to implement these methods.

    virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
    virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
    virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars,
                          size_t *nActual);

These methods are called by asynClients to set the new value of a parameter. The implementation of these methods in asynPortDriver copies the parameter into a cached location for use by the asynRead(Int32, Float64, and Octet) methods. Most drivers will provide their own implementations of these methods to do driver-dependent operations when there is a new value of the parameter.

     
    virtual asynStatus readXXXArray(asynUser *pasynUser, epicsInt8 *value, 
                                        size_t nElements, size_t *nIn);
    virtual asynStatus writeXXXArray(asynUser *pasynUser, epicsInt8 *value,
                                        size_t nElements);
    virtual asynStatus doCallbacksXXXArray(epicsInt8 *value,
                                        size_t nElements, int reason, int addr);
    virtual asynStatus readGenericPointer(asynUser *pasynUser, void *handle);
    virtual asynStatus writeGenericPointer(asynUser *pasynUser, void *handle);
    virtual asynStatus doCallbacksGenericPointer(void *handle, int reason, int addr);

where XXX=(Int8, Int16, Int32, Float32, or Float64). The readXXX and writeXXX methods only have stub methods that return an error in asynPortDriver, so they must be implemented in the derived classes if the corresponding interface is used. They are not pure virtual functions so that the derived class need not implement the interface if it is not used. The doCallbacksXXX methods in asynPortDriver call any registered asyn clients on the corresponding interface if the reason and addr values match. It typically does not need to be implemented in derived classes.

     
    virtual asynStatus findParam(asynParamString_t *paramTable, int numParams, const char *paramName, int *param);
    virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo, 
                                     const char **pptypeName, size_t *psize);
    virtual asynStatus drvUserGetType(asynUser *pasynUser,
                                        const char **pptypeName, size_t *psize);
    virtual asynStatus drvUserDestroy(asynUser *pasynUser);

drvUserCreate must be implemented in derived classes that use the parameter facilities of asynPortDriver. The findParam method is a convenience function that searches an array of {enum, string} structures and returns the enum (parameter number) matching the string. This is typically used in the implementation of drvUserCreate in derived classes. drvUserGetType and drvUserDestroy typically do not need to be implemented in derived classes.

     
    virtual void report(FILE *fp, int details);
    virtual asynStatus connect(asynUser *pasynUser);
    virtual asynStatus disconnect(asynUser *pasynUser);

The report function prints information on registered interrupt clients if details > 0, and prints parameter table information if details > 5. It is typically called by the implementation of report in derived classes before or after they print specific information about themselves. connect and disconnect call pasynManager-> exceptionConnect and pasynManager-> exceptionDisconnect respectively. Derived classes may or may not need to implement these functions.

     
    virtual asynStatus setIntegerParam(int index, int value);
    virtual asynStatus setIntegerParam(int list, int index, int value);
    virtual asynStatus setDoubleParam(int index, double value);
    virtual asynStatus setDoubleParam(int list, int index, double value);
    virtual asynStatus setStringParam(int index, const char *value);
    virtual asynStatus setStringParam(int list, int index, const char *value);
    virtual asynStatus getIntegerParam(int index, int * value);
    virtual asynStatus getIntegerParam(int list, int index, int * value);
    virtual asynStatus getDoubleParam(int index, double * value);
    virtual asynStatus getDoubleParam(int list, int index, double * value);
    virtual asynStatus getStringParam(int index, int maxChars, char *value);
    virtual asynStatus getStringParam(int list, int index, int maxChars, char *value);
    virtual asynStatus callParamCallbacks();
    virtual asynStatus callParamCallbacks(int list, int addr);

The setXXXParam methods set the value of a parameter in the parameter table in the object. If the value is different from the previous value of the parameter they also set the flag indicating that the value has changed. The getXXXParam methods return the current value of the parameter. There are two versions of the setXXXParam and getXXXParam methods, one with a list argument, and one without. The one without uses list=0, since there is often only a single parameter list (i.e. if maxAddr=1). The callParamCallbacks methods call back any registered clients for parameters that have changed since the last time callParamCallbacks was called. The version of callParamCallbacks with no arguments uses the first parameter list and matches asyn address=0. There is a second version of callParamCallbacks that takes an argument specifying the parameter list number, and the asyn address to match.

NDArray

The NDArray (N-Dimensional array) is the class that is used for passing detector data from drivers to plugins. The NDArray class is defined as follows:

#define ND_ARRAY_MAX_DIMS 10

/* Enumeration of array data types */
typedef enum
{
    NDInt8,
    NDUInt8,
    NDInt16,
    NDUInt16,
    NDInt32,
    NDUInt32,
    NDFloat32,
    NDFloat64
} NDDataType_t;


typedef struct NDDimension {
    int size;
    int offset;
    int binning;
    int reverse;
} NDDimension_t;

typedef struct NDArrayInfo {
    int nElements;
    int bytesPerElement;
    int totalBytes;
} NDArrayInfo_t;

class NDArray {
public:
    /* Data: NOTE this must come first because ELLNODE must be first, i.e. same address as object */
    /* The first 2 fields are used for the freelist */
    ELLNODE node;
    int referenceCount;
    /* The NDArrayPool object that created this array */
    void *owner;

    int uniqueId;
    double timeStamp;
    int ndims;
    NDDimension_t dims[ND_ARRAY_MAX_DIMS];
    NDDataType_t dataType;
    int dataSize;
    void *pData;

    /* Methods */
    NDArray();
    int          initDimension   (NDDimension_t *pDimension, int size);
    int          getInfo         (NDArrayInfo_t *pInfo);
    int          copy            (NDArray *pOut);
    int          reserve(); 
    int          release();
};


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 is not intended to 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_t structure. The fields in NDDimension_t are as follows:

The first 3 data fields in the NDArray class, (node, referenceCount, owner) are used by the NDArrayPool class discussed below. The remaining data fields are as follows:

The methods of the NDArray class are:

NDArrayPool

The NDArrayPool class manages a free list (pool) of NDArray objects (described above). 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 public interface of the NDArrayPool class is defined as follows:

class NDArrayPool {
public:
                 NDArrayPool   (int maxBuffers, size_t maxMemory);
    NDArray*     alloc         (int ndims, int *dims, NDDataType_t dataType, int dataSize, void *pData);
    int          reserve       (NDArray *pArray); 
    int          release       (NDArray *pArray);
    int          convert       (NDArray *pIn, 
                                NDArray **ppOut,
                                NDDataType_t dataTypeOut,
                                NDDimension_t *outDims);
    int          report        (int details);     

The methods of the NDArrayPool class are:

asynNDArrayDriver

asynNDArrayDriver inherits from asynPortDriver. It implements the asynGenericPointer functions, assuming that these reference NDArray objects. This is the class from which both plugins and area detector drivers are indirectly derived. Its public interface is defined as follows:

class asynNDArrayDriver : public asynPortDriver {
public:
    asynNDArrayDriver(const char *portName, int maxAddr, int paramTableSize, int maxBuffers, size_t maxMemory,
                      int interfaceMask, int interruptMask);
    virtual asynStatus readGenericPointer(asynUser *pasynUser, void *genericPointer);
    virtual asynStatus writeGenericPointer(asynUser *pasynUser, void *genericPointer);
    virtual void report(FILE *fp, int details);

};

The methods of the asynNDArrayDriver class are:

ADDriver

ADDriver inherits from asynNDArrayDriver. This is the class from which area detector drivers are directly derived. Its public interface is defined as follows:

class ADDriver : public asynNDArrayDriver {
public:
    ADDriver(const char *portName, int maxAddr, int paramTableSize, int maxBuffers, size_t maxMemory,
             int interfaceMask, int interruptMask);
                 
    /* These are the methods that we override from asynPortDriver */
     virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo, 
                                     const char **pptypeName, size_t *psize);
                                     
    /* These are the methods that are new to this class */
    int createFileName(int maxChars, char *fullFileName);

The methods of the ADDriver class are:

ADStdDriverParams

The file ADStdDriverParams.h defines the following:

/* Enumeration of shutter status */
typedef enum
{
    ADShutterClosed, 
    ADShutterOpen
} ADShutterStatus_t;

/* Enumeration of detector status */
typedef enum
{
    ADStatusIdle,
    ADStatusAcquire,
    ADStatusReadout,
    ASStatusCorrect,
    ADStatusSaving,
    ADStatusAborting,
    ADStatusError,
} ADStatus_t;

typedef enum
{
    ADImageSingle,
    ADImageMultiple,
    ADImageContinuous
} ADImageMode_t;

typedef enum
{
    ADTriggerInternal,
    ADTriggerExternal
} ADTriggerMode_t;

It also defines parameters that all area detector drivers 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 ADImageMode, ADTriggerMode, ADFileFormat, ADStatus), drivers can use a different set of enum values for these parameters. They can override the enum menu in ADBase.template with detector-specific choices by loading a detector-specific template file that redefines that record field after loading ADBase.template.

Parameter Definitions in ADStdDriverParams.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
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 image in the X direction
(0=No, 1=Yes)
REVERSE_X $(P)$(R)ReverseX
$(P)$(R)ReverseX_RBV
longout
longin
ADReverseY asynInt32 r/w Reverse image 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
Data type
ADDataType asynInt32 r/w Data type (NDDataType_t). DATA_TYPE $(P)$(R)DataType
$(P)$(R)DataType_RBV
mbbo
mbbi
Actual dimensions of image data
ADImageSizeX asynInt32 r/o Size of the image data in the X direction IMAGE_SIZE_X $(P)$(R)ImageSizeX_RBV longin
ADImageSizeY asynInt32 r/o Size of the image data in the Y direction IMAGE_SIZE_Y $(P)$(R)ImageSizeY_RBV longin
ADImageSize asynInt32 r/o Total size of image data in bytes IMAGE_SIZE $(P)$(R)ImageSize_RBV longin
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 record is linked to 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 bo
File saving parameters
ADFilePath asynOctet r/w File path FILE_PATH $(P)$(R)FilePath
$(P)$(R)FilePath_RBV
waveform
waveform
ADFileName asynOctet r/w File name FILE_NAME $(P)$(R)FileName
$(P)$(R)FileName_RBV
waveform
waveform
ADFileNumber asynInt32 r/w File number FILE_NUMBER $(P)$(R)FileNumber
$(P)$(R)FileNumber_RBV
longout
longin
ADFileTemplate asynOctet r/w Format string for constructing ADFullFileName from ADFilePath, ADFileName, and ADFileNumber. The final file name (which is placed in ADFullFileName) 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 ADFileFormat with no format specifiers at all, in which case ADFilePath, ADFileName, and ADFileNumber will be ignored.
FILE_TEMPLATE $(P)$(R)FileTemplate
$(P)$(R)FileTemplate_RBV
waveform
waveform
ADFullFileName asynOctet r/o Full file name constructed using the algorithm described in ADFileTemplate FULL_FILE_NAME $(P)$(R)FullFileName_RBV waveform
waveform
ADAutoIncrement 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
ADAutoSave 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
ADFileFormat 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
ADWriteFile asynInt32 r/w Manually save the most recent image to a file when value=1 WRITE_FILE $(P)$(R)WriteFile longout
ADReadFile asynInt32 r/w Manually read a file when value=1 READ_FILE $(P)$(R)ReadFile longout
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
ADImageCounter asynInt32 r/w Counter that increments by 1 each time an image is acquired IMAGE_COUNTER $(P)$(R)ImageCounter
$(P)$(R)ImageCounter_RBV
longout
longin
N/A N/A r/o Rate (Hz) at which ImageCounter is incrementing. Computed in database. N/A $(P)$(R)ImageRate_RBV calc
Shutter control. Note: no areaDetector drivers yet implement shutter control, and these parameters may change in the near future.
ADShutter asynInt32 r/w Shutter control (ADShutterStatus_t) SHUTTER $(P)$(R)ShutterMode
$(P)$(R)ShutterMode_RBV
mbbo
mbbi
Image data
NDArrayData asynGenericPointer r/w The image data as an NDArray object NDARRAY_DATA N/A. EPICS access to image data is through NDStdArrays plugin. N/A
asyn port information
N/A N/A N/A The name of the asyn port for this driver N/A $(P)$(R)PortName_RBV stringin
N/A N/A N/A asyn record to control debugging (asynTrace) N/A $(P)$(R)AsynIO asyn

The following is the MEDM screen that provides access to the parameters in ADStdDriverParams 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, so detector-specific MEDM screens should generally be created that only display the EPICS PVs for the features implemented for that detector. Note that the section of the screen labeled "Shutter" is not currently implemented for any areaDetector driver, and is subject to change in the near future.

ADBase.adl

ADBase.png

Plugins

areaDetector supports plugins, which receive the array data from the drivers and perform operations on the data. These are documented separately:

Detector drivers

areaDetector has been designed to minimize the amount of work required to write a new detector driver. The drivers currently available for the areaDetector module are:

In addition to these drivers, Brian Tieman is writing a driver for the Perkin-Elmer flat-panel amorphous silicon detector. Drivers for the MAR-CCD, MAR-345 online image plate, and the Roper Scientific CCD cameras will be written in the near future.