Tuesday, May 29, 2012

Arduino to Android – Turning an LED On and Off using ADK and the Circuits@Home USB Shield

This is the same example conceptually as the previous post Arduino to Android – Turning an LED On and Off except that it uses the Android Open Accessory Development Kit (ADK) and a USB connection via a Circuits@Home USB Shield rather than bluetooth to communicate between the Android tablet and the Arduino.

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:

  1. A breadboard Arduino with a Sparkfun FTDI 3.3v board.
  2. An Acer Iconia Tab A100 running Ice Cream Sandwich 4.0.3.
  3. A Circuits@Home USB Host Shield for Arduino Pro Mini.
  4. A red LED. Connected to the Arduino on digital pin 8.
  5. A 470 ohm resistor connecting the LED to ground.

The picture below shows how the hardware is setup.

ADKSetup
The USB shield was wired to the Arduino as shown in the diagram below.

uhm11_manual
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.

Ardunio Sketch
#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

LEDOnOffADK

Notes:

  1. I cannot think how you would get this to work with the emulator so I didn't try.
  2. 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.

1 comment:

AmolSawant said...

hello, great post..
i stuck in one problem when i am connecting my android phone with arduino LED on-off not working through Android phone. i checked in serial monitor is only showing
Waiting for adk. how to solve the problem.
Please help me.
Thank you in Advance.