Sunday, March 31, 2013

Android code sending command to Arduino Due to turn LED On/Off

It's the coding in Android side to send command to Arduino Due to control LED On/Off.


Modify AndroidManifest.xml to add <uses-feature> of "android.hardware.usb.accessory", <intent-filter> of "android.hardware.usb.action.USB_ACCESSORY_ATTACHED", and <meta-data> of resource="@xml/myfilter".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidadkled"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="12"
        android:targetSdkVersion="17" />

    <uses-feature android:name="android.hardware.usb.accessory"/>
    
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androidadkled.MainActivity"
            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/myfilter"/>
        </activity>
    </application>

</manifest>


Create file /res/xml/myfilter.xml
<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <usb-accessory
        manufacturer="Arduino-er"
        model="HelloADKLED"
        version="0.1"/>
</resources>


Layout file, /res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Arduino LED Control" />
    <TextView
        android:id="@+id/textin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <RadioGroup
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <RadioButton
            android:id="@+id/LedOn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="LED On" />
        <RadioButton
            android:id="@+id/LedOff"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="LED Off" />
    </RadioGroup>

</LinearLayout>


Create a abstract class AbstractAdkActivity.java to extend Activity, implement the function of ADK; such that we can easy re-use it in furture and reduce the ADK related job in MainActivity.java.
/*
 * abstract class for Activities have to read ADK
 * for android:minSdkVersion="12"
 * 
 */

package com.example.androidadkled;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

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.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;

public abstract class AbstractAdkActivity extends Activity {
 
 private static int RQS_USB_PERMISSION = 0;
 private static final String ACTION_USB_PERMISSION = "arduino-er.usb_permission";
 private PendingIntent PendingIntent_UsbPermission;
 
 private UsbManager myUsbManager;
 private UsbAccessory myUsbAccessory;
 private ParcelFileDescriptor myAdkParcelFileDescriptor;
 private FileInputStream myAdkInputStream;
 private FileOutputStream myAdkOutputStream;
 boolean firstRqsPermission;

 //do something in onCreate()
 protected abstract void doOnCreate(Bundle savedInstanceState);
 //do something after adk read
 protected abstract void doAdkRead(String stringIn); 
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  //setContentView(R.layout.activity_main);
  
  myUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
  IntentFilter intentFilter = new IntentFilter();
  intentFilter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
  registerReceiver(myUsbReceiver, intentFilter);
  
  //Ask USB Permission from user
  Intent intent_UsbPermission = new Intent(ACTION_USB_PERMISSION);
  PendingIntent_UsbPermission = PendingIntent.getBroadcast(
    this,      //context
    RQS_USB_PERMISSION,  //request code
    intent_UsbPermission, //intent 
    0);      //flags
  IntentFilter intentFilter_UsbPermission = new IntentFilter(ACTION_USB_PERMISSION);
  registerReceiver(myUsbPermissionReceiver, intentFilter_UsbPermission);
  
  firstRqsPermission = true;
  doOnCreate(savedInstanceState);
 }
 
 @Override
 protected void onResume() {
  super.onResume();
  
  if(myAdkInputStream == null || myAdkOutputStream == null){
   
   UsbAccessory[] usbAccessoryList = myUsbManager.getAccessoryList();
   UsbAccessory usbAccessory = null;
   if(usbAccessoryList != null){
    usbAccessory = usbAccessoryList[0];
    
    if(usbAccessory != null){
     if(myUsbManager.hasPermission(usbAccessory)){
      //already have permission
      OpenUsbAccessory(usbAccessory);
     }else{
      
      if(firstRqsPermission){
       
       firstRqsPermission = false;
       
       synchronized(myUsbReceiver){
        myUsbManager.requestPermission(usbAccessory, 
          PendingIntent_UsbPermission);
       }
      }
      
     }
    }
   }
  }
 }
 
 //Write String to Adk
 void WriteAdk(String text){

  byte[] buffer = text.getBytes();

  if(myAdkOutputStream != null){
   
   try {
    myAdkOutputStream.write(buffer);
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } 
  }
 }
 
 @Override
 protected void onPause() {
  super.onPause();
  closeUsbAccessory();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  unregisterReceiver(myUsbReceiver);
  unregisterReceiver(myUsbPermissionReceiver);
 }
 
 Runnable runnableReadAdk = new Runnable(){

  @Override
  public void run() {
   int numberOfByteRead = 0;
   byte[] buffer = new byte[255];
   
   while(numberOfByteRead >= 0){
    
    try {
     numberOfByteRead = myAdkInputStream.read(buffer, 0, buffer.length);
     final StringBuilder stringBuilder = new StringBuilder();
     for(int i=0; i<numberOfByteRead; i++){
      stringBuilder.append((char)buffer[i]);
     }
     
     runOnUiThread(new Runnable(){

      @Override
      public void run() {
       doAdkRead(stringBuilder.toString());
      }});
     
     
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     break;
    }
   }
  }
  
 };
 
 private BroadcastReceiver myUsbReceiver = new BroadcastReceiver(){
  
  @Override
  public void onReceive(Context context, Intent intent) {

   String action = intent.getAction();
   if(action.equals(UsbManager.ACTION_USB_ACCESSORY_DETACHED)){

    UsbAccessory usbAccessory = 
      (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
    
    if(usbAccessory!=null && usbAccessory.equals(myUsbAccessory)){
     closeUsbAccessory();
    }
   }
  }
 };
 
 private BroadcastReceiver myUsbPermissionReceiver = new BroadcastReceiver(){

  @Override
  public void onReceive(Context context, Intent intent) {
   String action = intent.getAction();
   if(action.equals(ACTION_USB_PERMISSION)){

    synchronized(this){
     
     UsbAccessory usbAccessory = 
       (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
     
     if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)){
      OpenUsbAccessory(usbAccessory);
     }else{
      finish();
     }
    }
   }
  }
  
 };
 
 private void OpenUsbAccessory(UsbAccessory acc){
  myAdkParcelFileDescriptor = myUsbManager.openAccessory(acc);
  if(myAdkParcelFileDescriptor != null){
   
   myUsbAccessory = acc;
   FileDescriptor fileDescriptor = myAdkParcelFileDescriptor.getFileDescriptor();
   myAdkInputStream = new FileInputStream(fileDescriptor);
   myAdkOutputStream = new FileOutputStream(fileDescriptor);
   
   Thread thread = new Thread(runnableReadAdk);
   thread.start();
  }
 }
 
 private void closeUsbAccessory(){
  
  if(myAdkParcelFileDescriptor != null){
   try {
    myAdkParcelFileDescriptor.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  
  myAdkParcelFileDescriptor = null;
  myUsbAccessory = null;
 }
}


Modify MainActivity.java to extend AbstractAdkActivity, and extend Activity in-turn. With AbstractAdkActivity handle most of the ADK related job, we only have to override the methods doOnCreate()(called in onCreate() method) and doAdkRead()(called after command read from ADK). To send command to ADK, call WriteAdk() method.
package com.example.androidadkled;

import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AbstractAdkActivity {
 
 TextView textIn;
 RadioButton ledOn, ledOff;

 @Override
 protected void doOnCreate(Bundle savedInstanceState) {
  setContentView(R.layout.activity_main);
  textIn = (TextView)findViewById(R.id.textin);
  ledOn = (RadioButton)findViewById(R.id.LedOn);
  ledOff = (RadioButton)findViewById(R.id.LedOff);
  
  ledOn.setOnCheckedChangeListener(new OnCheckedChangeListener(){

   @Override
   public void onCheckedChanged(CompoundButton buttonView,
     boolean isChecked) {
    if(isChecked){
     WriteAdk("LEDON");
     Toast.makeText(getApplicationContext(), 
       "LEDON", Toast.LENGTH_LONG).show();
    }
   }});
  
  ledOff.setOnCheckedChangeListener(new OnCheckedChangeListener(){

   @Override
   public void onCheckedChanged(CompoundButton buttonView,
     boolean isChecked) {
    if(isChecked){
     WriteAdk("LEDOFF");
     Toast.makeText(getApplicationContext(), 
       "LEDOFF", Toast.LENGTH_SHORT).show();
    }
   }});

 }

 @Override
 protected void doAdkRead(String stringIn) {
  textIn.setText(stringIn);
 }

}


download filesDownload the files.

Refer the another post for the code in Arduino Due side.


Updated@2015-10-15Android control Arduino Due LED, using ADK (Accessory Development Kit)

7 comments:

  1. Hi.I simply wonder about that: What does your android app send to usb?String, char?I want to use your on-off interface and just using serial read in arduino

    ReplyDelete
  2. Hi,
    Whow!

    I'm new to the arduino & android world, but that's what i'm looking for (sort of :-) )
    I am making a high-end chronometer for a dogsport called flyball, and i would love to get the chrono results (through USB cable) on a low cost android tablet (USB host capable) as output to the refereés of the game.

    I use an MEGA 2560 ADK to control and check the sensors, would it be possible to get the data on the tablet?

    How do I begin to program such interface?
    I need a few inputs to come on the tablet:

    for example:

    "Dog1 : " +time the dog was on the track + "Crossing" + time the next dog needed to pass the previous dog.
    and so on for the four dogs

    is there a sort of GUI for that sort of programing that i can use?

    Grtz
    Yves

    ReplyDelete
  3. If the screen rotates, someone hits back, the screen locks, etc, when the app restarts the app stops to communicate with the board. So I have to unplug the USB before the connection can be made again.
    Do you know how to fix it?
    Thanks! :D

    ReplyDelete
  4. Yes, it may be the most headache problem for me, when configuration change and the app re-create!

    Maybe you can force the app run in one orientation only.

    ReplyDelete
  5. Hi! I have been trying to do what you are doing with your example here for some time now. I have not been able to get communication going, even with a copy paste of your code. The android app always freezes about 3-5 seconds after i try to send something. Do you have any idea why this could happen?

    ReplyDelete
    Replies
    1. I re-build the example again on Android Studio, http://arduino-er.blogspot.com/2015/10/android-control-arduino-due-led-using.html

      With APK, you can try it.

      May be not all android devices support ADK.

      Delete