【发布时间】:2014-03-31 06:14:39
【问题描述】:
我正在使用各种手机/平板电脑和 Arduino DUE 对 Android 开放附件协议 (AOA) 进行一些实验。
我需要一些帮助来尝试找出导致基于 AOA 的简单应用程序出现不同行为的原因,该应用程序从模拟输入引脚读取数据并更改 Arduino DUE 的数字输出引脚的状态。
我尝试使用该应用程序的所有手机都没有植根,并且我已验证它们都有文件
- /system/framework/com.android.future.usb.accessory.jar
- /system/etc/permissions/android.hardware.usb.accessory.xml
据我所知,只有这两个请求支持 AOA。
指定的应用程序在三星 Galaxy S2(Android 版本 4.1.2,内核 v3.0.31-1211311)和 Galaxy Pocket Neo(Android 版本 4.1.2,内核 v3.0.15-1456085)上运行良好,但也可以运行仅在三星 Galaxy Note 3(Android 版本 4.3,内核 v3.4.0-2019540)上“部分”运行。
更详细地说,当我将配件连接到所有指定的手机(还有 Galaxy Note 3)时,它会被正确识别,并且与 Arduino 草图关联的应用程序会正确控制(所有手机)数字的状态输出引脚,但 Galaxy Note 似乎无法从 Arduino 接收并显示包含模数转换结果的消息(两个字节)。
该应用是UDOO开发平台的教程项目之一,原帖在这里:http://www.udoo.org/ProjectsAndTutorials/android-and-arduino-on-udoo-bidirectional-communication/?portfolioID=1394
这是MainActivity.java的代码:
package org.udoo.androidadkdemobidirect;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.udoo.androidadkdemobidirect.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.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
public class MainActivity extends Activity implements Runnable{
private static final String TAG = "UDOO_AndroidADKFULL";
private static final String ACTION_USB_PERMISSION = "org.udoo.androidadkdemobidirect.action.USB_PERMISSION";
private UsbManager mUsbManager;
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
private Message m;
UsbAccessory mAccessory;
ParcelFileDescriptor mFileDescriptor;
FileInputStream mInputStream;
FileOutputStream mOutputStream;
private static ToggleButton btn_LED = null;
private static TextView tv_adResult = null;
private boolean running = false;
// Receive the USB attached intent
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();
}
}
}
};
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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.activity_main);
btn_LED = (ToggleButton) findViewById(R.id.toggleButtonLED);
tv_adResult = (TextView) findViewById(R.id.adResult);
}
@SuppressWarnings("deprecation")
@Override
public Object onRetainNonConfigurationInstance() {
if (mAccessory != null) {
return mAccessory;
} else {
return super.onRetainNonConfigurationInstance();
}
}
@Override
public void onResume() {
super.onResume();
if (mInputStream != null && mOutputStream != null) {
running = true;
return;
}
//open the accessory from the accessory list
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() {
running = false;
super.onPause();
}
@Override
public void onDestroy() {
running = false;
closeAccessory();
unregisterReceiver(mUsbReceiver);
super.onDestroy();
}
// open the accessory and open the input and output stream from the descriptor
// start also the thread that reads from Arduino
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);
Thread thread = new Thread(this, "UDOO_ADK_readfrom");
running = true;
thread.start();
Toast.makeText(getApplicationContext(), "Accessory connected", Toast.LENGTH_SHORT).show();
Log.i(TAG, "openaccessory");
}
else {
Toast.makeText(getApplicationContext(), "Accessory not connected", Toast.LENGTH_SHORT).show();
}
}
// close the accessory
private void closeAccessory() {
Log.i(TAG, "closeaccessory");
try {
if (mFileDescriptor != null) {
mFileDescriptor.close();
}
} catch (IOException e) {
} finally {
mFileDescriptor = null;
mAccessory = null;
running = false;
}
}
// ToggleButton method - send message to Arduino
public void writeToAccessory(View v){
if (mAccessory != null) {
byte[] message = new byte[1];
message[0] = (byte) (btn_LED.isChecked()?1:0);
if (mOutputStream != null) {
try {
mOutputStream.write(message);
} catch (IOException e) {
Log.e(TAG, "write failed", e);
}
}
}
else
Toast.makeText(getApplicationContext(), "Accessory not connected", Toast.LENGTH_SHORT).show();
}
// Thread to read data from Arduino
public void run() {
int ret = 0;
byte[] buffer = new byte[4];
while (running) {
try {
ret = mInputStream.read(buffer);
} catch (IOException e) {
break;
}
m = Message.obtain(mHandler);
if (ret != 0) {
m.arg1 = (int) ((buffer[0] & 0xff) << 8) + (buffer[1] & 0xff);
ret = 0;
}
mHandler.sendMessage(m);
}
}
static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
final int temp = msg.arg1;
tv_adResult.setText(String.format("%4d (= %.2f V)", temp, 3.3/1024*temp));
}
};
}
我还验证了这种奇怪的行为对于基于 AOA 协议的其他应用程序也存在,即:Galaxy Note 3 正确地将输出消息发送到配件,但没有从中读取输入消息。
我找不到问题出在哪里,我想请 StackOverflow 社区给我一些提示。
任何帮助将不胜感激。
【问题讨论】:
-
您可以尝试从 Arduino 端的 AOA 实现添加一些调试输出,例如通过串行输出发送消息以指示它尝试将数据推送到 Android 设备,然后看看这在设备。您还可以尝试从设备上拉出相关的 jar,反编译它们,然后比较结果。我们的想法是看看您是否可以确定差异的确切来源 - 尽管这可能不会导致解决方法。
-
感谢您的建议;我会尝试应用它们!观察 Arduino 端和 Android 端代码,我发现在 AOA 协议中,通信过程是“开环”的,即 Arduino 在没有任何许可和/或确认的情况下向 Android 设备发送数据,反之亦然。我会尝试在双方之间实现某种数据传输控制机制,试图发现问题出在哪里。
-
我不认为是这种情况 - 实际的 USB 传输通常会得到确认,但可能比您看到的要低。
-
Analyzing Circuit@Home's Usb library for Arduino的代码(在后台用于ADK协议实现)我注意到有可能启用Arduino发送的跟踪模式在 USB 设置过程中以及在与 Android 设备交换消息时会发送大量消息。所以我注意到,只有当我连接 Galaxy Note 3 时,才会出现以下错误:ADK::Init Accessory mode switch attempt : error code: 4294967295 /!\ USBHost::Task : USB_STATE_CONFIGURING failed with code: 4294967295
-
现在我“只能”找到意义和原因了……
标签: android samsung-mobile android-open-accessory