Hello all,
I ran into a problem when reading from a serial device using I/O Intr
processing with streamDevice.
The device sends a string every 100 ms and this string is converted into
numbers using scalcout
record ( silly spaces between sign and numbers fail ai record conversion).
The conversion works, but depending on the poll period, I loose a lot of
strings.
If using a poll period of 50 ms, I get none conversions at all.
100 ms poll period converts about every other string,
500ms poll period converts 4-5 strings every 500 ms.
This is the db:
record (scalcout, "VRZ720:$(host)$(port)02") {
field (DTYP, "stream")
field (OUT, "@VRZ720.proto getYAxis VRZ01")
field (SCAN, "I/O Intr")
field (CALC, "AA=='-'?-1*A:A")
}
This is the protocol:
InTerminator = LF LF;
PollPeriod = 50;
ReadTimeout = 30;
getYAxis {
in "X=%*[+-]%*f%*[ RDrd]\r\nY=%(AA)[+-]%(A)f%*[ RDrd]\r";
}
This is an example string, which is sent to the device every 100ms.
X=- 757.4302 R\r\nY=- 75.6267 R\r\n\n
The problem is caused by the first call to pasynOctet->read with
readTimeout 0 if EOS is set.
If using eos asynInterposeEos will return asynTimeout even if some
characters have been
received, but not yet the eos-string. The timeout aborts the stream
protocol and the
partial string is discarded. If using a long poll period chances grow,
that a full string is in the
buffer at the first read which will be properly processed. But you don't
want to process
only once a second, if strings are delivered every 100 ms.
If preventing the stream protocol from aborting, even if the first read is
a timeout,
allows to read again and accumulate partial strings until eos is received.
The second call to pasynOctet->read has timeout=ReadTimeout, which must be
long
enough to read the full string.
I attached a patch (which hopefully doesn't break existing code) to do
this.
Jens
--- old/AsynDriverInterface.cc 2010-01-08 16:46:59.870812999 +0100
+++ new/AsynDriverInterface.cc 2010-01-08 17:05:33.404224396 +0100
@@ -807,6 +807,11 @@
}
// pasynOctet->read() has already cut off terminator.
+ // Timeout is considered success, if reading with EOS in
AsyncRead
+ // mode and at least one octet was received
+ if ((status == asynTimeout) && streameos && (ioAction ==
AsyncReadMore))
+ status = asynSuccess;
+
switch (status)
{
case asynSuccess:
@@ -823,7 +828,16 @@
// ignore what we got from here.
// input was already handeled by asynReadHandler()
// read until no more input is available
- readMore = -1;
+ if (streameoslen && (eomReason & ASYN_EOM_EOS)){
+ if (replyTimeout != 0.0) {
+ ioAction = AsyncRead;
+ startTimer(replyTimeout);
+ }
+ readMore = 0;
+ }
+ else {
+ readMore = -1;
+ }
break;
}
#ifndef NO_TEMPORARY