Marty Kraimer and Eric Norum
February 25, 2005
This product is available via the open source license described at the end of this document.
devGpib is the successor to the GPIB support that came with EPICS base 3.13. The 3.13 code was unbundled by Benjamin Franksen, and ultimately became gpibCore which is the 3.14 version of Benjamin's support. devGpib is the successor to the device support portion of gpibCore. The driver part of gpibCore is replaced by asynDriver and asynGpib.
This manual assumes that the reader is familiar with EPICS IOC record and device support and also with asynDriver.
devGpib is one method for implementing EPICS IOC device support for instruments. Other methods are available. If support for an instrument does not exist, consider using STREAMS instead of devGpib.
The 3.13 GPIB support only worked with real GPIB instruments. Since devGpib uses low level asyn drivers, it can also work with other instruments, e.g. serial devices. Thus, this manual uses the terminology instrument rather than GPIB device.
devGpib requires that a device support module be created for each supported instrument. Facilities are provided to make it relatively easy to write new support.
The following features are provided:
devGpib is bundled with the asynDriver. The code is in library asyn. Thus,
once asyn is included as part of an application, devGpib will also be
available. It is only necessary to include devGpib.dbd
in your
<app>Include.dbd
file. In addition, device support for
your specific instruments must be installed.
devGpib does not provide support for specific GPIB devices but 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 is not listed and a message to tech-talk does not provide any help, then you will have to write your own device support. This section assumes that an instrument support is available.
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>
- Is the name from a device
database definition, i.e. a definition of the form:
device(<record type>,GPIB_IO,<dsetName>,"<device support name>")
The INP or OUT field has the format:
field(INP,"#L<link> A<addr> @<number>") or field(OUT,"#L<link> A<addr> @<number>")where
<link>
<addr>
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>
recordType @<number> DescriptionIf 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, 0},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") ... }
In order to have these commands available, devGpib.dbd
must
be included as part of the applications xxxInclude.dbd
file.
A report of all devGpib devices can be generated via the command:
dbior("devGpib",level)
Three timeouts are defined:
timeout
- This is the timeout for individual I/O
operations. It is determined by the instrument support.queueTimeout
- Maximum time to wait in a the queue for
access to a device instance. The default is 60 seconds and can be changed
with the iocsh
command:
devGpibQueueTimeout(interfaceName,gpibAddr,timeout)
srqWaitTimeout
- Maximum time to wait for an SRQ after a
GPIBREADW or GPIBEFASTIW has sent a command to the device. The default is
5 seconds and can be changed with the iocsh
command:
devGpibSrqWaitTimeout(interfaceName,gpibAddr,timeout)
This section describes how to write device support for an instrument. It is assumed that the reader is already familiar with the dialogue required to operate the instrument and EPICS record and device support.
An instrument support module provides access to the operating parameters of the instrument.
Instruments typically have many operating parameters, each of which may be thought of in terms of an EPICS database record type. It is the job of the instrument support designer to map operating parameters to record types. Once this mapping is complete, an instrument support module can be written. For each operating parameter, a gpibCmd must be created.
device(<record type>,<link type>,<DSET name>,"<DTYP name>")
where
For example, the definitions for the test supplied with devGpib 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 EPICS Application Developers Guide.
If you are writing a new instrument support module just:
<asynTop>/bin/<EpicsHostArch>/makeSupport.pl -t devGpib <InstName>
An instrument device support module consists of DSET entries, an array of gpibCmds, efast tables (optional), name tables (optional), a devGpibParmBlock, a debugging flag, an init_ai routine, and custom conversion functions (optional.).
A simplified version of the skeleton file is:
/* devSkeletonGpib.c */ ... #include <devCommonGpib.h> ... /* define all desired DSETs */ ... #define DSET_BO devBiSkeletonGpib ... #include <devGpib.h> /* must be included after DSET defines */ #define TIMEOUT 1.0 #define TIMEWINDOW 2.0 ... /* Strings used by the init routines to fill in the znam,onam,... in BI and BO*/ static char *offOnList[] = { "Off", "On" }; static struct devGpibNames offOn = { 2, offOnList, 0, 1 }; static char *initNamesList[] = { "Init","Init" }; static struct devGpibNames initNames = { 2,initNamesList,0,1 }; /* example EFAST table */ static char *userOffOn[] = {"USER OFF;", "USER ON;", 0}; /* Array of structures that define all GPIB messages */ static struct gpibCmd gpibCmds[] = { /* Param 0 */ {&DSET_BO,GPIBCMD,IB_Q_HIGH,"init",0,0,32,NULL,0,0,NULL,&initNames,0}, /* Param 1 */ {&DSET_BO, GPIBEFASTO, IB_Q_HIGH,0,0, 0, 32,0, 0, 0, userOffOn, &offOn, 0}, /* 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.name = "devSkeletonGpib"; devSupParms.gpibCmds = gpibCmds; devSupParms.numparams = NUMPARAMS; devSupParms.timeout = TIMEOUT; devSupParms.timeWindow = TIMEWINDOW; devSupParms.respond2Writes = -1; } }
The meaning of each portion of the code should become clear as you read the following sections:
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. A #define must appear for each record type required. DSET_AI must be defined because an init_ai routine must be implemented as described below.
devCommonGpib provides device support for many standard record types. It is also possible to create custom support, but this is more difficult.
This is where the translation to and from the language of the instrument 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.
In the example above the definitions for the gpibCmds are:
static struct gpibCmd gpibCmds[] = { /* Param 0 */ {&DSET_BO, GPIBEFASTO, IB_Q_HIGH, 0, 0, 0, 32,0, 0, 0, userOffOn, &offOn, 0}, /* 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")
gpibCmd is
typedef struct gpibCmd { gDset *dset; /* used to indicate record type supported */ int type; /* enum - GPIBREAD...GPIBSRQHANDLER */ short pri; /* request priority IB_Q_LOW, IB_G_MEDIUM, or IB_Q_HIGH */ char *cmd; /* CONSTANT STRING to send to instrument */ char *format;/* string used to generate or interpret msg */ int rspLen; /* room for response error message */ int msgLen; /* room for return data message length */ /*convert is optional custom routine for conversions */ int (*convert) (gpibDpvt *pgpibDpvt,int P1, int P2, char **P3); int P1; /* P1 plays a dual role: */ /* For EFAST it is set internally to the /* number of entries in the EFAST table */ /* For convert it is passed to convert() */ int P2; /* user defined parameter passed to convert() */ char **P3; /* P3 plays a dual role: */ /* For EFAST it holds the address of the EFAST table */ /* For convert it is passed to convert() */ devGpibNames *pdevGpibNames; /* pointer to name strings */ char * eos; /* input end-of-string */ } gpibCmd;
where
dset
type
type
field must be set to one of the enumerated values
declared in devSupportGpib.h, i.e. GPIBREAD,...,GPIBSRQHANDLER. See
next section for the definitions.pri
IB_Q_HIGH
, IB_Q_MEDIUM
, or
IB_Q_LOW
.cmd
type
. See the discussion of type
below. Set
this field to 0 if not used.format
type
. See the discussion of type
.
Set this field to 0 if not used.rspLen
msgLen
convert
int (*convert) (gpibDpvt *pgpibDpvt,int P1, int P2, char **P3);The use depends on the pgpibCmd->type. See below for details. Set to 0 when no conversion function is present.
Conversion routines should return 0 to signify a successful conversion. If a convert routine finds an error, it should do the following:
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "<format>",...);
P1
For EFAST operations it is set equal to the number of entries in the
efast table by devSupportGpib:init_record
.
For other operations, it is an integer passed to the conversion
function specified in convert.
P2
convert
.P3
When type
is one of the EFAST operations, this field
points to the EFAST table. See the EFAST operation descriptions under
the type
field definitions and the section "Efast Tables"
for more on the use of this field. Set this field to 0 when it is not
used.
For other operations, it is passed to the conversion function
specified in convert
. It has a char**
value.
pdevGpibNames
eos
0
""
"\n"
)"\n"
sets the message terminator to a single ASCII
newline ('\n'
) character. Some drivers, e.g. the
VXI-11, allow only a single termination character.The following describes the semantics for the device support provided by the devGpib support provided with asynDriver. If an application extends this support, it must document its changes.
Supports record types: ai, bi, event, longin, mbbi, mbbiDirect, stringin, and waveform. For all of these types the following is done.
pgpibCmd->cmd
to the instrument.pgpibDpvt->msg
. pgpibCmd->msgLen
must specify a size large enough
for the message.If convert
is defined then:
convert
is called. It is expected to give a value to
the appropriate field of the record or return -1.pgpibDpvt->msgInputLen
contains the
number of bytes in the last read msg. This allows messages with
null characters to be processed.If convert
is not defined then what is done depends on
the record type.
pgpibDpvt->msg
is converted and the result put
into field VAL. If pgpibCmd->format is defined it is used for
the conversion, otherwise a format appropriate to the data type of
VAL is used.
pgpibDpvt->msg
is converted and the result put
into field VAL or RVAL. VAL is used if the DSET does NOT define
special_linconv and RVAL is used if special_linconv is defined. If
pgpibCmd->format is defined, it is used for the conversion.
Otherwise, a format appropriate to the field is used. The DSET
generated by devGpib.h does not define special_linconv.
pgpibDpvt->msg
is converted and the result put
into field VAL. If pgpibCmd->format is defined it is used for
the conversion, otherwise "%39c" is used.
Unless FTVL is menuFtypeCHAR, an error is generated and the
record is put into alarm. If FTVL is menuFtypeCHAR,then
epicsSnprintf is used to convert pgpibDpvt->msg
into BPTR. If format is defined it is used, otherwise "%s" is
used.
Supports record types: ao, bo, longout, mbbo, mbboDirect, stringout, and waveform.
convert
is defined, it is called. It must put a
command string into pgpibDpvt->msg. It can return:
Signifies error. The operation is aborted and the record put into alarm.
Success and call strlen to determine the length of msg.
Success and the return value is the number of bytes in msg.
convert
is not defined, then what happens is
determined by the record type.
If special_linconv is NOT defined in DSET, the RVAL field is converted as a long into msg. If special_linconv is defined, OVAL is converted as a double into msg.
VAL is converted as an unsigned long into msg.
VAL is converted as a long into msg.
VAL is converted into msg via epicsSnprintf. If pgpibCmd->format is defined it is used, otherwise "%s" is used.
BPTR is converted into msg via epicsSnprintf. If pgpibCmd->format is defined it is used, otherwise "%s" is used.
pgpibDpvt->msg
is sent to the instrument.
Supports record types:
ai, ao, bi, bo, event, longin.longout, mbbi, mbbo, mbbiDirect, mmboDirect, stringin, stringout, waveform.
All I/O is done by the convert
routine, which must be
defined. convert
is called by a callback routine and thus
can make an arbitrary number of calls to low level drivers. It is
passed the address of gpibDpvt
which contains the
information needed to call the low level drivers: asynCommon,
asynOctet, and asynGpib.
Note that asynGpib
may
not be present, i.e. pasynGpib
is null.
gpibDpvt
also contains a field pupvt
which
can be used by the convert routine. Is is initialized to null. The
macro gpibCmdGet
can be used to get the address of
gpibCmd
which contains other usefull information.
If the End of String terminator needs to be changed, it must be
changed by calling pdevSupportGpib->setEos
rather than
calling pgpibDpvt->pasynOctet->setEos
Also when the
convert
routine has finished with read operations it must
call pdevSupportGpib->restoreEos
Supports record types: ao, bo, longout, mbbo, mbboDirect, stringout, and waveform.
Send the command string specified in pgpibCmd->cmd
to the instrument exactly as specified.
pgpibCmd->convert
.
pgpibCmd->convert
must be defined If GPIBSOFT fails, it
calls asynPrint
with mask ASYN_TRACE_ERROR
and also puts the record into alarm.
This operation type is only valid on BO and MBBO record types.
pgpibCmd->P3
must contain the address of an efast
table. At init time some checks are made to see that an efast table is
defined, but if it is defined incorrectly problems may arise.
The following is done:
pibDpvt.efastVal
equal to the
VAL field.pgpibCmd->cmd
is not null, then
msgLen
must also be specified. msg
is set equal
to the concatenation of cmd
and the efast value
specified by pgpibCmd->P3
. The resulting
msg
is sent.pgpibCmd->cmd
is null, then the string pointed
to by pgpibCmd->P3[efastVal]
is sent.
This operation type is only valid on BI and MBBI record types.
The following is done:
cmd
to the
instrument exactly as specified.pgpibDpvt->msg
.msg
with each element of the EFAST table
referenced by pgpibCmd->P3.
pgpibDpvt->efastVal
to the
index of the EFAST table that matched.pgpibDpvt->efastVal
.
Valid only for BO records. If rval = (0,1) then (do nothing, pulse IFC). IFC is one of the GPIB Bus Management Lines.
Only define dset
, type
, and
pri
. A default pdevGpibNames is provided. For example
{&DSET_BO, GPIBIFC, IB_Q_LOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
Valid only for BO records. If rval = (0,1) then (drop,assert) REN. REN is one of the GPIB Bus Management Lines.
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.
Only define dset
, type
, and
pri
. A default pdevGpibNames is provided.
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 define dset
, type
, and
pri
. A default pdevGpibNames is provided.
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
After a LLO, the first time 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 temporarily be removed from LLO by sending the GPIBCTL command but it will go back to LLO state as soon as it is again addressed.
Only define dset
, type
, and
pri
. A default pdevGpibNames is provided.
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 define dset
, type
, and
pri
. A default pdevGpibNames is provided.
If rval = (0,1) then (do nothing, send GTL). GTL is an addressed GPIB command, i.e. it applys only to the addressed device.
If a device has local control locked out, local control can be temporarily granted by issuing this command. However the next time the device is addressed it will again disable local control.
Only define dset
, type
, and
pri
. A default pdevGpibNames is provided.
The format of an efast table is:
static char *tableName[] = { "OFF", /* when VAL = 0 */ "ON", /* when VAL = 1 */ 0 /* list terminator */}; And is referenced in an output parameter table entry like this:
{&DSET_BO, GPIBEFASTO, IB_Q_HIGH, 0, 0, 0, 0,0, 0, 0, tableName, 0, 0},For an input entry, it would look like this:
{&DSET_BI, GPIBEFASTI, IB_Q_HIGH, "<command>", 0, 0, 50, 0, 0, 0,
tableName, 0, 0},The efast table MUST be 0 terminated.
For outputs the VAL field is used to index into the efast table and select
a string to send to the instrument. If cmd
is 0, the string is
sent to the instrument exactly as as it appears in the efast table. If
cmd
is defined, then that string is prepended to the string
obtained from the efast table.
For input operations, the cmd
string is sent to the
instrument, and msg
is read from the instrument.
msg
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 0 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, if 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 */ 0}; /* list terminator */The 0 field is extremely important. If it is omitted and the instrument gets confused and responds with something that does not start with an "OFF" 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 INVALID alarm state.
devGpibNames
is:
struct devGpibNames { int count; /* CURRENTLY only used for MBBI and MBBO */ char **item; unsigned long *value; /* CURRENTLY only used for MBBI and MBBO */ short nobt; /* CURRENTLY only used for MBBI and MBBO */ };
To use a name table, the address of the table must be put into
pdevGpibNames
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 */ 0, /* pointer to value list */ 1}; /* number of valid bits */
devGpibNames
is defined in devSupportGpib.h
. For
binary records, the strings are placed into the name fields in order from
lowest to highest as shown above. For multibit binary records, up to sixteen
strings can be defined. A devGpibNames
structure referencing
these strings is then defined.
value
and nobt
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 devGpibNames
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 has assigned them values.
devGpibParmBlock
. init_ai
MUST initialize this
structure. For example:
static long init_ai(int parm) { if(parm==0) { devSupParms.name = "devSkeletonGpib"; devSupParms.gpibCmds = gpibCmds; devSupParms.numparams = NUMPARAMS; devSupParms.timeout = TIMEOUT; devSupParms.timeWindow = TIMEWINDOW; devSupParms.respond2Writes = -1; } return(0); }
devGpibParmBlock
is:
struct devGpibParmBlock { char *name; /* Name of this device support*/ gpibCmd *gpibCmds; /* pointer to gpib command list */ int numparams; /* number of elements in the command list */ double timeout; /* seconds to wait for I/O */ double timeWindow; /* seconds to stop I/O after a timeout*/ double respond2Writes; /* set >= 0 if device responds to writes */ /*The following are set by devSupportGpib*/ int msgLenMax; /*max msgLen all commands*/ int rspLenMax; /*max rspLen all commands*/ };
gpibCmds
name
numparams
timeout
timeWindow
respond2Writes
msgLenMax
rspLenMax
If the low level device driver implements interface asynGpib
,
then devSupportGpib registers itself to handle SRQs. It defines two types of
SRQs: solicited and unsollicited. Solicited SRQs are for GPIBREADW and
GPIBEFASTIW commands. If an SRQ is raised for a gpibAddr that does not have
an outstanding GPIBREADW or GPIBEFASTIW command, the SRQ is considered
unsolicited.
When the devSupportGpib receives an unsolicited SRQ and it has a registered handler for the gpibAddr, it calls the handler. Otherwise it issues a message that it received an unsolicited SRQ.
The device support for the longinRecord supports gpibCmd type GPIBSRQHANDLER. It calls the devSupportGpib registerSrqHandler method. When its interruptCallbackInt32 gets called, it puts the SRQ status byte into the VAL field and then makes a request to process the record. By forward linking this record to other records, the user can handle SRQs from specific devices. Note that the callback is an interruptCallbackInt32 since asynGpib handles SRQ callbacks via the asynInt32 interface and using asynUser.reason = ASYN_REASON_SIGNAL.
The facilities described above should satisfy most gpib requirements. This section and the next explain how to provide additional support. For example, support could be written for additional record types. This section explains devCommonGpib, and the next section explains devSupportGpib.
devCommonGpib provides support for specific record types by making calls to devSupportGpib. As explained above, an instrument support module must define some combination of DSET_AI,...,DSET_WF and then include devGpib.h. devGpib.h defines DSETs (Device Support Entry Tables) that refer to methods implemented in devCommonGpib.c
If you want to write additional support code that can be used for writing instrument specific device support, the easiest way is to start with code in devCommonGpib and modify it.
devGpib provides three header files:
devSupportGpib.h describes all the public structures used by devGpib. The structures gpibCmd, devGpibNames, and devGpibParmBlock were described above. They are needed to create an instrument device support module. The remaining structures are used by devCommonGpib, devSupportGpib, or other support. These structures are: gDset, gpibDpvt, devGpibPvt, and devSupportGpib.
A gDset is an "overloaded" definition of a DSET. A gDset looks to iocCore like a regular DSET, but it has an additional field that is the address of a devGpibParmBlock.
struct gDset { long number; DEVSUPFUN funPtr[6]; devGpibParmBlock *pdevGpibParmBlock; };
where
number
funPtr
pdevGpibParmBlock
The dpvt field of a record with devGpib device support contains the address of a gpibDpvt
struct gpibDpvt { devGpibParmBlock *pdevGpibParmBlock; CALLBACK callback; dbCommon *precord; asynUser *pasynUser; asynCommon *pasynCommon; void *pasynCommonPvt; asynOctet *pasynOctet; void *pasynOctetPvt; asynGpib *pasynGpib; void *pasynGpibPvt; int parm; /* parameter index into gpib commands */ char *rsp; /* for read/write message error responses */ char *msg; /* for read/write messages */ int msgInputLen; /* number of characters in last READ*/ int efastVal; /* For GPIBEFASTxxx */ void *pupvt; /*private pointer for custom code*/ devGpibPvt *pdevGpibPvt; /*private for devGpibCommon*/ };
where
pdevGpibParmBlock
pgDset->pdevGpibPvt
callback
precord
pasynUser
pasynCommon,pasynCommonPvt
pasynOctet,pasynOctetPvt
pasynGpib,pasynGpibPvt
parm
rsp
msg
msgInputLen
efastVal
pupvt
pdevGpibPvt
describes methods implemented by devSupportGpib.c.
/* If a method returns int then (0,-1) => (OK, failure) */ typedef void (*gpibWork)(gpibDpvt *pgpibDpvt,int failure); typedef int (*gpibStart)(gpibDpvt *pgpibDpvt,int failure); typedef void (*gpibFinish)(gpibDpvt *pgpibDpvt,int failure); typedef int (*gpibWork)(gpibDpvt *pgpibDpvt,int failure); struct devSupportGpib { long (*initRecord)(dbCommon *precord, struct link * plink); void (*processGPIBSOFT)(gpibDpvt *pgpibDpvt); void (*queueReadRequest)(gpibDpvt *pgpibDpvt,gpibStart start,gpibFinish finish); void (*queueWriteRequest)(gpibDpvt *pgpibDpvt,gpibStart start, gpibFinish finish); /* queueRequest returns (0,1) for (failure,success) */ int (*queueRequest)(gpibDpvt *pgpibDpvt, gpibWork work); void (*registerSrqHandler)( gpibDpvt *pgpibDpvt,interruptCallbackInt32 handler,void *userPrivate); int (*writeMsgLong)(gpibDpvt *pgpibDpvt,long val); int (*writeMsgULong)(gpibDpvt *pgpibDpvt,unsigned long val); int (*writeMsgDouble)(gpibDpvt *pgpibDpvt,double val); int (*writeMsgString)(gpibDpvt *pgpibDpvt,const char *str); int (*readArbitraryBlockProgramData)(gpibDpvt *pgpibDpvt); int (*setEos)(gpibDpvt *pgpibDpvt,gpibCmd *pgpibCmd); int (*restoreEos)(gpibDpvt *pgpibDpvt,gpibCmd *pgpibCmd); void (*completeProcess)(gpibDpvt *pgpibDpvt); }; epicsShareExtern devSupportGpib *pdevSupportGpib;
gpibWork
gpibStart
gpibFinish
initRecord
processGPIBSOFT
queueReadRequest
start
function is called before devGpibSupport issues
write/reads and finish
is called after the read.
start
is optional and not usually required for read
operations. The msg
buffer MUST not be accessed except via
the start or finish work functions.queueWriteRequest
start
and finish
work
function. The start
function is called before
devGpibSupport issues a write and finish
is called after
the write. The msg buffer MUST not be accessed except via the
start
or finish
work functions.
start
must set msg
or efastVal
depending on the pgpibCmd->type
.queueRequest
report
registerSrqHandler
writeMsgLong,writeMsgULong,writeMsgDouble,writeMsgString
readArbitraryBlockProgramData
#
) characters followed
by IEEE-488.2 definite-length arbitrary block program data followed by
the end-of-string specified by the active gpibCmd entry, and stores the
entire response in pgpibDpvt->msg. This routine is intended for use
by custom input functions to read a block of arbitrary data from a
serial-line device.setEos
restoreEos
completeProcess
pdevSupportGpib
NOTE: The following comments are from John Winan's original GPIB documentation.
Every type of communication system has its problems. Some instrument vendors don't properly test the GPIB interfaces on their products. Some devices miss messages or commands that are too close together in time. 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 about 5 seconds (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 don't 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 up 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.
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. asynDriver is distributed subject to the following license conditions: SOFTWARE LICENSE AGREEMENT Software: asynDriver 1. The "Software", below, refers to asynDriver (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.