Turn your Linux computer into a huge Android USB Accessory

Google is promoting it’s Arduino-Like hardware to test and prototype with USB accessories. Meanwhile you are either waiting for your USB-Host board or deciding if you even want to get one at all. At that point we would like to share a way of how to write your first “Hello World” application using your Linux Desktop/Laptop (we use Ubuntu …).

Your Desktop/Laptop probably has a USB host controller. This opens you all doors to write accessory applications using “libusb”. We have written some C code as a template that let’s you act as Accessory on Linux side.

simplectrl.c

You can use it for instance to benchmark the data throughput and do all other kinds of crazy stuff. (Did I just hear “use your Nexus S as RFID reader”?)

Java Code to follow …

update:

to compile on Ubuntu install the following packages:
apt-get source libusb
apt-get install libusb-dev
apt-get install libusb-1.0-0-dev

And compile using the line
gcc simplectrl.c -I/usr/include/ -o simplectrl -lusb-1.0 -I/usr/include/ -I/usr/include/libusb-1.0

update
The Java example can be found here.
Please note that the example is very rudimentary as well as threading just temporarily. During the next weeks we are going to require a better and more robust example which will be followed by some post with source code.

66 thoughts on “Turn your Linux computer into a huge Android USB Accessory”

  1. Need to add a libusb_close(handle); where you close the interface before re-opening connection to device in accessory mode. For me, this was required or the I/O would not work (though the new connection and interface claiming would work with no errors).

  2. Thank you very much for your fix Colin. Seems I missed that command :) so your deinit looks like the following snippet?

    static int deInit(){
        if(ctrlTransfer != NULL)
            libusb_free_transfer(ctrlTransfer);
        if(ctrlTransfer != NULL)
            libusb_close(handle);
        if(handle != NULL)
            libusb_release_interface (handle, 0);
        libusb_exit(NULL);
        return 0;
    }
    
  3. Installed the source & libraries in Ubuntu 11.04 as described.

    gcc simplectrl.c -I/usr/include/ -o simplectrl -lusb-1.0 -I/usr/include/ -I/usr/include/libusb-1.0

    when compiling as above I get this:

    simplectrl.c: In function ‘deInit’:
    simplectrl.c:119:5: error: ‘ctrlTransfer’ undeclared (first use in this function)
    simplectrl.c:119:5: note: each undeclared identifier is reported only once for each function it appears in

    1. Hey Oscar

      you are completely right, I made a mistake in my latest edit…
      I re-corrected it now :)

      cheers
      Manuel

      1. The first part in the mainPhase says:
        response = libusb_bulk_transfer(handle,IN,buffer,16384, &transferred,0);
        Should the second parameter be OUT instead of IN ?

  4. Heya

    Okok I know I owe you the java code :D Got a bit lost :)
    It’s really nothing much and I will upload it tomorrow.

    Cheers
    Manuel

    1. Hey Michael

      I will work on the java code and upload it as soon as possible. I wanted to do that the other week but found that large parts of the code won’t work anymore with the example since I made changes to it. I wanted to create a “virtual” Android NFC scanner and then transfer data over USB and emulate the key presses to enter the code (via uinput). The code follows strictly the ADK guidelines from the official documentation. However, I will try to fix everything and make a tar today :)

      Regards
      Manuel

  5. Manuel, sorry for my delayed response! As the other commenter noted, the transfer freeing was not valid for the posted code (I assumed it was part of a block you did not publish intentionally).

    The other thing I did was to sync up the buffer sizes on both sides and simplify things a bit to assume one command per read/write due to how Android ADK manages the data flow (or so I’m told…. I’m guessing your code is based on something that was not ADK-based, either pre-ADK work or non-Android?)

    As for the other commenter asking for the Java side, as Manuel stated, I just used the Android documentation and the ADK Sample application to somewhat easily create the Java Android side of things.

  6. I have some code that use libusb to control the pos printer on the android tablet, i can find and claim the usb device , but when i use ioctl function to send data to the usb device, it return the error epipe

    1. @androidy
      the code of the java part is heavily based on the sdk example and therefore it makes no sense to apply GPL. Use it under your own license :-)

  7. I would just wait for these mobil phones and tablets to be usb hosts. making a micro controller be a USB host is pretty tough. Host mode on linux, is much better to make a userspace driver out of libusb. There is also pyusb too.

    I have a droid bionic, host mode, libusb, keyboard and mouse support, etc, etc, are all good to go out of the box. I even installed that pyusb on the python that seemed to be preinstalled. worked like a charm. Now to get cracking on some other projects

    1. Hello Myriam

      Depending on what you want to try. So is your embedded device host? It will require a host USB driver. You can either use libusb or another USB library, or even make your own implementation using ioctl and such. In my opinion libusb will probably be the easiest.

  8. Thx for your reply Manuel,
    My embedded device is a gateway, i want to add support of Open Accessory on it.
    i think if i have to choose Libusb, i will try the cross compilation for my gateway..
    then i have to develope my own application to communicate with Android.
    So it is importante to me to know if libusb is the suitable solution ..

  9. Hello, the program seems to work fine but i have the pb :
    [mainPhase][99]
    Error: LIBUSB_ERROR_IO
    Input/output error.
    LIBUSB_ERROR_IO: -1
    what can i do to solve the issue ?

  10. when i run ./simplectrl i get “Problem acquireing handle”. The android device is connected and i have modified the accessorry setup to start a sample app. how am i supposed to launch/run the simplectrl program?

    Thanks

    1. Hi gowda,
      Please help, let me know?
      I just installed the packages & on Ubuntu that was running on virtual box on my windows. I installed the USBTest app on my Google nexus S, And just connect both with usb. But nothing happen on both.. :(
      I am not sure what can i do.. Is there any think i do for communicating with both?
      Please tell me the process How you did please….?

  11. Hi,
    thanks for the example but I have a question – what USB mode (mass storage/media player/kies and optional debug mode) should be set on the phone when running this code? I tried kies and media player (with and without debugging enabled), but I’m getting LIBUSB_ERROR_PIPE durign “Setting up accessory” on my linux. I’m using Fedora 16 and Samsung Galaxy S with Android 2.3.6. and uploaded future.usb jar and xml file. Or maybe you have some other idea what can be going wrong?
    Thanks in advance for your help

  12. Yes, ADB works normally (on standard user account too). I tried of course running it on Linux as a root, but nothing changed. I’m also waiting for a response from Samsung whether this should work or they had removed something when they was making the 2.3.6 release for my phone (it would be a bad surprise).

  13. Hi,

    I get the below error when I try to to run your program.

    Error: LIBUSB_ERROR_IO
    Input/output error.
    Error during main phase.

    Thank you! Appreciate your help!

  14. Hi,

    I got the app working on Nexus. I was trying to do the same on Acer 3.2. But write was returning with “No such device” error. Can you please let me know the reason.

    Thank you!

  15. This is a great series of posts. Keep ‘em coming!

    Before I forget, your source has a typo in line 77. You transposed two letters in “Nexus” so the error link fails.

    I did get your code to compile and run (with sudo) on my Ubuntu machine without any problems. I tried it with two Android devices. The first was a Motorola Atrix running Android 2.3.6 and the second was a Motorola Zoom tablet running Android 3.1.

    On the Atrix, I get the LIBUSB_PIPE_ERROR that others have mentioned. I’m wondering if my Android OS (2.3.6) is too old.
    ————————-
    Error: LIBUSB_ERROR_PIPE
    Pipe error.
    ————————-

    The Zoom gave this output:
    ————
    Verion Code Device: 1
    Accessory Identification sent
    Attempted to put device into accessory mode
    Error setting up accessory
    ————–
    On the Zoom itself, I got that error dialog saying “No installed apps work with this USB accessory. Learn more about this accessory at neuxs-computing.ch” I assume I need to have an app that is waiting for communication with the ‘simplectrl’ app running on my Linux box.

    Did I miss something or have you written a simple test app that I can build for Android that will talk to ‘simplectrl?’

      1. Hi Manuel,
        Please help, let me know?
        I just installed the packages & on Ubuntu that was running on virtual box on my windows. I installed the USBTest app on my Google nexus S, And just connect both with usb. But nothing happen on both..
        I am not sure what can i do.. Is there any think i do for communicating with both?
        Please tell me the process How you did please….?

  16. Who has problem with:
    Error: LIBUSB_ERROR_IO

    check what libusb version installed into your system.

    Seems for libusb1.i686 following define:
    #define IN 0×85
    must be changed to
    #define IN 0×81

    Works on Fedora-16.

  17. Okay, I’m getting close.

    I have the Java ‘UsbTest’ app installing via the Eclipse debugger on my Motorola Xoom, which I now realize is actually running Android 4.0.3. However, to get it to compile, I had to comment out two lines of “@override.” before ‘public void onClick()’ and ‘public void onRun().’ Is that an indication I have something wrong in my SDK setup?

    Anyway, I forged ahead with those lines commented out.

    Then, I modified the parameters in the call to setupAccessory() in simplectrl.c to use the same manufacturer/model/version specified in the accessory-filter.xml file in the Android application.

    I also modified the accessory PID/VID numbers to match those of the hub on my Linux machine in the call to libusb_open_device_with_vid_pid() in setupAccessory().

    So, now, when I run simplectrl, the UsbTest app opens on my Xoom asking me to send a number to the accessory. However, simplectrl reports a LIBUSB_ERROR duing the mainPhase() function.

    Any thoughts?

    By the way, this whole thing is a gift from above. I’m happy to make a donation to your cause as this tutorial has saved me a lot of hours on the learning curve.

    1. Hey David!

      Glad you liked the tutorial :) We try to give back to the open source community as good as possible :)

      Regarding Overrides:
      This has to do with your host systems’ Java version and is not related to the current Android version.

      Regarding the Error:
      I recall that there was a bug with the code in the main phase (simplectrl.c) which was pointed out in the comments. Anyhow, you should verify if the IN endpoint is the correct one, check this using lsusb -v : on your host machine. There you should also see the interfaces.

      Also it would be probably much simpler if you switch to some python script utilizing a wrapper like pyusb.

      All the best
      Manuel

  18. I tried your suggestions, both looking up the endpoint with ‘lsusb -v’ and also trying pyusb. I think that my problem is not a code thing, but something in my Linux configuration because both the C code and the pyUSB fail at the same point (the bulk transfer) and in the same way. My only other theory is that there is a problem in the Android Java code.

    I found that my Xoom provides two IN endpoints designed for bulk transfers, 0×81 and 0×83. Both lsusb and some pyUSB programs I wrote confirmed this. I tried both of these endpoint addresses, but I always ended up getting a LIBUSB_ERROR_IO when it goes to do the bulk transfer.

    When I enabled the debug messaging with libusb, I get a message like:

    libusb:error [submit_bulk_transfer] submiturb failed error -1 errno=2

    Looking at the source code of libusb, that results from a failed ioctl() call down into the lower levels of the kernel.

    So, after much reading about USB and Python, I wrote a pyUSB program that follows similar steps to simplectrl and I pretty much see the exact same behavior. The control transfers to setup the accessory mode work great, the app wakes up, but the bulk transfer fails giving the following “Resource Busy” error trace:
    ————————
    Traceback (most recent call last):
    File “bulk2.py”, line 70, in
    data = ep_in.read(16)
    File “/usr/local/lib/python2.6/dist-packages/usb/core.py”, line 301, in read
    return self.device.read(self.bEndpointAddress, size, self.interface, timeout)
    File “/usr/local/lib/python2.6/dist-packages/usb/core.py”, line 647, in read
    self._ctx.managed_claim_interface(self, intf)
    File “/usr/local/lib/python2.6/dist-packages/usb/core.py”, line 112, in managed_claim_interface
    self.backend.claim_interface(self.handle, i)
    File “/usr/local/lib/python2.6/dist-packages/usb/backend/libusb10.py”, line 519, in claim_interface
    _check(_lib.libusb_claim_interface(dev_handle, intf))
    File “/usr/local/lib/python2.6/dist-packages/usb/backend/libusb10.py”, line 403, in _check
    raise USBError(_str_error[ret], ret, _libusb_errno[ret])
    usb.core.USBError: [Errno 16] Resource busy
    ————————————

    I am in the process of setting up a couple newer Linux boxes anyway, so I will try this code on them, probably in the morning. (It’s 2AM here.)

    While I don’t quite have things working, I did manage to learn a whole lot about USB fundamentals, python, pyUSB and libusb, which will all be very valuable.

    If I get the pyUSB working. I will post it. I will be ugly Python probably. I’m new at that also.

  19. I tried another machine. This one is running Ubuntu 12.04 where before I had been running 10.10. The fact that my pyUSB and libusb code behave pretty similarly makes me wonder if I need to change something about the Java code or the Android device. I might see if I can get my hands on another device just to compare or upgrade the Android OS on my phone.

    Like I said before, in both cases the failure is pretty catastrophic in that after the failure of the bulk transfer attempt, the Android device does not even show up in lsusb.

    1. Hello Dave!

      That really doesn’t sound good. I can’t really think of any possible solution at the time. Maybe try another device with another Android version. Also, did you claim the correct USB interface before trying to transfer?

      All the best and hope you will be able to solve the issue
      Manuel

  20. Here is my pyUSB code that should talk to the USBTest app.
    http://pastie.org/4033450

    It behaves just like simplectrl.c, which unfortunately on my machine reports a Resource Busy error when it goes to do the bulk transfer.

    If anyone wants to try this and let me know it works for them, I would appreciate it.

    Sorry, for the sloppy python. This is my first python program.

  21. Hey there, thank you very much for your work.

    I am trying to get this running on my nexus s android 4.04, and it is erroring out where it tries to grab the handle of when it changes to accessory mode. The lsusb shows the change from 18d1:4e22 to 18d1:2d01. After it fails, the phone stays in accessory mode, and I tried to just change the initial handle acquire to use the accessory pid, yet it fails. On the phone, it recognizes a connected accessory and indeed opens the app. Any ideas?

    1. Hey Chris,

      One thing you could try is to induce a artificial delay after it re-enumerates, maybe this would help. Only a guess though :)

      All the best
      Manuel

  22. I believe it does have artificial delay in the form of the 5 tries and sleep(1), right? Also, did you end up adding the libusb_close(handle)?

  23. I was also wondering, how did you get the endpoint addresses? I mean, how did you know which ones to use?

    1. Hello Chris,

      I think there are only two Bulk Enpoints, one for IN transfers and one for OUT transfers if I remind correctly. As soon as I have a chance I will look into the matter.

      All the best
      Manuel

  24. There are indeed one set of endpoints that we should use. If we have adb debugging on, there are 2 sets in fact, the first is for our use and the second set is for adb

  25. Hi,

    First of all it is a very useful tutorial. Thanks a lot for it.

    I faced with a problem when switch to the accessory mode.
    After the following line:
    libusb_control_transfer(handle,0×40,53,0,0,NULL,0,0);
    the usb device is umounted and libusb_open_device_with_vid_pid() was failed.
    If I remount the device manually before calling libusb_open_device_with_vid_pid(), it works fine.

    Have anybody a suggestion, what can cause this? What do I wrong?
    How can I avoid the umount after switch to accessory mode?

    I’m working on Windows 7 and using Ubuntu via Virtual Box (I have tried it on Mac OS directly as well).
    I tested the code with Samsung Galaxy S III and Huawei Ascend G300.
    The code is modified so maybe it casuses the problem.

    Regards,

    Jeno

    1. HI, jeno
      Have you maken Virtualbox remount the android device after it enters into accessory mode?
      Or do you have any approch to avoid Virtualbox unmounting the android device?

  26. Hi,
    Great tutorial. I almost got it to work. First of all my phone is a Huawei G300 (custom ROM 4.0.3).
    The java app from this site does not start. I created another app. I just want to get the intent… I can take it from there :). But my app is not started when I run simplectrl.

    I get the error mentioned before
    Error: LIBUSB_ERROR_IO
    Input/output error.

    However, my phone says it changed to Accessory mode and after an “lsusb -v” I can confirm this (according to Google the VID = 0x18d1 and PID = 0x2D01 means Accessory mode).

    On the phone I can also see a message
    - the message “title” matches what I send from the PC (simplectrl)
    - instead of the actual message I get “res/drawable-hdpi/ic_sysbar_home” (this is the actual text)
    - the message has 2 buttons: Cancel and, here is the wierd part, “res / drawable / ic_sysbar_ime.xml” (this is what is actually written on the button).

    When I press the “res / drawable / ic_sysbar_ime.xml” button it promts for a web browser.

    Any ideas ?
    Thank you very much.

  27. Hi,

    Quick update. From time to time when I run simplectrl on my android I see that it crashes my system UI.
    Also one question. Shouldn’t
    response = libusb_control_transfer(handle,0×40,52,0,0,(char*)manufacturer,strlen(manufacturer),0);
    be
    response = libusb_control_transfer(handle,0×40,52,0,0,(char*)manufacturer,strlen(manufacturer)+1,0);

    Thank you

  28. Final update… maybe it might help someone.
    I realized that the simplectrl does indeed turn on Accessory mode.
    The problem was in my android phone. It seems that it did not want to show me the “open with” message box (alot of crashes with wierd messages). The crash happened only when Manufacturer, Model and Version number matched (PC vs application).
    I ended up flashing CyanogenMod 10 and now everything is working.

    Thank you once again for this great tutorial.

    1. Hey there,

      Thank you so much for sharing! I am glad everything works now with CM, some manufacturers just don’t cut it with the software part :)

      All the best for you and the project
      Manuel

    2. Hi PLP,

      I just compiled the andorid code in my nexux s running on android 4.1.2.
      i downloaded the simplectrl.c. And i compiled the C code with instructions above. (Actually am running in Mac with Virtual Machine as Ubuntu 12.0 . ) But when I run that file with ./ it is showing some thing like “Proble acquiring handle”. Not sure is this is an error? what I did wrong? Can you please tell me , How can i communicate with my Mac with andorid device?
      Please help me out… :(

      Thanks you Inadvance.. :)

  29. Hello! I tried to run your java code and build it against Google API 4.2.2 and got some errors :

    Description Resource Path Location Type
    The method getInstance(Context) is undefined for the type UsbManager UsbTest.java /UsbTest/src/ch/serverbox/android/usbtest line 153 Java Problem

    The method getAccessory(Intent) is undefined for the type UsbManager UsbReceiver.java /UsbTest/src/ch/serverbox/android/usbtest line 27 Java Problem

    Against which API do I need to build this ?
    Thank you in advance!

    1. Hi Andreid,

      I think your issue is related with the kind of package you are using.
      I guess you are using the java source code provided in this post itself.
      If you are building against API 2.3.4 you can straight away use that code but from Honeycomb 3.1 onwards you need to use different package. I mean to say instead of com.android.future.usb package you have to use android.hardware.usb package and accordingly the function call will also change.
      To be more specific (after importing android.hardware.usb package)

      fd = UsbManager.getInstance(getApplicationContext()).openAccessory(a).getFileDescriptor();

      will change to something like

      fd = mUsbManager.openAccessory(a).getFileDescriptor();

      Kindly go through this tutorial for further information Choosing the Right USB Accessory APIs.
      http://developer.android.com/guide/topics/connectivity/usb/accessory.html

      Hope this will help…
      All the best !

  30. Hello,! I have two problems with this example code.
    1. LIBUSB_ERROR_IO
    When I run code on PC, it’s successful to connect to android device. Than app on android device start to rung for sending data to PC. But after connected to android device, the program on pc dies immediately and prints the message

    >$ sudo ./simplectrl
    >Verion Code Device: 2
    >Accessory Identification sent
    >Attempted to put device into accessory mode
    >Interface claimed, ready to transfer data
    >Error: LIBUSB_ERROR_IO
    >Input/output error.
    >Error during main phase

    It seems that the program ended when try to receive data from android device
    response = libusb_bulk_transfer(handle,IN,buffer,16384, &transferred,0);

    Do you have the same error? Please help me fix this problem!

    2. Can’t run program on pc several times without unplug usb cable
    If I run program on pc, it’s successful to connect to android device than and die immediately. When I try program on pc again, it can’t connect to android device if I don’t unplug and plug usb cable again. Program exit with error message
    >$ sudo ./simplectrl
    >Problem acquireing handle
    How can we fix this problem?
    Thank you in advance!

  31. in order to access on accessory mode you used another PID: #define ACCESSORY_PID 0x2D01.

    I’M using wiko iggy phone : Bus 001 Device 035: ID 0bb4:0c02 HTC (High Tech Computer Corp.) Dream / ADP1 / G1 / Magic / Tattoo (Debug).

    I set:

    #define VID 0x0BB4
    #define PID 0x0C02
    and left ACCESSORY_PID the same

    is the ACCESSORY_PID used depend on device, because it does’t work for me, it stopps on Error setting up accessory on the tutorial

    when I launch the app first time I get :
    Device is not USB Accessory Mode
    Verion Code Device: 2
    Accessory Identification sent
    Attempted to put device into accessory mode
    connect to new PID…
    Error setting up accessory

    and then lsusb give me :
    Bus 001 Device 020: ID 18d1:2d01 Google Inc. Android-powered device in accessory mode with ADB support

  32. Thank you so much for the tutorial, It save my life :D

    Here is some experiment I get when I try to run this tutorial:

    - To get it run you must change the VID and PID to match with your phone conennection ( use lsusb to find them )

    - Change manufacture, model, version match with those information in file accessory_filter.xml in Java code.

  33. Hi everyone,

    I have a problem. When I run simplectrl.c, my phone turn into accessory mode then it changes VID to 0x18D1 and PID to 0x2D01. It seem good but when the program on pc try to reconnect to my phone with new VID PID, it return NULL.
    - (handle = libusb_open_device_with_vid_pid(NULL, VID, ACCESSORY_PID)) == NULL

    Can someone give me any ideas?

  34. I twerked some more per:

    - Change manufacture, model, version match with those information in file accessory_filter.xml in Java code.

    Now the App runs when launching simplctrl, but I still don’t see any data between the App and the terminal. Help?

    EC123

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>