iocCore includes:
The following are goals forEPICS base release 4.xx
The rest of this document describes details concerning three basic extensions to the existing iocCore:
The name recordtype will be replaced by struct.
COMMENT: maybe we should use the names struct, recordtype, and recordlink.These are the three types of things discussed below.
The following field types in epics base release 3.13 will be changed:
The following new or changed field types are provided:
Should we consider these? I will not discuss any further in this document.
where
link(<struct_name>.<field>,<link_struct_name>,<iid_name>,"<choice_string">)
where:
From the point of view of static database access, a link field consists of two components:
The <iid_name> identifies an interface that can be called at run time to process the link. More about interfaces below. The DBF_INLINK, DBF_OUTLINK, and DBF_FWDLINK are similar to DBF_XXXSTRUCTLINKs except that the menu choices, additional structure, and <iid_names>are automatically handled by the static and run time database access libraries.
The following changes are proposed:
Three examples follow: The first shows how soft links are handled, the second an existing vme link, and the third a vme link with additional configuration information.
A soft input link has the definitions :
menu(menuSoftInLink) { choice(menuSoftInLinkNULL,"NULL Link") choice(menuSoftInLinkDB,"Database Link") choice(menuSoftInLinkCA,"Channel Access Link") } menu(menuCALinkProcess) { choice(menuCALinkProcessNo,"No Process") choice(menuCALinkProcessPassive,"Process if Passive") choice(menuCALinkProcessAlways,"Process Always") } struct(dbSoftInLinkDB) { field(pvname,DBF_VSTRING) { prompt("Process Variable Name") promptgroup(GUI_INPUT) } field(process_passive,DBF_MENU) { prompt("Process Passive") promptgroup(GUI_INPUT) menu(menuYesNo) } field(max_sevr,DBF_MENU) { prompt("Maximize Severity") promptgroup(GUI_INPUT) menu(menuYesNo) } } struct(dbSoftInLinkCA) { field(pvname,DBF_VSTRING) { prompt("Process Variable Name") promptgroup(GUI_INPUT) } field(process_passive,DBF_MENU) { prompt("Process on Monitor") promptgroup(GUI_INPUT) menu(menuCALinkProcess) } field(max_sevr,DBF_MENU) { prompt("Maximize Severity") promptgroup(GUI_INPUT) menu(menuYesNo) } }
# The following are psuedo definitions. link(<all DBF_INLINKs>,NULL,<system>,"NULL Link") link(<all DBF_INLINKs>,dbSoftInLinkDB,<system>,"Database Link") link(<all DBF_INLINKs>,dbSoftInLinkCA,<system>,"Channel Access Link")
A record instance file could define a DBF_INLINK as follows:
... field(INPA,"Channel Access Link"){ field(pvname,"<record name>.<field_name>") field(process_passive,"Yes") field(max_sevr,"Yes") } ...
Comments:
The above allows a DCT to express the exact options permitted. In 3.13 this is not true.
Note that user must choose between DB and CA Link. We could have DB automatically converted to DB if pvname is not local. This is the existing functionality. In this case a warning message could also be issued.
Lets take an ai record connected to a VME_IO input. This example shows how existing 3.13 link functionality is reimplemented. The old recordtype(ai) definition is now:
struct(ai) { include "dbCommon" ... field(INP,DBF_INSTRUCTLINK) { ... } ... }
The following defines the vmeio structure .
struct(vmeLink) { field(card,DBF_USHORT) { prompt("card") promptgroup(GUI_INPUTS) } field(signal,DBF_USHORT) { prompt("signal") promptgroup(GUI_INPUTS) } field(parm,DBF_PSTRING) { prompt("parm") promptgroup(GUI_INPUTS) } }
The above definition results in an include file that duplicates the "struct vmeio" currently defined in link.h. The other existing bus types defined in link.h are defined in a similar manner. User defined bus types can be be created as desired.
Assume the old device definitions were:
device(ai,CONSTANT,devAiSoft,"Soft Channel") device(ai,CONSTANT,devAiSoftRaw,"Raw Soft Channel") device(ai,VME_IO,devAiXy566Se,"XYCOM-566 SE Scanned")
The new definition would be:
link(ai.INP,NULL,NULL,"NULL Link") link(ai.INP,dbSoftInLinkDB,devAiSoft,"Database Link") link(ai.INP,dbSoftInLinkCA,devAiSoft,"Channel Access Link") link(ai.INP,dbSoftInLinkDB,devAiSoftRaw,"Raw Database Link") link(ai.INP,dbSoftInLinkCA,devAiSoftRaw,"Raw Channel Access Link") link(ai.INP,VME_IO,devAiXy566Se,"XYCOM-566 SE Scanned")
NOTE: In order to get all the soft definitions out of base.dbd and baseLIBOBJS, the soft definitions and support modules should be bundled with record support.
A record instance is defined as follows:
record(ai,xxx) { ... field(INP,"vmeLink") { field(card,"1") field(signal,"2") } ... }
Comments:
This example show how existing hardware link support is duplicated. It should require only minor changes to existing device support.
It also shows that epics sites that have added their own bus types could easly add their local types without modifying epics base.
Now lets give an example that provides more functionality. We want to be able to configure the vme addresses for a module. In addition each channel can have individual gain. Lets define two additional structure: the first describes a module. The other describes a link.
#Each physical module will have a record instance of type xxxAdc struct(xxxAdc) { field(NAME,DBF_STRING) { prompt("Record Name") special(SPC_NOMOD) size(29) } field(card,DBF_ULONG) { prompt("VME Slot") promptgroup(GUI_INPUT) } field(a24o,DBF_ULONG) { prompt("A24 Offset") promptgroup(GUI_INPUT) } field(a24l,DBF_ULONG) { prompt("A24 Length") promptgroup(GUI_INPUT) } ... } #Each INP Link referencing a physical module will use this link type struct(xxxAdcLink) { field(xxxAdcName,DBF_STRING) { prompt("xxxAdc Record Name") promptgroup(GUI_INPUT) } field(signal,DBF_USHORT) { prompt("Signal") promptgroup(GUI_INPUT) } field(gain,DBF_MENU) { prompt("Gain") promptgroup(GUI_INPUT) menu(menuXxxAdcGain) } ... }
A record is defined as
#mycard is an actual physical module record(mycard,xxxAdc) { field(NAME,"xxxAdcCard1") field(card,"1") field(a24o,"0x00a000") field(a24l,"0x1000") } #This is the ai record that uses a signal of mycard record(xxx,ai) { ... field(INP,"xxxAdcLink") { field(xxxAdcName,"xxxAdcCard1") field(signal,"2") field(gain,"10x") } ... }
Comments:
This example demonstrates that it will be possible to provide arbitrary configuration information.
Full support for on-line add and delete requires a separate record for each physical device.
It is also possible to add diagnostic fields. For example a 16 channel adc support module could define a 16 element array field that contains the raw values. Another example is a field that reports the status of the nodule itself. The record could go into alarm if a problem is detected.
Now lets discuss how the three different viewpoints of epics databases, i.e. DCT tools, Runtime database Access, and record/device access. NOTE: These are "half baked" thoughts
long dbGetStruct(DBENTRY *pfrom,DBENTRY *pstruct)
{field1,field2,...fieldn}
Instead of having a single dbCommon that defines a large number of fields, a set of definitions will be provided. Each definition adds additional fields to the previous definition.
COMMENT: Groups of fields used by subsystems (access security, database access, channel access) are replaced by a "void *" field for each subsystem. In fact I think all DBF_NOACCESS fields should be "void *" fields. Also the fields that record support modules use privately should all be declared in a separate structure and referenced via a "void * recPvt" field.
The dbToRecordTypeH utility will be renamed to dbToStructH, i.e. a c structure can be generated for any structure. All code that intimately uses the information in a structure should use the generated structures. Note that except for a few special structure types iocCore will NOT include the generated structure definitions.
EPICS 3.13 supports the following interfaces: RSET, DSET, DRVET. Other than the first field (number) of each interface they are similar to the COM definition of an interface. What is being proposed is to use a few of the basic ideas of COM interfaces.
The header file ifInit.h is defined as:
typedef long ifInit_init(void); typedef struct ifInit { ifInit_init *init; } ifInit;
A record support module would implement this interface something like the following:
include "ifInit.h" ... LOCAL ifInit_init init; /* aiRecord_ifInit must be global variable. IT CAN BE THE ONLY ONE*/ ifInit aiRecord_ifInit = {init}; ... ifXXX_yyy yyy; ifXXX_zzz zzz; static ifXXX aiRecord_ifXXX = {yyy,zzz};
long init(void) { ifRegister("aiRecord_ifXXX",aiRecord_ifXXX); ... }
The old RSET will be replaced by the following interfaces:
Comments about init_record:
The arguments for init_record are:
init_record(void *precord,int phase, int passInPhase, int *nextPhase,int *delaySeconds)
phase
Four phases are defined:
0) Record can perform only self initialization, i.e. it may not access other records
1) Record can interact with cooperating records
2) Record can interact with any other records.
3) Any final initialization after all connections have been made.
passInPhase
Pass within phase.
nextPhase
The next phase for which initRecord should be called. -1 means all done.
delaySeconds
Delay in seconds until next call should be made.
The old DSET will be replaced by the following interfaces:
The arguments for init_link are:
init_link(DBLINK *plink,int phase, int passInPhase, int *nextPhase,int *delaySeconds)
This routine will be called by record support from it's init_record method.
COMMENT: Note that each record type can define a recordtype specific interface for communicating with it's link support modules. I also think it should define a structure or use parameters for communicating with its link support. Link support modules should NOT include the record structure declaration. This should get rid of a whole bunch of funny business in communication between record and device support.
More of the same.
Two routines are provided:
long ifRegister(char *name, void *location); void *ifLocate(char *name)
ifRegister is called by the ifInit init methods to register interfaces. Any code can call ifLocate to locate an interface. Every record type has an associated ifInit interface named <record type>Record_ifInit. Every link support interface is named in a link definition.Every driver support interface is named in a driver definition. Since the ifInit init interfaces call ifRegister for all other interfaces EVERY interface used in an ioc can be easily determined. One idea is to generate a source module from the xxxApp.dbd file. This source file maps the interface names to the external names of each ifInit interface. Jim Kowalkowski also has another method for location the names. In any case the gioal is to locate all interfaces without calling symFindByName. This makes the port to ,other operating system and toronado easier.
For complete on-line add delete each physical interface must have a record instance. The fields can be modified via database or channel access. Should have a field "CMD" that accepts commands like:
DBF_INLINK, DBF_FWDLINK, and DBF_OUTLINK fields can be modified by iocCore without aid from record support. This is just like in 3.13.
DBF_INSTRUCTLINK and DBF_OUTSTRUCTLINK need support from the an interface attached to the link definitions. Again it should accept commands like:
If record instances are to be deleted there must be help from an interface.
iocInit needs work. It 's functionality should be made into a library that can be called by iocInit as well as by something that adds things after iocInit. Something like dbAddDatabase is needed followed by iocReinit. This is a way to add new record/device/driver support and new record instances.
Needs lots of thought.