libftdi Archives

Subject: RE: libftdi: Make ftdi_read_data() honor usb_read_timeout

From: "Michael Plante" <michael.plante@xxxxxxxxx>
To: <libftdi@xxxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 28 Mar 2011 21:25:16 -0400
Uwe Bonnes wrote:
>> Is this your use case? The (microcontroller) device has already sent some
>> data. Now you do ftdi_read_data(struct ftdi_context *ftdi, unsigned char
>> *buf, big_size) and expect all data already in the FT fifo to be
>> returned even when the number of bytes available is smaller than the
>> requested number.

I expect what's available to be returned if the FTDI chip indicates that it
should be.  But my read call always blocked for a small amount of time,
depending on how much data the FTDI chip was ready to push out.  That was
desirable.  Blocking for the full timeout value is not desirable, and
setting it extremely small just hogs the CPU.


>> With the change I introduced in libftdi-0, the call would return
>> after usb_read_timeout with all available bytes or immediate when SIZE is
>> fullfilled.
>> So you would have to set the timeout to a sensible value before your call
>> and you should nearly have the old (broken) behaviour back. The behaviour
to
>> return immeadate is however broken i.m.h.o.  No other read(..., SIZE)
call I
>> know of will return immedate when neither size nor timeout is satisfied.

The FTDI device has the SI/WU pin.  How do you expect that to function if
you consider the current behavior "broken"?  The FTDI chip specifically has
a path to get data back sooner than usual, and the patch you've proposed
seems to block that FTDI feature from working.


>> Look at my use case: My devices starts to spew out data at high rate with
>> some command sent. To catch all data. I have to start reading before the
>> command is sent, otherwise I may overrun the FT internal fifo .
>> With ../examples/serial_read this spews out lots(!) of
>> "read 0 bytes" with a frequency of about 65 Hertz. So now I have the
>> overhead you talk about in "A" in my user application and in additional
>> calls to ftdi_read_data(). Is this better?

Ok, but that's not additional CPU overhead, it's additional code complexity.
You seem to want the print statements suppressed, which is not hard.  You
are reading data unsolicited, so you should expect that it sometimes won't
have anything to send.  I, on the other hand, need low-latency
variable-length responses without excessive CPU intervention.  My data
lengths are generally low, sometimes fitting in a single 62-byte packet,
sometimes fitting in a few.

I'm not convinced (see below) that changing the latency timer won't help
you.  It additively affected the time my operations took (except when I
explicitly bypassed the latency timer by strobing the SI/WU pin from my
MCU).  Indeed, if you have your timer set to the default of 16ms, the
frequency you observed is approximately its reciprocal.


>> Best way would probably be to provide a way to query the devices about
>> available bytes in the buffer.

Do you mean available bytes in the FTDI chip's buffer?  That sounds like
excessive calls into the OS, when it should just be able to block until the
chip indicates it's finished sending data (or the other conditions like
timing out or receiving a full buffer, though, like I said, I tried to
ensure that didn't happen in my situation).


>> Or perhaps provide a blocking and
>> non-blocking ( old behaviour) ftdi_read_data().

The old behavior is NOT "non-blocking".  It will block for a certain amount
of time.  This time was usually about how long it took my MCU to respond,
plus a bit of overhead.


>> This has no influence on ftdi_read_data(). In ftdi_read_data()
>> ret = libusb_bulk_transfer (ftdi->usb_dev, ftdi->out_ep,
ftdi->readbuffer, \
>>     ftdi->readbuffer_chunksize, &actual_length, ftdi->usb_read_timeout);
>> will return immedate despite a higher latency time and ftdi_read_data()
will
>> still return immediate.

Really?  Are you saying that a synchronous libusb call returns immediately
even with a high timeout and no data returned?  I don't think that's the
case.  Why then would you pass the final argument at all?  Maybe we just
have a different perspective on whether 16ms is a long time (for me) or
immediate (for you)?

If you look at AN232B-04, section 2.3 and 3.1:

  "The host controller will read data from the device until either:
   a) a packet shorter than 64 bytes is received or
   b) the requested data length is reached"

AND

  "When transferring data from an FTDI USB-Serial or USB-FIFO IC device to
the PC,
   the device will send the data given one of the following conditions:
   1. The buffer is full (64 bytes made up of 2 status bytes and 62 user
bytes).
   2. One of the RS232 status lines has changed [...]
   3. An event character had been enabled and was detected in the incoming
data stream.
   4. A timer integral to the chip has timed out. There is a timer (latency
timer) [...]
      measures the time since data was last sent to the PC. [...] If it
times-out then
      the chip will send back the 2 status bytes and any data that is held
in the buffer."

That sounds to me like the FTDI chip keeps sending 0 or more 64-byte
packets, and eventually sends one shorter than 64 bytes and it gets kicked
back out of libusb into libftdi.  This is the process by which the ftdi chip
indicates the end of a logical operation, and the behavior of libusb is to
return it at that point.  libftdi should not try to override this mechanism.


>>      - keep the old behavout?
>>      - Implement some ftdi_available_date() calls
>>      - Split into a blocking and non blocking behaviour?

I would NOT call it nonblocking, but either the first or third options are
fine.  It doesn't return immediately, but perhaps it's much sooner than you
were expecting.  The underlying libusb call is synchronous.  I might instead
call it "blocking" and "extra-blocking".

Regards,
Michael


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+unsubscribe@xxxxxxxxxxxxxxxxxxxxxxx   

Current Thread