In addition to a record support module, each record type can have an arbitrary number of device support modules. The purpose of device support is to hide hardware speciﬁc details from record processing routines. Thus support can be developed for a new device without changing the record support routines.
A device support routine has knowledge of the record deﬁnition. It also knows how to talk to the hardware directly or how to call a device driver which interfaces to the hardware. Thus device support routines are the interface between hardware speciﬁc ﬁelds in a database record and device drivers or the hardware itself.
Release 3.14.8 introduced the concept of extended device support, which provides an optional interface that a device support can implement to obtain notiﬁcation when a record’s address is changed at runtime. This permits records to be reconnected to a diﬀerent kind of I/O device, or just to a diﬀerent signal on the same device. Extended device support is described in more detail in Section 12.5 below.
Database common contains two device related ﬁelds:
The ﬁeld DTYP contains the index of the menu choice as deﬁned by the device ASCII deﬁnitions. iocInit uses this ﬁeld and the device support structures deﬁned in devSup.h to initialize the ﬁeld DSET. Thus record support can locate its associated device support via the DSET ﬁeld.
Device support modules can be divided into two basic classes: synchronous and asynchronous. Synchronous device support is used for hardware that can be accessed without delays for I/O. Many register based devices are synchronous devices. Other devices, for example all GPIB devices, can only be accessed via I/O requests that may take large amounts of time to complete. Such devices must have associated asynchronous device support. Asynchronous device support makes it more diﬃcult to create databases that have linked records.
If a device can be accessed with a delay of less then a few microseconds then synchronous device support is appropriate. If a device causes delays of greater than 100 microseconds then asynchronous device support is appropriate. If the delay is between these values your guess about what to do is as good as mine. Perhaps you should ask the hardware designer why such a device was created.
If a device takes a long time to accept requests there is another option than asynchronous device support. A driver can be created that periodically polls all its attached input devices. The device support just returns the latest polled value. For outputs, device support just notiﬁes the driver that a new value must be written. the driver, during one of its polling phases, writes the new value. The EPICS Allen Bradley device/driver support is a good example.
The example is devAiSoft, which supports soft analog inputs. The INP ﬁeld can be a constant or a database link or a channel access link. Only two routines are provided (the rest are declared NULL). The init_record routine ﬁrst checks that the link type is valid. If the link is a constant it initializes VAL. If the link is a Process Variable link it calls dbCaGetLink to turn it into a Channel Access link. The read_ai routine obtains an input value if the link is a database or Channel Access link, otherwise it doesn’t have to do anything.
This example shows how to write an asynchronous device support routine. It does the following sequence of operations:
At this point the record has been completely processed. The next time process is called everything starts all over.
Note that this is somewhat of an artiﬁcial example since real code of this form would more likely use the callbackcallbackRequestProcessCallbackDelayed function to perform the required processing.
This section describes the routines deﬁned in the DSET. Any routine that does not apply to a speciﬁc record type must be declared NULL.
This routine is responsible for reporting all I/O cards it has found. The interest value is provided to allow for diﬀerent kinds of reports, or to control how much detail to display. If a device support module is using a driver, it may choose not to implement this routine because the driver generates the report.
This routine is called twice at IOC initialization time. Any action is device speciﬁc. This routine is called twice: once before any database records are initialized, and once after all records are initialized but before the scan tasks are started. after has the value 0 before and 1 after record initialization.
The record support init_record routine calls this routine.
This is called by the I/O interrupt scan task. If cmd is (0,1) then this routine is being called when the associated record is being (placed in, taken out of) an I/O scan list. See chapter 17 for details.
All other device support routines are record type speciﬁc.
This section describes the additional behaviour and routines required for a device support layer to support online changes to a record’s hardware address.
In releases prior to R3.14.8 it is possible to change the value of the INP or OUT ﬁeld of a record but (unless a soft device support is in use) this generally has no eﬀect on the behaviour of the device support at all. Some device supports have been written that check this hardware address ﬁeld for changes every time they process, but they are in the minority and in any case they do not provide any means to switch between diﬀerent device support layers at runtime since no software is present that can lookup a new value for the DSET ﬁeld after iocInit.
The extended device interface has been carefully designed to retain maximal backwards compatibility with existing device and record support layers, and as a result it cannot just introduce new routines into the DSET:
Since both basic and extended device support layers have to co-exist within the same IOC, some rules are enforced concerning whether the device address of a particular record is allowed to be changed:
If an address change is refused, the change to the INP or OUT ﬁeld will cause an error or exception to be passed to the software performing the change. If this was a Channel Access client the result is to generate an exception callback.
To switch to a diﬀerent device support layer, it is necessary to change the DTYP ﬁeld before the INP or OUT ﬁeld. The change to the DTYP ﬁeld has no eﬀect until the latter ﬁeld change takes place.
If a record is set to I/O Interrupt scan but the new layer does not support this, the scan will be changed to Passive.
Device support that implements the extended behaviour must provide an init routine in the Device Support Entry Table (see Section 12.4.2). In the ﬁrst call to this routine (pass 0) it registers the address of its Device Support eXtension Table (DSXT) in a call to devExtend.
The only exception to this registration requirement is when the device support uses a link type of CONSTANT. In this circumstance the system will automatically register an empty DSXT for that particular support layer (both the add_record and del_record routines pointed to by this DSXT do nothing and return zero). This exception allows existing soft channel device support layers to continue to work without requiring any modiﬁcation, since the iocCore software already takes care of changes to PV_LINK addresses.
The following is an example of a DSXT and the initialization routine that registers it:
A call to devExtend can only be made during the ﬁrst pass of the device support initialization process, and registers the DSXT for that device support layer. If called at any other time it will log an error message and immediately return.
The full deﬁnition of struct dsxt is found in devSup.h and currently looks like this:
There may be future additions to this table to support additional functionality; such extensions may only be made by changing the devSup.h header ﬁle and rebuilding EPICS Base and all support modules, thus neither record types nor device support are permitted to make any private use of this table.
The two function pointers are the means by which the extended device support is notiﬁed about the record instances it is being given or that are being moved away from its control. In both cases the only parameter is a pointer to the record concerned, which the code will have to cast to the appropriate pointer for the record type. The return value from the routines should be zero for success, or an EPICS error status code.
This function is called to oﬀer a new record to the device support. It is also called during iocInit, in between the pass 0 and pass 1 calls to the regular device support init_record routine (described in Section 12.4.3 above). When converting an existing device support layer, this routine will usually be very similar to the old init_record routine, although in some cases it may be necessary to do a little more work depending on the particular record type involved. The extra code required in these cases can generally be copied straight from the record type implementation itself. This is necessary because the record type has no knowledge of the address change that is taking place, so the device support must perform any bitmask generation and/or readback value conversions itself. This document does not attempt to describe all the necessary processing for the various diﬀerent standard record types, although the following (incomplete) list is presented as an aid to device support authors:
If the add_record routine discovers any errors, say in the link address, it should return a non-zero error status value to reject the record. This will cause the record’s PACT ﬁeld to be set, preventing any further processing of this record until some other address change to it gets accepted.
This function is called to notify the device support of a request to change the hardware address of a record, and allow the device support to free up any resources it may have dedicated to this particular record.
Before this routine is called, the record will have had its SCAN ﬁeld changed to Passive if it had been set to I/O Interrupt. This ensures that the device support’s get_ioint_info routine is never called after the the call to del_record has returned successfully, although it may also lead to the possibility of missed interrupts if the address change is rejected by the del_record routine.
If the device support is unable to disconnect from the hardware for some reason, this routine should return a non-zero error status value, which will prevent the hardware address from being changed. In this event the SCAN ﬁeld will be restored if it was originally set to I/O Interrupt.
After a successfull call to del_record, the record’s DPVT ﬁeld is set to NULL and PACT is cleared, ready for use by the new device support.
The init_record routine from the DSET (section 12.4.3) is called by the record type, and must still be provided since the record type’s per-record initialization is run some time after the initial call to the DSXT’s add_record routine. Most record types perform some initialization of record ﬁelds at this point, and an extended device support layer may have to ﬁx anything that the record overwrites. The following (incomplete) list is presented as an aid to device support authors: