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);
我有这个 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);