Table of Contents
Previous Chapter This chapter is divided into the following sections:
The field types are:
DBF_ENUM is used for enumerated items, which is analogous to the C language enumeration. An example of an enum field is field VAL of a multi bit binary record.
The field types DBF_ENUM, ..., DBF_DEVCHOICE all have an associated set of ASCII strings defining the choices. For a DBF_ENUM, the record support module supplies values and thus are not available for static database access. The database access routines locate the choice strings for the other types.
DBF_INLINK and DBF_OUTLINK specify link fields. A link field can refer to a signal located in a hardware module, to a field located in a database record in the same IOC, or to a field located in a record in another IOC. A DBF_FWDLINK can only refer to a record in the same IOC. Link fields are described in a later chapter.
DBF_INLINK (input), DBF_OUTLINK (output), and DBF_FWDLINK (forward) specify that the field is a link structure as defined in link.h. There are three classes of links:
DBF_NOACCESS fields are for private use by record processing routines.
struct dbBase {
struct choiceSet *pchoiceCvt;
struct arrChoiceSet *pchoiceGbl;
struct choiceRec *pchoiceRec;
struct devChoiceRec *pchoiceDev;
struct arrBrkTable *pcvtTable;
struct recDes *precDes;
struct recType *precType;
struct recHeader *precHeader;
struct recDevSup *precDevSup;
struct drvSup *pdrvSup;
struct recSup *precSup;
struct pvd *pdbPvd; /* DCT pvd - remove when DCT goes away */
void *ppvd;/* pointer to process variable directory*/
char *pdbName;/* pointer to database name*/
struct sdrSum *psdrSum;/* pointer to default sum */
long sdrFileSize; /*size of default.dctsdr file*/
long pvtSumFlag; /*internal use only*/
};
Perhaps the easiest way to describe the database access layer is to list and briefly describe the set of routines that constitute database access. This provides a good look at the facilities provided by the database. It may seem strange that the structure of the IOC database is not described at this point but this would result in confusing detail. The structure is explained in the last chapter.
Before describing database access, one caution must be mentioned. The only way to communicate with an IOC database from outside the IOC is via Channel Access. In addition, any special purpose software, i.e. any software not described in this document, should communicate with the database via Channel Access, not database access, even if it resides in the same IOC as the database. Since Channel Access provides network independent access to a database, it must ultimately call database access routines. The database access interface was changed in 1991, but Channel Access was never changed. Instead a module was written which translates old style database access calls to new. This interface between the old and new style database access calls is discussed in the last section of this chapter.
The database access routines are:
dbGetField also accepts argument options which is a mask containing a bit for each additional type of information the caller desires. The complete set of options is:
struct dbAddr{
struct dbCommon *precord: /* address of record */
void *pfield; /* address of field */
void *pfldDes; /* address of struct fldDes */
long no_elements; /* number of elements (arrays) */
short record_type; /* type of record being accessed */
short field_type; /* type of database field */
short field_size; /* size (bytes) of the field being
accessed */
short special; /* special processing */
short choice_set; /* index of choiceSet GBLCHOICE &
RECCHOICE*/
short dbr_field_type} /* field type as seen by database
request DBR_STRING, ...,
DBR_ENUM, DBR_NOACCESS*/
struct buffer {
DBRstatus
DBRtime
float value[10];
} buffer;
The associated dbGetField call is:
long options,number_elements,status;
...
options = DBR_STATUS | DBR_TIME
number_elements = 10;
status = dbGetField(paddr,DBR_FLOAT,&buffer,&options,&number_elements);
Consult dbAccess.h for a complete list of macros.Structure dbAddr contains a field dbr_field_type. This field is the database request type that most closely matches the database field type. Using this request type will put the smallest load on the IOC.
Channel Access provides routines similar to dbGetField, and dbPutField. It provides remote access to dbGetField, dbPutField, and to the database monitors described below.
dbNameToAddr(
char *pname, /*ptr to process variable name */
struct dbAddr *paddr);
Given a process variable name, this routine locates the process variable and fills in the fields of structure dbAddr. The process variable name is of the form "<record_name>.<field_name>". For example the value field of a record with record name `sample_name" is "sample_name.VAL". Note that the name is case sensitive. All field names are all upper case letters. dbNameToAddr locates a record via a process variable directory (PVD). It fills in a structure (dbAddr) describing the field. dbAddr contains the address of the record and also the field. Thus other routines can locate the record and field without a search. Although the PVD allows the record to be located via a hash algorithm and the field within a record via a binary search, it still takes about 80 microseconds (25MHz 68040) to located a process variable. Once located the dbAddr structure allows the process variable to be accessed directly.
dbGetField(
struct dbAddr *paddr,
short dbrType, /* DBR_xxx */
void *pbuffer, /*addr of returned data */
long *options, /*addr of options */
long *nRequest, /*addr of number of elements */
void *pfl); /*used by monitor routines */
Thus routine locks, calls dbGet, and unlocks.
dbGetLink(
struct db_link *pdbLink, /*addr of database link */
struct dbCommon *pdest, /*addr of destination record */
short dbrType, /* DBR_xxx */
void *pbuffer, /*addr of returned data */
long *options, /*addr of options */
long *nRequest); /*addr of number of elements desired*/
This routine is called by database access itself and by record support and/or device support routines in order to get values from other database records via input links. It calls dbGet to obtain data and also implements the process passive and maximize severity link options.
dbFastLinkGet(
struct link *plink,
struct dbCommon *precord,
void *pdest);
This routine gets a value from an input link to pdest. Do not call this routine unless you have a properly initialized Channel Access or database link. This routine is not intended to be called directly by record support, use recGblGetFastLink() instead.
dbGet(
struct dbAddr *paddr,
short dbrType, /* DBR_xxx */
void *pbuffer, /*addr of returned data
long *options, /*addr of options */
long *nRequest, /*addr of number of elements */
void *pfl); /*used by monitor routines */
Thus routine retrieves the data referenced by paddr and converts it to the format specified by dbrType. "options" is a read/write field. Upon entry to dbGet, options specifies the desired options. When dbGetField returns, options specifies the options actually honored. If an option is not honored, the corresponding fields in buffer are filled with zeros.
"nRequest" is also a read/write field. Upon entry to dbGet it specifies the maximum number of data elements the caller is willing to receive. When dbGet returns it equals the actual number of elements returned. It is permissible to request zero elements. This is useful when only option data is desired.
"pfl" is a field used by the Channel Access monitor routines. All other users must set pfl=NULL.
dbGet calls one of a number of conversion routines in order to convert data from the DBF types to the DBR types. It calls record support routines for special cases such as arrays. For example, if the number of field elements is greater then 1 and record support routine get_array_info exists, then it is called. It returns two values: the current number of valid field elements and an offset. The number of valid elements may not match dbAddr.no_elements, which is really the maximum number of elements allowed. The offset is for use by records which implement circular buffers.
dbPutField(
struct dbAddr *paddr,
short dbrType, /* DBR_xxx*/
void *pbuffer, /*addr of data */
long nRequest); /*number of elements to write*/
This routine is responsible for accepting data in one of the DBR_xxx formats, converting it as necessary, and modifying the database. Similar to dbGetField, this routine calls one of a number of conversion routines to do the actual conversion and relies on record support routines to handle arrays and other special cases.It should be noted that routine dbPut does most of the work. The actual algorithm for dbPutField is:
dbPutLink(
struct db_link *pdbLink, /*addr of database link */
struct dbCommon *psource, /*addr of source record */
short dbrType, /* DBR_xxx*/
void *pbuffer, /*addr of data to write */
long nRequest); /*number of elements to write*/
This routine is called by database access itself and by record support and/or device support routines in order to put values into other database records via output links. It performs the following functions:
dbFastLinkPut(
struct link *plink,
struct dbCommon *precord,
void *psource);
This routine puts the value from psource to an output link. Do not call this routine unless you have a properly initialized Channel Access or database link. This routine is not intended to be called directly by record support, use recGblPutFastLink() instead.
typedef struct putNotify{
/*The following members MUST be set by user*/
void (*userCallback)(struct putNotify *);
struct dbAddr *paddr; /*dbAddr set by dbName ToAddr*/
void *pbuffer; /*address of data*/
long nRequest; /*number of elements to be written*/
short dbrType; /*database request type*/
void *usrPvt; /*for private use of user*/
/*The following is status of request. Set by dbPutNotify*/
long status;
/*The following are private to database access*/
CALLBACK callback;
void *list; /*list of records for which to wait*/
int nwaiting;
notifyCmd cmd;
unsigned char rescan; /*Should dbPutNotify be called again*/
}PUTNOTIFY;
long dbPutNotify(PUTNOTIFY *pputnotify);
void dbNotifyCancel(PUTNOTIFY *pputnotify);
The following routine is used only by old database access.
int dbPutNotifyMapType(PUTNOTIFY *pputnotify,short dbr_type)The status value stored in PUTNOTIFY can be one of the following:
dbPut(
struct dbAddr *paddr,
short dbrType, /* DBR_xxx*/
void *pbuffer, /*addr of data */
long nRequest); /*number of elements to write*/
This routine is responsible for accepting data in one of the DBR_xxx formats, converting it as necessary, and modifying the database. Similar to dbGet, this routine calls one of a number of conversion routines to do the actual conversion and relies on record support routines to handle arrays and other special cases.
long dbBufferSize(
short dbrType, /* DBR_xxx*/
long options, /* options mask*/
long nRequest); /* number of elements*/
This routine returns the number of bytes that will be returned to dbGetField if the request type, options, and number of elements are specified as given to dbBufferSize. Thus it can be used to allocate storage for buffers.NOTE: This should become a Channel Access routine
dbValueSize(short dbrType); /* DBR_xxx*/This routine returns the number of bytes for each element of type dbrType.
NOTE: This should become a Channel Access routine
dbScanPassive(
struct dbCommon *pfrom,
struct dbCommon *pto); /* addr of record*/
This request specifies the record requesting the scan, which may be NULL, and the record to be processed. If the record is passive and pact=FALSE then dbProcess is called. Note that this routine is called by dbGetLink, dbPutField, and by record processing routines for forward links. In addition to calling dbProcess this routine is responsible for creating lists needed for dbPutNotify.
dbProcess(struct dbCommom *precord); /* addr of record*/Request that record be processed. Record processing is described in detail below.
The routines provided are:
dbScanLockInit( /* called only by iocInit*/
int nset); /* number of lock sets*/
dbScanLock(struct dbCommon *precord); /*addr of record*/
dbScanUnlock(struct dbCommon *precord); /*addr of record*/
The routines provided are:
dbCaAddInLink(
struct link *plink,
void *precord,
char *pfieldName);
dbCaAddOutLink(
struct link *plink,
void *precord,
char *pfieldName);
dbCaGetLink(
struct link *plink);
dbCaPutLink(
struct link *plink);
For a description of these routines see:
Links in a Distributed database: Theory and Implementation,
Nicholas T. Karonis and Martin R. Kraimer, December 1991
Since this manual concentrates on IOC software, this is not the place to describe the old database interface. Other documents describe it. The header file db_access.h also provides descriptive information.