Difference between revisions of "V4 Design: dbdClass"

From EPICSWIKI
(Still making changes)
 
(23 intermediate revisions by the same user not shown)
Line 1: Line 1:
== EPICS: C++ class definitions for Database Definition ==
This page is obsolete. It is replaced by dbdInterfaces.
 
May 17 2005
 
<center>
 
== Overview ==
 
</center>
 
This document describes the C++ class definitions for code that implements
the semantics for 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:
** <tt>record</tt>
** <tt>struct</tt>
** <tt>menu</tt>
*  does not include the header files.
 
The following headers files are described:
* <tt>epicsTypes.h</tt> - A set of primitive types that are part of <tt>base/src/libCom</tt>
* <tt>dbdTypes.h</tt> - Type definitions for non-primitive <field> definitions in <struct> or <record> DBD definitions.
* <tt>dbdStatements.h</tt>  - Type definitions for DBD statements.
* <tt>dbdInterfaces.h</tt> - Type definitions for interfaces related to DBD definitions.
 
----
<center>
 
== epicsTypes ==
 
</center>
=== <tt>epicsTypes.h</tt> ===
<tt>epicsTypes.h</tt> defines a set of primitive tupes. It is used because the <tt>C99<tt> standard does not define the exact number of bits for the primitive data types. It only defines the minimum number of bits.
 
In addition two extra types are defined:
* epicsUnknownT - Unknown
* epicsOctetT - An 8 bit byte.
 
<tt>epicsTypes.h</tt> contains the following:
 
enum epicsType {
    epicsUnknownT,
    epicsBooleanT,
    epicsOctetT,
    epicsInt16T,
    epicsUInt16T,
    epicsInt32T,
    epicsUInt32T,
    epicsInt64T,
    epicsUInt64T,
    epicsFloat32T,
    epicsFloat64T,
};
 
/* some of the following may require OSD definitions*/
typedef bool              epicsBoolean;
typedef char              epicsOctet;
typedef short              epicsInt16;
typedef unsigned short    epicsUInt16;
typedef int                epicsInt32;
typedef unsigned int      epicsUInt32;
typedef long long          epicsInt64;
typedef unsigned long long epicsUInt64;
typedef float              epicsFloat32;
typedef double            epicsFloat64;
 
=== Discussion of epicsTypes ===
 
 
The types epicsBoolean, epicsOctet, epicsInt16, epicsUInt16, epicsInt32, epicsUInt32, epicsInt64,  epicsUInt64, epicsFloat32, epicsFloat64 all map to a C  or C++ primitive type. It may be necessary to provide operating system dependent definitions for some of the types. For example on some architectures a epicsInt64 may have to be defined as a <tt>long</tt> rather than a <tt>long long</tt>.
 
If a record is defined as:
    record(xxx) extends iocRecord {
        ...
        field(fbool,bool)
        field(foctet,octet)
        ...
        field(ffloat64,float64)
        ...
    }
Then the generated header file will be
    class xxxRecord : iocRecord {
    public:
        epicsBoolean fbool;
        epicsOctet  foctet;
        ...
        epicsFloat64 ffloat64;
        ...
    };
 
<tt>epicsType epicsTypeUnknownT</tt> is reserved for unknown types and will normally be cause by some configuration error.
 
----
<center>
 
== dbdTypes ==
 
</center>
=== <tt>dbdTypes.h</tt> ===
File dbdTypes.h describes the non-primitive types used by V4 databases:
The following naming conventions are used:
; Dbf
: any class starting with Dbf describes a struct or record field. For example DbfString describes a field(name,string).
; *Dbd*
: A class name that has Dbd imbeded in it describes something directly related to a dbd statement. For example LinkDbdSupport describes a dbd link definition.
 
<tt>dbdTypes.h</tt> contains the following:
#include <epicsTypes.h>
enum dbdType {
    dbdUnknownT = epicsUnknownT,
    dbdBooleanT = epicsBooleanT,
    dbdOctetT = epicsOctetT,
    dbdInt16T = epicsInt16T,
    dbdUInt16T = epicsUInt16T,
    dbdInt32T = epicsInt32T,
    dbdUInt32T = epicsUInt32T,
    dbdInt64T = epicsInt64T,
    dbdUInt64T = epicsUInt64T,
    dbdFloat32T = epicsFloat32T,
    dbdFloat64T = epicsFloat64T,
    DbfStringT,
    dbdStructT,
    DbfArrayT,
    // dbdNdimArrayT not yet defined
    dbdEnumT,
    dbdMenuT,
    dbdLinkT,
    dbdDeviceT
};
 
/*DbfString holds UTF-8 characters*/
class DbfString {
public:
    dbdInt32  capacity;  /*capacity in bytes*/
    dbdOctet  *pstorage;
};
 
// FieldDbdPtr is the address of a dbdType
typedef void *FieldDbdPtr;
// StructDbd is base class for classes implementing struct
class StructDbd {};
 
// Interface is base class for an interface
class Interface {};
class InterfaceLocator {
public:
    DbfString name;
    Interface *pinterface;
};
 
// The following are described  in dbdStatements.h
class StructDbdDef; //describes a dbd struct definition
class MenuDbdDef; //describes a dbd menu definition
class LinkDbd;    //describes dbd link statement
class DeviceDbd;  //describes dbd device statement
 
class DbfStruct{
public:
    StructDbdDef *pstructDef;
    StructDbd    *pstruct; // address of storage
};
 
template< class ARR_T > class DbfArray {
public:
    dbdInt32  capacity;  /*capacity in number of elements*/
    dbdInt32  size;      /*current number of elements*/
    dbdType  type;
    ARR_T    *pstorage;
};
 
/*  The following array types are supported by dbdCore
  *  DbfArray<void>;
  *  DbfArray<dbdOctet>;
  *  DbfArray<dbdInt16>;
  *  DbfArray<dbdUInt16>;
  *  DbfArray<dbdInt32>;
  *  DbfArray<dbdUInt32>;
  *  DbfArray<dbdInt64>;
  *  DbfArray<dbdUInt64>;
  *  DbfArray<dbdFloat32>;
  *  DbfArray<dbdFloat64>;
  *  DbfArray<DbfString>;
  *  DbfArray<dbdLinkField>;
**/
 
class DbfMenu{
public:
    dbdInt16    index;
    MenuDbdDef  *pmenuDef; /* address of global menu */
};
 
class DbfEnum{
public:
    dbdInt16  index;
    MenuDbdDef *pmenuDef; /* address of record instance menu */
};
enum LinkDir {
    LinkDirNone,
    LinkDirForward,
    LinkDirIn,
    LinkDirOut,
    LinkDirInOut
};
 
class DbfLink{
public:
    LinkDir  dir;
    LinkDbd  *plinkDef;
    DbfStruct dataStruct;
};
 
class DbfDevice{
public:
    LinkDir  dir;
    DeviceDbd *pdeviceDef;
    DbfStruct dataStruct;
};
 
=== Discussion of dbdTypes ===
 
==== Primitive Types ====
The types dbdBoolean, dbdOctet, dbdInt16, dbdUInt16, dbdInt32, dbdUInt32, dbdInt64,  dbdUInt64, dbdFloat32, dbdFloat64 all map to an epicsType.
==== DbfString ====
<tt>DbfString</tt> is described as:
    class DbfString {
    public:
        dbdInt32  capacity;  /*capacity in bytes*/
        dbdOctet  *pstorage;
    };
If a record definition contains
    field(sfield,string)
Then the generated header file contains
    DbfString sfield;
 
<tt>pstorage</tt>will always be the address of a UTF-8 null terminated character string. The <tt>capacity</tt> is the the number of bytes referenced by <tt>pstorage</tt> NOT the number of characters.
 
A support library and rules must be created for managing DbfStrings.
 
==== DbfStruct ====
 
<tt>DbfStruct></tt> is described as:
    class DbfStruct{
    public:
        StructDbdDef *pstructDef;
        StructDbd    *pstruct; // address of storage
    };
 
If a record definition contains
    field(sstruct,struct(name))
Then the generated header file contains
    DbfStruct sfield;
<tt>pstruct</tt> is the address of storage for the structure and <tt>pstructDef</tt> is the address of a description of the structure. StructDbdDef is described in <tt>dbdStatatements.h</tt>
 
Note that given a dbdStruct it is possible to locate both the address and description of the associated structure.
 
==== DbfArray ====
 
Discussion needed. Note that multi-dimensional arrays must also be described.
 
==== DbfMenu ====
<tt>dbdMenu></tt> is described as:
    class DbfMenu{
    public:
        dbdInt16    index;
        MenuDbfDef  *pmenuDef;
    };
 
If a record definition contains
    field(fmenu,menu(name))
Then the generated header file contains
    DbfMenu fmenu;
The definition of dbdMenu provides the current menu index and also the menu definition.
 
==== DbfEnum ====
<tt>DbfEnum></tt> is described as:
    class DbfEnum{
    public:
        dbdInt16  index;
        MenuDbdDef *pmenuDef; /* address of record instance menu */
    };
 
If a record definition contains
    field(fenum,enum)
Then the generated header file contains
    DbfEnum fenum;
Note that the definition of DbfEnum looks identical to DbfMenu. The difference
is that DbfMenu has the address of a global MenuDbfDef but DbfEnum has the addrsss of a MenuDbfDef that belongs to the record instance.
==== DbfLink ====
<tt>DbfLink</tt> is described as
    class DbfLink{
    public:
        LinkDir  dir;
        LinkDbd  *plinkDef;
        DbfStruct dataStruct;
    };
If a record definition contains
    field(flink,link(in))
Then the generated header file contains
    DbfLink flink;
The fields of DbfLink are initialized by locating a dbd <tt>link</tt> definition that matches the <tt>dir</tt> specified in the dbd <tt>field</tt> definition.
 
The fields of <tt>DbfLink</tt> are initialized as follows:
; <tt>dir</tt>
: This is taken from either the <tt>field</tt> definition or from the <tt>LinkDbd</tt> definition and is the most restrictive. For example if one says inout and the other says in then <tt>dir</tt> will be in.
; <tt>choiceName</tt>
: The record instance specifies this and it is used to locate the associated dbd <tt>link</tt> definition.
; <tt>plinkDef</tt>
: This is the address of the <tt>LinkDbd</tt>.
; <tt>dataStruct</tt>
: The describes the data structure specified in the dbd <tt>link</tt> definition. It contains data used by the link support.
 
Note that link support always implements interface <tt>LinkDbdSupport</tt>
==== dbdDevice ====
 
A <tt>dbdDevice</tt> is similar to a <tt>dbdLink</tt> except that the interface implemented by the device support is also specified, i.e. instead of implementing interface <tt>LinkDbdSupport</tt>, the device support implements an interface that both record support and device support understand.
 
 
----
<center>
 
== dbdStatements ==
 
</center>
 
=== <tt>dbdStatements.h</tt> ===
 
<tt>dbdStatements.h</tt> contains the following:
 
class StructFieldAttribute {
    DbfString  default;
    dbdBoolean readonly;
    dbdBoolean design;
    dbdBoolean special;
    dbdBoolean dynamic;
    epicsInt16 asl;
};
 
class StructDbdField {
public:
    DbfString name;
    dbdType  type;
    StructFieldAttribute *pattribute;
};
 
class StructDbdDef{
public:
    DbfString    name;
    Interface    *plifetime; // references a StructDbdLifetime
    dbdInt16    nfields;
    StructDbdField *pfields[]; // ptr to array of ptr to StructDbdField
};
 
class MenuDbdChoice {
    DbfString choiceName;
    DbfString menuName;
}
 
class MenuDbdDef{
public:
    DbfString name;
    dbdInt16  nchoices;
    MenuDbdChoice *pchoice[];
};
 
class LinkDbd{ //describes dbd link statement
public:
    LinkDir    dir;
    DbfString  choiceName;
    DbfString  dataStructName;
    Interface  *pinterface;
};
 
class DeviceDbd { //describes dbd device statement
public:
    LinkDir  dir;
    DbfString interfaceName;
    DbfString choiceName;
    DbfString dataStructName;
    Interface *pinterface;
};
 
// The following describes record types and record instances
class UserDbdField;
class userFieldHandler {
public:
    virtual bool initialize(dbfString *errorMessage,
                      iocRecord *precord,UserDbdField *puserField) = 0;
    virtual bool finalize(dbfString *errorMessage,
                      iocRecord *precord,UserDbdField *puserField) = 0;
    virtual bool process(dbfString *errorMessage,
                      iocRecord *precord,UserDbdField *puserField) = 0;
};
 
class UserDbdField {
public:
    dbfString  name;
    dbfType    type;
    FieldDbdPtr pfield;
    InterfacePtr *pinterface; // references userFieldHandler
}
 
class RecordDbdField {
public:
    dbfString name;
    dbfType  type;
};
 
class RecordDbd { // describes a record type
    dbfArray< UserDbdField > userField;
    dbfArray< RecordDbdField > recField;
    Interface    *plifetime; // references a StructDbdLifetime
}
 
=== Discussion of dbdStatements ===
The classes in <tt>dbdStatements.h</tt> allow introspection of ioc records. They describe everything defined in DBD definitions.
==== Struct ===
The Struct classes describe the fields in a dbd <tt>struct</tt> or <tt>record</tt> definition. The classes are : <tt>StructDbdDef</tt>, <tt>StructDbdField</tt>,and <tt>StructFieldAttribute</tt>
The fields of <tt>StructDbdDef</tt> are:
; <tt>name</tt>
: The name of the struct.
; <tt>plifetime</tt>
: The address of an implementation of interface <tt>StructDbdLifetime</tt>. The implementation is automatically generated from the dbd <tt>struct</tt> statement. See below for a description of the <tt>StructDbdLifetime</tt> methods.
; <tt>nfields</tt>
: The number of fields, e.g. fields in the structure.
; <tt>pfields</tt>
: pointer to an array of pointers to <tt>StructDbdField</tt>. Each StructDbdField contains the name and type of the fields.
 
The fields of <tt>StructDbdField</tt> are:
; <tt>name</tt>
: The name of the field
; <tt>type</tt>
: The dbfType for the field.
; <tt>pattribute</tt>
: The address of a StructFieldAttribute for the field
 
The fields of <tt>StructFieldAttribute</tt> show the falue of the attributes for the field.
 
==== Menu ===
 
A dbd <tt>menu</tt> is described by the classes: MenuDbdDef and MenuDbdChoice
 
The fields of MenuDbdDef are:
; <tt>name</tt>
: The menu name.
; <tt>nchoices</tt>
: The number of menu choices.
; <tt>pchoice</tt>
: The address of an array of pointers to choices
 
The fields of MenuDbdChoice described a single choice:
; <tt>choiceName</tt>
: The choice name, i.e. the C++ variable name that appears in the generated enum statement for the menu
; <tt>menuName</tt>
: The menu choice that DCTs and the value returned when the menu choice strings are requested.
 
=== Link and Device ===
 
Each dbd <tt>link</tt> definition has an associated class LinkDbd with fields:
; <tt>dir</tt>
: The link direction
; <tt>choiceName</tt>
: The name that to find a LinkDbd for a DbfLink instance.
; <tt>dataStructName</tt>
: The class name of a DbfStruct for the Interface implementation
; <tt>pinterface</tt>
: The address of the Interface implementation. The interface class is LinkDbdSupport
 
Each dbd <tt>device</tt> definition has an associated class DeviceDbd with fields:
; <tt>dir</tt>
: The link direction
; <tt>interfaceName</tt>
: The name of the interface class implemented by the device support
; <tt>choiceName</tt>
: The name that to find a LinkDbd for a DbfLink instance.
; <tt>dataStructName</tt>
: The class name of a DbfStruct for the Interface implementation
; <tt>pinterface</tt>
: The address of the Interface implementation. The interface class is LinkDbdSupport
----
<center>
 
== dbdInterfaces.h ==
 
</center>
 
=== <tt>dbdInterfaces.h</tt> ===
<tt>dbdInterfaces.h</tt> contains the following:
 
// every struct and every record support module implements the following
// The implementation is generated from the dbd definition
class StructDbdLifetime {
public:
    virtual StructDbdPtr create() = 0;
    virtual bool initialize(dbfString *errorMessage,
                              StructDbdPtr ptr) = 0;
    virtual bool finalize(dbfString *errorMessage,
                              StructDbdPtr ptr) = 0;
    virtual void destroy(StructDbdPtr ptr) = 0;
    virtual void *indexToAddr(dbfString *errorMessage,
                              StructDbdPtr ptr, dbfInt16 index) = 0;
    // ???? is anything else needed
};
 
// every link support module implements the following interface
class LinkDbdSupport {
public:
    virtual void report(dbfString *errorMessage,
                      iocRecord *precord, dbfLink *pdbfLink) = 0;
    virtual bool initialize(dbfString *errorMessage,
                      iocRecord *precord, dbfLink *pdbfLink) = 0;
    virtual bool finalize(dbfString *errorMessage,
                      iocRecord *precord, dbfLink *pdbfLink) = 0;
    virtual bool connect(dbfString *errorMessage,
                      iocRecord *precord, dbfLink *pdbfLink) = 0;
    virtual bool disconnect(dbfString *errorMessage,
                      iocRecord *precord, dbfLink *pdbfLink) = 0;
    virtual bool get(dbfString *errorMessage,
                      iocRecord *precord, dbfLink *pdbfLink,
                      dbfType type, FieldDbdPtr pfield) = 0;
    virtual bool put(dbfString *errorMessage,
                      iocRecord *precord, dbfLink *pdbfLink,
                      dbfType type, FieldDbdPtr pfield) = 0;
};
 
/* record support implements the following*/
class RecordDbdSupport {
public:
    virtual iocRecord *create(dbfString *errorMessage) = 0;
    virtual bool destroy(dbfString *errorMessage, iocRecord *precord) = 0;
    virtual bool init(dbfString *errorMessage,
                      iocRecord *precord, bool firstPass) = 0;
    virtual void special(iocRecord *precord, iocRecord *precord,
            bool  after,
            dbfInt16 nlevels, // number of elements in fieldIndex
            dbfInt16 fieldIndex[] // array of field indices
            ) = 0;
};
 
=== Discussion of dbdInterfaces ===
==== <tt>StructDbdLifetime</tt> ====
Every dbd <tt>struct</tt> and <tt>record</tt> has an associated <tt>StructDbdLifetime</tt> interface implementation. A tool is provided that automatically generates the implementation form the dbd definition.
<tt>StructDbdLifetime</tt> is described as:
    class StructDbdLifetime {
    public:
        virtual StructDbdPtr create() = 0;
        virtual bool initialize(dbfString *errorMessage,
                                  StructDbdPtr ptr) = 0;
        virtual bool finalize(dbfString *errorMessage,
                                  StructDbdPtr ptr) = 0;
        virtual void destroy(StructDbdPtr ptr) = 0;
        virtual void *indexToAddr(dbfString *errorMessage,
                                  StructDbdPtr ptr, dbfInt16 index) = 0;
        // ???? is anything else needed
    };
where:
; <tt>create</tt>
: Creates storage for the struct or record.
; <tt>initialize</tt>
: initializes the struct or record
; <tt>finalize<tt>
: cleans up but does not free storage
; <tt>destroy</tt>
: frees storage
; indexToAddr
: Given an index it returns the address of the storage. Note the the generated header files assign an index to each field.
 
==== <tt>LinkDbdSupport</tt> ====
Not yet described
 
==== <tt>RecordDbdSupport</tt> ====
Not yet described
 
----
<center>
 
== Example of Generated Header Files ==
 
</center>
 
=== Database Definition Files ===
 
<tt>menuAlarmSevr.dbd</tt> contains:
    menu(menuAlarmSevr) {
          choice(menuAlarmSevrNO_ALARM,"NO_ALARM")
          choice(menuAlarmSevrMINOR,"MINOR")
          choice(menuAlarmSevrMAJOR,"MAJOR")
          choice(menuAlarmSevrINVALID,"INVALID")
    }
 
<tt>displayLimit.dbd</tt> contains:
    struct(displayLimit) {
        field(low,float64)
        field(high,float64)
    }
<tt>exampleRecord.dbd</tt> contains:
    record(example) extends iocRecord {
        field(value,float64)
        field(displayLimit,struct(displayLimit))
    }
<tt>alltypesRecord.dbd</tt> contains:
    record(allTypes) extends iocRecord {
        field(fbool,bool)
        field(foctet,octet)
        field(fint16,int16)
        field(fuint16,uint16)
        field(fint32,int32)
        field(fuint32,uint32)
        field(fint64,int64)
        field(fuint64,uint64)
        field(ffloat32,float32)
        field(ffloat64,float64)
        field(fstring,string)
        field(fmenu,menu(menuName))
        field(fenum,enum)
        field(fstruct,struct(displayLimit))
        field(flink,link(dir))
        field(fdevice,device(dir,interfaceName))
    }
=== Generated Header Files ===
Tools are provided to generate header files from the following dbd definitions:
*menu
*struct
*record
<tt>menuAlarmSevr.h</tt> is generated from <tt>menuAlarmSevr.dbd</tt>
    enum menuAlarmSevr {
            menuAlarmSevrNO_ALARM,
            menuAlarmSevrMINOR,
            menuAlarmSevrMAJOR,
            menuAlarmSevrINVALID
    };
<tt>displayLimit.h</tt> is generated from <tt>displayLimit.dbd</tt>
    class displayLimit {
    public:
        dbfFloat64 low;
        dbfFloat64 high;
    };
    const dbfInt16 displayLimit_firstIndex = 1
    const dbfInt16 displayLimit_low        = 1
    const dbfInt16 displayLimit_high      = 2
    const dbfInt16 displayLimit_lastIndex =displayLimit_high
<tt>exampleRecord.h</tt> is generated from <tt>exampleRecord.dbd</tt>
    class exampleRecord {
    public:
        ...    All the fields from iocRecord.dbd
        dbfFloat64 value;
        dbfStruct  displayLimit;
    };
   
    const dbfInt16 example_firstIndex = 1001001
    const dbfInt16 example_low = 1001001;
    const dbfInt16 example_high = 1001002;
    const dbfInt16 example_lastIndex = example_high;
<tt>alltypesRecord.h</tt> is generated from <tt>alltypesRecord.dbd</tt>
    class allTypesRecord {
    public:
        ...    All the fields from iocRecord.dbd
        iocRecord  common;
        dbfBoolean fbool;
        dbfOctet  foctet;
        dbfInt16  fint16;
        dbfUInt16  fuint16;
        dbfInt32  fint32;
        dbfUInt32  fuint32;
        dbfInt64  fint32;
        dbfUInt64  fuint32;
        dbfFloat32 ffloat32;
        dbfFloat64 ffloat64;
        dbfString  fstring;
        dbfMenu    fmenu;
        dbfEnum    fenum
        dbfStruct  fstruct;
        dbfLink    flink;
        dbfDevice  fdevice;
    };
   
    const dbfInt16 allTypes_firstIndex = 1001001
    const dbfInt16 allTypes_fbool = 1001001;
    const dbfInt16 allTypes_foctet = 1001002;
    const dbfInt16 allTypes_fint16 = 1001003;
    const dbfInt16 allTypes_fuint16 = 1001004;
    const dbfInt16 allTypes_fint32 = 1001005;
    const dbfInt16 allTypes_fuint32 = 1001006;
    const dbfInt16 allTypes_fint64 = 1001007;
    const dbfInt16 allTypes_fuint64 = 1001008;
    const dbfInt16 allTypes_ffloat32 = 1001009;
    const dbfInt16 allTypes_ffloatn64 = 10010010;
    const dbfInt16 allTypes_ffstring = 10010011;
    const dbfInt16 allTypes_fmenu = 10010012;
    const dbfInt16 allTypes_fenum = 10010013;
    const dbfInt16 allTypes_fstruct = 10010014;
    const dbfInt16 allTypes_flink = 10010015
    const dbfInt16 allTypes_fdevice = 10010016
    const dbfInt16 allTypes_lastIndex = allTypes_fdevice;
 
----

Latest revision as of 19:53, 11 August 2005

This page is obsolete. It is replaced by dbdInterfaces.