Few weeks ago I wrote my first Android Jelly Bean App named
ColorChanger. Since then I wanted to integrate it with Arduino and Control a physical RGB LED Light from the ColorChanger Android App. I finally managed to get it done using the following Items.
- Arduino Mega 2560 Rev 3
- DFRobot USB Host Shield
- Arduino IDE 0023
- ADK Library
- 1 RGB LED
- 1 1k Resistor
- Few Jumper Cables
- One USB to Micro USB Cable
Few things changed from the original ColorChanger App starting from the AndroidManifest.xml where I had to allow my MainActivity to listen for USB_ACCESSORY_ATTACHED intent action and when my Accessory connects open the ColorChanger App.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.shazin.colorchanger"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.shazin.colorchanger.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/accessory_filter" />
</activity>
</application>
</manifest>
The filtering criteria is placed in res/xml/accessory_filter.xml file which is as follows
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-accessory model="ColorChangerApp" manufacturer="Shazin Sadakath" version="1.0"/>
</resources>
Then my MainActivity class changed as follows
package com.shazin.colorchanger;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import android.annotation.SuppressLint;
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.graphics.Color;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.view.Menu;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnSeekBarChangeListener, Runnable {
private TextView textViewColor;
private SeekBar seekBarRed;
private SeekBar seekBarGreen;
private SeekBar seekBarBlue;
private byte red, green, blue;
private LinearLayout linearLayout;
private UsbAccessory mAccessory;
private ParcelFileDescriptor mFileDescriptor;
private FileInputStream mInputStream;
private FileOutputStream mOutputStream;
private UsbManager mUsbManager;
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
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)) {
if(accessory != null){
//call method to set up accessory communication
openAccessory();
}
}
else {
//Log.d(TAG, "permission denied for accessory " + accessory);
Toast.makeText(context, "permission denied for accessory "+accessory, 2).show();
}
}
unregisterReceiver(mUsbReceiver);
}
}
};
public final BroadcastReceiver mUsbDetachReciever = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (accessory != null) {
cleanUp();
}
unregisterReceiver(mUsbDetachReciever);
}
}
};
private boolean mPermissionRequestPending;
private void cleanUp() {
try {
if(mFileDescriptor != null)
mFileDescriptor.close();
if(mInputStream != null)
mInputStream.close();
if(mOutputStream != null)
mOutputStream.close();
mAccessory = null;
mUsbManager = null;
Toast.makeText(this, "Closed all resources", 2).show();
} catch (IOException e) {
Toast.makeText(this, "Error occured "+e, 2).show();
}
}
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linearLayout = (LinearLayout) findViewById(R.id.linearLayout);
textViewColor = (TextView) findViewById(R.id.textViewColor);
seekBarRed = (SeekBar) findViewById(R.id.seekBarRed);
seekBarGreen = (SeekBar) findViewById(R.id.seekBarGreen);
seekBarBlue = (SeekBar) findViewById(R.id.seekBarBlue);
seekBarBlue.setOnSeekBarChangeListener(this);
seekBarGreen.setOnSeekBarChangeListener(this);
seekBarRed.setOnSeekBarChangeListener(this);
textViewColor.setText(String.format("(%d, %d, %d)", red, green, blue));
linearLayout.setBackgroundColor(Color.rgb(red, green, blue));
mAccessory = (UsbAccessory) getIntent().getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
Toast.makeText(this, "USB Accessory = "+mAccessory, 2).show();
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
Toast.makeText(this, "USB Manager = "+mUsbManager, 2).show();
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
Toast.makeText(this, "Intent Registered", 2).show();
if(mUsbManager.hasPermission(mAccessory)) {
Toast.makeText(this, "Accessory has permission", 2).show();
unregisterReceiver(mUsbReceiver);
openAccessory();
} else {
Toast.makeText(this, "Accessory has no permission", 2).show();
synchronized (mUsbReceiver) {
if (!mPermissionRequestPending) {
mUsbManager.requestPermission(mAccessory, mPermissionIntent);
Toast.makeText(this, "Permission Request Sent", 2).show();
mPermissionRequestPending = true;
}
}
}
IntentFilter filter2 = new IntentFilter(ACTION_USB_PERMISSION);
filter2.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(mUsbDetachReciever, filter2);
}
public void onDestroy() {
super.onDestroy();
cleanUp();
}
@SuppressLint("NewApi")
private void openAccessory() {
//Log.d(TAG, "openAccessory: " + accessory);
mFileDescriptor = mUsbManager.openAccessory(mAccessory);
Toast.makeText(this, "Accessory Opened", 2).show();
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
Toast.makeText(this, "File Desc "+fd, 2).show();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onProgressChanged(SeekBar seekBar, int value, boolean flag) {
if(seekBar == seekBarRed) {
red = (byte) value;
} else if(seekBar == seekBarGreen) {
green = (byte) value;
} else if(seekBar == seekBarBlue) {
blue = (byte) value;
}
linearLayout.setBackgroundColor(Color.rgb(red & 0xFF, green & 0xFF, blue & 0xFF));
textViewColor.setText(String.format("(%d, %d, %d)", red & 0xFF, green & 0xFF, blue & 0xFF));
if(mOutputStream != null) {
try {
byte[] data = new byte[4];
data[0] = 0x2;
data[1] = red;
data[2] = green;
data[3] = blue;
mOutputStream.write(data);
mOutputStream.flush();
} catch (IOException e) {
Toast.makeText(this, "Error "+e, 2).show();
}
}
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
}
@Override
public void onStopTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
}
@Override
public void run() {
}
}
And the Arduino Sketch is as follows
#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>
// For Arduino IDE 1.0.x Only following two is needed
#include <adk.h>
#include <usbhub.h>
USB Usb;
USBHub hub0(&Usb);
USBHub hub1(&Usb);
ADK adk(&Usb,"Shazin Sadakath",
"ColorChangerApp", // This name Should match with xml/res/accessory_filter.xml name
"Color Changer App",
"1.0",
"http://shazsterblog.blogspot.com",
"0000000012345678");
#define LED1_RED 5
#define LED1_GREEN 4
#define LED1_BLUE 3
void setup();
void loop();
void init_leds()
{
digitalWrite(LED1_RED, 0);
digitalWrite(LED1_GREEN, 0);
digitalWrite(LED1_BLUE, 0);
pinMode(LED1_RED, OUTPUT);
pinMode(LED1_GREEN, OUTPUT);
pinMode(LED1_BLUE, OUTPUT);
}
void setup()
{
Serial.begin(115200);
Serial.println("\r\nADK demo start");
if (Usb.Init() == -1) {
Serial.println("OSCOKIRQ failed to assert");
while(1); //halt
}//if (Usb.Init() == -1...
init_leds();
}
void loop()
{
uint8_t rcode;
uint8_t msg[4] = { 0x00 };
Usb.Task();
if( adk.isReady() == false ) {
analogWrite(LED1_RED, 255);
return;
}
uint16_t len = sizeof(msg);
rcode = adk.RcvData(&len, msg);
if( rcode ) {
USBTRACE2("Data rcv. :", rcode );
}
if(len > 0) {
if(msg[0] == 0x2) {
USBTRACE("\r\nData Packet.");
uint8_t r = (msg[1]) & 0xFF;
uint8_t g = (msg[2]) & 0xFF;
uint8_t b = (msg[3]) & 0xFF;
analogWrite(LED1_RED, 255 - r);
analogWrite(LED1_GREEN, 255 - g);
analogWrite(LED1_BLUE, 255 - b);
}
}
msg[0] = 0x1;
delay( 10 );
}
The video of the whole thing working together is available below.
References