V4 DBD Generated Code
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 generatedp>
- 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?