目录
前言
上期讲到QT添加HIDAPI的库,这次来讲一下如何使用HIDAPI库函数来进行HID USB设备的读取描述符和简单的读写。
一、使用函数介绍
1.初始化以及释放函数
//非必要函数,调用hid_enumerate()和hid_open()都会自动调用它
hid_init(void);
//释放hidapi
hid_exit(void);
2.遍历HID USB函数
//传入vid和pid可以遍历该id下的所有接口号地址等数据并形成链表返回
//若是vid和pid=0则遍历所有hid usb数据并形成链表返回
hid_enumerate(unsigned short vendor_id, unsigned short product_id);
3.打开USB函数
//指定vid和pid打开,最后一个参数可以是NULL,返回句柄(不建议使用)
//该操作使用默认端口,不能自主选择
hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
//指定路径打开usb设备,返回句柄(建议使用)
hid_open_path(const char *path);
//释放链表,参数为hid_enumerate()返回的链表
hid_free_enumeration(struct hid_device_info *devs);
4.读写USB函数
//写操作
hid_write(hid_device *dev, const unsigned char *data, size_t length);
//设定阻塞读与非阻塞读 0为阻塞 1为非阻塞
hid_set_nonblocking(hid_device *dev, int nonblock);
//读操作
hid_read(hid_device *dev, unsigned char *data, size_t length);
二、HID USB链表结构体介绍
结构如下:
/** hidapi信息结构 */
struct hid_device_info {
/** 设备路径 */
char *path;
/** VID */
unsigned short vendor_id;
/** PID */
unsigned short product_id;
/** 序列号 */
wchar_t *serial_number;
/** 以二进制编码的十进制表示的设备版本号 */
unsigned short release_number;
/** 制造商字符串 */
wchar_t *manufacturer_string;
/** 产品字符串 */
wchar_t *product_string;
/** 此设备/界面的使用页面
(仅限Windows/Mac/hidraw) */
unsigned short usage_page;
/** 此设备/接口的用法
(仅限Windows/Mac/hidraw) */
unsigned short usage;
/** 设备接口号 */
int interface_number;
/** 连接到下一个 */
struct hid_device_info *next;
};
三、获取指定VID和PID的HID USB设备信息
1.获取设备的VID和PID
在windows下打开usb应该是需要root权限,建议用管理员模式打开QT不然容易异常退出。
两种方式:
1.自己写的下位机VID
和PID
自己决定。
2.使用Bus Hound获取,具体使用方式就不说了。
2.代码
int USB::hid_print(void)
{
hid_device_info *hid_info;//usb链表
/*打开指定VID PID设备*/
hid_info = hid_enumerate(0x5511,0x0011);
/*遍历所有信息并打印*/
for(;hid_info != nullptr;hid_info = hid_info->next){
qDebug("设备接口号:%d",hid_info->interface_number);
qDebug("厂商字符串:%ls",hid_info->manufacturer_string);
qDebug("设备字符串:%ls",hid_info->product_string);
qDebug("版本号:%d",hid_info->release_number);
qDebug("地址:%s",hid_info->path);
}
/*释放链表*/
hid_free_enumeration(hid_info);
return 0;
}
运行后可以看到以下数据:
和Bus Hound读取到的对比一致,证明读取每出错。
四、指定HID USB设备端口读写
1.hid_write()函数详解
我们都知道USB可以有很多个端口,每个端口有四种收发模式,这里的hid_write()
好像只能使用中断模式,正好符合我下位机端口的收发模式。我的下位机设定了端口收发最大字节为64,在hid_write()
发送的数组中,必须带有一位Report ID
这个要和下位机设定的一致,不然就会报参数错误。
所以hid_write()
发送的数组长度为64+1;
2.端口的选择
在第三点中我们已经遍历了该USB设备内的所有端口,这些端口被保存在上述USB链表内,因此我们需要找到我们要操作的端口号,并通过hid_open_path()
这个函数来打开,这样才能指定端口收发数据。
代码如下:
#define TX_MAXSIZE 64;
int USB::usb_write(void)
{
int res;
uint8_t buf[TX_MAXSIZE + 1];
hid_device *handle;//usb句柄
hid_device_info *hid_info;//usb链表
/*打开指定VID PID设备*/
hid_info = hid_enumerate(0x5511,0x0011);
for(;hid_info != nullptr;hid_info = hid_info->next){
if(hid_info->interface_number == 2)//接口匹配
{
qDebug("interface_number:%s",hid_info->path);//打印地址
break;
}
}
return 0;
}
3.数据发送
代码如下:
int USB::usb_write(void)
{
int res;
uint8_t buf[TX_MAXSIZE + 1];
hid_device *handle;//usb句柄
hid_device_info *hid_info;//usb链表
/*打开指定VID PID设备*/
hid_info = hid_enumerate(0x5511,0x0011);
for(;hid_info != nullptr;hid_info = hid_info->next){
if(hid_info->interface_number == 2)//接口匹配
{
qDebug("interface_number:%s",hid_info->path);//打印地址
break;
}
}
/*打开指定地址的设备*/
handle = hid_open_path(hid_info->path);
/*释放链表*/
hid_free_enumeration(hid_info);
buf[0] = 0x3f;//Report ID(自定义)
buf[1] = 0x21;//随便一点东西
buf[2] = 0x03;
buf[3] = 0x00;
buf[4] = 0x00;
buf[5] = 0x00;
res = hid_write(handle, buf, TX_MAXSIZE + 1);
if(res < 0){
/*返回值查看*/
qDebug("err_string = %ls\n",hid_error(handle));
}
return 0;
}
可以通过Bus Hound看到端点3已经收到我们发出来的消息了
3.数据接收
阻塞式接收代码,不收到消息不会退出:
int USB::usb_read(void)
{
int res;
uint8_t buf[64+1];
hid_device *handle;//usb句柄
hid_device_info *hid_info;//usb链表
/*打开指定VID PID设备*/
hid_info = hid_enumerate(0x5511,0x0011);
for(;hid_info != nullptr;hid_info = hid_info->next){
if(hid_info->interface_number == 2)//接口匹配
{
qDebug("interface_number:%s",hid_info->path);//打印地址
break;
}
}
/*打开指定地址的设备*/
handle = hid_open_path(hid_info->path);
/*释放链表*/
hid_free_enumeration(hid_info);
res = hid_read(handle, buf, 64+1);
if(res < 0){
/*返回值查看*/
qDebug("err_string = %ls\n",hid_error(handle));
}
/*阻塞*/
hid_set_nonblocking(handle, 0);
for(int i = 0;i<64;i++){
qDebug("buf[%d]:%02x",i,buf[i]);
}
return 0;
}
使用Bus Hound发送指令,可以看到已经收到下位机返回的消息(当然这个接收指令后返回消息的处理是在下位机写的)
总结
以上就是简单的hidapi收发消息操作,若有错误,欢迎指出。