USB 协议明确规定:批量传输中,当发送数据量为端点最大包大小的整数倍时,必须通过 ZLP 标记传输结束。这是应用层需要遵守的协议规范。

USB 协议规定,对于批量传输(Bulk Transfer) 模式:

  • 当发送的数据量小于端点最大包大小(如 511 字节) 时,接收端会默认 “此包为完整数据”(因未填满一包),无需额外标记。
  • 当发送的数据量大于端点最大包大小(如 513 字节) 时,数据会被拆分为多个包(如 512 字节 + 1 字节),接收端通过 “最后一个非满包” 判断传输结束。
  • 当发送的数据量等于端点最大包大小(如 512 字节) 时,接收端无法区分 “这是完整数据” 还是 “后续仍有数据”(因刚好填满一包),此时必须通过零长度包(ZLP) 明确标记 “传输结束”。

解决方案:

比如原来发送数据的代码如下:

private void sendMessage(String msg) {
    byte[] bytes = msg.getBytes();
    Log.d(TAG, "mUsbConnection-->msg length: " + bytes.length + ";" + mEndpointOUT.getMaxPacketSize());
    if (mUsbConnection != null) {
        int result = mUsbConnection.bulkTransfer(mEndpointOUT, bytes, bytes.length, 100);
        if (result < 0) {
            Log.d(TAG, "发送失败");
        } else {
            Log.d(TAG, "发送成功" + msg);
        }
    } else {
        Log.d(TAG, "mUsbConnection-->null");
    }

增加ZLP(零长度数据包)发送代码后接收端即可正常接收512整数倍的数据包了。

private void sendMessage(String msg) {
    byte[] bytes = msg.getBytes();
    Log.d(TAG, "mUsbConnection-->msg length: " + bytes.length + ";" + mEndpointOUT.getMaxPacketSize());
    if (mUsbConnection != null) {
        int result = mUsbConnection.bulkTransfer(mEndpointOUT, bytes, bytes.length, 100);
        if (bytes.length % 512 == 0) {  // 若正好发送了最大包大小的整数倍,则再发送一个ZLP(零长度包),作为数据包结束标记。
            result = mUsbConnection.bulkTransfer(mEndpointOUT, new byte[0], 0, 100);
        }
        if (result < 0) {
            Log.d(TAG, "发送失败");
        } else {
            Log.d(TAG, "发送成功" + msg);
        }
    } else {
        Log.d(TAG, "mUsbConnection-->null");
    }

另一种解决方案,若发送端不方便修改增加发送ZLP(比如要兼容多款设备时),可考虑修改接收端,方式如下:

1,接收端将读取数据的缓冲区设置为512字节,然后循环读取数据。
2,通过超时或数据结束标记判断数据接收完成。

备注:RK3188 OTG控制器如果接收512字节整数倍的数据,只在两种情况下产生接收完成的中断:
1)收到ZLP
2)应用读取的缓冲区已满
所以,如果发送端不主动发送ZLP,那么接收端只能修改读取缓冲区,将缓冲区设置为512字节,确保512字节整数倍数据可以触发OTG控制器接收完成的中断,从而通知应用读取数据。如下代码:

                byte[] bytes = new byte[512];
                try {
                    for (int i = 0; i < bytes.length; i++) {
                        bytes[i] = 0;
                    }
                    lenght = inputStream.read(bytes);
                } catch (IOException e) {
                    Log.d(TAG, "RuntimeException------------- ");
                        isReceive = false;
                    throw new RuntimeException(e);
                }

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐