Android APP给HID设备发送指令
很多便携设备都需要连接到电脑才能工作。例如LED控制卡,在调试LED控制卡的时候需要连接到电脑上,通过电脑给控制卡发送数据或者指令,验证控制卡功能是否正常。有时候出门在外,不方便携带电脑,这个时候可以考虑用手机作为便携电脑,手机通过USB连接到LED控制卡。然后手机通过HID通讯协议给LED控制卡发数据和指令,测试LED卡的功能是否正常。
Android APP连接HID需要用到下面这些类和接口
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
首先需要从系统获取一个 UsbManager 对象 mUsbManager
然后通过 mUsbManager.getDeviceList() 查询系统有哪些USB设备,查询结果保存在一个HashMap 里面
通过 Iterator 遍历 hashMap 里面所有的UsbDevice 设备。可以根据PID和VID 来获取指定的USB设备。
1:获取到UsbDevice设备后,通过 mUsbManager.openDevice(); 连接到指定的USB设备,获取到一个 UsbDeviceConnection 对象。
2: 获取到UsbDevice设备对象后,获取设备的接口和端点
第一步链接到USB设备后,通过 UsbDeviceConnection.bulkTransfer() 给设备发送指令
遇到的问题
业务代码完成后APP并不能正常连接到USB设备,需要两步解决这个问题
1:在androidManifest.xml 中申请USB控制的权限
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
2:虽然申请了权限, 但是openDevice() 的时候还是会报没有USB权限。这是因为虽然在 androidManifest.xml 中申请了权限,
但是这个权限并没有被系统认可。
所以需要在 androidManifest.xml 中添加一个 Intent,用于在USB连接的时候弹出一个对话框,允许自己的APP使用USB。
这样操作结束后才可以真的打开 USB,并给USB发数据。
添加到 <Activity> 节点里面的配置。注意大小写。
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:value="@string/app_name"
android:resource="@xml/device_filter" />
3:<meta-data> 里面指定了一个 xml 文件 device_filter ,该文件里面定义了允许操作哪些USB设备。通过PID VID 来指定USB设备。
device_filter 里面定义格式如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 0x0403 / 0x6001: FTDI FT232R UART -->
<usb-device vendor-id="7247" product-id="18" />
<!-- 0x0403 / 0x6015: FTDI FT231X -->
<usb-device vendor-id="1027" product-id="24597" />
</resources>
这里面定义了两个USB设备,当具备这两个PID/VID 的设备连接到手机的时候,会自动打开我们的APP。
然后就可以在APP里面操作HID设备了
下面是一个简单的测试代码,可以直接使用
package com.xseayu.hid;
import android.app.Activity;
import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.xseayu.hid.databinding.ActivityMainBinding;
import java.util.HashMap;
import java.util.Iterator;
public class MainActivity extends Activity {
private ActivityMainBinding binding;
private UsbDeviceConnection mConnectionWrite = null;
UsbDevice mMouse = null;
UsbEndpoint mMouseData = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
TextView info = findViewById(R.id.textView);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
byte[] send = {0x01,0x02,0x03,0x04,0x05};
mConnectionWrite.bulkTransfer(mMouseData,send,5,1000);
}
});
UsbManager ums = (UsbManager) getSystemService(Context.USB_SERVICE);
StringBuffer sb = new StringBuffer();
HashMap<String, UsbDevice> deviceList = ums.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while (deviceIterator.hasNext()){
if(device.getVendorId() == 7247){
mMouse = device;
mMouseData = device.getInterface(1).getEndpoint(0);
break;
}
}
mConnectionWrite = ums.openDevice(mMouse);
sb.append("mMouse=null-----"+(mMouse == null)+"\n");
sb.append("mMouseData=null----"+(mMouseData == null)+"\n");
sb.append("mConnectionWrite=null-----"+(mConnectionWrite == null)+"\n");
info.setText(sb.toString());
}
}