version 2.2
This commit is contained in:
634
doc/businterface.html
Normal file
634
doc/businterface.html
Normal file
@ -0,0 +1,634 @@
|
||||
<!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="sls_icon.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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<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.
|
||||
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>disconnect()</code>;
|
||||
This function should return <code>true</code> immediately or
|
||||
<code>false</code> if disconnecting is impossible.
|
||||
There is no callback for <code>disconnect()</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>
|
||||
<script src="stream.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user