# areaDetector Plugins

## September 20, 2008

## Mark Rivers

## University of Chicago

## Contents

- Overview
- NDPluginDriver
- NDPluginStdArrays
- NDPluginFile
- NDPluginROI

## Overview

A powerful feature of the areaDetector module is the concept of plugins. A plugin is code that is called by a driver that passes NDArray data in a callback. Plugins can be used to process array data in real time. Existing plugins convert data to standard asyn arrays (NDPluginStdArrays), save data to disk (NDPluginFile), and select regions-of-interest (NDPluginROI). New plugins could be written to perform functions like finding the centroid of a beam, etc. Once a plugin is written it will work with any areaDetector driver. Plugins have the the following properties:

- They can execute either in a blocking mode or a non-blocking mode. In the blocking mode the callback is executed by the driver callback thread. In this mode the callback is guaranteed to execute for each NDArray callback. However, it can slow down the driver, and does not utilize the multi-core capability of modern CPUs. In the non-blocking mode the driver callback simply places the NDArray data in a queue that is part of the plugin. The plugin then executes the callback code in it own thread. It removes NDArray data from the queue, processes it, and releases the data back to the NDArrayPool when it is done. In the non-blocking mode some additional memory is required for the NDArray objects that are in the queue. It is also possible to drop NDArray data if the queue is full when a callback occurs, i.e. some callback data will not be processed. The non-blocking mode can utilize the multi-core capabilities of modern CPUs because each plugin is executing in its own thread. The operation of the queue and the NDArrayPool class means that data never needs to be copied, each plugin has a pointer to the data which will continue to be valid until the last plugin is done with it.
- They can be enabled or disabled at run time.
- They can be throttled to only execute at a limited rate. This means, for example, that a detector can be saving data to disk at full speed, but images can be posted to EPICS at a reduced rate.
- They can be unplugged from one driver, and plugged into another driver at run time. In particular the NDPluginROI driver is itself a source of NDArray data callbacks, so a file saving plugin could be unplugged from a detector driver (where it would be saving the entire detector), and plugged into a particular ROI, where it would just save a portion of the detector.

## NDPluginDriver

NDPluginDriver inherits from asynNDArrayDriver. NDPluginDriver is the class from which actual plugins are directly derived. The NDPluginDriver class handles most of the details of processing NDArray callbacks from the driver. Plugins derived from this class typically need to implement the processCallbacks method, the drvUser method, and one or more of the write(Int32, Float64, Octet) methods. The NDPluginDriver public interface is defined in NDPluginDriver.h as follows:

    class NDPluginDriver : public asynNDArrayDriver {
    public:
        NDPluginDriver(const char *portName, int queueSize, int blockingCallbacks,
                     const char *NDArrayPort, int NDArrayAddr, int maxAddr, int paramTableSize,
                     int maxBuffers, size_t maxMemory, int interfaceMask, int interruptMask);

        /* These are the methods that we override from asynNDArrayDriver */
        virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
        virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars,
                              size_t *nActual);
        virtual asynStatus readInt32Array(asynUser *pasynUser, epicsInt32 *value,
                                            size_t nElements, size_t *nIn);
        virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo,
                                         const char **pptypeName, size_t *psize);

        /* These are the methods that are new to this class */
        virtual void processCallbacks(NDArray *pArray);
        virtual int createFileName(int maxChars, char *fullFileName);
        virtual int createFileName(int maxChars, char *filePath, char *fileName);

    ...
    }

The methods of the NDPluginDriver class are:

- `NDPluginDriver` This is the constructor for the class. All parameters except queueSize, blockingCallbacks, NDArrayPort, and NDArrayAddr are just passed to the constructor for asynNDArrayDriver. NDArrayPort and NDArrayAddr, and blockingCallbacks are the initial values for the NDPluginDriverArrayPort, NDPluginDriverArrayAddr and NDPluginDriverBlockingCallbacks parameters described in the table below.
- `drvUserCreate` This method returns one of the enum values for the parameters defined in NDPluginDriver.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 plugin. If a parameter is not matched, then NDPluginDriver->drvUserCreate() will be called to see if it is a standard plugin parameter (defined in NDPluginDriver.h).
- `processCallbacks` This method is called each time a driver calls the plugin with a new NDArray object. Derived classes typically provide an implementation of this method that calls this base class method to perform some bookkeeping chores, and then they perform whatever operations are specific to that plugin.
- `createFileName` This is a convenience function that constructs a complete file name in the ADFullFileName parameter from the ADFilePath, ADFileName, ADFileNumber, and ADFileTemplate parameters. There are two variants: the first returns a complete file name, including the path. The second returns the path and file name separately.

NDPluginDriver defines parameters that all plugin 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 NDPluginBase.template provides access to these standard plugin parameters, listed in the following table. Note that to reduce the width of this table the enum names have been split into 2 lines, but these are just a single name, for example `NDPluginDriverArrayPort`.

Parameter Definitions in NDPluginDriver.h and EPICS Record Definitions in NDPluginBase.template
Enum name | asyn interface | Access | Description | drvUser string | EPICS record name | EPICS record type
--- | --- | --- | --- | --- | --- | ---
asyn NDArray driver doing callbacks
NDPluginDriver ArrayPort | asynOctet | r/w | asyn port name for NDArray driver that will make callbacks to this plugin. This port can be changed at run time, connecting the plugin to a different NDArray driver. | NDARRAY_PORT | $(P)$(R)NDArrayPort (P)$(R)NDArrayPort_RBV | stringout stringin
NDPluginDriver ArrayAddr | asynInt32 | r/w | asyn port address for NDArray driver that will make callbacks to this plugin. This address can be changed at run time, connecting the plugin to a different address in the NDArray driver. | NDARRAY_ADDR | $(P)$(R)NDArrayAddress $(P)$(R)NDArrayAddress_RBV | longout longin
Callback enable, minimum time, and statistics
NDPluginDriver EnableCallbacks | asynInt32 | r/w | Enable (1) or disable (0) callbacks from the driver to this plugin. If callbacks are disabled then the plugin will normally be idle and consume no CPU resources. | ENABLE_CALLBACKS | $(P)$(R)EnableCallbacks $(P)$(R)EnableCallbacks_RBV | bo bi
NDPluginDriver BlockingCallbacks | asynInt32 | r/w | 0 = callbacks from the driver do not block; the NDArray data is put on a queue and the callback processes in its own thread. 1 = callbacks from the driver block; the callback processes in the driver callback thread. | BLOCKING_CALLBACKS | $(P)$(R)CallbacksBlock $(P)$(R)CallbacksBlock_RBV | bo bi
NDPluginDriver MinCallbackTime | asynFloat64 | r/w | The minimum time in seconds between calls to processCallbacks. Any callbacks occuring before this minimum time has elapsed will be ignored. 0 means no minimum time, i.e. process all callbacks. | MIN_CALLBACK_TIME | $(P)$(R)MinCallbackTime $(P)$(R)MinCallbackTime_RBV | ao ai
NDPluginDriver ArrayCounter | asynInt32 | r/w | Counter that increments by 1 each time an NDArray callback is processed | ARRAY_COUNTER | $(P)$(R)ArrayCounter $(P)$(R)ArrayCounter_RBV | longout longin
N/A | N/A | r/o | Rate (Hz) at which ArrayCounter is incrementing. Computed in database. | N/A | $(P)$(R)ArrayRate_RBV | calc
NDPluginDriver DroppedArrays | asynInt32 | r/w | Counter that increments by 1 each time an NDArray callback occurs when NDPluginDriverBlockingCallbacks=0 and the plugin driver queue is full, so the callback cannot be processed. | DROPPED_ARRAYS | $(P)$(R)DroppedArrays $(P)$(R)DroppedArrays_RBV | longout longin
Information about last NDArray callback data
NDPluginDriver NDimensions | asynInt32 | r/o | Number of dimensions in last NDArray callback data | ARRAY_NDIMENSIONS | $(P)$(R)NDimensions_RBV | longin
NDPluginDriver Dimensions | asynInt32Array | r/o | Dimensions in last NDArray callback data | ARRAY_DIMENSIONS | $(P)$(R)Dimensions_RBV | waveform
N/A | N/A | r/o | First dimension of NDArray callback data | N/A | $(P)$(R)ArraySize0_RBV | longin
N/A | N/A | r/o | Second dimension of NDArray callback data | N/A | $(P)$(R)ArraySize1_RBV | longin
NDPluginDriver DataType | asynInt32 | r/o | Data type of last NDArray callback data (NDDataType_t). | DATA_TYPE | $(P)$(R)DataType_RBV | mbbi
NDPluginDriver UniqueId | asynInt32 | r/o | Unique ID number of last NDArray callback data | UNIQUE_ID | $(P)$(R)UniqueId_RBV | longin
NDPluginDriver TimeStamp | asynFloat64 | r/o | Time stamp number of last NDArray callback data | TIME_STAMP | $(P)$(R)TimeStamp_RBV | ai
Debugging control
N/A | N/A | N/A | asyn record to control debugging (asynTrace) | N/A | $(P)$(R)AsynIO | asyn