asyn Training EPICS Collaboration Meeting April 2012 1
asyn Training EPICS Collaboration Meeting April 2012 1. Overview of asyn 2. Overview of asyn. Port. Driver 3. Writing an asyn driver Tutorial for Measurement Computing USB-1608 GX-2 A 0
asyn: An Interface Between EPICS Drivers and Clients Mark Rivers, Marty Kraimer, Eric Norum University of Chicago Advanced Photon Source SLAC asyn class, Day 1, December 6, 2011
What is asyn and why to we need it? Motivation • Standard EPICS interface between device support and drivers is only loosely defined • Needed custom device support for each driver • asyn provides standard interface between device support and device drivers • And a lot more too! EPICS IOC architecture Well defined Pretty well defined Poorly defined
History – why the name asyn • • asyn replaces earlier APS packages called Hi. DEOS and MPF (Message Passing Facility) The initial releases of asyn were limited to “asynchronous” devices (e. g. slow devices) – Serial – GPIB – TCP/IP asyn provided the thread per port and queuing that this support needs. Current version of asyn is more general, synchronous (non-blocking) drivers are also supported. We are stuck with the name, or re-writing a LOT of code! Independent of EPICS asyn is largely independent of EPICS (except for optional device support and asyn. Record). It only uses lib. Com from EPICS base for OS independence in standard utilities like threads, mutexes, events, etc. asyn can be used in code that does not run in an IOC – asyn drivers could be used with Tango or other control systems
asyn Architecture (client/server) Device support (or SNL code, another driver, or non-EPICS software) Interfaces (named; asyn. Common (connect, report, …) pure virtual functions) asyn. Octet (write, read, set. Input. Eos, …) Port (named object) Port driver addr=0 device addr=1 device
Control flow – asynchronous driver (slow device)
Control flow – synchronous driver (fast device)
asyn. Manager – Methods for drivers • register. Port – Flags for multidevice (addr), can. Block, is. Auto. Connect – Creates thread for each asynchronous port (can. Block=1) • register. Interface – asyn. Common, asyn. Octet, asyn. Int 32, etc. • register. Interrupt. Source, interrupt. Start, interrupt. End • interpose. Interface – e. g. interpose. Eos, interpose. Flush • Example code: p. Pvt->int 32 Array. interface. Type = asyn. Int 32 Array. Type; p. Pvt->int 32 Array. pinterface = (void *)&drv. Ip 330 Int 32 Array; p. Pvt->int 32 Array. drv. Pvt = p. Pvt; status = pasyn. Manager->register. Port(port. Name, ASYN_MULTIDEVICE, /*is multi. Device*/ 1, /* autoconnect */ 0, /* medium priority */ 0); /* default stack size */ status = pasyn. Manager->register. Interface(port. Name, &p. Pvt->common); status = pasyn. Int 32 Base->initialize(p. Pvt->port. Name, &p. Pvt->int 32); pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->int 32 Interrupt. Pvt);
asyn. Manager – Methods for Clients (e. g. Device Support) Create asyn. User Connect asyn. User to device (port) Find interface (e. g. asyn. Octet, asyn. Int 32, etc. ) Register interrupt callbacks Query driver characteristics (can. Block, is. Multidevice, is. Enabled, etc). • Queue request for I/O to port • • • – asyn. Manager calls callback when port is free • Will be separate thread for asynchronous port – I/O calls done directly to interface methods in driver • e. g. pasyn. Octet->write()
asyn. Manager – Methods for Clients (e. g. Device Support) Example code: record(longout, "$(P)$(R)Bin. X") { field(PINI, "YES") field(DTYP, "asyn. Int 32") field(OUT, "@asyn($(PORT), $(ADDR), $(TIMEOUT))BIN_X") field(VAL, "1") } /* Create asyn. User */ pasyn. User = pasyn. Manager->create. Asyn. User(process. Callback, 0); status = pasyn. Epics. Utils->parse. Link(pasyn. User, plink, &p. Pvt->port. Name, &p. Pvt->addr, &p. Pvt->user. Param); status = pasyn. Manager->connect. Device(pasyn. User, p. Pvt->port. Name, p. Pvt->addr); status = pasyn. Manager->can. Block(p. Pvt->pasyn. User, &p. Pvt->can. Block); pasyn. Interface = pasyn. Manager->find. Interface(pasyn. User, asyn. Int 32 Type, 1); status = pasyn. Manager->queue. Request(p. Pvt->pasyn. User, 0, 0); In process. Callback() status = p. Pvt->pint 32 ->read(p. Pvt->int 32 Pvt, p. Pvt->pasyn. User, &p. Pvt->value);
asyn. Manager – asyn. User • asyn. User data structure. This is the fundamental “handle” used by asyn. User = pasyn. Manager->create. Asyn. User(user. Callback queue, user. Callback timeout); asyn. User = pasyn. Manager->duplicate. Asyn. User)(pasyn. User, user. Callback queue, user. Callback timeout); typedef struct asyn. User { char *error. Message; int error. Message. Size; /* The following must be set by the user */ double timeout; /* Timeout for I/O operations */ void *user. Pvt; void *user. Data; /* The following is for user to/from driver communication */ void *drv. User; /* reason is normally set by driver in drv. User->create() * to identify “parameter” */ int reason; /* The following are for additional information from method calls */ int aux. Status; /* For auxillary status / } asyn. User;
Standard Interfaces • • • Common interface, all drivers must implement asyn. Common: report(), connect(), disconnect() I/O Interfaces, most drivers implement one or more All of these have write(), read(), register. Interupt. User() and cancel. Interrupt. User() methods asyn. Octet: flush(), set. Input. Eos(), set. Output. Eos(), get. Input. Eos(), get. Output. Eos() asyn. Int 32: get. Bounds() asyn. Int 8 Array, asyn. Int 16 Array, asyn. Int 32 Array: asyn. UInt 32 Digital: asyn. Float 64: asyn. Float 32 Array, asyn. Float 64 Array: asyn. Generic. Pointer: Miscellaneous interfaces asyn. Option: set. Option() get. Option() asyn. Gpib: address. Command(), universal. Command(), ifc(), ren(), etc. asyn. Drv. User: create(), free() Developers are free to create new interfaces. In practice I don’t know of any!
asyn. Standard. Interfaces. h Greatly reduces driver code when initializing standard interfaces. Just fill in fields in asyn. Standard. Interfaces structure and call asyn. Standard. Interfaces. Base->initialize(). typedef struct asyn. Standard. Interfaces { asyn. Interface common; asyn. Interface drv. User; asyn. Interface octet; int octet. Process. Eos. In; int octet. Process. Eos. Out; int octet. Interrupt. Process; int octet. Can. Interrupt; void *octet. Interrupt. Pvt; … asyn. Interface int 32; int 32 Can. Interrupt; void *int 32 Interrupt. Pvt; • asyn. Interface float 64 Array; int float 64 Array. Can. Interrupt; void *float 64 Array. Interrupt. Pvt; } asyn. Standard. Interfaces; typedef struct asyn. Standard. Interfaces. Base { asyn. Status (*initialize)(const char *port. Name, asyn. Standard. Interfaces *p. Interfaces, asyn. User *pasyn. User, void *p. Pvt); } asyn. Standard. Interfaces. Base; epics. Share. Extern asyn. Standard. Interfaces. Base *pasyn. Standard. Interfaces. Base;
Driver before asyn. Standard. Interfaces #include <asyn. Driver. h> #include <asyn. Int 32. h> #include <asyn. Int 8 Array. h> #include <asyn. Int 16 Array. h> #include <asyn. Int 32 Array. h> #include <asyn. Float 64 Array. h> #include <asyn. Octet. h> #include <asyn. Drv. User. h>. . . typedef struct drv. ADPvt {. . . /* Asyn interfaces */ asyn. Interface common; asyn. Interface int 32; void *int 32 Interrupt. Pvt; asyn. Interface float 64; void *float 64 Interrupt. Pvt; asyn. Interface int 8 Array; void *int 8 Array. Interrupt. Pvt; asyn. Interface int 16 Array; void *int 16 Array. Interrupt. Pvt; asyn. Interface int 32 Array; void *int 32 Array. Interrupt. Pvt; asyn. Interface float 32 Array; void *float 32 Array. Interrupt. Pvt; asyn. Interface float 64 Array; void *float 64 Array. Interrupt. Pvt; asyn. Interface octet; void *octet. Interrupt. Pvt; asyn. Interface drv. User; } drv. ADPvt;
Driver before asyn. Standard. Interfaces int drv. ADImage. Configure(const char *port. Name, const char *detector. Driver. Name, int detector) {. . . /* Create asyn. User for debugging */ p. Pvt->pasyn. User = pasyn. Manager->create. Asyn. User(0, 0); /* Link with higher level routines */ p. Pvt->common. interface. Type = asyn. Common. Type; p. Pvt->common. pinterface = (void *)&drv. ADCommon; p. Pvt->common. drv. Pvt = p. Pvt; p. Pvt->int 32. interface. Type = asyn. Int 32 Type; p. Pvt->int 32. pinterface = (void *)&drv. ADInt 32; p. Pvt->int 32. drv. Pvt = p. Pvt; p. Pvt->float 64. interface. Type = asyn. Float 64 Type; p. Pvt->float 64. pinterface = (void *)&drv. ADFloat 64; p. Pvt->float 64. drv. Pvt = p. Pvt; p. Pvt->int 8 Array. interface. Type = asyn. Int 8 Array. Type; p. Pvt->int 8 Array. pinterface = (void *)&drv. ADInt 8 Array; p. Pvt->int 8 Array. drv. Pvt = p. Pvt; p. Pvt->int 16 Array. interface. Type = asyn. Int 16 Array. Type; p. Pvt->int 16 Array. pinterface = (void *)&drv. ADInt 16 Array; p. Pvt->int 16 Array. drv. Pvt = p. Pvt; p. Pvt->int 32 Array. interface. Type = asyn. Int 32 Array. Type; p. Pvt->int 32 Array. pinterface = (void *)&drv. ADInt 32 Array; p. Pvt->int 32 Array. drv. Pvt = p. Pvt; p. Pvt->float 32 Array. interface. Type = asyn. Float 32 Array. Type; p. Pvt->float 32 Array. pinterface = (void *)&drv. ADFloat 32 Array; p. Pvt->float 32 Array. drv. Pvt = p. Pvt; p. Pvt->float 64 Array. interface. Type = asyn. Float 64 Array. Type; p. Pvt->float 64 Array. pinterface = (void *)&drv. ADFloat 64 Array; p. Pvt->float 64 Array. drv. Pvt = p. Pvt; p. Pvt->octet. interface. Type = asyn. Octet. Type; p. Pvt->octet. pinterface = (void *)&drv. ADOctet; p. Pvt->octet. drv. Pvt = p. Pvt; p. Pvt->drv. User. interface. Type = asyn. Drv. User. Type; p. Pvt->drv. User. pinterface = (void *)&drv. ADDrv. User; p. Pvt->drv. User. drv. Pvt = p. Pvt; . . .
Driver before asyn. Standard. Interfaces status = pasyn. Manager->register. Interface(port. Name, &p. Pvt->common); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register common. n"); return -1; } status = pasyn. Int 32 Base->initialize(p. Pvt->port. Name, &p. Pvt->int 32); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register int 32n"); return -1; } pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->int 32 Interrupt. Pvt); status = pasyn. Float 64 Base->initialize(p. Pvt->port. Name, &p. Pvt->float 64); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register float 64n"); return -1; } pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->float 64 Interrupt. Pvt); status = pasyn. Int 8 Array. Base->initialize(p. Pvt->port. Name, &p. Pvt->int 8 Array); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register int 8 Arrayn"); return -1; } pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->int 8 Array. Interrupt. Pvt); status = pasyn. Int 16 Array. Base->initialize(p. Pvt->port. Name, &p. Pvt->int 16 Array); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register int 16 Arrayn"); return -1; } pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->int 16 Array. Interrupt. Pvt);
Driver before asyn. Standard. Interfaces status = pasyn. Int 32 Array. Base->initialize(p. Pvt->port. Name, &p. Pvt->int 32 Array); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register int 32 Arrayn"); return -1; } pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->int 32 Array. Interrupt. Pvt); status = pasyn. Float 32 Array. Base->initialize(p. Pvt->port. Name, &p. Pvt->float 32 Array); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register float 32 Arrayn"); return -1; } pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->float 32 Array. Interrupt. Pvt); status = pasyn. Float 64 Array. Base->initialize(p. Pvt->port. Name, &p. Pvt->float 64 Array); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register float 64 Arrayn"); return -1; } pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->float 64 Array. Interrupt. Pvt); status = pasyn. Octet. Base->initialize(p. Pvt->port. Name, &p. Pvt->octet, 0, 0, 0); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register octetn"); return -1; } pasyn. Manager->register. Interrupt. Source(port. Name, &p. Pvt->octet. Interrupt. Pvt); status = pasyn. Manager->register. Interface(p. Pvt->port. Name, &p. Pvt->drv. User); if (status != asyn. Success) { errlog. Printf("drv. Asyn. ADConfigure ERROR: Can't register drv. Usern"); return -1; }
Driver after asyn. Standard. Interfaces #include <asyn. Standard. Interfaces. h>. . . typedef struct drv. ADPvt {. . . /* Asyn interfaces */ asyn. Standard. Interfaces asyn. Interfaces; } drv. ADPvt; int drv. ADImage. Configure(const char *port. Name, const char *detector. Driver. Name, int detector) {. . . asyn. Standard. Interfaces *p. Interfaces; . . . /* Create asyn. User for debugging and for standard. Bases */ p. Pvt->pasyn. User = pasyn. Manager->create. Asyn. User(0, 0); /* Set addresses of asyn interfaces */ p. Interfaces = &p. Pvt->asyn. Interfaces; p. Interfaces->common. pinterface p. Interfaces->drv. User. pinterface p. Interfaces->octet. pinterface p. Interfaces->int 32. pinterface p. Interfaces->float 64. pinterface p. Interfaces->int 8 Array. pinterface p. Interfaces->int 16 Array. pinterface p. Interfaces->int 32 Array. pinterface p. Interfaces->float 64 Array. pinterface = = = = = /* Define which interfaces can generate p. Interfaces->octet. Can. Interrupt = p. Interfaces->int 32 Can. Interrupt = p. Interfaces->float 64 Can. Interrupt = p. Interfaces->int 8 Array. Can. Interrupt = p. Interfaces->int 16 Array. Can. Interrupt = p. Interfaces->int 32 Array. Can. Interrupt = p. Interfaces->float 64 Array. Can. Interrupt = (void (void (void *)&drv. ADCommon; *)&drv. ADDrv. User; *)&drv. ADOctet; *)&drv. ADInt 32; *)&drv. ADFloat 64; *)&drv. ADInt 8 Array; *)&drv. ADInt 16 Array; *)&drv. ADInt 32 Array; *)&drv. ADFloat 64 Array; interrupts */ 1; 1; status = pasyn. Standard. Interfaces. Base->initialize(port. Name, p. Interfaces, p. Pvt->pasyn. User, p. Pvt); if (status != asyn. Success) { errlog. Printf("drv. ADImage. Configure ERROR: Can't register interfaces: %s. n", p. Pvt->pasyn. User->error. Message); return -1; }
Standard Interfaces - drv. User • • • pdrv. User->create(void *drv. Pvt, asyn. User *pasyn. User, const char *drv. Info, const char **pptype. Name, size_t *psize); drv. Info string is parsed by driver. It typically sets pasyn. User->reason to a parameter index value (e. g. mca. Elapsed. Live, mca. Erase, etc. ) More complex driver could set pasyn. User->drv. User to a pointer to something. Example record(mbbo, "$(P)$(HVPS)INH_LEVEL") { field(DESC, "Inhibit voltage level") field(PINI, "YES") field(ZRVL, "0") field(ZRST, "+5 V") field(ONVL, "1") field(ONST, "+12 V") field(DTYP, "asyn. Int 32") field(OUT, "@asyn($(PORT), $(ADDR), $(TIMEOUT))INHIBIT_LEVEL") } status = pasyn. Epics. Utils->parse. Link(pasyn. User, plink, &p. Pvt->port. Name, &p. Pvt->addr, &p. Pvt->user. Param); pasyn. Interface = pasyn. Manager->find. Interface(pasyn. User, asyn. Drv. User. Type, 1); status = pasyn. Drv. User->create(drv. Pvt, pasyn. User, p. Pvt->user. Param, 0, 0);
Support for Callbacks (Interrupts) • The standard interfaces asyn. Octet, asyn. Int 32, asyn. UInt 32 Digital, asyn. Float 64 and asyn. XXXArray all support callback methods for interrupts • register. Interrupt. User(…, user. Function, user. Private, …) – Driver will call user. Function(user. Private, pasyn. User, data) with new data – Callback will not be at interrupt level, so callback is not restricted in what it can do • Callbacks can be used by device support, other drivers, etc. • Example interrupt drivers – Ip 330 ADC, Ip. Unidig binary I/O, SIS 38 XX MCS, area. Detector drivers, etc. – Measurement Computing devices we will study and demo later this morning
Support for Interrupts – Ip 330 driver static void int. Func(void *drv. Pvt) {. . . for (i = p. Pvt->first. Chan; i <= p. Pvt->last. Chan; i++) { data[i] = (p. Pvt->regs->mail. Box[i + p. Pvt->mail. Box. Offset]); } /* Wake up task which calls callback routines */ if (epics. Message. Queue. Try. Send(p. Pvt->int. Msg. QId, data, sizeof(data)) == 0). . . } static void int. Task(drv. Ip 330 Pvt *p. Pvt) { while(1) { /* Wait for event from interrupt routine */ epics. Message. Queue. Receive(p. Pvt->int. Msg. QId, data, sizeof(data)); /* Pass int 32 interrupts */ pasyn. Manager->interrupt. Start(p. Pvt->int 32 Interrupt. Pvt, &pclient. List); pnode = (interrupt. Node *)ell. First(pclient. List); while (pnode) { asyn. Int 32 Interrupt *pint 32 Interrupt = pnode->drv. Pvt; addr = pint 32 Interrupt->addr; reason = pint 32 Interrupt->pasyn. User->reason; if (reason == ip 330 Data) { pint 32 Interrupt->callback(pint 32 Interrupt->user. Pvt, pint 32 Interrupt->pasyn. User, p. Pvt->corrected. Data[addr]); } pnode = (interrupt. Node *)ell. Next(&pnode->node); } pasyn. Manager->interrupt. End(p. Pvt->int 32 Interrupt. Pvt);
Support for Interrupts – Performance • Ip 330 ADC driver. Digitizing 16 channels at 1 k. Hz. • Generates interrupts at 1 k. Hz. • Each interrupt results in: – 16 asyn. Int 32 callbacks to dev. Int 32 Average generic device support – 1 asyn. Int 32 Array callback to fast. Sweep device support for MCA records – 1 asyn. Float 64 callback to dev. Epid. Fast for fast feedback • 18, 000 callbacks per second • 21% CPU load on MVME 2100 PPC-603 CPU with feedback on and MCA fast sweep acquiring.
Generic Device Support • asyn includes generic device support for many standard EPICS records and standard asyn interfaces • Eliminates need to write device support in virtually all cases. New hardware can be supported by writing just a driver. • Record fields: – field(DTYP, “asyn. Int 32”) – field(INP, “@asyn(port. Name, addr, timeout) drv. Info. String) • Examples: – asyn. Int 32 • ao, ai, bo, bi, mbbo, mbbi, longout, longin – asyn. Int 32 Average • ai – asyn. UInt 32 Digital, asyn. UInt 32 Digital. Interrupt • bo, bi, mbbo, mbbi, mbbo. Direct, mbbi. Direct, longout, longin – asyn. Float 64 • ai, ao – asyn. Octet • stringin, stringout, waveform (in and out) – asyn. XXXArray • waveform (in and out)
Generic Device Support • All syn. Apps modules I am responsible for now use standard asyn device support, and no longer have specialized device support code: – – – area. Detector 2 D detectors Modbus General Modbus driver dxp (XIA Saturn, XMAP, Mercury spectroscopy systems) Ip 330 16 -channel 16 -bit Industry Pack ADC Ip. Unidig 24 bit Industry Pack digital I/O module quad. EM APS VME quad electrometer dac 128 V 8 channel 12 -bit Industry Pack DAC meas. Comp Measurement Computing USB modules (more later) Canberra ICB modules (Amp, ADC, HVPS, TCA) SIS 38 XX multichannel scalers Motors: Newport XPS, Parker Aries, ACS MCB-4 B
Generic Device Support • MCA and motor records use special device support, because they are not base record types. – Single device-independent device support file – Only driver is device-dependent • MCA and new motor drivers now only use the standard asyn interfaces, so it is possible (in principle) to write a database using only standard records and control any MCA driver or new motor driver
Generic Device Support corvette> view. . /Db/ip 330 Scan. template record(ai, "$(P)$(R)") { field(SCAN, "$(SCAN)") field(DTYP, "asyn. Int 32 Average") field(INP, "@asyn($(PORT) $(S))DATA") field(LINR, "LINEAR") field(EGUF, "$(EGUF)") field(EGUL, "$(EGUL)") field(HOPR, "$(HOPR)") field(LOPR, "$(LOPR)") field(PREC, "$(PREC)") } record(longout, "$(P)$(R)Gain") { field(PINI, "YES") field(VAL, "$(GAIN)") field(DTYP, "asyn. Int 32") field(OUT, "@asyn($(PORT) $(S))GAIN") }
asyn. Record • EPICS record that provides access to most features of asyn, including standard I/O interfaces • Applications: – Control tracing (debugging) – Connection management – Perform interactive I/O • Very useful for testing, debugging, and actual I/O in many cases • Replaces the old generic “serial” and “gpib” records, but much more powerful
asyn. Record – asyn. Octet devices Configure serial port parameters Interactive I/O to octet devices (serial, TCP/IP, GPIB, etc. ) Perform GPIB specific operations
asyn. Record – register devices Same asyn. Record, change to ADC port Read ADC at 10 Hz with asyn. Int 32 interface
asyn. Record – register devices Same asyn. Record, change to DAC port Write DAC with asyn. Float 64 interface
Synchronous interfaces • Standard interfaces also have a synchronous interface, even for slow devices, so that one can do I/O without having to implement callbacks • Example: asyn. Octet. Sync. IO – write(), read(), write. Read() • Very useful when communicating with a device that can block, when it is OK to block • Example applications: – EPICS device support in init_record(), (but not after that!) – SNL programs, e. g. communicating with serial or TCP/IP ports – Any asynchronous asyn port driver communicating with an underlying asyn. Octet port driver (e. g. motor drivers) – area. Detector driver talking to mar. CCD server, Pilatus camserver, etc. – iocsh commands
Synchronous interfaces – Tektronix scope driver example • In initialization: /* Connect to scope */ status = pasyn. Octet. Sync. IO->connect(scope. VXI 11 Name, 0, &this->pasyn. User. Scope, NULL); • In IO: status = pasyn. Octet. Sync. IO->write. Read(pasyn. User. Scope, send. Message, num. Send, receive. Message, sizeof(receive. Message), WRITE_READ_TIMEOUT, &num. Sent, response. Len, &eom. Reason);
iocsh Commands asyn. Report(filename, level, port. Name) asyn. Interpose. Flush. Config(port. Name, addr, timeout) asyn. Interpose. Eos. Config(port. Name, addr) asyn. Set. Trace. Mask(port. Name, addr, mask) asyn. Set. Trace. IOMask(port. Name, addr, mask) asyn. Set. Trace. File(port. Name, addr, filename) asyn. Set. Trace. IOTruncate. Size(port. Name, addr, size) asyn. Set. Option(port. Name, addr, key, val) asyn. Show. Option(port. Name, addr, key) asyn. Auto. Connect(port. Name, addr, yes. No) asyn. Enable(port. Name, addr, yes. No) asyn. Octet. Connect(entry, port. Name, addr, oeos, ieos, timeout, buffer_len) asyn. Octet. Read(entry, nread, flush) asyn. Octet. Write(entry, output) asyn. Octet. Write. Read(entry, output, nread) asyn. Octet. Flush(entry) asyn. Octet. Set. Input. Eos(port. Name, addr, eos, drv. Info) asyn. Octet. Get. Input. Eos(port. Name, addr, drv. Info) asyn. Octet. Set. Output. Eos(port. Name, addr, eos, drv. Info) asyn. Octet. Get. Output. Eos(port. Name, addr, drv. Info)
Tracing and Debugging • • • Standard mechanism for printing diagnostic messages in device support and drivers Messages written using EPICS logging facility, can be sent to stdout, stderr, or to a file. Device support and drivers call: – asyn. Print(pasyn. User, reason, format, . . . ) – asyn. Print. IO(pasyn. User, reason, buffer, len, format, . . . ) – Reason: • • ASYN_TRACE_ERROR ASYN_TRACEIO_DEVICE ASYN_TRACEIO_FILTER ASYN_TRACEIO_DRIVER ASYN_TRACE_FLOW Tracing is enabled/disabled for (port/addr) Trace messages can be turned on/off from iocsh, vx. Works shell, and from CA clients such as medm via asyn. Record. asyn. Octet I/O from shell
Fast feedback device support (epid record) • Supports fast PID control • Input: any driver that supports asyn. Float 64 with callbacks (e. g. callback on interrupt) • Output: any driver that supports asyn. Float 64. • In real use at APS for monochromator feedback with IP ADC/DAC, and APS VME beam position monitor and DAC • >1 k. Hz feedback rate
asyn: Drivers Included in the Module • drv. Asyn. Serial. Port – Driver for serial ports on most OS (Linux, Windows, Darwin, vx. Works, RTEMS, etc. ) – drv. Asyn. Serial. Port. Configure("port. Name", "tty. Name", priority, no. Auto. Connect, no. Process. Eos. In) – asyn. Set. Option("port. Name", addr, "key", "value") Key Value baud 9600 50 75 110 134 150 200 300 600 1200. . . 230400 bits 8765 parity none even odd stop 12 clocal YN crtscts NY ixon NY ixoff NY ixany NY
asyn: Drivers Included in the Module drv. Asyn. IPPort – driver for IP network communications drv. Asyn. IPPort. Configure("port. Name", "host. Info", priority, no. Auto. Connect, no. Process. Eos) host. Info - The Internet host name, port number and optional IP protocol of the device (e. g. "164. 54. 9. 90: 4002", "serials 8 n 3: 4002 TCP" or "164. 54. 17. 43: 5186 udp"). Protocols: TCP (default) UDP* — UDP broadcasts. The address portion of the argument must be the network broadcast address (e. g. "192. 168. 1. 255: 1234 UDP*"). HTTP — Like TCP but for servers which close the connection after each transaction. COM — For Ethernet/Serial adapters which use the TELNET RFC 2217 protocol. This allows port parameters (speed, parity, etc. ) to be set with subsequent asyn. Set. Option commands just as for local serial ports. The default parameters are 9600 -8 -N-1 with no flow control.
Where does an output record (ao, longout, mbbo, etc. ) get its initial value? 1. From the ao. Record. dbd file 2. From the database file you load 3. asyn device support init_record function does a read from your asyn driver to read the current value. If your driver returns asyn. Success on that read then that value is used. – Supports bumpless reboots. – If using asyn. Port driver then if your driver has done set. Integer. Param, set. Double. Param, or set. String. Param before init_record (i. e. typically in constructor) then the read. Int 32, etc. functions will return asyn. Success. If set. Int 32 Param has not been done then read. Int 32 returns asyn. Error, and that value will not be used. – 4. From save/restore 5. dbpf at the end of startup script.
asyn: Problems and Future Work • No support for driver providing enum strings to device support. – Currently enum strings must be hardcoded in the database. – Sometimes they should be generated by the driver, depending on what model device is connected. – They can even change dynamically: the list of valid gains can change when the readout speed changes. – Need to add new asyn. Enum. String interface, and it should support callbacks • No support for passing status information in the asyn callback functions. – This means that records with SCAN=I/O Intr will not go into alarm status when the driver detects an error. – Subject of multiple tech-talk requests – Seemed quite difficult to fix, because changing the interface to add status to the callback function would break all existing asyn drivers that do callbacks. – But I just realized on the plane ride out that pasyn. User->aux. Status could be used for this! • It would almost always be 0 now (=asyn. Success) so using non-zero value (e. g. asyn. Error, asyn. Timeout) is unlikely to break existing code.
Summary- Advantages of asyn • Drivers implement standard interfaces that can be accessed from: – Multiple record types – SNL programs – Other drivers • Generic device support eliminates the need for separate device support in 99% (? ) of cases – syn. Apps package 10 -20% fewer lines of code, 50% fewer files with asyn • Consistent trace/debugging at (port, addr) level • asyn. Record can be used for testing, debugging, and actual I/O applications • Easy to add asyn interfaces to existing drivers: – Register port, implement interface write(), read() and change debugging output – Preserve 90% of driver code • asyn drivers are actually EPICS-independent. Can be used in any other control system.
- Slides: 40