1 / 37

EPICS record/device/driver Support

EPICS record/device/driver Support. kasemir@lanl.gov, many slides copied from johill@lanl.gov. Interfacing Hardware. General Idea. EPICS. Software. IOC Core: Db, CA, …. Record Support. “Driver”. Device Support. Hardware. Driver Support. Hardware. Where to extend….

madra
Download Presentation

EPICS record/device/driver Support

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. EPICSrecord/device/driverSupport kasemir@lanl.gov,many slides copied from johill@lanl.gov

  2. Interfacing Hardware General Idea EPICS Software IOC Core: Db, CA, … Record Support “Driver” Device Support Hardware Driver Support Hardware

  3. 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).

  4. 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.

  5. The .dbd file entry • .dbd file includes • Record type definition recordtype(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 type device(recType,addrType,dset,"name") • Driver declaration driver(drvet)

  6. The .dbd file entry • The IOC discovers what device supports are present from entries in the .dbd file device(recType,addrType,dset,"name") • addrType is one of AB_IO BITBUS_IO BBGPIB_IO CAMAC_IO GPIB_IO INST_IO RF_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 example device(ai,INST_IO,devAiSymb,"vxWorks variable") device(bo,VME_IO,devBoXy240,"Xycom XY240")

  7. Record/Device/Driver

  8. 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!

  9. 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

  10. 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 };

  11. 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)

  12. 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 15 xy_config(0, 0xfe12, 15)

  13. 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.

  14. 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 */ }

  15. 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, …

  16. 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

  17. Common report initialization initialize instance attach to device interrupt AI-Specific read ai device value linear conversion(RVAL->VAL) Device Support for AI Record

  18. AI Device Support Type Initialization long 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, …

  19. 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"

  20. 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;

  21. 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); }

  22. 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 */

  23. 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;

  24. 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 Advanced: Interrupts

  25. 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;)

  26. 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

  27. 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

  28. Example Asynchronous Read long devXxxRead (struct aiRecord *pai) { if (pai->pact) return S_devXxx_OK; /* zero */ pai->pact = TRUE devXxxBeginAsyncIO(pai->dpvt); return S_devXxx_OK; }

  29. Example Asynchronous Read Completion void 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); }

  30. 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, …)

  31. 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) } … }

  32. 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

  33. 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; };

  34. Initialization • init() • Called once during IOC startup • init_record(void *precord, int pass) • Called twice per record instance. Second pass can affect other records.

  35. 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); }

  36. 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!

  37. 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

More Related