title: Android ADK with PC as USB Host with libusb, bulk transfer error
body: <p>I'm trying to make my PC the USB Host for Android 2.3.4 devices in order to be able to develop APIs without needing actual "accessories".  To do this, I need to establish the PC as the USB Host and the "device" (in my case a Nexus One running 2.3.4).</p>
  
  <p>I started with libusb code from <a href="http://android.serverbox.ch/">http://android.serverbox.ch/</a> as a base for the PC side and the DemoKit code and Android documentation on the Android side.</p>
  
  <p>The two seems to negotiate the connection fine, and the interface gets "claimed" but dies on the actual attempt at bulk transfer.  On OSX, the error is -5 (LIBUSB_ERROR_NOT_FOUND) and on Ubuntu Linux (as root) the error is -1 (LIBUSB_ERROR_IO).  (Most recent releases of each with most recent libusb 1.0.8).</p>
  
  <p>Here's the code.  Other comments on problems welcome, though this is mostly a proof-of-concept, so I'm really just looking for the reason the bulk transfer isn't working:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;libusb.h&gt;
  #include &lt;string.h&gt;
  
  #define ENDPOINT_BULK_IN 0x83
  #define ENDPOINT_BULK_OUT 0x03 // Have tried 0x00, 0x01 and 0x02
  
  #define VID 0x18D1
  #define PID 0x4E11
  
  #define ACCESSORY_PID 0x2D00
  #define ACCESSORY_ADB_PID 0x2D01 // Can't get this to work, if ADB is active, can't get handle on device
  
  /*
  ON OSX
  gcc adktest.c -I/usr/local/include -o adktest -lusb-1.0.0 -I/usr/local/include -I/usr/local/include/libusb-1.0
  ON UBUNTU
  gcc adktest.c -I/usr/include -o adktest -lusb-1.0 -I/usr/include -I/usr/include/libusb-1.0
  
  Testing on Nexus One with Gingerbread 2.3.4
  */
  
  static int transferTest();
  static int init(void);
  static int shutdown(void);
  static void error(int code);
  static void status(int code);
  static int setupAccessory(
  const char* manufacturer,
  const char* modelName,
  const char* description,
  const char* version,
  const char* uri,
  const char* serialNumber);
  
  //static
  static struct libusb_device_handle* handle;
  
  int main (int argc, char *argv[]){
  if(init() &lt; 0)
      return;
  
  if(setupAccessory(
      "PCHost",
      "PCHost1",
      "Description",
      "1.0",
      "http://www.mycompany.com",
      "SerialNumber") &lt; 0){
      fprintf(stdout, "Error setting up accessory\n");
      shutdown();
      return -1;
  };
  if(transferTest() &lt; 0){
      fprintf(stdout, "Error in transferTest\n");
      shutdown();
      return -1;
  }   
  shutdown();
  fprintf(stdout, "Finished\n");
  return 0;
  }
  
  static int transferTest(){
    // TEST BULK IN/OUT
    const static int PACKET_BULK_LEN=64;
    const static int TIMEOUT=5000;
    int r,i;
    int transferred;
    char answer[PACKET_BULK_LEN];
    char question[PACKET_BULK_LEN];
    for (i=0;i&lt;PACKET_BULK_LEN; i++) question[i]=i;
  
      // ***FAILS HERE***
      r = libusb_bulk_transfer(handle, ENDPOINT_BULK_OUT, question, PACKET_BULK_LEN,
                               &amp;transferred,TIMEOUT);
      if (r &lt; 0) {
          fprintf(stderr, "Bulk write error %d\n", r);
          error(r);
          return r;
      }
      fprintf(stdout, "Wrote %d bytes", r);
  
      r = libusb_bulk_transfer(handle, ENDPOINT_BULK_IN, answer,PACKET_BULK_LEN,
                               &amp;transferred, TIMEOUT);
      if (r &lt; 0) {
          fprintf(stderr, "Bulk read error %d\n", r);
          error(r);
          return r;
      }
      fprintf(stdout, "Read %d bytes", r);
  
      if (transferred &lt; PACKET_BULK_LEN) {
          fprintf(stderr, "Bulk transfer short read (%d)\n", r);
          error(r);
          return -1;
      }
      printf("Bulk Transfer Loop Test Result:\n");
      //     for (i=0;i&lt; PACKET_BULK_LEN;i++) printf("%i, %i,\n ",question[i],answer[i]);
      for(i = 0;i &lt; PACKET_BULK_LEN; i++) {
          if(i%8 == 0)
              printf("\n");
          printf("%02x, %02x; ",question[i],answer[i]);
      }
      printf("\n\n");
  
      return 0;
  
  }
  
  
  static int init(){
  libusb_init(NULL);
  if((handle = libusb_open_device_with_vid_pid(NULL, VID, PID)) == NULL){
      fprintf(stdout, "Problem acquiring handle\n");
      return -1;
  }
  libusb_claim_interface(handle, 0);  
  
  return 0;
  }
  
  static int shutdown(){
  if(handle != NULL)
      libusb_release_interface (handle, 0);
  libusb_exit(NULL);
  return 0;
  }
  
  static int setupAccessory(
  const char* manufacturer,
  const char* modelName,
  const char* description,
  const char* version,
  const char* uri,
  const char* serialNumber){
  
  unsigned char ioBuffer[2];
  int devVersion;
  int response;
  
  response = libusb_control_transfer(
      handle, //handle
      0xC0, //bmRequestType
      51, //bRequest
      0, //wValue
      0, //wIndex
      ioBuffer, //data
      2, //wLength
      0 //timeout
  );
  
  if(response &lt; 0){error(response);return-1;}
  
  devVersion = ioBuffer[1] &lt;&lt; 8 | ioBuffer[0];
  fprintf(stdout,"Version Code Device: %d\n", devVersion);
  
  usleep(1000);//sometimes hangs on the next transfer :(
  
  response = libusb_control_transfer(handle,0x40,52,0,0,(char*)manufacturer,strlen(manufacturer),0);
  if(response &lt; 0){error(response);return -1;}
  response = libusb_control_transfer(handle,0x40,52,0,1,(char*)modelName,strlen(modelName)+1,0);
  if(response &lt; 0){error(response);return -1;}
  response = libusb_control_transfer(handle,0x40,52,0,2,(char*)description,strlen(description)+1,0);
  if(response &lt; 0){error(response);return -1;}
  response = libusb_control_transfer(handle,0x40,52,0,3,(char*)version,strlen(version)+1,0);
  if(response &lt; 0){error(response);return -1;}
  response = libusb_control_transfer(handle,0x40,52,0,4,(char*)uri,strlen(uri)+1,0);
  if(response &lt; 0){error(response);return -1;}
  response = libusb_control_transfer(handle,0x40,52,0,5,(char*)serialNumber,strlen(serialNumber)+1,0);
  if(response &lt; 0){error(response);return -1;}
  
  fprintf(stdout,"Accessory Identification sent\n", devVersion);
  
  response = libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0);
  if(response &lt; 0){error(response);return -1;}
  
  fprintf(stdout,"Attempted to put device into accessory mode\n", devVersion);
  
  if(handle != NULL)
      libusb_release_interface (handle, 0);
  
  int tries = 4;
  for(;;){
      tries--;
      if((handle = libusb_open_device_with_vid_pid(NULL, VID, ACCESSORY_PID)) == NULL){
          if(tries &lt; 0){
              return -1;
          }
      }else{
          break;
      }
      sleep(1);
  }
  
  libusb_claim_interface(handle, 0);
  fprintf(stdout, "Interface claimed, ready to transfer data\n");
  return 0;
  }
  
  // error reporting function left out for brevity
  </code></pre>
  
  <p>And here's the Android app:</p>
  
  <pre><code>package com.cengen.android.pchost;
  
  import android.app.Activity;
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Message;
  import android.os.ParcelFileDescriptor;
  import com.android.future.usb.UsbAccessory;
  import com.android.future.usb.UsbManager;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import java.io.FileDescriptor;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  
  public class MainActivity extends Activity implements Runnable
  {
    private final Logger logger = LoggerFactory.getLogger("PCHost");
  
    private UsbManager usbManager;
  
    UsbAccessory accessory;
    ParcelFileDescriptor accessoryFileDescriptor;
    FileInputStream accessoryInput;
    FileOutputStream accessoryOutput;
  
    private final BroadcastReceiver usbBroadcastReceiver = new BroadcastReceiver()
    {
      public void onReceive(Context context, Intent intent)
      {
        String action = intent.getAction();
        if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action))
        {
          synchronized (this)
          {
            accessory = UsbManager.getAccessory(intent);
          }
        }
        else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action))
        {
          UsbAccessory accessory = UsbManager.getAccessory(intent);
          if (accessory != null)
          {
            // call your method that cleans up and closes communication with the accessory
          }
        }
      }
    };
  
    Handler messageHandler = new Handler()
    {
      @Override
      public void handleMessage(Message msg)
      {
        switch (msg.what)
        {
          case 1:
            logger.info("Got message type {}", msg.what);
  //              SendFileMessage m = (SendFileMessage) msg.obj;
  //              handleSendFile(m);
          break;
          case 2:
            logger.info("Got message type {}", msg.what);
  //              SendFileMessage m = (SendFileMessage) msg.obj;
  //              handleSendFile(m);
          break;
          case 3:
            logger.info("Got message type {}", msg.what);
  //              SendFileMessage m = (SendFileMessage) msg.obj;
  //              handleSendFile(m);
          break;
        }
      }
    };
  
    /**
     * Main USB reading loop, processing incoming data from accessory and parsing
     * it into messages via the defined format.
     */
    public void run()
    {
      int ret = 0;
      byte[] buffer = new byte[16384];
      int i;
  
      while (ret &gt;= 0)
      {
        try
        {
          ret = accessoryInput.read(buffer);
          logger.debug("Read {} bytes.", ret);
        }
        catch (IOException e)
        {
          logger.debug("Exception in USB accessory input reading", e);
          break;
        }
  
        i = 0;
        while (i &lt; ret)
        {
          int len = ret - i;
  
          switch (buffer[i])
          {
            case 0x1:
              if (len &gt;= 3)
              {
                Message m = Message.obtain(messageHandler, 1);
  //                      m.obj = new MessageTypeOne(buffer[i + 1], buffer[i + 2]);
                messageHandler.sendMessage(m);
              }
              i += 3;
              break;
  
            case 0x4:
              if (len &gt;= 3)
              {
                Message m = Message.obtain(messageHandler, 1);
  //                      m.obj = new MessageTypeTwo(buffer[i + 1], buffer[i + 2]);
                messageHandler.sendMessage(m);
              }
              i += 3;
              break;
  
            default:
              logger.debug("unknown msg: " + buffer[i]);
              i = len;
              break;
          }
        }
  
      }
    }
  
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
      super.onCreate(savedInstanceState);
  
      usbManager = UsbManager.getInstance(this);
  
      IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
      filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
      registerReceiver(usbBroadcastReceiver, filter);
  
      if (getLastNonConfigurationInstance() != null)
      {
        accessory = (UsbAccessory) getLastNonConfigurationInstance();
        openAccessory(accessory);
      }
      setContentView(R.layout.main);
    }
  
    @Override
    public Object onRetainNonConfigurationInstance()
    {
      return accessory != null ? accessory : super.onRetainNonConfigurationInstance();
    }
  
   @Override
   public void onResume()
   {
     super.onResume();
  
     Intent intent = getIntent();
     if (accessoryInput != null &amp;&amp; accessoryOutput != null)
       return;
  
     // TODO: verify, docs don't do this simple thing, not sure why?
     UsbAccessory accessory = UsbManager.getAccessory(intent);
     if (accessory != null)
       openAccessory(accessory);
     else
       logger.error("Failed to resume accessory.");
   }
  
    @Override
    public void onPause()
    {
      super.onPause();
      closeAccessory();
    }
  
    @Override
    public void onDestroy()
    {
      unregisterReceiver(usbBroadcastReceiver);
      super.onDestroy();
    }
  
    private void openAccessory(UsbAccessory accessory)
    {
      accessoryFileDescriptor = usbManager.openAccessory(accessory);
      if (accessoryFileDescriptor != null)
      {
        this.accessory = accessory;
        FileDescriptor fd = accessoryFileDescriptor.getFileDescriptor();
        accessoryInput = new FileInputStream(fd);
        accessoryOutput = new FileOutputStream(fd);
        Thread thread = new Thread(null, this, "AndroidPCHost");
        thread.start();
        logger.debug("accessory opened");
        // TODO: enable USB operations in the app
      }
      else
      {
        logger.debug("accessory open fail");
      }
    }
  
    private void closeAccessory()
    {
      // TODO: disable USB operations in the app
      try
      {
        if (accessoryFileDescriptor != null)
          accessoryFileDescriptor.close();
      }
      catch (IOException e)
      {}
      finally
      {
        accessoryFileDescriptor = null;
        accessory = null;
      }
    }
  }
  </code></pre>
  
  <p>And the manifest (including the intent-filtering so it auto-associates and auto-perms the device, according to the docs):</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.mycompany.android.pchost"
        android:versionCode="1"
        android:versionName="1.0"&gt;
    &lt;uses-feature android:name="android.hardware.usb.accessory" /&gt;
    &lt;uses-sdk android:minSdkVersion="10" /&gt;
    &lt;application android:label="@string/app_name" android:icon="@drawable/icon"&gt;
      &lt;uses-library android:name="com.android.future.usb.accessory" /&gt;
          &lt;activity android:name="MainActivity"
                    android:label="@string/app_name"
                    android:launchMode="singleInstance"&gt;
              &lt;intent-filter&gt;
                  &lt;action android:name="android.intent.action.MAIN" /&gt;
                  &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
              &lt;/intent-filter&gt;
            &lt;intent-filter&gt;
                &lt;action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /&gt;
            &lt;/intent-filter&gt;
  
            &lt;meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
                android:resource="@xml/accessory_filter" /&gt;
  
          &lt;/activity&gt;
      &lt;/application&gt;
  &lt;/manifest&gt; 
  </code></pre>