John Winans
Mar 25 1996
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 events are made available to the device support module if so desired. The processing of an SRQ event is completely up to the designer of the module. They may be ignored, tied to event based record processing, or anything else the designer wishes. Error conditions may be handled in a similar fashion.
The GPIB_IO or BBGPIB_IO field is used to specify the type of interface the device is attached to. The GPIB_IO interface is the National Instruments 1014 board and the BBGPIB_IO is the bitbus universal gateway (BUG.) This field becomes the record's link type field.
"devAiModName" represents the DSET name used to identify the entry point(s) to the GPIB device support module. This must be the exact same name specified in the device support module for the same record type, in this case, an analog input record.
The last field is the text field that will appear in the DCT choice menu that pops up when the user edits the DTYP field of a record.
Notice that the same DSET name appears for both the BUG and NI interfaces. This is because the GPIB library code uses the record's link type to differentiate between the two. Also note that unless explicitly stated otherwise, only GPIB device support modules that are designed using the GPIB device support library can actually support both the NI and BUG interfaces!
When the modifications are complete to the devSup.ascii file and the proper makesdr incantation has been made, DCT will provide access to the new devices by allowing them to appear in the choice menu for the DTYP fields for the record types specified in the devSup.ascii file. It will also present a menu box for the output (or input) specification field to query the user for the proper GPIB (or BitBus) link number, which parameter table entry to use when performing I/O, the device address (the actual GPIB address), and in the case of bitbus, the BUG's node number.
For more information on the various ascii and header files, makesdr, and how DCT uses them see the document "The Application Developers Guide".
The fast and easy way to create a new GPIB device support module is to copy the template and change the DSET entry names to a new unique value, change the debug flag name, and replace the parameter table entries. Then compile it and you are finished. This assumes that you do not wish to support SRQ processing and do not use the enumerated commands. In those cases, you might have to perform some additional work described in the sections below.
A typical DSET table used in a GPIB device support module looks like this:
gDset devAiDevicenameGpib { 6, /* number of EPICS elements in the DSET table */ {report, /* pointer to report function */ init_dev_sup, /* pointer to general init function */ devGpibLib_initAi, /* pointer to record-specific init function */ NULL, devGpibLib_readAi, /* pointer to record-specific I/O function */ NULL, (DRVSUPFUN) &devSupParms, /* pointer to GPIB parm block */ (DRVSUPFUN) &devGpibLib_aiGpibWork, /* pointer to GPIB work function */ (DRVSUPFUN) &devGpibLib_aiGpibSrq}}; /* pointer to GPIB SRQ handler */In general, the above example may be used for any and all analog input GPIB DSET structures. And the DSET tables provided in the generic GPIB device support module template should work unmodified in most cases. The data type gDset is defined in the devCommonGpib.h header file and should be used by GPIB device support modules when defining DSET tables.
There will be one DSET module for each type of record supported by a GPIB
device support module. Only one of them should include the pointers to the
general init function and the report function. Other DSET entries should use
NULL for those fields. The reason for this is because the init routine is
called in each DSET and in the case of a multi-DSET module, it will be called
unnecessarily. The report routine works the same way. It is currently called
only when a user types the dbior
command on an IOC console. And if more than
one DSET points to the same report routine, you will see multiple copies of
your report... Nothing fatal, just irritating.
All DSETs in the same support module will have the same pointer to the same parm block specified. This is required by the GPIB device support library.
Each DSET will have a different pointer for the work function and SRQ handler. There are record-type specific work functions and SRQ handlers available in the GPIB device support library that may be used for these if they are applicable.
Please see the document "The Epics Application Developers Guide" for more information about DSET tables.
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 */ {&DSET_BO, GPIBCMD, IB_Q_HIGH, "init", NULL, 0, 0, NULL, 0, 0, NULL, NULL, -1} };This example parameter table contains 2 parameters. They are numbered zero and one. Parameter zero is provided for reference. Parameter one is an actual parameter line that is used in the DC5009 frequency counter's parameter table. A formal description of the fields is as follows:
This field must be assigned the address of a DSET.
The f2 field must be set to one of the following enumerated values declared in devCommonGpib.h:
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 has the effect of reading data from the instrument and parsing the desired information out of it. In the case where f8 is NULL, the value is determined by the sscanf function. These are generally useful, but tricky. Keep in mind the data type of the VAL field for the type of record you are trying to update. 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. For the case when f8 is non-NULL, see the discussion of f8 below.
The GPIBREAD setting is only valid for input record types.
sprintf(dpvt.msg, f5, precord->val);Otherwise, a call is made to 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).
(*(parmblock.wrConversion))(read_status, pdpvt);
(*(parmblock.wrConversion))(read_status, pdpvt);
(*f8)(&dpvt, f9, f10, f11);When GPIBSOFT is specified, f8 must be set to point to the processing function.
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);
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);
Note that setting f8 to a non-NULL value is invalid for this operation type. Results in that case should be considered catastrophic.
Note that setting f8 to a non-NULL value is invalid for this operation type. Results in that case should be considered catastrophic.
Note that setting f8 to a non-NULL value is invalid for this operation type. Results in that case should be considered catastrophic.
IB_Q_HIGH
or IB_Q_LOW
. These values are enumerated in drvGpibInterface.h.
dpvt.rsp
. It is used to hold the message that is 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.
GPIBWRITE
, GPIBREAD
, or GPIBREADW
.
Set this field to zero when not used.
GPIBSOFT
, or to perform a conversion/parsing operation when
f2 is set to any of the other operation types. Note that 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. Great care should be taken in these
functions so as to not overflow the dpvt.msg field when it is being used. This
function is passed f9, f10, and f11 as parameters.
For output type operations, this custom conversion 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.
This field must be set to NULL when no conversion function is present.
Set this field to NULL when it is not used.
Set this to NULL when no Name Table is used.
GPIBWRITE
operations (see description of f2 above), you have to use a custom
conversion routine. And a custom function for every lousy binary and multibit
binary supported function is outrageous.
The efast tables are used to get around the formatting problem of these types of situations by removing the formatting altogether. The device support module designer simply types in each of the command or expected response strings 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, NULL, 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 that they all look the same. Otherwise you might forget one on used for an input operation and spend all day looking for the problem.
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[]) = { "OF", /* 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.
Before continuing, it should be understood that 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 struct 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 struct 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 you need is the list of name strings. This is done by the declaration of 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.
After the table of strings is defined, you define a devGpibNames structure that includes the number of strings/name fields to fill in, a pointer to the table of strings, a pointer to the table of values, and the number of bits field (a multi-bit record's NOBT field.)
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.
A sample parm block looks like this:
struct devGpibParmBlock devSupParms = { &Dc5009Debug, /* debugging flag pointer */ -1, /* set to -1 if device does not respond to writes */ 300, /* # of clock ticks to skip after a device times out */ NULL, /* hwpvt list head */ gpibCmds, /* GPIB command array (parameter table) */ NUMPARAMS, /* number of supported parameters */ -1, /* magic SRQ param number (-1 if none) */ "devXxDc5009Gpib", /* device support module type name */ DMA_TIME, /* # of clock ticks to wait for DMA completions */ NULL, /* SRQ handler function (NULL if none) */ NULL}; /* secondary conversion routine (NULL if none) */The debugging flag pointer 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.
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.
The next field represents the amount of time (in 60ths of a second) 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 that are directed at 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."
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 that describes the current state of each device. 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."
The command array pointer is a pointer to the parameter table.
The number of supported parameters is next and represents the number of entries in the parameter table. The standard template uses a simple #define to calculate this value. If you use it, you need not concern yourself with it.
The magic SRQ param number is only used if you have an SRQ handler specified. See "The SRQ Handler" and "SRQ Functions" for more information on this.
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.
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 must be in 60ths of a second.
The pointer to the SRQ handler function should point to a function with the following prototype format: static int srqHandler(struct hwpvt *phwpvt; int srqStatus;) It will be called when ever an SRQ is detected from one of the devices supported by the GPIB support module. If SRQs are to be ignored for the supported device type, this must be set to NULL. See the section "The SRQ Handler" for more information.
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.
The overall purpose of an SRQ handler is to determine if a given SRQ is expected, and if so call the required function(s) required to handle it. In the cases where an SRQ is not expected, it is up to the designer of the module designer to decide how to handle them.
The SRQ handler is provided a pointer to the hwpvt structure as well as the byte value returned from the serial poll made to the device. Since the device driver has no way of knowing what record (if any) that the SRQ is to be associated with, the SRQ handler has to figure it out. To make things a little easier, the GPIB library code stores the address of the dpvt structure as well as the record type specific SRQ processing function into the hwpvt structure for any record that is being processed that is expecting an SRQ. The library also informs the driver that no transactions are to be made to the device while waiting for the SRQ by returning a BUSY status to the driver when entering the wait state for the SRQ. This assures that the dpvt and function pointers in the hwpvt structure are valid when the expected SRQ arrives.
See the skeleton GPIB device support module for an example of handling solicited and unsolicited SRQs.
GPIBREADW
and GPIBEFASTIW
. In these cases, it is expected
that the command string is expected to solicit an SRQ that indicates that an
operation has completed.
If an SRQ is expected, the dpvt and record specific processing function addresses will be waiting in the hwpvt structure as outlined above. So to handle this type of SRQ, check to see if one was expected (the function pointer being non-NULL) and then invoke the handling function.
No example code is currently available. However, the following discussion should provide enough information for a developer to create an I/O-event scanned record that can be processed when unsolicited SRQs are recognized by the srqHandler function.
When it has been determined that an SRQ does not represent a solicited operation complete, a record may be processed by the use of a callbackRequest() or a scanIoRequest() function. These can process a record provided that the device support module can remember which one(s) is(are) to be processed.
Currently, the magic SRQ param number specified in the parm block is recognized by the GPIB library code as a parameter that records can specify that require processing when unsolicited SRQs are recognized. The library will only allow one record for each device to be defined that specifies the magic number (in contrast to one per device type.) When these records are initialized, the address of their dpvt structures are saved in the hwpvt structures associated with the physical devices. So when an unsolicited SRQ comes along, processing the right record is fairly straight forward. Make a callbackRequest to the record processing entry point for the record represented by the saved dpvt address. (see the skeleton GPIB device support's sample srqHandler function for an example of this.)
It would be nice if all record processing for unsolicited SRQs was done by using the scanIoRequest function. Perhaps some day...
It will be a good idea to start your code design copying the part(s) of the GPIB device support library into your module that require replacement. This way you will have an example of an operational version of your code with all the correct parameters and data types defined on the calls to the actual GPIB driver.
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.
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 a period of time specified by this flag and then perform a read operation from the device. The data from the read operation will be placed into dpvt.rsp. And 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.
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.
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.
long devGpibLib_initAi(struct aiRecord *pai, void (*process)())
long devGpibLib_initBi(struct biRecord *pbi, void (*process)())
long devGpibLib_initLi(struct longinRecord *pli, void (*process)())
long devGpibLib_initMbbi(struct mbbiRecord *pmbbi, void (*process)())
long devGpibLib_initSi(struct stringinRecord *psi, void (*process)())
long devGpibLib_initAo(struct aoRecord *pao, void (*process)())
long devGpibLib_initBo(struct boRecord *pbo; void (*process)();)
long devGpibLib_initLo(struct longoutRecord *plo, void(*process)())
long devGpibLib_initMbbo(struct mbboRecord *pmbbo, void (*process)())
long devGpibLib_initSo(struct stringinRecord *psi, void (*process)())
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.
dbProcess()
processing a record.
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)
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)
The output group are fairly simple. They format a message as specified in the parameter table and then call 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 are 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)
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)
For more information on handling SRQs see the section "The SRQ Handler."
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)
int srqPollInhibit( int linkType, /* link type (defined in link.h) */ int link, /* the link number the handler is related to */ int bug, /* the bug node address if on a bitbus link */ int gpibAddr) /* the device address the handler is for */The
srqPollInhibit()
function can be called by your startup
script. The purpose of it is to tell the GPIB driver to ignore any SRQ
interrupts that it gets from the specified device. This function is only supported for the NI1014 since the Bitbus and HiDEOS systems don't (currently)
support SRQ handling.
long reportGpib(void)The
reportGpib()
function can be called from the vxWorks shell any
time you wish to see a report of the GPIB driver configuration. (It is the
function that dbior
invokes.)
ibDebug /* Turns on debug messages from this driver */ bbibDebug /* Turns on ONLY bitbus related messages */ ibSrqDebug /* Turns on ONLY srq related debug messages */ niIrqOneShot /* Used for a one shot peek at the NI1014 DMAC */These variables may be used to turn on and off debugging information from the GPIB driver system. The value of these variables govern the verbosity of the messages. Sensitivity ranges from 0(none) to 100(so much that you will be amazed!)
ibSrqLock; /* set to 1 to stop ALL srq checking & polling */Instead of calling
srqPollInhibit()
for your devices, this flag
may be set to inhibit all SRQ processing. It is highly
recommended that you set this if you are not going to be processing any of
the SRQs.
Despite the nastiness of the NI1014 board and its driver, it is supported as a plug and play device by the GPIB driver. In order to access it, your database(s) must have records with link fields that are initialized to use the the GPIB_IO link type entries in your devSup.ascii file(s).
Since the Bitbus system does not (currently) support SRQ processing, the SRQ inhibit functions and flags are not supported on Bitbus links.
int HiDEOSGpibLinkConfig(int link, int BoardId, char *TaskName)The
link
field MUST be set to a number greater than the
last valid NI1014 link number. This is specified in the module_types.h file
by the variable NIGPIB_NUM_LINKS
and has a default value of 4.
It is recommend that you only use link numbers greater than 10 for HiDEOS
links. There is no hard limit to the number of HiDEOS links you may have, but
since this field is an int
, you will have to keep your link
numbers under 2 billion or so ;-)
The BoardId
field must be set to the HiDEOS board ID number.
See the HiDEOS system documentation for details.
The TaskName
field must be set to the name of the peer task on the
HiDEOS system that controls the IP488 GPIB board you wish the link to use.
The task names are generated by HiDEOS based on the slot that the IP488
board is in. These task names will always be a-ip488, b-ip488,
c-ip488,
or d-ip488
. Again, see the HiDEOS system
documentation for details.
Since the HiDEOS system does not (currently) support SRQ processing, the SRQ inhibit functions and flags are not supported on HiDEOS links.
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.