1

This is my first experience working with USB communication and an android app.

I'm using https://github.com/felHR85/UsbSerial to create a application that will allow tablets/phones to use USB OTG to act as a host and communicate with an accessory. I have gotten to the point where I'm using the SerialInputStreams and SerialOutputStreams to send and receive with the device.

This is about the maximum packet size a USB can send being 64 bytes with the cable I'm using. On my application, the accessory is sending data that is larger than 64 bytes. If the accessory does not have code that sends the data over in 64 byte packages, but instead all of it at once. Will any data that comes after 64 bytes be lost?

I'm receiving the first 64 bytes of the message from the accessory to the host and then host times out as it doesn't receive the full message and resends to the accessory. The first 64 bytes of the message are always what show up, that way I know the other parts of the message aren't waiting to be polled.

EDIT

The device I'm connecting to is a datalogger that is taken as a CDC device. I know that the connection I'm using has a maximum packet size of 64.

The USBConnectActivity happens whenever a usb device is attached and passes the filter that I have set up, and the interface and endpoints are correct.

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

    }
}

This class holds all the USB info

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

This is the code I use to set up the input and output streams

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

This is in felHR85 UsbSerialDevice, in his ReadThread, and what is commented out is what I included thinking it would grab the data if it was larger than 64 bytes

        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;

This is in his WriteThread

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

EDIT

This solved my problem but I'm still not sure what the answer is to my original question

          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);
dcbird
  • 11
  • 4

1 Answers1

0

Please put up your code. Please specify any device that you are using as accessory(Arduino, FPGA, etc) so that finding solution becomes easier. It is difficult to tell what is going wrong. I suggest you to do the following -

1)Check the device descriptor of the accessory where it is clearly mentioned the maximum bytes the USB endpoint can transfer at a time. Here I have it for my Arduino UnoLook 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)I request you to go through this instead of using a library.

3)There is a DTR signal which must be sent form host to accessory to indicate that data transfer is complete; so that the next data can be sent.Check this

4)You should be using a ring buffer for the receiving stream so that the data is not lost.

thapro
  • 44
  • 11