安卓USB主机API:批量传输缓冲区大小

13
我正在编写软件,用于在Android 4.0.3版本和内核版本2.6.39.4的Motorola Xoom平板电脑与使用Android提供的USB主机API的外部设备之间进行通信。我只使用两种类型的通信:
- 控制:controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout) - 批量:bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout)
控制传输正常工作,但是批量传输存在问题。对于bulkTransfer函数,我只能使用32768作为缓冲区的大小。不能使用更少或更多。我知道不能使用更多,因为缓冲管道的限制(大小为32769字节)。
该外设设备流式传输数据,但bulkTransfer函数无法正确读取数据。我猜测有些数据丢失了。
I find this: 在Linux中,如果一个进程试图从空管道(缓冲区)读取数据,则read(2)将阻塞,直到有数据可用。如果一个进程试图向满管道写入数据,则write(2)将阻塞,直到从管道中读取了足够的数据以允许写入完成。

基于此,我的问题解释是由于write(2)函数的阻塞标志而导致某些数据未被写入管道(缓冲区)。我理解正确吗?如果是这样,我可以更改管道缓冲区。

我的第一个解决方案是增加缓冲区大小。对于内核版本 >= 2.6.35,您可以使用fcntl(fd, F_SETPIPE_SZ, size)更改管道的大小,但我如何找到USB管道的fd(文件描述符)?
第二个选项是使用ulimit -p SIZE,但我的内核中参数p不是用于管道而是进程。
有人遇到过同样的问题吗?有什么解决方案吗?

使用批量传输时,我也遇到了数据丢失的问题。我正在调查此问题。一旦我找到根本原因,我会告诉你。请继续更新状态。 - yokks
@yokks 我以前见过这个,但对我没有帮助。 - syntagma
我基于serverbox的东西进行了一些编辑,我也经历了同样的事情。这让人感到沮丧。 - FabianCook
没有,我认为除了修改Android内核之外,没有其他解决方案。 - syntagma
可能是Android USB Host - bulkTransfer() is losing data的重复问题。 - David G
显示剩余2条评论
5个回答

2
Android SDK的UsbEndpoint对象提供了getMaxPacketSize()方法,让您可以检查设备适当的最大数据包大小。通常,USB“全速”设备的最大允许数据包大小为64字节,“高速”设备为512字节,远远小于您尝试使用的32768字节。您是否将底层USB数据包大小与某些高级协议的大小混淆了?

我已经在所有设备上检查过了,所有设备的数据包大小都是64。我有一台三星平板电脑,在那个平板电脑上一切正常。但是如果我在我的三星Galaxy S7上使用相同的代码,它就无法传输所有字节。有什么帮助吗?我该如何更改代码以使其在所有设备上运行? - Ajay Mehta

2
您应该使用USB数据分析仪,我正在使用这个: http://www.ellisys.com/products/usbex200/index.php。使用这样的工具在我做同类事情时真的帮了我很多,我发现你必须做一些while循环。对于我的设备,我收到64字节的数据包,其中包含两个控制字节和62个数据字节,因此对于我的传输,我必须做一些类似以下代码的东西:
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]);
    }
}

对我而言,下面的方法非常好用,我也曾遇到同样的问题,这就是如何解决它。如果您需要更多信息,请评论:)。我知道这对我来说真的很令人沮丧。顺便提一下,我使用的是安卓4.0.3的Acer Iconia A500。


传输大量数据USB

传输数据USB


我没有这种设备。我只使用USBlyzer来检查设备和Windows平台之间的传输。我在bulkTransfer中没有收到任何控制数据,可能数据包的最大大小为512字节。你有什么建议吗? - syntagma

1

根据gfour发布的同一份pdf文件,我在里面发现了这段话:

“数据包的大小会影响性能,取决于数据传输速率。对于非常高的速度,需要最大的数据包大小。对于正在以115200波特率传输音频数据的“实时”应用程序,例如,最小的数据包是理想的,否则设备将一次缓存4k数据。如果USB请求大小过大且数据速率相对较低,则可能导致“卡顿”的数据传输效果。”

我遇到了与SmartLemon类似的FTDI串行设备的情况,因此最近一直在寻求减轻这种情况的方法。这将要求我完全从头编写自己的函数,而以前我是使用一个库。

然而,在您的情况下,您可以尝试使用bulkTransfer的最低缓冲区大小,而不是追求最大值。也许您已经尝试过了,但也可能没有。我看到您说32768是唯一的大小,但也许您只是指最大值。它似乎很奇怪它只允许一个特定大小。


0
根据AN232B-04_DataLatencyFlow.pdf,高数据速率需要流量控制:

强烈建议使用流量控制,因为无法保证FTDI驱动程序始终会被调度。

您是否尝试过使用流量控制选项(RTS/CTS、DTR/DSR、XON/XOFF)来同步您的数据?


我没有尝试流量控制。我不应该使用这种解决方案,因为它会导致额外的延迟。我分析了设备和Windows平台之间的USB传输,发现没有流量控制。 - syntagma
@REACHUS:我的情况类似:在我的Linux电脑上从FTDI读取数据很好,但在Android平板电脑上会丢失数据。由于我进行了大约400kbps的连续数据传输(通过USB录制音频),我怀疑可能是平板电脑硬件/内核/驱动程序组合在高速数据率下表现不佳。像你一样,我知道在我的Linux情况下没有进行流控制,但在Android上可能有所不同,因此建议这么做。 - gfour

0

你可以尝试这个解决批量传输问题的方法

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;
                    }
                }

            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接