This product is available via open source license described at the end of this document.
asynDriver is a general purpose facility for interfacing device specific code to low level communication drivers
A primary target for asynDriver is EPICS IOC device support but, other than using libCom, it is independent of EPICS.
The following are some of the existing EPICS general purpose device support systems that have been converted to use asynDriver.
The following are some of the existing EPICS general purpose device support systems that could be converted to use asynDriver.
Each of these systems is used at EPICS facilities for accessing GPIB and/or serial devices. Because device support has been written for many instruments and thousands of database records use the device support, users will not be easily persuaded to switch from their existing solution. Thus asynDriver implements a framework below device support that can be used by all of the above systems so that all can share the same drivers.
Each system needs to be modified so that the device support component is compatible with existing use but replace the driver part with asynDriver. The benefit is that all could share the same set of low level drivers.
gpibCore has already been converted and is included with asynDriver.
Marty Kraimer will convert mpfSerial. Hopefully Dirk Zimoch will get time soon to convert streams and Allen Honey time to convert devAscii.
In the future other protocols will be supported especially for Ethernet based devices.
This version provides
The current version does not implement gpib specific methods. This will be done for a future release.
The National Instruments 1014 VME to GPIB driver has not been converted to asynDriver. This also will be done for a future release.
asynManager locks it's internal data structures so that modifications are thread safe. One exception is that report does not lock. If new ports or process modules are registered while report is active, report could have problems. Does this matter?
Interface asynGpib defines methods to handle SRQs. Should a more general interrupt mechanism be provided? Perhaps is is best to wait until a need arises.
The idea of creating asynDriver resulted from many years of experience with writing device support for serial and GPIB devices. The following individuals have been most influential.
asynDriver is a software layer between device specific code and communication drivers that send/receive messages to/from devices. asynDriver defines the following terminology:
All communication between software layers is done via interfaces. An interface definition is a C language structure consisting entirely of methods (functions). An asynDriver interface is analogous to a C++ or Java pure virtual interface.
A communication entity over which message are sent. Whenever this document uses the word port without a qualifier, it means a communication port. A port provides access to one or more devices.
The interfaces are defined so that most device specific code can communicate via a large variety of different types of port. If device support does all it's communication via reads and writes of messages consisting of 8 bit bytes (octets) then it should work with almost all types of port. If device support requires more complicated support then the types of ports will be more limited.
Examples of ports are GPIB controllers, serial ports, Ethernet ports, etc. One or more devices can be attached to a port. For example only one device can be attached to an RS-232 port but up to 15 devices can be attached to a GPIB port.
Multiple layers can exist between device specific code and a port driver. A process module can be registered with the queue manager. Just like a port driver a process module implements interfaces. The asynManager:findInterface method looks first for process module interfaces and then for driver interfaces. A process module normally calls drivers as part of it's processing.
For more complicated protocols additional layers can be created. For example GPIB support is implemented as an asynGpib interface which is called by user code and a asynGpibPort interface which is called by asynGpib.
A driver can implement multiple interfaces. For example asynGpib implements asynCommon, asynOctet, and asynGpib.
Asynchronous driver support uses the Operating System Independent features of EPICS base. It is, however, independent of record/device support. Thus it can be used by other code, e.g. a sequence program.
Provides the following services.
asynCommon is a set of methods that must be implemented by all drivers. The methods are:
asynOctet is a set of methods implemented by any driver that accepts octet messages (messages consisting of 8-bit bytes) and returns octet responses. This interface will be sufficient for most device specific code. For example the code for streams protocol files needs only this interface. The term octet is used instead of ASCII because the only requirement is that messages consist of 8-bit bytes. The methods are:
asynTrace is a set of methods for generating diagnostic messages.
During initialization a driver registers each communication port with asynManager.
User code creates an asynUser by calling pasynManager->createAsynUser. The address of the asynUser is passed to most other asynDriver methods.
User code connects to a device, which is located located at some address on a port, and communicates with the device via combination of asynManager and one or more interfaces.
User code communicates with drivers via the following method:
pasynManager->queueRequest(...)
asynDriver.h contains the following definitions:
typedef enum { asynSuccess,asynTimeout,asynOverflow,asynError }asynStatus; typedef enum { asynQueuePriorityLow,asynQueuePriorityMedium,asynQueuePriorityHigh }asynQueuePriority; typedef struct asynUser { char *errorMessage; int errorMessageSize; /* The following can be set by the user */ double timeout; /*Timeout for I/O operations*/ void *userPvt; }asynUser; typedef void (*userCallback)(asynUser *pasynUser); typedef struct asynInterface{ const char *interfaceType; /*For example asynCommonType*/ void *pinterface; /*For example pasynCommon */ void *drvPvt; }asynInterface; typedef struct asynManager { void (*report)(FILE *fd,int details); asynUser *(*createAsynUser)(userCallback queue,userCallback timeout); asynStatus (*freeAsynUser)(asynUser *pasynUser); asynStatus (*connectDevice)(asynUser *pasynUser, const char *portName,int addr); asynStatus (*disconnectDevice)(asynUser *pasynUser); asynInterface *(*findInterface)(asynUser *pasynUser, const char *interfaceType,int processModuleOK); asynStatus (*queueRequest)(asynUser *pasynUser, asynQueuePriority priority,double timeout); /*cancelRequest returns (0,-1) if request (was, was not) queued*/ int (*cancelRequest)(asynUser *pasynUser); asynStatus (*lock)(asynUser *pasynUser); /*lock portName,addr */ asynStatus (*unlock)(asynUser *pasynUser); int (*getAddr)(asynUser *pasynUser); /* drivers call the following*/ asynStatus (*registerPort)(const char *portName, asynInterface *paasynInterface,int nasynInterface, unsigned int priority,unsigned int stackSize); /* paasynInterface is pointer to array of asynInterface */ /*process modules call the following */ asynStatus (*registerProcessModule)( const char *processModuleName,const char *portName,int addr, asynInterface *paasynInterface,int nasynInterface); }asynManager; epicsShareExtern asynManager *pasynManager; /*Methods supported by ALL asyn drivers*/ #define asynCommonType "asynCommon" typedef struct asynCommon { void (*report)(void *drvPvt,FILE *fd,int details); /*following are to connect/disconnect to/from hardware*/ asynStatus (*connect)(void *drvPvt,asynUser *pasynUser); asynStatus (*disconnect)(void *drvPvt,asynUser *pasynUser); /*The following are generic methods to set/get port options*/ asynStatus (*setPortOption)(void *drvPvt, asynUser *pasynUser, const char *key, const char *val); asynStatus (*getPortOption)(void *drvPvt, asynUser *pasynUser, const char *key, char *val, int sizeval); }asynCommon; /* Methods supported by low level octet drivers. */ #define asynOctetType "asynOctet" typedef struct asynOctet{ int (*read)(void *drvPvt,asynUser *pasynUser, char *data,int maxchars); int (*write)(void *drvPvt,asynUser *pasynUser, const char *data,int numchars); asynStatus (*flush)(void *drvPvt,asynUser *pasynUser); asynStatus (*setEos)(void *drvPvt,asynUser *pasynUser, const char *eos,int eoslen); asynStatus (*getEos)(void *drvPvt,asynUser *pasynUser, char *eos, int eossize, int *eoslen); }asynOctet; /*asynTrace is implemented by asynManager*/ /*All asynTrace methods can be called from any thread*/ /* traceMask definitions*/ #define ASYN_TRACE_ERROR 0x0001 #define ASYN_TRACEIO_DEVICE 0x0002 #define ASYN_TRACEIO_FILTER 0x0004 #define ASYN_TRACEIO_DRIVER 0x0008 #define ASYN_TRACE_FLOW 0x0010 /* traceIO mask definitions*/ #define ASYN_TRACEIO_NODATA 0x0000 #define ASYN_TRACEIO_ASCII 0x0001 #define ASYN_TRACEIO_ESCAPE 0x0002 #define ASYN_TRACEIO_HEX 0x0004 /* asynPrint and asynPrintIO are macros that act like int asynPrint(asynUser *pasynUser,int reason, const char *format, ... ); int asynPrintIO(asynUser *pasynUser,int reason, const char *buffer, int len, const char *format, ... ); */ typedef struct asynTrace { /* lock/unlock are only necessary if caller performs I/O other then*/ /* by calling asynTrace methods */ asynStatus (*lock)(asynUser *pasynUser); asynStatus (*unlock)(asynUser *pasynUser); asynStatus (*setTraceMask)(asynUser *pasynUser,int mask); int (*getTraceMask)(asynUser *pasynUser); asynStatus (*setTraceIOMask)(asynUser *pasynUser,int mask); int (*getTraceIOMask)(asynUser *pasynUser); asynStatus (*setTraceFILE)(asynUser *pasynUser,FILE *fd); FILE *(*getTraceFILE)(asynUser *pasynUser); asynStatus (*setTraceIOTruncateSize)(asynUser *pasynUser,int size); int (*getTraceIOTruncateSize)(asynUser *pasynUser); int (*print)(asynUser *pasynUser,int reason, const char *pformat, ...); int (*printIO)(asynUser *pasynUser,int reason, const char *buffer, int len,const char *pformat, ...); }asynTrace; epicsShareExtern asynTrace *pasynTrace;
asynUser describes a structure that user code must provide for most asynManager and driver methods. Code must allocate and free an asynUser by calling asynUserCalloc and asynUserFree.
errorMessage | When either asynManager or a driver returns a status!=asynSuccess
it should put an error message into errorMessage via a call to
epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,"<format>",...) |
errorMessageSize | The size of errorMessage. The user can not change this value. |
timeout | The number of seconds before timeout for I/O requests. This is set by the user and can be changed between calls to drivers. |
puserPvt | For use by the user. The user should set this immediately after the call to pasynManager->createAsynUser. If this is changed while asynUser is queued, the results are undefined, e.g. it could cause a crash. |
asynManager contains the following methods.
report | Reports status about the asynManager. It also calls asynCommon.report for each registered port driver.. |
createAsynUser | Creates an asynUser. The caller specifies two callbacks, one for successful queueRequests and one if a queueRequest has a timeout. The timeout callback is optional. errorMessageSize characters are allocated for errorMessage. The amount of storage can not be changed. This method doesn't return if it is unable to allocate the storage. |
freeAsynUser | Free an asynUser. The user must free it only via this call. The call will fail if the asynUser is connected to a device. |
connectDevice | Device code calls this to connect to a device. It passes the name of the communication port and the address of the device.. The port Name is the same as that specified in the call to registerPort. The call will fail if the asynUser is already connected to a device. |
disconnectDevice | Disconnect. The call will fail if the asynUser is queued or locked. |
findInterface | Find a driver interface. If processModuleOK is true and a
processModule is reqistered for the device and address, then it's
asynInterface is returned; otherwise the asynInterface of the port
driver is returned. It returns 0 if the interfaceType is not
supported. The user needs the address of the drivers interface and
the address of pdrvPvt so that calls can be made to the driver. For
example:
asynInterface *pasynInterface; asynOctet *pasynOctet; void *pasynOctetPvt; ... pasynInterface = pasynManager->findInterface( pasynUser,asynOctetType,1); if(!pasynInterface) { /*error do something*/} pasynOctet = (asynOctet *)pasynInterface->pinterface; pasynOctetPvt = pasynInterface->pdrvPvt; ... pasynOctet->read(pasynOctetPvt,pasynUser,... |
queueRequest | Except for method report, a device support thread never calls a driver directly. Instead it calls queueRequest. After the thread associated with the port takes this request from the queue, it calls the queue callback specified in the call to createAsynUser. The callback makes calls to the driver. If the asynUser is already on a queue, asynError is returned. The timeout is from when the request is queued until it is taken from the queue. A value less than or equal to 0.0 means no timeout. The request is removed from the queue before the callback is called. Thus callbacks are allowed to lock, unlock, and issue new queue requests. |
cancelRequest | If a asynUser is queued remove it from the queue. If it is not on a queue nothing is done. In particular if the callback is active, this call has no effect. A return value of (0,-1) means that a request (was, was not) removed from the queue. |
lock/unlock | lock/unlock are used to block other users from accessing an instrument while a user is making a series of queueRequests. Note that only the addr specified in the connectDevice request is locked. asynManager locks when a queueRequest for a locked asynUser is taken from the queue. At that point all other entries in the queue must wait until unlock is called. lock/unlock fail if a request is currently queued. |
getAddr | Returns the addr that was specified in the call to connectDevice. |
registerPort | This method is called by drivers. A call is made for each communication interface instance. If priority is 0 then a default will be assigned. If stackSize is 0 a default is assigned. The portName argument specifies the name by which the upper levels of the asyn code will refer to this communication interface instance. |
registerProcessModule | This method is called by a process manager, i.e. code that wants to be called instead of the low level driver itself. Normally it adds additional functionality to the low level driver, It in turn normally calls the low level driver. It must be called after the driver calls registerDriver and before the client code calls findInterface. |
asynCommon describes the methods that must be implemented by all drivers.
report | Generates a report about the hardware device. |
connect | Connect to the hardware device or communication path. This is called by asynManager after the driver has called registerDriver. It may also be called by command utilities that first call disconnect and then connect. |
disconnect | Disconnect from the hardware device. This is normally called by command utilities that want to stop and then restart communication to a device. |
setPortOption | This is a generic routine for setting a port option. The arguments are a key,value pairs. The meaning is port driver specific. |
getPortOption | This is a generic routine for getting a port option. The value for the key is written into val. |
NOTE: The name octet is used instead of ASCII because it implies that communication is done via 8-bit bytes.
asynOctet describes the methods implemented by drivers that use octet strings for sending commands and receiving responses from a device.
read | Read a message from the device. The routine returns the number of 8-bit bytes read from the device or -1 to indicate error. | ||
write | Send a message to the device. The routine returns the number of 8-bit bytes sent to the device or -1 to indicate error. | ||
flush | Flush the input buffer. | ||
setEos | Set End Of String. For example "\n". Note that gpib drivers often accept at most a one character string. | getEos | Get the current end of string. |
asynDriver provides a trace facility with the following attributes:
In order for the trace facility to perform properly, device support, and all drivers must use the trace facility according to the above guidelines. Device and driver support can directly call the asynManager methods. The asynPrint and asynPrintIO macros are provided so that it is easier for device/driver support. Support can have calls like.
asynPrintIO(pasynUser,ASYN_TRACE_FLOW,"%s Calling queueRequest\n", someName);
The asynPrintIO call is designed for device support or drivers that do not know it they are sending ascii strings or binary data. The can make calls like:
asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER,data,nchars,"%s nchars %d ", someName,nchars);
The asynTrace methods are implemented by asynManager. These methods can be used by any code that has created an asynUser and connected to a device. All methods can be called by any thread. If a thread performs all I/O via calls to print or printIO, then it does not have to call lock or unlock. If it does want to do it's own I/O, it must lock before any I/O and unlock after. For example:
pasynTrace->lock(pasunUser); fd = pasynTrace->getTraceFILE(pasunUser); /*perform I/O of fd */ pasynTrace->unlock(pasunUser);methods can be called by any thread. If some code wants to do it's own I/O instead of calling print or printIO, then it must call lock before asynManager and driver methods. Code must allocate and free an asynUser by calling asynUserCalloc and asynUserFree.
lock/unlock | These are only needed if some code wants to do it's own I/O instead of using print and printIO. Set methods, print, and printIO all lock while performing their operations. The get routines do not lock but except for getTraceFILE they are safe. The worst that happens is that the user gets a little more or a little less output. |
setTraceMask | Set the trace mask. Normally set by the user requesting it via a shell command or the devTrace device support. |
getTraceMask | Get the trace mask. Support that wants to issue trace messages calls this to what trace options have been requested. |
setTraceIOMask | Set the traceIO mask. Normally set by the user requesting it via a shell command or the devTrace device support. |
getTraceIOMask | Get the traceIO mask. Support that wants to issue it's own IO messages instead of calling asynPrintIO should call this and honor the mask settings. Most code will not need it. |
setTraceFILE | Set the file descriptor to use for output. A null value means stdout. Normally set by the user requesting it via a shell command or the devTrace device support. |
getTraceFILE | Get the file descriptor to use for output. Support that wants to issue it's own IO messages instead of calling asynPrintIO should call this and honor the mask settings. In this case lock must have been called first. Most code will not need it. |
setTraceIOTruncateSize | Determines how much data is printed by printIO. In all cases it determines how many bytes of the buffer are displayed. The actual number of characters printed depends on the traceIO mask. For example ASYN_TRACEIO_HEX results in 3 characters being printed for each byte. Normally set by the user requesting it via a shell command or the devTrace device support. |
getTraceIOTruncateSize | Get the current truncate size. Called by asynPrintIO. Code that does it's own I/O should also support the traceIO mask. |
If reason ored with the current traceMask is not zero then the message is printed. Most code should call asynPrint instead of calling this method | |
printIO | If reason ored with the current traceMask is not zero then the message is printed. If len is >0 then the buffer is printed using the traceIO mask and getTraceIOTruncateSize to decide how to print. Most code should call asynPrintIO instead of calling this method |
The following reads from an instrument via octet messages.
#include <asynCommon.h> ... #define BUFSIZE 80 typedef struct myData { asynOctet *pasynOctet; void *pdrvPvt; char buffer[BUFSIZE]; }myData; void queueCallback(asynUser *pasynUser) myData *pmydata = (myData *)puserPvt; asynOctet *pasynOctet = pmydata->pasynOctet; void *pdrvPvt = pmydata->pdrvPvt; asynStatus status; int retlen; asynPrint(pasynUser,ASYN_TRACE_FLOW,"queueCallback entered\n"); status = pasynOctet->setEos(pdrvPvt,pasynUser,"\n",1); if(status!=asynSuccess) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "queueCallback setEos failed %s\n",pasynUser->errorMessage); } retlen = pasynOctet->read(pdrvPvt,pasynUser,pmydata->buffer,BUFSIZE); if(retlen<=0) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "queueCallback read failed %s\n",pasynUser->errorMessage); } else { asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE, pmydata->buffer,BUFSIZE, "queueCallback read returned: retlen %d data %s\n", retlen,pmydata->buffer); } } void mainThread(void) { myData *pmyData; asynUser *pasynUser; asynStatus status; asynInterface *pasynInterface; pmyData = calloc(1,sizeof(myData)); pasynUser = pasynManager->createAsynUser(queueCallback,0); pasynUser->userPvt = pmyData; status = pasynManager->connectDevice(pasynUser,"serialPort1",0) if(status!=asynSuccess) { printf("can't connect to serialPort1 %s\n",pasynUser->errorMessage); exit(1); } pasynInterface = (asynOctet *)pasynManager->findInterface( pasynUser,asynOctetType,1); if(!pasynInterface) { printf("%s driver not supported\n",asynOctetType); exit(-1); } pmyData->pasynOctet = (asynOctet *)pasynInterface->pinterface; pmyData->pdrvPvt = pasynInterface->pdrvPvt; status = pasynManager->queueRequest(pasynUser,asynQueuePriorityLow, 0.0); if(status) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "queueRequest failed %s\n",pasynUser->errorMessage); exit(1); } /*Note that callback will be called by another thread*/ ... }
The flow of control is as follows:
GPIB has additional features that are not supported by asynCommon and asynOctet. asynGpib defines two interfaces.
asynGpibDriver.h contains the following definitions:
#include "asynDriver.h" #define asynGpibUserType "asynGpibUser" /* GPIB drivers */ /*asynGpib defines methods called by GPIB aware users*/ struct asynGpib{ /*addressedCmd,...,ren are just passed to device handler*/ asynStatus (*addressedCmd) (void *drvPvt,asynUser *pasynUser, const char *data, int length); asynStatus (*universalCmd) (void *drvPvt,asynUser *pasynUser, int cmd); asynStatus (*ifc) (void *drvPvt,asynUser *pasynUser); asynStatus (*ren) (void *drvPvt,asynUser *pasynUser, int onOff); /* The following are implemented by asynGpib */ asynStatus (*registerSrqHandler)(void *drvPvt,asynUser *pasynUser, srqHandler handler, void *srqHandlerPvt); void (*pollAddr)(void *drvPvt,asynUser *pasynUser, int onOff); /* The following are called by low level gpib drivers */ /*srqHappened is passed the pointer returned by registerPort*/ void *(*registerPort)( const char *portName, asynGpibPort *pasynGpibPort, void *asynGpibPortPvt, unsigned int priority, unsigned int stackSize); void (*srqHappened)(void *asynGpibPvt); }; epicsShareExtern asynGpib *pasynGpib; struct asynGpibPort { /*asynCommon methods */ void (*report)(void *drvPvt,FILE *fd,int details); asynStatus (*connect)(void *drvPvt,asynUser *pasynUser); asynStatus (*disconnect)(void *drvPvt,asynUser *pasynUser); asynStatus (*setPortOption)(void *drvPvt,asynUser *pasynUser, const char *key,const char *val); asynStatus (*getPortOption)(void *drvPvt,asynUser *pasynUser, const char *key,char *val,int sizeval); /*asynOctet methods passed through from asynGpib*/ int (*read)(void *drvPvt,asynUser *pasynUser,char *data,int maxchars); int (*write)(void *drvPvt,asynUser *pasynUser,const char *data,int numchars); asynStatus (*flush)(void *drvPvt,asynUser *pasynUser); asynStatus (*setEos)(void *drvPvt,asynUser *pasynUser, const char *eos,int eoslen); asynStatus (*getEos)(void *drvPvt,asynUser *pasynUser, char *eos, int eossize, int *eoslen); /*asynGpib methods passed thrtough from asynGpib*/ asynStatus (*addressedCmd) (void *drvPvt,asynUser *pasynUser, const char *data, int length); asynStatus (*universalCmd) (void *drvPvt, asynUser *pasynUser, int cmd); asynStatus (*ifc) (void *drvPvt,asynUser *pasynUser); asynStatus (*ren) (void *drvPvt,asynUser *pasynUser, int onOff); /*asynGpibPort specific methods */ int (*srqStatus) (void *drvPvt); asynStatus (*srqEnable) (void *drvPvt, int onOff); asynStatus (*serialPollBegin) (void *drvPvt); int (*serialPoll) (void *drvPvt, int addr, double timeout); asynStatus (*serialPollEnd) (void *drvPvt); };
asynGpib describes the interface for device support code. It provides gpib specific functions like SRQ handling. It makes calls to asynGpibPort. Note that asynGpib.c also implements asynCommon and asynOctet.
addressedCmd | The request is passed to the low level driver. |
universalCmd | The request is passed to the low level driver. |
ifc | The request is passed to the low level driver. |
ren | The request is passed to the low level driver. |
registerSrqHandler | Register an srq handler for port,addr. The handler will be called when an SRQ is detected for that port,addr. |
pollAddr | Set SRQ polling on or off. onOff = (0,1) means (disable, enable) SRQ polling of specified address. |
registerPort | Register a port. When asynGpib receives this request it calls asynManager.registerPort. |
srqHappened | Called by low level driver when it detects that a GPIB device issues an SRQ. |
asynGpibPort is the interface that is implemented by gpib drivers, e.g. the vxi11. It provides:
asynCommon methods | All the methods of asynCommon |
asynOctet methods | All the methods of asynOctet |
addressedCmd | Issue a GPIB addressed command. |
universalCmd | Issue a GPIB universal command. |
ifc | Issue a GPIB Interface Clear command. |
ren | Issue a GPIB Remote Enable command |
srqStatus | Returns (0,1) if SRQ (is not, is) set. Normally only called by asynGpib. |
srqEnable | Enable or disable SRQs. Normally only called by asynGpib. |
serialPollBegin | Start of serial poll. Normally only called by asynGpib. |
serialPoll | Poll the specified address and return its response. Normally only called by asynGpib. |
serialPollEnd | End of serial poll. Normally only called by asynGpib. |
The generic serial driver supports devices connected to serial ports on the IOC and devices connected through Ethernet/Serial converter boxes.
Serial ports are configured with the drvGenericSerialConfigure and asynSetPortOption commands:
drvGenericSerialConfigure("portName","ttyName",priority,openOnlyOnDisconnect) asynSetPortOption("portName","key","value")where the arguments are:
The following table summarizes the generic serial driver asynSetPortOption keys and values. Default values are enclosed in square brackets.
Key | Value |
---|---|
baud | [9600] 50 75 110 134 150 200 300 600 1200 ... 230400 |
bits | [8] 7 6 5 |
parity | [none] even odd |
stop | [1] 2 |
clocal | [Y] N |
ctrscts | [N] Y |
Serial ports directly attached to a vxWorks IOC may need to be set up using hardware-specific commands. Once this is done the standard drvGenericSerialConfigure and asynSetPortOption commands can be issued. For example, the following example shows the configuration procedure for a port on a GreenSprings octal UART Industry-Pack module on a GreenSprings VIP616-01 carrier.
ipacAddVIPC616_01("0x6000,B0000000") tyGSOctalDrv(1) tyGSOctalModuleInit("RS232", 0x80, 0, 0) tyGSOctalDevCreate("/tyGS/0/0",0,0,1000,1000) drvGenericSerialConfigure("L0","/tyGS/0/0",0,0) asynSetPortOption("L0","baud","9600")The vxWorks serial driver does not provide independent control of the hardware handshaking and modem control lines thus
"clocal","Y"
implies "crtscts","N"
and "clocal","N"
implies
"crtscts","Y"
.
Consult the following documents (available on-line for free) for details.
VMEbus Extensions for Instrumentation VXI-11 TCP/IP Instrument Protocol Specification VXI-11.1 TCP/IP-VXIbus Interface Specification VXI-11.2 TCP/IP-IEEE 488.1 Interface Specification VXI-11.3 TCP/IP-IEEE 488.2 Instrument Interface Specification
The following commands may be specified in the st.cmd file
E2050Reboot("inet_addr") E5810Reboot("inet_addr","password") vxi11Configure("portName","inet_addr",recoverWithIFC,timeout,"vxiName",priority)where
This is support for the Green Springs Industry Pack GPIB carrier. The configuration command is:
gsIP488Configure(portName,carrier,module,intVec,priority)where
An example is:
#The following is for the Greensprings IP488 on an MV162 ipacAddMVME162("A:l=3,3 m=0xe0000000,64") gsIP488Configure("L0",0,0,0x61,0)
asynReport(filename,level) asynSetTraceMask(portName,addr,mask) asynSetTraceIOMask(portName,addr,mask) asynSetPortOption(portName,key,val) asynShowPortOption(portName,key)
asynReport
calls asynCommon:report
for all
registered drivers and processModules. asynSetTraceMask
calls
asynTrace:setTraceMask
for the specified port and address.
asynSetTraceIOMask
calls asynTrace:setTraceIOMask
for the specified port and address. asynSetPortOption
calls
asynCommon:setPortOption
. asynShowPortOption
calls
asynCommon:getPortOption
.
where
stdout
This provides a generic facility for setting trace options via MEDM. It consists of the following components:
devAsynTrace.c
devAsynTrace.dbd
file that must be included
by any application that wants to use this facility. This also provides
a driver(drvAsyn) that has a report method called by dbior.asynTrace.db
$(ioc):$(port)$(addr)
.asynTrace.adl
The following is the medm display.
.../support/asyn/
gunzip <file>.tar.gz tar xvf <file>.tar
.../support/asyn/X-Ywhere X-Y is the release. For example.
.../support/asyn/1-1
Since asynDriver does NOT provide support for specific instruments an application must obtain instrument specific support elsewhere. This section only explains how to include asynDriver components.
In the configure/RELEASE
file add definitions for
IPAC
and EPICS_BASE
.
In the src directory where the application is built
Makefile
<app>_LIBS += asyn
<app>Include.dbd
include "asyn.dbd" include "devAsynTrace.dbd"
In the st.cmd
file add.
dbLoadRecords("db/asynTrace.db","ioc=<ioc>,port=<port>,addr=<addr>")
This is done for each instrument. You must provide correct values for <ioc>,<port>, and <addr>
Once the application is running the medm display for each imstrument can be started by:
medm -x -macro "ioc=<ioc>,port=<port>,addr=<addr>" <asyntop>/testApp/adl/asynTrace.adl &
Again this done for each instrument. You must provide correct values for <ioc>,<port>, and <addr>
Copyright (c) 2002 University of Chicago All rights reserved. asynDriver is distributed subject to the following license conditions: SOFTWARE LICENSE AGREEMENT Software: asynDriver 1. The "Software", below, refers to asynDriver (in either source code, or binary form and accompanying documentation). Each licensee is addressed as "you" or "Licensee." 2. The copyright holders shown above and their third-party licensors hereby grant Licensee a royalty-free nonexclusive license, subject to the limitations stated herein and U.S. Government license rights. 3. You may modify and make a copy or copies of the Software for use within your organization, if you meet the following conditions: a. Copies in source code must include the copyright notice and this Software License Agreement. b. Copies in binary form must include the copyright notice and this Software License Agreement in the documentation and/or other materials provided with the copy. 4. You may modify a copy or copies of the Software or any portion of it, thus forming a work based on the Software, and distribute copies of such work outside your organization, if you meet all of the following conditions: a. Copies in source code must include the copyright notice and this Software License Agreement; b. Copies in binary form must include the copyright notice and this Software License Agreement in the documentation and/or other materials provided with the copy; c. Modified copies and works based on the Software must carry prominent notices stating that you changed specified portions of the Software. 5. Portions of the Software resulted from work developed under a U.S. Government contract and are subject to the following license: the Government is granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable worldwide license in this computer software to reproduce, prepare derivative works, and perform publicly and display publicly. 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED. 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGES.