documentation update

This commit is contained in:
2018-08-06 17:40:49 +02:00
parent 03d6d9672e
commit bb66a49ec1
4 changed files with 195 additions and 98 deletions

View File

@ -19,7 +19,7 @@
href="http://www.aps.anl.gov/epics/modules/soft/asyn/"> href="http://www.aps.anl.gov/epics/modules/soft/asyn/">
<em>asynDriver</em></a>. <em>asynDriver</em></a>.
You should first try to implement your bus driver compatible to You should first try to implement your bus driver compatible to
<em>asynDriver</em>. <em>asynOctet</em>.
Then it can be used by <em>StreamDevice</em> automatically. Then it can be used by <em>StreamDevice</em> automatically.
Only if that does not work, write your own bus interface. Only if that does not work, write your own bus interface.
</p> </p>
@ -68,17 +68,13 @@ class MyInterface : StreamBusInterface
// StreamBusInterface virtual methods // StreamBusInterface virtual methods
bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms); bool <a href="#lock">lockRequest</a>(unsigned long lockTimeout_ms);
bool <a href="#lock">unlock</a>(); bool <a href="#lock">unlock</a>();
bool <a href="#write">writeRequest</a>(const void* output, size_t size, bool <a href="#write">writeRequest</a>(const void* output, size_t size, unsigned long writeTimeout_ms);
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">readRequest</a>(unsigned long replyTimeout_ms,
unsigned long readTimeout_ms,
long expectedLength, bool async);
bool <a href="#read">supportsAsyncRead</a>(); bool <a href="#read">supportsAsyncRead</a>();
bool <a href="#event">supportsEvent</a>(); bool <a href="#event">supportsEvent</a>();
bool <a href="#event">acceptEvent</a>(unsigned long mask, bool <a href="#event">acceptEvent</a>(unsigned long mask, unsigned long timeout_ms);
unsigned long replytimeout_ms); bool <a href="#connect">connectRequest</a>(unsigned long timeout_ms);
bool <a href="#connect">connectRequest</a>(unsigned long connecttimeout_ms); bool <a href="#connect">disconnectRequest</a>();
bool <a href="#connect">disconnect</a>();
void <a href="#lock">finish</a>(); void <a href="#lock">finish</a>();
public: public:
@ -132,13 +128,13 @@ bool <a href="#event">supportsEvent</a>();
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
bool <a href="#event">acceptEvent</a>(unsigned&nbsp;long&nbsp;mask, bool <a href="#event">acceptEvent</a>(unsigned&nbsp;long&nbsp;mask,
unsigned&nbsp;long&nbsp;replytimeout_ms); unsigned&nbsp;long&nbsp;timeout_ms);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
bool <a href="#connect">connectRequest</a>(unsigned&nbsp;long&nbsp;connecttimeout_ms); bool <a href="#connect">connectRequest</a>(unsigned&nbsp;long&nbsp;timeout_ms);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
bool <a href="#connect">disconnect</a>(); bool <a href="#connect">disconnectRequest</a>();
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void <a href="#lock">finish</a>(); void <a href="#lock">finish</a>();
@ -157,24 +153,24 @@ callback methods which must be called in response to the above request
methods (most probably from another thread): methods (most probably from another thread):
</p> </p>
<div class="indent"><code> <div class="indent"><code>
void <a href="#lock">lockCallback</a>(StreamIoStatus&nbsp;status); void <a href="#lock">lockCallback</a>(StreamIoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void <a href="#write">writeCallback</a>(StreamIoStatus&nbsp;status); void <a href="#write">writeCallback</a>(StreamIoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
long <a href="#read">readCallback</a>(StreamIoStatus&nbsp;status, ssize_t <a href="#read">readCallback</a>(StreamIoStatus&nbsp;status,
const&nbsp;void*&nbsp;input&nbsp;=&nbsp;NULL, const&nbsp;void*&nbsp;buffer&nbsp;=&nbsp;NULL,
long&nbsp;size&nbsp;=&nbsp;0); size_t&nbsp;size&nbsp;=&nbsp;0);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void <a href="#event">eventCallback</a>(StreamIoStatus&nbsp;status); void <a href="#event">eventCallback</a>(StreamIoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void <a href="#connect">connectCallback</a>(StreamIoStatus&nbsp;status); void <a href="#connect">connectCallback</a>(StreamIoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void <a href="#connect">disconnectCallback</a>(StreamIoStatus&nbsp;status); void <a href="#connect">disconnectCallback</a>(StreamIoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<h3>Other provided methods, attibutes, and types</h3> <h3>Other provided methods, attibutes, and types</h3>
@ -197,6 +193,9 @@ const&nbsp;char*&nbsp;<a href="#read">getInTerminator</a>(size_t&&nbsp;length);
<div class="indent"><code> <div class="indent"><code>
enum&nbsp;StreamIoStatus {StreamIoSuccess, StreamIoTimeout, StreamIoNoReply, StreamIoEnd, StreamIoFault}; enum&nbsp;StreamIoStatus {StreamIoSuccess, StreamIoTimeout, StreamIoNoReply, StreamIoEnd, StreamIoFault};
</code></div> </code></div>
<div class="indent"><code>
const char* ::toStr(StreamIoStatus);
</code></div>
<a name="theory"></a> <a name="theory"></a>
<h2>Theory of Operation</h2> <h2>Theory of Operation</h2>
@ -276,34 +275,47 @@ correct.
<a name="connect"></a> <a name="connect"></a>
<h3>Connecting and disconnecting</h3> <h3>Connecting and disconnecting</h3>
<div class="indent"><code> <div class="indent"><code>
bool connectRequest(unsigned&nbsp;long&nbsp;connecttimeout_ms); bool connectRequest(unsigned&nbsp;long&nbsp;timeout_ms);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
bool disconnect(); bool disconnectRequest();
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void connectCallback(IoStatus&nbsp;status); void connectCallback(IoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void disconnectCallback(IoStatus&nbsp;status); void disconnectCallback(IoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<p> <p>
Connection should be handled automatically. Whenever possible connection should be handled automatically.
If the device is disconnected, each attempt to access the The interface should call <code>connectCallback()</code> when
device should try to (re-)connect. the device has connected and <code>disconnectCallback()</code> when
the device has disconnected.
These callbacks can be called asynchronously at any time.
</p>
<p>
If the device is disconnected, an attempt to access the
device should try to reconnect.
Normally, the interface should not try to disconnect unless Normally, the interface should not try to disconnect unless
the device does so. the device does so automatically.
</p> </p>
<p> <p>
However, sometimes the client wants to connect or However, sometimes the client wants to connect or
disconnect explicitely. disconnect explicitly.
To connect, the client calls <code>connectRequest()</code>. To connect, the client calls <code>connectRequest()</code>.
This function should return <code>true</code> immediately This function should set up things to reconnect but should not block
or <code>false</code> if the request cannot be accepted or connection waiting.
Instead it should immediately return <code>true</code> if
it expects that connection can be established soon, or
<code>false</code> if the request cannot be accepted or connection
handling is not supported. handling is not supported.
The interface should call <code>connectCallback(StreamIoSuccess)</code> The interface should call <code>connectCallback()</code>
once the bus could be connected. once the bus could be connected.
If the bus cannot be connected within <code>connecttimeout_ms</code> If the device can connect immediately without waiting, it may also call
<code>connectCallback()</code> directly from <code>connectRequest()</code>.
</p>
<p>
If the bus cannot be connected within <code>timeout_ms</code>
milliseconds, the bus interface should call milliseconds, the bus interface should call
<code>connectCallback(StreamIoTimeout)</code>. <code>connectCallback(StreamIoTimeout)</code>.
</p> </p>
@ -313,11 +325,11 @@ something wrong with the I/O hardware,
<code>connectCallback(StreamIoFault)</code> may be called. <code>connectCallback(StreamIoFault)</code> may be called.
</p> </p>
<p> <p>
To disconnect, the client calls <code>disconnectRequest()</code>; To disconnect explicitly, the client calls <code>disconnectRequest()</code>;
This function should return <code>true</code> immediately or This function should return <code>true</code> immediately or
<code>false</code> if the request cannot be accepted or connection <code>false</code> if the request cannot be accepted or connection
handling is not supported. handling is not supported.
The interface should call <code>connectCallback(StreamIoSuccess)</code> The interface should call <code>connectCallback()</code>
once the bus is disconnected. There is no timeout for this operation. once the bus is disconnected. There is no timeout for this operation.
If disconnecting is impossible, the interface should call If disconnecting is impossible, the interface should call
<code>connectCallback(StreamIoFault)</code>. <code>connectCallback(StreamIoFault)</code>.
@ -326,10 +338,10 @@ If disconnecting is impossible, the interface should call
<a name="lock"></a> <a name="lock"></a>
<h3>Bus locking</h3> <h3>Bus locking</h3>
<div class="indent"><code> <div class="indent"><code>
bool lockRequest(unsigned&nbsp;long&nbsp;lockTimeout_ms); bool lockRequest(unsigned&nbsp;long&nbsp;timeout_ms);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void lockCallback(IoStatus&nbsp;status); void lockCallback(IoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
bool unlock(); bool unlock();
@ -348,7 +360,7 @@ or <code>false</code> if the request cannot be accepted.
If the device is already locked, the bus interface should add itself to If the device is already locked, the bus interface should add itself to
a queue, sorted by <code>priority()</code>. a queue, sorted by <code>priority()</code>.
As soon as the device is available, the bus interface should call As soon as the device is available, the bus interface should call
<code>lockCallback(StreamIoSuccess)</code>. <code>lockCallback()</code>.
If the bus cannot be locked within <code>lockTimeout_ms</code> If the bus cannot be locked within <code>lockTimeout_ms</code>
milliseconds, the bus interface should call milliseconds, the bus interface should call
<code>lockCallback(StreamIoTimeout)</code>. <code>lockCallback(StreamIoTimeout)</code>.
@ -369,7 +381,7 @@ locked the device.
When the protocol ends and the device is locked, the client calls When the protocol ends and the device is locked, the client calls
<code>unlock()</code>. <code>unlock()</code>.
If other bus interfaces are in the lock queue, the next one should If other bus interfaces are in the lock queue, the next one should
call <code>lockCallback(StreamIoSuccess)</code> now. call <code>lockCallback()</code> now.
</p> </p>
<p> <p>
The client calls <code>finish()</code> when the protocol ends. The client calls <code>finish()</code> when the protocol ends.
@ -385,7 +397,7 @@ bool writeRequest(const&nbsp;void*&nbsp;output,
size_t&nbsp;size, unsigned&nbsp;long&nbsp;writeTimeout_ms); size_t&nbsp;size, unsigned&nbsp;long&nbsp;writeTimeout_ms);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void writeCallback(IoStatus&nbsp;status); void writeCallback(IoStatus&nbsp;status = StreamIoSuccess);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
const&nbsp;char*&nbsp;getOutTerminator(size_t&&nbsp;length); const&nbsp;char*&nbsp;getOutTerminator(size_t&&nbsp;length);
@ -404,7 +416,7 @@ The function should arrange transmission of <code>size</code> bytes of
or <code>false</code> if the request cannot be accepted. or <code>false</code> if the request cannot be accepted.
It must not block until output has completed. It must not block until output has completed.
After all output has been successfully transmitted, but not earlier, the After all output has been successfully transmitted, but not earlier, the
interface should call <code>writeCallback(StreamIoSuccess)</code>. interface should call <code>writeCallback()</code>.
</p> </p>
<p> <p>
If output blocks for <code>writeTimeout_ms</code> milliseconds, If output blocks for <code>writeTimeout_ms</code> milliseconds,
@ -417,14 +429,15 @@ something wrong with the I/O hardware,
<code>writeCallback(StreamIoFault)</code> may be called. <code>writeCallback(StreamIoFault)</code> may be called.
</p> </p>
<p> <p>
The interface must transmit excactly the <code>size</code> bytes The interface must send excactly the <code>size</code> bytes
from <code>output</code>. from <code>output</code>, not less.
It must not change anything and it should not assume that It should not change anything unless the bus needs some special
any bytes have a special meaning. formatting (e.g. added header, escaped bytes) and it should not
assume that any bytes have a special meaning.
In particular, a null byte does not terminate <code>output</code>. In particular, a null byte does not terminate <code>output</code>.
</p> </p>
<p> <p>
A call to <code>getOutTerminator</code> tells the interface which A call to <code>getOutTerminator()</code> tells the interface which
terminator has already been added to the output. terminator has already been added to the output.
If <code>NULL</code> was returned, the client is not aware of a If <code>NULL</code> was returned, the client is not aware of a
terminator (no outTerminator was defined in the protocol). terminator (no outTerminator was defined in the protocol).
@ -450,9 +463,9 @@ bool readRequest(unsigned&nbsp;long&nbsp;replyTimeout_ms,
long&nbsp;expectedLength, bool&nbsp;async); long&nbsp;expectedLength, bool&nbsp;async);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
long readCallback(IoStatus&nbsp;status, ssize_t readCallback(IoStatus&nbsp;status,
const&nbsp;void*&nbsp;input&nbsp;=&nbsp;NULL, const&nbsp;void*&nbsp;buffer&nbsp;=&nbsp;NULL,
long&nbsp;size&nbsp;=&nbsp;0); size_t&nbsp;size&nbsp;=&nbsp;0);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
const&nbsp;char*&nbsp;getInTerminator(size_t&&nbsp;length); const&nbsp;char*&nbsp;getInTerminator(size_t&&nbsp;length);
@ -487,11 +500,11 @@ The client copies its contents. It does not modify or free it.
It is not necessary to wait until all data has been received. It is not necessary to wait until all data has been received.
The bus interface can call <code>n=readCallback()</code> after The bus interface can call <code>n=readCallback()</code> after
any amount of input has been received. any amount of input has been received.
If the client needs more input, <code>readCallback()</code> If the client expects more input, <code>readCallback()</code>
returns a non-zero value. returns a non-zero value.
A positive <code>n</code> means, the client needs another A positive <code>n</code> means, the client expects another
<code>n</code> bytes of input. <code>n</code> bytes of input.
A negative <code>n</code> means, the client needs an unspecified A negative <code>n</code> means, the client expects an unspecified
amount of additional input. amount of additional input.
</p> </p>
<p> <p>
@ -559,46 +572,43 @@ something wrong with the I/O hardware,
<code>readCallback(StreamIoFault)</code> may be called. <code>readCallback(StreamIoFault)</code> may be called.
</p> </p>
<p> <p>
If the <code>async</code> flag is <code>true</code>, the client Sometimes a client wishes to get any input received at any time, even
wants to read input asyncronously without any timeout. when requested by another client.
That means, the bus interface should call <code>readCallback()</code> If a client wishes to receive such asynchronous input, it first calls
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>. <code>supportsAsyncRead()</code>.
The default implementation of this method always returns The default implementation of this method always returns
<code>false</code>. <code>false</code>.
A bus interface may overwrite this method to return <code>true</code> If a bus interface supports asynchronous input, it should overwrite
and eventually prepare for asynchonous input. this method to set up everything needed to receive asynchronous input
and then return <code>true</code>.
The client is then allowed to call <code>readRequest()</code> with The client is then allowed to call <code>readRequest()</code> with
the <code>async==true</code>. the <code>async==true</code>.
This means that the client is interested in any input. This means that the client is now interested in asynchronous input.
It should receive a <code>readCallback()</code> of all input which came It should receive a <code>readCallback()</code> of all input which came
in response to a synchonous (<code>async==false</code>) request from in response to any synchonous (<code>async==false</code>) request from
another client (which of course should receive the input, too). another client (which should receive the input, too).
The interface should also receive asynchonous input when no The interface should also receive asynchronous input when no
synchonous client is active at the moment. synchonous client is active at the moment.
Many asynchonous <code>readRequest()</code> calls from different clients Many asynchronous <code>readRequest()</code> calls from different clients
may be active at the same time. may be active at the same time.
All of them should receive the same input. All of them should receive the same input.
</p> </p>
<p> <p>
For asynchonous requests, <code>replyTimeout_ms</code> has a different For asynchronous requests, <code>replyTimeout_ms</code> has a different
meaning: If the bus interface has to poll the bus for input, it may take 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. <code>replyTimeout_ms</code> as a hint for the poll period.
If many asynchonous requests are active at the same time, it should poll If many asynchronous requests are active at the same time, it should poll
with the shortest period of all clients. with the shortest period of all clients.
An asynchonous request does not time out. An asynchronous request does not time out.
It stays active until the next input arrives. It stays active until the next input arrives.
The client may reissue the asynchronous <code>readRequest()</code> The client may reissue the asynchronous <code>readRequest()</code>
from within the <code>readCallback()</code> if it wants to continue from within the <code>readCallback()</code> if it wants to continue
receiving asynchonous input. receiving asynchronous input.
</p> </p>
<p> <p>
If the client calls <code>finish()</code> at any time, the bus If the client calls <code>finish()</code> at any time, the bus
interface should cancel all outstanding requests, including interface should cancel all outstanding requests, including
asynchonous read requests. asynchronous read requests.
</p> </p>
<a name="event"></a> <a name="event"></a>
<h3>Handling events</h3> <h3>Handling events</h3>
@ -606,10 +616,10 @@ asynchonous read requests.
bool supportsEvent(); bool supportsEvent();
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
bool acceptEvent(unsigned long mask, unsigned long replytimeout_ms); bool acceptEvent(unsigned long mask, unsigned long timeout_ms);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
void eventCallback(StreamIoStatus status); void eventCallback(StreamIoStatus status = StreamIoSuccess);
</code></div> </code></div>
<p> <p>
An event is a sort of input from a device which is not part of An event is a sort of input from a device which is not part of
@ -627,9 +637,9 @@ If <code>true</code> is returned, the client is allowed to call
If <code>mask</code> is illegal, <code>acceptEvent()</code> should If <code>mask</code> is illegal, <code>acceptEvent()</code> should
return <code>false</code>. return <code>false</code>.
The call to <code>acceptEvent()</code> must not block. The call to <code>acceptEvent()</code> must not block.
It should arrange to call <code>eventCallback(StreamIoSuccess)</code> It should arrange to call <code>eventCallback()</code>
when the event matching <code>mask</code> arrives within when the event matching <code>mask</code> arrives within
<code>replytimeout_ms</code> milliseconds. <code>timeout_ms</code> milliseconds.
If no such event arrives within this time, the bus interface If no such event arrives within this time, the bus interface
should call <code>eventCallback(StreamIoTimeout)</code>. should call <code>eventCallback(StreamIoTimeout)</code>.
</p> </p>

View File

@ -44,7 +44,7 @@ class MyConverter : public StreamFormatConverter
{ {
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool); int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printLong(const StreamFormat&, StreamBuffer&, long); bool printLong(const StreamFormat&, StreamBuffer&, long);
int scanLong(const StreamFormat&, const char*, long&); ssize_t scanLong(const StreamFormat&, const char*, long&);
}; };
RegisterConverter(MyConverter,"Q"); RegisterConverter(MyConverter,"Q");
@ -73,17 +73,17 @@ Provide multiple classes, that's more efficient.
<a name="parsing"></a> <a name="parsing"></a>
<h3>Parsing</h3> <h3>Parsing</h3>
<div class="indent"><code> <div class="indent"><code>
int parse (const&nbsp;StreamFormat&&nbsp;fmt, StreamBuffer&&nbsp;info, int parse(const&nbsp;StreamFormat&&nbsp;fmt, StreamBuffer&&nbsp;info,
const&nbsp;char*&&nbsp;source, bool&nbsp;scanFormat); const&nbsp;char*&&nbsp;source, bool&nbsp;scanFormat);
</code></div> </code></div>
<div class="indent"><code> <div class="indent"><code>
struct&nbsp;StreamFormat { struct&nbsp;StreamFormat {
char&nbsp;conv; char&nbsp;conv;
StreamFormatType&nbsp;type; StreamFormatType&nbsp;type;
unsigned&nbsp;char&nbsp;flags; unsigned&nbsp;short&nbsp;flags;
short&nbsp;prec; long&nbsp;prec;
unsigned&nbsp;short&nbsp;width; unsigned&nbsp;long&nbsp;width;
unsigned&nbsp;short&nbsp;infolen; unsigned&nbsp;long&nbsp;infolen;
const&nbsp;char*&nbsp;info; const&nbsp;char*&nbsp;info;
}; };
</code></div> </code></div>
@ -124,12 +124,12 @@ flags set:
</ul> </ul>
<p> <p>
It is not necessary that these flags have exactly the same meaning in your It is not necessary that these flags have exactly the same meaning in your
formats, but a similar and intuitive meaning helpful for the user. formats, but a similar and intuitive meaning is helpful for the user.
</p> </p>
<p> <p>
There are two additional flags, <code>default_flag</code> indicating a There are two additional flags, <code>default_flag</code> indicating a
<code>?</code> and <code>compare_flag</code> indicating a <code>=</code> <code>?</code> and <code>compare_flag</code> indicating a <code>=</code>
int the format, that are handled internally by <em>StreamDevice</em> and in the format, that are handled internally by <em>StreamDevice</em> and
are not of interest to the converter class. are not of interest to the converter class.
</p> </p>
<p> <p>
@ -163,13 +163,13 @@ This will probably be necessary if you have parsed additional characters
from the format string as in the above example<br> from the format string as in the above example<br>
</p> </p>
<p> <p>
Return <code>long_format</code>, <em>double_format</em>, Return <code>unsigned_format</code>, <code>signed_format</code>,
<em>string_format</em>, or <code>enum_format</code> depending on the <code>double_format</code>, <code>string_format</code>, or
<code>enum_format</code> depending on the
datatype associated with the conversion character. datatype associated with the conversion character.
It is not necessary to return the same value for print and for scan It is not necessary to return the same value for print and for scan
formats. formats.
You can even return different values depending on the format string, You can even return different values depending on the format string.
but I can't imagine why anyone should do that.
</p> </p>
<p> <p>
If the format is not a real data conversion but does other things with If the format is not a real data conversion but does other things with
@ -178,7 +178,8 @@ return <code>pseudo_format</code>.
</p> </p>
<p> <p>
Return <code>false</code> if there is any parse error or if print or scan Return <code>false</code> if there is any parse error or if print or scan
is requested but not supported by this conversion. is requested but not supported by this conversion or flags are used that
are not supported by this conversion.
</p> </p>
<a name="printing_scanning"></a> <a name="printing_scanning"></a>
@ -191,7 +192,45 @@ That method is called whenever the conversion appears in an output or input,
respectively. respectively.
You only need to implement the flavour of print and/or scan suitable for You only need to implement the flavour of print and/or scan suitable for
the datatype returned by <code>parse()</code>. the datatype returned by <code>parse()</code>.
Both <code>unsigned_format</code> and <code>signed_format</code> will use
the <code>Long</code> flavour.
</p> </p>
</p>
The possible interface methods are:
</p>
<div class="indent"><code>
bool printLong(const&nbsp;StreamFormat&&nbsp;fmt,
StreamBuffer& output, long value);
</code></div>
<div class="indent"><code>
bool printDouble(const&nbsp;StreamFormat&&nbsp;fmt,
StreamBuffer& output, double value);
</code></div>
<div class="indent"><code>
bool printString(const&nbsp;StreamFormat&&nbsp;fmt,
StreamBuffer& output, const&nbsp;char* value);
</code></div>
<div class="indent"><code>
bool printPseudo(const&nbsp;StreamFormat&&nbsp;fmt,
StreamBuffer& output);
</code></div>
<div class="indent"><code>
ssize_t scanLong(const&nbsp;StreamFormat&&nbsp;fmt,
const&nbsp;char* input, long& value);
</code></div>
<div class="indent"><code>
ssize_t scanDouble(const&nbsp;StreamFormat&&nbsp;fmt,
const&nbsp;char* input, double& value);
</code></div>
<div class="indent"><code>
ssize_t scanString(const&nbsp;StreamFormat&&nbsp;fmt,
const&nbsp;char* input, char* value, size_t& size);
</code></div>
<div class="indent"><code>
ssize_t scanPseudo(const&nbsp;StreamFormat&&nbsp;fmt,
StreamBuffer& inputLine, size_t& cursor);
</code></div>
<p> <p>
Now, <code>fmt.type</code> contains the value returned by <code>parse()</code>. Now, <code>fmt.type</code> contains the value returned by <code>parse()</code>.
With <code>fmt.info()</code> get access to the string you have written to With <code>fmt.info()</code> get access to the string you have written to
@ -203,16 +242,21 @@ The length of the info string can be found in <code>fmt.infolen</code>.
<p> <p>
In <code>print*()</code>, append the converted value to <code>output</code>. In <code>print*()</code>, append the converted value to <code>output</code>.
Do not modify what is already in output (unless you really know what you're Do not modify what is already in output (unless you really know what you're
doing). doing, e.g. some <code>printPseudo</code> methods).
Return <code>true</code> on success, <code>false</code> on failure. Return <code>true</code> on success, <code>false</code> on failure.
</p> </p>
<p> <p>
In <code>scan*()</code>, read the value from input and return the number of In <code>scan*()</code>, read the value from input and return the number of
consumed bytes. consumed bytes or -1 on failure.
In the string version, don't write more bytes than <code>maxlen</code>!
If the <code>skip_flag</code> is set, you don't need to write to If the <code>skip_flag</code> is set, you don't need to write to
<code>value</code>, since the value will be discarded anyway. <code>value</code>, since the value will be discarded anyway.
Return <code>-1</code> on failure. In <code>scanString()</code>, don't write more bytes than
<code>maxlen</code> to <code>value</code> and set <code>size</code> to the
actual string length, which may be different to the number of bytes consumed
(e.g. if leading spaces are skipped).
In <code>scanPseudo()</code>, <code>cursor</code> is the index of the first
byte in <code>inputLine</code> to consider, which may be larger than
<code>0</code>.
</p> </p>
<footer> <footer>

View File

@ -15,7 +15,7 @@
<h2>What is <em>StreamDevice</em>?</h2> <h2>What is <em>StreamDevice</em>?</h2>
<p> <p>
<em>StreamDevice</em> is a generic <em>StreamDevice</em> is a generic
<a href="http://www.aps.anl.gov/epics" target="ex">EPICS</a> <a href="https://www.aps.anl.gov/epics" target="ex">EPICS</a>
device support for devices with a "byte stream" based device support for devices with a "byte stream" based
communication interface. communication interface.
That means devices that can be controlled by sending and That means devices that can be controlled by sending and
@ -52,7 +52,7 @@ It does not provide loops or branches.
</p> </p>
<p> <p>
<em>StreamDevice</em> comes with an interface to<a target="ex" <em>StreamDevice</em> comes with an interface to<a target="ex"
href="http://www.aps.anl.gov/epics/modules/soft/asyn/"> href="https://www.aps.anl.gov/epics/modules/soft/asyn/">
<em>asynDriver</em></a> <em>asynDriver</em></a>
but can be extended to but can be extended to
<a href="businterface.html">support other bus drivers</a>. <a href="businterface.html">support other bus drivers</a>.
@ -82,14 +82,26 @@ primitive commands.
</p> </p>
<p> <p>
It is not a block oriented device support. It is not a block oriented device support.
It is not possible to send or receive huge blocks of data that contain It is not intended for huge binary blocks of data that contain
many process variables distributed over many records. many process variables distributed over many records.
Consider <a href="https://github.com/paulscherrerinstitute/regdev"
target="ex"><em>regDev</em></a>
for that.
</p>
<p>
It is not a very flexible html, xml, json, etc. parser. Data needs to
come in a predictible order to be parsable by <em>StreamDevice</em>.
</p> </p>
<h2>Recommended Readings</h2> <h2>Recommended Readings</h2>
<p> <p>
<a href="http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide" IOC Application Developer's Guide:
target="ex">IOC Application Developer's Guide</a> <a href="https://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide"
target="ex">R3.14.12</a>,
<a href="https://www.aps.anl.gov/epics/base/R3-16/1-docs/AppDevGuide"
target="ex">R3.15.5</a>,
<a href="https://www.aps.anl.gov/epics/base/R3-15/5-docs/AppDevGuide"
target="ex">R3.16.1</a>
</p> </p>
<p> <p>
<a href="https://wiki-ext.aps.anl.gov/epics/index.php/RRM_3-14" <a href="https://wiki-ext.aps.anl.gov/epics/index.php/RRM_3-14"
@ -105,6 +117,28 @@ This marks text you typically type in configuration files etc.
Longer code segments are often set in a box. Longer code segments are often set in a box.
</pre> </pre>
<h2>Changes in Version 2.8</h2>
<ul>
<li>Support standard EPICS module build system.
<li>Compatible with EPICS base releases up to 7.0.1.
<ul>
<li>Support for new record types: int64in, int64out, lsi, lso.
<li>Support for INT64 and UINT64 in aai, aao, waveform.
</ul>
<li>Run @init more often (e.g. when device re-connects or paused IOC is resumed).
<li>Use "COMM" error code in .STAT when device is disconnected.
<li>Allow spaces in protocol parameter list.
<li>Errors are new silent by default (var streamError 0) except during init.
<li>Support output redirect of all shell functions.
<li>Fix building shared libraries on Windows.
<li>Fix some C++11 warnings.
<li>Fix several signed/unsigned problems.
<li>Dropped support for cygnus-2.7.2 gcc (used by some old cygwin).
<li>Several bug fixes.
<li>Several documentation updates.
</ul>
<footer> <footer>
<a href="setup.html">Next: Setup</a> <a href="setup.html">Next: Setup</a>
Dirk Zimoch, 2018 Dirk Zimoch, 2018

View File

@ -210,6 +210,15 @@ div div div a {list-style-type:circle;}
</div> </div>
<div> <div>
<a target="_parent" href="formatconverter.html">Format Converter API</a> <a target="_parent" href="formatconverter.html">Format Converter API</a>
<div>
<a target="_parent" href="formatconverter.html#class">Converter Class</a>
<a target="_parent" href="formatconverter.html#theory">Theory of Operation</a>
<div>
<a target="_parent" href="formatconverter.html#registration">Registration</a>
<a target="_parent" href="formatconverter.html#parsing">Parsing</a>
<a target="_parent" href="formatconverter.html#printing_scanning">Printing and Scanning</a>
</div>
</div>
</div> </div>
<div> <div>
<a target="_parent" href="osinterface.html">Operating System API</a> <a target="_parent" href="osinterface.html">Operating System API</a>