On Fri, Apr 24, 2015 at 07:04:49PM -0400, Cody P Schafer wrote:
> 
> So in posix I'd do something like the following (buffer fullness &
> error checking omitted):
> 
> int b_fd = open_and_configure_port_as_blocking();
> uint8_t buf[1024];
> size_t used = 0;
> for (;;) {
>     ssize_t r = read(b_fd, buf + used, sizeof(buf) - used);
>     /* scan for 'X', if found break */
>     if (memchr(buf + used, 'X', r))
>        break;
>     used += r;
> }

I get the impression here that you're relying not just on the read()
blocking indefinitely until the first byte appears, but also on
returning not long after that, despite having read much fewer than the
1024 bytes in the initial request.

POSIX requires the former, but merely permits the latter. A different
implementation would be entirely justified in blocking until 1024 bytes
had been received, unless you set the termios VTIME value to specify a
timeout. You're depending on the fact that on the system you're using 
happens to have a default there that suits you (I think 0.1 seconds is
common), or that the serial driver has an internal timeout that has the
same effect.

So this code as shown can't be relied on, even on POSIX. And the "block
until first byte, then start the timeout" semantics aren't available on
other systems (e.g. Windows), so it's not a portable idiom.

Also to get those semantics, you need to open the port without
O_NONBLOCK, which has the side effect that it's impossible to then make
any non-blocking read/write calls later without closing and reopening
the port.

Rather than wanting the primitives to work like those on a given system
in a given mode, I think it's much clearer to express what you actually
want:

1. A blocking wait until a byte is received, followed by
2. A blocking read of bytes received up to some timeout after that.

And the way to express that in libserialport seems logical enough to me:

1. sp_wait(&set_with_rx_ready_event, 0);
2. sp_blocking_read(buf, length, your_preferred_timeout);

Which is almost what you have in your following example:

> With libserialport to get the same behaviour I need to:
> 
> struct sp_port *p = open_and_configure_port();
> uint8_t buf[1024];
> size_t used = 0;
> struct sp_event_set *ev;
> sp_new_event_set(&ev);
> sp_add_port_events(ev, p, SP_EVENT_RX_READY);
> for (;;) {
>     sp_wait(ev, 0);
>     sp_nonblocking_read(p, buf + used, sizeof(buf) - used);
>     /* scan for 'X', if found break */
>     if (memchr(buf + used, 'X', r))
>        break;
>     used += r;
> }

...except you should change the nonblocking read for a blocking one with
whatever short timeout value you want to use.

> Because sp_blocking_read() doesn't return early (like posix read does).

It does, but you have to tell it what timeout to use, rather than
relying on some system/driver default. 

And if you want to wait indefinitely for a character first, you need to
do that as a separate call, which seems reasonable to me.

I like the principle of least astonishment. Your first example depends
on a lot that is implicit in the port setup or the system details. The
second is very clear what it wants. I think that's the best way to do
things in a cross-platform API.


Martin

------------------------------------------------------------------------------
One dashboard for servers and applications across Physical-Virtual-Cloud 
Widest out-of-the-box monitoring support with 50+ applications
Performance metrics, stats and reports that give you Actionable Insights
Deep dive visibility with transaction tracing using APM Insight.
http://ad.doubleclick.net/ddm/clk/290420510;117567292;y
_______________________________________________
sigrok-devel mailing list
sigrok-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to