API Reference

All symbols of autoparamDriver are in the Autoparam namespace. A limited selection of symbols that are most needed when writing a driver based on Autoparam::Driver are put into the Autoparam::Convenience namespace which is meant to be imported with a using directive.

See also

The driver

class Driver : public asynPortDriver

An asynPortDriver that dynamically creates parameters referenced by records.

Normally, an asynPortDriver instantiates a predefined set of parameters, each associated with a string that can subsequently be used to reference a parameter from records in the EPICS database.

Autoparam::Driver works differently. No parameters exist when the Driver is constructed; instead, instances of DeviceVariable are created as EPICS database records are initialized. The string a record uses to refer to a parameter is split into a “function” and its “arguments” which, together, define a “parameter”. This is handled by the DeviceAddress and DeviceVariable classes, and needs to be implemented by the class subclassing Driver.

Drivers based on Autoparam::Driver do not need to override the read and write methods. Instead, they register read and write handlers for “functions” used by records. Autoparam::Driver will then call these handlers when records are processed.

To facilitate updating I/O Intr records, two mechanisms are provided:

To create a new driver based on Autoparam::Driver:

  1. Define a subclass of DeviceAddress.

  2. Define a subclass of DeviceVariable.

  3. Define a subclass of Driver.

  4. Define one or more iocshell commands to instatiate and configure the driver.

Apart from read and write functions, methods of asynPortDriver such as asynPortDriver::connect() can be overriden as needed. To facilitate that, Driver::deviceVariableFromUser() is provided to obtain DeviceVariable from the asynUser pointer that asynPortDriver methods are provided.

Public Functions

explicit Driver(const char *portName, DriverOpts const &params)

Constructs the Driver with the given options.

Parameters:
  • portName – The user-provided name of the port used to refer to this driver instance.

  • params – Options controlling the behavior of Driver.

Protected Functions

virtual DeviceAddress *parseDeviceAddress(std::string const &function, std::string const &arguments) = 0

Parse the given function and arguments.

DeviceAddress is meant to be subclassed. As records are initialized, Driver needs some information on the device variable referred to by function and arguments, thus it calls this method.

May return NULL on error.

virtual DeviceVariable *createDeviceVariable(DeviceVariable *baseVar) = 0

Convert the given DeviceVariable into an instance of a subclass.

DeviceVariable is meant to be subclassed. As records are initialized, Driver creates instances of the DeviceVariable base class, then passes them to this method to convert them to whichever subclass the implementation decides to return.

The baseVar pointer is intended to be passed to the constructor of DeviceVariable which will take ownership of it.

May return NULL on error.

template<typename T>
void registerHandlers(std::string const &function, typename Handlers<T>::ReadHandler reader, typename Handlers<T>::WriteHandler writer, InterruptRegistrar intrRegistrar)

Register handlers for the combination of function and type T.

Note that the driver is implicitly locked when when handlers are called.

Template Parameters:

T – A type corresponding to one of asyn interfaces/parameter types. See Autoparam::AsynType. It determines which EPICS device support provided by asyn (determined by record’s DTYP field) the function can be used with.

Parameters:
  • function

    The name of the “function” (in the sense of “device

    function”, see

    DeviceVariable).

  • reader – Handler function that is called when an input record referencing function with DTYP corresponding to T is processed;

  • writer – Handler function that is called when an output record referencing function with DTYP corresponding to T is processed;

  • intrRegistrar – A function that is called when a record referencing function switches to or from I/O Intr.

template<typename T>
asynStatus doCallbacksArray(DeviceVariable const &var, Array<T> &value, asynStatus status = asynSuccess, int alarmStatus = epicsAlarmNone, int alarmSeverity = epicsSevNone)

Propagate the array data to I/O Intr records bound to var.

Unless this function is called from a read or write handler, the driver needs to be locked. See asynPortDriver::lock().

Status and alarms of the records are set according to the same principles as on completion of a write handler. See Autoparam::ResultBase.

Note: strings are not arrays, even though Autoparam::Octet derives from Autoparam::Array. Use setParam() and callParamCallbacks() instead of doCallbacksArray().

template<typename T>
asynStatus setParam(DeviceVariable const &var, T value, asynStatus status = asynSuccess, int alarmStatus = epicsAlarmNone, int alarmSeverity = epicsSevNone)

Set the value of the parameter represented by var.

Unless this function is called from a read or write handler, the driver needs to be locked. See asynPortDriver::lock().

Status and alarms of the records are set according to the same principles as on completion of a write handler. See Autoparam::ResultBase.

Unlike doCallbacksArray(), no I/O Intr records are processed. Use asynPortDriver::callParamCallbacks() after setting the value. This allows more than one parameter to have its value set before doing record processing.

asynStatus setParam(DeviceVariable const &var, epicsUInt32 value, epicsUInt32 mask, asynStatus status = asynSuccess, int alarmStatus = epicsAlarmNone, int alarmSeverity = epicsSevNone)

Set the value of the parameter represented by var.

This is an overload for digital IO, where mask specifies which bits of value are of interest. While the default overload works with epicsUInt32, it uses the mask value 0xFFFFFFFF.

std::vector<DeviceVariable*> getAllVariables() const

Obtain a list of all device variables.

This function is threadsafe, locking the driver is not necessary.

std::vector<DeviceVariable*> getInterruptVariables()

Obtain a list of device variables bound by I/O Intr records.

The list of DeviceVariable pointers returned by this method is useful if you need to implement periodic polling for data and would like to know which data to poll. It is meant to be used together with doCallbacksArray(), setParam() and asynPortDriver::callParamCallbacks().

This function is threadsafe, locking the driver is not necessary.

DeviceVariable *deviceVariableFromUser(asynUser *pasynUser)

Obtain a DeviceVariable given an asynUser.

This facilitates overriding asynPortDriver methods if need be. Be aware, though, that the asynUser structure is used in asyn to represent any number of different things and the one you have may not correspond to any DeviceVariable. The argument to asynPortDriver::connect() is an example. Use of this method is subject to “know what you are doing” constraints.

class DriverOpts

Options controlling the behavior of Driver.

Certain behaviors of Driver and the underlying asynPortDriver can be controlled through DriverOpts. The value passed to the Driver’s constructor can be created and modified in place, like so:

Driver(portName,
       DriverOpts().setBlocking(true)
                   .setAutoInterrupts(false)
                   .setPriority(epicsThreadPriorityLow));

Public Types

typedef void (*InitHook)(Driver*)

A function that can be set to run after IOC init.

Public Functions

inline DriverOpts &setBlocking(bool enable = true)

Declare whether read and write handlers can block.

If any read or write handler can block in any situation, the driver needs to declare this. What “blocking” means is explained in EPICS Application Developer’s Guide in chapter Device Support.

In short, if read and write handlers return “immediately”, the driver does not need to declare itself as blocking. On the other hand, if handlers are “slow” (e.g. because the device is network-connected), the driver must declare itself as blocking. This causes the EPICS device support layer to implement asynchronous processing, calling read and write handlers from a separate thread.

Default: non-blocking

inline DriverOpts &setAutoConnect(bool enable = true)

Enable/disable asyn autoconnect functionality.

Please refer to asyn documentation for more information. In short, if you do not override asynPortDriver::connect() or asynPortDriver::disconnect(), enabling autoconnect simply means that the asyn port will always appear connected, which may be all you need.

Important: if overriding asynPortDriver::connect(), you need to know what you are doing. Be aware that autoconnect tries to connect before your driver is completely initialized. This means that your code will not be called when autoconnect is enabled. If you need to override asynPortDriver::connect(), you may be better off disabling the autoconnect option here and instead use the asynManager and asynCommonSyncIO interfaces to connect (and/or enable autoconnect) from your driver’s constructor, which is executed later when virtual functions have already been set up. See also setInitHook() for a way to connect to the device even later, after all the records are initialized.

Default: enabled

inline DriverOpts &setAutoDestruct(bool enable = true)

Instruct the driver to clean up on IOC exit.

If enabled, the Driver will register a hook that is run at IOC exit and deletes the Driver, which ensures that the destructor is run. This is convenient because the Driver can be allocated using new from an iocshell command, then let be.

Note: the exit hook will disable the asyn port before destroying the driver. The reason is that records can still be processed after the driver is destroyed. Disabling the port prevents the driver being called, though asyn may print warnings.

Default: disabled

inline DriverOpts &setAutoInterrupts(bool enable)

Enable/disable default I/O Intr behavior for write handlers.

When enabled, successful writes will process I/O Intr records bound to the parameter written to, unless overriden by ResultBase::processInterrupts.

Note that default write handlers (passed as NULL to Driver::registerHandlers()) are not affected by this: the write handler will always process interrupts.

Default: enabled

inline DriverOpts &setPriority(int prio)

Set the thread priority of read/write handlers in blocking mode.

If setBlocking() was enabled, read and write handlers run in a separate thread. This setting controls the priority of this thread.

Default: epicsThreadPriorityMedium

inline DriverOpts &setStacksize(int size)

Set the thread stack size of read/write handlers in blocking mode.

If setBlocking() was enabled, read and write handlers run in a separate thread. This setting controls the priority of this thread.

Default: epicsThreadStackMedium

inline DriverOpts &setInitHook(InitHook hook = NULL)

Set a function to run after IOC initialization is done.

If the driver needs to do something (like open communication to device) after all the records (and consequently, DeviceVariable) are constructed, registering a hook function here is the way to go.

The hook is run after the IOC is built, but before any record processing occurs. Specifically, it is hooked to initHookState::initHookAfterScanInit

Default: NULL

Device variables and addresses

class DeviceAddress

Represents parsed device address information.

The driver needs to subclass this and return it from the overridden Autoparam::Driver::parseDeviceAddress(). This class is intended for storing parsed function arguments, e.g. numeric addresses and offsets. It is used by the Driver base class to identify which records refer to the same device variable.

Unlike DeviceVariable, this class should not take any device resources, or, if unavoidable (e.g. because it needs to access the device for name resolution), must release resources when destroyed; because several records can refer to the same underlying variable, many instances of DeviceAddress can be created per DeviceVariable, then destroyed even before the IOC is fully initialized.

A DeviceAddress must be equality-comparable to other addresses. Two addresses shall compare equal when they refer to the same device variable.

Public Functions

virtual bool operator==(DeviceAddress const &other) const = 0

Compare to another address. Must be overridden.

class DeviceVariable

Represents a device variable and is a handle for asyn parameters.

This class is used as a handle referring to a device device variable, e.g. in read and write handlers or Driver::setParam().

DeviceVariable is meant to be subclassed for use by the subclassed driver. This greatly increases its utility as it can hold any information related to a device variable that the subclassed driver might require. Instances are created by Driver::createDeviceVariable().

DeviceVariable instances are created only once per device variable, and are shared between records referring to the same device variable. They are destroyed when the driver is destroyed.

Public Functions

explicit DeviceVariable(DeviceVariable *other)

Construct DeviceVariable from another; the other one is invalidated.

Being the only public constructor, this is the only way the driver subclassing Autoparam::Driver can construct a DeviceVariable. The usage pattern is the following:

virtual ~DeviceVariable()
inline std::string const &function() const

Returns the “function” given in the record.

inline std::string const &asString() const

Returns the “function+arguments” string representation.

The resulting string is used for display only, e.g. in error messages.

inline int asynIndex() const

Returns the index of the underlying asyn parameter.

This allows advanced users to call methods of asynPortDriver if the need arises.

inline asynParamType asynType() const

Returns the type of the underlying asyn parameter.

Apart from complementing asynIndex(), it allows the driver (or the constructor of the DeviceVariable subclass) to act differently based on the type. While the subclassed driver can also determine this information from function() (it knows which type each function handler is registered for), using asynType() is faster and more convenient.

inline DeviceAddress const &address() const

Returns the pre-parsed representation of the device address.

This is the same instance of DeviceAddress that has been previously created by Driver::parseDeviceAddress().

References to array and string data

template<typename T>
class Array

A non-owning reference to a data buffer.

Array is used to pass around a reference to a contiguous buffer of type T. For example, read and write handlers called by Driver receive an Array as an argument, pointing to the data of a waveform record.

An Array contains a data pointer, the current size of the buffer and the maximum size of the buffer. It also provides convenience function to copy data to and from other buffers.

Public Functions

inline Array(T *value, size_t maxSize)

Construct an Array reference to value, setting its size to maxSize.

inline T *data() const
inline size_t size() const
inline size_t maxSize() const
inline void setSize(size_t size)
inline void fillFrom(T const *data, size_t size)

Set the size and copy data from the provided buffer.

inline void fillFrom(std::vector<T> const &vector)

Set the size and copy data from the provided vector.

inline size_t writeTo(T *data, size_t maxSize) const

Copy data to the provided buffer, up to maxSize.

Protected Attributes

T *m_data
size_t m_size
size_t m_maxSize
class Octet : public Autoparam::Array<char>

A specialization of Array to deal with string data.

This class is called Octet instead of String to match the asyn nomenclature. It is an Array of char and provides convenience function to ensure null-termination required by C strings.

Note: Octets sometimes behave like arrays (i.e. in read and write handlers) and sometimes like scalars (i.e. when handling interrupts; see Autoparam::Driver::doCallbacksArray() and Autoparam::Driver::setParam()).

Public Functions

inline Octet(char *value, size_t maxSize)

Construct an Octet reference to value, setting it’s size to maxSize.

inline void terminate()

Terminate the string at its current size.

inline void fillFrom(char const *data, size_t size)

Set the size, copy data from the provided buffer and null-terminate.

inline void fillFrom(std::string const &string)

Set the size, copy data from the provided string and null-terminate.

inline size_t writeTo(char *data, size_t maxSize) const

Copy data to the provided buffer, up to maxSize, with null-termination.

Returning results from handlers

struct ProcessInterrupts

A tri-state determining whether I/O Intr records should be processed.

Used in ResultBase to determine whether interrupts should be processed. When left alone, it specifies the default behavior. When a bool is assigned to it, it overrides the default.

struct ResultBase

The result returned from a read or write handler.

ResultBase tells the Driver calling a read or write handler whether the call was successful and how to proceed. Based on this, the Driver will set the appropriate alarm status on the EPICS record that caused the call.

The default-constructed result represents a successful handling; thus, in the happy case, the handler need not change anything. If something went wrong, the handler as a fair bit of freedom in deciding what will happen to the record that caused processing.

Subclassed by Autoparam::ArrayResult, Autoparam::Result< T >, Autoparam::Result< Octet >, Autoparam::WriteResult

Public Members

asynStatus status

The overall status of read/write handling.

If status is set to asynSuccess (the default) upon returning from a handler, interrupts may be processed (see ResultBase::processInterrupts).

If status is set to anything else except asynSuccess, interrupts will not be processed.

For read handlers, the value read will be passed to the record regardless of status.

Unless ResultBase::alarmStatus and ResultBase::alarmSeverity are also set, the record’s alarm and severity are determined according to the value of status and the type of record. For example, on asynError, an input record will be put into READ_ALARM and an output record will be put into WRITE_ALARM.

epicsAlarmCondition alarmStatus

Overrides the record’s alarm status.

epicsAlarmSeverity alarmSeverity

Overrides the record’s severity status.

ProcessInterrupts processInterrupts

Determines whether interrupts should be processed on success.

When a read or write handler finishes with asynSuccess, it may be appropriate to process I/O Intr records that are bound to the same parameter. The decision can be done globally via Autoparam::DriverOpts::setAutoInterrupts, but can always be overriden by a handler by setting ResultBase::processInterrupts.

The default setting follows the default behavior of asynPortDriver:

  • do not process interrupts upon returning from a read handler;

  • process interrupts upon returning from a write handle, propagating the value just written.

To override the defaults, simply set processInterrupts to true or false.

struct WriteResult : public Autoparam::ResultBase

Result returned from a write handler, status only.

struct ArrayResult : public Autoparam::ResultBase

Result returned from an array read handler, status only.

template<typename T>
struct Result : public Autoparam::ResultBase

Result returned from a scalar read handler, status and value.

Public Members

T value

The value returned by the read handler.

template<>
struct Result<Octet> : public Autoparam::ResultBase

Result returned from Octet read handler, status only.

Octets behave like arrays in this respect.

Signatures of handler functions

typedef asynStatus (*Autoparam::InterruptRegistrar)(DeviceVariable &var, bool cancel)

Called when a device variable switches to or from I/O Intr scanning.

The registrar function is called both when a variable switches to I/O Intr and when it switches away; the cancel argument reflects that, being false in the former case and true in the latter. The purpose of the registrar function is to set up or tear down a subscription for events (or interrupts) relevant to the given var.

To be more precise: a device variable can be referred to by several EPICS records, any number of which can be set to I/O Intr scanning. This function is called with cancel = false when the number of I/O Intr records increases to 1, and with cancel = true when the number decreases to 0.

template<typename T, bool array = IsArray<T>::value>
struct Handlers

Handler signatures for type T.

Specializations of this struct describe the signatures of the read handler, write handler, and interrupt registrar for the given type T. Functions with these signatures are passed as arguments to Driver::registerHandlers().

This struct is defined separately for scalars, arrays, strings (Octets) and digital IO. See the specializations for concrete signatures.

template<typename T>
struct Handlers<T, false>

Signatures of handlers for scalar types T.

Public Types

typedef Result<T> ReadResult

Result type for scalar reads.

typedef WriteResult (*WriteHandler)(DeviceVariable &var, T value)

Writes value to the device.

typedef ReadResult (*ReadHandler)(DeviceVariable &var)

Reads a value from the device, returning it inside ReadResult.

template<typename T>
struct Handlers<Array<T>, true>

Signatures of handlers for array types Array<T>.

Public Types

typedef ArrayResult ReadResult

Result type for array reads.

typedef WriteResult (*WriteHandler)(DeviceVariable &var, Array<T> const &value)

Writes value to the device.

typedef ReadResult (*ReadHandler)(DeviceVariable &var, Array<T> &value)

Reads an array from the device, storing data in value.

Unlike a scalar read handler, the value is not returned as a ReadResult, but written directly to the given buffer, up to the amount returned by value.maxSize().

template<>
struct Handlers<epicsUInt32, false>

Signatures of handlers for epicsUInt32.

epicsUInt32 (a.k.a. asynParamUInt32Digital) is used for digital (i.e. bit-level) IO. As such, its handlers are passed an additional parameter mask. This mask tells the handler which bits the caller is interested in. It’s up to the handler to properly mask the value.

Note: You shouldn’t use epicsUInt32 support for “normal” integer IO, even for unsigned integers. It is meant only for digital IO, which is why the names of the asyn interface and device support explicitly say “Digital”. Use epicsInt32 for normal unsigned integers. If you need to handle unsigned integers which are larger than 31 bits, use epicsInt64.

Public Types

typedef Result<epicsUInt32> ReadResult

Result type for scalar reads.

typedef WriteResult (*WriteHandler)(DeviceVariable &var, epicsUInt32 value, epicsUInt32 mask)

Writes value to the device, honoring the given mask.

typedef ReadResult (*ReadHandler)(DeviceVariable &var, epicsUInt32 mask)

Reads a value from the device, honoring mask, returning it inside ReadResult.

template<>
struct Handlers<Octet, false>

Signatures of handlers for Octet.

For the purpose of read and write handlers, Octet behaves as an array.

Public Types

typedef Result<Octet> ReadResult

Result type for Octet reads (essentially ArrayResult).

typedef WriteResult (*WriteHandler)(DeviceVariable &var, Octet const &value)

Writes value to the device.

typedef ReadResult (*ReadHandler)(DeviceVariable &var, Octet &value)

Reads a string from the device, storing data in value.

Miscellania

char const *Autoparam::getAsynTypeName(asynParamType type)

Return string representation of the given asyn parameter type.

template<typename T>
struct AsynType

Maps type T to the corresponding asynParamType value.

This mapping allows using EPICS types everywhere as template arguments and types of function arguments. It is defined as follows:

  • epicsInt32asynParamInt32

  • epicsInt64asynParamInt64

  • epicsFloat64asynParamFloat64

  • epicsUint32asynParamUint32Digital

  • OctetasynParamOctet

  • Array<epicsInt8>asynParamInt8Array

  • Array<epicsInt16>asynParamInt16Array

  • Array<epicsInt32>asynParamInt32Array

  • Array<epicsInt64>asynParamInt64Array

  • Array<epicsFloat32>asynParamFloat32Array

  • Array<epicsFloat64>asynParamFloat64Array

Public Static Attributes

static const asynParamType value
namespace Convenience

Symbols that are often needed when implementing drivers.

This namespace is meant to be used as

using namespace Autoparam::Convenience;
This makes the symbols declared herein easily accessible. Apart from the typdefs shown below, this namespace exposes also:

Typedefs

typedef Autoparam::WriteResult WriteResult
typedef Autoparam::ArrayResult ArrayReadResult
typedef Result<epicsInt32> Int32ReadResult
typedef Result<epicsInt64> Int64ReadResult
typedef Result<epicsUInt32> UInt32ReadResult
typedef Result<epicsFloat64> Float64ReadResult
typedef Result<Octet> OctetReadResult