646 lines
24 KiB
HTML
646 lines
24 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
|
"http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>StreamDevice: Bus API</title>
|
|
<link rel="shortcut icon" href="favicon.ico">
|
|
<link rel="stylesheet" type="text/css" href="stream.css">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<meta name="author" content="Dirk Zimoch">
|
|
</head>
|
|
<body>
|
|
<iframe src="nav.html" id="navleft"></iframe>
|
|
<h1>Bus API</h1>
|
|
|
|
<a name="class"></a>
|
|
<h2>Bus Interface Class</h2>
|
|
<p>
|
|
<em>StreamDevice</em> already comes with an interface to <a target="ex"
|
|
href="http://www.aps.anl.gov/epics/modules/soft/asyn/">
|
|
<em>asynDriver</em></a>.
|
|
You should first try to implement your bus driver compatible to
|
|
<em>asynDriver</em>.
|
|
Then it can be used by <em>StreamDevice</em> automatically.
|
|
Only if that does not work, write your own bus interface.
|
|
</p>
|
|
<p>
|
|
A bus interface is a C++ class that inherits from
|
|
<em>StreamBusInterface</em>.
|
|
Its purpose is to provide an interface to <em>StreamDevice</em> for a
|
|
low-level I/O bus driver.
|
|
<em>StreamDevice</em> acts as a client of the interface, calling interface
|
|
methods and receiving replies via callbacks.
|
|
Since the internal details of <em>StreamDevice</em> are not of
|
|
interest to a bus interface, I will reference it simply as
|
|
<em>client</em> in this chapter.
|
|
The interface class must be registered via a call to
|
|
<code><a href="#registration">
|
|
RegisterStreamBusInterface</a>()</code>
|
|
in the global context of the C++ file (not in a header file).
|
|
</p>
|
|
<p>
|
|
Interface methods called by the client must not block for arbitrary
|
|
long times.
|
|
That means the interface is allowed to take mutex semaphores to protect
|
|
its internal data structures but it must not take event semaphores to
|
|
wait for external I/O or similar.
|
|
</p>
|
|
<p>
|
|
It is assumed that the interface creates a separate thread to handle
|
|
blocking I/O and to call the callback methods in the context of that
|
|
thread when I/O has completed or timed out.
|
|
The callback methods don't block but may in turn call interface methods.
|
|
Much of the actual work will be done in the context of those callbacks,
|
|
i.e. in the interface thread, thus be generous with stack.
|
|
</p>
|
|
|
|
<h3>Example bus interface class declaration</h3>
|
|
<pre>
|
|
#include <StreamBusInterface.h>
|
|
|
|
class MyInterface : StreamBusInterface
|
|
{
|
|
// ... (internally used attributes and methods)
|
|
|
|
<a href="#create">MyInterface</a>(Client* client);
|
|
<a href="#create">~MyInterface</a>();
|
|
|
|
// StreamBusInterface virtual methods
|
|
bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms);
|
|
bool <a href="#lock">unlock</a>();
|
|
bool <a href="#write">writeRequest</a>(const void* output, size_t size,
|
|
unsigned long writeTimeout_ms);
|
|
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms,
|
|
unsigned long readTimeout_ms,
|
|
long expectedLength, bool async);
|
|
bool <a href="#read">supportsAsyncRead</a>();
|
|
bool <a href="#event">supportsEvent</a>();
|
|
bool <a href="#event">acceptEvent</a>(unsigned long mask,
|
|
unsigned long replytimeout_ms);
|
|
bool <a href="#connect">connectRequest</a>(unsigned long connecttimeout_ms);
|
|
bool <a href="#connect">disconnect</a>();
|
|
void <a href="#lock">finish</a>();
|
|
|
|
public:
|
|
// creator method
|
|
static StreamBusInterface* <a href="#create">getBusInterface</a>(
|
|
Client* client, const char* busname,
|
|
int addr, const char* param);
|
|
};
|
|
|
|
<a href="#registration">RegisterStreamBusInterface</a>(MyInterface);
|
|
|
|
// ... (implementation)
|
|
</pre>
|
|
|
|
<h3>Methods to implement</h3>
|
|
<p>
|
|
The interface class must implement a public static creator method:
|
|
</p>
|
|
<div class="indent"><code>
|
|
static StreamBusInterface*
|
|
<a href="#create">getBusInterface</a>(Client* client,
|
|
const char* busname, int addr,
|
|
const char* param);
|
|
</code></div>
|
|
<p>
|
|
And it must implement the following pure virtual methods:
|
|
</p>
|
|
<div class="indent"><code>
|
|
bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool <a href="#lock">unlock</a>();
|
|
</code></div>
|
|
<p>
|
|
It may implement additional virtual methods if the bus supports it:
|
|
</p>
|
|
<div class="indent"><code>
|
|
bool <a href="#write">writeRequest</a>(const void* output,
|
|
size_t size, unsigned long writeTimeout_ms);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool <a href="#read">readRequest</a>(unsigned long replyTimeout_ms,
|
|
unsigned long readTimeout_ms,
|
|
long expectedLength, bool async);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool <a href="#read">supportsAsyncRead</a>();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool <a href="#event">supportsEvent</a>();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool <a href="#event">acceptEvent</a>(unsigned long mask,
|
|
unsigned long replytimeout_ms);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool <a href="#connect">connectRequest</a>(unsigned long connecttimeout_ms);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool <a href="#connect">disconnect</a>();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void <a href="#lock">finish</a>();
|
|
</code></div>
|
|
<p>
|
|
It also may override the following virtual method:
|
|
</p>
|
|
<div class="indent"><code>
|
|
void <a href="#create">release</a>();
|
|
</code></div>
|
|
|
|
<h3>Callback methods provided</h3>
|
|
<p>
|
|
The base class <em>StreamBusInterface</em> implements a set of protected
|
|
callback methods which must be called in response to the above request
|
|
methods (most probably from another thread):
|
|
</p>
|
|
<div class="indent"><code>
|
|
void <a href="#lock">lockCallback</a>(StreamIoStatus status);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void <a href="#write">writeCallback</a>(StreamIoStatus status);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
long <a href="#read">readCallback</a>(StreamIoStatus status,
|
|
const void* input = NULL,
|
|
long size = 0);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void <a href="#event">eventCallback</a>(StreamIoStatus status);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void <a href="#connect">connectCallback</a>(StreamIoStatus status);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void <a href="#connect">disconnectCallback</a>(StreamIoStatus status);
|
|
</code></div>
|
|
|
|
<h3>Other provided methods, attibutes, and types</h3>
|
|
|
|
<div class="indent"><code>
|
|
<a href="#create">StreamBusInterface</a>(Client* client);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
long <a href="#lock">priority</a>();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
const char* <a href="#create">clientName</a>();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
const char* <a href="#write">getOutTerminator</a>(size_t& length);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
const char* <a href="#read">getInTerminator</a>(size_t& length);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
enum StreamIoStatus {StreamIoSuccess, StreamIoTimeout, StreamIoNoReply, StreamIoEnd, StreamIoFault};
|
|
</code></div>
|
|
|
|
<a name="theory"></a>
|
|
<h2>Theory of Operation</h2>
|
|
|
|
<a name="registration"></a>
|
|
<h3>Registration</h3>
|
|
<div class="indent"><code>
|
|
RegisterStreamBusInterface(<i>interfaceClass</i>);
|
|
</code></div>
|
|
<p>
|
|
During initialization, the macro <code>RegisterStreamBusInterface()</code>
|
|
registers the bus interface.
|
|
It must be called exactly once for each bus interface class in global
|
|
file context.
|
|
</p>
|
|
|
|
<a name="create"></a>
|
|
<h3>Creation and deletion</h3>
|
|
<div class="indent"><code>
|
|
static StreamBusInterface* getBusInterface(Client* client,
|
|
const char* busname, int addr,
|
|
const char* param);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
StreamBusInterface(Client* client);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void release();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
const char* clientName();
|
|
</code></div>
|
|
|
|
<p>
|
|
During startup, each client instance searches for its bus interface
|
|
by name.
|
|
It does so by calling the static <code>getBusInterface()</code> method
|
|
of every registered interface class.
|
|
This method should check by <code>busname</code> if its interface class
|
|
is responsible for that bus.
|
|
If yes, it should check if the address <code>addr</code> is valid and
|
|
associate a <em>device</em> with <code>busname</code>/<code>addr</code>.
|
|
Some busses do not have addresses and allow only one device
|
|
(e.g. RS232).
|
|
Interfaces to such busses can ignore <code>addr</code>.
|
|
The bus interface may then try to connect to the device, but it should
|
|
allow it to be disconnected or switched off at that time.
|
|
If the bus interface requires additional parameters, parse the
|
|
<code>param</code> string.
|
|
Your constructor should pass <code>client</code> to the base class
|
|
constructor <code>StreamBusInterface(Client* client)</code>.
|
|
</p>
|
|
<p>
|
|
On success, <code>getBusInterface</code> should then return a pointer
|
|
to a bus interface instance.
|
|
Note that many client instances may want to connect to the same device.
|
|
Each needs its own bus interface instance.
|
|
The bus interface can get a string containing the name of the
|
|
client instance from <code>clientName()</code>.
|
|
This name is for use in error and log messages.
|
|
</p>
|
|
<p>
|
|
On failure, or if this interface class is not responsible for that bus,
|
|
<code>getBusInterface</code> should return <code>NULL</code>.
|
|
The client will then try other bus interface classes.
|
|
</p>
|
|
<p>
|
|
When the client does not need the interface any more, it calls
|
|
<code>release()</code>.
|
|
The default implementation of <code>release()</code> assumes that
|
|
<code>getBusInterface()</code> has allocated a new bus interface
|
|
and just calls <code>delete</code>.
|
|
You should change <code>release()</code> if that assumption is not
|
|
correct.
|
|
</p>
|
|
|
|
<a name="connect"></a>
|
|
<h3>Connecting and disconnecting</h3>
|
|
<div class="indent"><code>
|
|
bool connectRequest(unsigned long connecttimeout_ms);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool disconnect();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void connectCallback(IoStatus status);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void disconnectCallback(IoStatus status);
|
|
</code></div>
|
|
<p>
|
|
Connection should be handled automatically.
|
|
If the device is disconnected, each attempt to access the
|
|
device should try to (re-)connect.
|
|
Normally, the interface should not try to disconnect unless
|
|
the device does so.
|
|
</p>
|
|
<p>
|
|
However, sometimes the client wants to connect or
|
|
disconnect explicitely.
|
|
To connect, the client calls <code>connectRequest()</code>.
|
|
This function should return <code>true</code> immediately
|
|
or <code>false</code> if the request cannot be accepted or connection
|
|
handling is not supported.
|
|
The interface should call <code>connectCallback(StreamIoSuccess)</code>
|
|
once the bus could be connected.
|
|
If the bus cannot be connected within <code>connecttimeout_ms</code>
|
|
milliseconds, the bus interface should call
|
|
<code>connectCallback(StreamIoTimeout)</code>.
|
|
</p>
|
|
<p>
|
|
If a device cannot be connected, for example because there is
|
|
something wrong with the I/O hardware,
|
|
<code>connectCallback(StreamIoFault)</code> may be called.
|
|
</p>
|
|
<p>
|
|
To disconnect, the client calls <code>disconnectRequest()</code>;
|
|
This function should return <code>true</code> immediately or
|
|
<code>false</code> if the request cannot be accepted or connection
|
|
handling is not supported.
|
|
The interface should call <code>connectCallback(StreamIoSuccess)</code>
|
|
once the bus is disconnected. There is no timeout for this operation.
|
|
If disconnecting is impossible, the interface should call
|
|
<code>connectCallback(StreamIoFault)</code>.
|
|
</p>
|
|
|
|
<a name="lock"></a>
|
|
<h3>Bus locking</h3>
|
|
<div class="indent"><code>
|
|
bool lockRequest(unsigned long lockTimeout_ms);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void lockCallback(IoStatus status);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool unlock();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
long priority();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void finish();
|
|
</code></div>
|
|
<p>
|
|
Before doing output, the client calls <code>lockRequest()</code> to get
|
|
exclusive access to the device.
|
|
This function should return <code>true</code> immediately
|
|
or <code>false</code> if the request cannot be accepted.
|
|
If the device is already locked, the bus interface should add itself to
|
|
a queue, sorted by <code>priority()</code>.
|
|
As soon as the device is available, the bus interface should call
|
|
<code>lockCallback(StreamIoSuccess)</code>.
|
|
If the bus cannot be locked within <code>lockTimeout_ms</code>
|
|
milliseconds, the bus interface should call
|
|
<code>lockCallback(StreamIoTimeout)</code>.
|
|
</p>
|
|
<p>
|
|
If a device cannot be locked, for example because there is
|
|
something wrong with the I/O hardware,
|
|
<code>lockCallback(StreamIoFault)</code> may be called.
|
|
</p>
|
|
<p>
|
|
Normally, it is not necessary to lock the complete bus but only one
|
|
device (i.e. one address).
|
|
Other clients should still be able to talk to other devices on the same bus.
|
|
</p>
|
|
<p>
|
|
The client may perform several read and write operations when it has
|
|
locked the device.
|
|
When the protocol ends and the device is locked, the client calls
|
|
<code>unlock()</code>.
|
|
If other bus interfaces are in the lock queue, the next one should
|
|
call <code>lockCallback(StreamIoSuccess)</code> now.
|
|
</p>
|
|
<p>
|
|
The client calls <code>finish()</code> when the protocol ends.
|
|
This allows the bus interface to clean up.
|
|
The bus interface should also cancel any outstanding requests of
|
|
this client.
|
|
</p>
|
|
|
|
<a name="write"></a>
|
|
<h3>Writing output</h3>
|
|
<div class="indent"><code>
|
|
bool writeRequest(const void* output,
|
|
size_t size, unsigned long writeTimeout_ms);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void writeCallback(IoStatus status);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
const char* getOutTerminator(size_t& length);
|
|
</code></div>
|
|
<p>
|
|
To start output, the client calls <code>writeRequest()</code>.
|
|
You can safely assume that the device has already been locked at this
|
|
time.
|
|
That means, no other client will call <code>writeRequest()</code>
|
|
for this device and no other output is currently active for this device
|
|
until it has been unlocked.
|
|
</p>
|
|
<p>
|
|
The function should arrange transmission of <code>size</code> bytes of
|
|
<code>output</code> but return <code>true</code> immediately
|
|
or <code>false</code> if the request cannot be accepted.
|
|
It must not block until output has completed.
|
|
After all output has been successfully transmitted, but not earlier, the
|
|
interface should call <code>writeCallback(StreamIoSuccess)</code>.
|
|
</p>
|
|
<p>
|
|
If output blocks for <code>writeTimeout_ms</code> milliseconds,
|
|
the interface should abort the transmision and call
|
|
<code>writeCallback(StreamIoTimeout)</code>.
|
|
</p>
|
|
<p>
|
|
If output is impossible, for example because there is
|
|
something wrong with the I/O hardware,
|
|
<code>writeCallback(StreamIoFault)</code> may be called.
|
|
</p>
|
|
<p>
|
|
The interface must transmit excactly the <code>size</code> bytes
|
|
from <code>output</code>.
|
|
It must not change anything and it should not assume that
|
|
any bytes have a special meaning.
|
|
In particular, a null byte does not terminate <code>output</code>.
|
|
</p>
|
|
<p>
|
|
A call to <code>getOutTerminator</code> tells the interface which
|
|
terminator has already been added to the output.
|
|
If <code>NULL</code> was returned, the client is not aware of a
|
|
terminator (no outTerminator was defined in the protocol).
|
|
In this case, the interface may add a terminator which it knows from
|
|
other sources.
|
|
An interface is not required to support <code>NULL</code> results
|
|
and may not add any terminator in this case.
|
|
</p>
|
|
<p>
|
|
The buffer referenced by <code>output</code> stays valid until
|
|
<code>writeCallback()</code> is called.
|
|
</p>
|
|
<p>
|
|
The client may request more I/O or call <code>unlock()</code> after
|
|
<code>writeCallback()</code> has been called.
|
|
</p>
|
|
|
|
<a name="read"></a>
|
|
<h3>Reading input</h3>
|
|
<div class="indent"><code>
|
|
bool readRequest(unsigned long replyTimeout_ms,
|
|
unsigned long readTimeout_ms,
|
|
long expectedLength, bool async);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
long readCallback(IoStatus status,
|
|
const void* input = NULL,
|
|
long size = 0);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
const char* getInTerminator(size_t& length);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool supportsAsyncRead();
|
|
</code></div>
|
|
<p>
|
|
The client calls <code>readRequest()</code> to tell the bus interface
|
|
that it expects input.
|
|
Depending on the bus, this function might have to set the bus hardware
|
|
into receive mode.
|
|
If <code>expectedLength>0</code>, the the bus interface should stop
|
|
input after this number of bytes have been received.
|
|
In opposite to writing, the device may be in a non-locked status when
|
|
<code>readRequest()</code> is called.
|
|
</p>
|
|
<p>
|
|
This function must not block until input is available.
|
|
Instead, it should arrange for
|
|
<code>readCallback(StreamIoSuccess, buffer, size)</code> to be called
|
|
when input has been received and return <code>true</code>
|
|
immediately or <code>false</code> if the request cannot be accepted.
|
|
</p>
|
|
<p>
|
|
Here, <code>buffer</code> is a pointer to
|
|
<code>size</code> input bytes.
|
|
The bus interface is responsible for the buffer.
|
|
The client copies its contents. It does not modify or free it.
|
|
</p>
|
|
<p>
|
|
It is not necessary to wait until all data has been received.
|
|
The bus interface can call <code>n=readCallback()</code> after
|
|
any amount of input has been received.
|
|
If the client needs more input, <code>readCallback()</code>
|
|
returns a non-zero value.
|
|
A positive <code>n</code> means, the client needs another
|
|
<code>n</code> bytes of input.
|
|
A negative <code>n</code> means, the client needs an unspecified
|
|
amount of additional input.
|
|
</p>
|
|
<p>
|
|
With some bus interfaces, <code>readRequest()</code> might not have to
|
|
do anything because the bus is always receiving.
|
|
It might also be that the bus has no local buffer associated to store
|
|
input before it is fetched with some <code>read()</code> call.
|
|
In this case, a race condition between device and client can occure.
|
|
To avoid loss of data, <code>readCallback(StreamIoSuccess, buffer, size)</code>
|
|
may be called in this case even before <code>readRequest()</code>.
|
|
If the client is expecting input in the next future, it will store it.
|
|
Otherwise the input is dropped.
|
|
</p>
|
|
<p>
|
|
The <code>replyTimeout_ms</code> parameter defines how many milliseconds
|
|
to wait for the first byte of a reply before the device is considered
|
|
offline.
|
|
If no input has been received after <code>replyTimeout_ms</code>
|
|
milliseconds, the bus interface should call
|
|
<code>readCallback(StreamIoNoReply)</code>.
|
|
</p>
|
|
<p>
|
|
The <code>readTimeout_ms</code> parameter is the maximum time to wait
|
|
for further input.
|
|
If input stops for longer than <code>readTimeout_ms</code> milliseconds
|
|
the bus interface should call
|
|
<code>readCallback(StreamIoTimeout,buffer,size)</code>.
|
|
The client decides if this timeout is an error or a legal termination.
|
|
Thus, pass all input received so far.
|
|
</p>
|
|
<p>
|
|
A call to <code>getInTerminator(length)</code> tells the interface which
|
|
terminator is expected for input and <code>length</code> is set to the
|
|
number of bytes of the terminator. The result is a hint to the bus
|
|
interface to recognize the end of an input.
|
|
Once the terminator string is found, the bus interface should stop
|
|
receiving input and call
|
|
<code>readCallback(StreamIoSuccess, buffer, size)</code>.
|
|
It is not necessary to remove the terminator string from the received input.
|
|
An empty terminator string (<code>length==0</code>) means:
|
|
Don't look for terminators.
|
|
</p>
|
|
<p>
|
|
If <code>NULL</code> was returned, the client is not aware of a
|
|
terminator (no inTerminator was defined in the protocol).
|
|
In this case, the interface may look for a terminator which it knows from
|
|
other sources, reduce size by the terminator length and call
|
|
<code>readCallback(StreamIoEnd, buffer, size)</code>.
|
|
A bus interface is not required to support <code>NULL</code> results and
|
|
may treat them as empty terminator (see above).
|
|
</p>
|
|
<p>
|
|
Some busses (e.g. GPIB) support special "end of message" signals.
|
|
If such a signal is received, the bus interface should call
|
|
<code>readCallback(StreamIoEnd, buffer, size)</code>.
|
|
Use it to indicate a special "end of message" signal which is not
|
|
visible in the normal byte data stream.
|
|
If <code>getInTerminator()</code> has not returned <code>NULL</code>
|
|
it it not necessary to remove a terminator which may come in
|
|
addition to the "end of message" signal.
|
|
</p>
|
|
<p>
|
|
If input is impossible, for example because there is
|
|
something wrong with the I/O hardware,
|
|
<code>readCallback(StreamIoFault)</code> may be called.
|
|
</p>
|
|
<p>
|
|
If the <code>async</code> flag is <code>true</code>, the client
|
|
wants to read input asyncronously without any timeout.
|
|
That means, the bus interface should call <code>readCallback()</code>
|
|
even if the input was requested by another client.
|
|
</p>
|
|
<p>
|
|
If a client wishes to receive asynchonous input, it first calls
|
|
<code>supportsAsyncRead()</code>.
|
|
The default implementation of this method always returns
|
|
<code>false</code>.
|
|
A bus interface may overwrite this method to return <code>true</code>
|
|
and eventually prepare for asynchonous input.
|
|
The client is then allowed to call <code>readRequest()</code> with
|
|
the <code>async==true</code>.
|
|
This means that the client is interested in any input.
|
|
It should receive a <code>readCallback()</code> of all input which came
|
|
in response to a synchonous (<code>async==false</code>) request from
|
|
another client (which of course should receive the input, too).
|
|
The interface should also receive asynchonous input when no
|
|
synchonous client is active at the moment.
|
|
Many asynchonous <code>readRequest()</code> calls from different clients
|
|
may be active at the same time.
|
|
All of them should receive the same input.
|
|
</p>
|
|
<p>
|
|
For asynchonous requests, <code>replyTimeout_ms</code> has a different
|
|
meaning: If the bus interface has to poll the bus for input, it may take
|
|
<code>replyTimeout_ms</code> as a hint for the poll period.
|
|
If many asynchonous requests are active at the same time, it should poll
|
|
with the shortest period of all clients.
|
|
An asynchonous request does not time out.
|
|
It stays active until the next input arrives.
|
|
The client may reissue the asynchronous <code>readRequest()</code>
|
|
from within the <code>readCallback()</code> if it wants to continue
|
|
receiving asynchonous input.
|
|
</p>
|
|
<p>
|
|
If the client calls <code>finish()</code> at any time, the bus
|
|
interface should cancel all outstanding requests, including
|
|
asynchonous read requests.
|
|
</p>
|
|
<a name="event"></a>
|
|
<h3>Handling events</h3>
|
|
<div class="indent"><code>
|
|
bool supportsEvent();
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
bool acceptEvent(unsigned long mask, unsigned long replytimeout_ms);
|
|
</code></div>
|
|
<div class="indent"><code>
|
|
void eventCallback(StreamIoStatus status);
|
|
</code></div>
|
|
<p>
|
|
An event is a sort of input from a device which is not part of
|
|
the normal byte stream.
|
|
One example is the SRQ line of GPIB.
|
|
Not all bus types have events.
|
|
To support events, the bus interface must overwrite
|
|
<code>supportsEvent()</code> to return <code>true</code>.
|
|
The default implementation always returns <code>false</code>.
|
|
</p>
|
|
<p>
|
|
If <code>true</code> is returned, the client is allowed to call
|
|
<code>acceptEvent()</code>, where <code>mask</code> defines the
|
|
(bus dependent) type of event or events to wait for.
|
|
If <code>mask</code> is illegal, <code>acceptEvent()</code> should
|
|
return <code>false</code>.
|
|
The call to <code>acceptEvent()</code> must not block.
|
|
It should arrange to call <code>eventCallback(StreamIoSuccess)</code>
|
|
when the event matching <code>mask</code> arrives within
|
|
<code>replytimeout_ms</code> milliseconds.
|
|
If no such event arrives within this time, the bus interface
|
|
should call <code>eventCallback(StreamIoTimeout)</code>.
|
|
</p>
|
|
<p>
|
|
To avoid race conditions, the bus interface should buffer events and
|
|
also report a matching event which occured before the actual call
|
|
to <code>acceptEvent()</code> but after any previous call of any
|
|
other request method like <code>writeRequest()</code>.
|
|
</p>
|
|
<hr>
|
|
<p><small>Dirk Zimoch, 2007</small></p>
|
|
</body>
|
|
</html>
|