Difference between revisions of "V4 DBD Generated Code"

From EPICSWIKI
 
Line 312: Line 312:
=== exampleRecord.dbd ===
=== exampleRecord.dbd ===


From this files the following two files are generatedp>
From this files the following two files are generated


* File <tt>exampleRecord.h</tt> contains:
* File <tt>exampleRecord.h</tt> contains:

Revision as of 21:33, 2 May 2005

EPICS: Code generated from DBD

April 29 2005


WARNING: This contains 1/2 baked ideas. Needs lots of work!!!

Overview

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 xxx.dbd file:

  • xxx.h

This contains a struct definition that contains only data. The record support module uses this to access the record.

  • xxxMeta.cpp

This implements an iocStructMetaSupport, which is described below, for accessing data without requiring the generated header file.

  • xxxDA.h

This contains a class definition which is uses for dataAccess.

  • xxxDA.cpp

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 struct and record definition.


Example Database Definition Files

The following Database Definition Files are used as examples.

  • displayLimit.dbd contains:
struct(displayLimit) {
    field(low,float64)
    field(high,float64)
}
  • exampleRecord.dbd contains:
include "dbCommon.dbd"
record(example) extends iocRecord {
    field(value,float64)
    field(displayLimit,struct(displayLimit))
}
  • alltypesRecord.dbd 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))
}

iocTypes.h

File iocTypes.h describes the datatypes used by V4 databases:

/* 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;
 };

Generated Record Support files

displayLimit.dbd

From this file the following two files are generated for use by record support.

  • File displayLimit.h 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 displayLimitMeta.cpp 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 generated

  • File exampleRecord.h 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 exampleRecordMeta.cpp 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;

Generated dataAccess files

displayLimitDA.h

From displayLimit.dbd files style="font-family: courier">displayLimitDA.hand displayLimitDA.cpp are generated.

  • displayLimitDA.h 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
  • displayLimitDA.cpp 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 exampleRecord.dbd 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
  • exampleRecordDA.cpp is the dataAccess interface for exampleRecord
 #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);
 }
     

Standard Interfaces

NOTE: This discussion belongs elsewhere but for now it here.

iocTypes.h defines two interfaces:

  • iocStructMetaSupport
  • iocRecordSupport

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.

iocStructMetaSupport

This has an implementation for every struct and every record. A tool will exist to create this support. For most structures the generated file may be sufficient. For a "smart" struct 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:

create
Create storage for the struct or record. The default implementation should always be sufficiant.
initialize
Perform initialization. This is analagous to V3 init_record.
Questions. Are multiple passes needed? How many? Note that device link, device have separate interfaces for connecting and disconnecting.
finalize
Is this needed? Are multiple passes needed?
destroy
free storage used by struct or record
indexToAddr
This converts a field index to an address. The generated header files contain the field indices.
Additional????
Are they needed?

iocRecordSupport

This is implemented by record support. Support for "smart" structures can also implement this interface. It implements the following methods:

special
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?