Android的ADK与PC机作为USB主机与libusb的,批量传输错误 [英] Android ADK with PC as USB Host with libusb, bulk transfer error

查看:2466
本文介绍了Android的ADK与PC机作为USB主机与libusb的,批量传输错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让我的电脑的USB主机为Android 2.3.4的设备,以便能够开发的API,而无需实际的配件。要做到这一点,我需要建立PC作为USB主机和设备(在我的情况下,Nexus One的运行2.3.4)。

我开始用的libusb code从 http://android.serverbox.ch/ 作为PC端的基和DEMOKIT $ C $在Android端c和Android的文档。

这两个似乎协商连接的罚款,并在界面被声称,但死在在批量传输实际的尝试。在OSX,误差为-5(LIBUSB_ERROR_NOT_FOUND)和Ubuntu Linux操作系统(作为root)的误差为-1(LIBUSB_ERROR_IO)。 (最近发布的每一个与最近的libusb 1.0.8)。

这里的code。对问题的其他意见表示欢迎,虽然这主要是一个概念证明型的,所以我真的只是想要批量传输不工作的原因:

 的#include< stdio.h中>
#包括< libusb.h>
#包括< string.h中>

#定义ENDPOINT_BULK_IN 0X83
#定义ENDPOINT_BULK_OUT 0×0​​3 //尝试过0×00,0×01和0×02

#定义VID 0x18D1
#定义PID 0x4E11

#定义ACCESSORY_PID 0x2D00
#定义ACCESSORY_ADB_PID 0x2D01 //不能得到这个工作,如果亚行是活动的,不能处理的设备

/ *
在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
在Ubuntu
GCC adktest.c -I / usr / include目录-o adktest -lusb-1.0 -I / usr / include目录-I / usr / include目录/ libusb的-1.0

测试在Nexus One上使用姜饼2.3.4
* /

静态INT transferTest();
静态INT的init(无效);
静态INT关机(无效);
静态无效的错误(INT code);
静态无效状态(INT code);
静态INT setupAccessory(
为const char *制造商,
为const char * MODELNAME,
为const char *的描述,
为const char *版本,
为const char * URI,
为const char *的serialNumber);

//静态
静态结构libusb_device_handle *手柄;

INT主(INT ARGC,字符* argv的[]){
如果(的init()&小于0)
    返回;

如果(setupAccessory(
    PCHost
    PCHost1
    描述,
    1.0,
    http://www.mycompany.com
    的SerialNumber)< 0){
    fprintf中(标准输出,错误设置附件\ N);
    关掉();
    返回-1;
};
如果(transferTest()℃,){
    fprintf中(标准输出,在transferTest \ n错误);
    关掉();
    返回-1;
}
关掉();
fprintf中(标准输出,完成\ N);
返回0;
}

静态INT transferTest(){
  //测试BULK IN / OUT
  常量静态INT PACKET_BULK_LEN = 64;
  常量静态INT超时= 5000;
  INT R,I;
  诠释转移;
  焦炭答案[PACKET_BULK_LEN]
  字符的问题[PACKET_BULK_LEN]
  对于(i = 0; I< PACKET_BULK_LEN;我++)的问题[我] =我;

    // ***方式无法HERE ***
    R = libusb_bulk_transfer(手柄,ENDPOINT_BULK_OUT,问题,PACKET_BULK_LEN,
                             &功放;转移,TIMEOUT);
    如果(为r 0){
        fprintf中(错误,批量写入错误%D \ N,R);
        误差(r)的;
        返回ř;
    }
    fprintf中(标准输出,写道:%d字节,R);

    R = libusb_bulk_transfer(手柄,ENDPOINT_BULK_IN,答案,PACKET_BULK_LEN,
                             &功放;转移,TIMEOUT);
    如果(为r 0){
        fprintf中(错误,批量读取错误%D \ N,R);
        误差(r)的;
        返回ř;
    }
    fprintf中(标准输出,读取%d字节,R);

    如果(转< PACKET_BULK_LEN){
        fprintf中(错误,批量传输短读取(%D)\ N,R);
        误差(r)的;
        返回-1;
    }
    的printf(批量传输回路测试结果:\ N);
    //为(i = 0; I< PACKET_BULK_LEN;我++)的printf(%I,%I,\ N的问题[I],回答[I]);
    对于(i = 0; I< PACKET_BULK_LEN;我++){
        如果(I%8 == 0)
            的printf(\ N);
        的printf(%02X,02X%;问题[I],回答[I]);
    }
    的printf(\ñ\ N);

    返回0;

}


静态INT的init(){
libusb_init(NULL);
如果((手柄= libusb_open_device_with_vid_pid(NULL,VID,PID))== NULL){
    fprintf中(标准输出,问题取得手柄的\ n);
    返回-1;
}
libusb_claim_interface(手柄,0);

返回0;
}

静态INT关机(){
如果(处理!= NULL)
    libusb_release_interface(手柄,0);
libusb_exit(NULL);
返回0;
}

静态INT setupAccessory(
为const char *制造商,
为const char * MODELNAME,
为const char *的描述,
为const char *版本,
为const char * URI,
为const char *的serialNumber){

unsigned char型ioBuffer [2];
INT devVersion;
INT响应;

响应= libusb_control_transfer(
    处理,//处理
    为0xC0,// bmRequestType
    51,// bRequest
    0,// wValue
    0,// WINDEX
    ioBuffer,//数据
    2,// wLength
    0 //超时
);

如果(响应℃,){误差(响应);返回-1;}

devVersion = ioBuffer [1];&其中; 8 | ioBuffer [0];
fprintf中(标准输出,版本code设备数:%d \ N,devVersion);

usleep(1000); //有时挂在一个传输:(

响应= libusb_control_transfer(手柄,0x40,52,0,0,(字符*)生产的strlen(制造商),0);
如果(响应℃,){误差(响应);返回-1;}
响应= libusb_control_transfer(手柄,0x40,52,0,1,(字符*)MODELNAME,strlen的(MODELNAME)+1,0);
如果(响应℃,){误差(响应);返回-1;}
响应= libusb_control_transfer(手柄,0x40,52,0,2,(字符*)的说明,strlen的(介绍)+1,0);
如果(响应℃,){误差(响应);返回-1;}
响应= libusb_control_transfer(手柄,0x40,52,0,3,(字符*)版本,strlen的(版本)+1,0);
如果(响应℃,){误差(响应);返回-1;}
响应= libusb_control_transfer(手柄,0x40,52,0,4,(字符*)URI,strlen的(URI)+1,0);
如果(响应℃,){误差(响应);返回-1;}
响应= libusb_control_transfer(手柄,0x40,52,0,5,(字符*)的SerialNumber,strlen的(的serialNumber)+1,0);
如果(响应℃,){误差(响应);返回-1;}

fprintf中(标准输出,配件识别发送\ N,devVersion);

响应= libusb_control_transfer(手柄,0x40,53,0,0,NULL,0,0);
如果(响应℃,){误差(响应);返回-1;}

fprintf中(标准输出,试图将设备插入附件模式\ N,devVersion);

如果(处理!= NULL)
    libusb_release_interface(手柄,0);

INT试图= 4;
对于(;;){
    tries--;
    如果((手柄= libusb_open_device_with_vid_pid(NULL,VID,ACCESSORY_PID))== NULL){
        如果(尝试℃,){
            返回-1;
        }
    }其他{
        打破;
    }
    睡眠(1);
}

libusb_claim_interface(手柄,0);
fprintf中(标准输出接口声称,准备传输数据的\ n);
返回0;
}

//错误报告功能冷落为了简便起见,
 

和这里的Andr​​oid应用程序:

 包com.cengen.android.pchost;

进口android.app.Activity;
进口android.content.BroadcastReceiver;
进口android.content.Context;
进口android.content.Intent;
进口android.content.IntentFilter;
进口android.os.Bundle;
进口android.os.Handler;
进口android.os.Message;
进口android.os.ParcelFileDescriptor;
进口com.android.future.usb.UsbAccessory;
进口com.android.future.usb.UsbManager;
进口org.slf4j.Logger;
进口org.slf4j.LoggerFactory;

进口java.io.FileDescriptor中;
进口java.io.FileInputStream中;
进口java.io.FileOutputStream中;
进口java.io.IOException异常;

公共类MainActivity扩展活动实现Runnable
{
  私人最终记录器记录器= LoggerFactory.getLogger(PCHost);

  私人UsbManager usbManager;

  UsbAccessory配件;
  ParcelFileDescriptor accessoryFileDescriptor;
  的FileInputStream accessoryInput;
  FileOutputStream中accessoryOutput;

  私人最终的BroadcastReceiver usbBroadcastReceiver =新的BroadcastReceiver()
  {
    公共无效的onReceive(上下文的背景下,意图意图)
    {
      串动= intent.getAction();
      如果(UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(动作))
      {
        同步(这)
        {
          附件= UsbManager.getAccessory(意向);
        }
      }
      否则,如果(UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(行动))
      {
        UsbAccessory附件= UsbManager.getAccessory(意向);
        如果(附件!= NULL)
        {
          //调用你的方法来清理和关闭与附件通信
        }
      }
    }
  };

  处理器的MessageHandler =新的处理程序()
  {
    @覆盖
    公共无效的handleMessage(信息MSG)
    {
      开关(msg.what)
      {
        情况1:
          logger.info(得到消息类型{},msg.what);
// SendFileMessage M =(SendFileMessage)msg.obj;
// handleSendFile(米);
        打破;
        案例2:
          logger.info(得到消息类型{},msg.what);
// SendFileMessage M =(SendFileMessage)msg.obj;
// handleSendFile(米);
        打破;
        案例3:
          logger.info(得到消息类型{},msg.what);
// SendFileMessage M =(SendFileMessage)msg.obj;
// handleSendFile(米);
        打破;
      }
    }
  };

  / **
   *主要USB读取循环,处理来自配件和分析输入数据
   *成通过定义的格式信息。
   * /
  公共无效的run()
  {
    INT RET = 0;
    byte []的缓冲区=新的字节[16384]
    INT I;

    而(RET> = 0)
    {
      尝试
      {
        RET = accessoryInput.read(缓冲区);
        logger.debug(读{}字节,RET);
      }
      赶上(IOException异常E)
      {
        logger.debug(异常的USB辅助输入读书,E);
        打破;
      }

      I = 0;
      而(I< RET)
      {
        INT LEN = RET  - 我;

        开关(缓冲[I])
        {
          案例为0x1:
            如果(LEN> = 3)
            {
              消息m = Message.obtain(MessageHandler的,1);
// m.obj =新MessageTypeOne(缓冲[I + 1],缓冲液[I + 2]);
              messageHandler.sendMessage(米);
            }
            I + = 3;
            打破;

          案例为0x4:
            如果(LEN> = 3)
            {
              消息m = Message.obtain(MessageHandler的,1);
// m.obj =新MessageTypeTwo(缓冲[I + 1],缓冲液[I + 2]);
              messageHandler.sendMessage(米);
            }
            I + = 3;
            打破;

          默认:
            logger.debug(未知消息:+缓冲[I]);
            I = len个;
            打破;
        }
      }

    }
  }

  @覆盖
  公共无效的onCreate(包savedInstanceState)
  {
    super.onCreate(savedInstanceState);

    usbManager = UsbManager.getInstance(本);

    IntentFilter的过滤器=新的IntentFilter(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
    filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
    registerReceiver(usbBroadcastReceiver,过滤器);

    如果(getLastNonConfigurationInstance()!= NULL)
    {
      附件=(UsbAccessory)getLastNonConfigurationInstance();
      openAccessory(附件);
    }
    的setContentView(R.layout.main);
  }

  @覆盖
  公共对象onRetainNonConfigurationInstance()
  {
    返回配件!= NULL?附件:super.onRetainNonConfigurationInstance();
  }

 @覆盖
 公共无效onResume()
 {
   super.onResume();

   意向意图= getIntent();
   如果(accessoryInput = NULL和放大器;!&安培;!accessoryOutput = NULL)
     返回;

   // TODO:验证,文档不这样做简单的事情,不知道为什么?
   UsbAccessory附件= UsbManager.getAccessory(意向);
   如果(附件!= NULL)
     openAccessory(附件);
   其他
     logger.error(无法恢复附件。);
 }

  @覆盖
  公共无效的onPause()
  {
    super.onPause();
    closeAccessory();
  }

  @覆盖
  公共无效的onDestroy()
  {
    unregisterReceiver(usbBroadcastReceiver);
    super.onDestroy();
  }

  私人无效openAccessory(UsbAccessory附件)
  {
    accessoryFileDescriptor = usbManager.openAccessory(附件);
    如果(accessoryFileDescriptor!= NULL)
    {
      this.accessory =附件;
      的FileDescriptor FD = accessoryFileDescriptor.getFileDescriptor();
      accessoryInput =新的FileInputStream(FD);
      accessoryOutput =新的FileOutputStream(FD);
      线程线程=新的Thread(null,则此,AndroidPCHost);
      thread.start();
      logger.debug(打开附件);
      // TODO:让应用程序中的USB操作
    }
    其他
    {
      logger.debug(附件打开失败);
    }
  }

  私人无效closeAccessory()
  {
    // TODO:在应用程序中禁用USB操作
    尝试
    {
      如果(accessoryFileDescriptor!= NULL)
        accessoryFileDescriptor.close();
    }
    赶上(IOException异常E)
    {}
    最后
    {
      accessoryFileDescriptor = NULL;
      附件= NULL;
    }
  }
}
 

和清单(包括意向性过滤,因此自动同事和自动烫发设备,根据文档):

 < XML版本=1.0编码=UTF-8&GT?;
<舱单的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
      包=com.mycompany.android.pchost
      安卓版code =1
      机器人:VERSIONNAME =1.0>
  <使用特征的android:NAME =android.hardware.usb.accessory/>
  <使用-SDK安卓的minSdkVersion =10/>
  <应用机器人:标签=@字符串/ APP_NAME机器人:图标=@可绘制/图标>
    <使用库机器人:名称=com.android.future.usb.accessory/>
        <活动机器人:名称=MainActivity
                  机器人:标签=@字符串/ APP_NAME
                  机器人:launchMode =singleInstance>
            <意向滤光器>
                <作用机器人:名称=android.intent.action.MAIN/>
                <类机器人:名称=android.intent.category.LAUNCHER/>
            &所述; /意图滤光器>
          <意向滤光器>
              <作用机器人:名称=android.hardware.usb.action.USB_ACCESSORY_ATTACHED/>
          &所述; /意图滤光器>

          <元数据的android:NAME =android.hardware.usb.action.USB_ACCESSORY_ATTACHED
              机器人:资源=@ XML / accessory_filter/>

        < /活性GT;
    < /用途>
< /舱单>
 

解决方案

最初的问题是,为了告诉它进入辅助模式,设备原始连接永远不会关闭。 USB子系统和/或的libusb不会引发错误,如果你再重新打开,并声称一个接口,而原有的设备仍然处于打开状态。你只得到一个IO或NOT FOUND错误,当你真正尝试从端点写入/。

通过添加:

  libusb_close(手柄);
 

if语句所在的初始界面是从最初的连接问题的一面的libusb解决内释放。

这prevents数据通过软件中的这个特殊的组合,是Android的一侧等待字节的大段它接受这导致超时读取之前的下一个问题(还没有制定出由于哪一方还),因此,如果您设置缓冲区的libusb的侧(64)匹配,你会得到一组初始从PC写入到Android设备的字节。软件仍然会在那之后打破由于PC / libusb的侧然后试图读取数据,但机器人侧不写入任何,但是这仅仅是未完成的软件,而不是问题的范围之内。

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).

I started with libusb code from http://android.serverbox.ch/ as a base for the PC side and the DemoKit code and Android documentation on the Android side.

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).

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:

#include <stdio.h>
#include <libusb.h>
#include <string.h>

#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() < 0)
    return;

if(setupAccessory(
    "PCHost",
    "PCHost1",
    "Description",
    "1.0",
    "http://www.mycompany.com",
    "SerialNumber") < 0){
    fprintf(stdout, "Error setting up accessory\n");
    shutdown();
    return -1;
};
if(transferTest() < 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<PACKET_BULK_LEN; i++) question[i]=i;

    // ***FAILS HERE***
    r = libusb_bulk_transfer(handle, ENDPOINT_BULK_OUT, question, PACKET_BULK_LEN,
                             &transferred,TIMEOUT);
    if (r < 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,
                             &transferred, TIMEOUT);
    if (r < 0) {
        fprintf(stderr, "Bulk read error %d\n", r);
        error(r);
        return r;
    }
    fprintf(stdout, "Read %d bytes", r);

    if (transferred < 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< PACKET_BULK_LEN;i++) printf("%i, %i,\n ",question[i],answer[i]);
    for(i = 0;i < 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 < 0){error(response);return-1;}

devVersion = ioBuffer[1] << 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 < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,1,(char*)modelName,strlen(modelName)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,2,(char*)description,strlen(description)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,3,(char*)version,strlen(version)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,4,(char*)uri,strlen(uri)+1,0);
if(response < 0){error(response);return -1;}
response = libusb_control_transfer(handle,0x40,52,0,5,(char*)serialNumber,strlen(serialNumber)+1,0);
if(response < 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 < 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 < 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

And here's the Android app:

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 >= 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 < ret)
      {
        int len = ret - i;

        switch (buffer[i])
        {
          case 0x1:
            if (len >= 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 >= 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 && 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;
    }
  }
}

And the manifest (including the intent-filtering so it auto-associates and auto-perms the device, according to the docs):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.mycompany.android.pchost"
      android:versionCode="1"
      android:versionName="1.0">
  <uses-feature android:name="android.hardware.usb.accessory" />
  <uses-sdk android:minSdkVersion="10" />
  <application android:label="@string/app_name" android:icon="@drawable/icon">
    <uses-library android:name="com.android.future.usb.accessory" />
        <activity android:name="MainActivity"
                  android:label="@string/app_name"
                  android:launchMode="singleInstance">
            <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_ACCESSORY_ATTACHED" />
          </intent-filter>

          <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
              android:resource="@xml/accessory_filter" />

        </activity>
    </application>
</manifest> 

解决方案

Initial problem is that the original connection to the device in order to tell it to go into accessory mode is never closed. The USB subsystem and/or libusb do not throw an error if you then reopen and claim an interface while the original device is still left open. You only get an IO or NOT FOUND error when you actually try to write to/from an endpoint.

By adding:

libusb_close(handle);

within the if statement where the initial interface is released from initial connection the libusb side of the issue is resolved.

The next issue that prevents data to pass in this particular combination of softwares, is that the Android side is waiting for a larger segment of bytes before it accepts the read which results in a timeout (haven't worked out due to which side yet) and so if you set the buffer to match the libusb side (64), you will get an initial set of bytes written from the PC to the Android device. The software will still break after that since the PC/libusb side then tries to read data but the Android side isn't writing any, but that is simply unfinished software and not within the scope of the question.

这篇关于Android的ADK与PC机作为USB主机与libusb的,批量传输错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆