Difference between revisions of "V4 DBD Generated Code"

From EPICSWIKI
 
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
== EPICS: Code generated from DBD ==
Obsolete relpaced by "V4 Design: Runtime interfaces"
 
April 29 2005
 
 
== WARNING: This contains 1/2 baked ideas. Needs lots of work!!! ==
 
<center>
 
== Overview ==
 
</center>
 
This is the beginning of the task of deciding what code should be generated from the V4 database definition files. So far the following are discussed:
 
* code that implements a dataAccess interface.
* A header file for use by record support.
* Code that provides access without requiring the generated header file
* Code that provides a dataAccess interface.
 
The general scheme is to generate the following from each <tt>xxx.dbd</tt> file:
 
* <tt>xxx.h</tt>
This contains a <tt>struct</tt> definition that contains only data. The record support module uses this to access the record.
* <tt>xxxMeta.cpp</tt>
This implements an <tt>iocStructMetaSupport</tt>, which is described below, for accessing data without requiring the generated header file.
* <tt>xxxDA.h</tt>
This contains a <tt>class</tt> definition which is uses for dataAccess.
* <tt>xxxDA.cpp</tt>
This implements the dataAccess interface to xxx. All access from outside the record uses this interface to access the record.
 
The above files are generated for each <tt> struct</tt> and <tt>record</tt> definition.
 
----
<center>
 
== Example Database Definition Files ==
 
</center>
 
The following Database Definition Files are used as examples.
 
* <tt>displayLimit.dbd</tt> contains:
struct(displayLimit) {
    field(low,float64)
    field(high,float64)
}
* <tt>exampleRecord.dbd</tt> contains:
include "dbCommon.dbd"
record(example) extends iocRecord {
    field(value,float64)
    field(displayLimit,struct(displayLimit))
}
* <tt>alltypesRecord.dbd</tt> contains:
include "dbCommon.dbd"
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))
}
 
----
<center>
 
== iocTypes.h ==
 
</center>
 
File iocTypes.h describes the datatypes used by V4 databases:
 
<nowiki>/* TBD iocNdimArrayT*/
enum iocType {
    iocUnknownT,iocBooleanT,iocOctetT,
    iocInt16T,iocUInt16T,iocInt32T,iocUInt32T,iocInt64T,iocUInt64T,
    iocFloat32T,iocFloat64T,
    iocStringT,iocMenuT,iocEnumT,iocLinkT,iocDeviceT,iocArrayT
};
 
/* some of the following may require OSD definitions*/
typedef bool              iocBoolean;
typedef char              iocOctet;
typedef short              iocInt16;
typedef unsigned short    iocUInt16;
typedef int                iocInt32;
typedef unsigned int      iocUInt32;
typedef long long          iocInt64;
typedef unsigned long long iocUInt64;
typedef float              iocFloat32;
typedef double            iocFloat64;
 
class iocRecord;
 
/* iocStructPtr always references a class that contains only data*/
typedef void * iocStructPtr;
 
/* iocInterfacePtr always references a class that contains only methods*/
typedef void *iocInterfacePtr;
 
class iocInterface {
    const char      *interfaceType;
    iocInterfacePtr *pinterface;
};
 
/*iocString holds UTF-8 characters*/
class iocString {
public:
    iocInt32  capacity;  /*capacity in bytes*/
    iocOctet  *pstorage;
};
 
class iocStructMember {
    iocString name;
    iocType  type;
};
 
class iocStructDef{
    iocString      name;
    iocInt16        nmembers;
    iocStructMember *pmember[];
    iocInterface    interface;
};
 
class iocStructField{
    iocStructDef *piocStructDef;
    iocStructPtr ptr;
};
 
class iocMenuDef{
public:
    iocString name;
    iocInt16  nchoices;
    iocString *pchoice[];
};
 
class iocMenuField{
public:
    iocInt16    index;
    iocMenuDef  *piocMenuDef[];
};
 
class iocEnumField{
public:
    iocInt16  index;
    iocInt16  nchoices;
    iocString *pchoice[];
};
 
enum iocLinkDir {
    iocLinkDirNone,
    iocLinkDirForward,
    iocLinkDirIn,
    iocLinkDirOut,
    iocLinkDirInOut
};
 
enum iocLinkType {
    iocLinkTypeconstant,
    iocLinkTypepvlink,
    iocLinkTypecalink,
    iocLinkTypedblink
};
 
class iocLinkDef{
public:
    iocString    choice;
    iocLinkDir    dir;
    iocString    configName;
    iocString    interfaceName;
    iocInterface *piocInterface;
};
class iocLinkField{
public:
    iocLinkType type;
    iocLinkDef  linkDef;
    iocString  pvname;
    iocStruct  config;
};
 
class iocDeviceDef {
public:
    iocString    choice;
    iocLinkDir  dir;
    iocString    configName;
    iocInterface interface;
};
class iocDeviceField {
public:
    iocDeviceDef device;
    iocStruct    config;
};
 
template< class ARR_T > class iocArray {
public:
    iocInt32  capacity;  /*capacity in number of elements*/
    iocInt32  size;      /*current number of elements*/
    iocType  type;
    ARR_T    *pstorage;
};
 
/*  The following array types are supported by iocCore
  *  iocArray<void>;
  *  iocArray<iocOctet>;
  *  iocArray<iocInt16>;
  *  iocArray<iocUInt16>;
  *  iocArray<iocInt32>;
  *  iocArray<iocUInt32>;
  *  iocArray<iocInt64>;
  *  iocArray<iocUInt64>;
  *  iocArray<iocFloat32>;
  *  iocArray<iocFloat64>;
  *  iocArray<iocString>;
  *  iocArray<iocLinkField>;
**/
 
/* every struct and every record support module implements the following*/
class iocStructMetaSupport {
    virtual iocStructPtr create() = 0;
    virtual iocBoolean initialize(iocString *errorMessage, iocStructPtr ptr) = 0;
    virtual iocBoolean finalize(iocString *errorMessage, iocStructPtr ptr) = 0;
    virtual void destroy(iocStructPtr ptr) = 0;
    virtual void *indexToAddr(iocString *errorMessage,
            iocStructPtr ptr, iocInt16 index) = 0;
    // ???? is anything else needed
};
 
/* record support implements the following*/
class iocRecordSupport {
    virtual void special(iocRecord *piocRecord,
            iocBoolean  after,
            iocInt16 nlevels, // number of elements in fieldIndex
            iocInt16 fieldIndex[] // array of field indices
            ) = 0;
};</nowiki>
 
----
<center>
 
== Generated Record Support files ==
 
</center>
 
=== displayLimit.dbd ===
 
From this file the following two files are generated for use by record support.
 
* File <tt>displayLimit.h</tt> contains:
class displayLimit {
public:
    iocFloat64 low;
    iocFloat64 high;
};
const iocInt16 displayLimit_low = 0;
const iocInt16 displayLimit_high = 1;
const iocInt16 displayLimit_lastIndex = displayLimit_high;
epicsExtern iocStructMetaSupport *pdisplayLimitMetaSupport;
* File <tt>displayLimitMeta.cpp</tt> contains:
class displayLimitMetaSupport : public iocStructMetaSupport
{
    iocStructPtr create();
    iocBoolean initialize(iocString *errorMessage, iocStructPtr ptr);
    iocBoolean finalize(iocString *errorMessage, iocStructPtr ptr);
    void destroy(iocStructPtr ptr);
    void *indexToAddr(iocString *errorMessage,
            iocStructPtr ptr, iocInt16 index);
}
iocStructMetaSupport *pdisplayLimitMetaSupport;
iocStructPtr displayLimitMetaSupport::create() {return new displayLimit;}
iocBoolean displayLimitMetaSupport::initialize(
        iocString *errorMessage,iocStructPtr ptr)
{
    displayLimit *pdisplayLimit = prt;
    pdisplayLimit->low = 0;
    pdisplayLimit->high = 0;
    return iocTrue;
}
iocBoolean displayLimitMetaSupport::finalize(
        iocString *errorMessage,iocStructPtr ptr)
{ return iocTrue}
void displayLimitMetaSupport::destroy(iocStructPtr ptr) {delete ptr;}
void * displayLimitMetaSupport::indexToAddr(iocString *errorMessage,
    iocStructPtr ptr, iocInt16 index)
{
    displayLimit *pdisplayLimit = ptrptr;
    switch(index) {
        case displayLimit_low:  return (void *)&pdisplayLimit->low;
        case displayLimit_high: return (void *)&pdisplayLimit->high;
        default: break;
    }
    // write a message to errorMessage How?
    return null;
}
static void displayLimitRegister(void)
{
    pdisplayLimitMetaSupport = new displayLimitMetaSupport;
    // NOTE MUST ALSO register interface
}
epicsExportRegistrar(displayLimitRegister);
 
=== exampleRecord.dbd ===
 
From this files the following two files are generatedp>
 
* File <tt>exampleRecord.h</tt> contains:
class exampleRecord : iocRecord {
public:
    iocFloat64 value;
    iocStruct  displayLimit;
};
const iocInt16 exampleRecord_firstIndex = 1001
const iocInt16 exampleRecord_value = 1001;
const iocInt16 exampleRecord_displayLimit = 1002;
const iocInt16 exampleRecord_lastIndex = exampleRecord_displayLimit;
epicsExtern iocStructMetaSupport *pexampleRecordMetaSupport;
* File <tt>exampleRecordMeta.cpp</tt> contains:
class exampleRecordMetaSupport : public iocClassMetaSupport
{
    iocStructPtr create();
    iocBoolean init(iocString *errorMessage, iocStructPtr ptr);
    void destroy(iocStructPtr ptr);
    void *indexToAddr(iocString *errorMessage,
            iocStructPtr ptr, iocInt16 index);
}
iocClassMetaSupport *pexampleRecordMetaSupport;
iocStructPtr exampleRecordMetaSupport::create() { return new exampleRecord}
iocBoolean exampleRecordMetaSupport::initialize(
        iocString *errorMessage,iocStructPtr ptr)
{
    exampleRecord *pexampleRecord = ptr;
    if(piocRecordMetaSupport->initialize(errorMessage,pexampleRecord)==iocFalse)
        return iocFalse;
    pexampleRecord->value = 0;
    return iocTrue;
}
iocBoolean exampleRecordMetaSupport::finalize(
        iocString *errorMessage,iocStructPtr ptr)
{
    exampleRecord *pexampleRecord = ptr;
    if(piocRecordMetaSupport->finalize(errorMessage,pexampleRecord)==iocFalse)
        return iocFalse;
    pexampleRecord->value = 0;
    return iocTrue;
}
void exampleRecordMetaSupport::destroy(iocStructPtr ptr)
{
    // Most records have much more to do
    delete ptr;
}
void * exampleRecordMetaSupport::indexToAddr(iocString *errorMessage,
    iocStructPtr ptr, iocInt16 index)
{
    exampleRecord *pexampleRecord = ptrptr;
    switch(index) {
        case exampleRecord_common:
                    return (void *)&pexampleRecord->common;
        case exampleRecord_value:
                    return (void *)&pexampleRecord->value;
        case exampleRecord_displayLimit:
                    return (void *)&pexampleRecord->displayLimit;
        default: break;
    }
    // write a message to errorMessage How?
    return null;
}
static void exampleRecordRegister(void)
{
    pexampleRecordMetaSupport = new exampleRecordMetaSupport;
    // NOTE MUST ALSO register interface
}
epicsExportRegistrar(exampleRecordRegister);
 
=== alltypesRecord.dbd ===
 
As a last example alltypesRecord.h is generated as follows:
 
class allTypesRecord {
public:
    iocRecord  common;
    iocBoolean fbool;
    iocOctet  foctet;
    iocInt16  fint16;
    iocUInt16  fuint16;
    iocInt32  fint32;
    iocUInt32  fuint32;
    iocInt64  fint32;
    iocUInt64  fuint32;
    iocFloat32 ffloat32;
    iocFloat64 ffloat64;
    iocString  fstring;
    iocMenu    fmenu;
    iocEnum    fenum
    iocStruct  fstruct;
    iocLink    flink;
    iocDevice  fdevice;
};
 
const iocInt16 allTypes_firstIndex = 1001001
const iocInt16 allTypes_fbool = 1001;
const iocInt16 allTypes_foctet = 1002;
const iocInt16 allTypes_fint16 = 1003;
const iocInt16 allTypes_fuint16 = 1004;
const iocInt16 allTypes_fint32 = 1005;
const iocInt16 allTypes_fuint32 = 1006;
const iocInt16 allTypes_fint64 = 1007;
const iocInt16 allTypes_fuint64 = 1008;
const iocInt16 allTypes_ffloat32 = 1009;
const iocInt16 allTypes_ffloatn64 = 10010;
const iocInt16 allTypes_ffstring = 10011;
const iocInt16 allTypes_fmenu = 10012;
const iocInt16 allTypes_fenum = 10013;
const iocInt16 allTypes_fstruct = 10014;
const iocInt16 allTypes_flink = 10015
const iocInt16 allTypes_fdevice = 10016
const iocInt16 allTypes_lastIndex = allTypes_fdevice;
 
epicsExtern iocStructMetaSupport *allTypesMetaSupport;
 
----
<center>
 
== Generated dataAccess files ==
 
</center>
 
== displayLimitDA.h ==
 
From <tt>displayLimit.dbd</tt> files style="font-family: courier">displayLimitDA.hand <tt>displayLimitDA.cpp</tt> are generated.
 
* <tt>displayLimitDA.h</tt> contains:
    #ifdef displayLimitDAH
    #define displayLimitDAH
    #include <displayLimit.h>
    #include <dataAccess.h>
    #include <daDataLocator.h>
    using namespace da;
    class displayLimitDA : public propertyCatalog {
    public:
        displayLimitDA(displayLimit *pdisplayLimit);
        ~displayLimitDA();
        void traverse (propertyViewer & ) const;
        traverseModifyStatus traverse(propertyManipulator &);
        bool find (const propertyId &, propertyViewer &) const;
        displayLimitDA & operator = (const displayLimitDA &) const;
        displayLimitDA & operator != (const displayLimitDA &) const;
        displayLimitDA & operator = (const daData &);
    private:
        displayLimit *pdisplayLimit;
        static bool init;
        static locator < displayLimitDA > locate;
        void lowReadBinder ( propertyViewer & ) const;
        void lowWriteBinder ( propertyViewer & ) const;
        void highReadBinder ( propertyViewer & ) const;
        void highWriteBinder ( propertyViewer & ) const;
    };
    #endif //displayLimitDAH
* <tt>displayLimitDA.cpp</tt> implements the dataAccess interface.
    #include "displayLimitDA.h"
    #include <daPropertyId.h>
    bool displayLimitDA::init = false;
    locator < displayLimitDA > displayLimitDA::locate;
    static const propertyId propertyDisplayLimit("displayLimit");
    static const propertyId propertyLow("low");
    static const propertyId propertyHigh("high");
    void displayLimitDA::traverse ( propertyViewer & viewer ) const
    {
        viewer.reveal(propertyLow,low);
        viewer.reveal(propertyHigh,high);
    }
    traverseModifyStatus displayLimitDA::traverse ( propertyManipulator & manipulator ) const
    {
        manipulator.reveal(propertyLow,low);
        manipulator.reveal(propertyHigh,high);
        return tmsSuccess;
    }
    displayLimitDA &displayLimitDA::find ( const propertyId &type, propertyViewer &adt ) const
    {
        return displayLimitDA::locate.callExportFunction ( *this, type, adt );
    }
    bool displayLimitDA::operator == ( const displayLimitDA & d ) const
    {
        equivStatus stat = equiv ( *this, d );
        return equivStatusToBool ( stat );
    }
    displayLimitDA & displayLimitDA::operator = ( const displayLimitDA & d )
    {
        assignStatus stat = assign ( *this, d );
        throwExceptionIfUnsuccessful ( stat );
        return *this;
    }
    void displayLimitDA::lowReadBinder(propertyViewer &adt ) const
    { adt.reveal(propertyLow,low); }
    void displayLimitDA::lowWriteBinder(propertyManipulator &adt ) const
    { adt.reveal(propertyLow,low); }
    void displayLimitDA::highReadBinder(propertyViewer &adt ) const
    { adt.reveal(propertyHigh,high); }
    void displayLimitDA::highWriteBinder(propertyManipulator &adt ) const
    { adt.reveal(propertyHigh,high); }
    displayLimitDA::displayLimitDA(displayLimit *p) : pdisplayLimit(p)
    {
        if(init==false) {
            locate.installExportFunction(propertyLow,&lowReadBinder);
            locate.installExportFunction(propertyLow,&lowWriteBinder);
            locate.installExportFunction(propertyHigh,&highReadBinder);
            locate.installExportFunction(propertyHigh,&highWriteBinder);
            init = true;
        }
    }
 
== exampleRecord ==
 
From <tt>exampleRecord.dbd</tt> The following files are generated
 
* exampleRecordDA.h contains:
    #ifdef exampleRecordDAH
    #define exampleRecordDAH
    #include <dataAccess.h>
    #include <daDataLocator.h>
    using namespace da;
    class exampleRecordDA : public propertyCatalog {
    public:
        exampleRecordDA(exampleRecord *pexampleRecord);
        ~exampleRecordDA();
        void traverse (propertyViewer & ) const;
        traverseModifyStatus traverse(propertyManipulator &);
        bool find (const propertyId &, propertyViewer &) const;
        exampleRecordDA & operator = (const exampleRecordDA &) const;
        exampleRecordDA & operator != (const exampleRecordDA &) const;
        exampleRecordDA & operator = (const daData &);
    private:
        exampleRecord *pexampleRecord;
        static bool init;
        static locator < exampleRecordDA > locate;
        void lowReadBinder ( propertyViewer & ) const;
        void lowWriteBinder ( propertyViewer & ) const;
        void highReadBinder ( propertyViewer & ) const;
        void highWriteBinder ( propertyViewer & ) const;
    };
    #endif //exampleRecordDA
* <tt>exampleRecordDA.cpp</tt> is the dataAccess interface for exampleRecord
<nowiki> #include "exampleRecord.h"
#include <daPropertyId.h>
struct exampleRecordDAPvt {
    displayLimitDA *pdisplayLimitDA;
};
bool exampleRecordDA::init = false;
locator < exampleRecordDA > exampleRecordDA::locate;
static const propertyId propertyValue("value");
static const propertyId propertyDisplayLimit("displayLimit");
void exampleRecordDA::traverse ( propertyViewer & viewer ) const
{
    displayLimitDA *pdisplayLimitDA = pexampleRecordDAPvt->pdisplayLimitDA;
    viewer.reveal(propertyValue,value);
    pdisplayLimitDA->traverse(viewer);
}
traverseModifyStatus exampleRecordDA::traverse ( propertyManipulator & manipulator ) const
{
    displayLimitDA *pdisplayLimitDA = (displayLimitDA*)recDAPvt;
    manipulator.reveal(propertyValue,value);
    return pdisplayLimitDA->traverse(manipulator);
}
exampleRecordDA &exampleRecordDA::find ( const propertyId &type, propertyViewer &adt ) const
{
    return exampleRecordDA::locate.callExportFunction ( *this, type, adt );
}
bool exampleRecordDA::operator == ( const exampleRecordDA & d ) const
{
    equivStatus stat = equiv ( *this, d );
    return equivStatusToBool ( stat );
}
exampleRecordDA & exampleRecordDA::operator = ( const exampleRecordDA & d )
{
    assignStatus stat = assign ( *this, d );
    throwExceptionIfUnsuccessful ( stat );
    return *this;
}
void exampleRecordDA::valueReadBinder(propertyViewer &adt ) const
{ adt.reveal(propertyValue,value); }
void exampleRecordDA::valueWriteBinder(propertyManipulator &adt ) const
{ adt.reveal(propertyValue,value); }
exampleRecordDA::exampleRecordDA(exampleRecord *p) : pexampleRecord(p)
{
    if(init==false) {
        locate.installExportFunction(propertyValue,&valueReadBinder);
        locate.installExportFunction(propertyValue,&valueWriteBinder);
        locate.installExportFunction(propertyDisplayLimit,&displayLimitReadBinder);
        locate.installExportFunction(propertyDisplayLimit,&displayLimitWriteBinder);
        init = true;
    }
    pexampleRecordDAPvt->pdisplayLimitDA  = new displayLimitDA(pdisplayLimit);
}
    </nowiki>
 
----
<center>
 
== Standard Interfaces ==
 
</center>
 
NOTE: This discussion belongs elsewhere but for now it here.
 
<tt>iocTypes.h</tt> defines two interfaces:
 
* <tt>iocStructMetaSupport</tt>
* <tt>iocRecordSupport</tt>
 
This is the beginning of defining the successor to the V3 Record Support Entry Table. This needs more thought so the following are just preliminary ideas.
 
=== <tt>iocStructMetaSupport</tt> ===
 
This has an implementation for every <tt>struct</tt> and every <tt>record</tt>. A tool will exist to create this support. For most structures the generated file may be sufficient. For a "smart" <tt>struct</tt> and for all record types the generated file is only a skeleton that must be modified to implement the semantics. It contains the following methods:
 
; <tt>create</tt>
: Create storage for the <tt>struct</tt> or <tt>record</tt>. The default implementation should always be sufficiant.
; <tt>initialize</tt>
: Perform initialization. This is analagous to V3 <tt>init_record</tt>.
: Questions. Are multiple passes needed? How many? Note that device link, device have separate interfaces for connecting and disconnecting.
; <tt>finalize</tt>
: Is this needed? Are multiple passes needed?
; <tt>destroy</tt>
: free storage used by <tt>struct</tt> or <tt>record</tt>
; <tt>indexToAddr</tt>
: This converts a field index to an address. The generated header files contain the field indices.
; Additional????
: Are they needed?
 
=== <tt>iocRecordSupport</tt> ===
 
This is implemented by record support. Support for "smart" structures can also implement this interface. It implements the following methods:
 
; <tt>special</tt>
: Called before and after the field is modified from outside record support itself. fieldIndex is an array in field indices that locate the exact field being modified.
; Additional????
: Are they needed?

Latest revision as of 19:48, 15 September 2005

Obsolete relpaced by "V4 Design: Runtime interfaces"