Android 通过 USB 控制中继

Control relay over USB from Android

我有这个 USB Relay,我想通过 Android phone.

进行控制

(有一个类似的 post here 但它解释了如何从 Linux shell 开始。通过查看该代码我想我会能够解决它 - 显然不能。)

lsusb 中的设备列表:


Bus 002 Device 011: ID 16c0:05df VOTI 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x16c0 VOTI
  idProduct          0x05df 
  bcdDevice            1.00
  iManufacturer           1 
  iProduct                2 
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           34
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower               20mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.01
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      22
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              20

我觉得很奇怪,终点定义为"EP IN"。在我看来应该是 "EP OUT" 因为方向应该是 "host->device".

无论如何,我使用 Android USB 管理器创建连接,然后为基于中断的端点初始化 USbRequest。 Android 权限和所有已处理的设备连接成功。

用于发送数据的代码段。它按照 Android 准则在单独的线程中运行:

UsbRequest request = new UsbRequest();
synchronized (mUsbLock) {
    if (mUsbConnection != null && mUsbEndPointIn != null) {
        if (!request.initialize(mUsbConnection, mUsbEndPointIn)) {
            Log.e(TAG, "Unable to initialize UsbRequest. Thread exits");
            return;
        } else {
            if (DEBUG) {
                Log.d(TAG, String.format("Usb request is initialized"));
            }
        }
    } else {
        Log.e(TAG, "Usb communication is not up and running. The worker thread should never be started.");
        return;
    }
}
mRunning.set(true);
while (mRunning.get()) {
    if (DEBUG) {
        Log.d(TAG, String.format("Waiting for data to be sent to end point"));
    }
    WorkPackage wp = mWorkQueue.take();
    // send the package.
    byte[] data = wp.getData();
    if (!request.queue(ByteBuffer.wrap(data), data.length)) {
        Log.e(TAG, "Unable to queue to send data on UsbRequest.");
        continue;
    } else {
        if (DEBUG) {
            Log.d(TAG, String.format("Usb request is queued on end point, ep=%s", printUsbEndpoint(mUsbEndPointIn)));
        }
    }
}

似乎一切都很好,没有发生错误,请求在终点排队,但随后什么也没有发生。我没有收到任何关于请求已处理的消息。

由于供应商不会发布 on/off 命令,我尝试了基于 Linux post(上文)的变体。 None 似乎有效。供应商仅发布 Windows 二进制库。

发送8字节包(根据最大包):

public static byte[] SET_RELAY_ON = {(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
public static byte[] SET_RELAY_OFF = {(byte) 0xfd, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};

感谢帮助。

所以,我想出了如何做到这一点。我会在这里写下解决方案,以防其他人遇到类似问题。

我不得不窥探 USB 流量以了解实际发送的内容。结果发现根本没有使用定义的中断端点。因此,与设备的通信不是基于中断的,而是使用端点 0 上的控制传输类型。

所以,使用 Android USB API 这转化为:

开启设备(设备->主机方向):

int r = mUsbConnection.controlTransfer(0xa1, 0x01, 0x0300, 0x00, buffer, buffer.length, 500);

打开继电器'1'(主机->设备方向)。

byte[] buffer = {(byte) 0xff, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
int r = mUsbConnection.controlTransfer(0x21, 0x09, 0x0300, 0x00, buffer, buffer.length, 500);

注意,缓冲区 (0x01) 中的第二个参数是继电器编号(如果板上有 >1 个继电器)。我只有一个。

关闭继电器'1'(主机->设备方向):

byte[] buffer = {(byte) 0xfd, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
int r = mUsbConnection.controlTransfer(0x21, 0x09, 0x0300, 0x00, buffer, buffer.length, 500);