Difference between revisions of "V4 Design: dbdInterfaces"
MartyKraimer (talk | contribs) |
MartyKraimer (talk | contribs) |
||
Line 1: | Line 1: | ||
= EPICS: dbdInterfaces - IOC Database Description = | = EPICS: dbdInterfaces - IOC Database Description = | ||
September | September 14 2005 | ||
---- | ---- | ||
Line 10: | Line 10: | ||
This document describes definitions for code that accessses | This document describes definitions for code that accessses | ||
IOC records, i.e. the records created from Database Definitions. | IOC records, i.e. the records created from Database Definitions: | ||
The definitions | menu, struct, record, link, device, and record instances. | ||
The interfaces support introspection of everything created from Database | |||
Definitions. The interfaces can be used by tools such as VDCT or on | |||
a running IOC database. | |||
The definitions can be used by code that use code automatically | |||
genereted from DBD files or by code that uses only introspection. | |||
Code is automatically generated from the following definitions: | |||
* <tt>record</tt> - Used by record support. | |||
* <tt>struct</tt> - Used by code that understands the struct. | |||
* <tt>menu</tt> - Used by code that understands the menu. | |||
---- | |||
<center> | |||
== Syntax == | == Syntax == | ||
</center> | |||
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. | ||
Line 26: | Line 37: | ||
=== Primitive Types === | === Primitive Types === | ||
* boolean - a value that takes the values true or false | * boolean - a value that takes the values true or false | ||
* octet - | * octet - 8 bit byte | ||
* int16 - | * int16 - 16 bit signed integer | ||
* int32 - | * int32 - 32 bit signed integer | ||
* int64 - | * int64 - 64 bit signed integer | ||
* float32 - | * float32 - 32 bit IEEE float | ||
* float64 - | * float64 - 64 bit IEEE float | ||
In Java these types become: | In Java these types become: | ||
Line 45: | Line 56: | ||
In C++ these types become: | In C++ these types become: | ||
* boolean => bool | * boolean => bool BUT no arithmetic or conversion to/from int is implied | ||
* octet => char BUT no arithmetic is implied | * octet => char BUT no arithmetic is implied | ||
* int16 => int16_t | * int16 => int16_t | ||
Line 119: | Line 130: | ||
public: | public: | ||
virtual bool get() = 0; | virtual bool get() = 0; | ||
virtual void put( | virtual void put(bool val) = 0; | ||
}; | }; | ||
Line 235: | Line 246: | ||
class | static class DbfConvertPrimitive { | ||
public: | public: | ||
int16 get(Dbf from); | |||
int32 get(Dbf from); | |||
int64 get(Dbf from); | |||
float32 get(Dbf from); | |||
float64 get(Dbf from); | |||
get(Dbf from, int32 lenValue,const *char value); | |||
get(DbfBoolean from, int32 lenValue,const *char value); | |||
put(Dbf to, int16 value); | |||
put(Dbf to, int32 value); | |||
put(Dbf to, int64 value); | |||
put(Dbf to, float32 value); | |||
put(Dbf to, float64 value); | |||
put(Dbf to,int32 lenValue,const *char value); | |||
put(DbfBoolean to, int32 lenValue,const *char value); | |||
get(DbfArray from, int16 value[]); | |||
get(DbfArray from, int32 value[]); | |||
get(DbfArray from, int64 value[]); | |||
get(DbfArray from, float32 value[]); | |||
get(DbfArray from, float64 value[]); | |||
put(DbfArray to, int16 value[]); | |||
put(DbfArray to, int32 value[]); | |||
put(DbfArray to, int64 value[]); | |||
put(DbfArray to, float32 value[]); | |||
put(DbfArray to, float64 value[]); | |||
} | } | ||
Line 278: | Line 289: | ||
The following naming conventions are used: | The following naming conventions are used: | ||
; Dbf | ; Dbf | ||
: any class starting with Dbf describes a field in a | : any class starting with Dbf describes a field in a header file generated from a <tt>struct</tt> or <tt>record</tt> definition. For example DbfArray describes a field generated from <tt>field(name,array(float64[])</tt>. | ||
; Dbd | ; Dbd | ||
: A class name starting with Dbd describes something related to dbd definitions. For example DbdMenu describes a dbd menu definition. | : A class name starting with Dbd describes something related to dbd definitions. For example DbdMenu describes a dbd menu definition. | ||
Line 321: | Line 332: | ||
=== Discussion of DbfTypes === | === Discussion of DbfTypes === | ||
The following shows the code generated from DBD files: | The following shows the Java code generated from DBD files: | ||
==== structure definitions ==== | ==== structure definitions ==== | ||
Line 329: | Line 340: | ||
# A class named <tt>nameSupport</tt> | # A class named <tt>nameSupport</tt> | ||
The class <tt>name</tt> | The class <tt>name</tt> implements: | ||
interface Struct { | interface Struct { | ||
Dbf getField(int16 index); | Dbf getField(int16 index); | ||
Line 343: | Line 354: | ||
A generated file <tt>DisplayLimit.java</tt> contains: | A generated file <tt>DisplayLimit.java</tt> contains: | ||
public class DisplayLimit implements Struct{ | |||
public DbfFloat64 low; | public DbfFloat64 low; | ||
public DbfFloat64 high; | public DbfFloat64 high; | ||
public static final | public static final short lowIndex = 1; | ||
public static final | public static final short highIndex = 2; | ||
public static final | public static final short lastIndex = indexHigh; | ||
Dbf getField(short index) { | Dbf getField(short index) { | ||
switch(index) { | switch(index) { | ||
Line 360: | Line 371: | ||
A generated file <tt>DisplayLimitSupport.java</tt> contains: | A generated file <tt>DisplayLimitSupport.java</tt> contains: | ||
public class DisplayLimitData { | public class DisplayLimitData { | ||
Line 394: | Line 403: | ||
Similar files are generated for C++. | Similar files are generated for C++. | ||
==== record definitions ==== | ==== record definitions ==== | ||
Line 474: | Line 481: | ||
interface Dbf{ | interface Dbf{ | ||
DbfType getType(); | |||
boolean isPrimitive(); // BasicTypeBoolean,...,BasicTypeFloat64 | boolean isPrimitive(); // BasicTypeBoolean,...,BasicTypeFloat64 | ||
boolean isBasic(); | boolean isBasic(); | ||
BasicType getBasicType(); | BasicType getBasicType(); | ||
DbRecord getRecord(); | |||
int16 getIndex(); | int16 getIndex(); | ||
} | } | ||
The interfaces are designed as follows: | The interfaces are designed as follows: | ||
* | * Database Access provides access to the field without exposing the address. | ||
* DbAccess posts monitors when a field is modified. | * DbAccess posts monitors when a field is modified. | ||
Database access by default allocates the actual storage for each field | |||
but allows support code to register itself to provide storage for field | |||
instances. | |||
This is particularly usefull for array fields. Two examples are: | |||
* The compress record registers to provide storage for the value. | |||
** This allows it to implement a circular buffer. | |||
** Code that accesses the value field may have to issue two get requests. | |||
* Device support for a transient recorder registers to provide storage for the array | |||
** This allows device support to read data from hardware in segments | |||
** Code that accesses the array may have to issue many get requests. | |||
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. | ||
Line 489: | Line 508: | ||
class Field { | class Field { | ||
DbRecord instance; | |||
short index; | short index; | ||
}; | }; | ||
Line 499: | Line 518: | ||
This each field has the overhead of | This each field has the overhead of | ||
* instance - a reference to | * instance - a reference to DbRecord, i.e. record instance | ||
* index - a 16 bit integer | * index - a 16 bit integer | ||
* vtbl - a reference to the object implementation | * vtbl - a reference to the object implementation | ||
Line 558: | Line 577: | ||
Code that does not include the generated header file can access these fields | Code that does not include the generated header file can access these fields | ||
via the | via the introspection interfaces described later in this document. | ||
For example code that expects a float64 field can access it via | For example code that expects a float64 field can access it via | ||
Line 568: | Line 587: | ||
DbfFloat64 dbfdouble = (DbfFloat64)dbf; | DbfFloat64 dbfdouble = (DbfFloat64)dbf; | ||
dbfdouble.put(10.0); | dbfdouble.put(10.0); | ||
or more concisely (but exception may be thrown) | |||
DbfFloat64 dbfdouble = DbfConvertPrimitive( | |||
LocateInstance.getPV("recordname.value").getField()); | |||
=== String fields === | === String fields === | ||
Line 614: | Line 637: | ||
For example DisplayLimitData can be obtained via the statements: | For example DisplayLimitData can be obtained via the statements: | ||
ExampleRecord record; | ExampleRecord record; | ||
DisplayLimitData | DisplayLimitData limit; | ||
... | ... | ||
DisplayLimitSupport.get(record.displayLimit, | DisplayLimitSupport.get(record.displayLimit,limit); | ||
printf("low %f high %f\n", | printf("low %f high %f\n",limit.low,limit.high); | ||
=== Array Fields === | === Array Fields === | ||
The generated header file will have a type that extends <tt>DbfArray</tt> | |||
interface DbfArray extends Dbf { | interface DbfArray extends Dbf { | ||
Line 678: | Line 703: | ||
ExampleRecord record; | ExampleRecord record; | ||
double[] data; | |||
double[] data = new double[] {1.0,2.0,3.0};; | |||
if(!record.ffloat.isPrimitive() | |||
|| record.ffloat.getBasicType()!=basicTypeFloat64) // DO SOMTHING!!!! | |||
... | |||
array.put(0,nelements,precord->data); | |||
or more concisely | |||
ExampleRecord record; | |||
... | ... | ||
DbfConvertPrimitive.put(precord.array,new double[] {1.0,2.0,3.0}); | |||
As described above support can implement get and put, which can operate | |||
on array segments. | |||
* 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. | |||
=== DbfMDArray === | === DbfMDArray === | ||
Line 750: | Line 781: | ||
} | } | ||
See below for the description of | See below for the description of <tt>Support</tt>, which included record, link, | ||
and device support. | and device support. | ||
Line 772: | Line 803: | ||
</center> | </center> | ||
These describe everything defined in database definition files. | These describe everything defined in database definition files. | ||
=== <tt>DbdMenu</tt> === | === <tt>DbdMenu</tt> === | ||
interface DbdMenu { | interface DbdMenu { | ||
int32 getNameLength( | int32 getNameLength( | ||
void getName(string name); | void getName(string name); | ||
int16 getNchoices(); | int16 getNchoices(); | ||
int32 | int32 getChoiceNameLength(int16 index); | ||
void getChoice(int16 index,string choice); | void getChoice(int16 index,string choice); | ||
} | } | ||
Line 800: | Line 829: | ||
interface DbdLink extends DbdSupport{ | interface DbdLink extends DbdSupport{ | ||
} | } | ||
Line 806: | Line 834: | ||
int32 getInterfaceNameLength(); | int32 getInterfaceNameLength(); | ||
void getInterfaceName(string name); | void getInterfaceName(string name); | ||
} | } | ||
Line 843: | Line 870: | ||
int16 getNumberFields(); | int16 getNumberFields(); | ||
DbdField getFieldDescription(int16 index); | DbdField getFieldDescription(int16 index); | ||
} | } | ||
interface DbdRecord { | |||
int32 getNameLength(); | int32 getNameLength(); | ||
void getName(string name); | void getName(string name); | ||
Line 853: | Line 878: | ||
DbdField getFieldDescription(int16 index); | DbdField getFieldDescription(int16 index); | ||
DbdRecordSupport getSupport(); | DbdRecordSupport getSupport(); | ||
} | } | ||
=== Record Instance === | === Record Instance === | ||
interface | interface DbRecord { | ||
int32 getNameLength(); | int32 getNameLength(); | ||
void getName(string name); | void getName(string name); | ||
DbdRecord getDescription(); | DbdRecord getDescription(); | ||
Dbf getPV(string fieldName); | |||
} | } | ||
---- | |||
<center> | |||
== Locate Interfaces == | |||
== | |||
</center> | |||
Classes are available to find and traverse the various Dbd definitons | |||
and record instances. | |||
The implementation will be language specific. For Java they will be something | |||
like the following: | |||
In addition the following is defined: | |||
class | public class DbdLocate { | ||
public DbdMenu getMenu(String name); | |||
public DbdLink getLink(String name); | |||
public DbdDevice getDevice(String name); | |||
public DbdStruct getStruct(String name); | |||
public DbdRecord getRecord(String name); | |||
public LinkedList<DbdMenu> menuList; | |||
public LinkedList<DbdLink> linkList; | |||
public LinkedList<DbdDevice> deviceList; | |||
public LinkedList<DbdStruct> structList; | |||
public LinkedList<DbdRecord> recordList; | |||
} | } | ||
public class DbInstance { | |||
public DbRecord getRecord(String name); | |||
public Dbf getField(string name); | |||
public Dbf getField(string recordName, string fieldName); | |||
public LinkedList<DbRecord> instanceList; | |||
public LinkedList<DbRecord> instanceList(String recordTypeName); | |||
} | } | ||
< | <b>Question</b> Are the above methods static or should there be something like | ||
public class FindLocator { | |||
public static DbdLocate findDbdLocate(); | |||
public static DbInstance findDbInstance(); | |||
} | } | ||
The following locates a specific menu. | |||
DbdMenu menu = DbdLocate.get("DisplayLimit"); | |||
if(menu!=null) printf("found menu %s\n","DisplayLimit"); | |||
The following locates a field of a record instance. | |||
Dbf field = DbInstance.getField("example.value"); | |||
if(addr!=null) printf("found %s\n","example.value"); | |||
---- | ---- |
Revision as of 13:09, 14 September 2005
EPICS: dbdInterfaces - IOC Database Description
September 14 2005
Overview
This document describes definitions for code that accessses IOC records, i.e. the records created from Database Definitions: menu, struct, record, link, device, and record instances.
The interfaces support introspection of everything created from Database Definitions. The interfaces can be used by tools such as VDCT or on a running IOC database.
The definitions can be used by code that use code automatically genereted from DBD files or by code that uses only introspection.
Code is automatically generated from the following definitions:
- record - Used by record support.
- struct - Used by code that understands the struct.
- menu - Used by code that understands the menu.
Syntax
The syntax is defined so that it is easy to provide C++ and Java definitions.
NOTE: Most of the code fragments use Java syntax.
Primitive Types
- boolean - a value that takes the values true or false
- octet - 8 bit byte
- int16 - 16 bit signed integer
- int32 - 32 bit signed integer
- int64 - 64 bit signed integer
- float32 - 32 bit IEEE float
- float64 - 64 bit IEEE float
In Java these types become:
- boolean => boolean
- octet => byte BUT no arithmetic is implied
- int16 => short
- int32 => int
- int64 => long
- float32 => float
- float64 => double
In C++ these types become:
- boolean => bool BUT no arithmetic or conversion to/from int is implied
- octet => char BUT no arithmetic is implied
- int16 => int16_t
- int32 => int32_t
- int64 => int64_t
- float32 => float
- float64 => double
NOTE:
- The C++ integer types require C99 stdint.h
- Should exceptions be defined?
enum, struct, interface, class, string, array
In adition to the primitive types the syntax uses the terms enum, struct, interface, and array.
enum
An example of an enum is:
enum LinkDir { LinkDirNone, LinkDirProcess, LinkDirIn, LinkDirOut, LinkDirInOut }
The C++ definition is identical. In Java 5 the definition would be:
public enum LinkDir { LinkDirNone, LinkDirProcess, LinkDirIn, LinkDirOut, LinkDirInOut };
struct
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; }
interface
An example of an interface definition is:
interface DbfBoolean extends Dbf { boolean get(); void put(boolean val); }
In C++ would be:
class DbfBoolean : public Dbf { public: virtual bool get() = 0; virtual void put(bool val) = 0; };
In Java would be:
interface DbfBoolean extends Dbf { boolean get(); void put(boolean val) }
class
For now only static class definitions are required. An example of a static class definition is:
static class RegisterSupport { link(SupportFactory support, string name); ... }
In C++ would be:
class RegisterSupport { public: static link(SupportFactory &support, int nameLength, char name[]); ... };
On Java would be:
public final class RegisterSupport { public static final link(SupportFactory support, string name); ... }
string
For C++ a string will be a char * array containing UTF-8 compatible characters not necessarily terminated with a null character. Wherever a string argument appears, the C++ definition will have len and char * arguments.
For Java string will just be a String. It is assumed that Java Strings will be converted to/from UTF-8 byte streams when the data is transfered to/from the network.
An example of a definition that includes a string argument is
void get(string name);
In C++ this will become
void get(int lenName, char *name);
In Java this will become
void get(String name);
array
An example of a definition that includes an array is:
void get(float64[] data);
In C++ ,this would become:
void get(int lenData, doible data[]);
In Java this would be:
void get(doible[] data);
C++ support for strings and arrays
Note that the support described here is not needed for Java since Java already provides facilities
string support
The following interfaces are for allocating tempory storage for strings:
class NonmutableString { public: void destroy(); // Call this when done with string int32 getLength(); char data[]; } class NonmutableStringFactory { public: static NonmutableString *create(int32 len,char data[]); }
class MutableString : public NonmutableString { public: int32 getCapacity(); void setLength(int32 len); } class MutableStringFactory { static MutableString *create(int32 int32 capacity); }
These will use free lists to manage the storage for the octet arrays.
array support
// ArrayCopy only works on primitive types class ArrayCopy { public: void copy(DbfArray from,DbfArray to); }
This only supports primitive types, i.e. DbfBoolean,...,DbfFloat64.
Arithmetic Type Conversions
static class DbfConvertPrimitive { public: int16 get(Dbf from); int32 get(Dbf from); int64 get(Dbf from); float32 get(Dbf from); float64 get(Dbf from); get(Dbf from, int32 lenValue,const *char value); get(DbfBoolean from, int32 lenValue,const *char value); put(Dbf to, int16 value); put(Dbf to, int32 value); put(Dbf to, int64 value); put(Dbf to, float32 value); put(Dbf to, float64 value); put(Dbf to,int32 lenValue,const *char value); put(DbfBoolean to, int32 lenValue,const *char value);
get(DbfArray from, int16 value[]); get(DbfArray from, int32 value[]); get(DbfArray from, int64 value[]); get(DbfArray from, float32 value[]); get(DbfArray from, float64 value[]); put(DbfArray to, int16 value[]); put(DbfArray to, int32 value[]); put(DbfArray to, int64 value[]); put(DbfArray to, float32 value[]); put(DbfArray to, float64 value[]); }
NOTES:
- For Dbf to and from must be one of DbfInt16, ..., DbfFloat64
- The get to a string uses printf semantics
- The put from a string value just uses scanf semantics.
- The DbfBoolean method supports all the choices specified in the DBD Record Instance Specification
- For DbfArray tt>to and from must be an array of one of DbfInt16, ..., DbfFloat64
DbfTypes
The following naming conventions are used:
- Dbf
- any class starting with Dbf describes a field in a header file generated from a struct or record definition. 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 DbdMenu describes a dbd menu 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 { basicTypeBoolean, // DbfBoolean basicTypeOctet, // DbfOctet basicTypeInt16, // DbfInt16 basicTypeInt32, // DbfInt32 basicTypeInt64, // DbfInt64 basicTypeFloat32, // DbfFloat32 basicTypeFloat64, // DbfFloat64 basicTypeString, // DbfString basicTypeArray, // DbfArray basicTypeStruct, // DbfStruct }
enum DbfType { dbfTypeBasic, // DbfBoolean,...,DbfStruct dbfTypeMenu, // DbfMenu dbfTypeEnum, // DbfEnum dbfTypeLink, // DbfLink dbfTypeDevice, // DbfDevice dbfTypeMDArray, // DbfMDArray dbfTypeTimeStamp // DbfTimeStamp }
Discussion of DbfTypes
The following shows the Java code generated from DBD files:
structure definitions
Two class implementations are generated from struct(name) definitions.
- A class named name
- A class named nameSupport
The class name implements:
interface Struct { Dbf getField(int16 index); }
If a structure is defined as:
struct(DisplayLimit) { field(low,double) field(high,double) }
A generated file DisplayLimit.java contains:
public class DisplayLimit implements Struct{ public DbfFloat64 low; public DbfFloat64 high; public static final short lowIndex = 1; public static final short highIndex = 2; public static final short lastIndex = indexHigh; Dbf getField(short index) { switch(index) { case lowIndex: return(low); case highIndex: return(high); default: throw java.lang.IllegalStateException; } return null; } }
A generated file DisplayLimitSupport.java contains:
public class DisplayLimitData { public double low; public double high; } public final class DisplayLimitSupport implements StructFactory{ public Struct create() { return new DisplayLimit; } public static final void get(DbfStruct from,DisplayLimitData data) { DbfFloat64 dbf = from.getInterface(1); data.low = dbf.get(); DbfFloat64 dbf = from.getInterface(2); data.high = dbf.get(); } public static final void put(DbfStruct to, DisplayLimitData data) { DbfFloat64 dbf = to.getInterface(1); dbf.put(data.low); DbfFloat64 dbf = to.getInterface(2); dbf.put(data.high); } }
public final class DisplayLimitSupportRegister { static public createAndRegister() { DisplayLimitSupport support = new DisplayLimitSupport; RegisterSupport.structure(support,"DisplayLimit"); } }
NOTE The V4 replacement for registerRecordDeviceDriver must call DisplayLimitSupportRegister.createAndRegister.
Similar files are generated for C++.
record definitions
If a record is defined as:
record(Example) extends IocRecord { ... field(fboolean,boolean) field(octet,octet) field(fint,int16) ... field(ffloat,float64) field(string,string) field(array,array(double[]) field(mdarray,array(double[,]) field(menu,menu(name)) field(fenum,enum) field(link,link(in)) field(device,link(in,analogIO)) field(displayLimit,struct(DisplayLimit)) }
The generated Java file is
public class ExampleRecord implements Struct { public DbfBoolean fboolean; public DbfOctet ctet; public DbfInt16 fint; ... public DbfFloat64 ffloat; public DbfString string; public DbfArray array; public DbfMDArray mdarray; public DbfMenu menu; public DbfEnum fenum; public DbfLink link; public DbfDevice device; public DbfStruct displayLimit; public static final int16 fbooleanIndex = 1; ... public static final int16 lastIndex = displayLimitIndex; Dbf getField(short index) { switch(index) { case fbooleanIndex : return(fboolean); ... case displayLimitIndex: return(displayLimit); default: throw java.lang.IllegalStateException; } } }
public final class ExampleRecordFactory implements StructFactory{ public static final Struct create() { return new ExampleRecord; } }
public final class ExampleRecordFactoryRegister { static public createAndRegister() { ExampleRecordFactory factory = new ExampleRecordFactory; RegisterSupport.record(factory,"ExampleRecord"); } }
NOTE The V4 replacement for registerRecordDeviceDriver must call ExampleRecordFactoryRegister.createAndRegister
Similar code is generated for C++.
Database Fields
Each database field is accessed via an interface which all extend the following interface:
interface Dbf{ DbfType getType(); boolean isPrimitive(); // BasicTypeBoolean,...,BasicTypeFloat64 boolean isBasic(); BasicType getBasicType(); DbRecord getRecord(); int16 getIndex(); }
The interfaces are designed as follows:
- Database Access provides access to the field without exposing the address.
- DbAccess posts monitors when a field is modified.
Database access by default allocates the actual storage for each field but allows support code to register itself to provide storage for field instances. This is particularly usefull for array fields. Two examples are:
- The compress record registers to provide storage for the value.
- This allows it to implement a circular buffer.
- Code that accesses the value field may have to issue two get requests.
- Device support for a transient recorder registers to provide storage for the array
- This allows device support to read data from hardware in segments
- Code that accesses the array may have to issue many get requests.
The fact the each field is an object means that additional storage is required. DbAccess will probably have something like the following:
class Field { DbRecord instance; short index; }; ... class IntField extends Field { int data; } ...
This each field has the overhead of
- instance - a reference to DbRecord, i.e. record instance
- index - a 16 bit integer
- vtbl - a reference to the object implementation
An additional pointer field will be needed for things like monitors. This field can start out null and only allocate additional storage as needed.
Primitive Types
DbfOctet, ..., DbfFloat64 are all interfaces with methods get and put.
interface DbfBoolean extends Dbf { boolean get(); void put(boolean 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 record; short 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 introspection interfaces described later in this document. For example code that expects a float64 field can access it via
DbAddr dbdAddr = LocateInstance.getPV("recordname.value"); if(dbdAddr==null) // do something Dbf dbf = dbdAddr.getField(); if(!dbf.isPrimitive() || (dbf.getBasicType() != basicTypeFloat64) ) // do something DbfFloat64 dbfdouble = (DbfFloat64)dbf; dbfdouble.put(10.0);
or more concisely (but exception may be thrown)
DbfFloat64 dbfdouble = DbfConvertPrimitive( LocateInstance.getPV("recordname.value").getField());
String fields
The interface for a string field is:
interface DbfString extends Dbf { int32 getLength(); void get(string value); void setPutSize(int32 size); void put(string value); }
The following code prints a string.
ExampleRecord record; String string; record.fstring.get(string); printf("%s\n",string);
Code that does not include the header file can use the introspection methods to locate the DbfString that provides access to the field.
Structure Fields
interface DbfStruct extends Dbf { int16 getNfields(); Dbf getInterface(int16 index); DbdField getDescription(int16 index); }
The following traverses the fields of a DbfStruct
DbfStruct dbfStruct; for(i=0; i < dbfStruct.getNfields(); i++) { DbdField dbdField = dbfStruct.getDescription(i); String name; dbdField.getName(name); printf("field %s\n",name); }
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 record; DisplayLimitData limit; ... DisplayLimitSupport.get(record.displayLimit,limit); printf("low %f high %f\n",limit.low,limit.high);
Array Fields
The generated header file will have a type that extends DbfArray
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 DbfBooleanArray extends DbfArray { int32 get(int32 offset, int32 len, boolean[] pto); int32 put(int32 offset, int32 len, boolean[] 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 record;
double[] data = new double[] {1.0,2.0,3.0};; if(!record.ffloat.isPrimitive() || record.ffloat.getBasicType()!=basicTypeFloat64) // DO SOMTHING!!!! ... array.put(0,nelements,precord->data);
or more concisely
ExampleRecord record; ... DbfConvertPrimitive.put(precord.array,new double[] {1.0,2.0,3.0});
As described above support can implement get and put, which can operate on array segments.
- 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.
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, LinkDirProcess, LinkDirIn, LinkDirOut, LinkDirInOut } interface DbfLink extends Dbf { LinkDir getDir(); DbdLink getDbdLink(); LinkSupport getSupport(); } interface DbfDevice extends Dbf { LinkDir getDir(); DbdDevice getDbdDevice(); 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.
DbdMenu
interface DbdMenu { int32 getNameLength( void getName(string name); int16 getNchoices(); int32 getChoiceNameLength(int16 index); void getChoice(int16 index,string choice); }
DbdLink and DbdDevice
interface DbdSupport { LinkDir getDir(); int32 getChoiceNameLength(); void getChoiceName(string name); int32 getSupportNameLength(); void getSupportName(string name); int32 getDataStructNameLength(); void getDataStructName(string name); } interface DbdLink extends DbdSupport{ } interface DbdDevice extends DbdSupport{ int32 getInterfaceNameLength(); void getInterfaceName(string name); }
DbdStruct and DbdRecord
interface DbdAttribute { int32 getDefaultLength(); void getDefault(string value); boolean isReadonly(); boolean isDesign(); boolean 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(string name); DbfType getType(); DbdDefaults getDefaults(); DbdAttribute getAttributes(); }
interface DbdStruct { int32 getNameLength(); void getName(string name); int16 getNumberFields(); DbdField getFieldDescription(int16 index); }
interface DbdRecord { int32 getNameLength(); void getName(string name); int16 getNumberFields(); DbdField getFieldDescription(int16 index); DbdRecordSupport getSupport(); }
Record Instance
interface DbRecord { int32 getNameLength(); void getName(string name); DbdRecord getDescription(); Dbf getPV(string fieldName); }
Locate Interfaces
Classes are available to find and traverse the various Dbd definitons and record instances. The implementation will be language specific. For Java they will be something like the following:
In addition the following is defined:
public class DbdLocate { public DbdMenu getMenu(String name); public DbdLink getLink(String name); public DbdDevice getDevice(String name); public DbdStruct getStruct(String name); public DbdRecord getRecord(String name); public LinkedList<DbdMenu> menuList; public LinkedList<DbdLink> linkList; public LinkedList<DbdDevice> deviceList; public LinkedList<DbdStruct> structList; public LinkedList<DbdRecord> recordList; }
public class DbInstance { public DbRecord getRecord(String name); public Dbf getField(string name); public Dbf getField(string recordName, string fieldName); public LinkedList<DbRecord> instanceList; public LinkedList<DbRecord> instanceList(String recordTypeName); }
Question Are the above methods static or should there be something like
public class FindLocator { public static DbdLocate findDbdLocate(); public static DbInstance findDbInstance(); }
The following locates a specific menu.
DbdMenu menu = DbdLocate.get("DisplayLimit"); if(menu!=null) printf("found menu %s\n","DisplayLimit");
The following locates a field of a record instance.
Dbf field = DbInstance.getField("example.value"); if(addr!=null) printf("found %s\n","example.value");