From bb66a49ec16b8d7b1c49830c089d3e84aad524cc Mon Sep 17 00:00:00 2001
From: Dirk Zimoch
bool acceptEvent(unsigned long mask,
- unsigned long replytimeout_ms);
+ unsigned long timeout_ms);
-bool connectRequest(unsigned long connecttimeout_ms);
+bool connectRequest(unsigned long timeout_ms);
-bool disconnect();
+bool disconnectRequest();
void finish();
@@ -157,24 +153,24 @@ callback methods which must be called in response to the above request
methods (most probably from another thread):
-void lockCallback(StreamIoStatus status);
+void lockCallback(StreamIoStatus status = StreamIoSuccess);
-void writeCallback(StreamIoStatus status);
+void writeCallback(StreamIoStatus status = StreamIoSuccess);
-long readCallback(StreamIoStatus status,
- const void* input = NULL,
- long size = 0);
+ssize_t readCallback(StreamIoStatus status,
+ const void* buffer = NULL,
+ size_t size = 0);
-void eventCallback(StreamIoStatus status);
+void eventCallback(StreamIoStatus status = StreamIoSuccess);
-void connectCallback(StreamIoStatus status);
+void connectCallback(StreamIoStatus status = StreamIoSuccess);
-void disconnectCallback(StreamIoStatus status);
+void disconnectCallback(StreamIoStatus status = StreamIoSuccess);
Other provided methods, attibutes, and types
@@ -197,6 +193,9 @@ const char* getInTerminator(size_t& length);
enum StreamIoStatus {StreamIoSuccess, StreamIoTimeout, StreamIoNoReply, StreamIoEnd, StreamIoFault};
+
+const char* ::toStr(StreamIoStatus);
+
Theory of Operation
@@ -276,34 +275,47 @@ correct.
Connecting and disconnecting
-bool connectRequest(unsigned long connecttimeout_ms);
+bool connectRequest(unsigned long timeout_ms);
-bool disconnect();
+bool disconnectRequest();
-void connectCallback(IoStatus status);
+void connectCallback(IoStatus status = StreamIoSuccess);
-void disconnectCallback(IoStatus status);
+void disconnectCallback(IoStatus status = StreamIoSuccess);
-Connection should be handled automatically.
-If the device is disconnected, each attempt to access the
-device should try to (re-)connect.
+Whenever possible connection should be handled automatically.
+The interface should call connectCallback()
when
+the device has connected and disconnectCallback()
when
+the device has disconnected.
+These callbacks can be called asynchronously at any time.
+
+
+If the device is disconnected, an attempt to access the
+device should try to reconnect.
Normally, the interface should not try to disconnect unless
-the device does so.
+the device does so automatically.
However, sometimes the client wants to connect or
-disconnect explicitely.
+disconnect explicitly.
To connect, the client calls connectRequest()
.
-This function should return true
immediately
-or false
if the request cannot be accepted or connection
+This function should set up things to reconnect but should not block
+waiting.
+Instead it should immediately return true
if
+it expects that connection can be established soon, or
+false
if the request cannot be accepted or connection
handling is not supported.
-The interface should call connectCallback(StreamIoSuccess)
+The interface should call connectCallback()
once the bus could be connected.
-If the bus cannot be connected within connecttimeout_ms
+If the device can connect immediately without waiting, it may also call
+connectCallback()
directly from connectRequest()
.
+
+
+If the bus cannot be connected within timeout_ms
milliseconds, the bus interface should call
connectCallback(StreamIoTimeout)
.
@@ -313,11 +325,11 @@ something wrong with the I/O hardware,
connectCallback(StreamIoFault)
may be called.
-To disconnect, the client calls disconnectRequest()
;
+To disconnect explicitly, the client calls disconnectRequest()
;
This function should return true
immediately or
false
if the request cannot be accepted or connection
handling is not supported.
-The interface should call connectCallback(StreamIoSuccess)
+The interface should call connectCallback()
once the bus is disconnected. There is no timeout for this operation.
If disconnecting is impossible, the interface should call
connectCallback(StreamIoFault)
.
@@ -326,10 +338,10 @@ If disconnecting is impossible, the interface should call
Bus locking
-bool lockRequest(unsigned long lockTimeout_ms);
+bool lockRequest(unsigned long timeout_ms);
-void lockCallback(IoStatus status);
+void lockCallback(IoStatus status = StreamIoSuccess);
bool unlock();
@@ -348,7 +360,7 @@ or false
if the request cannot be accepted.
If the device is already locked, the bus interface should add itself to
a queue, sorted by priority()
.
As soon as the device is available, the bus interface should call
-lockCallback(StreamIoSuccess)
.
+lockCallback()
.
If the bus cannot be locked within lockTimeout_ms
milliseconds, the bus interface should call
lockCallback(StreamIoTimeout)
.
@@ -369,7 +381,7 @@ locked the device.
When the protocol ends and the device is locked, the client calls
unlock()
.
If other bus interfaces are in the lock queue, the next one should
-call lockCallback(StreamIoSuccess)
now.
+call lockCallback()
now.
The client calls finish()
when the protocol ends.
@@ -385,7 +397,7 @@ bool writeRequest(const void* output,
size_t size, unsigned long writeTimeout_ms);
-void writeCallback(IoStatus status);
+void writeCallback(IoStatus status = StreamIoSuccess);
const char* getOutTerminator(size_t& length);
@@ -404,7 +416,7 @@ The function should arrange transmission of size
bytes of
or false
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 writeCallback(StreamIoSuccess)
.
+interface should call writeCallback()
.
If output blocks for writeTimeout_ms
milliseconds,
@@ -417,14 +429,15 @@ something wrong with the I/O hardware,
writeCallback(StreamIoFault)
may be called.
-The interface must transmit excactly the size
bytes
-from output
.
-It must not change anything and it should not assume that
-any bytes have a special meaning.
+The interface must send excactly the size
bytes
+from output
, not less.
+It should not change anything unless the bus needs some special
+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 output
.
-A call to getOutTerminator
tells the interface which
+A call to getOutTerminator()
tells the interface which
terminator has already been added to the output.
If NULL
was returned, the client is not aware of a
terminator (no outTerminator was defined in the protocol).
@@ -450,9 +463,9 @@ bool readRequest(unsigned long replyTimeout_ms,
long expectedLength, bool async);
-long readCallback(IoStatus status,
- const void* input = NULL,
- long size = 0);
+ssize_t readCallback(IoStatus status,
+ const void* buffer = NULL,
+ size_t size = 0);
const char* getInTerminator(size_t& 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.
The bus interface can call n=readCallback()
after
any amount of input has been received.
-If the client needs more input, readCallback()
+If the client expects more input, readCallback()
returns a non-zero value.
-A positive n
means, the client needs another
+A positive n
means, the client expects another
n
bytes of input.
-A negative n
means, the client needs an unspecified
+A negative n
means, the client expects an unspecified
amount of additional input.
@@ -559,46 +572,43 @@ something wrong with the I/O hardware,
readCallback(StreamIoFault)
may be called.
-If the async
flag is true
, the client
-wants to read input asyncronously without any timeout.
-That means, the bus interface should call readCallback()
-even if the input was requested by another client.
-
-
-If a client wishes to receive asynchonous input, it first calls
+Sometimes a client wishes to get any input received at any time, even
+when requested by another client.
+If a client wishes to receive such asynchronous input, it first calls
supportsAsyncRead()
.
The default implementation of this method always returns
false
.
-A bus interface may overwrite this method to return true
-and eventually prepare for asynchonous input.
+If a bus interface supports asynchronous input, it should overwrite
+this method to set up everything needed to receive asynchronous input
+and then return true
.
The client is then allowed to call readRequest()
with
the async==true
.
-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 readCallback()
of all input which came
-in response to a synchonous (async==false
) request from
-another client (which of course should receive the input, too).
-The interface should also receive asynchonous input when no
+in response to any synchonous (async==false
) request from
+another client (which should receive the input, too).
+The interface should also receive asynchronous input when no
synchonous client is active at the moment.
-Many asynchonous readRequest()
calls from different clients
+Many asynchronous readRequest()
calls from different clients
may be active at the same time.
All of them should receive the same input.
-For asynchonous requests, replyTimeout_ms
has a different
+For asynchronous requests, replyTimeout_ms
has a different
meaning: If the bus interface has to poll the bus for input, it may take
replyTimeout_ms
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.
-An asynchonous request does not time out.
+An asynchronous request does not time out.
It stays active until the next input arrives.
The client may reissue the asynchronous readRequest()
from within the readCallback()
if it wants to continue
-receiving asynchonous input.
+receiving asynchronous input.
If the client calls finish()
at any time, the bus
interface should cancel all outstanding requests, including
-asynchonous read requests.
+asynchronous read requests.
Handling events
@@ -606,10 +616,10 @@ asynchonous read requests.
bool supportsEvent();
-bool acceptEvent(unsigned long mask, unsigned long replytimeout_ms);
+bool acceptEvent(unsigned long mask, unsigned long timeout_ms);
-void eventCallback(StreamIoStatus status);
+void eventCallback(StreamIoStatus status = StreamIoSuccess);
An event is a sort of input from a device which is not part of
@@ -627,9 +637,9 @@ If true
is returned, the client is allowed to call
If mask
is illegal, acceptEvent()
should
return false
.
The call to acceptEvent()
must not block.
-It should arrange to call eventCallback(StreamIoSuccess)
+It should arrange to call eventCallback()
when the event matching mask
arrives within
-replytimeout_ms
milliseconds.
+timeout_ms
milliseconds.
If no such event arrives within this time, the bus interface
should call eventCallback(StreamIoTimeout)
.
diff --git a/documentation/formatconverter.html b/documentation/formatconverter.html
index a598238..9f72916 100644
--- a/documentation/formatconverter.html
+++ b/documentation/formatconverter.html
@@ -44,7 +44,7 @@ class MyConverter : public StreamFormatConverter
{
int parse(const StreamFormat&, StreamBuffer&, const char*&, bool);
bool printLong(const StreamFormat&, StreamBuffer&, long);
- int scanLong(const StreamFormat&, const char*, long&);
+ ssize_t scanLong(const StreamFormat&, const char*, long&);
};
RegisterConverter(MyConverter,"Q");
@@ -73,17 +73,17 @@ Provide multiple classes, that's more efficient.
Parsing
-int parse (const StreamFormat& fmt, StreamBuffer& info,
+int parse(const StreamFormat& fmt, StreamBuffer& info,
const char*& source, bool scanFormat);
struct StreamFormat {
char conv;
StreamFormatType type;
-unsigned char flags;
-short prec;
-unsigned short width;
-unsigned short infolen;
+unsigned short flags;
+long prec;
+unsigned long width;
+unsigned long infolen;
const char* info;
};
@@ -124,12 +124,12 @@ flags set:
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.
There are two additional flags, default_flag
indicating a
?
and compare_flag
indicating a =
-int the format, that are handled internally by StreamDevice and
+in the format, that are handled internally by StreamDevice and
are not of interest to the converter class.
@@ -163,13 +163,13 @@ This will probably be necessary if you have parsed additional characters
from the format string as in the above example
-Return long_format
, double_format,
-string_format, or enum_format
depending on the
+Return unsigned_format
, signed_format
,
+double_format
, string_format
, or
+enum_format
depending on the
datatype associated with the conversion character.
It is not necessary to return the same value for print and for scan
formats.
-You can even return different values depending on the format string,
-but I can't imagine why anyone should do that.
+You can even return different values depending on the format string.
If the format is not a real data conversion but does other things with
@@ -178,7 +178,8 @@ return pseudo_format
.
Return false
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.
@@ -191,7 +192,45 @@ That method is called whenever the conversion appears in an output or input,
respectively.
You only need to implement the flavour of print and/or scan suitable for
the datatype returned by parse()
.
+Both unsigned_format
and signed_format
will use
+the Long
flavour.
+
+The possible interface methods are:
+
+
+bool printLong(const StreamFormat& fmt,
+ StreamBuffer& output, long value);
+
+
+bool printDouble(const StreamFormat& fmt,
+ StreamBuffer& output, double value);
+
+
+bool printString(const StreamFormat& fmt,
+ StreamBuffer& output, const char* value);
+
+
+bool printPseudo(const StreamFormat& fmt,
+ StreamBuffer& output);
+
+
+ssize_t scanLong(const StreamFormat& fmt,
+ const char* input, long& value);
+
+
+ssize_t scanDouble(const StreamFormat& fmt,
+ const char* input, double& value);
+
+
+ssize_t scanString(const StreamFormat& fmt,
+ const char* input, char* value, size_t& size);
+
+
+ssize_t scanPseudo(const StreamFormat& fmt,
+ StreamBuffer& inputLine, size_t& cursor);
+
+
Now, fmt.type
contains the value returned by parse()
.
With fmt.info()
get access to the string you have written to
@@ -203,16 +242,21 @@ The length of the info string can be found in fmt.infolen
.
In print*()
, append the converted value to output
.
Do not modify what is already in output (unless you really know what you're
-doing).
+doing, e.g. some printPseudo
methods).
Return true
on success, false
on failure.
In scan*()
, read the value from input and return the number of
-consumed bytes.
-In the string version, don't write more bytes than maxlen
!
+consumed bytes or -1 on failure.
If the skip_flag
is set, you don't need to write to
value
, since the value will be discarded anyway.
-Return -1
on failure.
+In scanString()
, don't write more bytes than
+maxlen
to value
and set size
to the
+actual string length, which may be different to the number of bytes consumed
+(e.g. if leading spaces are skipped).
+In scanPseudo()
, cursor
is the index of the first
+byte in inputLine
to consider, which may be larger than
+0
.