Files
ADAndor/documentation/areaDetectorDoc.html
2010-11-13 16:25:42 +00:00

1991 lines
68 KiB
HTML
Executable File

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>areaDetector: EPICS software for area detectors</title>
<meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type" />
</head>
<body>
<div style="text-align: center">
<h1>
areaDetector: EPICS Area Detector Support</h1>
<h2>
May 20, 2010</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="#NDAttribute">NDAttribute</a></li>
<li><a href="#NDAttributeList">NDAttributeList</a></li>
<li><a href="#PVAttribute">PVAttribute</a></li>
<li><a href="#paramAttribute">paramAttribute</a></li>
<li><a href="#asynNDArrayDriver">asynNDArrayDriver</a></li>
</ul>
</li>
<li>Detector drivers
<ul>
<li><a href="#ADDriver">ADDriver</a></li>
<li><a href="#Guidelines">Guidelines and rules for drivers</a></li>
<li><a href="adscDoc.html">ADSC driver</a></li>
<li><a href="brukerDoc.html">Bruker driver</a></li>
<li><a href="http://controls.diamond.ac.uk/downloads/support/firewireDCAM/index.html">
Firewire Linux driver</a></li>
<li><a href="FirewireWinDoc.html">Firewire Windows driver</a></li>
<li><a href="Mar345Doc.html">mar345 driver</a></li>
<li><a href="MarCCDDoc.html">MarCCD driver</a></li>
<li><a href="PerkinElmerDoc.html">Perkin-Elmer flat panel driver</a></li>
<li><a href="pilatusDoc.html">Pilatus driver</a></li>
<li><a href="prosilicaDoc.html">Prosilica driver</a></li>
<li><a href="pvcamDoc.html">PVCAM driver</a></li>
<li><a href="RoperDoc.html">Roper driver</a></li>
<li><a href="simDetectorDoc.html">Simulation detector driver</a></li>
<li><a href="URLDriverDoc.html">URL driver</a></li>
</ul>
</li>
<li><a href="pluginDoc.html">Plugins</a>
<ul>
<li><a href="pluginDoc.html#NDPluginDriver">NDPluginDriver</a></li>
<li><a href="pluginDoc.html#Guidelines">Guidelines and rules for plugins</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>
<li><a href="NDPluginStats.html">NDPluginStats</a></li>
<li><a href="NDPluginProcess.html">NDPluginProcess</a></li>
<li><a href="NDPluginOverlay.html">NDPluginOverlay</a></li>
<li><a href="NDPluginTransform.html">NDPluginTransform</a></li>
<li><a href="NDPluginColorConvert.html">NDPluginColorConvert</a></li>
</ul>
</li>
<li><a href="#MEDM_screens">MEDM screens</a></li>
<li><a href="areaDetectorViewers.html">Viewers</a>
<ul>
<li><a href="areaDetectorViewers.html#ImageJViewer">ImageJ Viewer</a></li>
<li><a href="areaDetectorViewers.html#IDLViewer">IDL Viewer</a></li>
</ul>
</li>
<li><a href="#Installation">Installation, configuration, and startup</a></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 <a href="http://www.aps.anl.gov/epics/">EPICS</a>. 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, IEEE 1394 (Firewire) cameras, ADSC and
MAR CCD x-ray detectors, MAR-345 online imaging plate detectors, the Pilatus pixel-array
detector, Roper Scientific CCD cameras, and the Perkin-Elmer amorphous silicon detector.</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 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 can pass 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 800 to 1800
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),
color mode conversion (NDPluginColorConvert), 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 300 to 800 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. areaDetector includes two client applications that
can display images using EPICS waveform and other records communicating with the
NDPluginStdArrays plugin at Layer 3. One of these clients is an ImageJ plugin, and
the other is a freely runnable IDL application.</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/10-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. Plugins can be used to form an image processing pipeline, for
example with a detector providing data to a color convert plugin, which feeds an
ROI plugin, which feeds a file saving plugin. Each plugin can run in its own thread,
and hence in its own core on a modern multi-core CPU.
</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++.
</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.
They inherit from the <a href="http://www.aps.anl.gov/epics/modules/soft/asyn/R4-11a/asynPortDriver.html">
asynPortDriver base C++ class</a> that is provided in the asyn module. That base
class handles all of the details of registering the port driver, registering the
supported interfaces, and registering the required interrupt sources. It also provides
a parameter library for int, double, and string parameters indexed by the integer
index values defined in the driver. The parameter library provides methods to write
and read the parameter values, and to perform callbacks to registered clients when
a parameter value has changed. The <a href="http://www.aps.anl.gov/epics/modules/soft/asyn/R4-11a/asynDoxygenHTML/classasyn_port_driver.html">
asynPortDriver class documentation</a> describes this class in detail.
</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. An NDArray is a general purpose class for handling
array data. An NDArray object is self-describing, meaning it contains enough information
to describe the data itself. It can optionally contain "attributes" (class NDAttribute)
which contain meta-data describing how the data was collected, etc.
</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 <a href="areaDetectorDoxygenHTML/struct_n_d_dimension.html">
NDDimension structure</a>. The <a href="areaDetectorDoxygenHTML/class_n_d_array.html">
NDArray class documentation </a>describes this class in detail.
</p>
<h3 id="NDArrayPool">
NDArrayPool</h3>
<p>
The NDArrayPool class manages a free list (pool) of NDArray objects. Drivers allocate
NDArray objects from the pool, and pass these objects to plugins. Plugins increase
the reference count on the object when they place the object on their queue, and
decrease the reference count when they are done processing the array. When the reference
count reaches 0 again the NDArray object is placed back on the free list. This mechanism
minimizes the copying of array data in plugins. The <a href="areaDetectorDoxygenHTML/class_n_d_array_pool.html">
NDArrayPool class documentation </a>describes this class in detail.
</p>
<h3 id="NDAttribute">
NDAttribute</h3>
<p>
The NDAttribute is a class for linking metadata to an NDArray. An NDattribute has
a name, description, data type, value, source type and source information. Attributes
are identified by their names, which are case-insensitive. There are methods to
set and get the information for an attribute.</p>
<p>
It is useful to define some conventions for attribute names, so that plugins or
data analysis programs can look for a specific attribute. The following are the
attribute conventions used in current plugins:</p>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left">
<tbody>
<tr>
<td align="center" colspan="7">
<b>Conventions for standard attribute names</b></td>
</tr>
<tr>
<th>
Attribute name</th>
<th>
Description</th>
<th>
Data type</th>
</tr>
<tr>
<td>
ColorMode</td>
<td>
"Color mode"</td>
<td>
int (NDColorMode_t)</td>
</tr>
<tr>
<td>
BayerPattern</td>
<td>
"Bayer pattern"</td>
<td>
int (NDBayerPattern_t)</td>
</tr>
</tbody>
</table>
<p>
Attribute names are case-insensitive in the areaDetector software, but external
software may not be case-insensitive so the attribute names should generally be
used exactly as they appear above. For attributes not in this table a good convention
would be to use the corresponding driver parameter without the leading ND or AD,
and with the first character of every "word" of the name starting with upper case.
For example, the standard attribute name for ADManufacturer should be "Manufacturer",
ADNumExposures should be "NumExposures", etc.</p>
<p>
The <a href="areaDetectorDoxygenHTML/class_n_d_attribute.html">NDAttribute class documentation</a>
describes this class in detail.
</p>
<h3 id="NDAttributeList">
NDAttributeList</h3>
<p>
The NDAttributeList implements a linked list of NDAttribute objects. NDArray objects
contain an NDAttributeList which is how attributes are associated with an NDArray.
There are methods to add, delete and search for NDAttribute objects in an NDAttributeList.
Each attribute in the list must have a unique name, which is case-insensitive.
</p>
<p>
When NDArrays are copied with the NDArrayPool methods the attribute list is also
copied.
</p>
<p>
IMPORTANT NOTE: When a new NDArray is allocated using NDArrayPool::alloc() the behavior
of any existing attribute list on the NDArray taken from the pool is determined
by the value of the global variable <code>eraseNDAttributes</code>. By default the
value of this variable is 0. This means that when a new NDArray is allocated from
the pool its attribute list is <strong>not</strong> cleared. This greatly improves
efficiency in the normal case where attributes for a given driver are defined once
at initialization and never deleted. (The attribute <strong>values</strong> may
of course be changing.) It eliminates allocating and deallocating attribute memory
each time an array is obtained from the pool. It is still possible to add new attributes
to the array, but any existing attributes will continue to exist even if they are
ostensibly cleared e.g. asynNDArrayDriver::readNDAttributesFile() is called again.
If it is desired to eliminate all existing attributes from NDArrays each time a
new one is allocated then the global variable <code>eraseNDAttributes</code> should
be set to 1. This can be done at the iocsh prompt with the command:</p>
<pre> var eraseNDAttributes 1
</pre>
<p>
The <a href="areaDetectorDoxygenHTML/class_n_d_attribute_list.html">NDAttributeList
class documentation</a> describes this class in detail.
</p>
<h3 id="PVAttribute">
PVAttribute</h3>
<p>
The PVAttribute class is derived from NDAttribute. It obtains its value by monitor
callbacks from an EPICS PV, and is thus used to associate current the value of any
EPICS PV with an NDArray. The <a href="areaDetectorDoxygenHTML/class_p_v_attribute.html">
PVAttribute class documentation</a> describes this class in detail.
</p>
<h3 id="paramAttribute">
paramAttribute</h3>
<p>
The paramAttribute class is derived from NDAttribute. It obtains its value from
the current value of a driver or plugin parameter. The paramAttribute class is typically
used when it is important to have the current value of the parameter and the value
of a corresponding PVAttribute might not be current because the EPICS PV has not
yet updated. The <a href="areaDetectorDoxygenHTML/classparam_attribute.html">paramAttribute
class documentation</a> describes this class in detail.
</p>
<h3 id="asynNDArrayDriver">
asynNDArrayDriver</h3>
<p>
asynNDArrayDriver inherits from asynPortDriver. It implements the asynGenericPointer
functions for NDArray objects. This is the class from which both plugins and area
detector drivers are indirectly derived. The <a href="areaDetectorDoxygenHTML/classasyn_n_d_array_driver.html">
asynNDArrayDriver class documentation </a>describes this class in detail.
</p>
<p>
The file <a href="areaDetectorDoxygenHTML/asyn_n_d_array_driver_8h.html">asynNDArrayDriver.h</a>
defines a number of parameters that all NDArray drivers and plugins should implement
if possible. These parameters are defined by strings (drvInfo strings in asyn) with
an associated asyn interface, and access (read-only or read-write). There is also
an integer index to the parameter which is assigned by asynPortDriver when the parameter
is created in the parameter library. 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>Parameter index variable:</b> The variable name for this parameter index in
the driver. There are several EPICS records in ADBase.template that do not have
corresponding parameter indices, 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>drvInfo 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. It
is also used to associate a <a href="areaDetectorDoxygenHTML/classparam_attribute.html">
paramAttribute</a> with a driver parameter in the XML file that is read by asynNDArrayDriver::readNDAttributesFile</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 such long strings from a string to
an integer or byte array before sending the path name to EPICS. In IDL this is done
as follows:
<pre> ; Convert a string to a null-terminated byte array and write with caput
IDL> t = caput('13PS1:TIFF1:FilePath', [byte('/home/epics/scratch'),0B])
; Read a null terminated byte array
IDL> t = caget('13PS1:TIFF1:FilePath', v)
; Convert to a string
IDL> s = string(v)
</pre>
In SPEC this is done as follows:
<pre> array _temp[256]
# Setting the array to "" will zero-fill it
_temp = ""
# Copy the string to the array. Note, this does not null terminate, so if array already contains
# a longer string it needs to first be zeroed by setting it to "".
_temp = "/home/epics/scratch"
epics_put("13PS1:TIFF1:FilePath", _temp)
</pre>
</li>
</ul>
<p>
Note that for parameters whose values are defined by enum values (e.g NDDataType,
NDColorMode, etc.), drivers can use a different set of enum values for these parameters.
They can override the enum menu in ADBase.template with driver-specific choices
by loading a driver-specific template file that redefines that record field after
loading ADBase.template.
</p>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left">
<tbody>
<tr>
<td align="center" colspan="7">
<b>Parameter Definitions in asynNDArrayDriver.h and EPICS Record Definitions in ADBase.template
(file-related records are in NDFile.template)</b></td>
</tr>
<tr>
<th>
Parameter index variable</th>
<th>
asyn interface</th>
<th>
Access</th>
<th>
Description</th>
<th>
drvInfo string</th>
<th>
EPICS record name</th>
<th>
EPICS record type</th>
</tr>
<tr>
<td align="center" colspan="7">
<b>Information about the asyn port</b></td>
</tr>
<tr>
<td>
NDPortNameSelf</td>
<td>
asynOctet</td>
<td>
r/o</td>
<td>
asyn port name</td>
<td>
PORT_NAME_SELF</td>
<td>
$(P)$(R)PortName_RBV</td>
<td>
stringin</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Data type</b></td>
</tr>
<tr>
<td>
NDDataType</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>Color mode</b></td>
</tr>
<tr>
<td>
NDColorMode</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Color mode (NDColorMode_t).</td>
<td>
COLOR_MODE</td>
<td>
$(P)$(R)ColorMode<br />
$(P)$(R)ColorMode_RBV</td>
<td>
mbbo<br />
mbbi</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Actual dimensions of array data</b></td>
</tr>
<tr>
<td>
NDArraySizeX</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Size of the array data in the X direction</td>
<td>
ARRAY_SIZE_X</td>
<td>
$(P)$(R)ArraySizeX_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td>
NDArraySizeY</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Size of the array data in the Y direction</td>
<td>
ARRAY_SIZE_Y</td>
<td>
$(P)$(R)ArraySizeY_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td>
NDArraySizeZ</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Size of the array data in the Z direction</td>
<td>
ARRAY_SIZE_Z</td>
<td>
$(P)$(R)ArraySizeZ_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td>
NDArraySize</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Total size of the array data in bytes</td>
<td>
ARRAY_SIZE</td>
<td>
$(P)$(R)ArraySize_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>File saving parameters (records are defined in NDFile.template)</b></td>
</tr>
<tr>
<td>
NDFilePath</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>
NDFilePathExists</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Flag indicating if file path exists</td>
<td>
FILE_PATH_EXISTS</td>
<td>
$(P)$(R)FilePathExists_RBV</td>
<td>
bi</td>
</tr>
<tr>
<td>
NDFileName</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>
NDFileNumber</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>
NDFileTemplate</td>
<td>
asynOctet</td>
<td>
r/w</td>
<td>
Format string for constructing NDFullFileName from NDFilePath, NDFileName, and NDFileNumber.
The final file name (which is placed in NDFullFileName) is created with the following
code:
<pre>epicsSnprintf(
FullFilename,
sizeof(FullFilename),
FileTemplate, FilePath,
Filename, FileNumber);
</pre>
FilePath, Filename, FileNumber are converted in that order with FileTemplate. 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 FileTemplate as desired. If one does not want to have FileNumber in the file
name at all, then just omit the %d format specifier from FileTemplate. If the client
wishes to construct the complete file name itself, then it can just put that file
name into NDFileTemplate with no format specifiers at all, in which case NDFilePath,
NDFileName, and NDFileNumber 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>
NDFullFileName</td>
<td>
asynOctet</td>
<td>
r/o</td>
<td>
Full file name constructed using the algorithm described in NDFileTemplate</td>
<td>
FULL_FILE_NAME</td>
<td>
$(P)$(R)FullFileName_RBV</td>
<td>
waveform<br />
waveform</td>
</tr>
<tr>
<td>
NDAutoIncrement</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>
NDAutoSave</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>
NDFileFormat</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>
NDWriteFile</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Manually save the most recent array to a file when value=1</td>
<td>
WRITE_FILE</td>
<td>
$(P)$(R)WriteFile<br />
$(P)$(R)WriteFile_RBV</td>
<td>
busy<br />
bi</td>
</tr>
<tr>
<td>
NDReadFile</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<br />
$(P)$(R)ReadFile_RBV</td>
<td>
busy<br />
bi</td>
</tr>
<tr>
<td>
NDFileWriteMode</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
File saving mode (Single, Capture, Stream)(NDFileMode_t)</td>
<td>
WRITE_MODE</td>
<td>
$(P)$(R)FileWriteMode<br />
$(P)$(R)FileWriteMode_RBV</td>
<td>
mbbo<br />
mbbi</td>
</tr>
<tr>
<td>
NDFileCapture</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Start (1) or stop (0) file capture or streaming</td>
<td>
CAPTURE</td>
<td>
$(P)$(R)Capture<br />
$(P)$(R)Capture_RBV</td>
<td>
busy<br />
bi</td>
</tr>
<tr>
<td>
NDFileNumCapture</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Number of frames to acquire in capture or streaming mode</td>
<td>
NUM_CAPTURE</td>
<td>
$(P)$(R)NumCapture<br />
$(P)$(R)NumCapture_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
NDFileNumCaptured</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Number of arrays currently acquired capture or streaming mode</td>
<td>
NUM_CAPTURED</td>
<td>
$(P)$(R)NumCaptured_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Array data</b></td>
</tr>
<tr>
<td>
NDArrayCallbacks</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Controls whether the driver does callbacks with the array data to registered plugins.
0=No, 1=Yes. Setting this to 0 can reduce overhead in the case that the driver is
being used only to control the device, and not to make the data available to plugins
or to EPICS clients.</td>
<td>
ARRAY_CALLBACKS</td>
<td>
$(P)$(R)ArrayCallbacks<br />
$(P)$(R)ArrayCallbacks_RBV</td>
<td>
bo<br />
bi</td>
</tr>
<tr>
<td>
NDArrayData</td>
<td>
asynGenericPointer</td>
<td>
r/w</td>
<td>
The array data as an NDArray object</td>
<td>
NDARRAY_DATA</td>
<td>
N/A. EPICS access to array data is through NDStdArrays plugin.</td>
<td>
N/A</td>
</tr>
<tr>
<td>
NDArrayCounter</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Counter that increments by 1 each time an array is acquired. Can be reset by writing
a value to it.</td>
<td>
ARRAY_COUNTER</td>
<td>
$(P)$(R)ArrayCounter<br />
$(P)$(R)ArrayCounter_RBV</td>
<td>
longout<br />
longin</td>
</tr>
<tr>
<td>
N/A</td>
<td>
N/A</td>
<td>
r/o</td>
<td>
Rate at which arrays are being acquired. Computed in the ADBase.template database.</td>
<td>
N/A</td>
<td>
$(P)$(R)ArrayRate_RBV</td>
<td>
calc</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Array attributes</b></td>
</tr>
<tr>
<td>
NDAttributesFile</td>
<td>
asynOctet</td>
<td>
r/w</td>
<td>
The name of an XML file defining the PVAttributes and paramAttributes to be added
to each NDArray by this driver or plugin. The format of the XML file is described
in the documentation for <a href="areaDetectorDoxygenHTML/classasyn_n_d_array_driver.html">
asynNDArrayDriver::readNDAttributesFile().</a></td>
<td>
ND_ATTRIBUTES_FILE</td>
<td>
$(P)$(R)NDAttributesFile</td>
<td>
waveform</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Debugging control</b></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>
<h3 id="ADDriver">
ADDriver</h3>
<p>
ADDriver inherits from asynNDArrayDriver. This is the class from which area detector
drivers are directly derived. It provides parameters and methods that are specific
to area detectors, while asynNDArrayDriver is a general NDArray driver. The <a href="areaDetectorDoxygenHTML/class_a_d_driver.html">
ADDriver class documentation </a>describes this class in detail.
</p>
<p>
The file <a href="areaDetectorDoxygenHTML/_a_d_driver_8h.html">ADDriver.h</a> defines
the parameters that all areaDetector drivers should implement if possible.
</p>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left">
<tbody>
<tr>
<td align="center" colspan="7">
<b>Parameter Definitions in ADDriver.h and EPICS Record Definitions in ADBase.template</b></td>
</tr>
<tr>
<th>
Parameter index variable</th>
<th>
asyn interface</th>
<th>
Access</th>
<th>
Description</th>
<th>
drvInfo string</th>
<th>
EPICS record name</th>
<th>
EPICS record type</th>
</tr>
<tr>
<td align="center" colspan="7" style="height: 25px">
<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>
ADTemperature</td>
<td>
asynFloat64</td>
<td>
r/w</td>
<td>
Detector temperature</td>
<td>
TEMPERATURE</td>
<td>
$(P)$(R)Temperature<br />
$(P)$(R)Temperature_RBV<br />
</td>
<td>
ao<br />
ai</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 array 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 array 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>Frame type</b></td>
</tr>
<tr>
<td>
ADFrameType</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Frame type (ADFrameType_t).</td>
<td>
FRAME_TYPE</td>
<td>
$(P)$(R)FrameType<br />
$(P)$(R)FrameType_RBV</td>
<td>
mbbo<br />
mbbi</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 is an EPICS busy record that does
not process its forward link until acquisition is complete. Clients should write
1 to the Acquire record to start acquisition, and wait for Acquire to go to 0 to
know that acquisition is complete.</td>
<td>
ACQUIRE</td>
<td>
$(P)$(R)Acquire<br />
$(P)$(R)Acquire_RBV</td>
<td>
busy<br />
bi</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>
ADNumExposuresCounter</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Counter that increments by 1 each time an exposure is acquired for the current image.
Driver resets to 0 when acquisition is started.</td>
<td>
NUM_EXPOSURES_COUNTER</td>
<td>
$(P)$(R)NumExposuresCounter_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td>
ADNumImagesCounter</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Counter that increments by 1 each time an image is acquired in the current acquisition
sequence. Driver resets to 0 when acquisition is started. Drivers can use this as
the loop counter when ADImageMode=ADImageMultiple.</td>
<td>
NUM_IMAGES_COUNTER</td>
<td>
$(P)$(R)NumImagesCounter_RBV</td>
<td>
longin</td>
</tr>
<tr>
<td>
ADTimeRemaining</td>
<td>
asynFloat64</td>
<td>
r/o</td>
<td>
Time remaining for current image. Drivers should update this value if they are doing
the exposure timing internally, rather than in the detector hardware.</td>
<td>
TIME_REMAINING</td>
<td>
$(P)$(R)TimeRemaining_RBV</td>
<td>
ai</td>
</tr>
<tr>
<td>
ADReadStatus</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Write a 1 to this parameter to force a read of the detector status. Detector drivers
normally read the status as required, so this is usually not necessary, but there
may be some circumstances under which forcing a status read may be needed.</td>
<td>
READ_STATUS</td>
<td>
$(P)$(R)ReadStatus</td>
<td>
bo</td>
</tr>
<tr>
<td align="center" colspan="7">
<b>Shutter control</b></td>
</tr>
<tr>
<td>
ADShutterMode</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Shutter mode (None, detector-controlled or EPICS-controlled) (ADShutterMode_t)</td>
<td>
SHUTTER_MODE</td>
<td>
$(P)$(R)ShutterMode<br />
$(P)$(R)ShutterMode_RBV</td>
<td>
mbbo<br />
mbbi</td>
</tr>
<tr>
<td>
ADShutterControl</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
Shutter control for the selected (detector or EPICS) shutter (ADShutterStatus_t)</td>
<td>
SHUTTER_CONTROL</td>
<td>
$(P)$(R)ShutterControl<br />
$(P)$(R)ShutterControl_RBV</td>
<td>
bo<br />
bi</td>
</tr>
<tr>
<td>
ADShutterControlEPICS</td>
<td>
asynInt32</td>
<td>
r/w</td>
<td>
This record processes when it receives a callback from the driver to open or close
the EPICS shutter. It triggers the records below to actually open or close the EPICS
shutter.</td>
<td>
SHUTTER_CONTROL_EPICS</td>
<td>
$(P)$(R)ShutterControlEPICS</td>
<td>
bi</td>
</tr>
<tr>
<td>
N/A</td>
<td>
N/A</td>
<td>
r/w</td>
<td>
This record writes its OVAL field to its OUT field when the EPICS shutter is told
to open. The OCAL (and hence OVAL) and OUT fields are user-configurable, so any
EPICS-controllable shutter can be used.</td>
<td>
N/A</td>
<td>
$(P)$(R)ShutterOpenEPICS</td>
<td>
calcout</td>
</tr>
<tr>
<td>
N/A</td>
<td>
N/A</td>
<td>
r/w</td>
<td>
This record writes its OVAL field to its OUT field when the EPICS shutter is told
to close. The OCAL (and hence OVAL) and OUT fields are user-configurable, so any
EPICS-controllable shutter can be used.</td>
<td>
N/A</td>
<td>
$(P)$(R)ShutterCloseEPICS</td>
<td>
calcout</td>
</tr>
<tr>
<td>
ADShutterStatus</td>
<td>
asynInt32</td>
<td>
r/o</td>
<td>
Status of the detector-controlled shutter (ADShutterStatus_t)</td>
<td>
SHUTTER_STATUS</td>
<td>
$(P)$(R)ShutterStatus_RBV</td>
<td>
bi</td>
</tr>
<tr>
<td>
N/A</td>
<td>
N/A</td>
<td>
r/o</td>
<td>
Status of the EPICS-controlled shutter. This record should have its input link (INP)
set to a record that contains the open/close status information for the shutter.
The link should have the "CP" attribute, so this record processes when the input
changes. The ZRVL field should be set to the value of the input link when the shutter
is closed, and the ONVL field should be set to the value of the input link when
the shutter is open.</td>
<td>
N/A</td>
<td>
$(P)$(R)ShutterStatusEPICS_RBV</td>
<td>
mbbi</td>
</tr>
<tr>
<td>
ADShutterOpenDelay</td>
<td>
asynFloat64</td>
<td>
r/w</td>
<td>
Time required for the shutter to actually open (ADShutterStatus_t)</td>
<td>
SHUTTER_OPEN_DELAY</td>
<td>
$(P)$(R)ShutterOpenDelay<br />
$(P)$(R)ShutterOpenDelay_RBV</td>
<td>
ao<br />
ai</td>
</tr>
<tr>
<td>
ADShutterCloseDelay</td>
<td>
asynFloat64</td>
<td>
r/w</td>
<td>
Time required for the shutter to actually close (ADShutterStatus_t)</td>
<td>
SHUTTER_CLOSE_DELAY</td>
<td>
$(P)$(R)ShutterCloseDelay<br />
$(P)$(R)ShutterCloseDelay_RBV</td>
<td>
ao<br />
ai</td>
</tr>
</tbody>
</table>
<h2 id="Guidelines">
Guidelines and rules for drivers</h2>
<p>
The following are guidelines and rules for writing areaDetector drivers</p>
<ul>
<li>Drivers will generally implement one or more of the writeInt32(), writeFloat64()
or writeOctet() functions if they need to act immediately on a new value of a parameter.
For many parameters it is normally sufficient to simply have them written to the
parameter library, and not to handle them in the writeXXX() functions. The parameters
are then retrieved from the parameter library with the getIntParam(), getDoubleParam(),
or getStringParam() function calls when they are needed.</li>
<li>If the writeInt32(), writeFloat64() or writeOctet() functions are implemented
they <b>must</b> call the base class function for parameters that they do not handle
and whose parameter index value is less than the first parameter of this class,
i.e. parameters that belong to a base class.</li>
<li>Drivers will need to call the createParam() function in their constructor if they
have additional parameters beyond those in the asynPortDriver or ADDriver base classes.</li>
<li>Drivers will generally need to create a new thread in which they run the acquisition
task. Some vendor libraries create such a thread themselves, and then the driver
must just implement a callback function that runs in that thread (the Prosilica
is an example of such a driver).</li>
<li>The acquisition thread will typically monitor the acquisition process and perform
periodic status update callbacks. The details of how to implement this will vary
depending on the specifics of the vendor API. There are many existing detector drivers
that can be used as examples of how to write a new driver.</li>
<li>If the detector hardware does not support fixed-period acquisition or muliple-image
acquisition sequence (ADNumImages parameter) then these should be emulated in the
driver. The simDetector, marCCD and other drivers can be used as examples of how
to do this.</li>
<li>If NDArrayCallbacks is non-zero then drivers should do the following:
<ul>
<li>Call asynNDArrayDriver::getAttributes to attach any attributes defined for this
driver to the current array.</li>
<li>Call doCallbacksGenericPointer() so that registered clients can get the values
of the new arrays. Drivers must release their mutex by calling this->unlock() before
they call doCallbacksGenericPointer(), or a deadlock can occur if the plugin makes
a call to one of the driver functions.</li>
</ul>
</li>
</ul>
<h2 id="MEDM_screens">
MEDM screens</h2>
<p>
The following is the top-level MEDM screen that provides links to the screens for
most of the detectors and plugins that areaDetector supports. This screen is useful
for testing, and as a source for copying related-display menus to be placed in application-specific
MEDM screens.
</p>
<div style="text-align: center">
<p>
<b>ADTop.adl</b></p>
<img alt="ADTop.png" src="ADTop.png" /></div>
<p>
The following is the MEDM screen that provides access to the parameters in asynNDArrayDriver.h
and ADDriver.h through records in ADBase.template. This is a top-level MEDM screen
that will work with any areaDetector driver. Note however that many drivers will
not implement all of these parameters, and there will usually be detector-specific
parameters not shown in this screen, so detector-specific MEDM screens should generally
be created that display the EPICS PVs for the features implemented for that detector.
</p>
<div style="text-align: center">
<p>
<b>ADBase.adl</b></p>
<img alt="ADBase.png" src="ADBase.png" /></div>
<p>
The following is the MEDM screen that provides access to the file-related parameters
in asynNDArrayDriver.h through records in NDFile.template. This screen is for use
with detector drivers that directly implement file I/O.
</p>
<div style="text-align: center">
<p>
<b>NDFile.adl</b></p>
<img alt="NDFile.png" src="NDFile.png" /></div>
<p>
The following is the MEDM screen that provides access to the EPICS shutter parameters
in ADDriver.h through records in ADBase.template. This screen allows one to define
the EPICS PVs to open the shutter, close the shutter, and determine the shutter
status. The values of these PVs for open and close drive and status can also be
defined. Note that in many cases the same PV will be used for open and close drive,
but in some cases (e.g. APS safety shutters) different PVs are used for open and
close.
</p>
<div style="text-align: center">
<p>
<b>ADEpicsShutter.adl</b></p>
<img alt="ADEpicsShutter.png" src="ADEpicsShutter.png" /></div>
<h2 id="Installation">
Installation, configuration, and running</h2>
<h3>
Installation: source code version</h3>
<p>
After obtaining a copy of the distribution, it must be installed and built for use
at your site. These steps only need to be performed once for the site (unless versions
of the module running under different releases of EPICS and/or the other required
modules are needed).</p>
<ol>
<li>Create an installation directory for the module, usually this will end with<br />
<br />
<tt>.../support/</tt>
<br />
</li>
<li>Place the distribution file in this directory. Then issue the commands (Unix style)
<pre>tar xvzf areaDetectorRX-Y.tgz
</pre>
where X-Y is the release.</li>
<li>This creates a &lt;top&gt; application.<br />
<pre>.../support/areaDetectorRX-Y
</pre>
</li>
<li>Download all required supporting modules if you don't already have them. This
includes asyn, autosave, busy, etc.</li>
<li>Edit the <tt>configure/RELEASE</tt> file and set the paths to your installation
of EPICS base and to your versions of supporting modules.</li>
<li>Run <tt>gnumake</tt> in the top level directory and check for any compilation
errors.</li>
</ol>
<h3>
Installation: prebuilt version</h3>
<p>
Prebuilt versions of areaDetector are provide for Windows (win32-x86), Cygwin (cygwin-x86),
and Linux (linux-x86). Follow these steps to use the prebuilt version:</p>
<ol>
<li>Create an installation directory for the module. On Windows I typically use C:\EPICS\support.
On Linux I typically use /home/ACCOUNT/epics/support, where ACCOUNT is the name
of the account that is normally used to run the detector software, e.g. marccd on
a marCCD detector, mar345 on a mar345 detector, etc.</li>
<li>Place the distribution file in this directory. Then issue the commands (Unix style)
<pre>tar xvzf areaDetectorPrebuilt_RX-Y.tgz</pre>
</li>
<li>In the iocBoot directory make a <b>copy</b> of the example ioxXXX directory for
the detector you are using and give it a new local name. By doing this you will
be able to update to later versions of areaDetector without overwriting modifications
you make in the iocXXX directory.</li>
<li>In the new iocXXX directory you just created edit st.cmd to change the PV prefix
$(P) to one that is unique to your site. PV prefixes must be unique on the subnet,
and if you use the default prefix there could be a conflict with other detectors
of the same type. </li>
<li>In the same iocXXX directory edit the file envPaths to point to the locations
of all of the support modules on your system. Normally this is handled by the EPICS
build system, but when using the prebuilt version this must be manually edited.
Do not worry about the path to EPICS_BASE, it is not required.</li>
</ol>
<h3>
Installation: medm</h3>
<p>
areaDetector provides display/control screens for the <a href="http://www.aps.anl.gov/epics/extensions/medm/">
medm</a> Motif Editor and Display Manager. A prebuilt version of medm for Windows
can be found in the <a href="http://www.aps.anl.gov/epics/distributions/win32/">EPICS
WIN32 Extensions</a>. For Linux one can build medm from source code, which requires
downloading and building <a href="http://www.aps.anl.gov/epics/base/">EPICS base</a>
first. Alternatively I provide a prebuilt version of medm for Linux in the <a href="http://cars.uchicago.edu/software/pub/EPICS_Linux_binaries.tar">
EPICS_Linux_binraries.tar</a> package. To use this version copy the medm executable
to some location in your PATH, e.g. /usr/local/bin, or ~/bin, etc. Copy the 2 shareable
libraries libCom.so and libca.so to a location which is in your LD_LIBRARY_PATH.
To use either the source code or prebuilt version you need to have the OpenMotif
package installed. This typically is <b>not</b> installed by default with recent
versions of Linux. Go to <a href="http://www.openmotif.org/">www.openmotif.org</a>
and download and install the appropriate RPM package for your Linux version.</p>
<h3>
Configuration</h3>
<p>
Before running an areaDetector application it is usually necessary to configure
a number of items.</p>
<ul>
<li>EPICS environment variables. There are several environment variables that EPICS
uses. I suggest setting these in the .cshrc (or .bashrc) file for the account that
will be used to run the detector.
<ul>
<li>EPICS_CA_AUTO_ADDR_LIST and EPICS_CA_ADDR_LIST. These variables control the IP
addresses that EPICS clients use when searching for EPICS PVs. The default is EPICS_CA_AUTO_ADDR_LIST=YES
and EPICS_CA_ADDR_LIST to be the broadcast address of all networks connected to
the host. Some detectors, for example the marCCD and mar345, come with 2 network
cards, which are on 2 different subnets, typically a private one connected to the
detector and a public one connected to the local LAN. If the default value of these
variables is used then EPICS clients (e.g. medm) running on the detector host computer
will generate many errors because each EPICS PV will appear to be coming from both
networks. The solution is to set these variables as follows:
<pre> setenv EPICS_CA_AUTO_ADDR_LIST NO
setenv EPICS_CA_ADDR_LIST localhost:XX.YY.ZZ.255
</pre>
where XX.YY.ZZ.255 should be replaced with the broadcast address for the public
network on this computer.</li>
<li>EPICS_CA_MAX_ARRAY_BYTES. This variable controls the maximum array size that EPICS
can transmit with Channel Access. The default is only 16kB, which is much too small
for most detector data. This value must be set to a large enough value on both the
EPICS server computer (e.g. the one running the areaDetector IOC) and client computer
(e.g. the one running medm, ImageJ, IDL, etc.). This can simply be set to a very
large value like 100MB.
<pre> setenv EPICS_CA_MAX_ARRAY_BYTES 100000000
</pre>
</li>
<li>EPICS_DISPLAY_PATH. This variable controls where medm looks for .adl display files.
If the recommendation below is followed to copy all adl files to a single directory,
then this environment variable should be defined to point to that directory. For
example:
<pre> setenv EPICS_DISPLAY_PATH /home/mar345/epics/adls
</pre>
</li>
</ul>
</li>
<li>medm display files. I find it convenient to copy all medm .adl files to a single
directory and then point the environment variable EPICS_DISPLAY_PATH to this directory.
The alternative is to point EPICS_DISPLAY_PATH to a long list of directories where
the adl files are located in the distributions, which is harder to maintain. On
the mar345, for example, I create a directory called /home/mar345/epics/adls, where
I put all of the adl files. To simplify copying the adl files to that location I
use the following one-line script, which I place in /home/mar345/bin/sync_adls.
<pre> find /home/mar345/epics/support -name '*.adl' -exec cp -fv {} /home/mar345/epics/adls \;
</pre>
This script finds all adl files in the epics/support tree and copies them to /home/mar345/epics/adls.
That directory must be created before running this script. Similar scripts can be
used for other Linux detectors (marCCD, Pilatus, etc.) and can be used on Windows
as well if Cygwin is installed. Each time a new release of areaDetector is installed
remove the old versions of each support module (areaDetector, asyn, autosave, etc.)
and then run this script to install the latest medm files. </li>
</ul>
<h3>
Running the IOC</h3>
<p>
Each example IOC directory comes with a Linux script (start_epics) or a Windows
batch file (start_epics.bat) or both depending on the architectures that the detector
runs on. These scripts provide simple examples of how to start medm and the EPICS
IOC. For example, for the mar345 iocBoot/iocMAR345/start_epics contains the following:</p>
<pre> medm -x -macro "P=13MAR345_1:, R=cam1:, I=image1:, ROI=ROI1:, NETCDF=netCDF1:, TIFF=TIFF1:, JPEG=JPEG1:, NEXUS=Nexus1:" mar345.adl &amp;
../../bin/linux-x86/mar345App st.cmd
</pre>
<p>
This script starts medm in execute mode with the appropriate medm display file and
macro parameters, running it in the background. It then runs the IOC application.
This script assumes that iocBoot/iocMAR345 is the default directory when it is run,
which could be added to the command or set in the configuration if this script is
set as the target of a desktop shortcut, etc. The script assumes that EPICS_DISPLAY_PATH
has been defined to be a location where the mar345.adl and related displays that
it loads can be found. You will need to edit the script in your copy of the iocXXX
directory to change the prefix (P) from 13MAR345_1: to whatever prefix you chose
for your IOC. The start_epics script could also be copied to a location in your
PATH (e.g. /home/mar345/bin/start_epics). Add a command like <code>cd /home/mar345/epics/support/areaDetector/1-5/iocBoot/iocMAR345</code>
at the beginning of the script and then type <code>start_epics</code> from any directory
to start the EPICS IOC.</p>
</body>
</html>