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