It's another example to implement Bi-directional communication between Android and Arduino in USB Host Mode. A button on Andndroid is used to turn ON/OFF the on-board LED of Arduino Uno, and EditText to send string to Arduino Uno. it will be displayed on connected LCD, and sent back to Android.
Notice:
- Sync word of '0xFF' is used to mark the beginning of data, to sync the communication. Extra in-correct '0x00' received in Android side (I don't know why), so have to ignore it. Make sure the data will not be '0xFF' and '0x00'.
- Command 0x01, 0x02, and 0x03 are used to define LED ON, LED OFF, and string of text.
- Data will lost if sent too fast, so I break the message and insert dummy delay between bytes. (inside method sendArduinoText())
- A USB OTG cable is need to connect to Android side, and a normal USB is used to connect USB OTG cable and Arduino Uno.
Android side:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidusbhostarduino"
android:versionCode="1"
android:versionName="1.0" >
<uses-feature android:name="android.hardware.usb.host" />
<uses-sdk
android:minSdkVersion="12"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".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_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>
</manifest>
/res/xml/device_filter.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- idVendor=2341, idProduct=0043 for Arduino Uno R3 -->
<usb-device
vendor-id="9025"
product-id="0067" />
</resources>
/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:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidusbhostarduino.MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<ToggleButton
android:id="@+id/arduinoled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textOn="ON"
android:textOff="OFF" />
<EditText
android:id="@+id/textout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Send"/>
<TextView
android:id="@+id/textin"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
MainActivity.java
package com.example.androidusbhostarduino;
import java.nio.ByteBuffer;
import android.support.v7.app.ActionBarActivity;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbRequest;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.ToggleButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
public class MainActivity extends ActionBarActivity implements Runnable{
private static final String TAG = "AndroidUsbHostArduino";
private static final byte IGNORE_00 = (byte) 0x00;
private static final byte SYNC_WORD = (byte) 0xFF;
private static final int CMD_LED_OFF = 2;
private static final int CMD_LED_ON = 1;
private static final int CMD_TEXT = 3;
private static final int MAX_TEXT_LENGTH = 16;
ToggleButton buttonLed;
EditText textOut;
Button buttonSend;
TextView textIn;
String stringToRx;
private UsbManager usbManager;
private UsbDevice deviceFound;
private UsbDeviceConnection usbDeviceConnection;
private UsbInterface usbInterfaceFound = null;
private UsbEndpoint endpointOut = null;
private UsbEndpoint endpointIn = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonLed = (ToggleButton)findViewById(R.id.arduinoled);
buttonLed.setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(isChecked){
sendArduinoCommand(CMD_LED_ON);
}else{
sendArduinoCommand(CMD_LED_OFF);
}
}});
textOut = (EditText)findViewById(R.id.textout);
textIn = (TextView)findViewById(R.id.textin);
buttonSend = (Button)findViewById(R.id.send);
buttonSend.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
final String textToSend = textOut.getText().toString();
if(textToSend!=""){
stringToRx = "";
textIn.setText("");
Thread threadsendArduinoText =
new Thread(new Runnable(){
@Override
public void run() {
sendArduinoText(textToSend);
}});
threadsendArduinoText.start();
}
}});
usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
}
@Override
public void onResume() {
super.onResume();
Intent intent = getIntent();
String action = intent.getAction();
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
setDevice(device);
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
if (deviceFound != null && deviceFound.equals(device)) {
setDevice(null);
}
}
}
private void setDevice(UsbDevice device) {
usbInterfaceFound = null;
endpointOut = null;
endpointIn = null;
for (int i = 0; i < device.getInterfaceCount(); i++) {
UsbInterface usbif = device.getInterface(i);
UsbEndpoint tOut = null;
UsbEndpoint tIn = null;
int tEndpointCnt = usbif.getEndpointCount();
if (tEndpointCnt >= 2) {
for (int j = 0; j < tEndpointCnt; j++) {
if (usbif.getEndpoint(j).getType()
== UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (usbif.getEndpoint(j).getDirection()
== UsbConstants.USB_DIR_OUT) {
tOut = usbif.getEndpoint(j);
} else if (usbif.getEndpoint(j).getDirection()
== UsbConstants.USB_DIR_IN) {
tIn = usbif.getEndpoint(j);
}
}
}
if (tOut != null && tIn != null) {
// This interface have both USB_DIR_OUT
// and USB_DIR_IN of USB_ENDPOINT_XFER_BULK
usbInterfaceFound = usbif;
endpointOut = tOut;
endpointIn = tIn;
}
}
}
if (usbInterfaceFound == null) {
return;
}
deviceFound = device;
if (device != null) {
UsbDeviceConnection connection =
usbManager.openDevice(device);
if (connection != null &&
connection.claimInterface(usbInterfaceFound, true)) {
connection.controlTransfer(0x21, 34, 0, 0, null, 0, 0);
connection.controlTransfer(0x21, 32, 0, 0,
new byte[] { (byte) 0x80, 0x25, 0x00,
0x00, 0x00, 0x00, 0x08 },
7, 0);
usbDeviceConnection = connection;
Thread thread = new Thread(this);
thread.start();
} else {
usbDeviceConnection = null;
}
}
}
private void sendArduinoCommand(int control) {
synchronized (this) {
if (usbDeviceConnection != null) {
byte[] message = new byte[2];
message[0] = SYNC_WORD;
message[1] = (byte)control;
usbDeviceConnection.bulkTransfer(endpointOut,
message, message.length, 0);
Log.d(TAG, "sendArduinoCommand: " + String.valueOf(control));
}
}
}
private void sendArduinoText(String s) {
synchronized (this) {
if (usbDeviceConnection != null) {
Log.d(TAG, "sendArduinoText: " + s);
int length = s.length();
if(length>MAX_TEXT_LENGTH){
length = MAX_TEXT_LENGTH;
}
byte[] message = new byte[length + 3];
message[0] = SYNC_WORD;
message[1] = (byte)CMD_TEXT;
message[2] = (byte)length;
s.getBytes(0, length, message, 3);
/*
usbDeviceConnection.bulkTransfer(endpointOut,
message, message.length, 0);
*/
byte[] b = new byte[1];
for(int i=0; i< length+3; i++){
b[0] = message[i];
Log.d(TAG, "sendArduinoTextb[0]: " + b[0]);
usbDeviceConnection.bulkTransfer(endpointOut,
b, 1, 0);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(1);
UsbRequest request = new UsbRequest();
request.initialize(usbDeviceConnection, endpointIn);
while (true) {
request.queue(buffer, 1);
if (usbDeviceConnection.requestWait() == request) {
byte dataRx = buffer.get(0);
Log.d(TAG, "dataRx: " + dataRx);
if(dataRx!=IGNORE_00){
stringToRx += (char)dataRx;
runOnUiThread(new Runnable(){
@Override
public void run() {
textIn.setText(stringToRx);
}});
}
} else {
break;
}
}
}
}
Download the files.
Arduino side:
UsbSlave.ino
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int pinLED = 13;
const int ST_0 = 0; //waiting Sync word
const int ST_1_CMD = 1; //Waiting CMD
const int ST_2_LENGTH= 2;//Receiving Length for CMD_03_TEXT
const int ST_3_DATA= 3; //Receiving Data for CMD_03_TEXT
const byte IGNORE_00 = 0x00;
const byte SYNC_WORD = 0xFF;
const byte CMD_01_LEDON = 0x01;
const byte CMD_02_LEDOFF= 0x02;
const byte CMD_03_TEXT = 0x03;
int cmdState;
int dataIndex;
const int MAX_LENGTH = 16;
byte data[MAX_LENGTH];
int dataLength;
void setup() {
Serial.begin(9600);
pinMode(pinLED, OUTPUT);
digitalWrite(pinLED, LOW);
lcd.begin(16, 2);
lcd.print("USB Host Mode:");
}
void loop() {
if(Serial.available()){
//lcd.setCursor(0, 1);
//lcd.print(" ");
//delay(100);
//lcd.setCursor(0, 1);
while(Serial.available() > 0){
int byteIn = Serial.read();
//Serial.write(byteIn);
//lcd.write(byteIn);
cmdHandle(byteIn);
}
}
}
void cmdHandle(int incomingByte){
//prevent from lost-sync
if(incomingByte == SYNC_WORD){
cmdState = ST_1_CMD;
return;
}
if(incomingByte == IGNORE_00){
return;
}
switch(cmdState){
case ST_1_CMD:{
switch(incomingByte){
case CMD_01_LEDON:
digitalWrite(pinLED, HIGH);
break;
case CMD_02_LEDOFF:
digitalWrite(pinLED, LOW);
break;
case CMD_03_TEXT:
for(int i=0; i < MAX_LENGTH; i++){
data[i] = 0;
}
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
cmdState = ST_2_LENGTH;
dataIndex = 0;
break;
default:
cmdState = ST_0;
}
}
break;
case ST_2_LENGTH:{
dataLength = incomingByte;
if(dataLength > MAX_LENGTH){
dataLength = MAX_LENGTH;
}
cmdState = ST_3_DATA;
}
break;
case ST_3_DATA:{
data[dataIndex] = incomingByte;
dataIndex++;
Serial.write(incomingByte);
lcd.write(incomingByte);
if(dataIndex==dataLength){
cmdState = ST_0;
}
}
break;
}
}
Download
HERE.
Connection of LCD in Arduino Uno:
-
Bi-directional communication between Android and Arduino in USB Host Mode, example 1
-
Bi-directional communication between Android and Arduino in USB Host Mode, example 3 - work with 8x8 LED Matrix
Related:
-
More example of communication between Android to Arduino Uno, in USB Host Mode