Difference between revisions of "V4 Design: dbdInterfaces"

From EPICSWIKI
 
Line 1: Line 1:
= EPICS: dbdInterfaces - IOC Database Description =
= EPICS: dbdInterfaces - IOC Database Description =
August 11 2005  
August 12 2005  


----
----
Line 20: Line 20:
== Syntax ==
== Syntax ==


The syntax is defined so that it is easy to provide C++ and Java definitions
The syntax is defined so that it is easy to provide C++ and Java definitions.
 
NOTE: Most of the code fragments use C++ syntax.


=== Primitive Types ===
=== Primitive Types ===
Line 59: Line 61:
The syntax uses the terms enum, interface, and struct.
The syntax uses the terms enum, interface, and struct.


An example of a enum is:
An example of an enum is:


     enum LinkDir {
     enum LinkDir {
Line 101: Line 103:
An example of a struct definition is:
An example of a struct definition is:


     struct displayLimitsData {
     struct DisplayLimitData {
         float64 low;
         float64 low;
         float64 high;
         float64 high;
Line 108: Line 110:
In C++ this would be:
In C++ this would be:


     struct displayLimitsData {
     class DisplayLimitData {
    public:
         double low;
         double low;
         double high;
         double high;
Line 115: Line 118:
In Java this would be:
In Java this would be:


     class displayLimitsData {
     class DisplayLimitData {
         public double low;
         public double low;
         public double high;
         public double high;
Line 135: Line 138:


=== string support ===
=== string support ===
The string support is only needed for C++. The Jave implementation
can just use String wherever NonmutableString or MutableString appear.
The following interfaces are for allocating tempory storage for strings:
The following interfaces are for allocating tempory storage for strings:


Line 159: Line 166:


=== array support ===
=== array support ===
This is only needed for C++. Jave already provides an analogous facility.


     // ArrayCopy only works on primitive types
     // ArrayCopy only works on primitive types
Line 169: Line 178:
<center>
<center>


== dbfTypes ==
== DbfTypes ==
  </center>
  </center>
The following naming conventions are used:
The following naming conventions are used:
Line 184: Line 193:
record, link, or device support.
record, link, or device support.


=== <tt>dbfTypes.h</tt> ===
=== <tt>DbfTypes.h</tt> ===


The following <tt>enum</tt> definitions describe  
The following <tt>enum</tt> definitions describe  
Line 190: Line 199:
<tt>record</tt> definitions.
<tt>record</tt> definitions.


     enum basicType {
     enum BasicType {
         basicTypeBool,    // DbfBool
         BasicTypeBool,    // DbfBool
         basicTypeOctet,    // DbfOctet
         BasicTypeOctet,    // DbfOctet
         basicTypeInt16,    // DbfInt16
         BasicTypeInt16,    // DbfInt16
         basicTypeInt32,    // DbfInt32
         BasicTypeInt32,    // DbfInt32
         basicTypeInt64,    // DbfInt64
         BasicTypeInt64,    // DbfInt64
         basicTypeFloat32,  // DbfFloat32
         BasicTypeFloat32,  // DbfFloat32
         basicTypeFloat64,  // DbfFloat64
         BasicTypeFloat64,  // DbfFloat64
         basicTypeString,  // DbfString
         BasicTypeString,  // DbfString
         basicTypeArray,    // DbfArray
         BasicTypeArray,    // DbfArray
         basicTypeStruct,  // DbfStruct
         BasicTypeStruct,  // DbfStruct
     };
     };


     enum dbfType {
     enum DbfType {
         dbfTypeBasic,      // DbfBool,...,DbfStruct
         DbfTypeBasic,      // DbfBool,...,DbfStruct
         dbfTypeMenu,        // DbfMenu
         DbfTypeMenu,        // DbfMenu
         dbfTypeEnum,        // DbfEnum
         DbfTypeEnum,        // DbfEnum
         dbfTypeLink,        // DbfLink
         DbfTypeLink,        // DbfLink
         dbfTypeDevice,      // DbfDevice
         DbfTypeDevice,      // DbfDevice
         dbfTypeMDArray,    // DbfMDArray
         DbfTypeMDArray,    // DbfMDArray
         dbfTypeTimeStamp   // DbfTimeStamp
         DbfTypeTimeStamp   // DbfTimeStamp
     };
     };




=== Discussion of dbfTypes ===
=== Discussion of DbfTypes ===


The following shows the code generated from DBD files:
The following shows the code generated from DBD files:
Line 220: Line 229:
==== structure definitions ====
==== structure definitions ====
If a structure is defined as:
If a structure is defined as:
     struct(displayLimits) {
     struct(DisplayLimit) {
         field(low,double)
         field(low,double)
         field(high,double)
         field(high,double)
Line 227: Line 236:
Then the generated C++ header file will be
Then the generated C++ header file will be


     class displayLimit {
     class DisplayLimit {
     public:
     public:
         DbfFloat64 low;
         DbfFloat64 *low;
         DbfFloat64 high;
         DbfFloat64 *high;
         static int16 lowIndex = 1;
         static int16 lowIndex = 1;
         static int16 highIndex = 2;
         static int16 highIndex = 2;
Line 238: Line 247:
The generated Java file is
The generated Java file is


     class displayLimit {
     class DisplayLimit {
         public DbfFloat64 low;
         public DbfFloat64 low;
         public DbfFloat64 high;
         public DbfFloat64 high;
Line 248: Line 257:
In addition code will be generated that implements the following:
In addition code will be generated that implements the following:


     struct displayLimitData {
     struct DisplayLimitData {
         float64 low;
         float64 low;
         float64 high;
         float64 high;
     }
     }
     interface displayLimitAccess{
     interface DisplayLimitAccess{
         void get(DbfStruct, displayLimitData data);
         void get(DbfStruct, DisplayLimitData data);
         void put(DbfStruct, displayLimitData data);
         void put(DbfStruct, DisplayLimitData data);
     }
     }


==== record definitions ====
==== record definitions ====
If a record is defined as:
If a record is defined as:
     record(example) extends iocRecord {
     record(Example) extends IocRecord {
         ...
         ...
         field(fbool,bool)
         field(fbool,bool)
Line 273: Line 282:
         field(flink,link(in))
         field(flink,link(in))
         field(fdevice,link(in,analogIO))
         field(fdevice,link(in,analogIO))
         field(displayLimits,struct(displayLimits))
         field(DisplayLimit,struct(DisplayLimit))
     }
     }


Then the generated C++ header file will be
Then the generated C++ header file will be
     class iocRecord {
     class IocRecord {
     public:
     public:
         DbdRecordInstance base;
         DbdRecordInstance *base;
     };
     };


     class exampleRecord : public iocRecord {
     class ExampleRecord : public IocRecord {
     public:
     public:
         DbfBool      fbool;
         DbfBool      *fbool;
         DbfOctet    foctet;
         DbfOctet    *foctet;
         DbfInt16    fint;
         DbfInt16    *fint;
         ...
         ...
         DbfFloat64  ffloat;
         DbfFloat64  *ffloat;
         DbfString    fstring;
         DbfString    *fstring;
         DbfArray    farray;
         DbfArray    *farray;
         DbfMDArray  fmdarray;
         DbfMDArray  *fmdarray;
         DbfMenu      fmenu;
         DbfMenu      *fmenu;
         DbfEnum      fenum;
         DbfEnum      *fenum;
         DbfLink      flink;
         DbfLink      *flink;
         DbfDevice    fdevice;
         DbfDevice    *fdevice;
         DbfStruct    displayLimits;
         DbfStruct    *displayLimit;
         static int16 baseIndex = 1;
         static int16 baseIndex = 1;
         static int16 fboolIndex = 2;
         static int16 fboolIndex = 2;
         ...
         ...
         static int16 lastIndex = displayLimitsIndex;
         static int16 lastIndex = DisplayLimitIndex;
};
};


The generated Java file is
The generated Java file is


     class iocRecord {
     class IocRecord {
         public DbdRecordInstance base;
         public DbdRecordInstance base;
     };
     };
     class exampleRecord extends iocRecord {
     class ExampleRecord extends IocRecord {
         public DbfBool      fbool;
         public DbfBool      fbool;
         public DbfOctet    foctet;
         public DbfOctet    foctet;
Line 321: Line 330:
         public DbfLink      flink;
         public DbfLink      flink;
         public DbfDevice    fdevice;
         public DbfDevice    fdevice;
         public DbfStruct    displayLimits;
         public DbfStruct    DisplayLimit;
         public static final int16 baseIndex = 1;
         public static final int16 baseIndex = 1;
         public static final int16 fboolIndex = 2;
         public static final int16 fboolIndex = 2;
         ...
         ...
         public static final int16 lastIndex = displayLimitsIndex;
         public static final int16 lastIndex = DisplayLimitIndex;
     };
     };


Line 338: Line 347:


     interface Dbf{
     interface Dbf{
         bool isPrimitive(); // basicTypeBool,...,basicTypeFloat64
         bool isPrimitive(); // BasicTypeBool,...,BasicTypeFloat64
         bool isBasic();
         bool isBasic();
         basicType getBasicType();
         BasicType getBasicType();
         DbdRecordInstance getRecord();
         DbdRecordInstance getRecord();
         int16 getIndex();
         int16 getIndex();
Line 346: Line 355:


The interfaces are designed as follows:
The interfaces are designed as follows:
* dbAccess provides storage for fields and never exposes the address of any field.
* DbAccess provides storage for fields and never exposes the address of any field.
* dbAccess notifies Channel Access when an field is modified.
* DbAccess notifies Channel Access when an field is modified.
* Can we just lock individual records rather than lock sets?
* Can we just lock individual records rather than lock sets?
** What about deadlock copying from one record to another?


The fact the each field is an object means that additional storage is required.
The fact the each field is an object means that additional storage is required.
dbAccess will probably have something like the following:
DbAccess will probably have something like the following:


     class Field {
     class Field {
Line 414: Line 424:
file. Some examples are:
file. Some examples are:


     exampleRecord *precord;
     ExampleRecord *precord;
     epicsInt16 myint;
     epicsInt16 myint;
     ...
     ...
Line 434: Line 444:
     pDbdAddr = pLocateInstance->getPV(pvname);
     pDbdAddr = pLocateInstance->getPV(pvname);
     pvname->destroy();
     pvname->destroy();
     if(!pDbdAddr || (pDbdAddr->getType != dbfTypeFloat64)) // do SOMETHING
     if(!pDbdAddr || (pDbdAddr->getType != DbfTypeFloat64)) // do SOMETHING
     pfield = (epicsFloat64 *)pDbdAddr->getAddr();
     pfield = (epicsFloat64 *)pDbdAddr->getAddr();
     pfield->put(10.0);
     pfield->put(10.0);
Line 453: Line 463:
The following code prints a string.
The following code prints a string.


     exampleRecord *precord;
     ExampleRecord *precord;
     epicsInt32 len = precord->fstring->getLength();
     epicsInt32 len = precord->fstring->getLength();
     MutableString *pstring = pMutableStringFactory->create(len);
     MutableString *pstring = pMutableStringFactory->create(len);
Line 464: Line 474:


NOTES:
NOTES:
* Does record support have to have any say in how dbAccess manages storage for strings? I don't think so.
* Does record support have to have any say in how DbAccess manages storage for strings? I don't think so.


=== Structure Fields ===
=== Structure Fields ===
Line 480: Line 490:
Structure fields can only be accessed via introspection.
Structure fields can only be accessed via introspection.
However, for each structure, code is generated that does the introspection.
However, for each structure, code is generated that does the introspection.
For example displayLimitData can be obtained via the statements:
For example DisplayLimitData can be obtained via the statements:
     exampleRecord *precord;
     ExampleRecord *precord;
     displayLimitData limits;
     DisplayLimitData limits;
      
      
     ...
     ...
     pdisplayLimitAccess->get(precord->displayLimits,limits);
     pDisplayLimitAccess->get(precord->displayLimit,limits);
     printf("low %f high %f\n",limits.low,limits.high);
     printf("low %f high %f\n",limits.low,limits.high);


Line 491: Line 501:


     interface DbfArray extends Dbf {
     interface DbfArray extends Dbf {
         dbfType getType();
         DbfType getType();
         int32 getNelements();
         int32 getNelements();
         void setNelements(int32 len);
         void setNelements(int32 len);
Line 543: Line 553:
     };
     };


The following puts data into a float54 field.
The following puts data into a float64 field.


     exampleRecord *precord;
     ExampleRecord *precord;
     float64 *pdata; // assume this has been allocated somehow
     float64 *pdata; // assume this has been allocated somehow
     int32  nelements; // this is number of elements
     int32  nelements; // this is number of elements
Line 557: Line 567:
* It must be possible for support to provide an implementation of get and put. It must be possible to do this in segments. For example
* It must be possible for support to provide an implementation of get and put. It must be possible to do this in segments. For example
** A circular buffer requires two segments
** A circular buffer requires two segments
** If the memory is in hardware, the support can read/write the data in segmemnts. Transient recorders are an example.
** If the memory is in hardware, the support can read/write the data in segments. Transient recorders are an example.
* If support implements get and put then dbAccess does NOT manage storage but just call support to get/put data.
* If support implements get and put then DbAccess does NOT manage storage but just calls support to get/put data.


=== DbfMDArray ===
=== DbfMDArray ===
Line 634: Line 644:
<center>
<center>


== dbdStatements ==
== DbdStatements ==


  </center>
  </center>
The definitions in <tt>dbdStatements.h</tt> describe everything defined in  
These describe everything defined in database definition files.
database definition files.


In the definitions:
In the definitions:
Line 646: Line 655:


     interface DbdMenu {
     interface DbdMenu {
         NonmutableString getName();
         int32 getNameLength();
        void getName(int32 len,octet[] data);
         int16 getNchoices();
         int16 getNchoices();
         NonmutableString getChoice(int16 index);
         int32 getChoiceLength(int16 index);
        void getChoice(int16 index,int32 len,octet[] data);
     };
     };


Line 655: Line 666:
     interface DbdLink {
     interface DbdLink {
         LinkDir getDir();
         LinkDir getDir();
         NonmutableString getChoiceName();
         int32 getChoiceNameLength();
        void getChoiceName(int32 len,octet[] data);
         LinkSupport create(DbfLink link);
         LinkSupport create(DbfLink link);
     };
     };
Line 662: Line 674:
     interface DbdDevice {
     interface DbdDevice {
         LinkDir getDir();
         LinkDir getDir();
         NonmutableString getChoiceName();
         int32 getChoiceNameLength();
        void getChoiceName(int32 len,octet[] data);
         Support  create(DbfDevice device);
         Support  create(DbfDevice device);
     };
     };
Line 670: Line 683:


     interface DbdAttribute {
     interface DbdAttribute {
         NonmutableString getDefault();
         int32 getDefaultLength();
        void getDefault(int32 len,octet[] data);
         bool isReadonly();
         bool isReadonly();
         bool isDesign();
         bool isDesign();
Line 679: Line 693:
     interface DbdDefaults {};
     interface DbdDefaults {};
      
      
    interface DbdStringDefaults extends DbdDefaults{
        NonmutableString getBufferType();
        int32 getCapacity();
    };
     interface DbdArrayDefaults extends DbdDefaults{
     interface DbdArrayDefaults extends DbdDefaults{
         dbfType getType();
         DbfType getType();
        NonmutableString getBufferType();
        int32 getCapacity();
         int32 getLength();
         int32 getLength();


Line 695: Line 702:


     interface DbdField {
     interface DbdField {
         NonmutableString getName();
         int32 getNameLength();
         dbfType getType();
        void getName(int32 len,octet[] data);
         DbfType getType();
         DbdDefaults getDefaults();
         DbdDefaults getDefaults();
         DbdAttribute getAttributes();
         DbdAttribute getAttributes();
Line 702: Line 710:


     interface DbdStruct {
     interface DbdStruct {
         NonmutableString getName();
         int32 getNameLength();
        void getName(int32 len,octet[] data);
         int16 getNumberFields();
         int16 getNumberFields();
         DbdField getFieldDescription(int16 index);
         DbdField getFieldDescription(int16 index);
Line 710: Line 719:
     interrface DbdRecord {
     interrface DbdRecord {
         // Need list of instances
         // Need list of instances
         NonmutableString getName();
         int32 getNameLength();
        void getName(int32 len,octet[] data);
         int16 getNumberFields();
         int16 getNumberFields();
         DbdField getFieldDescription(int16 index);
         DbdField getFieldDescription(int16 index);
Line 730: Line 740:
     interface DbdRecordInstance {
     interface DbdRecordInstance {
         DbdRecord getDescription();
         DbdRecord getDescription();
         NonmutableString getName();
         int32 getNameLength();
         iocRecord getReference();
        void getName(int32 len,octet[] data);
         IocRecord getReference();
     };
     };


     interface DbdAddr {
     interface DbdAddr {
         void    destroy();  // call this when done with DbAddr
         void    destroy();  // call this when done with DbAddr
         dbfType getType();
         DbfType getType();
         DbdRecordInstance getInstance();
         DbdRecordInstance getInstance();
         int16 getIndex();
         int16 getIndex();
Line 753: Line 764:
     interface Support {
     interface Support {
         void destroy();
         void destroy();
         NonmutableString getSupportName();
         int32 getSupportNameLength();
         NonmutableString getDataStructName();
        void getSupportName(int32 len,octet[] data);
        int32 getDataStructNameLength();
         void getDataStructName(int32 len,octet[] data);
         void report(int16 level);
         void report(int16 level);
         void initialize();
         void initialize();

Revision as of 14:04, 12 August 2005

EPICS: dbdInterfaces - IOC Database Description

August 12 2005


Overview

This document describes definitions for code that accessses IOC records, i.e. the records created from Database Definitions. The definitions are intended for code that:

  • includes header files generated from dbd definitions. Header files are generated from the following dbd definitions:
    • record - Should only be included by record support.
    • struct - Included by code that understands the struct.
    • menu - Included by code that understands the menu.
  • does not include the header files.

Syntax

The syntax is defined so that it is easy to provide C++ and Java definitions.

NOTE: Most of the code fragments use C++ syntax.

Primitive Types

  • bool - a value that takes the values true or false
  • octet - an 8 bit byte
  • int16 - a 16 bits signed integer
  • int32 - a 32 bit signed integer
  • int64 - a 64 bit signed integer
  • float32 - a 32 bit IEEE float
  • float64 - a 64 bit IEEE float

In Java these types become:

  • bool => bool
  • octet => byte BUT no arithmetic is implied
  • int16 => short
  • int32 => int
  • int64 => long
  • float32 => float
  • float64 => double

In C++ these types become:

  • bool => bool
  • octet => char BUT no arithmetic is implied
  • int16 => short
  • int32 => int
  • int64 => long long
  • float32 => float
  • float64 => double

NOTES:

  • C++ may require something else to handle the integer types
  • Exceptions must be defined. TBD

enum, interface, struct, array

The syntax uses the terms enum, interface, and struct.

An example of an enum is:

    enum LinkDir {
        LinkDirNone,
        LinkDirForward,
        LinkDirIn,
        LinkDirOut,
        LinkDirInOut
    };

The C++ definition is identical. In Java 5 the definition would be:

    public enum LinkDir {
        LinkDirNone,
        LinkDirForward,
        LinkDirIn,
        LinkDirOut,
        LinkDirInOut
    };

An example of an interface definition is:

    interface DbfBool extends Dbf {
        bool get();
        void put(bool val);
    };

In C++ would be:

    class DbfBool : public Dbf {
    public:
        virtual bool get() = 0;
        virtual void put(bool val) = 0;
    };

In Java would be:

    interface DbfBool extends Dbf {
        bool get();
        void put(bool val)
    };

An example of a struct definition is:

    struct DisplayLimitData {
        float64 low;
        float64 high;
    };

In C++ this would be:

   class DisplayLimitData {
   public:
        double low;
        double high;
    };

In Java this would be:

    class DisplayLimitData {
        public double low;
        public double high;
    };

An example of a definition that includes an array is:

    bool get(int32 len,octet[] data);

In C++ ,this would become:

    bool get(int len, char data[]);

support for strings and arrays

string support

The string support is only needed for C++. The Jave implementation can just use String wherever NonmutableString or MutableString appear.

The following interfaces are for allocating tempory storage for strings:

    interface NonmutableString {
       void destroy(); // Call this when done with string
       int32 getLength();
       void get(int32 len,octet[] data);
    };
   
    interface NonmutableStringFactory {
        NonmutableString create(int32 len,octet[] data);
    }
    interface MutableString extends NonmutableString {
       int32 getCapacity();
       void put(int32,len,octet[] data);
    };
   
    interface MutableStringFactory {
        MutableString create(int32 int32 capacity);
    }

These will use free lists to manage the storage for the octet arrays.

array support

This is only needed for C++. Jave already provides an analogous facility.

    // ArrayCopy only works on primitive types
    interface ArrayCopy {
        copy(DbfArray from,DbfArray to);
    }

This only supports primitive types, i.e. DbfBool,...,DbfFloat64.


DbfTypes

The following naming conventions are used:

Dbf
any class starting with Dbf describes a field in a generated header file. For example DbfArray describes a field generated from field(name,array(float64[]).
Dbd
A class name starting with Dbd describes something related to dbd definitions. For example DbdLinkSupport describes a dbd link definition.

All Dbf and Dbd definitions are interfaces. Thus all access to data is via interfaces. The IOC database implements the interfaces, with help from record, link, and device support. After initialization data can only be accessed via the interfaces. This allows the database to handle actions like posting database monitors without any help from record, link, or device support.

DbfTypes.h

The following enum definitions describe each field in the header files generated from DBD struct and record definitions.

    enum BasicType {
        BasicTypeBool,     // DbfBool
        BasicTypeOctet,    // DbfOctet
        BasicTypeInt16,    // DbfInt16
        BasicTypeInt32,    // DbfInt32
        BasicTypeInt64,    // DbfInt64
        BasicTypeFloat32,  // DbfFloat32
        BasicTypeFloat64,  // DbfFloat64
        BasicTypeString,   // DbfString
        BasicTypeArray,    // DbfArray
        BasicTypeStruct,   // DbfStruct
    };
    enum DbfType {
        DbfTypeBasic,       // DbfBool,...,DbfStruct
        DbfTypeMenu,        // DbfMenu
        DbfTypeEnum,        // DbfEnum
        DbfTypeLink,        // DbfLink
        DbfTypeDevice,      // DbfDevice
        DbfTypeMDArray,     // DbfMDArray
        DbfTypeTimeStamp    // DbfTimeStamp
    };


Discussion of DbfTypes

The following shows the code generated from DBD files:

structure definitions

If a structure is defined as:

    struct(DisplayLimit) {
        field(low,double)
        field(high,double)
    }

Then the generated C++ header file will be

    class DisplayLimit {
    public:
        DbfFloat64 *low;
        DbfFloat64 *high;
        static int16 lowIndex = 1;
        static int16 highIndex = 2;
        static int16 lastIndex = highIndex;
    };

The generated Java file is

    class DisplayLimit {
        public DbfFloat64 low;
        public DbfFloat64 high;
        public static final int16 lowIndex = 1;
        public static final int16 highIndex = 2;
        public static final int16 lastIndex = indexHigh;
    };

In addition code will be generated that implements the following:

    struct DisplayLimitData {
        float64 low;
        float64 high;
    }
    interface DisplayLimitAccess{
        void get(DbfStruct, DisplayLimitData data);
        void put(DbfStruct, DisplayLimitData data);
    }

record definitions

If a record is defined as:

    record(Example) extends IocRecord {
        ...
        field(fbool,bool)
        field(foctet,octet)
        field(fint,int16)
        ...
        field(ffloat,float64)
        field(fstring,string)
        field(farray,array(double[])
        field(fmdarray,array(double[,])
        field(fmenu,menu(name))
        field(fenum,enum)
        field(flink,link(in))
        field(fdevice,link(in,analogIO))
        field(DisplayLimit,struct(DisplayLimit))
    }

Then the generated C++ header file will be

    class IocRecord {
    public:
        DbdRecordInstance *base;
    };
    class ExampleRecord : public IocRecord {
    public:
        DbfBool      *fbool;
        DbfOctet     *foctet;
        DbfInt16     *fint;
        ...
        DbfFloat64   *ffloat;
        DbfString    *fstring;
        DbfArray     *farray;
        DbfMDArray   *fmdarray;
        DbfMenu      *fmenu;
        DbfEnum      *fenum;
        DbfLink      *flink;
        DbfDevice    *fdevice;
        DbfStruct    *displayLimit;
        static int16 baseIndex = 1;
        static int16 fboolIndex = 2;
        ...
        static int16 lastIndex = DisplayLimitIndex;

};

The generated Java file is

    class IocRecord {
        public DbdRecordInstance base;
    };
    class ExampleRecord extends IocRecord {
        public DbfBool      fbool;
        public DbfOctet     foctet;
        public DbfInt16     fint;
        ...
        public DbfFloat64   ffloat;
        public DbfString    fstring;
        public DbfArray     farray;
        public DbfMDArray   fmdarray;
        public DbfMenu      fmenu;
        public DbfEnum      fenum;
        public DbfLink      flink;
        public DbfDevice    fdevice;
        public DbfStruct    DisplayLimit;
        public static final int16 baseIndex = 1;
        public static final int16 fboolIndex = 2;
        ...
        public static final int16 lastIndex = DisplayLimitIndex;
    };

Database Fields

Each database field is accessed via an interface which all derived from the following interface:

    interface Dbf{
        bool isPrimitive(); // BasicTypeBool,...,BasicTypeFloat64
        bool isBasic();
        BasicType getBasicType();
        DbdRecordInstance getRecord();
        int16 getIndex();
    };

The interfaces are designed as follows:

  • DbAccess provides storage for fields and never exposes the address of any field.
  • DbAccess notifies Channel Access when an field is modified.
  • Can we just lock individual records rather than lock sets?
    • What about deadlock copying from one record to another?

The fact the each field is an object means that additional storage is required. DbAccess will probably have something like the following:

   class Field {
   public:
       DbdRecordInstance &instance;
       short             index;
   };
   ...
   class IntField : public Field {
   public:
       int data;
   }
   ...

This each field has the overhead of

  • instance - a reference to DbdRecordInstance
  • index - a 16 bit integer
  • vtbl - a reference to the class implementation


Primitive Types

DbfOctet, ..., DbfFloat64 are all interfaces with methods get and put.

    interface DbfBool extends Dbf {
        bool get();
        void put(bool val);
    };
   
    interface DbfOctet extends Dbf {
        octet get();
        void put(octet val);
    };
   
    interface DbfInt16 extends Dbf {
        int16 get();
        void put(int16 val);
    };
   
    interface DbfInt32 extends Dbf {
        int32 get();
        void put(int32 val);
    };
   
    interface DbfInt64 extends Dbf {
        int64 get();
        void put(int64 val);
    };
   
    interface DbfFloat32 extends Dbf {
        float32 get();
        void put(float32 val);
    };
   
    interface DbfFloat64 extends Dbf {
        float64 get();
        void put(float64 val);
    };


Record support code can access such fields via the generated header file. Some examples are:

    ExampleRecord *precord;
    epicsInt16 myint;
    ...
    precord->ffloat->put(10.0);
    ...
    myint = precord->fint->get();

Code that does not include the generated header file can access these fields via the introspecion interfaces described later in this document. For example code that expects a epicsFloat64 field can access it via

    char *name = "recordname.value";
    NonmutableString *pvname = pNonmutableStringFactory->create(
                     strlen(name),name);
    DbdAddr *pDbdAddr;
    DbfFloat64 *pfield;
    ...
    
    pDbdAddr = pLocateInstance->getPV(pvname);
    pvname->destroy();
    if(!pDbdAddr || (pDbdAddr->getType != DbfTypeFloat64)) // do SOMETHING
    pfield = (epicsFloat64 *)pDbdAddr->getAddr();
    pfield->put(10.0);
    // Note that the database will automatically post monitors on the field
    

String fields

The interface for a string field is:

    interface DbfString extends Dbf {
       int32 getLength();
       void get(MutableString string);
       void setPutSize(int32 size);
       void put(NonmutableString string);
    };

The following code prints a string.

    ExampleRecord *precord;
    epicsInt32 len = precord->fstring->getLength();
    MutableString *pstring = pMutableStringFactory->create(len);
    ...
    precord->fstring->get(pstring);
    printf("%.*s\n",len,pdata);

Code that does not include the header file can use the introspection methods to locate the DbfString that provides access to the field.

NOTES:

  • Does record support have to have any say in how DbAccess manages storage for strings? I don't think so.

Structure Fields

    interface DbfIntrospect {
        dfType getType();
        Dbf getInterface();
    };
   
    interface DbfStruct extends Dbf {
        int16 getNfields();
        DbfIntrospect getIntrospect(int16 index);
    };

Structure fields can only be accessed via introspection. However, for each structure, code is generated that does the introspection. For example DisplayLimitData can be obtained via the statements:

    ExampleRecord *precord;
    DisplayLimitData limits;
    
    ...
    pDisplayLimitAccess->get(precord->displayLimit,limits);
    printf("low %f high %f\n",limits.low,limits.high);

Array Fields

    interface DbfArray extends Dbf {
       DbfType getType();
       int32 getNelements();
       void setNelements(int32 len);
    };
    interface DbfOctetArray extends DbfArray {
       int32 get(int32 offset, int32 len, octet[] pto);
       int32 put(int32 offset, int32 len, octet[] pfrom);
    };
    interface DbfBoolArray extends DbfArray {
       int32 get(int32 offset, int32 len, bool[] pto);
       int32 put(int32 offset, int32 len, bool[] pfrom);
    };
    interface DbfInt16Array extends DbfArray {
       int32 get(int32 offset, int32 len, int16[] pto);
       int32 put(int32 offset, int32 len, int16[] pfrom);
    };
    interface DbfInt32Array extends DbfArray {
       int32 get(int32 offset, int32 len, int32[] pto);
       int32 put(int32 offset, int32 len, int32[] pfrom);
    };
    interface DbfInt64Array extends DbfArray {
       int32 get(int32 offset, int32 len, int64[] pto);
       int32 put(int32 offset, int32 len, int64[] pfrom);
    };
    interface DbfFloat32Array extends DbfArray {
       int32 get(int32 offset, int32 len, float32[] pto);
       int32 put(int32 offset, int32 len, float32[] pfrom);
    };
    interface DbfFloat64Array extends DbfArray {
       int32 get(int32 offset, int32 len, float64[] pto);
       int32 put(int32 offset, int32 len, float64[] pfrom);
    };
    interface DbfStringArray extends DbfArray {
        DbfString getInterface(int32 index);
    };
    interface DbfArrayArray extends DbfArray {
        DbfArray getInterface(int32 index);
    };
    interface DbfStructArray extends DbfArray {
        DbfStruct getInterface(int32 index);
    };

The following puts data into a float64 field.

    ExampleRecord *precord;
    float64 *pdata; // assume this has been allocated somehow
    int32   nelements; // this is number of elements
    DbfFloat64Array *parray = (DbfFloat64Array *)precord->farray;
    ...
    parray->put(0,nelements,pdata);


NOTES:

  • It must be possible for support to provide an implementation of get and put. It must be possible to do this in segments. For example
    • A circular buffer requires two segments
    • If the memory is in hardware, the support can read/write the data in segments. Transient recorders are an example.
  • If support implements get and put then DbAccess does NOT manage storage but just calls support to get/put data.

DbfMDArray

NOT YET DEFINED


DbfMenu

DbfMenu is described as:

    interface DbfMenu extends Dbf {
        int16 getIndex();
        void putIndex(int16 val);
        DbdMenu getDbdMenu();
    };

DbfMenu allows the menu index to be set and retrieved and also provides access to the DbdMenu.

A DbfMenu field can be accessed via the generated header file or via the introspection methods.


DbfEnum

DbfEnum is described as:

    interface DbfEnum extends Dbf {
        int16 getIndex();
        void putIndex(int16 val);
        DbfStringArray getChoiceArray();
    };


DbfEnum allows the enum index to be set and retrieved and also provides access to the The DbfArray field that contains the choices.

DbfLink and DbfDevice

DbfLink is described as

    enum LinkDir {
        LinkDirNone,
        LinkDirForward,
        LinkDirIn,
        LinkDirOut,
        LinkDirInOut
    };
   
    interface DbfLink extends Dbf {
        LinkDir getDir();
        LinkSupport support;
    };
   
    interface DbfDevice extends Dbf {
        LinkDir getDir();
        Support support; // Support is base class for device support
    };

See below for the description of support, which included record, link, and device support.

DbfTimeStamp

    struct TimeStamp {
        int64 secondsSinceEpoch;
        int32 nanoSeconds;
    };
    interface DbfTimeStamp extends Dbf {
        void get(TimeStamp timeStamp);
        void put(TimeStamp timeStamp);
    };

DbdStatements

These describe everything defined in database definition files.

In the definitions:


DbdMenu

    interface DbdMenu {
        int32 getNameLength();
        void getName(int32 len,octet[] data);
        int16 getNchoices();
        int32 getChoiceLength(int16 index);
        void getChoice(int16 index,int32 len,octet[] data);
    };


DbdLink and DbdDevice

    interface DbdLink {
        LinkDir getDir();
        int32 getChoiceNameLength();
        void getChoiceName(int32 len,octet[] data);
        LinkSupport create(DbfLink link);
    };
   
   
    interface DbdDevice {
        LinkDir getDir();
        int32 getChoiceNameLength();
        void getChoiceName(int32 len,octet[] data);
        Support  create(DbfDevice device);
    };


DbdStruct and DbdRecord

    interface DbdAttribute {
        int32 getDefaultLength();
        void getDefault(int32 len,octet[] data);
        bool isReadonly();
        bool isDesign();
        bool isSpecial();
        int16 getAsl();
    };
   
    interface DbdDefaults {};
   
    interface DbdArrayDefaults extends DbdDefaults{
        DbfType getType();
        int32 getLength();
    interface DbdStructDefaults extends DbdDefaults{
        DbdStruct getDescription();
    };
    interface DbdField {
        int32 getNameLength();
        void getName(int32 len,octet[] data);
        DbfType getType();
        DbdDefaults getDefaults();
        DbdAttribute getAttributes();
    };
    interface DbdStruct {
        int32 getNameLength();
        void getName(int32 len,octet[] data);
        int16 getNumberFields();
        DbdField getFieldDescription(int16 index);
        DbdStructLifetime getLifetime();
    };
    interrface DbdRecord {
        // Need list of instances
        int32 getNameLength();
        void getName(int32 len,octet[] data);
        int16 getNumberFields();
        DbdField getFieldDescription(int16 index);
        DbdRecordSupport getSupport();
        DbdRecordLifetime getLifetime();
    };
    interface DbdLocate {
        DbdMenu getMenu(NonmutableString name);
        DbdLink getLink(NonmutableString name);
        DbdDevice getDevice(NonmutableString name);
        DbdStruct getStruct(NonmutableString name);
        DbdRecord getRecord(NonmutableString name);
    };


Record Instance

    interface DbdRecordInstance {
        DbdRecord getDescription();
        int32 getNameLength();
        void getName(int32 len,octet[] data);
        IocRecord getReference();
    };
    interface DbdAddr {
        void    destroy();  // call this when done with DbAddr
        DbfType getType();
        DbdRecordInstance getInstance();
        int16 getIndex();
        void  getField(NonmutableString field);
    };
    interface LocateInstance{
        DbdAddr getPV(NonmutableString pvname);
        DbdAddr getField(NonmutableString record,NonmutableString field);
    }


Record, Link, Device Support

    // base interface for support
    interface Support {
        void destroy();
        int32 getSupportNameLength();
        void getSupportName(int32 len,octet[] data);
        int32 getDataStructNameLength();
        void getDataStructName(int32 len,octet[] data);
        void report(int16 level);
        void initialize();
        void connect();
        void disconnect();
    };
   
    enum processState {
        processIdle,
        processInputActive,
        processActive,
        processOutputActive,
        processDone
    };
   
    interface RecordSupport {
        void destroy();
        void initialize();
        processState process(processState state);
        void special(bool after,DbfField field);
    };
   
    interface Callback {
        void done();
        void timedout();
    }
   
    interface LinkSupport extends Support {
        void get(DbfField field);
        void getProcess(DbfField field,double timeout,Callback callback);
        void put(DbfField field, bool process);
        void putWait(DbfField field,double timeout,Callback callback);
        void process();
        void processWait(double timeout,Callback callback);
    }