Android USB附件主机通讯截断

时间:2018-06-06 21:57:15

标签: android usb host serial-communication

这是我第一次使用USB通信和Android应用程序。

我正在使用https://github.com/felHR85/UsbSerial创建一个应用程序,允许平板电脑/手机使用USB OTG充当主机并与附件通信。我已经到了使用SerialInputStreams和SerialOutputStreams来发送和接收设备的地步。

这是关于USB可以使用我正在使用的电缆发送的最大数据包大小为64字节。在我的应用程序中,附件发送的数据大于64字节。如果附件没有以64字节包发送数据的代码,而是一次性全部发送数据。将丢失64字节后的任何数据吗?

我正在接收从附件到主机的消息的前64个字节,然后主机超时,因为它没有收到完整的消息并重新发送到附件。消息的前64个字节总是显示出来,这样我知道消息的其他部分不等待轮询。

修改

我要连接的设备是作为CDC设备的数据记录器。我知道我使用的连接的最大包大小为64。

每当连接USB设备并通过我设置的过滤器并且接口和端点正确时,就会发生USBConnectActivity。

public class USBConnectActivity extends Activity
{
    public UsbDevice device = null;
    public UsbManager manager = null;
    public UsbDeviceConnection usbDeviceConnection = null;
    public UsbSerialDevice serialPort = null;
    public String deviceID = "";
    public boolean isUSBConnected = false;
    private PendingIntent mPermissionIntent;
    private final String ACTION_USB_PERMISSION =
            "com.android.example.USB_PERMISSION";

    private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                stopUsbConnection();
                unregisterReceiver(usbReceiver);
            }
            if(ACTION_USB_PERMISSION.equals(action))
            {
                setupCom();
            }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState)
    {

        super.onCreate(savedInstanceState);
        manager = (UsbManager) getSystemService(Context.USB_SERVICE);
        USBConnection.getInstance().setManager(manager);
        mPermissionIntent = PendingIntent.getBroadcast(
                this,0,new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter mfilter = new IntentFilter(ACTION_USB_PERMISSION);
        registerReceiver(usbReceiver,mfilter);

        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
        registerReceiver(usbReceiver, filter);

        findDevice(mPermissionIntent);
        finish();
    }

    private void findDevice(PendingIntent i)
    {
        UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        boolean found = false;
        UsbDevice xDevice = null;
        while (deviceIterator.hasNext()) {
           UsbDevice tDevice = deviceIterator.next();

            // Loop through the interfaces of the attached USB device
            for (int count = 0; count < tDevice.getInterfaceCount(); count++) {
                if (found) break;
                // Use temp variables to check and then match with the private variables
                UsbInterface inter = tDevice.getInterface(count);
                UsbEndpoint tOut = null;
                UsbEndpoint tIn = null;

                if (inter.getEndpointCount() >= 2) {
                    for (int end_count = 0; end_count < inter.getEndpointCount(); end_count++) {
                        UsbEndpoint end = inter.getEndpoint(end_count);
                        if (end.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                            if (end.getDirection() == UsbConstants.USB_DIR_OUT) tOut = end;
                            else if (end.getDirection() == UsbConstants.USB_DIR_IN) tIn = end;
                        }
                    }
                }
                if (tOut != null && tIn != null) {
                   device = tDevice; manager.requestPermission(device, i); found = true;
                   isUSBConnected = true;
                   USBConnection.getInstance().setDevice(device);
                   USBConnection.getInstance().attach();
                }
            }
        }
        if(usbDeviceConnection == null) setupCom();
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        unregisterReceiver(usbReceiver);
    }

    private void setupCom()
    {
        deviceID = device.getDeviceName();
        if(usbDeviceConnection == null) usbDeviceConnection = manager.openDevice(device);
        if(serialPort == null)
        {
            serialPort = UsbSerialDevice.createUsbSerialDevice(device, usbDeviceConnection);
            if(serialPort != null && serialPort.open())
            {
                serialPort.setBaudRate(115200);
                serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
                serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
                serialPort.setParity(UsbSerialInterface.PARITY_NONE);
                serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
                USBConnection.getInstance().setSerialPort(serialPort);
                USBConnection.getInstance().setUsbDeviceConnection(usbDeviceConnection);
            }
        }
    }

    private void stopUsbConnection(){
        manager = null;
        device = null;
        isUSBConnected = false;
        USBConnection.getInstance().detach();
        deviceID = "";
        try
        {
            if(serialPort != null)
                serialPort.close();
            if(usbDeviceConnection != null)
                usbDeviceConnection.close();
        }
        finally
        {
            serialPort = null;
            usbDeviceConnection = null;
        }

    }
}

此类包含所有USB信息

public class USBConnection
{

    // USB information
    public boolean isConnected;
    public UsbDevice device;
    public UsbManager manager;
    public UsbSerialDevice serialPort;
    public UsbDeviceConnection usbDeviceConnection;
    public String deviceName;
    public boolean waitForReading;

    private static USBConnection instance;
    public static USBConnection getInstance()
    {
        if(instance == null)
            instance = new USBConnection();
        return instance;
    }

    public void setDevice(UsbDevice device_)
    {
        device = device_;
        deviceName = device.getDeviceName();
    }

    public void setManager(UsbManager manager_)
    {
        manager = manager_;
    }

    public void attach()
    {
        isConnected = true;
    }

    public void detach()
    {
        isConnected = false;
    }

    public void setSerialPort(UsbSerialDevice serialPort_)
    {
        serialPort = serialPort_;
    }

    public void setUsbDeviceConnection(UsbDeviceConnection usbDeviceConnection_)
    {
        usbDeviceConnection = usbDeviceConnection_;
    }

    public void writing() {
        waitForReading = true;
    }

    public void reading(){
        waitForReading = false;
    }

    public boolean waitingForRead()
    {
        return waitForReading;
    }
}

这是我用来设置输入和输出流的代码

else if(USBConnection.getInstance().isConnected)   // check if usb is connected
            {
               manager = USBConnection.getInstance().manager;
               device = USBConnection.getInstance().device;
               // Attempt at setting up a USB input and output stream
               if (manager != null) {
                 if(usbDeviceConnection == null) usbDeviceConnection = manager.openDevice(device);
                  if(serialPort == null)
                  {
                     serialPort = UsbSerialDevice.createUsbSerialDevice(device, usbDeviceConnection);
                     if(serialPort != null && serialPort.open())
                     {
                        serialPort.setBaudRate(115200);
                        serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
                        serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
                        serialPort.setParity(UsbSerialInterface.PARITY_NONE);
                        serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);

                        input = new SerialInputStream(serialPort);
                        output = new SerialOutputStream(serialPort);
                        Log.d("Direct", "Connected to the USB socket");
                     }
                  }
                 }
              } // else there is no usb connected

这是在felHR85 UsbSerialDevice中,在他的ReadThread中,被注释掉的内容是我认为如果数据大于64字节会抓取数据

        int numberBytes, bytes;
        if(inEndpoint != null) {
            bytes = numberBytes = connection.bulkTransfer(inEndpoint, serialBuffer.getBufferCompatible(),
                    SerialBuffer.DEFAULT_READ_BUFFER_SIZE, 100);

        }/*while(numberBytes >= 64) {
                numberBytes = connection.bulkTransfer(inEndpoint, serialBuffer.getBufferCompatible(), bytes,
                        124, 100);
                bytes += numberBytes;
                Log.i("Bytes", " : " + bytes);
            }*/
        else
            bytes = numberBytes = 0;

这是他的WriteThread

    while(working.get())
    {
        byte[] data = serialBuffer.getWriteBuffer();
        if(data.length > 0)
            connection.bulkTransfer(outEndpoint, data, data.length, USB_TIMEOUT);
    }

修改

这解决了我的问题,但我仍然不确定我的原始问题的答案是什么

          if(serialPort == null)
          {
             usbDeviceConnection.claimInterface(USBConnection.getInstance().usbInterface, true);
             usbDeviceConnection.controlTransfer(64,0,1,0,null,0,0); // clear tx
             usbDeviceConnection.controlTransfer(64,0,2,0,null,0,0); // clear rx
             serialPort = UsbSerialDevice.createUsbSerialDevice(device, usbDeviceConnection);

1 个答案:

答案 0 :(得分:0)

请提出你的代码。请指定您作为附件使用的任何设备(Arduino,FPGA等),以便更容易找到解决方案。很难说出现了什么问题。我建议你做以下事情 -

1)检查附件的设备描述符,其中明确提到USB端点一次可以传输的最大字节数。在这里,我将它用于我的Arduino Uno Look at the last and 3rd last lines where it shows 64 bytes. Now look at the 8th line from the end-- that endpoint can transfer mx 8 bytes!

2)我请求您通过this而不是使用库。

3)有一个DTR信号必须从主机发送到附件,以指示数据传输完成;这样就可以发送下一个数据。Check this

4)您应该使用ring buffer作为接收流,这样数据就不会丢失。