Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 2009: Device Support EPICS Device Support Andy Foster Observatory Sciences Limited.

Similar presentations


Presentation on theme: "1 2009: Device Support EPICS Device Support Andy Foster Observatory Sciences Limited."— Presentation transcript:

1 1 2009: Device Support EPICS Device Support Andy Foster Observatory Sciences Limited

2 2 2009: Device Support EPICS Outline u What is device support? u The.dbd file entry u The Device Support Entry Table u DSET – report u DSET – init u DSET – init_record u DSET – read_write u Hardware device addresses u Useful EPICS Facilities u Interrupts u EPICS and Interrupts u The callback system u scanIoInit u DSET – get_ioint_info u scanIoRequest u Asynchronous I/O u The optional driver layer

3 3 2009: Device Support EPICS What is Device Support? u Interface between record and hardware u Provides an API for record support to call u Record type determines routines needed u Performs record I/O on request u Determines whether a record is to be synchronous or asynchronous u Provides I/O Interrupt support u Determines whether I/O Interrupts are allowed RECORD SUPPORT DEVICE SUPPORT DRIVER SUPPORT DATABASE ACCESS CHANNEL ACCESS

4 4 2009: Device Support EPICS Why use it u Why not make record types for each hardware interface, with fields to allow full control over the facilities it provides? u Users don't have to learn about a new record type for each I/O board they want to use u Changing the I/O hardware is much easier than writing new records! u Record types provided are sufficient for most hardware interfacing tasks u Device support is simpler than record support u Device support isolates the hardware interface code from changes to the record API u Bug-fixes or enhancements to record support only need to happen in one place u Modularity (good software engineering practice)

5 5 2009: Device Support EPICS The.dbd file entry u The IOC discovers what device supports are present from entries in the.dbd file device(recType,addrType,dset,"name") u addrType is one of AB_IOBITBUS_IOBBGPIB_IO CAMAC_IOGPIB_IOINST_IO RF_IOVME_IOVXI_IO u dset is the C symbol name for the Device Support Entry Table (DSET) u By convention the dset name indicates the record type and hardware interface u This is how record support and the database code call device support routines u For example device(bi,INST_IO, devBiXy2440,XYCOM-2440") device(bo,VME_IO, devBoXy240, XYCOM-240")

6 6 2009: Device Support EPICS The Device Support Entry Table … is a C struct containing function pointers, the content of which can vary by record type u Each device support layer defines a named DSET with pointers to its own routines u All DSET structure declarations start struct xxxdset { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read_write; }; u number gives the number of function pointers in the DSET, usually 5 for standard types u A NULL pointer is given when an optional routine is not implemented

7 7 2009: Device Support EPICS How does a record find its device support? Through.dbd device statements:

8 8 2009: Device Support EPICS DSET: report long report(int type); Optional function. Called by dbior shell command u Normally omitted because the driver also has a report function which prints out information about the current state of the hardware. The value of type defines how much information to print.

9 9 2009: Device Support EPICS DSET: init long init(int pass); u Initializes the device support layer u Used for one-time startup operations, e.g. u Starting background tasks u Creating semaphores u Optional routine, not always needed u Routine called twice by iocInit: pass=0 Before record initialization u At this stage we dont know what I/O is to be used by the database, therefore, do not access hardware. pass=1 After all record initialization u Can be used as a final startup step, all devices addressed by database are known by this point

10 10 2009: Device Support EPICS DSET: init_record long init_record( struct xxxRecord *prec ); u Called from xxxRecords init_record routine once for each record. This occurs at iocInit. u Important routine, normally required. u init_record should: u Parse the hardware address contained in the INP or OUT field u Check if addressed hardware is present u Allocate any private storage required Every record type has a void *dpvt field for device support to use as it wishes u Program device registers u Set record-specific fields needed for conversion to/from engineering units

11 11 2009: Device Support EPICS DSET: read_write long read_write( struct xxxRecord *prec ); u Important routine. u Called from xxxRecords process routine and implements the I/O operation (or calls the driver to do this) which occurs when the record is processed. u Precise action depends on the record type and whether synchronous or asynchronous processing. u Generally, synchronous input support Reads hardware value into prec->rval u Returns 0 u and synchronous output support Copies value in prec->rval to hardware u Returns 0

12 12 2009: Device Support EPICS Hardware Device Addresses u Device support.dbd entry was device( recType, addrType, dset," name ") u addrType tells database software what type to use for the address link device(bo,VME_IO,devBoXy240,"XYCOM-240) implies that: u pbo->out.type = VME_IO u If we look in base/include/link.h we see that struct vmeio { short card; short signal; char *parm; } u We can obtain card, signal, parm as follows: pvmeio = (struct vmeio *)&(pbo->out.value) u The most flexible link type is INST_IO which provides a string the user can parse.

13 13 2009: Device Support EPICS A simple example #include long init_record(biRecord *prec) { char *pbyte, dummy; prec->pact = 1; if ((prec->inp.type != VME_IO) || (prec->inp.value.vmeio.signal < 0) || (prec->inp.value.vmeio.signal > 7)) { recGblRecordError(S_dev_badInpType, (void *)prec, "devBiFirst: Bad INP address"); return S_dev_badInpType; } if( devRegisterAddress("devBiFirst", atVMEA16, prec->inp.value.vmeio.card, 0x1, &pbyte) != 0) { recGblRecordError(S_dev_badCard, (void *)prec, "devBiFirst: Bad VME address"); return -1; } if( devReadProbe(1, pbyte, &dummy) < 0 ) { recGblRecordError(S_dev_badCard, (void *)prec, "devBiFirst: Nothing there!"); return -1; } prec->dpvt = pbyte; prec->pact = 0; return OK; }

14 14 2009: Device Support EPICS A simple example long read_bi(biRecord *prec) { char *pbyte = (char *)prec->dpvt; prec->rval = *pbyte; return OK; } struct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read_write; } devBiFirst = { 5, NULL, init_record, NULL, read_bi }; epicsExportAddress(dset, devBiFirst);

15 15 2009: Device Support EPICS A simple example – device support.dbd file The.dbd file for the device support routines shown on the preceding pages might be: device(bi, VME_IO, devBiFirst, simpleInput) An application.db file using the device support routines shown might contain: record(bi, "$(P):statusBit") { field(DESC, "Simple example binary input") field(DTYP, "simpleInput") field(INP, "#C$(C) S$(S)") }

16 16 2009: Device Support EPICS A simple example – application startup script An application startup script (st.cmd) using the device support routines shown on the preceding pages might contain: dbLoadRecords("db/example.db", "P=test,C=0x1E0,S=0") which would expand the.db file into record(bi, "test:statusBit") { field(DESC, "Simple example binary input") field(DTYP, "simpleInput") field(INP, "#C0x1E0 S0") }

17 17 2009: Device Support EPICS Useful facilities u ANSI C routines (EPICS headers fill in vendor holes) u epicsStdio.h – printf, sscanf, epicsSnprintf u epicsString.h – strcpy, memcpy, epicsStrDup u epicsStdlib.h – getenv, abs, epicsScanDouble u OS-independent hardware access (devLib.h) u Bus address Local address conversion u Interrupt control u Bus probing u EPICS routines u epicsEvent.h – process synchronization semaphore u epicsMutex.h – mutual-exclusion semaphore u epicsThread.h – multithreading support u recGbl.h – record error and alarm reporting

18 18 2009: Device Support EPICS Interrupts u vxWorks ISRs can be written in C u On VME two parameters are needed: u Interrupt Level prioritized 1-7 u Often set with I/O board DIP switches or jumpers u Level 7 is non-maskable and can crash vxWorks u Interrupt Number u 0-255 has to be unique within this CPU u Interrupt numbers < 64 are reserved by MC680x0 Use EPICS veclist on IOC to see vectors in use However, not supported by some PPC BSPs! u OS initialization takes two calls Connect interrupt handler to vector: devConnectInterruptVME( unsigned vectorNumber, void (*pFunction)(void *), void *parameter); Enable interrupt from VME level: devEnableInterruptLevelVME (unsigned level);

19 19 2009: Device Support EPICS EPICS and Interrupts The callback system u How do you make an EPICS record process when an interrupt occurs? u Use the SCAN setting of I/O Intr in the record u Since an ISR cannot call a records process routine directly, I/O interrupt scanning is implemented using the EPICS callback system. u The callback system uses ring buffers to queue callback requests made from interrupt level. u One of 3 prioritized callback tasks executes the registered callback function which in turn calls the records process routine. u See callback.h for a definition of the EPICS callback structure. u The choice of callback task is determined by the PRIO field in the record (LOW, MEDIUM, HIGH). u From the device/driver layer, we support I/O interrupt scanning by using the following routines: u scanIoInit u get_ioint_info u scanIoRequest

20 20 2009: Device Support EPICS EPICS and Interrupts scanIoInit u scanIoInit must be called for each possible interrupt source. Device support can be written to allow any number of sources. Ultimately, the granularity of interrupts depends on the hardware. u One source per card u One source per bit u scanIoInit is typically called from the driver initialize routine to initialize a pointer void scanIoInit(IOSCANPVT *ppvt) int xy2440Initialise( void ) { struct config2440 *plist = ptrXy2440First; #ifndef NO_EPICS { int i; for( i=0; i<MAXPORTS*MAXBITS; i++ ) { scanIoInit( &plist->biScan[i] ); scanIoInit( &plist->mbbiScan[i] ); } } #endif... }

21 21 2009: Device Support EPICS EPICS and Interrupts scanIoInit – contd struct config2440 {... #ifndef NO_EPICS IOSCANPVT biScan[MAXPORTS*MAXBITS]; IOSCANPVT mbbiScan[MAXPORTS*MAXBITS]; #endif } scanIoInit allocates an array of 3 scan lists, one for each callback priority (PRIO field). IOSCANPVT will hold the address of this array.

22 22 2009: Device Support EPICS EPICS and Interrupts get_ioint_info The DSET must have a get_ioint_info routine. This is called at iocInit for all records with SCAN = I/O Intr. Device support copies the IOSCANPVT value for this record (determined by which bit) into *ppvt typedef struct { int port; int bit; } xipIo_t; static long init_bi( struct biRecord *pbi ) { xipIo_t *pxip; switch(pbi->inp.type) { case(INST_IO): pxip = (xipIo_t *)malloc(sizeof(xipIo_t)); status = xipIoParse(pbi->inp.value.instio.string, pxip); pbi->dpvt = pxip; ret = 0; break; default: printf("Suitable error message\n"); ret = 1; break; } return(ret); }

23 23 2009: Device Support EPICS EPICS and Interrupts get_ioint_info – contd static long bi_ioinfo( int cmd, struct biRecord *pbi, IOSCANPVT *ppvt ) { struct config2440 *plist = ptrXy2440First; xipIo_t *pxip; pxip = (xipIo_t *)pbi->dpvt; /* "channel" is calculated from pxip->port, pxip->bit */ *ppvt = plist->biScan[channel]; return(0); } Return 0 if OK, else non-zero when scan will be reset to Passive Can usually ignore the cmd value: At iocInit this routine is called with cmd=0 for all records with SCAN=I/O Intr. If SCAN is later changed by a caPut or dbPut, this routine will be called again with cmd=1. We do not have to worry about this case. u get_ioint_info adds this record to the appropriate scan list, depending on PRIO.

24 24 2009: Device Support EPICS EPICS and Interrupts scanIoRequest In the ISR, determine which channel on the card caused the interrupt and then call: scanIoRequest(plist->biScan[channel]); u This causes all records in all 3 scan lists associated with plist->biScan[channel] to process!

25 25 2009: Device Support EPICS Asynchronous I/O u It is never permissible for Device Support to wait for slow I/O u If hardware read/write operations take a long time, (>100µsec) use asynchronous record processing u If the device does not provide a suitable completion interrupt, a background task can poll it periodically u An asynchronous read_write routine looks at precord->pact, and if FALSE, it: u Starts the I/O operation u Sets precord->pact = TRUE and returns

26 26 2009: Device Support EPICS Asynchronous I/O continued u When the operation completes, Device Support must run the following code at task level, not in the ISR: struct rset *prset = (struct rset *)precord->rset; dbScanLock(precord); (*prset->process)(precord); dbScanUnlock(precord); u The records process routine will call the Device Support read_write routine again. Now pact is TRUE, the read_write routine will: u Complete the I/O by setting the rval field etc. u Return 0

27 27 2009: Device Support EPICS Asynchronous example #include static long init_record(); static long read_ai(); static void myCallback( CALLBACK * ); typedef struct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read_ai; DEVSUPFUN special_linconv; } ANALOGDSET; ANALOGDSET devAiTestAsyn = { 6, NULL, NULL, init_record, NULL, read_ai, NULL }; /* Device Private Structure */ struct devPrivate { CALLBACK callback; /* EPICS CALLBACK structure */ WDOG_ID wdId; };

28 28 2009: Device Support EPICS Asynchronous example - continued static long init_record( struct aiRecord *pai ) { struct devPrivate *pdevp; pai->udf = FALSE; pdevp = (struct devPrivate *)(calloc(1,sizeof(struct devPrivate))); pai->dpvt = (void *)pdevp; callbackSetCallback( myCallback, &pdevp->callback ); callbackSetPriority( pai->prio, &pdevp->callback ); callbackSetUser( pai, &pdevp->callback ); pdevp->wdId = wdCreate(); return(0); } static long read_ai(struct aiRecord *pai) { struct devPrivate *pdevp = (struct devPrivate *)(pai->dpvt); int waitTime; if( pai->pact == FALSE ) { waitTime = (int)(pai->val * vxTicksPerSecond); printf("(%s) Starting Async. Processing...\n", pai->name); wdStart( pdevp->wdId, waitTime, (FUNCPTR)callbackRequest, (int)&pdevp->callback ); pai->pact = TRUE; return(0); } else { printf("(%s) Completed Async. Processing...\n", pai->name); return(2); /* No linear conversion in record */ }

29 29 2009: Device Support EPICS Asynchronous example - continued static void myCallback( CALLBACK *pCallback ) { struct dbCommon *precord; struct rset *prset; callbackGetUser( precord, pCallback ); prset = (struct rset *)precord->rset; dbScanLock(precord); (*prset->process)(precord); dbScanUnlock(precord); }

30 30 2009: Device Support EPICS The optional Driver layer u Some reasons to include a driver layer: u Share code between similar device support layers for different record types u Most digital I/O interfaces support record types bi, bo, mbbi, mbbo, mbbiDirect and mbboDirect u Initialize a software module before individual device layers using it are initialized u The order in which device support initialization is called is not guaranteed u Provide a common interface to an I/O bus such as GPIB, Bitbus, Allen-Bradley etc. u I/O devices placed on this bus need their own device support, but share the interface hardware u Provide a wrapper around commercial device drivers or other software libraries


Download ppt "1 2009: Device Support EPICS Device Support Andy Foster Observatory Sciences Limited."

Similar presentations


Ads by Google