Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android USB Host - bulkTransfer() is losing data

Tags:

android

host

usb

I'm trying to receive data from a custom device based on an FTDI 2232H chip.

I am using a simple Async FIFO mode, and the incoming data rate is 3.2MB/sec.

Everything works perfectly with test code on my PC, but I'm having problems receiving data on my Toshiba Thrive.

TDI's Android driver fails, so I am coding using Java.

I can receive 95%+ of the data perfectly, but every once in a while the data 'sputters' and I get portions of the same 4-5K of data two or three times, then back to good data.

I am not going too fast for the Thrive or Android, because I previously had the data coming in at double (6.4MB/sec) and it got about 95% of that as well. (So it should have no problem at half the rate.)

It seems like there is some sort of bug in the buffering (or double-buffering) that happens within Android. (It is not the buffer within the FTDI 2232H because the repeated data is larger than the chip's 4K internal buffer.)

The setup code is simple, and again it's working ~almost~ perfectly.

The loop where the data grab occurs is very simple:

while(!fStop)
  if(totalLen < BIG_BUFF_LEN-IN_BUFF_LEN)
  {
    len=conn.bulkTransfer(epIN, inBuff, IN_BUFF_LEN, 0);
    System.arraycopy(inBuff, 0, bigBuff, totalLen, len);
    totalLen+=len;
  }

In case you think it's the time delay for the arraycopy - I still lose the data even if I comment that line out.

The IN_BUFF_LEN is 16384 (bulkTransfer won't return more than that even if I increase the size of the inBuff).

The bigBuff is several megabytes.

As a secondary question - does anyone know how to pass a pointer to bulkTransfer that will populate bigBuff directly --- at an offset (not starting at position '0'?

like image 228
Greg Avatar asked Feb 02 '12 07:02

Greg


3 Answers

UsbConnection.bulktransfer(...) is buggy. Use UsbRequest.queue(...) Api.

Many people has reported that using bulktransfer directly fails around 1% or 2% of the input transfers.

like image 133
Pablo Valdes Avatar answered Nov 19 '22 20:11

Pablo Valdes


Just to clarify a few of the approaches I tried...The USB code ran in it's own thread and was given max priority (no luck) - I tried API calls, libUSB, native C, and other methods (no luck) - I buffered, and polled, and queued (no luck) - ultimately I decided Android could not handle USB data at 'high speed' (constant 3.2MB/sec w/ no flow control). I built an 8MB hardware FIFO buffer into my design to make up for it. (If you think you have an answer, come up with something that feeds data in at 3.2MB/sec and see if Android can handle it without ANY hiccups. I'm pretty sure it can't.)

like image 2
Greg Avatar answered Nov 19 '22 19:11

Greg


In Nexus Media Importer I can consistently push through about 9MB/s, so it is possible. I'm not sure if you have control of the source, but you may want to break the feed into 16K blocks with some sort of sequenced header so you can detect missing blocks and corruption.

Also, you are not checking for len < 0. I'm not sure what will have if the underlying stack gets a NAK or NYET from the other end. I get this enough that I have recovery code to handle this.

I have looked long and hard for a way to offset the bulkTransfer destination buffer, but I have yet to find it. FYI: USBRequest.queue() does not respect the ByteBuffer.position().

I'm kind of surprised we can do 16K on bulkTransfer anyway. According to the USB 2.0 spec, the max is supposed to be 512 bytes for a bulkTransfer endpoint. Is Android bundling the the bulkTransfers, or are we breaking the rules?

like image 1
Dustin Avatar answered Nov 19 '22 19:11

Dustin