Gpib device and driver support

# EPICS: GPIB Support

# Release 1.2

# Benjamin Franksen, John Winans, Marty Kraimer, Eric Norum

# August 2003

# Contents

Introduction
Acknowledgments
Install and Build
Getting Started
GPIB Database Links
Using in Applications
Creating GPIB device support
devGpibCommon
drvGpib
Low Level Drivers
Changes to previous EPICS GPIB support
General GPIB Problems
License Agreement

# License Agreement

This product is available via the open source license described at the end of this document

# Introduction

This manual describes GPIB support for EPICS. It provides the following features

- GPIB I/O can be performed via database records
- GPIB device support for specific gpib devices can be written.
- Provides an interface between device specific code and the gpib drivers.
- Provides a hardware independent interface to GPIB low level drivers.
- Provides three low level GPIB drivers.
- Additional Low Level drivers can be added.

The support consists of the following components:

devGpibCommon
  Interface between device specific code and drvGpib. Features are provided that make it easy to implement support for new devices. Support is provided for connecting to many of the standard EPICS record types.
drvCommonGpib
  Hardware independent interface to low level gpib controllers. For each controller it provides a thread that handles all communication with it.
drvVxi11
  This supports the Agilent E5810 and Agilent E2050 Ethernet based GPIB controllers. It has also been tested connecting directly to the ethernet port of a TSD3014B scope.

  It is designed to support any device that uses the VXIBus VXI-11 standard.. This is supported on vxWorks, RTEMS, Solaris, Linux, Darwin and HPUX.

drvNi1014
  This supports the National Instruments NI1014 ,VME based GPIB controller. This is supported only on vxWorks.
drvTermiosTty
  This supports serial ports that can be accessed the vxWorks 'ty' interface, the POSIX termios interface or Ethernet/RS-232 converters.

drvCommonGpib is written so that support for additional GPIB controllers can be provided. Support is available for Industry Pack and for GPIB via bitbus in other unbundled EPICS products.

# Acknowledgments

John Winans
  John provided the original EPICS GPIB support. His work is still the basis of the current support. Databases using John's support can be used without modification with the latest support. With small modifications, device support modules written for John's support can be used with the latest support.
Benjamin Franksen
  John's support only worked on vxWorks. In addition the driver support was implement as a single source file, i.e. what is now drvGpib, drvNI1014, and drvBitBusGpib was all mixed together. Benjamin defined an interface between drvCommon and low level controllers and split the code into drvGpib and the low level drivers. He also created the support for drvVxi11.
Eric Norum
  Eric started with Benjamin's code and converted it to use the Operating System Independent features of EPICS 3.14. This is the basis of the existing version.
Marty Kraimer
  Marty started with Eric's version and made changes to support secondary addressing and to replace ioctl with code to support general bus management, universial commands, and addressed commands.
Others? Benjamin should know

# Install and Build

After obtaining a copy of the distribution, it must be installed and built for use at your site.

1. Create an installation directory for the module, usually this will end with

    .../support/gpibCore/

2. Place the distribution file in this directory. Then issue the commands (Unix style)

    gunzip <file>.tar.gz
    tar xvf <file>.tar

3. This creates a <top> application with EPICS base 3.14 style rules.

    .../support/gpibCore/gpibCoreX-Y

where X-Y is the release. For example.

    .../support/gpibCore/gpibCore2-0beta1

4. Edit the `configure/RELEASE` file and set the paths to EPICS base.
5. Run `make` in the top level directory and check for any compilation errors.

# Getting Started

gpibCore includes a test application. Two ioc boot directories are provided: iochost and iocvxWorks. Each contains a st.cmd file. Both configure drvVxi11, and on vxWorks also configures drvNi1014. Before booting you must edit the st.cmd files.

- drvVxi11Config - change the INET address to the address of your hpLan.
- E2050Reboot and E5810Reboot - change the INET address.
- drvNi1014GpibConfig (iocvxWorks only). Check all arguments. See drvNi1014GpibConfig below for details.
- dbLoadRecords - Change A=3 to the gpib address of a device that is 488.2 complient, i.e. implements *IDN? and follows the 488.2 event model.

After editing the above file boot your IOC. Once your IOC is running just type:

        GI

GI is an interactive tool that allows you to send commands and receive replies from gpib devices. It should be self explanatory.

Directory <top>/testApp/adl contains two files: startmedmHpLan and startmedmNi1014. Choose the one for the gpib driver you are testing.

gpibCore includes a test application: a test device support module, a test database, and an medm adl file.

The device support modules provides support for the following GPIB commands.

- *IDN? - If a device supports the 488.2 standard it will return an identification string. Older gpib devices do not suport the command.
- IFC and REN - GPIB bus management lines.
- DCL and LLO - Universial GPIB commands, apply to all devices on the link.
- SDC and GTL - Addressed GPIB commands.
- RESETLINK - Restart the link thread.
- SRQHANDLER - Unsolicited SRQ handlet.

# GPIB Database Links

An EPICS record is connected to gpib by the fields DTYP and INP or OUT.

The DTYP field has the format:

        field(DTYP,"<device support name>")

where

<device support name> - The name from a device database definition, i.e. a definition of the form:

        device(<record type>,GPIB_IO,<dsetName>,"<device support name>")

You or someone else must provide the device support for specific gpib devices.

The INP or OUT field has the format:

        field(INP,"#L<link> A<addr> @<number>")
        or
        field(INP,"#L<link> A<addr> @<number>")

where:

<link>
  Must match the link number of the low level GPIB driver that connects to your GPIB device.
<addr>
  GPIB address of your device. May be a primary address or an extended address. A primary address has a value <31. An extended addresss is of the form: PSS,where P represents the primary address and SS is the secondary address. It is NOT possible to express an extended address if the primary adddress is 0. Some examples are :

      A9    primary address 9
      A900  extended address: primary address is 9, secondary address is 0
      A906  extended address: primary address is 9, secondary address is 6.

<number>
  An integer that identifies a gpibCmd definition in a gpib device support module.
gpibCore does not provide support for specific gpib devices but only for implementing such support. Within the EPICS community, support exists for many gpib devices. The EPICS supported hardware list shows some of the support. If your device does not appear there and a message to tech-talk does not provide any help then you will have to write your own device support.
When support is provided, it is still necessary to relate <number> to the correct gpibCmd in the device support module. If the implementer is nice documentation like the following is provided:

       recordType  @<number>   Description

If such documentation is not available, look at the device support itself for statements like:

      /* Param 12 */
      {&DSET_LI, GPIBREAD, IB_Q_LOW, "*ESR?",  "%ld", 0, 20, 0, 0, 0, 0, 0, -1},

The above states that @12 is a gpib read command via a longin record. Thus the record definition would be:

        record(longin,"<name>") {
            field(DTYP,"<device support name>")
            ...
            field(OUT,"#L<link> A<addr> @12")
            ...
        }

# Using in Applications

## <top>/xxxApp/configure/RELEASE

Before the definition of EPICS_BASE add the statement:

    GPIB=<full path name to gpibCore>

## <top>/xxxApp/src/Makefile

Add the statements:

    <prod>_LIBS += gpib

## <top>/xxxApp/src/<product>Include.dbd

Add one or more of the statements as appopriate for your application:

    include "gpib.dbd"
    include "drvVxi11.dbd"
    include "drvTermiosTty.dbd"
    include "drvNi1014.dbd"

NOTES:

- drvNi1014 is supported ONLY on vxWorks.

In addition you must provide definitions for any device support you need. Look at testApp/src/ for an example of how to build and use gpib device support.

## <top>/iocBoot/iocxxx/st.cmd

Must contain commands to configure gpib low level drivers. gpibCore supports three low level drivers: drvVxi11,drvTermiosTty, and drvNi1014.

The configuration commands for drvVxi11 are:

    drvVxi11Config(int link, char *inetAddr, int recoverWithIFC, int defTimeout, char *vxiName,int isSingleLink)
    E2050Reboot(char *inetAddr)
    E5810Reboot(char *inetAddr,char *password)

where:

link
  Link number. Matches the #L<link> in INP or OUT fields..
inetAddr
  Host name or internet address.
recoverWithIFC
  If an operation fails should an IFC be issued? (0,1)=>(no,yes)
defTimeout
  default timeout in milliseconds for RPC time out. If 0 a default is used.
vxiName
  This is (hpib,gpib0) for (E2050,E5810)
isSingleLink
  THIS MAY CHANGE. If you are interfacing to a LAN GPIB server makes this 0. Currently only one ethernet vxi11 instrumant has been tested, a TDS3014B. For this device set isSingleLink to 1. For it the gpib address is ignored and all commands are sent to the single Device-Link for the device itself. This may change as we get more experience with ethernet vxi11 instruments.

The configuration command for drvNi1014 is:

    drvNi1014GpibConfig(int link,int nPorts, int base, int vector, int level)

where:

link
  Link number. Matches the #L<link> in INP or OUT fields.
nPorts
  Number of ports on the interface. This must be 1 or 2 and MUST match the NI1014.
base
  Offset from the A24 VME base address.
vector
  VME interrupt vector
level
  VME interrupt level

The configuration command for drvTermiosTtyGpib is:

    drvTermiosTtyGpibConfigure(int link,char *serialLineName,int openOnReset)

where:

link
  Link number. Matches the #L<link> in INP or OUT fields.
serialLineName
  The name of the serial port, e.g. /dev/ttyS0 for local serial lines or hostname:port for Ethernet/RS-232 adapter serial lines. The hostname may be an IP number in dotted-decimal form or a DNS host name.
openOnReset
  If non-zero, reopen the communications link after a timeout or I/O error only when an explicit link reset operation is performed. If zero the link will be reopened as soon as another I/O operation is attempted. Link reconnection attempts occur only 2 seconds or more after a timeout or other I/O error.

Serial line parameters can be set with the IOC shell stty command. The stty command accepts the following arguments:

––file=name or –F name
  Specify name of serial port whose parameters are to be set. This argument must be present.
cs5, cs6, cs7, cs8
  Set number of bits per character. Default is 8 bits.
parenb, -parenb
  Enable/disable parity generation and checking. Default is no parity.
parodd, -parodd
  Set odd/even parity. Default is even parity.
cstopb, -cstopb
  Set number (2 or 1) of stop bits. Default is 1 stop bit.
clocal, -clocal
  Monitor/ignore state of serial port DTR line. Default is to ignore DTR.
crtscts, -crtscts
  Enable/disable RTS/CTS hardware handshaking. Default is to disable hardware handshaking. Hardware handshaking is not supported on all systems.
####
  Serial line speed (bits/second). Default is 9600.

Serial line parameters should be set before the call to drvTermiosTtyGpibConfigure.

## Shell commands

Commands that can be issued via the IOC shell.

    drvGpibLogData(int onOff,int link,int addr)

onOff - (0,1) means turn logging (off,on)
link - link
addr - gpib addr. Addresses>=100 signifies extended addrsssing. For example 901 means primary address 9, secondary address 1.

    drvGpibPoll(int link,int addr,int onOff)

link - link
addr - gpib addr. Addresses>=100 signifies extended addrsssing. For example 901 means primary address 9, secondary address 1.
onOff - (0,1) means turn Polling (off,on)

    drvGpibResetLink(int link)

link - link to reset

    setibDebug(int value)

value - The higher the value the more debugging information is displayed

    setibSeqDebug(int value)

value - The higher the value the more debugging information is displayed

    setibSrqLock(int value)

value - (0,1) means (don't, do) allow srq processing.

    setibTimeoutSquelch(int value)

value - (0,1) means (don't, do) report srq processing errors.

    setibSrqTimeout(int value)

value - Number of seconds to wait for sollicited SRQs.

    setibSrqRingSize(int value)

value - Number of SRQ events in ring buffer. MUST be set before iocInit.

    setibSrqPollTimeout(int value)

value - Timeout in milliseconds for srqPoll of a particular device.

    setibSrqPollRate(double value)

value - How often (in seconds) to issue an srqStatus. Some low level devices do not support SRQ interrupts. drvCommonGpib periodically asks if an SRQ is present. The command is used to set the rate.

# Creating GPIB device support

This section describes how to write device support for GPIB devices. It is assumed that the reader is already familiar with the dialogue required to operate a GPIB instrument and EPICS record and device support. gpibCore provides a facility devCommon for creating support for specific gpib devices.

## Purpose

A GPIB device support module provides access to the operating parameters of a GPIB device.

## Overview

GPIB devices typically have many parameters, each of which may be thought of in terms of the standard types of database records available in EPICS. It is the job of the device support module designer to decide how the mapping of these parameters will be made to the available record types. Once this mapping is complete, the device support module may be written.

The writing of the device support module consists primarily of the construction of a parameter table. This table is used to associate the database record types with the operating parameters of the GPIB instrument.

Other aspects of module design include the handling of SRQ events and errors. SRQ processing is described in a separate section below.

## Using a GPIB Device Support Module

To make use of a GPIB device support module, the appropriate device definitions must be defined:

    device(<record type>,<link type>,<DSET name>,"<DTYP name>")

where:

<record type>
  The record type, e.g. ai,ao,...
<link type>
  Link type. Must be GPIB_IO.
<DSET name>
  Device Support Entry Table name. This is the external name defined in the device support code.
<DTYP name>
  Device Type name. This is what appears in the DTYP field of record instances.

For example the definitions for the test supplied with gpibCore are:

    device(ai,GPIB_IO,devAiTestGpib,"GPIB Test")
    device(ao,GPIB_IO,devAoTestGpib,"GPIB Test")
    device(bi,GPIB_IO,devBiTestGpib,"GPIB Test")
    device(bo,GPIB_IO,devBoTestGpib,"GPIB Test")
    device(longin,GPIB_IO,devLiTestGpib,"GPIB Test")
    device(longout,GPIB_IO,devLoTestGpib,"GPIB Test")
    device(mbbi,GPIB_IO,devMbbiTestGpib,"GPIB Test")
    device(mbbo,GPIB_IO,devMbboTestGpib,"GPIB Test")
    device(stringin,GPIB_IO,devSiTestGpib,"GPIB Test")
    device(stringout,GPIB_IO,devSoTestGpib,"GPIB Test")

For more information about device support, and also how to define INP or OUT links of records, see the the EPICS Application Developers Guide.

## The GPIB Device Support Module

The common GPIB support code includes a file >top>/gpib/devCommon/devSkeletonGpib.c. If you are writing a new GPIB device support module just:

- Copy it to your source directory
- Change it's name.
- Globally change "Skeleton" to a name of your choice.
- Modify it to provide the functionality needed by your device.

A GPIB device support module consists of DSET entries, an array of gpibCmds, efast tables (optional), name tables (optional), a devGpibParmBlock, a debugging flag, and init_ai routine, an SRQ handler function (optional), and some custom conversion functions (optional.).

A simplified version of the skeleton file is:

    /* devSkeletonGpib.c */
    #include <devCommonGpib.h>
    /* define all desired DSETs */
    #define DSET_AI    devAiSkeletonGpib
    #define DSET_BI    devBiSkeletonGpib
    #define DSET_MBBI   devMbbiSkeletonGpib
    #include <devGpib.h>    /* must be included after DSET defines */
    int SkeletonDebug = 0;
    #define TIME_WINDOW 2000    /* wait 2 seconds after device timeout */
    #define IO_TIME     1000    /* wait 1 second for IO */
    /* example choices for BI */
    static  char    *offOnList[] = { "Off", "On" };
    static  struct  devGpibNames   offOn = { 2, offOnList, NULL, 1 };
    /* example EFAST table */
    static char *(userOffOn[]) = {"USER OFF;", "USER ON;", NULL};
    /* Array of structures that define all GPIB messages */
    static struct gpibCmd gpibCmds[] =
    {
      /* Param 0 */
      {&DSET_BO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 32,
        NULL, 0, 0, userOffOn, &offOn, -1},
      /* definitions for other parameters follow*/
    };
    /* The following is the number of elements in the command array above.  */
    #define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd)
    /* User MUST define init_ai */
    static long init_ai(int parm)
    {
      if(parm==0)  {
        devSupParms.debugFlag = &SkeletonDebug;
        devSupParms.respond2Writes = -1;
        devSupParms.timeWindow = TIME_WINDOW;
        devSupParms.hwpvtHead = 0;
        devSupParms.gpibCmds = gpibCmds;
        devSupParms.numparams = NUMPARAMS;
        devSupParms.magicSrq = -1;
        devSupParms.name = "devXxSkeletonGpib";
        devSupParms.dmaTimeout = IO_TIME;
        devSupParms.srqHandler = devGpibLib_srqHandler;
        devSupParms.wrConversion = 0;
      }
      return(devGpibLib_initDevSup(parm, &DSET_AI));
    }

The meaning of each portion of the code should become clear as you read the following sections:

## Defining DSET Table Entries

The following statements create the Device Support Entry Tables

    #define DSET_AI    devAiSkeletonGpib
    #define DSET_BI    devBiSkeletonGpib
    #define DSET_MBBI   devMbbiSkeletonGpib
    ...
    #include <devGpib.h>    /* must be included after DSET defines */

The actual DSETs are created by devGpib.h based on which DSET_xx definitions are defined. Thus you must have a #define for each record type your support uses. Also you MUST have a definition for DSET_AI because you must also supply an init_ai routine as described below.

## gpibCmd definitions.

This is where the translation to and from the language of the GPIB device is defined. The actual table contains one element for each parameter that is made available to the user via the @<number> portion of an INP or OUT field.

The definition of gpibCmd is:

    typedef struct gpibCmd
    {
        gDset *rec_typ; /* address of DSET for specified record type */
        int type;       /* enum - GPIBREAD...GPIBEFASTIW */
        short pri;      /* request priority--IB_Q_HIGH or IB_Q_LOW */
        char *cmd;      /* CONSTANT STRING to send to instrument */
        char *format;   /* string used to generate or interpret msg */
        long rspLen;    /* room for response error message */
        long msgLen;    /* room for return data message length */
        int (*convert) ();  /* custom routine for conversions */
        int P1;             /* user defined parameter used in convert() */
        int P2;             /* user defined parameter used in convert() */
        /* P3 plays dual role. For EFAST address of EFAST table   */
        /*                     For convert it is passed to convert*/
        char **P3;
        struct devGpibNames *namelist; /* pointer to name strings */
        int companion; /* companion command (used at init time) */
    }gpibCmd;

In the example above the definitions for the gpibCmds are:

    static struct gpibCmd gpibCmds[] =
    {
      /* Param 0 */
      {&DSET_BO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 32,
        NULL, 0, 0, userOffOn, &offOn, -1},
      /* definitions for other parameters follow*/
    };

This example defines a single command. A database record using this definition must define field OUT as

    field(OUT,,"#L<link> A<addr> @0")

The format of the parameter table is as follows:

    static struct gpibCmd gpibCmds[] =
    {
        /* Parameter 0 */
        {f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13},

        /* parameter 1 */
        ...
    };

where

f1
  Address of the Device Support Entry Table (DSET) that describes the record type supported by the table entry..

f2
  Type of GPIB I/O operation that is to be performed. The f2 field must be set to one of the enumerated values declared in devCommonGpib.h, i.e. GPIBREAD,...,GPIBEOS. See next section for the definitions.

f3
  Processing priority of the I/O operation. Must be `IB_Q_HIGH` or `IB_Q_LOW`.

f4
  Constant string that is used differently depending on the value of f2. See the discussion of f2 below. Set this field to NULL if not used.

f5
  Constant string that is used differently depending on the value of f2. See the discussion of f2. Set this field to NULL if not used.

f6
  Length of the buffer pointed to by `dpvt.rsp`. Holds the message read back from a device when performing a responds-to-writes read operation. Set this field to zero when not used. See the section "Machines That Respond to Everything" for more information.

f7
  Length of the buffer that is pointed to by dpvt.msg. The buffer is used for `GPIBWRITE`, `GPIBREAD`, or `GPIBREADW`. Set this field to zero when not used.

f8
  Function that is called to perform the I/O operation when f2 is set to `GPIBSOFT`, or to perform a conversion/parsing operation when f2 is set to any of the other operation types. This function is intended to be used to generate and parse strings being sent to and from an instrument, but can be used for anything. This function must make sure that it does not overflow the dpvt.msg field.. This function is passed f9, f10, and f11 as parameters.

  For output operations the function is called to generate the string (possibly using the records VAL field) that is to be sent to the instrument. For input type operations, it is called to scan the response string from the instrument (and fill in the records VAL field.) It is highly recommended that if a custom conversion routine be used, that the designer of the function be familiar with the record-specific library function that calls it.

  The function should be declared as returning an int. This return value is passed back to the caller of the device support module after a processing request when f2 is set to `GPIBSOFT` and is ignored in other cases.

  Set to NULL when no conversion function is present.

f9
  Integer passed to any conversion function specified in f8. It may be used for any purpose the designer wishes.

f10
  Integer passed to any conversion function specified in f8. It may be used for any purpose the designer wishes.

f11
  This field plays a double role. When the parameter table entry has a custom conversion routine, it is passed to the conversion routine specified in f8. When f2 is one of the EFAST operations, this field points to the EFAST table. See the EFAST operation descriptions under the f2 field definitions and the section "Efast Tables" for more on the use of this field.

  Set this field to NULL when it is not used.

f12
  Pointer to a Name Table. Name tables are described in the section "Name Tables".

  Set this to NULL when no Name Table is used.

f13
  Currently only used if GPIBEOS is specified for any operation. If GPIBEOS is specified then f13 is the value (interpeted as an unsigned 8 bit value) is the end of message character.

### Definitions for f2 - GPIB I/O Operation

This section describes the operation types.

GPIBREAD
  - Send the command string specified in f4 to the instrument exactly as specified.
  - Data is read from the instrument and placed into the dpvt.msg field. f7 must specify a size large enough for the message.
  - If f8 is NULL, the data from the read operation is scanned via sscanf() with the following code

                 sscanf(dpvt.msg, f5, &(precord->val));

    Otherwise, a call is made to the function pointed to by f8 as follows:

                 (*(f8))(&dpvt, f9, f10, f11);

  This reads and parses data from the instrument . If f8 is NULL, the value is determined by the sscanf function. Keep in mind the data type of the VAL field for the associated record type. For example the Analog Input record type has a double precision floating point data type. So a %lf (percent ell eff) is required, not a %f. If f8 is not NULL, see the discussion of f8 below.

  The GPIBREAD setting is only valid for input record types.

GPIBWRITE
  - If f8 is NULL, a command string is built via sprintf() as follows: (f7 must specify a size large enough for the message)

            sprintf(dpvt.msg, f5, precord->val);

    Otherwise, a call is made to the function pointed to by f8 as follows:

            (*(f8))(&dpvt, f9, f10, f11);

    This allows the module to create a character string that includes the val field of a record. As in the case of the GPIBREAD operation, keep the specific data type of the VAL field in mind. An oddity of the sprintf() function that comes with vxWorks is that the %lf (percent ell eff) format command will generate nothing when the VAL field is zero. So you should use a length specifier of at least one when using floating point formatting. For example %.1f (percent dot one eff). IS THIS STILL TRUE?
  - dpvt.msg is sent to the instrument.
  - If the responds-to-writes flag is not -1 in the parm block
    - The driver pauses for the number of milliseconds given by the responds-to-writes value.
    - If f6 is non-zero, up to f6 bytes are read from the instrument and placed in the dpvt.rsp string.
    - If the secondary conversion routine pointer is not NULL in the parm block, it is invoked as follows:

              (*(parmblock.wrConversion))(read_status, pdpvt);

  For more information on the secondary conversion routine, see "Machines That Respond to Everything." For more information on the case when f8 is not NULL, see the discussion of f8 below.

GPIBCMD
  - Send the command string specified in f4 to the instrument exactly as specified.
  - If the responds-to-writes flag is not -1 in the parm block.
    - The driver pauses for the number of milliseconds given by the responds-to-writes value.
    - If f6 is non-zero, up to f6 bytes are read from the instrument and placed in the dpvt.rsp string.
    - If the secondary conversion routine pointer is not NULL in the parm block, it is invoked as follows:

              (*(parmblock.wrConversion))(read_status, pdpvt);

  For more information on the secondary conversion routine, see the section "Machines That Respond to Everything."

GPIBACMD
  This is like GPIBCMD except that ATN is held active. This should rarely be necessary.
GPIBSOFT
  No I/O is done. It simply calls the custom conversion routine directly. The return value from the conversion routine is passed back to the caller of the device support processing entry point. The custom conversion routine is called as follows:

          (*f8)(&dpvt, f9, f10, f11);

  When GPIBSOFT is specified, f8 must be set to point to the processing function.

GPIBREADW
  Like GPIBREAD except for that it waits for the device to issue an SRQ before it issues mthe read request.. In order to use this, there must be an srqHandler defined in the parm block. A generic handler devGpibLib_srqHandler is provided. It should be sufficient for most users.
GPIBRAWREAD
  Like GPIBREAD except that no command is sent to the instrument
GPIBEFASTO
  This operation type is only valid on BO and MBBO record types.
  - The string pointed to by f11[VAL] is sent to the instrument.
  - If the responds to writes flag is not -1 in the parm block, data is read from the instrument and placed in the `dpvt.rsp` buffer. If the secondary conversion function pointer is not `NULL` in the parm block, it is invoked as follows:

            (*(parmblock.wrConversion))(read_status, pdpvt);

  For more information on the secondary conversion function, see the section "Machines That Respond to Everything." For more information of the use of f11, see the section "Efast Tables".

  Note that setting f8 to a non-NULL value is invalid for this operation type. Results in that case should be considered catastrophic.

GPIBEFASTI
  This operation type is only valid on BI and MBBI record types.
  - Send the command string specified in f4 to the instrument exactly as specified.
  - Read the data from the instrument and place it into the dpvt.msg buffer.
  - Compare dpvt.msg against each element of the Efast Table.
  - Set the VAL field to the entry number of the first Efast Table element that matched.

  Note that setting f8 to a non-NULL value is invalid for this operation type. Results in that case should be considered catastrophic.

GPIBEFASTIW
  This operation type is like GPIBEFASTI except that it waits for the device to raise SRQ before the data is read.
GPIBIFC

  Valid only for BO records. If rval = (0,1) then (do nothing, pulse IFC). IFC is one of the GPIB Bus Management Lines.

  Only f1,f2,and f3 need to be defined. A default EFAST table is provided.

GPIBREN

  Valid only for BO records. If rval = (0,1) then (drop,assert) REN. REN is one of the GPIB Bus Management Lines.

  Only f1,f2,and f3 need to be defined. A default EFAST table is provided.

  If devices are in the LLO state they can be removed from this state by toggling the REN line, i.e. turn it off and then turn it back on.

GPIBDCL

  Valid only for BO records. If rval = (0,1) then (do nothing, send DCL). DCL is a Universal GPIB command, i.e. it applys to all devices on the link

  Only f1,f2,and f3 need to be defined. A default EFAST table is provided.

GPIBLLO

  If rval = (0,1) then (do nothing, send LLO). LLO is a Universal GPIB command, i.e. it applys to all devices on the link

  Only f1,f2,and f3 need to be defined. A default EFAST table is provided.

  After a LLO command is issued, as soon as a device is addressed it will disable local control, i.e. the front pannel controls will not respond. To remove devices from this state toggle the REN line. A single device can temporily be removed from LLO by sending the GPIBCTL coimmand but it will go back to LLO state as soon as it is again addressed.

GPIBSDC

  If rval = (0,1) then (do nothing, send SDC). SDC is an addressed GPIB command, i.e. it applys only to the addressed device.

  Only f1,f2,and f3 need to be defined. A default EFAST table is provided.

GPIBGTL

  If rval = (0,1) then (do nothing, send GTL). GTL is an addressed GPIB command, i.e. it applys only to the addressed device.

  Only f1,f2,and f3 need to be defined. A default EFAST table is provided.

  If a device has local control locked out, local control can be temporily granted by issuing this command. However the next time the device is addressed it will again disable local control.

GPIBRESETLNKValid only for BO records.

  If rval = (0,1) then (do nothing, reset link task). This completly restarts the link thread. This is a very drastic action.

  Only f1,f2,and f3 need to be defined. A default EFAST table is provided.

GPIBSRQHANDLER
  This is used to handle unsollicited SRQs, i.e. a device raises SRQ when a read wait, e.g. GPIBREADW, is not active. This request is implermented only for longin records. When the device issues an SRQ the status byte is put into the val field and a scanIoRequest is requested. The record should have SCAN set to "I/O Intr". It is expected that the record will forward link to records that issue GPIB commands to read the information that caused the SRQ.
GPIBEOS
  This is NOT a separate request type but is ored with another operation type, e.g. GPIBREAD|GPIBEOS. It signifies that f13 contains an end of message character. This is for devicesthat don't use EOL to signify end of message. Most GPIB devices should not requite this feature but serial devices will most likely require it.

## Efast (Enumerated Fast I/O) Tables

There are many times when a device's command set includes things like "OFF" or "ON" in the command string. It is convienient to issue such commands vi binary and multibit binary records. The efast tables allow the easy specification of such strings. The device support module designer simply specifies the string value for each of the possible states of the VAL field of the record.

The format of an efast table is:

        static char  *(tableName[]) = {
            "TERM LO",    /* when VAL = 0 */
            "TERM HI",    /* when VAL = 1 */
            NULL};        /* list terminator */

And is referenced in an output parameter table entry like this:

        {&DSET_BO, GPIBEFASTO, IB_Q_HIGH, NULL, NULL, 0, 0,NULL, 0, 0, tableName, NULL, -1},

For an input entry, it would look like this:

        {&DSET_BI, GPIBEFASTI, IB_Q_HIGH, "<command>", NULL, 0, 50, NULL, 0, 0, tableName, NULL, -1},

The efast table MUST be null terminated when used for input record types. It is not required for output records, but is a good idea anyway so an efast table can be used for input and output records.

The way the the table is used for outputs is that the VAL field is used to index into the efast table and select which string to send to the instrument. The string is then sent to the instrument as it appears in the efast table with no formatting.

For input operations, the f4 string is sent to the instrument without formatting, and then the response string is read from the instrument. This response string is compared against each of the entries in the efast table starting at the zeroth entry. The slot number of the first table entry that matches the response string is used as the setting for the RVAL field of the record. When strings are compared, they are compared from left to right until the number of characters in the efast table are checked. When ALL of the characters up to but NOT including the NULL of the string in the efast table match the corresponding characters of the response string, it is considered a valid match. This allows the user to check response strings fairly fast. For example, it a device returns something like "ON;XOFF;9600" or "OFF;XOFF;9600" in response to a status check, and you wish to know if the first field is either "OFF" or "ON", your efast table could look like this:

        static char *(statCheck[]) = {
            "OFF",      /* set RVAL to 0 */
            "ON",      /* set RVAL to 1 */
            NULL};     /* list terminator */

Note again that the NULL field is important here. If the instrument gets confused and responds with something that does not start with an "OF" or "ON", the GPIB support library code will end up running off the end of the table.

In the case when none of the choices in an efast table match for an input operation, The record is placed into a VALID alarm state.

## Name Tables

For binary and multibit binary records the choice fields of a record can be assigned values at record initialization. If f12 has a value, then when record is initialized, the gpib device support uses the associated name table to assign values to choice fields that have not been assigned values. These name tables have absolutely nothing to do with the operation of the GPIB device support library with respect to the way any I/O operations are performed.

To use a name table, the address of the table must be put into f12 of the parameter table. The table format for a multibit record type looks like this:

        static char *tABCDList[] = {
            "T",                 /* zrst*/
            "A",                 /* onst */
            "B",                 /* twst */
            "C",                 /* thst */
            "D"};                /* frst */

        static unsigned long tABCDVal[] = {
            1,                  /* zrvl */
            2,                  /* onvl */
            3,                  /* twvl */
            5,                  /* thvl */
            6 };                /* frvl */

        static devGpibNames tABCD = {
            5,                  /* number of elements in string table */
            tABCDList,          /* pointer to string table */
            tABCDVal,           /* pointer to value table */
            3 };                /* value for the nobt field */

The table format for a binary record type looks like this:

        static char *disableEnableList[] = {
            "Disable",          /* znam */
            "Enable" };         /* onam */

        static devGpibNames disableEnable = {
            2,                  /* number of elements */
            disableEnableList,  /* pointer to strings */
            NULL,               /* pointer to value list */
            1};                 /* number of valid bits */

The devGpibNames structure is defined in the devCommonGpib.h header file. The first thing required is list of name strings defined by an array of pointers to strings. For binary record types, the strings are placed into the name fields in order from lowest to highest as shown above. For multibit binary records, there can be up to sixteen strings defined. A devGpibNames structure referencing these strings is then defined.

The value list pointer, and NOBT field are not used for binary record types, but should be specified anyway as if the binary record was a multibit binary record with only 2 values.

For multibit record types, the name strings, values, and NOBT fields are filled in from the name table information. For binary record types, only the znam and onam fields are filled in.

Name strings (and their associated values in the multibit cases) are not filled in if the database designer fills them in via DCT.

## Defining the devGpibParmBlock.

The parm block is the interface between your module and decCommonGpib. It must be defined and initialized similar to the following:

    /* User MUST define init_ai */
    static long init_ai(int parm)
    {
      if(parm==0)  {
        devSupParms.debugFlag = &SkeletonDebug;
        devSupParms.respond2Writes = -1;
        devSupParms.timeWindow = TIME_WINDOW;
        devSupParms.hwpvtHead = 0;
        devSupParms.gpibCmds = gpibCmds;
        devSupParms.numparams = NUMPARAMS;
        devSupParms.magicSrq = 4;
        devSupParms.name = "devXxSkeletonGpib";
        devSupParms.dmaTimeout = IO_TIME;
        devSupParms.srqHandler = devGpibLib_srqHandler;
        devSupParms.wrConversion = 0;
      }
      return(devGpibLib_initDevSup(parm, &DSET_AI));
    }

The fields of the devGpibParmBlock are:

debugFlag
  Must point to a integer that is set to a non-zero value if you want the GPIB device support library to provide debugging output for you.
respond2Writes
  The responding to writes flag is a kluge that is used to indicate that all output-type commands (see the section "The parameter table") to this

  device type will solicit a response from the device. See the section on "Machines that Respond to Everything" for more information about this.

timeWindow
  The amount of time in milliseconds that the GPIB system will wait after a device times-out, before trying to contact it again. During this time window, any I/O operations directed to the timed out device will result in an error and the appropriate alarm status will be raised for the record (either READ_ALARM or WRITE_ALARM depending on the record type and VALID_ALARM in all cases.) For more about this and other exceptional conditions, see the sections on "SRQ Functions" and "General GPIB Problems."
hwpvtHead
  The hwpvt list head is the head pointer to a singly linked list of structures that are called hardware private blocks. There are one of these hwpvt blocks allocated for each instance of a device type supported by this GPIB device support module. They contain information needed by the GPIB device support library. This includes the time the last time-out happened, total number of time-outs processed by the library (this will not include time-outs that happen in result to I/O operations initiated by the interactive GPIB debugging tool), a user private pointer that may be used by a device support module designer for any reason (it is not referenced by any of the library code), and some information about SRQ interrupt processing (see the section "SRQ Functions" for more on these fields.) The hwpvt structures are built and maintained by the GPIB device support library and unless additional information is needed on a per-device instance basis, you may ignore their existence entirely. The proper initialization of the hwpvt field is as shown above, NULL. If you should decide that you want to use the user private pointer, you should read the section "Talking to Machines that Don't Fit Into the Required Model."
gpibCmds
  Address of the parameter table.
numparams
  The number of entries in the parameter table. A #define is used to set it's value.
magicSrq
  Obsolete. No longer used.
name
  The device support module type name field is used by the GPIB support library code when it prints debugging information. The string declared here is prepended to any debugging text printed by the library. If you do not wish to have anything printed, you must specify a null string, not the NULL pointer.
dmaTimeout
  The time to wait for DMA completions is passed on to the driver and used to determine if a machine times out on a transaction or not. If the transfer of the data portion of a GPIB message is not complete within the time specified by this field, the transaction is considered timed out, and an appropriate VALID_ALARM is raised for the record being processed. The value specified for this field is in milliseconds.
srqHandler
  The pointer to the SRQ handler function should point to a function with the following prototype format: static int srqHandler( hwpvt *phwpvt; int srqStatus;) For most device support devGpibLib_srqHandler should be specified. It handles bot sollicited and unsollicited SRQs. If SRQs are to be ignored for the device then just set srqHandler to 0.
wrConversion
  Secondary conversion routine. The secondary conversion routine is used in cases where the responds to writes field is not set to -1. If a machine responds to writes, this field can be used to specify a function to call after the response is read from the device. It is offered here to allow the support module to inspect the response. If no response checking is to be done, this field must be set to NULL. Please see the section on "Machines that Respond to Everything" for more information about this.

## Debugging Flags

The device support library provides some debugging output for exceptional conditions during normal processing if the debug flag in the parm block is set to a non-zero value. It will also prefix its debug statements with the module type name string also defined in the parm block.

## Custom Conversion Routines

When a device's response can not be parsed with a simple sscanf or whose commands can not be formatted with an sprintf. A customized conversion routine will be required. These are supplied in the form as a function with a prototype of:

        static int specialConvert(struct gpibDpvt *pdpvt, int p1, int p2, char **p3)

and are specified in the parameter table. See the discussion of the f8 field above for more information about the parameter table entry.

Given the address of the dpvt structure as well as the developer-entered values for p1, p2, and p3 (that come from the parameter table), the custom conversion function should have all the information required to perform the needed conversion(s).

For some examples of various conversion routines, see the Dg535 device support module.

## Machines that Respond to Everything

One of the basic problems with the (current) implementation of the GPIB device support library code, is that there is no way to perform read operations that consist of the formatting of the command sent to the instrument and the parsing of the response returned from it. In general this has not been much of a problem since most vendors of GPIB devices use strictly defined commands that solicit responses from their devices. However, some devices send back replies to everything.

The GPIB device support library currently supports devices like these by providing a flag in the parm block that can be set to a non-negative value indicating that the library should read data from the device on every type of operation defined in the parameter table.

If the responds to writes flag in the parm block is not set to -1, the library will wait for the number of milliseconds specified by this flag and then, if the f6 parameter is non-zero, will perform a read operation from the device. The data from the read operation will be placed into dpvt.rsp. Then a call will be made to the secondary conversion routine (if not specified as NULL in the parm block) and it will be passed the status from the read operation and the address of the dpvt structure. The prototype of a secondary conversion routine function is:

        static int secondaryConversion(int status; struct gpibDpvt *pdpvt)

Where status is the number of bytes read from the device or -1 if the read operation failed. And pdpvt is the address of the dpvt structure associated with the record being processed.

The return value from the secondary conversion function must either be OK or ERROR. If ERROR is returned the record will be placed into a VALID_ALARM state. Otherwise, the processing of the I/O operation will be completed as normal.

In the future, modifications the the GPIB library will be made to correct this problem and secondary conversion routines will no longer be required or supported.

# devGpibCommon

If the device support generated by devGpib.h doesn't satisfy your needs then you must provide your own. Two ways are:

1. Continue to use devGpibCommon but create your own DSETs. Thus instead of letting devGpib.h create DSETS based on the DSET_xx macros, custom DSET code is provided. This method requires familiarity with devgpibCommon. This section gives a brief description. Look at the code for details.
2. Make direct calls to drvGpib. This is explained in the next section. It again requires that you write your own device support but make calls directly to drvGpib instead of using devGpibCommon.

It is fine to mix all three methods.

There is a library of commonly used functions available to the GPIB module designer. It contains enough code such that a device support module can be written that contains as little as two lines of executable C code.

All GPIB device support library functions have names that are prefixed with `devGpibLib_` and include the type of record they apply to. For example, the `devGpibLib_initAi()` function is used to initialize analog input records. And the `devGpibLib_readAi()` function is used to fill in the VAL field on an analog input record.

### Initialization Functions

The initialization functions are used to verify the validity of information in the device support module as well as the information in a database record before any database record processing begins.

### General Initialization

            long devGpibLib_initDevSup(int parm, gDset *dset,)

Call with parm=0 before any calls are made to the record-type specific init functions, and again with parm != 0 after all calls have been made to record-type specific init functions. The DSET value must point to any one of the DSET data structures for the GPIB device type that is being initialized.

This function does nothing more than print an initialization time message. It might be used in the future to initialize the value fields of output record types.

### Record Specific Initialization

The record specific initialization functions are used to allocate and initialize any data structures needed by the library. For all record types, the operations start the same way:

- Allocate a dpvt structure and connect it to the record.
- Verify that the DTYPE field is either GPIB_IO or BBGPIB_IO.
- Verify that the parameter number is within valid range.
- Allocate a hwpvt structure if necessary.
- Inform the GPIB driver of intended use of the link specified in the record.
- Verify the GPIB device address is within valid range.
- Verify that the parameter table entry's f1 points to the same DSET as the record's.
- Register the SRQ handler with the driver if one specified in the parm block.

For each supported record type, an init routine, e.g. devGpibLib_initAi, is provided. See the code for details.

### Report and Status Functions

    long devGpibLibReport(gDset *dset)

Print a one-liner report of the device name, its addressing information, link type and the total number of observed time-outs. This function is provided so that the dbior function can be used to coarsely observe the operation of a device.

### Transaction Request Functions

The transaction functions are used to perform the I/O operation associated with an initialized database record. In general, they are called as a result of `dbProcess()` processing a record.

### Input Functions

This section describes the library functions that can be used to process a record that requires data to be solicited from a GPIB device. If the record being processed specifies a GPIBSOFT parameter, the soft-processing takes place immediately with no asynchronous return to the caller. In all other cases, the function queues a request to the GPIB driver and returns asynchronously.

If the queue request to the driver fails, the record is placed in a VALID_ALARM state.

The return value from the second call in the asynchronous processing for each function is 2 for each of the following functions except for the MBBI and BI versions... then the return value is 0.

    long devGpibLib_readAi(struct aiRecord *pai)
    long devGpibLib_readBi(struct biRecord *pbi)
    long devGpibLib_readLi(struct longinRecord *pli)
    long devGpibLib_readMbbi(struct mbbiRecord *pmbbi)
    long devGpibLib_readSi(struct stringinRecord *psi)

### Output Functions

This section describes the library functions that can be used to process a record that requires data to be sent to a GPIB device. If the record being processed specifies a GPIBSOFT parameter, the soft-processing takes place immediately with no asynchronous return to the caller. In all other cases, the function queues a request to the GPIB driver and returns asynchronously.

If the queue request to the driver fails, the record is placed in a VALID_ALARM state.

The return value from the second call in the asynchronous processing is zero for each of the following functions.

    long devGpibLib_writeAo(struct aoRecord *pao)
    long devGpibLib_writeBo(struct boRecord *pbo)
    long devGpibLib_writeLo(struct longoutRecord *plo)
    long devGpibLib_writeMbbo(struct mbboRecord *pmbbo)
    long devGpibLib_writeSo(struct stringoutRecord *pso)

### Transaction Processing Functions

These are the functions that perform the actual I/O operations by making calls to the GPIB driver. These functions are called by the driver's link task then the driver has determined that a transaction request is ready for processing.

### Work Functions

These functions are divided into two categories, an input group and an output group.

The output group is fairly simple. An output function formats a message as specified in the parameter table and then calls the driver to send it. After the message is sent, a callbackRequest is made to dbProcess() so that the second half of the asynchronous processing may take place. If the output operation fails, the record is placed into a VALID_ALARM state before the callback to dbProcess() is made.

    int devGpibLib_aoGpibWork(struct gpibDpvt *pdpvt)
    int devGpibLib_boGpibWork(struct gpibDpvt *pdpvt)
    int devGpibLib_loGpibWork(struct gpibDpvt *pdpvt)
    int devGpibLib_mbboGpibWork(struct gpibDpvt *pdpvt)
    int devGpibLib_stringoutGpibWork(struct gpibDpvt *pdpvt)

The input group is a little more complex because a message is not only sent to a device, but a response is read back afterward. If the parameter table entry specifies that it is to be treated as an operation that includes an SRQ to indicate completion, these functions return to the driver before reading the response message back. In the SRQ case, the driver will end up calling the srqHandler function defined in the parm block when it arrives. The srqHandler is responsible for then calling the record specific SRQ handling function described in the section "SRQ Functions" below. This process is described in the section "The SRQ Handler" above.

In the non-SRQ based style of operation, the message specified in the parameter table is sent to the device, the response read back, the response converted to the required VAL field data type as specified in the parameter table, and a callbackRequest() is made to dbProcess to initiate the second half of the asynchronous record processing.

If any errors are encountered, the record is placed in a VALID_ALARM state before the callbackRequest() is made to dbProcess().

    int devGpibLib_aiGpibWork(struct gpibDpvt *pdpvt)
    int devGpibLib_biGpibWork(struct gpibDpvt *pdpvt)
    int devGpibLib_liGpibWork(struct gpibDpvt *pdpvt)
    int devGpibLib_mbbiGpibWork(struct gpibDpvt *pdpvt)
    int devGpibLib_stringinGpibWork(struct gpibDpvt *pdpvt)

### Finish Functions

The finish functions are used to perform the conversion of the data read back from a work function that processes an input operation. These functions are only used internally by the library's work and SRQ processing functions and are presented here only for the sake of completeness. They are currently not useful except to other functions within the library.

    int devGpibLib_aiGpibFinish(struct gpibDpvt *pdpvt)
    int devGpibLib_biGpibFinish(struct gpibDpvt *pdpvt)
    int devGpibLib_liGpibFinish(struct gpibDpvt *pdpvt)
    int devGpibLib_mbbiGpibFinish(struct gpibDpvt *pdpvt)
    int devGpibLib_stringinGpibFinish(struct gpibDpvt *pdpvt)

### SRQ Functions

These are used to perform the reading of a message from a device that has already been solicited by one of the input type work functions described above. They are called by the srqHandler functions in the GPIB device support modules. They simply perform the read operation and call the finish function associated with the type of record being processed.

    int devGpibLib_aiGpibSrq(struct gpibDpvt *pdpvt; int srqStatus)
    int devGpibLib_biGpibSrq(struct gpibDpvt *pdpvt; int srqStatus)
    int devGpibLib_liGpibSrq(struct gpibDpvt *pdpvt; int srqStatus)
    int devGpibLib_mbbiGpibSrq(struct gpibDpvt *pdpvt; int srqStatus)
    int devGpibLib_stringinGpibSrq(struct gpibDpvt *pdpvt; int srqStatus)

# drvGpib

drvGpib is the interface between devCommonGpib and low level drivers. It can also be used by other code, e.g. GI makes calls directly to drvGpibCommon. The interface is descrtibed in two header files: drvGpib.h and drvGpibInterface.h It implements the following interface:

    typedef struct dpvtGpibHead
    {
        ELLNODE node;
        int (*workStart) ();  /* work start function for the transaction */
        int link;
        int device;           /* GPIB primary address for transaction */
        int secondary;        /* secondary address. -1 means only primary*/
        ibLink *pibLink;      /* used by generic driver */
    } dpvtGpibHead;

    typedef struct drvGpibEt
    {
        long number;
        long (*report)(int level);
        long (*init)(void);
        ibLink* (*getLink)(int link, int gpibAddr, int secondary);
        long (*qGpibReq)(dpvtGpibHead *pdpvt,int prio);
        long (*registerSrqHandler)(ibLink *pibLink, int gpibAddr, int secondary,
                                   srqHandlerFunc handler, void *parm);
        long (*read)(ibLink *pibLink, int gpibAddr, int secondary,
                        char *data, int length, int timeout, int eos);
        long (*write)(ibLink *pibLink, int gpibAddr, int secondary,
                      char *data, int length, int timeout);
        long (*addressedCmd)(ibLink *pibLink, int gpibAddr, int secondary,
                             char *data, int length, int timeout);
        long (*universalCmd)(ibLink *pibLink, int cmd);
        long (*ifc)(ibLink *pibLink);
        long (*ren)(ibLink *pibLink,int onOff);
        long (*reset)(ibLink *pibLink);
    } drvGpibEt;
    extern drvGpibEt drvGpib;

drvGpibCommon creates a thread for each link, i.e. for each gpib interface. All gpib I/O request MUST be made via that thread.

Code that uses drvGpibEt has the following structure:

    ...
    typedef struct myWork{
        struct dpvtGpibHead head;
        ....
    }myWork;

    ibLink *pibLink;
    ...
    static int myWorkFunc(dpvtGpibHead *phead)
    {
        myWork *pmyWork = (myWork *)phead;
        int status;
        /* Issue all I/O requests from this function */
        /*For example */
        status = drvGpib.read(phead->pibLink,phead->device,phead->secondary,buffer,buflen,1000,-1);
        return(status);
    }

    ibLink *pibLink;
    myWork work;
    ...
        work.head.workStart = myWorkFunc;
        work.head.link = link;
        work.head.device = gpibAddr;
        work.head.secondary = secondary;
        work.head.pibLink = 0;
        ...
        status = (*drvGpib.qGpibReq)(@work.head,IB_Q_LOW);
        ...

Thus all I/O requests are made via a work function called by drvGpibCommon.

The methods provided by drvGpibEt are:

report
  Prints information about the link. Calls the lower level driver's reportLink method.
init
  Does not need to be called. drvGpibCommon handles this itself.
getLink
  Does not need to be called. drvGpibCommon handles this itself. May be usefull, however, so that user code has a pointer to associated ibLink. For example it is needed to call registerSrqHandler or report.
qGpibReq
  Queues a request to call the user supplied work function.
registerSrqHandler
  Reqisters an SRQ handler for the gpib device
read
  Performs a gpib read command, i.e. it asks to read data from the gpib device/
write
  Peforms a gpib write command, i.e. writes data to the gpib device.
addressedCmd
  Write data to the device with ATN asserted.
universalCmd
  Issues a universial gpib command, i.e. a special byte is sent that all devices receive. ATN is asserted while sending the byte.
ifc
  Issues a gpib IFC pulse
ren
  Sets REN off or on.
reset
  Restarts the thread asscciated with the link.

# Low Level Drivers

drvGpibCommon itself has no knowledge of the details about specific gpib controllers. Instead each link has an associated low level driver. A low level driver must implement the following interface:

    struct drvHwGpibEt
    {
        long (*genLink)(ibLink *pibLink, int pass);
        long (*destroyLink)(ibLink *pibLink);
        long (*reportLink)(ibLink *pibLink, int level);
        long (*probe)(ibLink *pibLink);
        long (*read)(ibLink *pibLink, int gpibAddr, int secondary,
                     char *data, int length, int timeout, int eos);
        long (*write)(ibLink *pibLink, int gpibAddr, int secondary,
                      char *data, int length, int timeout);
        long (*addressedCmd)(ibLink *pibLink, int gpibAddr, int secondary,
                             char *data, int length, int timeout);
        long (*universalCmd)(ibLink *pibLink, int cmd);
        long (*ifc)(ibLink *pibLink);
        long (*ren)(ibLink *pibLink,int onOff);
        long (*srqStatus)(ibLink *pibLink);
        long (*srqEnable)(ibLink *pibLink);
        long (*srqDisable)(ibLink *pibLink);
        long (*serialPollBegin)(ibLink *pibLink);
        unsigned char (*serialPoll)(ibLink *pibLink,int gpibAddr, int secondary,
            int timeout);
        long (*serialPollEnd)(ibLink *pibLink);
    };

where:

genLink
  This is called by drvGpibCommon twice. It is called with pass=0 by drvGpibLinkInit and with pass=1 after the thread for the link is running.
destroyLink
  This is called by drvGpibCommon when it is restarting the link task.
reportLink
  This is called when the report method of drvGpibCommon is called, i.e. when dbior is called.
probe
  Called by drvGpibCommon to see if low level device is still alive.

  WHAT SHOULD LOW LEVEL DEVICE DO? IS IT NEEDED?

read

  Does a gpib read. Driver should do the following:

  LAD for device requested
  TAD for controller
  read data bytes.
  UNT UNL

  NOTE: when reading If eos is -1 then EOL terminates the message otherwise eos is the end of message character.

write

  Does a gpib write. Driver should do the following:

  TAD for controller
  LAD for device
  write data bytes. Set EOL for last byte
  UNT UNL

addressedCmd
  Like write except assert ATTN while writing data bytes
universalCmd
  Write a single byte with ATN asserted.
ifc

  Interface Clear

  Assert IFC
  wait gpib specified time
  release IFC

ren
  Assert or release REN
srqStatus
  Return (0,1) if SRQ (is not, is) asserted.
srqEnable
  Enable SRQs for interface
srqDisable
  Disable SRQs for interface
serialPollBegin

  UNL
  Assert SPE

serialPoll

  Read and return a status byte from the device:

  TAD device being polled
  read a single data byte
  UNT

serialPollEnd

  SPD
  UNT

NOTE: A low level device can also do nothing in serialPollBegin and serialPollBegin and do the following in serialPoll:

UNL
SPE
TAD device being polled
read status byte
SPD
UNT

A low level driver must allocate an ipLink, even though the information in an ipLink is private to drvGpibCommon. It normally does this by defining:

    typedef struct xxxLink {
        ibLink head; /*for use by  drbGpibCommon */
       .... private info for xxxLink
    }xxxLink;

A low level driver starts as follows:

- Every low level driver provides a configuration routine. It must call drvGpibLinkInit as follows:

      pxxxLink->head.pdrvHwGpibEt = &xxxGpibEt;
      pxxxLink->head.link = link;
      status = drvGpibLinkInit(&pxxxLink->head);

- drvGpinLinkInit calls the drivers genLink metod with pass=0
- When the low level driver is initialized it calls drvGpibLinkStart, which spawns a thread for the link
- When the link thread is running it calls genLink with pass=1

# Changes to previous EPICS GPIB support

### devGpibCommon

EXTREMELY IMPORTANT: Previously timeouts were in units of 1/60th of a second. Now timeouts are in milliseconds. Thus previously device support would have definitions like:

    #define TIME_WINDOW     120     /* 2 seconds  */
    #define DMA_TIME        60      /* 1 second   */

Now the definitions would be:

    #define TIME_WINDOW     2000    /* 2 seconds  */
    #define DMA_TIME        1000    /* 1 second   */

Older device created it's own DSET_xxx definitions. Remove all of these and use the techique of defining DSET_AI as shown above, i.e.

    #define devAiXXXGpib
    #define devBiXXXGpib
    ...
    #include <devGpib.h>

Older device support initialized devGpibParmBlock with the statement:

    static struct devGpibParmBlock devSupParms = {
    &xxxDebug,
    ...
    };

Newer support initialized it by a function:

    static long
    init_dev_sup(parm)
    int     parm;
    {
      if(parm==0)  {
        devSupParms.debugFlag = &xxxDebug;

Now this is done via the function:

    static long init_ai(int parm)
    {
      if(parm==0)  {
        devSupParms.debugFlag = &Dg535Debug;
    ...

In a device support module used GPIBIOCTL it will have to be changed to use one on the new GPIBxxx command types.

drvGpibLogData(int onOff,int link,int addr) is now drvGpibLogData(int link,int addr,int onOff)

## drvCommonGpib and low level drivers

The ioctl method is gone. It is replaced by addressedCmd, universalCmd, ifc, ren, and reset. drvHwGpibEt also has the new methods serialPollBegin, serialPoll, and serialPollEnd.

The link thread uses a different method to decide when to call srqStatus. It now calls it every ibSrqPollRate seconds.

The low level drivers now issue UNT UNL commands as given by the guidelines above.

The fields number, report, init are removced from drvHwGpibEt

# General GPIB Problems

Every type of communication system has its problems. The problems with the use of GPIB instruments seem to exist in the fact that vendors simply don't test their GPIB interfaces on their products.

More than one device that misses messages or commands that are given one after the other because they are too close together in time has been identified during the testing of the GPIB support library. There are handshaking lines that are supposed to throttle the speed, but are apparently improperly implemented by device vendors, or make the (wrong) assumption that the controller in charge is slow in its ability to burst bytes down the bus. The only way that this problem can be worked around is to add delays in the GPIB device device support modules. The current device support library does not provide any means to do this.

Very often, a device will slow down over 800% when a user presses a button on the front panel of the device. This can cause the GPIB message transfer to time out, alarms to be set and so on. When devices of this type have to be used, operators will have to be instructed to "look, but don't touch."

Some devices like to go out to lunch once every hour, or day or so and not respond to a command for up to 5 seconds or so (the DG 535 has done this on more than one occasion.) This can be more frustrating that anything else. All that can be said about these types of things is BEWARE of machines that actually work as advertised. There is probably something wrong with it that won't surface until it is in use and controlling something very important.

Test, test, and test your devices after writing a new device support module. Many devices can run fine if doing only three or five transactions per second, but crank it up to 50 or more, and watch it go down in flames. Even if all the records in an EPICS database are scanned slowly, they can still get processed in bursts. EPICS can actually process over 20,000 records in one second if they are all ready to go at the same time. And if there are enough records tied to the same device there is no telling how fast the device will be pushed.

## License Agreement

    Copyright (c) 2002 University of Chicago, The Regents of the
    University of California, and Berliner Elektronenspeicherring
    Gesellschaft fuer Synchrotronstrahlung m.b.H. (BESSY) All rights
    reserved.

    gpibCore - driver suite
    gpibCore is distributed subject to the following license conditions:

     SOFTWARE LICENSE AGREEMENT
     Software: gpibCore

     1. The "Software", below, refers to gpibCore (in either source code, or
        binary form and accompanying documentation). Each licensee is
        addressed as "you" or "Licensee."

     2. The copyright holders shown above and their third-party licensors
        hereby grant Licensee a royalty-free nonexclusive license, subject to
        the limitations stated herein and U.S. Government license rights.

     3. You may modify and make a copy or copies of the Software for use
        within your organization, if you meet the following conditions:
          a. Copies in source code must include the copyright notice and this
             Software License Agreement.
          b. Copies in binary form must include the copyright notice and this
             Software License Agreement in the documentation and/or other
             materials provided with the copy.

     4. You may modify a copy or copies of the Software or any portion of it,
        thus forming a work based on the Software, and distribute copies of
        such work outside your organization, if you meet all of the following
        conditions:
          a. Copies in source code must include the copyright notice and this
             Software License Agreement;
          b. Copies in binary form must include the copyright notice and this
             Software License Agreement in the documentation and/or other
             materials provided with the copy;
          c. Modified copies and works based on the Software must carry
             prominent notices stating that you changed specified portions of
             the Software.

     5. Portions of the Software resulted from work developed under a U.S.
        Government contract and are subject to the following license: the
        Government is granted for itself and others acting on its behalf a
        paid-up, nonexclusive, irrevocable worldwide license in this computer
        software to reproduce, prepare derivative works, and perform publicly
        and display publicly.

     6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY
        OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE
        UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR
        EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
        BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
        FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME
        ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS,
        OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE
        SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT
        THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE
        OR THAT ANY ERRORS WILL BE CORRECTED.

     7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR
        THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT
        OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
        CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE,
        INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY
        REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF
        CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR
        OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
        POSSIBILITY OF SUCH LOSS OR DAMAGES.