13
votes

I am writing software to communicate between tablet (Motorola Xoom with Android version 4.0.3 and Kernel version 2.6.39.4) and a peripheral device using USB Host API provided by Android. I use only two types of communication:

  • control: controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout)
  • bulk: bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout)

Control transfer works fine, but I have a problem with bulk transfer. I can use only 32768 as a size of the buffer for bulkTransfer function. It is not possible to use less or more. I know that I cannot use more because of the limit of the buffer pipe (size: 32769 bytes).

This peripheral device streams data which is not correctly read by bulkTranfer function. I suppose that some data is lost.

I find this: In Linux If a process attempts to read from an empty pipe (buffer), then read(2) will block until data is available. If a process attempts to write to a full pipe , then write(2) blocks until sufficient data has been read from the pipe to allow the write to complete.

And based on that, my explanation of the problem is that some data is not written to pipe (buffer) because of blocking flag made by write(2) function. Am I correct? If this is true I could change pipe buffer.

  1. My first solution for this problem is greater buffer. For kernel >= 2.6.35, you can change the size of a pipe with fcntl(fd, F_SETPIPE_SZ, size) but how can I find fd (file descriptor) for USB pipes?
  2. Second option is to use ulimit -p SIZE but parameter p for my kernel is not for pipe but process.

Has anyone faced the same problem, any solutions?

5
using bulk transfer, am also facing the data loss issue. amlooking into it. I will let you know,once i found the root cause. keep updating the status.yokks
OK, thanks for the info.syntagma
android.serverbox.ch/?p=370 can you go through this conversation? here one logic is presented for handling incoming data. hope it will help you.yokks
@yokks I've seen that before, it didn't help me.syntagma
I based my stuff of the serverbox stuff with a bit of editing, I went through the same thing. Was frustratingFabianCook

5 Answers

2
votes

You should get a USB data analyzer, Im using this one: http://www.ellisys.com/products/usbex200/index.php

Using something like this really helped me when I was doing the same type of thing, what I found was that you had to do some type of while loop.

For my device I had 64 bytes of data coming in packets to me, the packet would be two control bytes and 62 for data, so for my transfer I had to do something like

StringBuilder sb = new StringBuilder();
while(bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) > 2){
    for(int i = 2; i < buffer.length(); i++){
        sb.append((char) buffer[i]);
    }
}

something a long these lines worked good for me, i had exactly the same issue and this is how I fixed it. I have more information if you need it. Just comment :). I know this was really frustrating for me to. Im using an Acer Iconia A500 with Android 4.0.3 btw


Transferring larger amounts of data USB

Transferring data USB

1
votes

According to the same .pdf gfour posted, I found this paragraph in there:

"The size of the packet will affect the performance and is dependent on the data rate. For very high speed, the largest packet size is needed. For 'real-time' applications that are transferring audio data at 115200 Baud for example, the smallest packet possible is desirable, otherwise the device will be holding up 4k of data at a time. This can give the effect of 'jerky' data transfer if the USB request size is too large and the data rate too low (relatively)."

I'm running into a situation similar to SmartLemon with a FTDI Serial device, so I've been recently looking up ways to alleviate it. This will require me to pretty much write my own functions from scratch while previously I was using a library.

However, it seems that in your case, you could try using bulkTransfer's lowest buffer size instead of shooting for the biggest. You may have tried this already, but maybe not. I see that you say 32768 is the only size, but maybe you only meant the max. It seems weird that it'd only allow one specific size.

1
votes

The Android SDK's UsbEndpoint object provides a getMaxPacketSize() method, allowing you to check what is appropriate for your device. Generally, the maximum allowable packet size is 64 bytes for USB 'Full-speed' devices and 512 for 'High-speed' devices - far less than 32,768 you are attempting. Are you perhaps confusing the underlying USB packet size with that of some higher-level protocol?

0
votes

According to AN232B-04_DataLatencyFlow.pdf, flow control is needed for high data rates:

It is strongly encouraged that flow control is used because it is impossible to ensure that the FTDI driver will always be scheduled.

Have you tried using one of the flow control options (RTS/CTS, DTR/DSR, XON/XOFF) to synchronize your data?

0
votes

You can try this for Bulk transfer issue

byte[] buffer = new byte[4096];

            StringBuilder strIN = new StringBuilder();

            if (conn.bulkTransfer(epIN, buffer, 4096, 500) >= 0) {
                for (int i = 2; i < 4096; i++) {
                    if (buffer[i] != 0) {
                        strIN.append((char) buffer[i]);

                        textReceiveDataInfo.append(strIN + "\n");
                    } else {
                        l(strIN);
                        break;
                    }
                }

            }