使用Andriod的USB主机API来阅读我的USB游戏手柄/或其他USB设备的数据 [英] Using Andriod USB Host API to read my USB game controller/Or other USB device data

查看:347
本文介绍了使用Andriod的USB主机API来阅读我的USB游戏手柄/或其他USB设备的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用的Andr​​iod USB主机API来阅读我的USB游戏控制器的数据,一旦我得到这个工作,我将连接其他设备进行测试。
我的游戏控制器使用OTG线连接到我的Andr​​iod手机。我现在能够得到的设备,端点的信息,但我不知道如何读的原始数据并显示它。

有人能帮帮我吗?一些示例codeS将AP preciated。

谢谢!

 的TextView countDisplay;
    ArrayList的<串GT;时listItems =新的ArrayList<串GT;();
    ArrayAdapter<串GT;适配器;
    字符串值=;
    UsbManager mManager的;
    UsbDevice设备= NULL;
    私人字节[]字节;
    私有静态诠释TIMEOUT = 0;
    私人布尔forceClaim = TRUE;
    静态的PendingIntent mPermissionIntent;
    UsbDeviceConnection连接= NULL;
    UsbEndpoint InputEndpoint = NULL;
    UsbEndpoint OutputEndpoint = NULL;
    私人处理程序mHandler =新的处理程序();
@覆盖
公共无效的onCreate(捆绑savedInstanceState){
    super.onCreate(savedInstanceState);
    mManager的=(UsbManager)getSystemService(Context.USB_SERVICE);
    mPermissionIntent = PendingIntent.getBroadcast(这一点,0,新意图(
            com.android.example.USB_PERMISSION),0);
    IntentFilter的过滤器=新的IntentFilter();
    filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
    registerReceiver(mUsbReceiver,过滤器);    HashMap的<弦乐,UsbDevice> DEVICELIST = mManager.getDeviceList();
    值=价值+deviceListSize:+ deviceList.size()+的toString:
            + deviceList.toString();
    迭代器< UsbDevice> deviceIterator = deviceList.values​​()迭代器()。
    而(deviceIterator.hasNext()){
        设备= deviceIterator.next();
        值=价值+,设备ID:+ device.getDeviceId()
                +,设备名称:+ device.getDeviceName();
        值=价值+,协议:+ device.getDeviceProtocol()
                +,产品编号:+ device.getProductId();
        值=价值+,DEVICECLASS:+ device.getDeviceClass()
                +,VENDORID:+ device.getVendorId();
    }
    如果(设备!= NULL){
        值=价值+,getInterfaceCount:
                + device.getInterfaceCount();
        的UsbInterface INTF = device.getInterface(0);
        值=价值+,intf.getEndpointCount():
                + intf.getEndpointCount();
        UsbEndpoint端点1 = intf.getEndpoint(0);
        UsbEndpoint端点2 = intf.getEndpoint(1);        mManager.requestPermission(设备,mPermissionIntent);
        如果(mManager.hasPermission(设备)){
            值=价值+,拥有超过设备的许可!;
            连接= mManager.openDevice(设备);
            如果(连接== NULL){
                值=价值+,连接空;
            }其他{
                值=价值+,getFileDescriptor:
                        + connection.getFileDescriptor();
                如果(endpoint1.getDirection()== UsbConstants.USB_DIR_IN){
                    InputEndpoint =端点1;
                }其他{
                    OutputEndpoint =端点1;
                }
                如果(endpoint2.getDirection()== UsbConstants.USB_DIR_IN){
                    InputEndpoint =端点2;
                }其他{
                    OutputEndpoint =端点2;
                }
            }
            如果(InputEndpoint == NULL){
                countDisplay.setText(值+,InputEndpoint为空);
            }
            如果(OutputEndpoint == NULL){
                countDisplay.setText(值+,OutputEndPoint为空);
            }
            connection.claimInterface(INTF,forceClaim);
            mHandler.postDelayed(可运行,1);
        }其他{
            值=价值+,没有权限在设备!
        }    }    的setContentView(R.layout.activity_main);
    LayoutInflater吹气=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);    视图V = inflater.inflate(R.layout.activity_main,NULL);
    LL的LinearLayout =新的LinearLayout(本);
    ll.setOrientation(LinearLayout.VERTICAL);
    INT计数器= 1;
    countDisplay =新的TextView(本);
    ll.addView(countDisplay);    countDisplay.setText(值+,反在这里);
    最后Button按钮=新按钮(本);
    button.setOnClickListener(新OnClickListener(){        @覆盖
        公共无效的onClick(视图v){
            // TODO自动生成方法存根
            如果(设备= NULL&放大器;!&安培; mManager.hasPermission(设备)){
                值=价值+,设备ID:+ device.getDeviceId()
                        +,设备名称:+ device.getDeviceName();
                值=价值+,协议:+ device.getDeviceProtocol()
                        +,产品编号:+ device.getProductId();
                值=价值+,DEVICECLASS:+ device.getDeviceClass()
                        +,VENDORID:+ device.getVendorId();                countDisplay.setText(值+,奥科克);            }其他{
                如果(设备!= NULL)
                    mManager.requestPermission(设备,mPermissionIntent);
            }
        }    });
    ll.addView(按钮);
    的setContentView(Ⅱ);
}

和Runnable接口:

 私人可运行的可运行=新的Runnable(){
    公共无效的run(){
        如果(连接!= NULL){
            诠释计数= connection.bulkTransfer(InputEndpoint,字节,
                    bytes.length,TIMEOUT);
            countDisplay.setText(值+,bultTransferNo:+计数);
            countDisplay.setText(值+bulkValue:+字节);
        }其他{
            countDisplay.setText(值+,连接为空);
        }
    }
};


解决方案

该计划作为下面的USB主机功能的例子:


  • 根据接口类,子类和协议(见device_filter.xml)配套设备


  • 异步IO上批量端点


所有code版权所有:

  / *
     *版权所有(C)2011年Android开源项目
     *
     *在Apache许可,2.0版(以下简称许可证);
     *您不能使用这个文件除了在遵守许可。
     *您可以在获得许可证的副本
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     *除非适用法律要求或书面同意,软件
     *许可下发布的分布在原样的基础,
     *无担保或任何形式的条件,无论是前preSS或暗示的保证。
     *请参阅许可证的特定语言的管理权限和
     *根据许可证的限制。
     * /

AdbDevice

 包com.android.adb;    进口android.hardware.usb.UsbConstants;
    进口android.hardware.usb.UsbDeviceConnection;
    进口android.hardware.usb.UsbEndpoint;
    进口android.hardware.usb.UsbInterface;
    进口android.hardware.usb.UsbRequest;
    进口android.util.SparseArray;    进口java.util.LinkedList中;    / *这个类重presents支持亚行协议的USB设备。 * /
    公共类AdbDevice {        私人最终AdbTestActivity mActivity;
        私人最终UsbDeviceConnection mDeviceConnection;
        私人最终UsbEndpoint mEndpointOut;
        私人最终UsbEndpoint mEndpointIn;        私人字符串mSerial;        //为OUT端点请求池
        私人最终的LinkedList< UsbRequest> mOutRequestPool =新的LinkedList< UsbRequest>();
        //为IN端点请求池
        私人最终的LinkedList< UsbRequest> mInRequestPool =新的LinkedList< UsbRequest>();
        //当前打开的套接字列表
        私人最终SparseArray< AdbSocket> mSockets =新SparseArray< AdbSocket>();
        私人INT mNextSocketId = 1;        私人最终WaiterThread mWaiterThread =新WaiterThread();        公共AdbDevice(AdbTestActivity活动,UsbDeviceConnection连接,
                INTF的UsbInterface){
            mActivity =活动;
            mDeviceConnection =连接;
            mSerial = connection.getSerial();            UsbEndpoint epOut = NULL;
            亿品UsbEndpoint = NULL;
            //寻找我们的批量端点
            的for(int i = 0; I< intf.getEndpointCount();我++){
                UsbEndpoint EP = intf.getEndpoint(ⅰ);
                如果(ep.getType()== UsbConstants.USB_ENDPOINT_XFER_BULK){
                    如果(ep.getDirection()== UsbConstants.USB_DIR_OUT){
                        epOut = EP;
                    }其他{
                        亿品= EP;
                    }
                }
            }
            如果(epOut == NULL ||亿品== NULL){
                抛出新抛出:IllegalArgumentException(未找到所有端点);
            }
            mEndpointOut = epOut;
            mEndpointIn =亿品;
        }        //返回设备序列号
        公共字符串getSerial(){
            返回mSerial;
        }        //从我们的池出请求
        公共UsbRequest getOutRequest(){
            同步(mOutRequestPool){
                如果(mOutRequestPool.isEmpty()){
                    UsbRequest要求=新UsbRequest();
                    request.initialize(mDeviceConnection,mEndpointOut);
                    返回请求;
                }其他{
                    返回mOutRequestPool.removeFirst();
                }
            }
        }        //返回一个OUT请求池
        公共无效releaseOutRequest(UsbRequest要求){
            同步(mOutRequestPool){
                mOutRequestPool.add(请求);
            }
        }        //从池中获取IN请求
        公共UsbRequest getInRequest(){
            同步(mInRequestPool){
                如果(mInRequestPool.isEmpty()){
                    UsbRequest要求=新UsbRequest();
                    request.initialize(mDeviceConnection,mEndpointIn);
                    返回请求;
                }其他{
                    返回mInRequestPool.removeFirst();
                }
            }
        }        公共无效的start(){
            mWaiterThread.start();
            连接();
        }        公共AdbSocket openSocket(字符串目的地){
            AdbSocket插座;
            同步(mSockets){
                INT ID = mNextSocketId ++;
                插座=新AdbSocket(本,身份证);
                mSockets.put(ID,插座);
            }
            如果(socket.open(目标)){
                返回插座;
            }其他{
                返回null;
            }
        }        私人AdbSocket getSocket(INT ID){
            同步(mSockets){
                返回mSockets.get(ID);
            }
        }        公共无效socketClosed(AdbSocket插座){
            同步(mSockets){
                mSockets.remove(socket.getId());
            }
        }        //发送连接命令
        私人无效连接(){
            AdbMessage消息=新AdbMessage();
            message.set(AdbMessage.A_CNXN,AdbMessage.A_VERSION,AdbMessage.MAX_PAYLOAD,主持人:: \\ 0);
            message.write(本);
        }        //处理连接响应
        私人无效handleConnect(AdbMessage消息){
            如果(message.getDataString()startsWith(设备:)){
                日志(连接);
                mActivity.deviceOnline(本);
            }
        }        公共无效停止(){
            同步(mWaiterThread){
                mWaiterThread.mStop = TRUE;
            }
        }        //从设备调度的消息
        无效DispatchMessage函数(AdbMessage消息){
            INT命令= message.getCommand();
            开关(命令){
                案例AdbMessage.A_SYNC:
                    日志(得到A_SYNC);
                    打破;
                案例AdbMessage.A_CNXN:
                    handleConnect(消息);
                    打破;
                案例AdbMessage.A_OPEN:
                案例AdbMessage.A_OKAY:
                案例AdbMessage.A_CLSE:
                案例AdbMessage.A_WRTE:
                    AdbSocket插座= getSocket(message.getArg1());
                    如果(插座== NULL){
                        日志(ERROR插座未找到);
                    }其他{
                        socket.handleMessage(消息);
                    }
                    打破;
            }
        }        无效日志(String s)将{
            mActivity.log(多个);
        }
        私有类WaiterThread继承Thread {
            公共布尔MSTOP;            公共无效的run(){
                //启动了一个命令读
                AdbMessage currentCommand =新AdbMessage();
                AdbMessage CURRENTDATA = NULL;
                // FIXME错误检查
                currentCommand.readCommand(getInRequest());                而(真){
                    同步(本){
                        如果(MSTOP){
                            返回;
                        }
                    }
                    UsbRequest请求= mDeviceConnection.requestWait();
                    如果(要求== NULL){
                        打破;
                    }                    AdbMessage消息=(AdbMessage)request.getClientData();
                    request.setClientData(NULL);
                    AdbMessage messageToDispatch = NULL;                    如果(消息== currentCommand){
                        INT DATALENGTH = message.getDataLength();
                        //读取数据,如果长度GT; 0
                        如果(DATALENGTH大于0){
                            message.readData(getInRequest()DATALENGTH);
                            CURRENTDATA =消息;
                        }其他{
                            messageToDispatch =消息;
                        }
                        currentCommand = NULL;
                    }否则如果(消息== CURRENTDATA){
                        messageToDispatch =消息;
                        CURRENTDATA = NULL;
                    }                    如果(messageToDispatch!= NULL){
                        //队列中的另一个读第一
                        currentCommand =新AdbMessage();
                        currentCommand.readCommand(getInRequest());                        //然后派遣当前消息
                        在DispatchMessage(messageToDispatch);
                    }                    // PUT请求放回相应的池
                    如果(request.getEndpoint()== mEndpointOut){
                        releaseOutRequest(请求);
                    }其他{
                        同步(mInRequestPool){
                            mInRequestPool.add(请求);
                        }
                    }
                }
            }
        }
    }

AdbMessage

 包com.android.adb;    进口android.hardware.usb.UsbRequest;    进口java.nio.ByteBuffer中;
    进口java.nio.ByteOrder中;    / *此类封装和亚行命令包* /
    公共类AdbMessage {        //命令名
        公共静态最终诠释A_SYNC = 0x434e5953;
        公共静态最终诠释A_CNXN = 0x4e584e43;
        公共静态最终诠释A_OPEN = 0x4e45504f;
        公共静态最终诠释A_OKAY = 0x59414b4f;
        公共静态最终诠释A_CLSE = 0x45534c43;
        公共静态最终诠释A_WRTE = 0x45545257;        // ADB协议版本
        公共静态最终诠释A_VERSION =为0x01000000;        公共静态最终诠释MAX_PAYLOAD = 4096;        私人最终的ByteBuffer mMessageBuffer;
        私人最终的ByteBuffer mDataBuffer;        公共AdbMessage(){
            mMessageBuffer = ByteBuffer.allocate(24);
            mDataBuffer = ByteBuffer.allocate(MAX_PAYLOAD);
            mMessageBuffer.order(ByteOrder.LITTLE_ENDIAN);
            mDataBuffer.order(ByteOrder.LITTLE_ENDIAN);
        }        //设置在命令头字段
        公共无效集(INT命令,诠释为arg0,ARG1 INT,字节[]数据){
            mMessageBuffer.putInt(0,命令);
            mMessageBuffer.putInt(4,为arg0);
            mMessageBuffer.putInt(8,ARG1);
            mMessageBuffer.putInt(12,(数据== NULL?0:data.length));
            mMessageBuffer.putInt(16,(数据==空?0:校验(数据)));
            mMessageBuffer.putInt(20,命令^ 0xFFFFFFFF的);
            如果(数据!= NULL){
                mDataBuffer.put(数据,0,data.length);
            }
        }        公共无效集(INT命令,诠释为arg0,ARG1 INT){
            集(命令,为arg0,ARG1,(字节[])NULL);
        }
        公共无效集(INT命令,诠释为arg0,ARG1 INT,字符串数据){
            //添加尾随零
            数据+ ='\\ 0';
            设置(指挥,为arg0,ARG1,data.getBytes());
        }        //返回命令的消息ID
        公众诠释getCommand(){
            返回mMessageBuffer.getInt(0);
        }        //返回命令的第一个参数
        公众诠释getArg0(){
            返回mMessageBuffer.getInt(4);
        }        //返回命令的第二个参数
        公众诠释getArg1(){
            返回mMessageBuffer.getInt(8);
        }        //返回命令的数据缓冲区
        公众的ByteBuffer的getData(){
            返回mDataBuffer;
        }        //返回命令的数据长度
        公众诠释getDataLength(){
            返回mMessageBuffer.getInt(12);
        }        //返回命令的数据作为一个字符串
        公共字符串getDataString(){
            INT长度= getDataLength();
            如果(长度== 0)返回NULL;
            //修剪尾随零
            返回新的String(mDataBuffer.array(),0,长度 - 1);
        }
        公共布尔写(AdbDevice设备){
            同步(器){
                UsbRequest请求= device.getOutRequest();
                request.setClientData(本);
                如果(request.queue(mMessageBuffer,24)){
                    INT长度= getDataLength();
                    如果(长度大于0){
                        请求= device.getOutRequest();
                        request.setClientData(本);
                        如果(request.queue(mDataBuffer,长度)){
                            返回true;
                        }其他{
                            device.releaseOutRequest(请求);
                            返回false;
                        }
                    }
                    返回true;
                }其他{
                    device.releaseOutRequest(请求);
                    返回false;
                }
            }
        }        公共布尔readCommand(UsbRequest要求){
            request.setClientData(本);
            返回request.queue(mMessageBuffer,24);
        }        公共布尔READDATA(UsbRequest要求,INT长度){
            request.setClientData(本);
            返回request.queue(mDataBuffer,长度);
        }        私人静态字符串extractString(ByteBuffer的缓冲区,诠释抵消,诠释长度){
            字节[]字节=新的字节[长度]
            的for(int i = 0; I<长度;我++){
                字节[I] = buffer.get(偏移++);
            }
            返回新的字符串(字节);
        }        @覆盖
        公共字符串的toString(){
            串的CommandName = extractString(mMessageBuffer,0,4);
            INT DATALENGTH = getDataLength();
            字符串结果=ADB消息:+ +的CommandName为arg0:+ getArg0()+
                 ARG1:+ getArg1()+DATALENGTH:+ DATALENGTH;
            如果(DATALENGTH大于0){
                结果+ =(数据:\\+ getDataString()+\\);
            }
            返回结果;
        }        私有静态诠释校验(字节[]数据){
            INT结果为0;
            的for(int i = 0; I< data.length;我++){
                INT X =数据[I]
                //党,没有在java中的无符号整数
                如果(X℃,)X + = 256;
                结果+ = X;
            }
            返回结果;
        }
    }

AdbSocket

 包com.android.adb;    / *这个类重presents亚行插座。亚行支持多个独立
     *套接字连接到一台设备。通常创建套接字
     *为所执行的每个ADB命令。
     * /
    公共类AdbSocket {        私人最终AdbDevice mDevice;
        私人最终诠释中旬;
        私人诠释mPeerId;        公共AdbSocket(AdbDevice设备,INT ID){
            mDevice =设备;
            MID = ID;
        }        公众诠释的getId(){
            返回MID;
        }        公共布尔开放(字符串目的地){
            AdbMessage消息=新AdbMessage();
            message.set(AdbMessage.A_OPEN,MID,0,目的地);
            如果(!message.write(mDevice)){
                返回false;
            }            同步(本){
                尝试{
                    等待();
                }赶上(InterruptedException的E){
                    返回false;
                }
            }
            返回true;
        }        公共无效的handleMessage(AdbMessage消息){
            开关(message.getCommand()){
                案例AdbMessage.A_OKAY:
                    mPeerId = message.getArg0();
                    同步(本){
                        通知();
                    }
                    打破;
                案例AdbMessage.A_WRTE:
                    mDevice.log(message.getDataString());
                    sendReady();
                    打破;
            }
        }        私人无效sendReady(){
            AdbMessage消息=新AdbMessage();
            message.set(AdbMessage.A_OKAY,MID,mPeerId);
            message.write(mDevice);
        }
    }

I am trying to use Andriod USB Host API to read my USB game controller data, once I get this to work, I will connect other device to test. My game controller is connected to my Andriod phone using OTG cable. I am now able to get device, endpoints information, but I don't know how to read the raw data and display it.

Can someone please help me? Some example codes will be appreciated.

Thanks!!

TextView countDisplay;
    ArrayList<String> listItems = new ArrayList<String>();
    ArrayAdapter<String> adapter;
    String values = "";
    UsbManager mManager;
    UsbDevice device = null;
    private byte[] bytes;
    private static int TIMEOUT = 0;
    private boolean forceClaim = true;
    static PendingIntent mPermissionIntent;
    UsbDeviceConnection connection = null;
    UsbEndpoint InputEndpoint = null;
    UsbEndpoint OutputEndpoint = null;
    private Handler mHandler = new Handler();


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
            "com.android.example.USB_PERMISSION"), 0);
    IntentFilter filter = new IntentFilter();
    filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
    registerReceiver(mUsbReceiver, filter);

    HashMap<String, UsbDevice> deviceList = mManager.getDeviceList();
    values = values + "deviceListSize:" + deviceList.size() + ",tostring:"
            + deviceList.toString();
    Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
    while (deviceIterator.hasNext()) {
        device = deviceIterator.next();
        values = values + ",device id:" + device.getDeviceId()
                + ",device name:" + device.getDeviceName();
        values = values + ",Protocol:" + device.getDeviceProtocol()
                + ",ProductId:" + device.getProductId();
        values = values + ",DeviceClass:" + device.getDeviceClass()
                + ",VendorId:" + device.getVendorId();
    }
    if (device != null) {
        values = values + ",getInterfaceCount:"
                + device.getInterfaceCount();
        UsbInterface intf = device.getInterface(0);
        values = values + ",intf.getEndpointCount():"
                + intf.getEndpointCount();
        UsbEndpoint endpoint1 = intf.getEndpoint(0);
        UsbEndpoint endpoint2 = intf.getEndpoint(1);

        mManager.requestPermission(device, mPermissionIntent);
        if (mManager.hasPermission(device)) {
            values = values + ",has permission over device!";
            connection = mManager.openDevice(device);
            if (connection == null) {
                values = values + ",connection null";
            } else {
                values = values + ",getFileDescriptor:"
                        + connection.getFileDescriptor();
                if (endpoint1.getDirection() == UsbConstants.USB_DIR_IN) {
                    InputEndpoint = endpoint1;
                } else {
                    OutputEndpoint = endpoint1;
                }
                if (endpoint2.getDirection() == UsbConstants.USB_DIR_IN) {
                    InputEndpoint = endpoint2;
                } else {
                    OutputEndpoint = endpoint2;
                }
            }
            if (InputEndpoint == null) {
                countDisplay.setText(values + ",InputEndpoint is null");
            }
            if (OutputEndpoint == null) {
                countDisplay.setText(values + ",OutputEndPoint is null");
            }
            connection.claimInterface(intf, forceClaim);
            mHandler.postDelayed(runnable, 1);
        } else {
            values = values + ",Do not have permission over device!";
        }

    }

    setContentView(R.layout.activity_main);
    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    View v = inflater.inflate(R.layout.activity_main, null);
    LinearLayout ll = new LinearLayout(this);
    ll.setOrientation(LinearLayout.VERTICAL);
    int counter = 1;
    countDisplay = new TextView(this);
    ll.addView(countDisplay);

    countDisplay.setText(values + ",counter here");
    final Button button = new Button(this);
    button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (device != null && mManager.hasPermission(device)) {
                values = values + ",device id:" + device.getDeviceId()
                        + ",device name:" + device.getDeviceName();
                values = values + ",Protocol:" + device.getDeviceProtocol()
                        + ",ProductId:" + device.getProductId();
                values = values + ",DeviceClass:" + device.getDeviceClass()
                        + ",VendorId:" + device.getVendorId();

                countDisplay.setText(values + ",okok");

            } else {
                if (device != null)
                    mManager.requestPermission(device, mPermissionIntent);
            }
        }

    });
    ll.addView(button);
    setContentView(ll);
}

And Runnable:

private Runnable runnable = new Runnable() {
    public void run() {
        if (connection != null) {
            int count = connection.bulkTransfer(InputEndpoint, bytes,
                    bytes.length, TIMEOUT);
            countDisplay.setText(values + ",bultTransferNo:" + count);
            countDisplay.setText(values + "bulkValue:" + bytes);
        } else {
            countDisplay.setText(values + ",connection is null");
        }
    }
};

解决方案

This program serves as an example of the following USB host features:

  • Matching devices based on interface class, subclass and protocol (see device_filter.xml)

  • Asynchronous IO on bulk endpoints

All code Copyright:

    /*
     * Copyright (C) 2011 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */

AdbDevice

    package com.android.adb;

    import android.hardware.usb.UsbConstants;
    import android.hardware.usb.UsbDeviceConnection;
    import android.hardware.usb.UsbEndpoint;
    import android.hardware.usb.UsbInterface;
    import android.hardware.usb.UsbRequest;
    import android.util.SparseArray;

    import java.util.LinkedList;

    /* This class represents a USB device that supports the adb protocol. */
    public class AdbDevice {

        private final AdbTestActivity mActivity;
        private final UsbDeviceConnection mDeviceConnection;
        private final UsbEndpoint mEndpointOut;
        private final UsbEndpoint mEndpointIn;

        private String mSerial;

        // pool of requests for the OUT endpoint
        private final LinkedList<UsbRequest> mOutRequestPool = new LinkedList<UsbRequest>();
        // pool of requests for the IN endpoint
        private final LinkedList<UsbRequest> mInRequestPool = new LinkedList<UsbRequest>();
        // list of currently opened sockets
        private final SparseArray<AdbSocket> mSockets = new SparseArray<AdbSocket>();
        private int mNextSocketId = 1;

        private final WaiterThread mWaiterThread = new WaiterThread();

        public AdbDevice(AdbTestActivity activity, UsbDeviceConnection connection,
                UsbInterface intf) {
            mActivity = activity;
            mDeviceConnection = connection;
            mSerial = connection.getSerial();

            UsbEndpoint epOut = null;
            UsbEndpoint epIn = null;
            // look for our bulk endpoints
            for (int i = 0; i < intf.getEndpointCount(); i++) {
                UsbEndpoint ep = intf.getEndpoint(i);
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        epOut = ep;
                    } else {
                        epIn = ep;
                    }
                }
            }
            if (epOut == null || epIn == null) {
                throw new IllegalArgumentException("not all endpoints found");
            }
            mEndpointOut = epOut;
            mEndpointIn = epIn;
        }

        // return device serial number
        public String getSerial() {
            return mSerial;
        }

        // get an OUT request from our pool
        public UsbRequest getOutRequest() {
            synchronized(mOutRequestPool) {
                if (mOutRequestPool.isEmpty()) {
                    UsbRequest request = new UsbRequest();
                    request.initialize(mDeviceConnection, mEndpointOut);
                    return request;
                } else {
                    return mOutRequestPool.removeFirst();
                }
            }
        }

        // return an OUT request to the pool
        public void releaseOutRequest(UsbRequest request) {
            synchronized (mOutRequestPool) {
                mOutRequestPool.add(request);
            }
        }

        // get an IN request from the pool
        public UsbRequest getInRequest() {
            synchronized(mInRequestPool) {
                if (mInRequestPool.isEmpty()) {
                    UsbRequest request = new UsbRequest();
                    request.initialize(mDeviceConnection, mEndpointIn);
                    return request;
                } else {
                    return mInRequestPool.removeFirst();
                }
            }
        }

        public void start() {
            mWaiterThread.start();
            connect();
        }

        public AdbSocket openSocket(String destination) {
            AdbSocket socket;
            synchronized (mSockets) {
                int id = mNextSocketId++;
                socket = new AdbSocket(this, id);
                mSockets.put(id, socket);
            }
            if (socket.open(destination)) {
                return socket;
            } else {
                return null;
            }
        }

        private AdbSocket getSocket(int id) {
            synchronized (mSockets) {
                return mSockets.get(id);
            }
        }

        public void socketClosed(AdbSocket socket) {
            synchronized (mSockets) {
                mSockets.remove(socket.getId());
            }
        }

        // send a connect command
        private void connect() {
            AdbMessage message = new AdbMessage();
            message.set(AdbMessage.A_CNXN, AdbMessage.A_VERSION, AdbMessage.MAX_PAYLOAD, "host::\0");
            message.write(this);
        }

        // handle connect response
        private void handleConnect(AdbMessage message) {
            if (message.getDataString().startsWith("device:")) {
                log("connected");
                mActivity.deviceOnline(this);
            }
        }

        public void stop() {
            synchronized (mWaiterThread) {
                mWaiterThread.mStop = true;
            }
        }

        // dispatch a message from the device
        void dispatchMessage(AdbMessage message) {
            int command = message.getCommand();
            switch (command) {
                case AdbMessage.A_SYNC:
                    log("got A_SYNC");
                    break;
                case AdbMessage.A_CNXN:
                    handleConnect(message);
                    break;
                case AdbMessage.A_OPEN:
                case AdbMessage.A_OKAY:
                case AdbMessage.A_CLSE:
                case AdbMessage.A_WRTE:
                    AdbSocket socket = getSocket(message.getArg1());
                    if (socket == null) {
                        log("ERROR socket not found");
                    } else {
                        socket.handleMessage(message);
                    }
                    break;
            }
        }

        void log(String s) {
            mActivity.log(s);
        }


        private class WaiterThread extends Thread {
            public boolean mStop;

            public void run() {
                // start out with a command read
                AdbMessage currentCommand = new AdbMessage();
                AdbMessage currentData = null;
                // FIXME error checking
                currentCommand.readCommand(getInRequest());

                while (true) {
                    synchronized (this) {
                        if (mStop) {
                            return;
                        }
                    }
                    UsbRequest request = mDeviceConnection.requestWait();
                    if (request == null) {
                        break;
                    }

                    AdbMessage message = (AdbMessage)request.getClientData();
                    request.setClientData(null);
                    AdbMessage messageToDispatch = null;

                    if (message == currentCommand) {
                        int dataLength = message.getDataLength();
                        // read data if length > 0
                        if (dataLength > 0) {
                            message.readData(getInRequest(), dataLength);
                            currentData = message;
                        } else {
                            messageToDispatch = message;
                        }
                        currentCommand = null;
                    } else if (message == currentData) {
                        messageToDispatch = message;
                        currentData = null;
                    }

                    if (messageToDispatch != null) {
                        // queue another read first
                        currentCommand = new AdbMessage();
                        currentCommand.readCommand(getInRequest());

                        // then dispatch the current message
                        dispatchMessage(messageToDispatch);
                    }

                    // put request back into the appropriate pool
                    if (request.getEndpoint() == mEndpointOut) {
                        releaseOutRequest(request);
                    } else {
                        synchronized (mInRequestPool) {
                            mInRequestPool.add(request);
                        }
                    }
                }
            }
        }
    }

AdbMessage

    package com.android.adb;

    import android.hardware.usb.UsbRequest;

    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;

    /* This class encapsulates and adb command packet */
    public class AdbMessage {

        // command names
        public static final int A_SYNC = 0x434e5953;
        public static final int A_CNXN = 0x4e584e43;
        public static final int A_OPEN = 0x4e45504f;
        public static final int A_OKAY = 0x59414b4f;
        public static final int A_CLSE = 0x45534c43;
        public static final int A_WRTE = 0x45545257;

        // ADB protocol version
        public static final int A_VERSION = 0x01000000;

        public static final int MAX_PAYLOAD = 4096;

        private final ByteBuffer mMessageBuffer;
        private final ByteBuffer mDataBuffer;

        public AdbMessage() {
            mMessageBuffer = ByteBuffer.allocate(24);
            mDataBuffer = ByteBuffer.allocate(MAX_PAYLOAD);
            mMessageBuffer.order(ByteOrder.LITTLE_ENDIAN);
            mDataBuffer.order(ByteOrder.LITTLE_ENDIAN);
        }

        // sets the fields in the command header
        public void set(int command, int arg0, int arg1, byte[] data) {
            mMessageBuffer.putInt(0, command);
            mMessageBuffer.putInt(4, arg0);
            mMessageBuffer.putInt(8, arg1);
            mMessageBuffer.putInt(12, (data == null ? 0 : data.length));
            mMessageBuffer.putInt(16, (data == null ? 0 : checksum(data)));
            mMessageBuffer.putInt(20, command ^ 0xFFFFFFFF);
            if (data != null) {
                mDataBuffer.put(data, 0, data.length);
            }
        }

        public void set(int command, int arg0, int arg1) {
            set(command, arg0, arg1, (byte[])null);
        }
        public void set(int command, int arg0, int arg1, String data) {
            // add trailing zero
            data += "\0";
            set(command, arg0, arg1, data.getBytes());
        }

        // returns the command's message ID
        public int getCommand() {
            return mMessageBuffer.getInt(0);
        }

        // returns command's first argument
        public int getArg0() {
            return mMessageBuffer.getInt(4);
        }

        // returns command's second argument
        public int getArg1() {
            return mMessageBuffer.getInt(8);
        }

        // returns command's data buffer
        public ByteBuffer getData() {
            return mDataBuffer;
        }

        // returns command's data length
        public int getDataLength() {
            return mMessageBuffer.getInt(12);
        }

        // returns command's data as a string
        public String getDataString() {
            int length = getDataLength();
            if (length == 0) return null;
            // trim trailing zero
            return new String(mDataBuffer.array(), 0, length - 1);
        }


        public boolean write(AdbDevice device) {
            synchronized (device) {
                UsbRequest request = device.getOutRequest();
                request.setClientData(this);
                if (request.queue(mMessageBuffer, 24)) {
                    int length = getDataLength();
                    if (length > 0) {
                        request = device.getOutRequest();
                        request.setClientData(this);
                        if (request.queue(mDataBuffer, length)) {
                            return true;
                        } else {
                            device.releaseOutRequest(request);
                            return false;
                        }
                    }
                    return true;
                } else {
                    device.releaseOutRequest(request);
                    return false;
                }
            }
        }

        public boolean readCommand(UsbRequest request) {
            request.setClientData(this);
            return request.queue(mMessageBuffer, 24);
        }

        public boolean readData(UsbRequest request, int length) {
            request.setClientData(this);
            return request.queue(mDataBuffer, length);
        }

        private static String extractString(ByteBuffer buffer, int offset, int length) {
            byte[] bytes = new byte[length];
            for (int i = 0; i < length; i++) {
                bytes[i] = buffer.get(offset++);
            }
            return new String(bytes);
        }

        @Override
        public String toString() {
            String commandName = extractString(mMessageBuffer, 0, 4);
            int dataLength = getDataLength();
            String result = "Adb Message: " + commandName + " arg0: " + getArg0() +
                 " arg1: " + getArg1() + " dataLength: " + dataLength;
            if (dataLength > 0) {
                result += (" data: \"" + getDataString() + "\"");
            }
            return result;
        }

        private static int checksum(byte[] data) {
            int result = 0;
            for (int i = 0; i < data.length; i++) {
                int x = data[i];
                // dang, no unsigned ints in java
                if (x < 0) x += 256;
                result += x;
            }
            return result;
        }
    }

AdbSocket

    package com.android.adb;

    /* This class represents an adb socket.  adb supports multiple independent
     * socket connections to a single device.  Typically a socket is created
     * for each adb command that is executed.
     */
    public class AdbSocket {

        private final AdbDevice mDevice;
        private final int mId;
        private int mPeerId;

        public AdbSocket(AdbDevice device, int id) {
            mDevice = device;
            mId = id;
        }

        public int getId() {
            return mId;
        }

        public boolean open(String destination) {
            AdbMessage message = new AdbMessage();
            message.set(AdbMessage.A_OPEN, mId, 0, destination);
            if (! message.write(mDevice)) {
                return false;
            }

            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    return false;
                }
            }
            return true;
        }

        public void handleMessage(AdbMessage message) {
            switch (message.getCommand()) {
                case AdbMessage.A_OKAY:
                    mPeerId = message.getArg0();
                    synchronized (this) {
                        notify();
                    }
                    break;
                case AdbMessage.A_WRTE:
                    mDevice.log(message.getDataString());
                    sendReady();
                    break;
            }
        }

        private void sendReady() {
            AdbMessage message = new AdbMessage();
            message.set(AdbMessage.A_OKAY, mId, mPeerId);
            message.write(mDevice);
        }
    }

这篇关于使用Andriod的USB主机API来阅读我的USB游戏手柄/或其他USB设备的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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