Arduino Mega ADK 奇怪的 acc.write() 行为(巨大的延迟)NAK 问题似乎得到证实。 Android 生成 NAK 作为 acc.write 的结果

Arduino Mega ADK strange acc.write() behavior (huge delay) NAK issue seemd to be confirmed. Android generates NAK's as a result of acc.write

我正在尝试在 Arduino Mega Adk (ADK 2011) 和 android 设备之间进行通信。 事情进展顺利,但事情完全错了。 通过 acc.read 从 Arduino 端将数据从 Android 传输到 Arduino 工作正常。 但是当我尝试将一些字节从 Arduino 发送到 Android 时 - 发生了一些奇怪的事情。 首先是 Arduino 草图:

    #include <Max3421e_constants.h>
    #include <Max3421e.h>
    #include <Usb.h>
    #include <AndroidAccessory.h>

    #define COMMAND_LED 0x2
    #define TARGET_PIN_18 0x12
    #define TARGET_PIN_19 0x13
    #define V_ON 0x1
    #define V_OFF 0x0

    #define PIN_18 18
    #define PIN_19 19
    #define INPUT_PIN 30


    AndroidAccessory acc("Google, Inc.",
                 "DemoKit",
                 "Ololo device board",
                 "1.0",
                 "http://www.android.com",
                 "0000000012345678");

    byte rcvmsg[3];
    byte sndmsg[3];
    int buttonState = 0;

    void setup();
    void loop();

    void led_setup(){
      pinMode(PIN_18, OUTPUT);     
      pinMode(PIN_19, OUTPUT);
      pinMode(INPUT_PIN, INPUT);
    }
    void setup()
    {
      Serial.begin(115200);
      Serial.print("\r\nStart");
      led_setup();
      acc.powerOn();
    }
    void loop()
    {
      if (acc.isConnected()) {
     buttonState = digitalRead(INPUT_PIN);
      if (buttonState == 1){
       sndmsg[0] = 0x2;
       sndmsg[1] = 0x1;
       sndmsg[2] = 0x1;
       int len = acc.write(sndmsg, 3);
       digitalWrite(PIN_19, HIGH);
      }
      else {
       //Nothing here for test
      }  
    }
  //usefull test for button  
     buttonState = digitalRead(INPUT_PIN);
     if (buttonState == 1){
       digitalWrite(PIN_19, HIGH);
      }
      else {
        digitalWrite(PIN_19, LOW);
      }
    }

好的。当执行 acc.write() 时,最多需要约 1 秒的时间将数据传输到 android。而这个时间不依赖于 sndmsg 中的字节数。仅当我执行 acc.write(sndmsg,0)(发送 0 个字节)时 - 一切都很快。 这有点令人不安。我试图将电路板换成另一个,但得到了相同的结果。 有什么建议吗?可能这是一个常见的错误,但网络上没有这么多信息。

更新: 写了一些非常简单的代码,只通过 acc.write 发送 3 个字节。 这里是:

#include <Max3421e_constants.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>

AndroidAccessory acc("Google, Inc.",
             "DemoKit",
             "Demokit board",
             "1.0",
             "http://www.android.com",
             "0000000012345678");


byte msg[3];
unsigned long time;
void setup();
void loop();
void led_setup(){
}
void setup()
{
  Serial.begin(115200);
  Serial.print("\r\nStart");
  acc.powerOn();
}
void loop()
{
  if (acc.isConnected()) {
   Serial.print("\r\nis Connected");
   msg[0] = 0x1;
   msg[1] = 0x1;
   msg[2] = 0x1;
   //Serial.print("\r\nSending");
   time = millis();
   Serial.print ("\r\nBefore write\r\n");
   Serial.print (time);
   acc.write(msg, 3);
   time = millis();
   Serial.print("\r\nAfter write: \r\n");
   Serial.print (time);
   //delay(500);
  }
}

它的调试输出是:

is Connected
Before write
6983
After write: 
10958
is Connected
Before write
10958
After write: 
14491
is Connected

等等。所以由于某些原因 acc.write 需要很多时间并且 android 应用程序中没有数据。

新更新 (19.01.2015):

今天我做了一些实验。这是结果。 首先,我查看了 AndroidAccessory.cpp 并找到了写入函数:

 int AndroidAccessory::write(void *buff, int len)
    {
        usb.outTransfer(1, out, len, (char *)buff);
        return len;
    }

好的,然后我查看了 usb host shield 库,发现 usb.cpp 具有 outTransfer 功能,如果出现 returns 错误代码,如果一切正常则为 0x00。 所以我将写入函数修改为 return 错误代码而不是长度,如下所示:

int AndroidAccessory::write(void *buff, int len)
{
    byte rcode;
    rcode =  usb.outTransfer(1, out, len, (char *)buff);
    return int(rcode);
}

结果收到“4”。 根据 MAX3421Econstants.h 是 hrNAK (0x04) 错误代码。 有任何想法吗?看起来 accessory 没有从 Android 接收到 NAK,因此写入失败。

情况更新: 做了一些研究。连接附件时会出现大量 NAK。这是来自 USB 连接器的转储:

我找到了解决方案。而且非常简单——我没有正确设置与附件的通信。 这不是 Arduino 的问题。阿杜诺工作正常。 这就是 android 与 android 配件的交互方式。 所以,结果:

  • 当 Android附件插入 Android 并且 Android 还没有设置 还没有和附件通信,AndroidOS会发很多 USB NAKs 到配件,这是正常的。
  • 你一定要小心 在设置与附件的通信期间。如果你做一些 错误,你会收到同样的情况:可能会写 附件,但附件无法写入 android。
  • 如果 UsbManager 正确打开配件,它会停止发送 NAKs 并开始从 arduino 接收数据。

对我来说有点奇怪,因为真的很难找到问题:我有一个应用程序,根据这个手册写的:http://developer.android.com/guide/topics/connectivity/usb/accessory.html但是,因为我不是很熟悉android,看来我犯了一些错误并收到奇怪的行为:

  • 我能写信给arduino
  • 我能够检索有关 arduino 的信息作为 android 附件
  • 可以请求权限
  • 但是当 arduino 尝试写入 android 时,它会收到很多 NAK

所以我决定用更简单的方式重写程序,只用一个函数,并尝试以正确的方式完成。经过一些调试,它终于开始按我的意愿工作了。 感谢大家花时间阅读本文。 奖励:正常数据包的转储,以 EOP 而不是 NAK 结束

UPD 26.01.2015: 我发现了问题,它在我的 android 代码中。 这是解释:

Android 开发人员手册说,与附件建立通信的函数必须启动它自己的线程,在该线程中保存与输入和输出流的所有通信。像这样:

private void openAccessory() {
    Log.d(TAG, "openAccessory: " + accessory);
    mFileDescriptor = mUsbManager.openAccessory(mAccessory);
    if (mFileDescriptor != null) {
        FileDescriptor fd = mFileDescriptor.getFileDescriptor();
        mInputStream = new FileInputStream(fd);
        mOutputStream = new FileOutputStream(fd);
        Thread thread = new Thread(null, this, "AccessoryThread");
        thread.start();
    }
}

我真的把这件事搞砸了。忘记在 openAccessory 函数中创建新线程并尝试在不同的地方创建它。并收到大量的 NAK。然后我更改了代码并添加了一些 debug-like 运行() 函数,如下所示:

public void run() {
        final byte[] buffer = new byte[16384];
        int ret = 0;
        int i = 0;
        while (i<50) {
            try {
                ret = mInputStream.read(buffer);
                i++;
                Thread.sleep(500);
            } catch (IOException e) {
                break;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

直到这个运行方法存在(当我<50)android正确读取arduino。当线程结束时 (i > 50) - Arduino 开始从 Android 读出错误代码 4 (NAK)。

这就是所有人。