epics record/device/driver support
DESCRIPTION
EPICS record/device/driver Support. [email protected], many slides copied from [email protected]. Interfacing Hardware. General Idea. EPICS. Software. IOC Core: Db, CA, …. Record Support. “Driver”. Device Support. Hardware. Driver Support. Hardware. Where to extend…. - PowerPoint PPT PresentationTRANSCRIPT
![Page 2: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/2.jpg)
Interfacing Hardware
Hardware
“Driver”
Software
General Idea
Hardware
Device Support
IOC Core: Db, CA, …
EPICS
Driver Support
Record Support
![Page 3: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/3.jpg)
Where to extend… Common Case: New Hardware (I/O Board,..)
Driver: Any low-level code to talk to the hardware.Might not have any knowledge of EPICS
Device: EPICS-specific glue code between driver and (subset of) records
Sometimes: Specialized Record Copy of existing record w/ slight change
Seldom: New Record Type Can task be handled by combination of existing
records, maybe w/ help of SNL? But sometime it is fun to introduce a new
record(NY).
![Page 4: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/4.jpg)
Driver/Device/Record Support Read the “IOC Application Developer's Guide”
before even thinking about doing this! Common Idea:
Describe the new driver/device/record via DBD (Database Description File, ASCII)
Implement the functionality, providing a function table(DRVET,DSET or RSET) specific to driver/device/record support (init(), report(), do_something(), …)
Link/load the binaries which export a function table During startup, iocCore will parse the DBD, locate
the function table and invoke the appropriate functions
Well-defined interfaces for adding new support, minimal recompilation.
![Page 5: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/5.jpg)
The .dbd file entry .dbd file includes
Record type definitionrecordtype(xxx){include "dbCommon.dbd"
field(VAL,DBF_DOUBLE) {
prompt("Current EGU Value")asl(ASL0)pp(TRUE)
}…
}name of RSET for the record xxx have to be xxxRSET
Device support link to a record typedevice(recType,addrType,dset,"name") Driver declarationdriver(drvet)
![Page 6: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/6.jpg)
The .dbd file entry The IOC discovers what device supports are
present from entries in the .dbd filedevice(recType,addrType,dset,"name")
addrType is one ofAB_IO BITBUS_IO BBGPIB_IOCAMAC_IOGPIB_IOINST_IORF_IO VME_IO VXI_IO
dset is the ‘C’ symbol name for the Device Support Entry Table (DSET)
By convention the dset name indicates the record type and hardware interface
This is how record support and the database code call device support routines
For exampledevice(ai,INST_IO,devAiSymb,"vxWorks variable")device(bo,VME_IO,devBoXy240,"Xycom XY240")
![Page 7: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/7.jpg)
Record/Device/DriverTek4320
HPXXX PS contr.
AdVME1521
Td4V
AI devAITek4320
… … … …
AO devAOTek4302
… … … …
LI … … … … …
Driver
GP-IB ARCnet
VME
![Page 8: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/8.jpg)
Driver Support Drivers can be complicated:
Bus-level access, critical timing, interrupts, semaphores, threads, deadlocks, fail-safe, OS-specific (vxWorks, Linux, Win32), …
Typical collection of routines:Check, report, init, read, write, setup_trigger(callback),…
“EPICS part”: Optional & Trivial!
![Page 9: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/9.jpg)
Driver Support Entry Table
/* EPICS Base include file <drvSup.h> */
typedef long (*DRVSUPFUN) ();
struct drvet
{
long number; /*number of support routines*/DRVSUPFUN report; /*print report*/DRVSUPFUN init; /*init the driver */
};
Any routine pointer can be NULL
![Page 10: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/10.jpg)
DRVET Example/* xy.c */#include<drvSup.h>
static long xy_report(){
printf(“XY Driver Info:\n); …} static long xy_init(){
if (xy_check()) { …} struct drvet drvXy ={
2, xy_report,
xy_init};
![Page 11: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/11.jpg)
Registering Driver w/ EPICS EPICS DBD File Entry
driver(drvXy) Results:
EPICS iocInit will locate “drvXy” in symbol table, call the registered “init” routine (unless NULL)
EPICS dbior will invoke “report” routine (unless NULL)
![Page 12: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/12.jpg)
Good Practice Wrong: Assume e.g. two XY board, one
at base address 0x1234 and one at 0x4567, all hard-coded in driver.
Best: Provide “configure” routine, callable from e.g. vxWorks startup file before invoking iocInit:
# EPICS records that refer to XY #0 will
# access board at base addr. 0xfe12# in mode 15xy_config(0, 0xfe12, 15)
![Page 13: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/13.jpg)
Device Support Glue between record and driver is highly
specific to the resp. record: AI record, DTYP=“XY”, INP=“#C0 S5”:
Device support has to call driver for “XY” card #0 and get signal #5 into the record’s RVAL field
Dev.sup routines common to all records: Report: Show info Init: Called once Init_Record: Called for each record Get I/O Interrupt Info: Used w/ SCAN=“I/O Intr”Most are optional, but check specific record type.
![Page 14: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/14.jpg)
Device Support Entry Table
/* Defined in devSup.h */
struct dset
{
long number; /* number of support routines */
DEVSUPFUN report; /* print report*/
DEVSUPFUN init; /* init support*/
DEVSUPFUN init_record; /* init particular record */
DEVSUPFUN get_ioint_info; /* get I/O Intr. Info */
/* Rest specific to record, e.g. BI:
DEVSUPFUN read_bi;
Result: (0,2,error) 0 -> raw value stored in RVAL, convert to VAL 2 -> value already stored in VAL, don’t convert
*/
}
![Page 15: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/15.jpg)
Registering Device Support EPICS DBD File:
device(ai,INST_IO,devAiXX,“My XX")
Result: iocCore … now allows DTYP=“My XX” for ai records will locate DSET “devAiXX” in symbol
table,call init(), then init_record() for each record, record will call read() whenever record gets processed, …
![Page 16: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/16.jpg)
Before Implementing Dev.Sup Understand how to use the driver Read
“Application Developer Guide” Source for specific record type XX,
understand how record calls its device support
Examples in EPICS base sources: base/src/dev/softDev/devXXSoft.c
![Page 17: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/17.jpg)
Device Support for AI Record Common
report initialization initialize instance attach to device
interrupt
AI-Specific read ai device
value linear conversion
(RVAL->VAL)
![Page 18: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/18.jpg)
AI Device Support Type Initializationlong aiDevInit (unsigned pass) common to all record types device specific initialization pass = 0, prior to initializing each record
during "iocInit()“ Check hardware, …
but note that records are not ready to handle data
pass = 1, after initializing each record during "iocInit()“ Activate triggers, …
![Page 19: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/19.jpg)
AI Device Report
long aiDevReport (struct aiRecord * pai, int level);
common to all records, but gets passed pointer to specific record type
called once for every record instance when the user types "dbior <level>"
device status to "stdout" from this routine Idea: detail increases with increasing
"level"
![Page 20: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/20.jpg)
AI Device Initialization for Record long aiDevInitInstance(struct aiRecord *pai)
Called from within “iocInit()” once for each record attached to device
Typical Parse & check device address (pai->inp) Store device-data, e.g. the parsed signal #,
driver handles, … in DPVT:pvt = (X *) calloc(1, sizeof(X);pvt->signal = signal_this_record_wants;pvt->drv = magic_handle_we_got_from_driver;pai->dpvt = (void *) pvt;
![Page 21: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/21.jpg)
Read Signal Value
long aiDevRead_(struct aiRecord * pai){long rval;if (device OK){
rval=pDevMemoryMap->aiRegister[pai->dpvt->signal];
pai->rval = rval;}else
recGblSetSevr(pai, READ_ALARM, INVALID_ALARM);
}
![Page 22: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/22.jpg)
AI Linear Conversion
long aiDevLinearConv (struct aiRecord *pai, int after);
Setup the slope and offset for the conversion to engineering units
if (!after) return S_XXXX_OK;
/* A 12 bit DAC is assumed here */pai->eslo = (pai->eguf - pai->egul)/0x0FFF;pai->roff = 0;
/* roff could be different for device w/ e.g. +-5V, half scale = 0V */
![Page 23: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/23.jpg)
From convert() in aiRecord.c
double val;val = pai->rval + pai->roff;/* * adjust with slope/offset * if linear convert is used */if ( pai->aslo != 0.0 ) val *= pai->aslo;if( pai->aoff != 0.0 ) val+= pai->aoff;
if(pai->linr == menuConvertLINEAR) val = (val * pai->eslo) + pai-
>eoff;
![Page 24: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/24.jpg)
Advanced: Interrupts
Device supports interrupts, want to use SCAN=“I/O Intr”
higher scan rate scan synchronized with device
Difficulty Interrupts: interrupt level, most OS routines
prohibited Record processing: task level
IOSCANPVT EPICS Core Helper for processing records in response
to interrupt
![Page 25: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/25.jpg)
IOSCANPVT
Initialize & keep one IOSCANPVT per distinct interrupt that the hardware can generate /* Record’s DPVT points to struct X* which contains IOCSCANPVT ioscanpvt */X = (X *) rec->dpvt;scanIoInit(&X->ioscanpvt);
Each Interrupt Occurrence (ISR):
scanIoRequest(X->ioscanpvt); safe to call from ISR, but don’t call
scanIoRequest() until after database init (“iocInit()”) completes(extern volatile int interruptAccept;)
![Page 26: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/26.jpg)
Provide IO Interrupt Info
long aiDevGetIoIntInfo (int cmd, struct aiRecord *pai,IOSCANPVT *ppvt);
associates interrupt source with record
*ppvt = X->ioscanpvt; cmd==0 - insert into IO interrupt scan cmd==1 - remove from IO Interrupt
scan
![Page 27: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/27.jpg)
Asynchronous Devices
read/write routine sets “PACT” true and returns zero for success.
asynchronous IO completion callback completes record processing
don’t process a record from within an ISR
![Page 28: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/28.jpg)
Example Asynchronous Readlong devXxxRead (struct aiRecord *pai) {
if (pai->pact)return S_devXxx_OK; /* zero */
pai->pact = TRUEdevXxxBeginAsyncIO(pai->dpvt);return S_devXxx_OK;
}
![Page 29: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/29.jpg)
Example Asynchronous Read Completionvoid devXxxAsyncIOCompletion(struct aiRecord *pai, long ioStatus){
struct rset *prset = (struct rset *) pai->rset;
dbScanLock(pai); if (ioStatus != S_devXxx_OK) {
recGblSetSevr(pai, READ_ALARM, INVALID_ALARM);}(*prset->process)(pai);dbScanUnlock(pai);
}
![Page 30: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/30.jpg)
Record Support
Similar to device & driver support: Certain routines need to be implemented Binary exports a “Record support entry
table” which contains those routines DBD File to describe record and each field
(name, data type, maybe menu of enumerated values, …)
![Page 31: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/31.jpg)
Record DBD File Need to read “IOC Application Developer's Guide”
to understand full DBD syntax! Use xxxRecord created by makeBaseApp as
example
recordtype(xxx){
# Each record needs to start w/ the common fields!include "dbCommon.dbd" field(VAL,DBF_DOUBLE)
{prompt("Current EGU Value")asl(ASL0)pp(TRUE)
}…
}
![Page 32: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/32.jpg)
Record support entry table Initialization:
General and per-record instance Process routine:
Implements functionality of record. Often calls device support specific to this record type checks for alarms posts monitors processes forward links
Utility routines that allow iocCore to properly read, write & display fields of this record
![Page 33: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/33.jpg)
Record support entry table… Record Implementation must export
struct rset <xxxRecord>RSET;struct rset /* record support entry table */{
long number; /* number of support routine */RECSUPFUN report; /* print report */RECSUPFUN init; /* init support */RECSUPFUN init_record; /* init record */RECSUPFUN process; /* process record */RECSUPFUN special; /* special processing */RECSUPFUN get_value; /* OBSOLETE: Just leave NULL */RECSUPFUN cvt_dbaddr; /* cvt dbAddr */RECSUPFUN get_array_info;RECSUPFUN put_array_info;RECSUPFUN get_units;RECSUPFUN get_precision;RECSUPFUN get_enum_str; /* get string from enum */RECSUPFUN get_enum_strs; /* get all enum strings */RECSUPFUN put_enum_str; /* put enum from string */RECSUPFUN get_graphic_double;RECSUPFUN get_control_double;RECSUPFUN get_alarm_double;
};
![Page 34: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/34.jpg)
Initialization init()
Called once during IOC startup init_record(void *precord, int pass)
Called twice per record instance. Second pass can affect other records.
![Page 35: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/35.jpg)
Processing Usually follows this example:static long process(void *precord){
xxxRecord*pxxx = (xxxRecord *)precord;xxxdset *pdset = (xxxdset *)pxxx->dset;long status;unsigned char pact=pxxx->pact;if( (pdset==NULL) || (pdset->read_xxx==NULL) ){
/* leave pact true so that dbProcess doesnt call again*/pxxx->pact=TRUE;recGblRecordError(S_dev_missingSup, pxxx, ”read_xxx”);return (S_dev_missingSup);
}/* pact must not be set true until read_xxx completes*/status=(*pdset->read_xxx)(pxxx); /* read the new value *//* return if beginning of asynch processing*/if(!pact && pxxx->pact) return(0);pxxx->pact = TRUE;recGblGetTimeStamp(pxxx);/* check for alarms */alarm(pxxx);/* check event list */monitor(pxxx);/* process the forward scan link record */recGblFwdLink(pxxx);pxxx->pact=FALSE;return(status);
}
![Page 36: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/36.jpg)
Utility Routines Allow to define
how the record responds when fields are read or written
the units, precision, limits;not only of the VAL field!
![Page 37: EPICS record/device/driver Support](https://reader035.vdocuments.site/reader035/viewer/2022081506/56814e87550346895dbc2243/html5/thumbnails/37.jpg)
Utility Routines… special(DBADDR *addr, int after)
Allows us to react before/after somebody else accesses field ref’ed by addr.
get_units(DBADDR *addr, char *units),get_precision(DBADDR *addr, long *prec),get_array_info(…) Can simply copy contents of EGU or PREC
fields,can also provide information specific to field ref’ed by addr