一、前言
最近项目中,再次使用到USB设备,而项目需要是在系统中,也就是一台电脑同时使用两个USB涉设备。这两个USB设备,底层固件一模一样,因此,两个设备在系统中枚举出来的 PID 和 VID 是一样的。由于以前项目上,一般都是使用一个设备,在使用代码查找目标HID 设备时,都是只使用PID 和 VID 。因此,如何解决,在一个操作系统中,怎么区分相同PID 和 VID 两个设备,并同时与其通讯,由此,写下这篇文章记录。
二、关于USB-HID设备
可以查看我之前的文章,已经分享很多篇,这里不再赘述。
三、在系统中如何区分相同PIV 和 VID 的USB-HID 设备
1. 在windows 使用 USB-TreeView 软件查看,usb 设备的详细信息,
2. 根据USB规范的定义,所有的USB设备都用供应商ID(VID)和产品识别码(PID),主机通过不同的VID和PID来区别不同的设备,VID和PID都是两个字节长,其中,VID由供应商向USB执行论坛申请,每个供应商的VID是唯一的,PID由供应商自行决定,理论上来说,不同的产品、相同产品的不同型号、相同型号的不同设计的产品最好采用不同的PID,以便区别相同厂家的不同设备。
3. 但是呢, 在实际上由于设备厂家为了方便,一般相同型号的设备,PID 和 VID 都是一样的,很少会去给每个设备分配不同的ID。并且,同款产品,每个设备要保证PID 和 VID 不同,是非常困难的一件事情,并且成本高。
4. 在实际更多的厂家中,为了方便管理,不同型号的usb设备,其设备的PID 和 VID 都是一样。
这样子操作对于开发者都是非常方便。
5. 当有多个vid,pid相同的usb设备一起插入到电脑上,他们在系统的USB是通用串行总线上都是可以识别出来的。因此当一个usb 设备插入总线上会自动分配一个地址给该设备,每个设备都具有唯一的地址。
因此,当上面,提到当有多个vid,pid相同的usb设备一起插入到电脑上,usb 设备总线,也会分别给它们在分配一个地址,这个地址在总线上是唯一的,不会重复。
7. 根据上面所述,可以的得出,假设,有多个vid,pid相同的usb设备一起插入到电脑上,如何来区分到底是哪一个usb设备?可以根部不同设备在USB总线上地址来区分。
四、在Windows上
1. 使用Win API 寻找USB设备,在获读取设备的信息,可以看到返回设备的地址,如图
这个是设备在系统中唯一的地址,具体代码如下,
当遇到,目标设备的PID 和 VID 保存对应的strtDetailData->DevicePath, 即可,后续使用时,直接调用CreateFile(), 打开设备记录。
strtDetailData->DevicePath 每个设备不一样,可以确保操作的是目标设备。
五,在Linux 系统上
在linux操作,一般使用的是libusb, 使用libusb 库中的testlibusb 例程,调用打印可以发现
将相同USB-HID设备插入,可以找到相同的PID 和 VID 设备,同时会输出它们的 在USB设备总线上的地址。
在查找时,需要保存这些设备的bus 和 addr, 后后续操作中,根据这连个就可以区分出来。代码如下:
// 2. 打开设备
ret = libusb_open(dev, &handle);
if (ret != LIBUSB_SUCCESS)
{
PrintError(ret);
return -999;
}
// 3. 查看设备PID , VID 是否为目标的PIV 和 VID
if (desc.idVendor != cmpVID || desc.idProduct != cmpPID)
{
//不是目标设备,退出
ret = -999;
goto Finish;
}
// 3.1 保存ID
usbDeviceInfo->idVendor = desc.idVendor;
usbDeviceInfo->idProduct = desc.idProduct;
// 4. 发现目标设备, 保存设备描述符
memset(&usbDeviceInfo->deviceDescriptor, 0, sizeof(libusb_device_descriptor));
memcpy(&usbDeviceInfo->deviceDescriptor, &desc, sizeof(libusb_device_descriptor));
// 4.1 保存设备路径
bus = libusb_get_bus_number(dev);
address = libusb_get_device_address(dev);
//保存总线位置
usbDeviceInfo->bus = bus;
usbDeviceInfo->address = address;
// 4.2 路径
memset(usbDeviceInfo->devicePath, 0, sizeof(usbDeviceInfo->devicePath));
snprintf(usbDeviceInfo->devicePath, sizeof(usbDeviceInfo->devicePath), ": /?/USB#VID_%.4X&PID_%.4X#%d&%d#{bus-%.3d-address-%.3d}#(GUID_DEVINTERFACE_USB_DEVICE)", desc.idVendor, desc.idProduct, bus, address, bus, address);
// 5. 获取设备序列号
if (desc.iSerialNumber)
{
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *)stringBuffer, sizeof(stringBuffer));
if (ret > 0)
{
//保存序列号
memset(usbDeviceInfo->serialNumber, 0, sizeof(usbDeviceInfo->serialNumber));
strcpy(usbDeviceInfo->serialNumber, stringBuffer);
}
else
{
//失败
PrintError(ret);
ret = -1;
goto Finish;
}
}
综上,根据上述,将多个USB-HID设备插入,相同的PID 和 VID 设备,如何区分,并找到目标设备。
终于完成记录,一个月之前说要写,拖到今天。。。。。。。。。。。
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████ ┃+
* ┃ ┃ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃
* ┃ ┃ + + + +
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ + 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃ +
* ┃ ┗━━━┓ + +
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*
* @author chenxi
* @date 2022年9月4日12:10:293
*/
————————————————