安卓USB主机通信

16

我正在开发一个利用Android 3.2中的USB主机功能的项目。 我在USB /串行通信方面缺乏知识和技能。 我也无法找到所需操作的任何好的示例代码。

我需要从USB通信设备中读取数据。
例如:当我通过我的PC上的Putty连接时,我输入:

>GO

设备开始为我输出数据。包括俯仰/翻滚/温度/校验和。

例如:

$R1.217P-0.986T26.3*60
$R1.217P-0.986T26.3*60
$R1.217P-0.987T26.3*61
$R1.217P-0.986T26.3*60
$R1.217P-0.985T26.3*63

我可以从Android设备发送初始的“GO”命令,此时我会收到“GO”的回显。

然后在任何后续读取中都没有其他数据。

我该如何做到: 1)发送“go”命令。 2)读取结果产生的数据流。

我正在使用的USB设备具有以下接口(端点)。

设备类:通信设备(0x2)

接口:

接口#0 类别:通信设备(0x2) 端点#0 方向:入站(0x80) 类型:中断(0x3) 轮询间隔:255 最大数据包大小:32 属性:000000011

接口#1 类别:通信设备类(CDC)(0xa) 端点#0 地址:129 数量:1 方向:入站(0x80) 类型:块(0x2) 轮询间隔(0) 最大数据包大小:32 属性:000000010

端点#1 地址:2 数量:2 方向:出站(0x0) 类型:块(0x2) 轮询间隔(0) 最大数据包大小:32 属性:000000010

我已经处理好了权限、连接到设备、找到正确的接口并分配端点。但是我在确定使用哪种技术来发送初始命令并读取随后的数据时遇到了困难。我已经尝试了不同组合的bulkTransfer和controlTransfer但没有成功。

谢谢。

如下所示,我正在使用接口#1:

public AcmDevice(UsbDeviceConnection usbDeviceConnection, UsbInterface usbInterface) {
    Preconditions.checkState(usbDeviceConnection.claimInterface(usbInterface, true));
    this.usbDeviceConnection = usbDeviceConnection;

    UsbEndpoint epOut = null;
    UsbEndpoint epIn = null;
    // look for our bulk endpoints
    for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
      UsbEndpoint ep = usbInterface.getEndpoint(i);
     Log.d(TAG, "EP " + i + ": " + ep.getType());
      if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
        if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
          epOut = ep;

        } else if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
          epIn = ep;
        }

      }
    }
    if (epOut == null || epIn == null) {
      throw new IllegalArgumentException("Not all endpoints found.");
    }

    AcmReader acmReader = new AcmReader(usbDeviceConnection, epIn);
    AcmWriter acmWriter = new AcmWriter(usbDeviceConnection, epOut);
    reader = new BufferedReader(acmReader);
    writer = new BufferedWriter(acmWriter);
  }

对于我们中的一些人来说,您是如何选择接口1的?接口0,即中断接口,将用于什么目的?谢谢! - Rachael
1个回答

13
我不想回答自己的问题,但是...我已经弄清楚了。我只是混淆了我的读写操作。此外,设备不喜欢我在命令末尾使用的 '\n'。它似乎更喜欢 '\r'。

最终我使用了安卓的bulkTransfer进行读写操作。我的写操作如下:

    try {
            device.getWriter().write(command + "\r");
            device.getWriter().flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

我的BufferedWriter覆盖写方法:
@Override
  public void write(char[] buf, int offset, int count) throws IOException {
    byte[] buffer = new String(buf, offset, count).getBytes(Charset.forName("US-ASCII"));
    int byteCount = connection.bulkTransfer(endpoint, buffer, buffer.length, TIMEOUT);
  }

这些读数相似:

    char[] buffer = new char[BUF_SIZE];
    try {
        BufferedReader reader = device.getReader();

        int readBytes = reader.read(buffer);
        Log.d(TAG, "BYTES READ: " + readBytes);

    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    String strBuf = new String(buffer).trim();
    if (DEBUG) {
        Log.d(TAG, "Read: " + strBuf);
    }

并且:

@Override
  public int read(char[] buf, int offset, int count) throws IOException {
    byte[] buffer = new byte[count];
    int byteCount = connection.bulkTransfer(endpoint, buffer, buffer.length, TIMEOUT);

    if (byteCount < 0) {
      throw new IOException();
    }
    char[] charBuffer = new String(buffer, Charset.forName("US-ASCII")).toCharArray();
    System.arraycopy(charBuffer, 0, buf, offset, byteCount);
    return byteCount;
  }

这一切都是在一个线程中开始的,就像这样:
new Thread() {
    @Override
public void run() {

    String command = "go";
    write(command);

    while (true) {
        String coords = read(); 
        }
}
}.start();

显然,这只是通讯部分,我现在需要对其进行处理(将其放入服务中,使用处理程序向顶层UI活动报告)。但这部分已经想清楚了。
非常感谢那些正在开发rosjava(http://code.google.com/p/rosjava/)的人们……他们已经组合了许多优秀的项目,他们的代码非常有帮助。
添加我的设备类以帮助澄清事情。
import com.google.common.base.Preconditions;

import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;

import java.io.BufferedReader;
import java.io.BufferedWriter;

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

// private static final int TIMEOUT = 3000;

private final UsbDeviceConnection usbDeviceConnection;
private final BufferedReader reader;
private final BufferedWriter writer;
public static final String TAG = "AcmDevice";

public BKDevice(UsbDeviceConnection usbDeviceConnection,
        UsbInterface usbInterface) {
    Preconditions.checkState(usbDeviceConnection.claimInterface(
            usbInterface, true));
    this.usbDeviceConnection = usbDeviceConnection;

    UsbEndpoint epOut = null;
    UsbEndpoint epIn = null;
    // look for our bulk endpoints
    for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
        UsbEndpoint ep = usbInterface.getEndpoint(i);
        Log.d(TAG, "EP " + i + ": " + ep.getType());

        if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
            if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                epOut = ep;

            } else if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
                epIn = ep;

            }
        }
    }
    if (epOut == null || epIn == null) {
        throw new IllegalArgumentException("Not all endpoints found.");
    }

    BKReader acmReader = new BKReader(usbDeviceConnection, epIn);
    BKWriter acmWriter = new BKWriter(usbDeviceConnection, epOut);

    reader = new BufferedReader(acmReader);
    writer = new BufferedWriter(acmWriter);
}

public BufferedReader getReader() {
    return reader;
}

public BufferedWriter getWriter() {
    return writer;
}
}

添加BKReader代码:

import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.util.Log;

import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;

public class BKReader extends Reader {

    private static final int TIMEOUT = 1000;

    private final UsbDeviceConnection connection;
    private final UsbEndpoint endpoint;

    public BKReader(UsbDeviceConnection connection, UsbEndpoint endpoint) {
        this.connection = connection;
        this.endpoint = endpoint;
    }

    @Override
    public int read(char[] buf, int offset, int count) throws IOException {
        byte[] buffer = new byte[count];
        int byteCount = connection.bulkTransfer(endpoint, buffer, buffer.length, TIMEOUT);

        if (byteCount < 0) {
          throw new IOException();
        }
        char[] charBuffer = new String(buffer, Charset.forName("US-ASCII")).toCharArray();
        System.arraycopy(charBuffer, 0, buf, offset, byteCount);
        return byteCount;
    }

    @Override
    public void close() throws IOException {
    }

}

我的设备类包含了一个 BufferedWriter。getWriter 方法返回该对象。因此, flush() 只是将流刷新。为了帮助你,我会把我的类代码粘贴在上面。 - K.R.
@K.R. 你应该接受这个答案。它是一个非常有用的解决方案,也是仅有几个带有答案和代码示例的USB主机问题之一。谢谢 :) - Rachael
@K.R. 这帮助了我很多,谢谢。问题:如果您想要在使用BulkTransfer的同时使用中断端点接口,那么您是否会创建一个InterruptDevice类对象并与BulkTransfer一起使用,并且如果是,那么在该端点上进行什么通信?此外,需要采取哪些步骤才能正确关闭端点/设备上的通信?再次感谢! - Rachael
@Rachael,非常抱歉错过了你的问题。老实说,我不太确定 :-) 我已经很久没有处理这个问题了。我会尝试找到原始来源并看看能否提供帮助...如果你在此期间找到答案,请告诉我。 - K.R.
@K.R. 经过一番波折,我 终于 让我的自己的库起作用了。我仍在进行测试和优化,但我计划将代码发布到Github上。那里的很多东西都太抽象了,或者源代码没有公开。缓冲数据和查询以创建非阻塞流是最大的挑战,因为Android文档对我来说不够详细。它也非常依赖于设备,无论它是否需要控制传输,或批量传输,发送命令之间的等待时间,以及用于从设备读取流的缓冲方法。 - Rachael
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接