Re: Blocking read() from a USB->Serial adapter.



Charles Sullivan <cwsulliv@xxxxxxxxxxxx> wrote:
On Fri, 24 Nov 2006 15:54:24 -0900, Floyd L. Davidson wrote:

Charles Sullivan <cwsulliv@xxxxxxxxxxxx> wrote:
A blocking read() of more than one character from an actual RS232 serial
port returns when the number of characters specified has been read.

Not necessarily true.

However I've found that a blocking read() of more than one character from
a USB->Serial adapter reads only the first character before returning and
I have to loop to read all the characters.

Which makes it the same as a regular port. There may well be timing
differences though, I don't know.

If that's the case, then that answers my questions. I thought blocking
meant blocking until the specified number of characters is read, or
until the read is interrupted.

I depends on the configuration of the serial port, which we
haven't seen. It *can* be configured to block forever (though
you might not really want to do that...).

See http://www.easysw.com/~mike/serial/serial.html for the best
tutorial available. The top part of the index looks like this:

...
Chapter 2, Configuring the Serial Port
The POSIX Terminal Interface
Control Options
Local Options
Input Options
Output Options
Control Characters

Click on that last one, "Control Characters". That will take
you to a chart showing the c_cc character array, and the two
elements you are interested in are VTIME and VMIN. (And while
that is indeed the best tutorial... I would not say the
description given for VMIN and VTIME are the best I've ever
seen! Hence, I'll describe them in different terms, and between
the two descriptions you might be able to make sense out of it.)

Note first that it mentions the VTIME and VMIN parameters are
*not* used if NDELAY is set via fcntl(2) or with the open(2)
functions (that is, calling open() with the O_NONBLOCK flag
set), or if canonical input is configured (via the c_lflag value
in the termios struct). Typically a modem line is opened with
NDELAY set, so that the call to open() will return even though
there is no carrier detect. Then fcntl() is called to clear the
NDELAY flag so that calls to read() can block.

And hence, if you configure for raw mode with blocking enabled,
the blocking will be controlled by the values in VTIME and VMIN.

If VMIN is set to 0, then VTIME is a read timer. If VMIN is
non-zero, then VTIME is an inter-byte timer (which will also be
disabled if VTIME is see to 0).

If, for example, VMIN is set to 0 and VTIME is set to 5, we have
a situation were a call to read() for a block of say 10 bytes
can have at least three different results. If there are bytes
already buffered by the serial port, up to the specified block
of 10 of them will *immediately* be returned by the read()
function. If there are no bytes buffered, then the timer is
activated, and will wait for VTIME*0.1 seconds, which in this
case is half a second, *for* *a* *single* *byte* to be received
on the serial port. If one byte is received, read() will
instantly return with just that one byte. If no bytes are
receive in 0.5 seconds, the read() function will return with no
bytes.

That is one scenario that could provide results such as you have
described. Note that with slow bit rates it is easily possible
to put read() in a loop that is tight enough to return no data
many times between each iteration that actually does return a
single byte per call. It is also possible to put a delay into
the loop and return data in chunks. But with that
configuration, the read() will never block forever.

If both VTIME and VMIN are zero, the timeout will happen
immediately. Hence if there is no data buffered, zero bytes
will immediately be returned. If there is any data, from 1 up
to the number of bytes requested in the read() function call
will be returned immediately. The call to read() will *never*
wait for data.

When VMIN is non-zero, VTIME becomes a inter-byte timer, which
acts differently. If VTIME is zero, the timer is simply
disabled. In that case a read() function call will block until
the number of bytes specified by VMIN are available (which might
mean it blocks forever, if that many bytes are never received).

However, when VMIN is non-zero, if VTIME is also non-zero, the
call to read() will block until at least one byte is received
(which again could mean blocking forever, if no bytes are ever
received). When a byte is received if the total number
available is equal to VMIN, the read() function will return;
otherwise, the inter-byte timer is started and read() will return
whatever number of bytes it currently has if the inter-byte timer
times out before another byte is received. If another byte is
received, the inter-byte timer is reset and that process is
started again with a comparison of the number of available bytes
vs the size of the block request by the read() function call.

You can see that it is entirely possible to configure a serial
port exactly as you described, "blocking until the specified
number of characters is read, or until the read is interrupted".
Just as a word of warning though, that isn't usually a good way
to configure a serial port, and in particular it is not often
beneficial to set VMIN any higher than 1 in some expectation
that fixed size packets will be received. If a single byte is
added or lost (e.g., due to noise) it becomes virtually
impossible to resynchronize the framing for packets!

--
Floyd L. Davidson <http://www.apaflo.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska) floyd@xxxxxxxxxx
.



Relevant Pages

  • Re: 8ms Timer for serial port access
    ... >> or if VTIME deciseconds elapses between bytes, ... >> and readwill block until VMIN bytes are available. ... It is generally figured that "Advanced Programming in a Unix ... the other is "UNIX Network ...
    (comp.os.linux.development.apps)
  • Re: 8ms Timer for serial port access
    ... >> times for every frame I wait for. ... > If VTIME is zero and VMIN in non-zero, the timer is disabled, ... > and readwill block until VMIN bytes are available. ... > your 23 byte packet. ...
    (comp.os.linux.development.apps)
  • Re: 8ms Timer for serial port access
    ... times between each frame of data! ... except for the special case when VMIN is set to ... If VMIN is set to 0 and VTIME is non-zero, ... the only way to know when a new packet is starting? ...
    (comp.os.linux.development.apps)
  • Re: Serial I/O from C
    ... VMIN and VTIME can be confusing. ... The timer is not started until the first character is received, ...
    (comp.os.linux.development.apps)