A closer look at Google’s open accessory development kit
May 11, 2011
Google announced a new addition to Android, the open accessory development kit, a way for microcontrollers to connect to Android devices over USB. The idea seems to be that anyone will be able to develop Android accessories, although there seems to be a lot of focus on the hobby market as well. This is especially evident from their choice of platform, the reference design is an Arduino Mega 2560 paired with Oleg’s USB Host shield, and their demo software is written in the Wiring language.
Since I’ve been doing some work in extending Android devices with extra IO I was naturally interested in ADK. There has been a lof of confusion over how it works and how it compares to other solutions however, so I decided to do a write-up of the alternatives and a review of this latest solution. Before I dive into Google’s ADK, I’d first like to talk a bit about the story of Android/MCU connectivity so far and the options that are currently out there, which should hopefully put this new toolkit into context.
Projects such as Amarino and Cellbots were some of the first to connect micros to Android devices. These use Bluetooth modems with the serial profile (i.e. Bluesmirf) which makes it extremely easy to send bytes back and forth. This continues to be a popular option especially for projects where a wired connection is undesirable.
If you own an HTC phone you can get a breakout board for their proprietary connector to bring out ttl uart (3.3v). Another wired solution exploits the audio output jack to implement a one-way (phone to controller) serial connection. Examples include Sparkfun’s audio jack modem and HiJack. These are cheap and work with almost any controller but suffer from occasional data corruption and are sensitive to the output volume of the phone.
A lot of Android devices have controllers that support USB on-the-go (OTG). If your phone supports it and you are willing to root your device, you can simply make your phone play bus master and have your Arduino’s FTDI as a slave. An external 5V power source is required to supply VBUS. While this good enough for a lot of projects it does not work across all devices and still requires root and a lot of fiddling with FTDI drivers to work.
ADB and USB host
Android devices version 1.5 and above support a USB protocol for debugging applications, which also provides a lot of other useful functionality such as shell access, TCP forwarding, pushing files to the device, and so on. This protocol is know as the Android Debug Bridge (ADB), and can be enabled manually in the settings of your phone. ADB is very useful since it is essentially a byte stream multiplexer over USB. The host can open multiple streams concurrently, so it’s for example possible to talk to a running process through TCP or a local unix pipe, read logcat data, and pipe data to a file, all at the same time. Especially redirecting logcat output to the serial port of the MCU is crucial for debugging, but can also be used to let your micro detect when the Android process has crashed so it can be restarted. If worst comes to worst it can even reboot the phone.
My own work, MicroBridge, is an implementation of ADB and runs an Arduino with Oleg Mazurov’s USB host shield – the exact same hardware that Google later used for their ADK reference design. The Arduino is bus master (host), and the Android phone is a slave device. This setup is essentially the same as when your phone is connected to your PC, and the Arduino has the exact same capabilities and rights. What is more, the phone can be powered through VBUS which is great for permanent installations. The original MicroBridge code was later reworked into spin code for propeller microcontrollers by Spiritplumber and released as PropBridge. More recently Sparkfun announced IOIO, a separate and much more polished ADB implementation with a solid Java library. IOIO gives the phone direct control over the various pins of its PIC24 chip, removing the need for to write their own firmware. In my own personal opinion IOIO is by far the most advanced, complete, and well-designed solution out there right now.
So how does ADK fit into all of this? First of all, ADK uses the same hardware setup as the above projects, with the microcontroller acting as USB host. This is where the similarities end however, as ADK invented its own USB protocol specifically for accessories. This protocol offers a single bidirectional byte pipe between the phone and the accessory device, and comes with a nice Java API to detect and interact with connected accessories. So with ADK you can essentially attach a USB host capable microcontroller and talk to it from Java, but that’s about it. This means it actually offers fewer features than what was already out there, especially compared to IOIO. What is worse, because ADK has its own protocol you’ll need an Android 3.1 or 2.3.4 device (API level 12) for it to work, while the ADB solutions are compatible with any 1.5 or above device and have been shown to work on a wide range of phones and tablets.
So why does ADK come with a new byte stream protocol when pretty much every device in existence already supports ADB, a protocol which was specifically designed to do just that? This to me is a great mystery in itself, but it gets worse. Much, much worse. You see, I would have been fine with a new protocol specifically for accessories – ADB wasn’t intended to do this in the first place, and although I would have preferred an extension to ADB over a new protocol, I can see how it makes sense to have something dedicated to the task. But then I read their documentation.
A USB device can support multiple protocols through interfaces. A smartphone for example can act as a USB storage device, it can offer a network connection (thethering), and in the Android case it will do ADB when enabled. You can use the lsusb -v command in Linux to have a look at what interfaces your devices support. If you want to detect an ADB device connected to your machine for example you can simply iterate over all connected devices, and see if any of them advertise the ADB interface. It would have been logical to simply add a new interface definition for the new protocol, which would have made detecting an Android device supporting accessories trivial. But for reasons unknown the ADK team decided they had a ‘better’ solution. And by better I of course mean ass-backwards.
If you read the documentation, the official way to ‘detect’ an Android device supporting accessories is to send it a control request. If it responds with a non-zero protocol number, send it some configuration data, and tell the device to go into ‘accessory mode’. Note that all actions use non-standard control requests (0×51-0×53). After the final request to switch modes, ‘the connected USB device should re-introduce itself on the bus in accessory mode and the accessory can re-enumerate the connected devices’. Wait, what? Yes, the Android device reconfigures itself and shows up as a different device with specific vendor and product IDs. Classy.
Not only is this whole process completely unnecessary and completely contrary to how USB devices generally operate, it actually introduces real implementation problems that could (and should) have been easily avoided. For example, what happens if the Android device is not the only device connected to the host? This may happen when I want to operate an accessory in a pass-through fashion, allowing other devices to connect to it. How exactly am I supposed to detect which one is an Android device supporting accessory mode? I cannot query the interface list because the new protocol is not advertised there. I can also not look at the vendor/product IDs because that would require an exhaustive list of all Android devices ever produced, and is not exactly future-proof for obvious reasons. My only option is to send a non-standard control packet (0×51) to every slave device, but sending random control packets to random devices is probably not a great idea as they might actually happen to have meaning for those devices. The obvious answer is that the ADK designers made the assumption that there is only a single device on the bus.
Why they chose this approach is beyond me. When you have an accessory attached you can not also have the device act as a USB storage device, for example, and you can forget about thethering too. I have a sneaking suspicion however which may explain this strange technique which I can only pray isn’t true. The library they used for Oleg’s USB host shield contains a bug that basically makes it impossible to use endpoint numbers other than 0 and 1, a bug which I happen to know about because I had to fix it for my own ADB implementation. Maybe this is why they hacked the USB stack on the phone side to go into ‘accessory mode’, wich conveniently has its bulk in/out endpoints at those addresses, rather than just locate and fix this bug on the microcontroller side?
By botching together a new protocol the ADK team ensured that nobody will be able to use this on anything but the latest phones, which makes it completely useless for commercial applications in the short term. For hobbyists it means that unless they’re willing and able to update their devices to the latest roms they won’t be able to join the fun until their next smartphone purchase. So we’re dealing with a badly designed, incompatible alternative to existing solutions. And this alternative is now the standard backed by Google.
I really want to love ADK, and I would have been the first to applaud Google for a job well done if they had actually taken the time to come up with a proper design. They could have added a new protocol properly, they could have built something on top of ADB, but more importantly they could have added proper support for OTG. As it stands ADK doesn’t solve any problems that weren’t already solved. Instead, they made the situation only worse by adding a new poorly thought-out standard, and we all know that’s the last thing Android needs another one of.
In the mean time, if you want to play with Android/microcontroller integration I suggest you hop over to Sparkfun and get yourself an IOIO.