2
votes

I'm trying to communicate between Arduino Mega Adk (ADK 2011) and android device. Something goes ok, but something goes completely wrong. Transfer data from Android to Arduino via acc.read from Arduino side works fine. But when i try to send some bytes from Arduino to Android - something strange happens. First of all here is Arduino sketch:

    #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);
      }
    }

Ok. When acc.write() is executed it takes up to ~1 second to transfer data to android. And this time doesn't depend on number of bytes in sndmsg. Only if i execute acc.write(sndmsg,0) (sending 0 bytes) - everything goes fast. That is a little bit disturbing. I've tried to change board to another one but have got the same result. Any advices? may be that is a common bug, but there is no such much information in web.

UPD: Wrote some very simple code, that only sends 3 bytes via acc.write. here it is:

#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);
  }
}

And it's debug output is:

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

and so on. So on some reasons acc.write takes a lot of time and there is no data in the android app.

New UPD (19.01.2015):

Today i've performed some experiments. Here are results. First, i've looked into AndroidAccessory.cpp and found write function:

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

Ok, then i looked into usb host shield library and found there usb.cpp with outTransfer fucntion, that returns error code if ouccured and 0x00 if everything is ok. So i modified write function to return an error code instead of lenght, like this:

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

and recived "4" as result. According to MAX3421Econstants.h it is hrNAK (0x04) error code. Any ideas? Looks like accessory does not recive NAKs from Android and write fails as a result.

Situation update: Did some research. There is a hell of NAK's when accessory is connected. Here is dump from usb connector: enter image description here

1
Might be the isConnected handshake that's taking the second. Do the isconnected out side of the loop light up a button if it's connected. Then drop into the processing loop. Then go for the buttons. My arduino is on the way from Hong Kong expected deliver Jan 9th to Jan 23rd. I can't wait.danny117
isConnected doesn't take a lot of time after powerOn ends successfully. If i comment acc.write lines - everything goes fast and smooth - even reading from android and acting on (this code isn't in this example but ot works).mikebutrimov
I've changes test code to very very simple one and add some debug timing. I'll update post to add new data.mikebutrimov
How are you connecting the android? I'll probably have to buy another shield to connect my arduino to a mobile device and then I'll be able to help. FYI my arduino ultimate starter kit should arrive in a few days the tracking has it in my home state.danny117
@danny117 i have two boards - fork of arduino mega adk calld iteaduino and an original Arduino Mega ADK board by arduino.cc Same behavior on both of them. From android side i'm using code, that is based on this article: developer.android.com/guide/topics/connectivity/usb/… transfering from android to arduino is ok, but from arduino to android - isn't. Is it possible, that adk acc.write function waits for something special from android side? because i think it just writes some bytes to the usb and doesn't wait for any response. Am i right or it's a mistake?mikebutrimov

1 Answers

0
votes

i found the solution. And it is very simple - i didn't setup communication with accessory correctly. This is not an Arduino problem. Arduino works fine. It is just how android interacts with android accessory. So, results:

  • When AndroidAccessory is plugged to Android and Android haven't setup communication with the accessory yet, Android OS will send a lot of USB NAKs to the accessory and this is normal.
  • You must be careful during setuping communication with the accessory. If you make some mistakes, you can receive same situation: Probably possible to write to the accessory, but accessory isn't possible to write to the android.
  • If UsbManager opens accessory correctly, it stops sending NAKs and starts recieve data from arduino.

It is a little bit strange for me, because it was really hard to found a problem: i have an application, written according to this manual: http://developer.android.com/guide/topics/connectivity/usb/accessory.html But, because i'm not very familiar with android, it seems that i've done some mistakes and receive strange behavior:

  • i was able to write to arduino
  • i was able to retrive information about arduino as android accessory
  • it was possible to ask for permissions
  • but when arduino tries to write to android, it recievs a lot of NAKs

So i decided to rewrite program in more simple way, just with one function and tried to do it in right way. And after some debugging it finally started to work as i want. So thank everyone, who spend time for reading this. Bonus: dump of normal packet, ended with EOP not NAK enter image description here

UPD 26.01.2015: I found problem and it was in my android code. here is explanation:

Android developer's manual said that function, which set up communication with accessory must start it's own thread in which all communications with input and output streams are held. Smth like this:

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();
    }
}

I really messed this thing up. Forgot about creating new thread in openAccessory function and tried to do it in different place. And recieve a hell of NAK's. Then i've changed my code and add some debug-like run() function like this:

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();
            }
        }
    }

And until this run method exists (while i < 50) android reads arduino correctly. And when thread ends up (i > 50) - Arduino starts to readout Error Code 4 (NAK) from Android.

That's all folks.