Files
ADAndor/documentation/areaDetectorDoc.html
2008-09-19 22:51:24 +00:00

1661 lines
63 KiB
HTML
Executable File

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>areaDetector: EPICS Area Detector Support</title>
</head>
<body>
<div style="text-align: center">
<h1>
areaDetector: EPICS Area Detector Support</h1>
<h2>
September 19, 2008</h2>
<h2>
Mark Rivers</h2>
<h2>
University of Chicago</h2>
</div>
<p>
&nbsp;</p>
<h2>
Contents</h2>
<ul>
<li><a href="#Overview">Overview</a></li>
<li><a href="#Architecture">Architecture</a></li>
<li><a href="#Implementation_details">Implementation details</a>
<ul>
<li><a href="#asynPortDriver">asynPortDriver</a></li>
<li><a href="#NDArray">NDArray</a></li>
<li><a href="#NDArrayPool">NDArrayPool</a></li>
<li><a href="#asynNDArrayDriver">asynNDArrayDriver</a></li>
<li><a href="#ADDriver">ADDriver</a></li>
<li><a href="#ADStdDriverParams">ADStdDriverParams</a></li>
</ul>
</li>
<li><a href="pluginDoc.html">Plugins</a>
<ul>
<li><a href="pluginDoc.html#NDPluginDriver">NDPluginDriver</a></li>
<li><a href="NDPluginStdArrays.html">NDPluginStdArrays</a></li>
<li><a href="NDPluginFile.html">NDPluginFile</a></li>
<li><a href="NDPluginROI.html">NDPluginROI</a></li>
</ul>
</li>
<li><a href="#Detector_drivers">Detector drivers</a>
<ul>
<li><a href="simDetectorDoc.html">Simulation detector driver</a></li>
<li><a href="prosilicaDoc.html">Prosilica driver</a></li>
<li><a href="pilatusDoc.html">Pilatus driver</a></li>
<li><a href="adscDoc.html">ADSC driver</a></li>
</ul>
</li>
</ul>
<p>
&nbsp;</p>
<h2 id="Overview">
Overview</h2>
<p>
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.</p>
<p>
The goals of this module are:
</p>
<ul>
<li>Minimize the amount of code that needs to be written to implement a new detector.</li>
<li>Provide a standard interface defining the functions and parameters that a detector
driver must support.</li>
<li>Provide a set of base EPICS records that will be present for every detector using
this module. This allows the use of generic EPICS clients for displaying images
and controlling cameras and detectors.</li>
<li>Allow easy extensibility to take advantage of detector-specific features beyond
the standard parameters.</li>
<li>Have high-performance. Applications can be written to get the detector image data
through EPICS, but an interface is also available to receive the detector data at
a lower-level for very high performance.</li>
<li>Provide an optional Region-Of-Interest (ROI) driver that performs computations
on regions within the image data. A basic ROI driver is included in the module,
and it is easy to add addtional ROI drivers for specific applications.</li>
<li>Provide detector drivers for commonly used detectors in synchrotron applications.
These include Prosilica GigE video cameras, MAR-CCD x-ray detectors, MAR-345 online
imaging plate detectors, the Pilatus pixel-array detector, and the Roper Scientific
CCD cameras.</li>
</ul>
<p>
&nbsp;</p>
<h2 id="Architecture">
Architecture</h2>
<p>
The architecture of the areaDetector module is shown below.</p>
<p style="text-align: center">
<img alt="areaDetectorArchitecture.png" src="areaDetectorArchitecture.png" /></p>
<p>
From the bottom to the top this architecture consists of the following:</p>
<ul>
<li>Layer 1. This is the layer that allows user written code to communicate with the
hardware. It is usually provided by the detector vendor. It may consist of a library
or DLL, of a socket protocol to a driver, a Microsoft COM interface, etc.</li>
<li>Layer 2. This is the driver that is written for the areaDetector application to
control a particular detector. It is normally written in C++ and inherits from the
ADDriver class. It uses the standard asyn interfaces for control and status information.
Each time it receives a new data array it passes it as an NDArray object to all
Layer 3 clients that have registered for callbacks. This is the only code that needs
to be written to implement a new detector. Existing drivers range from 650 to 1050
lines of code.</li>
<li>Layer 3. Code running at this level is called a "plug-in". This code registers
with a driver for a callback whenever there is a new data array. The existing plugins
implement file saving (NDPluginFile), region-of-interest (ROI) calculations (NDPluginROI),
and conversion of detector data to standard EPICS array types for use by Channel
Access clients (NDPluginStdArrays). Plugins are normally written in C++ and inherit
from NDPluginDriver. Existing plugins range from 280 to 650 lines of code.</li>
<li>Layer 4. This is standard asyn device support that comes with the EPICS asyn module.</li>
<li>Layer 5. These are standard EPICS records, and EPICS database (template) files
that define records to communicate with drivers at Layer 2 and plugins at Layer
3.</li>
<li>Layer 6. These are EPICS channel access clients, such as MEDM that communicate
with the records at Layer 5. There is a free IDL client that can display images
using EPICS waveform and other records communicating with the NDPluginStdArrays
plugin at Layer 3.</li>
</ul>
<p>
The code in Layers 1-3 is essentially independent of EPICS. There are only 2 EPICS
dependencies in this code.
</p>
<ol>
<li><a href="http://www.aps.anl.gov/epics/base/R3-14/9-docs/AppDevGuide.pdf">libCom</a>.
libCom from EPICS base provides operating-system independent functions for threads,
mutexes, etc.</li>
<li><a href="http://www.aps.anl.gov/epics/modules/soft/asyn">asyn</a>. asyn is a module
that provides interthread messaging services, including queueing and callbacks.</li>
</ol>
<p>
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.
</p>
<p>
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.
</p>
<p>
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 API has the ability to save the data to a file.
</p>
<p>
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.
</p>
<h2 id="Implementation_details">
Implementation details</h2>
<p>
The areaDetector module depends heavily on <a href="http://www.aps.anl.gov/epics/modules/soft/asyn">
asyn</a>. 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.
</p>
<h2 id="asynPortDriver">
asynPortDriver</h2>
<p>
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.
</p>
<p>
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
</p>
<ol>
<li>New parameter value arrives, or new data arrives from detector.</li>
<li>Change values of one or more parameters.</li>
<li>For each parameter whose value changes set a flag noting that it changed.</li>
<li>When operation is complete, call the registered callbacks for each changed parameter.</li>
</ol>
<p>
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-&gt 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.
</p>
<p>
The following are the public definitions in the asynPortDriver class:
</p>
<pre>#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;
};
</pre>
<p>
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.
</p>
<pre> asynPortDriver(const char *portName, int maxAddr, int paramTableSize, int interfaceMask, int interruptMask);
</pre>
<p>
This is the constructor for the class.
</p>
<ul>
<li><code>portName</code> is the name of the asyn port for this driver or plugin.</li>
<li><code>maxAddr</code> is the maximum number of asyn addresses that this driver
supports. This number returned by the <code>pasynManager-&gt getAddr()</code> function.
Typically it is 1, but some plugins (e.g. NDPluginROI) support values &gt 1. This
controls the number of parameter tables that are created.</li>
<li><code>parmTableSize</code> is the maximum number of parameters that this driver
or plugin supports. This controls the size of the parameter tables.</li>
<li><code>interfaceMask</code> is a mask with each bit defining which asyn interfaces
this driver or plugin supports. The bit mask values are defined in asynPortDriver.h,
e.g. <code>asynInt32Mask</code>.</li>
<li><code>interruptMask</code> is a mask with each bit defining which of the asyn
interfaces this driver or plugin supports can generate interrupts. The bit mask
values are defined in asynPortDriver.h, e.g. <code>asynInt8ArrayMask</code>.</li>
</ul>
<pre> virtual asynStatus getAddress(asynUser *pasynUser, const char *functionName, int *address);
</pre>
<p>
Returns the value from pasynManager-&gt getAddr(pasynUser,...). Returns an error
if the address is not valid, e.g. &gt= this-&gt maxAddr.
</p>
<pre> 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);
</pre>
<p>
These methods are called by asyn clients to return the current cached value for
the parameter indexed by pasynUser-&gt reason in the parameter table defined by
<code>getAddress()</code>. Derived classed typically do not need to implement these
methods.
</p>
<pre> 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);
</pre>
<p>
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.
</p>
<pre>
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);
</pre>
<p>
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 <code>reason</code> and <code>addr</code>
values match. It typically does not need to be implemented in derived classes.
</p>
<pre>
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);
</pre>
<p>
drvUserCreate must be implemented in derived classes that use the parameter facilities
of asynPortDriver. The <code>findParam</code> 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 <code>drvUserCreate</code>
in derived classes. <code>drvUserGetType</code> and <code>drvUserDestroy</code>
typically do not need to be implemented in derived classes.
</p>
<pre>
virtual void report(FILE *fp, int details);
virtual asynStatus connect(asynUser *pasynUser);
virtual asynStatus disconnect(asynUser *pasynUser);
</pre>
<p>
The <code>report</code> function prints information on registered interrupt clients
if details &gt 0, and prints parameter table information if details &gt 5. It is
typically called by the implementation of <code>report</code> in derived classes
before or after they print specific information about themselves. <code>connect</code>
and <code>disconnect</code> call <code>pasynManager-&gt exceptionConnect</code>
and <code>pasynManager-&gt exceptionDisconnect</code> respectively. Derived classes
may or may not need to implement these functions.
</p>
<pre>
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);
</pre>
<p>
The <code>setXXXParam</code> 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 <code>getXXXParam</code>
methods return the current value of the parameter. There are two versions of the
<code>setXXXParam</code> and <code>getXXXParam</code> methods, one with a <code>list</code>
argument, and one without. The one without uses <code>list=0</code>, since there
is often only a single parameter list (i.e. if maxAddr=1). The <code>callParamCallbacks</code>
methods call back any registered clients for parameters that have changed since
the last time <code>callParamCallbacks</code> was called. The version of <code>callParamCallbacks</code>
with no arguments uses the first parameter list and matches asyn address=0. There
is a second version of <code>callParamCallbacks</code> that takes an argument specifying
the parameter list number, and the asyn address to match.
</p>
<h2 id="NDArray">
NDArray</h2>
<p>
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:
</p>
<pre>#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();
};
</pre>
<p>
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.
</p>
<p>
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:
</p>
<ul>
<li><code>size</code> is the number of elements in this dimension.</li>
<li><code>offset</code> is the starting element in this dimension relative to the
first element of the detector in unbinned units. If a selected region of the detector
is being read, then this value may be &gt 0. The offset value is cumulative, so
if a plugin such as NDPluginROI further selects a subregion, the offset is relative
to the first element in the detector and not to the first element of the region
passed to NDPluginROI.</li>
<li><code>binning</code> is the binning (sumation of elements) in this dimension.
The offset value is cumulative, so if a plugin such as NDPluginROI performs binning,
the binning is expressed relative to the pixels in the detector and not to the possibly
binned pixels passed to NDPluginROI.</li>
<li><code>reverse</code> is 0 if the data are in their normal order as read out from
the detector in this dimension, and 1 if they are in reverse order. This value is
cumulative, so if a plugin such as NDPluginROI reverses the data, the value must
reflect the orientation relative to the original detector, and not to the possibly
reversed data passed to NDPluginROI.</li>
</ul>
<p>
The first 3 data fields in the NDArray class, <code>(node, referenceCount, owner)</code>
are used by the NDArrayPool class discussed below. The remaining data fields are
as follows:
</p>
<ul>
<li><code>uniqueId</code> This should be a number that uniquely identifies this array.
Detector drivers should assign this number to the NDArray before calling the plugins.</li>
<li><code>timeStamp</code> This should be a timestamp value in seconds recording when
the frame was collected. The time=0 reference is driver-dependent because of differences
in vendor libraries. If there is a choice, it is recommended to use timeStamp=0
for Epoch, (00:00:00 UTC, January 1, 1970).</li>
<li><code>ndims</code> The number of dimensions in this array.</li>
<li><code>dims</code> Array of NDDimension_t structures. The array is of length ND_MAX_DIMS,
but only the first <code>ndims</code> values must contain valid information.</li>
<li><code>dataType</code> The data type of this array, one of the NDDataType_t enum
values. The data types supported are signed and unsigned 8, 16, and 32-bit integers,
and 32 and 64-bit floats. </li>
<li><code>dataSize</code> The size of the memory buffer pointed to by <code>pData</code>
in bytes. This may be larger than the amount actually required to hold the data
for this array.</li>
<li><code>pData</code> Pointer to the memory for this array. The data is assumed to
be stored in the order of <code>dims[0]</code> changing fastest, and <code>dims[ndims-1]</code>
changing slowest.</li>
</ul>
<p>
The methods of the NDArray class are:
</p>
<ul>
<li><code>initDimension</code> This method simply initializes the dimension structure
to size=size, binning=1, reverse=0, offset=0.</li>
<li><code>getInfo</code>. This convenience method returns information about an NDArray,
including the total number of elements, the number of byte per element, and the
total number of bytes in the array.</li>
<li><code>copy</code>. This method makes a copy of an NDArray object. If the output
array pointer is NULL then it is first allocated. If the output array object already
exists (pOut!=NULL) then it must have sufficient memory allocated to it to hold
the data.</li>
<li><code>reserve</code>. This method calls NDArrayPool->reserve() for this object.
It increases the reference count for this array.</li>
<li><code>release</code>. This method calls NDArrayPool->release() for this object.
It decreases the reference count for this array.</li>
</ul>
<h2 id="NDArrayPool">
NDArrayPool</h2>
<p>
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:
</p>
<pre>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);
</pre>
<p>
The methods of the NDArrayPool class are:
</p>
<ul>
<li><code>NDArrayPool</code> This is the constructor for the class. The maxBuffers
argument is the maximum number of NDArray objects that the pool is allowed to contain.
The maxMemory argument is the maxiumum number of bytes of memory the the pool is
allowed to use, summed over all of the NDArray objects.</li>
<li><code>alloc</code> This method allocates a new NDArray object. The first 3 arguments
are required. ndims is the number of dimensions in the NDArray. dims is an array
of dimensions, whose size must be at least ndims. dataType is the data type of the
NDArray data. dataSize is the number of bytes to allocate for the array data. If
it is 0 then alloc() will compute the size required from ndims, dims, and dataType.
pData is a pointer to a data buffer. If it is NULL then alloc will allocate a new
array buffer. If pData is not NULL then it is assumed to point to a valid buffer.
In this case dataSize must contain the actual number of bytes in the existing array,
and this array must be large enough to hold the array data. alloc() searches its
free list to find a free NDArray buffer. If is cannot find one then it will allocate
a new one and add it to the free list. If doing so would exceed maxBuffers then
alloc() will return an error. Similarly if allocating the memory required for this
NDArray would cause the cumulative memory allocated for the pool to exceed maxMemory
then an error will be returned. alloc() sets the reference count for the returned
NDArray to 1.</li>
<li><code>reserve</code>. This method increases the reference count for the NDArray
object. Plugins must call reserve() when an NDArray is placed on a queue for later
processing.</li>
<li><code>release</code>. This method decreases the reference count for the NDArray
object. Plugins must call release() when an NDArray is removed from the queue and
processing on it is complete. Drivers must call release() after calling all plugins.</li>
<li><code>convert</code> This method creates a new output NDArray from an input NDArray,
performing conversion operations. The conversion can change the data type if dataTypeOut
is different from pIn->dataType. It can also change the dimensions. outDims may
have different values of size, binning, offset and reverse for each of its dimensions
from input array dimensions (pIn->dims).</li>
<li><code>report</code> This method reports on the free list size and other properties
of the NDArrayPool object.</li>
</ul>
<h2 id="asynNDArrayDriver">
asynNDArrayDriver</h2>
<p>
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:
</p>
<pre>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);
};
</pre>
<p>
The methods of the asynNDArrayDriver class are:
</p>
<ul>
<li><code>asynNDArrayDriver</code> This is the constructor for the class. portName,
maxAddr, paramTableSize, interfaceMask and interruptMask are simply passed to the
asynPortDriver base class constructor. asynNDArray creates an NDArrayPool object
to allocate NDArray objects. maxBuffers and maxMemory are passed to the constructor
for the NDArrayPool object.</li>
<li><code>readGenericPointer</code> This method copies an NDArray object from the
asynNDArrayDriver to an NDArray whose address is passed by the caller in the genericPointer
argument. The caller must allocate the memory for the array, and pass the size in
NDArray->dataSize. The method will limit the amount of data copied to the actual
array size or the input dataSize, whichever is smaller.</li>
<li><code>writeGenericPointer</code> This method currently does nothing. Derived classes
must implement this method as required.</li>
<li><code>report</code> This method calls the report function in the asynPortDriver
base class. It then calls the NDArrayPool->report() method if details &gt 5.</li>
</ul>
<h2 id="ADDriver">
ADDriver</h2>
<p>
ADDriver inherits from asynNDArrayDriver. This is the class from which area detector
drivers are directly derived. Its public interface is defined as follows:
</p>
<pre>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);
</pre>
<p>
The methods of the ADDriver class are:
</p>
<ul>
<li><code>ADDriver</code> This is the constructor for the class. All of the arguments
are simply passed to the constructor for the asynNDArrayDriver base class. After
calling the base class constructor this method sets reasonable default values for
all of the parameters defined in ADStdDriverParams.h.</li>
<li><code>drvUserCreate</code> This method returns one of the enum values for the
parameters defined in ADStdDriverParams.h if the driverInfo field matches one the
strings defined in that file. Derived classes will typically provide an implementation
of drvUserCreate() that searches for parameters that are unique to that detector
driver. If a parameter is not matched, then ADDriver->drvUserCreate() will be called
to see if it is a standard driver parameter (defined in ADStdDriverParams.h).</li>
<li><code>createFileName</code> This is a convenience function that constructs a complete
file name in the ADFullFileName parameter from the ADFilePath, ADFileName, ADFileNumber,
and ADFileTemplate parameters.</li>
</ul>
<h2 id="ADStdDriverParams">
ADStdDriverParams</h2>
<p>
The file <code>ADStdDriverParams.h</code> defines the following:
</p>
<pre>/* 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;
</pre>
<p>
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:
</p>
<ul>
<li><b>Enum name:</b> The name of the enum value for this parameter in ADStdDriverParams.h.
There are several EPICS records in ADBase.template that do not have corresponding
enum fields, and these are indicated as Not Applicable (N/A).</li>
<li><b>asyn interface:</b> The asyn interface used to pass this parameter to the driver.</li>
<li><b>Access:</b> Read-write (r/w) or read-only (r/o).</li>
<li><b>drvUser string:</b> The string used to look up the parameter in the driver
through the drvUser interface. This string is used in the EPICS database file for
generic asyn device support to associate a record with a particular parameter.</li>
<li><b>EPICS record name:</b> The name of the record in ADBase.template. Each record
name begins with the two macro parameters $(P) and $(R). In the case of read/write
parameters there are normally two records, one for writing the value, and a second,
ending in _RBV, that contains the actual value (Read Back Value) of the parameter.</li>
<li><b>EPICS record type:</b> The record type of the record. Waveform records are
used to hold long strings, with length (NELM) = 256 bytes and EPICS data type (FTVL)
= UCHAR. This removes the 40 character restriction on path name lengths that arise
if an EPICS "string" PV is used. medm allows one to edit and display such records
correctly. EPICS clients will typically need to convert the path name from a string
to an integer or byte array before sending the path name to EPICS. This is easy
to do in clients like SPEC, Matlab, and IDL.</li>
</ul>
<p>
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 after
loading ADBase.template.
</p>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left">
<tbody>
<tr>
<td align="center" colspan="7">
<b>Parameter Definitions in ADStdDriverParams.h and EPICS Record Definitions in ADBase.template</b></td>
</tr>
<tr>
<th>
Enum name</th>
<th>
asyn interface</th>
<th>
Access</th>
<th>
Description</th>
<th>
drvUser string</th>
<th>
EPICS record name</th>
<th>
EPICS record type</th>
</tr>
<tr>
<td align="center" colspan="7">
<b>Information about the detector</b></td>
</tr>
<tr>
<td>
ADManufacturer</td>
<td>
asynOctet</td>
<td>
r/o</td>
<td>
Detector manufacturer name</td>
<td>
MANUFACTURER</td>
<td>
$(P)$(R)Manufacturer_RBV</td>
<td>
stringin</td>
</tr>
<tr>
<td>
ADModel</td>
<td>
asynOctet</td>
<td>
r/o</td>
<td>
Detector model name</td>
<td>
MODEL</td>
<td>
$(P)$(R)Model_RBV</td>
<td>
stringin</td>
</tr>
<tr>
<td>
ADMaxSizeX</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Maximum (sensor) size in the X direction</td>
<td>
MAX_SIZE_X</td>
<td>
$(P)$(R)MaxSizeX_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td>
ADMaxSizeY</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Maximum (sensor) size in the Y direction</td>
<td>
MAX_SIZE_Y</td>
<td>
$(P)$(R)MaxSizeY_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Detector readout control including gain, binning, region start and size, reversal</b></td>
</tr>
<tr>
<td>
ADGain</td>
<td>
asynFloat64</td>
<td>
r/w</td>
<td>
Detector gain</td>
<td>
GAIN</td>
<td>
$(P)$(R)Gain<br />
$(P)$(R)Gain_RBV</td>
<td>
ao<br />
ai</td>
</tr>
<tr>
<td>
ADBinX</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Binning in the X direction</td>
<td>
BIN_X</td>
<td>
$(P)$(R)BinX<br />
$(P)$(R)BinX_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADBinY</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Binning in the Y direction</td>
<td>
BIN_Y</td>
<td>
$(P)$(R)BinY<br />
$(P)$(R)BinY_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADMinX</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
First pixel to read in the X direction.
<br />
0 is the first pixel on the detector.</td>
<td>
MIN_X</td>
<td>
$(P)$(R)MinX<br />
$(P)$(R)MinX_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADMinY</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
First pixel to read in the Y direction.<br />
0 is the first pixel on the detector.</td>
<td>
MIN_Y</td>
<td>
$(P)$(R)MinY<br />
$(P)$(R)MinY_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADSizeX</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Size of the region to read in the X direction</td>
<td>
SIZE_X</td>
<td>
$(P)$(R)SizeX<br />
$(P)$(R)SizeX_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADSizeY</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Size of the region to read in the Y direction</td>
<td>
SIZE_Y</td>
<td>
$(P)$(R)SizeY<br />
$(P)$(R)SizeY_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADReverseX</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Reverse image in the X direction<br />
(0=No, 1=Yes)</td>
<td>
REVERSE_X</td>
<td>
$(P)$(R)ReverseX<br />
$(P)$(R)ReverseX_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADReverseY</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Reverse image in the Y direction<br />
(0=No, 1=Yes)</td>
<td>
REVERSE_Y</td>
<td>
$(P)$(R)ReverseY<br />
$(P)$(R)ReverseY_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Image and trigger modes</b></td>
</tr>
<tr>
<td>
ADImageMode</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Image mode (ADImageMode_t).</td>
<td>
IMAGE_MODE</td>
<td>
$(P)$(R)ImageMode<br />
$(P)$(R)ImageMode_RBV</td>
<td>
mbbo<br />
mbbi</td>
</tr>
<tr>
<td>
ADTriggerMode</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Trigger mode (ADTriggerMode_t).</td>
<td>
TRIGGER_MODE</td>
<td>
$(P)$(R)TriggerMode<br />
$(P)$(R)TriggerMode_RBV</td>
<td>
mbbo<br />
mbbi</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Data type</b></td>
</tr>
<tr>
<td>
ADDataType</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Data type (NDDataType_t).</td>
<td>
DATA_TYPE</td>
<td>
$(P)$(R)DataType<br />
$(P)$(R)DataType_RBV</td>
<td>
mbbo<br />
mbbi</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Actual dimensions of image data</b></td>
</tr>
<tr>
<td>
ADImageSizeX</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Size of the image data in the X direction</td>
<td>
IMAGE_SIZE_X</td>
<td>
$(P)$(R)ImageSizeX_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td>
ADImageSizeY</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Size of the image data in the Y direction</td>
<td>
IMAGE_SIZE_Y</td>
<td>
$(P)$(R)ImageSizeY_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td>
ADImageSize</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Total size of image data in bytes</td>
<td>
IMAGE_SIZE</td>
<td>
$(P)$(R)ImageSize_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Acquisition time and period</b></td>
</tr>
<tr>
<td>
ADAcquireTime</td>
<td>
asynFloat64</td>
<td>
r/w</td>
<td>
Acquisition time per image</td>
<td>
ACQ_TIME</td>
<td>
$(P)$(R)AcquireTime<br />
$(P)$(R)AcquireTime_RBV</td>
<td>
ao<br />
ai</td>
</tr>
<tr>
<td>
ADAcquirePeriod</td>
<td>
asynFloat64</td>
<td>
r/w</td>
<td>
Acquisition period between images</td>
<td>
ACQ_PERIOD</td>
<td>
$(P)$(R)AcquirePeriod<br />
$(P)$(R)AcquirePeriod_RBV</td>
<td>
ao<br />
ai</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Number of exposures and number of images</b></td>
</tr>
<tr>
<td>
ADNumExposures</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Number of exposures per image to acquire</td>
<td>
NEXPOSURES</td>
<td>
$(P)$(R)NumExposures<br />
$(P)$(R)NumExposures_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADNumImages</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Number of images to acquire in one acquisition sequence</td>
<td>
NIMAGES</td>
<td>
$(P)$(R)NumImages<br />
$(P)$(R)NumImages_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Acquisition control</b></td>
</tr>
<tr>
<td>
ADAcquire</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
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.</td>
<td>
ACQUIRE</td>
<td>
$(P)$(R)Acquire</td>
<td>
bo</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>File saving parameters</b></td>
</tr>
<tr>
<td>
ADFilePath</td>
<td>
asynOctet</td>
<td>
r/w</td>
<td>
File path</td>
<td>
FILE_PATH</td>
<td>
$(P)$(R)FilePath<br />
$(P)$(R)FilePath_RBV</td>
<td>
waveform<br />
waveform</td>
</tr>
<tr>
<td>
ADFileName</td>
<td>
asynOctet</td>
<td>
r/w</td>
<td>
File name</td>
<td>
FILE_NAME</td>
<td>
$(P)$(R)FileName<br />
$(P)$(R)FileName_RBV</td>
<td>
waveform<br />
waveform</td>
</tr>
<tr>
<td>
ADFileNumber</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
File number</td>
<td>
FILE_NUMBER</td>
<td>
$(P)$(R)FileNumber<br />
$(P)$(R)FileNumber_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
ADFileTemplate</td>
<td>
asynOctet</td>
<td>
r/w</td>
<td>
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:
<pre> epicsSnprintf(FullFilename, sizeof(FullFilename), FileFormat,
FilePath, Filename, FileNumber);
</pre>
FilePath, Filename, FileNumber are converted in that order with FileFormat. An example
file format is <code>"%s%s%4.4d.tif"</code>. 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.</td>
<td>
FILE_TEMPLATE</td>
<td>
$(P)$(R)FileTemplate<br />
$(P)$(R)FileTemplate_RBV</td>
<td>
waveform<br />
waveform</td>
</tr>
<tr>
<td>
ADFullFileName</td>
<td>
asynOctet</td>
<td>
r/o</td>
<td>
Full file name</td>
<td>
FULL_FILE_NAME</td>
<td>
$(P)$(R)FullFileName_RBV</td>
<td>
waveform<br />
waveform</td>
</tr>
<tr>
<td>
ADAutoIncrement</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Auto-increment flag. Controls whether FileNumber is automatically incremented by
1 each time an acquisition completes (0=No, 1=Yes)</td>
<td>
AUTO_INCREMENT</td>
<td>
$(P)$(R)AutoIncrement<br />
$(P)$(R)AutoIncrement_RBV</td>
<td>
bo<br />
bi</td>
</tr>
<tr>
<td>
ADAutoSave</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Auto-save flag (0=No, 1=Yes)</td>
<td>
AUTO_SAVE</td>
<td>
$(P)$(R)AutoSave<br />
$(P)$(R)AutoSave_RBV</td>
<td>
bo<br />
bi</td>
</tr>
<tr>
<td>
ADFileFormat</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
File format. The format to write/read data in (e.g. TIFF, netCDF, etc.)</td>
<td>
FILE_FORMAT</td>
<td>
$(P)$(R)FileFormat<br />
$(P)$(R)FileFormat_RBV</td>
<td>
mbbo<br />
mbbi</td>
</tr>
<tr>
<td>
ADWriteFile</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Manually save the most recent image to a file when value=1</td>
<td>
WRITE_FILE</td>
<td>
$(P)$(R)WriteFile</td>
<td>
longout</td>
</tr>
<tr>
<td>
ADReadFile</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Manually read a file when value=1</td>
<td>
READ_FILE</td>
<td>
$(P)$(R)ReadFile</td>
<td>
longout</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Status information</b></td>
</tr>
<tr>
<td>
ADStatus</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Acquisition status (ADStatus_t)</td>
<td>
STATUS</td>
<td>
$(P)$(R)DetectorState_RBV</td>
<td>
mbbi</td>
</tr>
<tr>
<td>
ADStatusMessage</td>
<td>
asynOctet</td>
<td>
r/o</td>
<td>
Status message string</td>
<td>
STATUS_MESSAGE</td>
<td>
$(P)$(R)StatusMessage_RBV</td>
<td>
waveform</td>
</tr>
<tr>
<td>
ADStringToServer</td>
<td>
asynOctet</td>
<td>
r/o</td>
<td>
String from driver to string-based vendor server</td>
<td>
STRING_TO_SERVER</td>
<td>
$(P)$(R)StringToServer_RBV</td>
<td>
waveform</td>
</tr>
<tr>
<td>
ADStringFromServer</td>
<td>
asynOctet</td>
<td>
r/o</td>
<td>
String from string-based vendor server to driver</td>
<td>
STRING_FROM_SERVER</td>
<td>
$(P)$(R)StringFromServer_RBV</td>
<td>
waveform</td>
</tr>
<tr>
<td>
ADImageCounter</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Counter that increments by 1 each time an image is acquired</td>
<td>
IMAGE_COUNTER</td>
<td>
$(P)$(R)ImageCounter<br />
$(P)$(R)ImageCounter_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
N/A</td>
<td>
N/A</td>
<td>
r/o</td>
<td>
Rate (Hz) at which ImageCounter is incrementing. Computed in database.</td>
<td>
N/A</td>
<td>
$(P)$(R)ImageRate_RBV</td>
<td>
calc</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Shutter control. Note: no areaDetector drivers yet implement shutter control, and
these parameters may change in the near future.</b></td>
</tr>
<tr>
<td>
ADShutter</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Shutter control (ADShutterStatus_t)</td>
<td>
SHUTTER</td>
<td>
$(P)$(R)ShutterMode<br />
$(P)$(R)ShutterMode_RBV</td>
<td>
mbbo<br />
mbbi</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Image data</b></td>
</tr>
<tr>
<td>
NDArrayData</td>
<td>
asynGenericPointer</td>
<td>
r/w</td>
<td>
The image data as an NDArray object</td>
<td>
NDARRAY_DATA</td>
<td>
N/A. EPICS access to image data is through NDStdArrays plugin.</td>
<td>
N/A</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>asyn port information</b></td>
</tr>
<tr>
<td>
N/A</td>
<td>
N/A</td>
<td>
N/A</td>
<td>
The name of the asyn port for this driver</td>
<td>
N/A</td>
<td>
$(P)$(R)PortName_RBV</td>
<td>
stringin</td>
</tr>
<tr>
<td>
N/A</td>
<td>
N/A</td>
<td>
N/A</td>
<td>
asyn record to control debugging (asynTrace)</td>
<td>
N/A</td>
<td>
$(P)$(R)AsynIO</td>
<td>
asyn</td>
</tr>
</tbody>
</table>
<p>
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.
</p>
<div style="text-align: center">
<p>
<b>ADBase.adl</b></p>
<img alt="ADBase.png" src="ADBase.png" /></div>
<h2 id="Detector_drivers">
Detector drivers</h2>
<p>
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:</p>
<ul>
<li><a href="simDetectorDoc.html">Simulation detector driver</a></li>
<li><a href="prosilicaDoc.html">Prosilica driver</a></li>
<li><a href="pilatusDoc.html">Pilatus driver</a></li>
<li><a href="adscDoc.html">ADSC driver</a></li>
</ul>
</body>
</html>