V4 Design: driverInterfaces

From EPICSWIKI

EPICS V4: driverInterfaces - Communication beween record support and drivers

July 14 2005


Overview

This is the first attempt at defining how EPICS V4 record support will interface to driver support.

What follows is taken from asynDriver. Since this is being prepared for a talk to be given in about two hours, the names still use asyn and everything is C rather than C++. Thus many syntax changes are required but the basic ideas are what is proposed for EPICS V4.

For V4 the V3 concept of record support calling device suppport calling driver support will no longer exist. Instead drivers will implement one or more interfaces. Record support communicates with drivers via these interfaces.

The interfaces are divided into two basic classes:

  • message based - Communication is via ascii messages.
  • register based - Communication is via primitive data types or arrays of primitive types.

For V4 something similar to asynManager will be provided. It provides the following services:

  • access to drivers
  • registration of drivers and interfaces
  • locating drivers and interfaces.

This document will only give details of one interface. See the asynDriver documentation for descriptions of the other interfaces.


Standard Message Interfaces

These are interfaces for communicating with message based devices, where message based means that the device communicates via octet strings, i.e. arrays of 8 bit bytes. Three interfaces are provided: asynOctet, asynOctetBase, and asynOctetSyncIO. asynOctet is generic message based interface. asynOctetBase is an interface used by port drivers that implement asynOctet. It's primary putpose is to help with interrupt support. asynOctetSyncIO provides a synchronous inteface to asynOctet and can be used by code that is willing to block.

asynOctet describes the methods implemented by drivers that use octet strings for sending commands and receiving responses from a device. This interface is for records like stringin, stringout, and waveform.



Standard Register Interfaces

This section descibes interfaces for register based devices. Support is provided for:

  • Int32 - registers appear as 32 integers
  • UInt32Digital - registers appear a 32 bit unsigned integers and masks can be used to address specific bits.
  • Float64 - registers appear as double precision floats.
  • Int32Array - Arrays of 32 bit integers.
  • Float64Array - Arrays of double precision floats.

Lets use Int32 as an example. The interfaces for Int32 are intended for ADC or DAC register based devices. This the ai, ao, etc records would use this interface. Since communication is done via interfaces, other specialized records can also use this interface.

For Int32 the following are provided.

  • asynInt32 - An interface with methods: read, write, getBounds, registerInterruptUser, and cancelInterruptUser.
  • asynInt32Base - An interface used by drivers that implement asynInt32. It also has an implementation that:
    • registers the asynInt32 interface
    • has default methods for read, write, and getBounds. A null method in the interface passed to initialize is replaced by a method implemented by asynInt32Base.
    • implements registerInterruptUser and cancelInterruptUser. The caller should leave these methods null because asynInt32Base always replaces them by it's implementation.
    • Drivers that implement asynInt32 normally call asynInt32Base:initialize. It implements registerInterruptUser and cancelInterruptUser. If the driver provides interrupt support it must:
      • Call "initialize"
      • Call "pasynManager->registerInterruptSource"
      • Interact with asynManager to call the users that have registered with asynInt32Base:registerInterruptUser


asynInt32 describes the methods implemented by drivers that use integers for communicating with a device.

typedef void (*interruptCallbackInt32)(void *userPvt, asynUser *pasynUser,
                                      epicsInt32 data);
typedef struct asynInt32Interrupt {
    int addr;
    asynUser *pasynUser;
    interruptCallbackInt32 callback;
    void *userPvt;
} asynInt32Interrupt;
#define asynInt32Type "asynInt32"
typedef struct asynInt32 {
    asynStatus (*write)(void *drvPvt, asynUser *pasynUser, epicsInt32 value);
    asynStatus (*read)(void *drvPvt, asynUser *pasynUser, epicsInt32 *value);
    asynStatus (*getBounds)(void *drvPvt, asynUser *pasynUser,
                           epicsInt32 *low, epicsInt32 *high);
    asynStatus (*registerInterruptUser)(void *drvPvt,asynUser *pasynUser,
                           interruptCallbackInt32 callback, void *userPvt,
                           void **registrarPvt);
    asynStatus (*cancelInterruptUser)(void *registrarPvt, asynUser *pasynUser);
} asynInt32;

/* asynInt32Base does the following:
   calls  registerInterface for asynInt32.
   Implements registerInterruptUser and cancelInterruptUser
   Provides default implementations of all methods.
   registerInterruptUser and cancelInterruptUser can be called
   directly rather than via queueRequest.
*/

#define asynInt32BaseType "asynInt32Base"
typedef struct asynInt32Base {
    asynStatus (*initialize)(const char *portName,
                            asynInterface *pint32Interface);
} asynInt32Base;

epicsShareExtern asynInt32Base *pasynInt32Base;

asynInt32 has the following methods:

write
Write an integer value to the device.
read
Read an integer value from the device.
getBounds
Get the bounds. For example a 16 bit ADC might set low=-32768 and high = 32767.
registerInterruptUser
Registers a callback that will be called whenever new data is available. Since it can be called directly rather than via a queueRequest this method must not block.
cancelInterruptUser
Cancels the callback. Since it can be called directly rather than via a queueRequest this method must not block.