The Android device connects using ADK over USB to the Ardunio which is running in a loop waiting for data from the USB Shield. If the Android device sends a 1 then the Arduino turns the LED on. If a 0 is sent the LED is turned off.
Hardware Setup
For this example I used:
- A breadboard Arduino with a Sparkfun FTDI 3.3v board.
- An Acer Iconia Tab A100 running Ice Cream Sandwich 4.0.3.
- A Circuits@Home USB Host Shield for Arduino Pro Mini.
- A red LED. Connected to the Arduino on digital pin 8.
- A 470 ohm resistor connecting the LED to ground.
The picture below shows how the hardware is setup.
The USB shield was wired to the Arduino as shown in the diagram below.
Starting from the top left of the board and working around the board clockwise.
USB Shield | Arduino |
INT (D9) | Digital Pin 9 |
GND | GND |
RESET | Reset |
GND | GND |
3.3v | 3.3v |
SCK | Digital Pin 13 |
MISO | Digital Pin 12 |
MOSI | Digital Pin 11 |
SS (D10) | Digital Pin 10 |
Software Setup
This example assumes you have the eclipse Android development environment and the Arduino development environment.
If you are using the Circuits@Home USB Shield you will need to download the 2.0 libraries for the shield and put them in your Arduino libraries directory. The libraries and example files are on GitHub.
#include <avrpins.h> #include <max3421e.h> #include <usbhost.h> #include <usb_ch9.h> #include <Usb.h> #include <usbhub.h> #include <avr/pgmspace.h> #include <address.h> #include <adk.h> #include <printhex.h> #include <message.h> #include <hexdump.h> #include <parsetools.h> USB Usb; USBHub hub0(&Usb); USBHub hub1(&Usb); ADK adk(&Usb,"Digitalhack", "LEDOnOffADK", "DemoKit Arduino Board", "1.0", "http://www.android.com", "0000000012345678"); uint8_t b, b1; #define LED 8 void setup(); void loop(); void setup() { Serial.begin(115200); Serial.println("\r\nADK demo start"); digitalWrite(LED, LOW); pinMode(LED, OUTPUT); if (Usb.Init() == -1) { Serial.println("OSCOKIRQ failed to assert"); while(1); //halt } } void loop() { uint8_t rcode; uint8_t msg[3] = { 0x00 }; Usb.Task(); if (adk.isReady() == false) { Serial.println("Waiting for adk."); } else { uint16_t len = sizeof(msg); rcode = adk.RcvData(&len, msg); if( rcode && rcode != hrNAK) { Serial.print("Data rcv rcode: "); Serial.println(rcode); } if(len > 0) { Serial.println("Data Packet."); // assumes only one command per packet if (msg[0] == 0x2) { switch( msg[1] ) { case 0: digitalWrite(LED, LOW); break; case 1: digitalWrite(LED, HIGH); break; } } } delay( 10 ); } }LEDOnOFFADK.java
goes in ProjectRoot>\src\com\example\ledonoffadk\
package com.example.ledonoffadk; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import com.example.ledonoffadk.R; import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbManager; public class LEDOnOffADK extends Activity { private static final String TAG = "LEDOnOffADK"; private static final String ACTION_USB_PERMISSION = "com.example.LEDOnOffADK.USB_PERMISSION"; private UsbManager mUsbManager; private PendingIntent mPermissionIntent; private boolean mPermissionRequestPending; UsbAccessory mAccessory; ParcelFileDescriptor mFileDescriptor; FileInputStream mInputStream; FileOutputStream mOutputStream; Button btnOn, btnOff; private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (this) { UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (intent.getBooleanExtra( UsbManager.EXTRA_PERMISSION_GRANTED, false)) { openAccessory(accessory); } else { Log.d(TAG, "permission denied for accessory " + accessory); } mPermissionRequestPending = false; } } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) { UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (accessory != null && accessory.equals(mAccessory)) { closeAccessory(); } } } }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "In onCreate()"); mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); registerReceiver(mUsbReceiver, filter); if (getLastNonConfigurationInstance() != null) { mAccessory = (UsbAccessory) getLastNonConfigurationInstance(); openAccessory(mAccessory); } setContentView(R.layout.main); btnOn = (Button) findViewById(R.id.btnOn); btnOff = (Button) findViewById(R.id.btnOff); btnOn.setOnClickListener(new OnClickListener() { public void onClick(View v) { byte[] buffer = new byte[2]; buffer[0]= 0x2; buffer[1]=(byte)1; // button says on, light is off if (mOutputStream != null) { try { mOutputStream.write(buffer); } catch (IOException e) { Log.e(TAG, "write failed", e); } } Toast msg = Toast.makeText(getBaseContext(), "You have clicked On", Toast.LENGTH_SHORT); msg.show(); } }); btnOff.setOnClickListener(new OnClickListener() { public void onClick(View v) { byte[] buffer = new byte[2]; buffer[0]= 0x2; buffer[1]=(byte)0; // button says on, light is off if (mOutputStream != null) { try { mOutputStream.write(buffer); } catch (IOException e) { Log.e(TAG, "write failed", e); } } Toast msg = Toast.makeText(getBaseContext(), "You have clicked Off", Toast.LENGTH_SHORT); msg.show(); } }); } @Override public Object onRetainNonConfigurationInstance() { if (mAccessory != null) { return mAccessory; } else { return super.onRetainNonConfigurationInstance(); } } @Override public void onResume() { super.onResume(); if (mInputStream != null && mOutputStream != null) { return; } UsbAccessory[] accessories = mUsbManager.getAccessoryList(); UsbAccessory accessory = (accessories == null ? null : accessories[0]); if (accessory != null) { if (mUsbManager.hasPermission(accessory)) { openAccessory(accessory); } else { synchronized (mUsbReceiver) { if (!mPermissionRequestPending) { mUsbManager.requestPermission(accessory,mPermissionIntent); mPermissionRequestPending = true; } } } } else { Log.d(TAG, "mAccessory is null"); } } @Override public void onPause() { super.onPause(); closeAccessory(); } @Override public void onDestroy() { unregisterReceiver(mUsbReceiver); super.onDestroy(); } private void openAccessory(UsbAccessory accessory) { mFileDescriptor = mUsbManager.openAccessory(accessory); if (mFileDescriptor != null) { mAccessory = accessory; FileDescriptor fd = mFileDescriptor.getFileDescriptor(); mInputStream = new FileInputStream(fd); mOutputStream = new FileOutputStream(fd); Log.d(TAG, "accessory opened"); } else { Log.d(TAG, "accessory open fail"); } } private void closeAccessory() { try { if (mFileDescriptor != null) { mFileDescriptor.close(); } } catch (IOException e) { } finally { mFileDescriptor = null; mAccessory = null; } } }strings.xml
goes in <ProjectRoot>\res\values\
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">LED On Off (ADK)</string> </resources>main.xml
goes in <ProjectRoot>\res\layout\
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btnOn" android:layout_width="100dp" android:layout_height="wrap_content" android:text="Turn LED On" /> <Button android:id="@+id/btnOff" android:layout_width="100dp" android:layout_height="wrap_content" android:text="Turn LED Off" /> </LinearLayout>accessory_filter.xml
goes in <ProjectRoot>\res\xml\
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory manufacturer="Digitalhack" model="LEDOnOffADK" version="1.0" /> </resources>AndroidManifest.xml
goes in <ProjectRoot>
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.ledonoffadk" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name"> <activity android:name=".LEDOnOffADK" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity> </application> </manifest>Screen Capture from Acer A100
Notes:
- I cannot think how you would get this to work with the emulator so I didn't try.
- This example is built upon the work of others. I post it here not as an example of original work but rather as a complete working example for reference. If I didn't appropriately credit you for your work please let me know and I will add you.