Difference between revisions of "V4 Link Support Tutorial"

From EPICSWIKI
 
(7 intermediate revisions by the same user not shown)
Line 1: Line 1:
EPICS: IOC Link Support Tutorial Sept 30 2005
V4 Link Support Tutorial - November 03 2005


----
----
= Overview =
= Overview =


The V4 link support is a replacement for V3  
The V4 link/struct support is a replacement for V3  
# DBF_DEVICE, DBF_INLINK, DBF_OUTLINK, and DBF_FWDLINK
# DBF_DEVICE, DBF_INLINK, DBF_OUTLINK, and DBF_FWDLINK
# device DBD definition and device support
# device DBD definition and device support
# driver DBD definition and driver support
# driver DBD definition and driver support


The link support model is:
Each link and struct field in a record can have associated support.
* For each link, record support defines a list of interfaces it can use for communicating with link support
* record support communicates with support via interfaces
* Link support defines the set of interfaces it implements
* link or struct support implements interfaces
** link or struct support registers the interfaces it implements
** record support looks for interfaces it uses
*** it uses only the interfaces it finds
*** if no interfaces are found it reports an error


Link support has no knowledge of what record types are using it
Support has no knowledge of what record types are using it.
and record support has no knowledge about link support other than the
Struct support may have knowledge of the struct field
but not of the record type.
recordSupport has no knowledge about support other than the
interface it is using.
interface it is using.


EPICS base defines a standard set of interfaces for link support.
For the rest of this document recordSupport means record support and support,
The intention is that the set includes enough functionality such that
unless qualified, means link or struct support.
 
EPICS base defines a standard set of interfaces for support,
which includes enough functionality such that
most link support can be implemented via just these interfaces.
most link support can be implemented via just these interfaces.


The interfaces support all the functionality needed by Channel/Database access
Base provides struct support for the following:
and by the generic EPICS device support supplied by asynDriver.
* RecordCommon - used by all record types in base
* LinearConvert - can be used by any analog type record
* others TBD
 
Base provides channel/database access link support for primitive,
string, and array fields.
The link interfaces provided by base are also used by asynDriver.
Since asynDriver is intended as a framework for interfacing to most hardware,
Since asynDriver is intended as a framework for interfacing to most hardware,
this means that the interfaces supplied and used by base allows support
this means that the interfaces supplied and used by base allows support
for most hardware. The support can communicate with the hardware
for most hardware. The support can communicate with the hardware
however it wants but must implement some set of the interfaces defined
anyway it wants but must implement some set of the interfaces defined
by base.
by base.


This document gives a brief overview of the V4 link support model.
This document gives a brief overview of the V4 link/struct support model.


----
----
<center>
<center>
=  Database Definitions For Links =
=  Database Definitions For links and structures =
  </center>
  </center>


Line 42: Line 57:


A record link has the syntax:
A record link has the syntax:
     link(linkDirection,interface(interfaceName,...))
     field(name,link)
A link itself has the syntax:
A record struct has the syntax
     link(linkDirection,choiceName,dataStructName,interface(interfaceName,...))
    field(name,struct(structName))
 
Support for a struct or link has the syntax
where
     support(choiceName) // no SupportStruct
 
    support(choiceName,SupportStruct)
; <tt>linkDirection</tt>
A record instance link has the syntax
: Must be one of <tt>none</tt>,<tt>in</tt>,<tt>out</tt>,<tt>process</tt>, or <tt>inout</tt>. Compatible checks are made to match the interface with a field.
    field = support(choiceName) SupportStruct{structAssignmentList}
A record instance struct has the the syntax
    field = StructName{structAssignmentList} // no support
    field = support(choiceName)
            StructName{structAssignmentList} // support has no SupportStruct
    field = support(choiceName) SupportStruct{structAssignmentList}
            StructName{structAssignmentList}


; <tt>interface</tt>
; <tt>structName</tt>
: This is a list of the interfaces that the record support understands.
: The name of a <tt>struct</tt>
; <tt>choiceName</tt>
; <tt>choiceName</tt>
: UTF-8 string that describes the choice
: UTF-8 string that describes the choice. Each support must have a unique name.
; <tt>StructName</tt>
: The same name that appears in the field definition of the record.
; <tt>SupportStruct</tt>
: The name of a <tt>struct</tt> containing configuration information for the support. recordSupport normally does not access this structure. Database configuration tools prompt the user to assign values to the structure.


; <tt>interfaceName</tt>
Assume the following definitions:
: The name of an interface via which record support communicates with device support.
    record(AiRecord) {
 
        ...
; <tt>dataStructName</tt>
        field(in,link)
: The name of a <tt>struct</tt> containing configuration information for the link support. Record support normally does not access this structure. Database configuration tools do prompt the user to assign values to the structure.
        ...
 
    }
When a record instance is created the choiceName and interfaceName select
    ...
the support to attach to a record link.
     struct(MonitorLink) {
The interfaceName must be one of the interface names the record
         field(pvname,string)
has listed as a valid type and linkDirection must be compatible
with the linkDirection the record type specified.
 
== Standard Definitions For Channel/Database Access ==
 
These are the database definitions defined in dbCommon are used by
the base supplied support for Channel/Database access.
 
=== Data Structures ===
 
The complete set of definitions are defined in "V4 DB RecordCommon".
     struct(MonitorLinkData) {
         field(pvname,string) { link}
         field(process,boolean) // process this record when monitor occurs
         field(process,boolean) // process this record when monitor occurs
         field(inheritSeverity,boolean)
         field(inheritSeverity,boolean)
     }
     }
     struct(InputLinkData) {
     struct(InputLink) {
         field(pvname,string) { link}
         field(pvname,string)
         field(process,boolean)
         field(process,boolean)
         field(wait,boolean)
         field(wait,boolean)
         field(timeout,float64)
         field(timeout,float64)
        field(block,boolean)
         field(inheritSeverity,boolean)
         field(inheritSeverity,boolean)
     }
     }
     ... also OutputLinkData and ProcessLinkData
     ...
    support(monitorLink,MonitorLink)
    support(inputLink,InputLink)
    struct VME{
        field(a16,int16)
        field(a32,int32)
        field(channel,int16)
    }
    ...
    support(someVmeADC,VME)


A look at the fields shows that these are what is required to implement
The first example instance definition selects a monitor link.
the V4 semantics for Channel/Database access links.
    AiRecord aiMonitorExample = {
        ...
        in = {
                  support(monitorLink) MonitorLink {   
                        pvname = "someRecord";
                        process = true;
                        inheritSeverity = false
                  }
              }
The next example selects a channel access input link.
    AiRecord aiInputExample = {
        ...
        in = {
                  support(inputLink) InputLink {   
                        pvname = "someRecord";
                        process = true;
                        wait = true;
                        timeout = 1.0;
                        inheritSeverity = false
                  }
              }
The last example selects support for a VME Analog to Digital device.
    AiRecord aiMonitorExample = {
        ...
        in = {support(someVmeADC) VME {a16 = 0xc000; channel = 1} }
 
== Standard Definitions For Channel/Database Access ==


=== Link Definitions ===
menuStructBase.dbd defines definitions for Channel/Database Access Links.
The base supplied support registers each choiceName in the support definitions.
The complete set of data structure and support definitions are defined
in "V4 DB RecordCommon".


Link support is provided for
Link support is provided for
* process
* monitor
* input
* input
** monitor support
** input support
* output
* output
* process


For input and output The following data types are supported:
For monitor, input, and output the following data types are supported:
* primitive types
* primitive types
* string
* string
* arrays of primitive types and strings
* arrays of primitive types and strings
"V4 DB RecordCommon" describes the complete set of link definitions
supplied by EPICS base. These are:
    link(process,processLink,ProcessLinkData,interface(ProcessLink))
    link(in,monitorLink,MonitorLinkData interface(
        LinkBoolean,
        LinkInt16,LinkInt32,LinkInt64,
        LinkFloat32,LinkFloat64,
        LinkString
    ))
    link(in,monitorLinkArray,MonitorLinkData interface(
        LinkArrayOctet,LinkArrayBoolean,
        LinkArrayInt16,LinkArrayInt32,LinkArrayInt64,
        LinkArrayFloat32,LinkArrayFloat64,
        LinkArrayString
    ))
    link(in,inputLink,InputLinkData interface(
        LinkBoolean,
        LinkInt16,LinkInt32,LinkInt64,
        LinkFloat32,LinkFloat64,
        LinkString
    ))
    link(in,inputLinkArray,InputLinkData interface(
        LinkArrayOctet,LinkArrayBoolean,
        LinkArrayInt16,LinkArrayInt32,LinkArrayInt64,
        LinkArrayFloat32,LinkArrayFloat64,
        LinkArrayString
    ))
    link(in,outputLink,OutputLinkData interface(
        LinkBoolean,
        LinkInt16,LinkInt32,LinkInt64,
        LinkFloat32,LinkFloat64,
        LinkString
    ))
    link(in,outputLinkArray,OutputLinkData interface(
        LinkArrayOctet,LinkArrayBoolean,
        LinkArrayInt16,LinkArrayInt32,LinkArrayInt64,
        LinkArrayFloat32,LinkArrayFloat64,
        LinkArrayString
    ))
These are the link definitions for the Channel/Database access link
support supplied with base. The support registers support for processLink,
monitorLinkArrayOctet, ...


== asynDriver link support ==
== asynDriver link support ==
Line 162: Line 164:


=== Data Definitions ===
=== Data Definitions ===
     struct(AsynLinkData) {
     struct(AsynLink) {
         field(portName,string)
         field(portName,string)
         field(addr,int32)
         field(addr,int32)
Line 169: Line 171:
     }
     }


=== link definitions ===
=== support definitions ===


     link(inout,asynInt32,AsynLinkData,interface(LinkInt32))
     support(asynInt32,AsynLink)
     link(in,asynInt32Average,AsynLinkData,interface(LinkInt32))
     support(asynInt32Average,AsynLink)
     link(in,asynInt32Monitor,AsynLinkData,interface(LinkInt32))
     support(asynInt32Monitor,AsynLink)
     link(inout,asynFloat64,AsynLinkData,interface(LinkFloat64))
     support(asynFloat64,AsynLink)
     link(in,asynFloat64Average,AsynLinkData,interface(LinkFloat64))
     support(asynFloat64Average,AsynLink)
     link(in,asynFloat64Monitor,AsynLinkData,interface(LinkFloat64))
     support(asynFloat64Monitor,AsynLink)
     link(in,asynDigitalMonitor,AsynLinkData,interface(AsynDigital))
     support(asynDigitalMonitor,AsynLink)
     link(inout,asynDigital,AsynLinkData,interface(AsynDigital)))
     support(asynDigital,AsynLink)
     link(inout,asynInt32Array,AsynLinkData,interface(LinkArrayInt32)))
     support(asynInt32Array,AsynLink)
     link(inout,asynFloat64Array,AsynLinkData,interface(LinkArrayFloat64)))
     support(asynFloat64Array,AsynLink)
     link(inout,asynOctet,AsynLinkData,interface(AsynOctet)))
     support(asynOctet,AsynLink)


This is the set of definitions for the standard EPICS device support implemented
This is the set of definitions for the standard EPICS device support implemented
by asynDriver. Although, at least for the first few V4 releases,
by asynDriver. At least for the first few V4 releases,
asynDriver will not be part of base, they are shown here because the
asynDriver will not be part of base.
LinkInt32,... interface definitions are defined as part of base.
Again it is expected that almost all hardware support be created by
implementing a combination of these link interface definitions or
the interfaces implemented by Channel/Database access link support.
---
---
<center>
<center>
Link Support =
interfaces for link and struct support =
  </center>
  </center>


== Overview ==
Support can be provided for link and struct fields.
An arbitrary number of Link Support implementations can exist.
An arbitrary number of Support implementations can exist.
An implementation can be either soft support or support that communicates with
An implementation can be either soft support or support that communicates with
hardware.
hardware.


Other link support can also be supplied.
The syntax for interface definitions is similar to Java syntax
New support should try very hard to implement the standard interfaces
since it is more concise than C++.
supplied by EPICS base. These are the interfaces that the record types
It can easily be translated to C++ syntax. For example the
supplied with base know how to use.
definition:
    interface LinkInt16 {
        LinkResult get(Callback callback,Int16 data);
        LinkResult put(Callback callback,int16 data);
        boolean getBounds(Int16 low, Int16 high);
    }
In C++ would be:
    class LinkInt16 {
    public:
        virtual LinkResult get(Callback &callback, int16_t &data) = 0;
        virtual LinkResult put(Callback &callback, int16_t data) = 0;
        virtual bool getBounds(int16_t &low, int16_t &high) = 0;
    };


Soft support should try to implement the same interfaces implemented by
<b>NOTE:</b> Int16 becomes int16_t &data and int16 data becomes int16_t data.
the Channel/Database access support supplied with base. The support
can, of course, define data structures for it's own use.
Implementing these interfaces means that nthe support will work for
the same set of record links as the Channel/Database access support.


Hardware support should, if possible, also implement the same interfaces
Support and SupportMonitor are interfaces that are common to
implemented by the Channel/Database access support.
the support for both link and struct fields.
Message based support may also have to implement the AsynOctet interface
but this interface is only used by a few record links.


 
<b>NOTE: arguments and return types ignored for now</b>
This section describes the interfaces implemented by all link support
     interface Support {
and then the standard interfaces used by the records supplied with base.
 
== Link and MonitorLink ==
 
     interface Link {
         void report(int16 level);
         void report(int16 level);
        void cancel();
         void destroy();
         void destroy();
         void initialize();
         void initialize(int16 pass);
         void connect();
         void connect();
         void disconnect();
         void disconnect();
        void cancel();
     }
     }


     interface MonitorLink {
     interface SupportMonitor {
         void addMonitor(Callback callback);
         void addMonitor(Callback callback);
         void removeMonitor();
         void removeMonitor();
     }
     }


<tt>Link</tt> is an interface that must be implemented by every link
<tt>Support</tt> is an interface that must be implemented by every  
support.
support module.
An instance of this is connected to each DbfLink field.
<tt>SupportMonitor</tt> is an interface that is implemented by support that
The <tt>Link</tt> methods are:
* <tt>report</tt> - report
* <tt>cancel</tt> - Cancel any outstanding I/O
* <tt>destroy</tt> - This is called if the field is being changed after initialization or if the record is being removed.
* <tt>initialize</tt> - Called to initialize a link.
* <tt>connect</tt> - Called to connect. Note that this is different than initilization.
* <tt>disconnect</tt> - disconnect.
 
<tt>MonitorLink</tt> is an interface that is implemented by link support that
supports monitors. An example is support for hardware interrupts.
supports monitors. An example is support for hardware interrupts.
The <tt>MonitorLink</tt> methods are:
* <tt>addMonitor</tt> - Add a monitor callback
* <tt>removeMonitor</tt> - Remove monitor


Normally record support does not need to call any of the Link
Normally recordSupport does not need to call any of the Support
or MonitorLink methods since database access does this automatically.
or SupportMonitor methods since database access does this automatically.
For example if a link field is modified via a channel access put,
For example if a link field is modified via a channel access put,
database access will call destroy before modifying the link
database access will call destroy before modifying the link
and initialize and connect after the link is modified.
and initialize and connect after the link is modified.
 
---
Neither Link or MonitorLink is listed in the <tt>link</tt> database
<center>
definition.
=  interfaces for struct support =
 
</center>
== Definitions that apply to Process,Monitor,Input,and Output support ==
== support for RecordCommon ==
These are the definitions used by the Channel/Database access support
This implements an interface, not yet defined, that is similar to the
supplied with base. It is also used by the standard EPICS support from asyn.
interface record support implements.
 
== support for LinearConvert ==
     enum LinkWaitResult {
This implements the interface
        linkNoop,           // Nothing was done, e.g. link is null link
     interface SupportLinearConvert{
        linkDone,           // field was modified. No wait is necessary
           convert(int32 raw,Float64 value) // from raw to eng
        linkWait,           // waiting. can do additional procsssing
           convert(float64 value,Int32 raw) // from eng to raw
        linkWaitBlock,     // waiting. dont do additional processing until
     }
     }


     interface Callback {
In addition it provides a factory
         void done();
     interface FactoryLinearConvert{
        void failure();
         SupportLinearConvert(string choiceName,
    }
            DbfStruct linearConvert,DbfLink inlink)
== Process Link Support ==
    interface ProcessLinkSupport<type> {
        LinkWaitResult process(Callback callback);
     }
     }
== support for simulation ==
This needs to be defined.
== support for breakpoint tables ==
This needs to be defined.


== Octet Support ==
---
There is no support for octet but there is support for an array of octets.
<center>
= interfaces for link Support =
</center>


EPICS base defines a number of standard interfaces
that are used by the record types supplied with epics base.
These interfaces are appropriate for the soft support supplied with EPICS
base and should also be sufficient for a wide variety of hardware support.
In particular they sufficient for communication with asynDriver.


    interface LinkArrayOctet {
        LinkWaitResult getWait(octet[] data,Callback callback);
        LinkWaitResult putWait(octet[] data,Callback callback);
    }


The data source must be an array of octets or the connect request will fail.
The standard interfaces use the following definitions:


<b>GENERIC QUESTION</b> The data is passed as primitive or arrays of
     enum LinkResult {
primitive types. Should <tt>Dbf</tt> interfaces be used? Needs thought.
         linkNoop,           // Nothing was done, e.g. link is null link
 
         linkNoop,           // field was modified. No wait is necessary
 
         linkWait,           // waiting for completion
== asynOctet Support ==
 
This still needs more work. It attempts to reproduce the functionality
of V3 asynDriver.
 
     interface AsynOctet {
         LinkWaitResult write(Callback callback,
          octet[] data, int32 numchars, Int32 nbytesTransfered);
         LinkWaitResult writeRaw(Callback callback,
          octet[] data, int32 numchars, Int32 nbytesTransfered);
         LinkWaitResult read(Callback callback,
          octet[] data, Int32 nbytesTransfered);
        LinkWaitResult readRaw(Callback callback,
          octet[] data, Int32 nbytesTransfered);
        void flush();
        void setInputEos(octet[] eos);
        void getInputEos(octet[] eos);
        void setOutputEos(octet[] eos);
        void getOutputEos(octet[] eos);
     }
     }


    enum interruptReason {
     interface Callback {
        interruptOnZeroToOne, interruptOnOneToZero, interruptOnBoth
         void done();
    }
         void failure();
    struct asynDigitalInterrupt {
        octet[] mask;
        int32 addr;
        Callback callback
    }
 
    interface AsynDigital {
          LinkWaitResult write(octet[] value, octet[] mask);
          LinkWaitResult read(octet[] value, octet[] mask);
          void setInterrupt(octet[] mask, interruptReason reason);
          void clearInterrupt(octet[] mask);
          void getInterrupt(octet[] mask, interruptReason reason);
          void registerInterruptUser(interruptCallbackUInt32Digital callback,
              octet[] mask);
          void cancelInterruptUser();
    }
 
== Boolean Support ==
    interface LinkBoolean {
        LinkWaitResult getWait(Boolean data,Callback callback);
        LinkWaitResult putWait(boolean data,Callback callback);
    }
     interface LinkArrayBoolean {
        LinkWaitResult getWait(boolean[] data,Callback callback);
        LinkWaitResult putWait(boolean[] data,Callback callback);
    }
 
 
The data source must be a boolean or a string that contains a valid
boolean value.
 
== Integer Support ==
 
Support is available. for int16, int32, and int64.
This section uses the Java generic syntax, e.g. <type>. In this
section <type> must be int16, int32, or int64.
 
    interface Link<type> {
         LinkWaitResult getWait(<type> data,Callback callback);
        LinkWaitResult putWait(<type> data,Callback callback);
         void getBounds(<type> low, <type> high);
    }
    interface LinkArray<type> {
        LinkWaitResult getWait(<type>[] data,Callback callback);
        LinkWaitResult putWait(<type>[] data,Callback callback);
     }
     }


    enum interruptReason {
The complete set of interfaces are described in V4 Design: Runtime Interfaces.
        interruptOnZeroToOne, interruptOnOneToZero, interruptOnBoth
Some examples are:
    }
       
       
== Float Support ==
 
Support is available. for float32 and float64.
This section uses the Java generic syntax, e.g. <type>. In this
section <type> must be float32 or float64.


     interface Link<type> {
     interface LinkProcess {
         LinkWaitResult getWait(<type> data,Callback callback);
         LinkResult process(Callback callback);
        LinkWaitResult putWait(<type> data,Callback callback);
    }
    interface LinkArray<type> {
        LinkWaitResult getWait(<type>[] data,Callback callback);
        LinkWaitResult putWait(<type>[] data,Callback callback);
     }
     }


== String Support ==
     interface LinkInt16 {
     interface LinkString {
         LinkResult get(Callback callback,Int16 data);
         LinkWaitResult getWait(string data,Callback callback);
        LinkResult put(Callback callback,int16 data);
         LinkWaitResult putWait(string data,Callback callback);
         boolean getBounds(Int16 low, Int16 high);
     }
     }
    interface LinkArrayString {
        LinkWaitResult getWait(string[] data,Callback callback);
        LinkWaitResult putWait(string[] data,Callback callback);
    }
The data source must be a string.


<tt>LinkProcess</tt> is the interface for process link fields
and <tt>LinkInt16</tt> is the interface for int16 fields.
----
----
<center>
<center>
= Example - VME ADC support =
= Example - VME ADC support =
  </center>
  </center>
== database definitions ==
Assume the VME and support definitions given in the examples at the beginning
The following struct is defined for configuration information.
of this document.
    struct VMEADC {
        field(a16 int16)
        field(a32 int32)
        field(channel int16)
    }
The following link definition is defined:
    link(in,myAdcSupport,VMEADCinterface(LinkInt32))


This allows record instance definitions like:
    AiRecord aiExample = {
        ...
        input = myAdcSupport(LinkInt32){a16=0x0010;channel=1}
        ...
    }
== link support implementation ==
The following is presented with Java syntax.
The following is presented with Java syntax.
It assumes that there is VME support of the form
It assumes that there is VME support of the form


public class VME {
    public class vme {
    static public short getShort(long addr);
        static public short getShort(long addr);
    ...
        ...
}
    }


The link support would be something like:
The link support would be something like:


     class AdcSupport implements Link LinkInt32 {
     class AdcSupport implements Link LinkInt32 {
     AdcSupport(VMEADCData fromFactory)
     AdcSupport(VME fromFactory)
     {
     {
         data = fromFactory;
         addr = fromFactory;
         connected = false;
         connected = false;
         //  from the VMEADC initailze vmeaddr and channel
         //  from the VME initialize vmeaddr and channel
         // details left to your imagination
         // details left to your imagination
     }
     }
Line 457: Line 350:
      
      
     // LinkInt32 methods
     // LinkInt32 methods
     LinkWaitResult getWait(Int data,Callback callback)
     LinkResult get(Callback callback, Int data)
     {
     {
         data = (Int)VME.getShort(vmeaddr);
         data = (Int)VME.getShort(vmeaddr);
         return linkDone;
         return linkNoop;
     }
     }
     LinkWaitResult putWait(Int data,Callback callback)
     LinkResult put(Callback callback, int data)
     {
     {
         throw CantWriteAdc;
         throw CantWriteAdc;
Line 472: Line 365:
     }
     }
     private:
     private:
         VMEADCData data;
         VME addr;
         int vmeaddr;
         int vmeaddr;
         int channel;
         int channel;
         boolean connected;
         boolean connected;
     }
     }
----
<center>
= Additional requirements for link support =
</center>
== Overview ==
The following are two important requirements:
* analog I/O
** link support can return raw value. Support must convert to engineering units.
** link support can return engineering units
* output records
** If possible link support should provide initial value during initialization
** If output can be modified other than by record itself than the records balue should be modified without causing a new output
Lets consider each of these separately.
== Analog I/O ==
In V3 the aiRecord and aoRecords are responsible for conversion between
raw values and engineering units. Raw values are 32 bit integers. Device
support is responsible for setting the slope and intercept fields of the record.
recordSupport takes care of the actual conversions.
Device support can tell recordSupport that it set the engineering units
rather than a raw value by a different return value.
For V4 the following is done:
aiRecord and aoRecord both have the following fields:
    menu(menuConvert) {
        choice(menuConvertRaw, "None")
        choice(menuConvertLinear, "Linear")
        choice(menuConvertTable, "Table")
    }
    struct(LinearConvert) {
        field(engUnitsHigh,float64)
        field(engUnitsLow,float64)
        field(slope,float64)
        field(intercept,float64)
    }
    ...
    field(convert, menu(menuConvert))
    field(linearConvert, struct(LinearConvert))
    field(convertTable,string);
    field(units, string)
<b>NOTE</b> This section is written as though record support itself does
the conversions. Most record support would call the standard support
for LinearConvert.
If a record instance has convert set to None then recordSupport does the following.
* if link support implements LinkFloat64 it just calls this to obtain an engineering units value
* otherwise it gets a value via interface LinkInt32 and converts the value from in int32 to a float64.
If a record instance has convert linear
* if link support implements LinkInt32 it uses LinkInt32 otherwise it uses LinkFloat64
* it uses slope and interccept to convert from raw to engineering units
<tt>LinkInt32</tt> is defined as:
    interface LinkInt32 {
        LinkResult get(Callback callback,Int32 data);
        LinkResult put(Callback callback,Int32 data);
        boolean getBounds(Int32 low, Int32 high);
    }
If convert is linear and getBounds returns true than recordSupport
uses the returned value to compute slope and intercept. In all
other cases recordSupport just uses whatever values they have.
For example support for a 16 bit unipolar ADC would set low=0, high=65535,
and return true.
If link support can not determine the bounds then getBounds returns false.
<b>NOTE:</b>The interface implemented by breakpoint tables must be defined.
It will support the same semantics as the V3 breakpoint tables.
== Output Records ==
The following are two features that link support should implement
whenever possible:
# When a record is initalized provide the current value of the output
# If the actual output is changed by something other than the output record than the output record should also be modified to reflect the new output value.
The first feature is especially desirable when an IOC is rebooted.
If a hardware output can survive a reboot this is a very desirable feature.
If the output is to a field bus, a PLC, or to a record in another IOC
it is often possible for the link support to determine the current value.
The second feature is something that was often asked for in V3 but
only implemented
for some special cases. This is especially desirable when the output is
connected to a system that can have multiple sources of control.
Examples are GPIB devices with front pannel controls, PLC systems that
have manual controls or non-epics network access.
For V3 some of the hardware , but none of the soft,
support implemented the first feature but by
modifying actual fields in the record. V3 did not implement the second
feature. Some special device support, not part of base, was implemented
to support this feature.
For V4 these features are supported as follows:
=== record initialization ===
The link support implements an interface that has a put and a get method.
For example:
    interface LinkInt32 {
        LinkResult get(Callback callback,Int32 data);
        LinkResult put(Callback callback,Int32 data);
        boolean getBounds(Int32 low, Int32 high);
    }
If the link support can support readbacks then it implements get
and returns linkNoop. If it does not support readbacks
then it implements get by just returning linkNoop.
=== monitors for outputs ===
If output link support can detect when something besides the link support
itself modifies the output then it implements interface <tt>MonitorLink</tt>
    interface SupportMonitor {
        void addMonitor(Callback callback);
        void removeMonitor();
    }
At initialization recordSupport looks for this interface and if found
it calls <tt>addMonitor</tt>. The link support calls the callback whenever
it detects a change in the output that it did not cause. recordSupport
causes itself to be processed without making a new call to the
link support.
---

Latest revision as of 19:46, 3 November 2005

V4 Link Support Tutorial - November 03 2005


Overview

The V4 link/struct support is a replacement for V3

  1. DBF_DEVICE, DBF_INLINK, DBF_OUTLINK, and DBF_FWDLINK
  2. device DBD definition and device support
  3. driver DBD definition and driver support

Each link and struct field in a record can have associated support.

  • record support communicates with support via interfaces
  • link or struct support implements interfaces
    • link or struct support registers the interfaces it implements
    • record support looks for interfaces it uses
      • it uses only the interfaces it finds
      • if no interfaces are found it reports an error

Support has no knowledge of what record types are using it. Struct support may have knowledge of the struct field but not of the record type. recordSupport has no knowledge about support other than the interface it is using.

For the rest of this document recordSupport means record support and support, unless qualified, means link or struct support.

EPICS base defines a standard set of interfaces for support, which includes enough functionality such that most link support can be implemented via just these interfaces.

Base provides struct support for the following:

  • RecordCommon - used by all record types in base
  • LinearConvert - can be used by any analog type record
  • others TBD

Base provides channel/database access link support for primitive, string, and array fields. The link interfaces provided by base are also used by asynDriver. Since asynDriver is intended as a framework for interfacing to most hardware, this means that the interfaces supplied and used by base allows support for most hardware. The support can communicate with the hardware anyway it wants but must implement some set of the interfaces defined by base.

This document gives a brief overview of the V4 link/struct support model.


Database Definitions For links and structures

This section first reviews the DBD syntax related to link definitions. It then gives a brief description of link related definitions in dbCommon.dbd

Syntax

A record link has the syntax:

    field(name,link)

A record struct has the syntax

    field(name,struct(structName))

Support for a struct or link has the syntax

    support(choiceName) // no SupportStruct
    support(choiceName,SupportStruct)

A record instance link has the syntax

   field = support(choiceName) SupportStruct{structAssignmentList}

A record instance struct has the the syntax

   field = StructName{structAssignmentList} // no support
   field = support(choiceName)
           StructName{structAssignmentList} // support has no SupportStruct
   field = support(choiceName) SupportStruct{structAssignmentList}
           StructName{structAssignmentList}
structName
The name of a struct
choiceName
UTF-8 string that describes the choice. Each support must have a unique name.
StructName
The same name that appears in the field definition of the record.
SupportStruct
The name of a struct containing configuration information for the support. recordSupport normally does not access this structure. Database configuration tools prompt the user to assign values to the structure.

Assume the following definitions:

    record(AiRecord) {
        ...
        field(in,link)
        ...
    }
    ...
    struct(MonitorLink) {
        field(pvname,string)
        field(process,boolean) // process this record when monitor occurs
        field(inheritSeverity,boolean)
    }
    struct(InputLink) {
        field(pvname,string)
        field(process,boolean)
        field(wait,boolean)
        field(timeout,float64)
        field(inheritSeverity,boolean)
    }
    ...
    support(monitorLink,MonitorLink)
    support(inputLink,InputLink)
    struct VME{
        field(a16,int16) 
        field(a32,int32)
        field(channel,int16)
    }
    ...
    support(someVmeADC,VME)

The first example instance definition selects a monitor link.

    AiRecord aiMonitorExample = {
        ...
        in = {
                  support(monitorLink) MonitorLink {    
                       pvname = "someRecord";
                       process = true;
                       inheritSeverity = false
                  }
              }

The next example selects a channel access input link.

    AiRecord aiInputExample = {
        ...
        in = {
                  support(inputLink) InputLink {    
                       pvname = "someRecord";
                       process = true;
                       wait = true;
                       timeout = 1.0;
                       inheritSeverity = false
                  }
              }

The last example selects support for a VME Analog to Digital device.

    AiRecord aiMonitorExample = {
        ...
        in = {support(someVmeADC) VME {a16 = 0xc000; channel = 1} }

Standard Definitions For Channel/Database Access

menuStructBase.dbd defines definitions for Channel/Database Access Links. The base supplied support registers each choiceName in the support definitions. The complete set of data structure and support definitions are defined in "V4 DB RecordCommon".

Link support is provided for

  • process
  • monitor
  • input
  • output

For monitor, input, and output the following data types are supported:

  • primitive types
  • string
  • arrays of primitive types and strings

asynDriver link support

These are definitions that are used by the standard EPICS device support for asynDriver. Since asynDriver is a generic way of interfacing arbitrary hardware support, this is a generic way of attaching links in records to hardware.

Data Definitions

    struct(AsynLink) {
        field(portName,string)
        field(addr,int32)
        field(timeout,float64)
        field(drvPvt,string)
    }

support definitions

    support(asynInt32,AsynLink)
    support(asynInt32Average,AsynLink)
    support(asynInt32Monitor,AsynLink)
    support(asynFloat64,AsynLink)
    support(asynFloat64Average,AsynLink)
    support(asynFloat64Monitor,AsynLink)
    support(asynDigitalMonitor,AsynLink)
    support(asynDigital,AsynLink)
    support(asynInt32Array,AsynLink)
    support(asynFloat64Array,AsynLink)
    support(asynOctet,AsynLink)

This is the set of definitions for the standard EPICS device support implemented by asynDriver. At least for the first few V4 releases, asynDriver will not be part of base. ---

interfaces for link and struct support

Support can be provided for link and struct fields. An arbitrary number of Support implementations can exist. An implementation can be either soft support or support that communicates with hardware.

The syntax for interface definitions is similar to Java syntax since it is more concise than C++. It can easily be translated to C++ syntax. For example the definition:

    interface LinkInt16 {
        LinkResult get(Callback callback,Int16 data);
        LinkResult put(Callback callback,int16 data);
        boolean getBounds(Int16 low, Int16 high);
    }

In C++ would be:

    class LinkInt16 {
    public:
        virtual LinkResult get(Callback &callback, int16_t &data) = 0;
        virtual LinkResult put(Callback &callback, int16_t data) = 0;
        virtual bool getBounds(int16_t &low, int16_t &high) = 0;
    };

NOTE: Int16 becomes int16_t &data and int16 data becomes int16_t data.

Support and SupportMonitor are interfaces that are common to the support for both link and struct fields.

NOTE: arguments and return types ignored for now

    interface Support {
        void report(int16 level);
        void destroy();
        void initialize(int16 pass);
        void connect();
        void disconnect();
        void cancel();
    }
    interface SupportMonitor {
        void addMonitor(Callback callback);
        void removeMonitor();
    }

Support is an interface that must be implemented by every support module. SupportMonitor is an interface that is implemented by support that supports monitors. An example is support for hardware interrupts.

Normally recordSupport does not need to call any of the Support or SupportMonitor methods since database access does this automatically. For example if a link field is modified via a channel access put, database access will call destroy before modifying the link and initialize and connect after the link is modified. ---

interfaces for struct support

support for RecordCommon

This implements an interface, not yet defined, that is similar to the interface record support implements.

support for LinearConvert

This implements the interface

    interface SupportLinearConvert{
         convert(int32 raw,Float64 value) // from raw to eng
         convert(float64 value,Int32 raw) // from eng to raw
    }

In addition it provides a factory

    interface FactoryLinearConvert{
        SupportLinearConvert(string choiceName,
            DbfStruct linearConvert,DbfLink inlink)
    }

support for simulation

This needs to be defined.

support for breakpoint tables

This needs to be defined.

---

interfaces for link Support

EPICS base defines a number of standard interfaces that are used by the record types supplied with epics base. These interfaces are appropriate for the soft support supplied with EPICS base and should also be sufficient for a wide variety of hardware support. In particular they sufficient for communication with asynDriver.


The standard interfaces use the following definitions:

    enum LinkResult {
        linkNoop,           // Nothing was done, e.g. link is null link
        linkNoop,           // field was modified. No wait is necessary
        linkWait,           // waiting for completion 
    }
    interface Callback {
        void done();
        void failure();
    }

The complete set of interfaces are described in V4 Design: Runtime Interfaces. Some examples are:

    interface LinkProcess {
        LinkResult process(Callback callback);
    }
    interface LinkInt16 {
        LinkResult get(Callback callback,Int16 data);
        LinkResult put(Callback callback,int16 data);
        boolean getBounds(Int16 low, Int16 high);
    }

LinkProcess is the interface for process link fields and LinkInt16 is the interface for int16 fields.


Example - VME ADC support

Assume the VME and support definitions given in the examples at the beginning of this document.

The following is presented with Java syntax. It assumes that there is VME support of the form

    public class vme {
        static public short getShort(long addr);
        ...
    }

The link support would be something like:

    class AdcSupport implements Link LinkInt32 {
    AdcSupport(VME fromFactory)
    {
        addr = fromFactory;
        connected = false;
        //  from the VME initialize vmeaddr and channel
        // details left to your imagination
    }
    // Link methods
    void report(int16_t level)
    {
        printf("AdcSupport a16 %x channel %d\n",a16,channel);
    }
    void cancel() {} // nothing to do
    void destroy() {} //nothing to do
    void initialize()
    {
        // make sure we can access a16
    }
    void connect() {connected = true}
    void disconnect() {connected = false}
    
    // LinkInt32 methods
    LinkResult get(Callback callback, Int data)
    {
        data = (Int)VME.getShort(vmeaddr);
        return linkNoop;
    }
    LinkResult put(Callback callback, int data)
    {
        throw CantWriteAdc;
    }
    void getBounds(Int low, Int high) 
    {
        // assume 16 bit unipolor adc
        low = 0; high = 0xffff;
    }
    private:
        VME addr;
        int vmeaddr;
        int channel;
        boolean connected;
    }

Additional requirements for link support

Overview

The following are two important requirements:

  • analog I/O
    • link support can return raw value. Support must convert to engineering units.
    • link support can return engineering units
  • output records
    • If possible link support should provide initial value during initialization
    • If output can be modified other than by record itself than the records balue should be modified without causing a new output

Lets consider each of these separately.

Analog I/O

In V3 the aiRecord and aoRecords are responsible for conversion between raw values and engineering units. Raw values are 32 bit integers. Device support is responsible for setting the slope and intercept fields of the record. recordSupport takes care of the actual conversions. Device support can tell recordSupport that it set the engineering units rather than a raw value by a different return value.

For V4 the following is done:

aiRecord and aoRecord both have the following fields:

    menu(menuConvert) {
        choice(menuConvertRaw, "None")
        choice(menuConvertLinear, "Linear")
        choice(menuConvertTable, "Table")
    }
    struct(LinearConvert) {
        field(engUnitsHigh,float64)
        field(engUnitsLow,float64)
        field(slope,float64)
        field(intercept,float64)
    }


    ...
    field(convert, menu(menuConvert))
    field(linearConvert, struct(LinearConvert))
    field(convertTable,string);
    field(units, string)

NOTE This section is written as though record support itself does the conversions. Most record support would call the standard support for LinearConvert.


If a record instance has convert set to None then recordSupport does the following.

  • if link support implements LinkFloat64 it just calls this to obtain an engineering units value
  • otherwise it gets a value via interface LinkInt32 and converts the value from in int32 to a float64.

If a record instance has convert linear

  • if link support implements LinkInt32 it uses LinkInt32 otherwise it uses LinkFloat64
  • it uses slope and interccept to convert from raw to engineering units


LinkInt32 is defined as:

    interface LinkInt32 {
        LinkResult get(Callback callback,Int32 data);
        LinkResult put(Callback callback,Int32 data);
        boolean getBounds(Int32 low, Int32 high);
    }

If convert is linear and getBounds returns true than recordSupport uses the returned value to compute slope and intercept. In all other cases recordSupport just uses whatever values they have.

For example support for a 16 bit unipolar ADC would set low=0, high=65535, and return true. If link support can not determine the bounds then getBounds returns false.


NOTE:The interface implemented by breakpoint tables must be defined. It will support the same semantics as the V3 breakpoint tables.

Output Records

The following are two features that link support should implement whenever possible:

  1. When a record is initalized provide the current value of the output
  2. If the actual output is changed by something other than the output record than the output record should also be modified to reflect the new output value.

The first feature is especially desirable when an IOC is rebooted. If a hardware output can survive a reboot this is a very desirable feature. If the output is to a field bus, a PLC, or to a record in another IOC it is often possible for the link support to determine the current value.

The second feature is something that was often asked for in V3 but only implemented for some special cases. This is especially desirable when the output is connected to a system that can have multiple sources of control. Examples are GPIB devices with front pannel controls, PLC systems that have manual controls or non-epics network access.

For V3 some of the hardware , but none of the soft, support implemented the first feature but by modifying actual fields in the record. V3 did not implement the second feature. Some special device support, not part of base, was implemented to support this feature.

For V4 these features are supported as follows:

record initialization

The link support implements an interface that has a put and a get method. For example:

    interface LinkInt32 {
        LinkResult get(Callback callback,Int32 data);
        LinkResult put(Callback callback,Int32 data);
        boolean getBounds(Int32 low, Int32 high);
    }

If the link support can support readbacks then it implements get and returns linkNoop. If it does not support readbacks then it implements get by just returning linkNoop.

monitors for outputs

If output link support can detect when something besides the link support itself modifies the output then it implements interface MonitorLink

    interface SupportMonitor {
        void addMonitor(Callback callback);
        void removeMonitor();
    }

At initialization recordSupport looks for this interface and if found it calls addMonitor. The link support calls the callback whenever it detects a change in the output that it did not cause. recordSupport causes itself to be processed without making a new call to the link support. ---