git-svn-id: https://subversion.xor.aps.anl.gov/synApps/areaDetector/trunk@7672 dc6c5ff5-0b8b-c028-a01f-ffb33f00fc8b
1665 lines
64 KiB
HTML
Executable File
1665 lines
64 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>
|
|
<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>
|
|
</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 a mechanism for device-independent real-time data analysis such as regions-of-interest
|
|
and statistics.</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>
|
|
</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 provides an API has the ability to save the data
|
|
to a file and an application to display the images.
|
|
</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>
|
|
<h3 id="asynPortDriver">
|
|
asynPortDriver</h3>
|
|
<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-> 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-> getAddr()</code> function.
|
|
Typically it is 1, but some plugins (e.g. NDPluginROI) support values > 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-> getAddr(pasynUser,...). Returns an error
|
|
if the address is not valid, e.g. >= this-> 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-> 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 > 0, and prints parameter table information if details > 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-> exceptionConnect</code>
|
|
and <code>pasynManager-> 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>
|
|
<h3 id="NDArray">
|
|
NDArray</h3>
|
|
<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 > 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,
|
|
e.g. frame number. 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>
|
|
<h3 id="NDArrayPool">
|
|
NDArrayPool</h3>
|
|
<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>
|
|
<h3 id="asynNDArrayDriver">
|
|
asynNDArrayDriver</h3>
|
|
<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 > 5.</li>
|
|
</ul>
|
|
<h3 id="ADDriver">
|
|
ADDriver</h3>
|
|
<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>
|
|
<h3 id="ADStdDriverParams">
|
|
ADStdDriverParams</h3>
|
|
<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 string 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 that
|
|
redefines that record field 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 constructed using the algorithm described in ADFileTemplate</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 a file is saved (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) controlling whether a file is automatically saved each
|
|
time acquisition completes.</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>
|
|
<p>
|
|
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.</p>
|
|
</body>
|
|
</html>
|