Device.Read can return 0,nil
rasky opened this issue · comments
Documentation of io.Reader
says:
Implementations of Read are discouraged from returning a zero byte count with a nil error, except when len(p) == 0. Callers should treat a return of 0 and nil as indicating that nothing happened; in particular it does not indicate EOF.
It looks like Device.Read
is a wrapper on ftdi_read_data
:
Line 441 in f54995a
which is documented that it can return
0
if no data is available on USB.
This BTW breaks io.ReadFull
but maybe this is more a problem on Go side, given that returning 0,nil
is "discouraged" but not "forbidden". Anyway, is there any way to more strictly adhere to io.Reader
and have Device.Read
automatically block until at least a byte is available?
Hmm...
Generally this package is intended to be a thin wrapper over libftdi so you can read the doc of ftdi_read_data and expect the same behavior from Device.Read.
Even if we want to block if no data can be read from USB I wander how do it efficiently if the ftdi_read_data returns immediately...
Generally this package is intended to be a thin wrapper over libftdi so you can read the doc of ftdi_read_data and expect the same behavior from Device.Read.
If the function was called (*Device).ReadData
I would have not objected. (*Device).Read
implements io.Reader
so you're not only providing a thin wrapper: you're actually promising to adhere to a specific protocol, which all Go users know and that is composable with many utilities with expect a specific behavior.
Even if we want to block if no data can be read from USB I wander how do it efficiently if the ftdi_read_data returns immediately...
I don't know libftdi well. I was hoping that one of the existing function allowed to either block, or wait for some timeout. If that's not the case, then I agree there's nothing we can do.
You are right that user can rely on Read to implement io.Reader
.
I've just read the ftdi_read_data
source. It calls libusb_bulk_transfer
with default timeout 5000 ms. So if it returns after 5 s we can simply return 0, ErrTimeout
. I haven't tested this case myself, but if I understand you correctly the ftdi_read_data
can return 0 immediately, so that's not the case.
Internally the ftdi_read_data
reads two FTDI status bytes followed by data bytes. The status bytes are removed from returned data. It seems it returns 0 and not timeout error if it has read only these two status bytes. Maybe the subsequent call will wait more but probably no more than the duration set by Device.SetLatencyTimer
that is 255 ms max.
If you have any FTxxx device on hand please test it with something like this:
d.SetLatencyTimer(ms)
for {
t1 := time.Now()
n, err := d.Read(buf)
t2 := time.Now()
fmt.Println(n, err, t2.Sub(t1))
}