MicroBridge: ADB support for Arduino

Google recently announced their open accessory toolkit, a new way of making Android talk to microcontrollers over USB. Unfortunately there are currently two barriers that are preventing people from playing with it. One is a lack of hardware, which I addressed in my previous post. Another is a lack of devices that support the new USB protocol, requiring either Android 2.3.4 or 3.1.

Fortunately almost every Android device since 1.5 supports the Android Debug Bridge (ADB) protocol, which allows for some interesting functionality such as TCP forwarding between the phone and PC, shell access, logcat output, and so forth. This protocol can be easily exploited to do communication between an Android application and an Arduino with USB host support. MicroBridge and other projects such as PropBridge and IOIO implement ADB on microcontroller platforms, and have been shown to work with a wide range of devices. For those who want Android/Arduino connectivity but don’t have access to a phone that is capable of accessory mode, ADB is a good alternative.

MicroBridge uses an Arduino and a USB host shield. This is concidentally the exact same setup Google later chose for their ADK reference kit. Since it was first released back in February I got a lot of response from people asking if I would port it to the Wiring language so that it would be available in the Arduino IDE. My original implementation was in C because I personally prefer it over the C++/Wiring stuff that Arduino uses. With Google releasing ADK however I’ve seen a sharp increase in interest for MicroBridge as well, and with new exciting hardware coming out, such as this board from diyrones, I felt it was time to finally put in the effort and do a port.

disclaimer: this solution has been tested on Arduino Uno, but should also work on an Arduino Mega + Oleg’s 2.0 shield. It should also be trivial to make it work on Google’s ADK reference board and the new diydrones board. If you have access to such hardware and would like to test it for me, please let me know.

Here’s a quick video of MicroBridge in action:

The code is available here. Follow this guide for installation instructions. The library contains all the code for driving the max3421e USB host chip, so there are no dependencies on Oleg Mazurov’s library. My code is heavily based on his work however, so credits should go to Oleg for his hard work. In case you were wondering about the board in the video, it’s a DFRobot Romeo.

Programming

The library supports multiple streams and is event driven. You create connections to ADB streams and receive events when streams (re)connect, disconnect, or receive data. First you must initialise the library in the setup function of your sketch:

void setup()
{
// Initialise the ADB subsystem.
ADB::init();
}
In the loop method, you must continually poll the ADB layer, like so:

void loop()
{
// Poll the ADB subsystem.
ADB::poll();
}
These two calls are the minimum for establishing and maintaining a connection to your phone. Even without opening any streams you should see the debugging symbol show up in the notification bar of your phone.

Opening a connection is done with the addConnection method. This method creates a new Connection object and returns a reference to it. You will use this reference to issue writes. The first argument describes what you’re connect to. Examples are shell: to get a unix shell, shell:exec logcat for logcat output, and tcp:4567 to forward local TCP port to the Arduino. The second argument indicates whether the connection should auto-reopen. You can choose to either create a connection that is opened only once when the device is first connected, or one that automatically re-opens when it is closed. This can be used to create connections that are re-established when a device is unplugged and then plugged back in. The final argument is a callback method that serves as an event handler. If you don’t want to receive events or read from this stream you are allowed to pass NULL. For example:

// Open an ADB stream to the phone’s shell. Auto-reconnect
shell = ADB::addConnection(“shell:”, true, adbEventHandler);
To receive data from the shell you must implement the event handler function. It takes three arguments, the Connection that is the source of the event, the payload length, and the payload data. Note that these last two are only relevant in the context of ADB_CONNECTION_RECEIVE events. Other possible events are ADB_CONNECT, ADB_DISCONNECT, ADB_CONNECTION_OPEN, ADB_CONNECTION_CLOSE, and ADB_CONNECTION_FAILED. The first two indicate device connect/disconnect, the rest should be pretty self-explanatory.

// Event handler for the shell connection.
void adbEventHandler(Connection * connection, adb_eventType event,
uint16_t length, uint8_t * data)
{
int i;

if (event == ADB_CONNECTION_RECEIVE)
for (i=0; iisOpen())
shell->writeString(“reboot\n”);
Here’s a video of me rebooting my phone from an Arduino.

So how do we use ADB to get a two-way connection to the phone? The demo application seen in the video above the Android application listens on TCP a port, and the Arduino connects to it over ADB using TCP forwarding. This establishes a two-way byte pipe much like ADK provides. The source of the Android app is here.

Conclusion

The ADB protocol is certainly not perfect, but it can be a good alternative for hobbyists who don’t have access to devices with support for accessory mode. It also has some interesting features that ADK does not, such as rebooting your device, which enables the Arduino to watchdog the phone. ADB also supports multiple streams which is really nice since you don’t need to write a separate byte protocol to funnel multiple data streams over a single pipe. It also allows the Arduino to log data directly to SD card. Finally, I got a lot of use out of redirecting logcat output from the phone to the serial port, which meant that I didn’t have to debug in the dark when writing Android code.

ADB will not go away any time soon. According to the spec it should also be available in accessory mode which means you can use protocols at the same time. While the MicroBridge library does not support this yet, I will certainly add this if/once I get a compatible phone.

In the mean time, I’d love to hear your feedback, bug reports, test results, and so forth.