2

I've been looking at examples and I'm still not clear on how to actually read data from the usb port in my Android application. I'd like it to be event/intent driven but I'm pretty lost on how to do this. I have a BroadcastReceiver but I'm unsure what Intent.action I need to be looking for to catch data coming in. Any insight is appreciated!

Edit: To clarify my Android device is a Nexus 9 running as a USB Host and I'm looking to communicate with an Arduino Leonardo.

Edit2: At this point I have an Arduino sketch running sending a message over serial every 2 seconds. I have a button that based off of my understanding should read the buffer when pressed but doesn't actually do anything.

    TextView displayMessages = (TextView)findViewById(R.id.textView);

    try
    {
        byte[] msgBytes = new byte[1000];
        connection.bulkTransfer(input, msgBytes, msgBytes.length, TIMEOUT);

        String msgString = new String(msgBytes, "UTF-8");// msgBytes.toString();
        displayMessages.setText(msgString);
    }
    catch (Exception e)
    {
        displayMessages.setText(e.getMessage());
    }

The result is simply that the textView is blank. If I don't do the conversion and drop the byte[].toString() in I get hex values that change each press but I'm not sure how to interpret that.

Edit 3: Just some more information as some time has passed, I have disabled the Arduino Leonardo showing up as an HID keyboard input device as per Arduino being recognized as keyboard by android. I simply modified the USBDesc.h to remove "#define HID_ENABLED". This didn't change the situation. In the meantime I have also implemented the Physicaloid USB library and that proved unsuccessful as well. I am in the process of debugging/converting mik3y's USB-serial-for-android library but have so far been unable to test with it.

Community
  • 1
  • 1
Karoly S
  • 3,180
  • 4
  • 35
  • 55

1 Answers1

0

Your android device can be used as a usb host or accessory. So depending on whether you use your phone as a usb host, you use the following intents and permissions in your manifest.

<uses-feature android:name="android.hardware.usb.host" />
<activity ... usb host...>
        <intent-filter>
            <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
        </intent-filter>
            <meta-data
            android:resource="@xml/device_filter"
            android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />

With an xml resource file giving the details of your device.

<?xml version="1.0" encoding="utf-8"?>
<resources>
//details of a device I own
<usb-device vendor-id="22b8" product-id="2e76" class="ff" subclass="ff" protocol="00" />
</resources>

Then set up the broadcast receiver and follow the steps in the API.

    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();
        if (ACTION_USB_PERMISSION.equals(action)) {
            synchronized (this) {
                UsbDevice device =
                        (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if (device != null) {
                        //call method to set up device communication
                    }
                } else {
                }
            }
        }
    }
};

You need to register your receiver.

    mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

    mPermissionIntent =
            PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
    IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
    registerReceiver(mUsbReceiver, filter);

Then create your function to read and write data.

private Byte[] bytes
private static int TIMEOUT = 0;
private boolean forceClaim = true;

...

UsbInterface intf = device.getInterface(0);
UsbEndpoint endpoint = intf.getEndpoint(0);
UsbDeviceConnection connection = mUsbManager.openDevice(device); 
connection.claimInterface(intf, forceClaim);
connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread

You need to modify this code to take the data where you'd like to. This link (android.serverbox) gives good discussion about handling the transfer thread.

This code has been taken and partially modified from the android.com docs.

Likewise there is a similar process to set up your device as a usb accessory.

  • Yea so I've seen this piece of code before but I still don't understand what part of that has to do with reading incoming data. As far as I understand what is happening it's simply setting up device communication permissions, not actually reading anything off of the USB. – Karoly S Jan 23 '15 at 21:06
  • Okay so I have all of that set up already and I can send data to my device and it is received. Having read everything you've posted in the Android docs already, reading is still unclear which is why I came here. From what it looks like the docs imply I cannot have an event/intent based read and I effectively have to asynchronously read from my USB Port constantly which feels like a terrible solution. There has to be a better way to do that and that's what I'd like to know. – Karoly S Jan 23 '15 at 21:21
  • I don't see the new link touch upon reading from the serial port either. Am I expected to simply create a constantly running thread that reads from the port? I'm struggling to accept there is no event driven way of doing this. – Karoly S Jan 24 '15 at 01:06