Android USB 主机通信

发布于 2024-12-28 10:55:03 字数 2113 浏览 3 评论 0原文

我正在开发一个利用 Android 3.2 中 USB 主机功能的项目。我非常缺乏有关 USB/串行通信的知识和人才。我也无法找到任何适合我需要做的事情的好的示例代码。

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

>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) 发送“开始”命令。 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);
  }

I'm working on a project that utilizes the USB Host capabilities in Android 3.2. I'm suffering from a deplorable lack of knowledge and talent regarding USB/Serial communication in general. I'm also unable to find any good example code for what I need to do.

I need to read from a USB Communication Device.
Ex: When I connect via Putty (on my PC) I enter:

>GO

And the device starts spewing out data for me. Pitch/Roll/Temp/Checksum.

Ex:

$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

I can send the initial 'GO' command from the Android device at which time I receive an echo of 'GO'.

Then nothing else on any subsequent reads.

How can I:
1) Send the 'go' command.
2) Read in the stream of data that results.

The USB device I'm working with has the following interfaces (endpoints).

Device Class: Communication Device (0x2)

Interfaces:

Interface #0
Class: Communication Device (0x2)
Endpoint #0
Direction: Inbound (0x80)
Type: Intrrupt (0x3)
Poll Interval: 255
Max Packet Size: 32
Attributes: 000000011

Interface #1
Class: Communication Device Class (CDC) (0xa)
Endpoint #0
Address: 129
Number: 1
Direction: Inbound (0x80)
Type: Bulk (0x2)
Poll Interval (0)
Max Packet Size: 32
Attributes: 000000010

Endpoint #1
Address: 2
Number: 2
Direction: Outbound (0x0)
Type: Bulk (0x2)
Poll Interval (0)
Max Packet Size: 32
Attributes: 000000010

I'm able to deal with permission, connect to the device, find the correct interface and assign the endpoints. I'm just having trouble figuring out which technique to use to send the initial command read the ensuing data. I'm tried different combinations of bulkTransfer and controlTransfer with no luck.

Thanks.

I'm using interface#1 as seen below:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

桃酥萝莉 2025-01-04 10:55:03

我讨厌回答我自己的问题,但是......我已经弄清楚了。我只是混淆了我的阅读和写作。此外,该设备不喜欢我在命令末尾使用的“\n”。它似乎与 '\r' 相处得更好。

我最终使用android的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 {
    }

}

I hate to answer my own question but... I got it figured out. I was just mixing up my reads and writes. Additionally the device didn't like the '\n' I was using at the end of my commands. It appears to get along with '\r' much better.

I ended up using android's bulkTransfer for reads and writes. My writes looked like this.

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

And my overridden write method for my 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);
  }

The reads were similar:

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

And:

@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;
  }

This was all just kicked off in a thread like so:

new Thread() {
    @Override
public void run() {

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

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

Obviously this is just the comm stuff and I'll need to now do something with it (put it in a Service that can report back to a top level UI Activity using a handler). But this part of it is figured out.

A huge thank you to the folks who are working on rosjava (http://code.google.com/p/rosjava/)... They have put together a lot of great projects and their code was very helpful.

Adding my device class to help clarify things.

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

Adding BKReader code:

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 {
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文