• Windows 和 Linux 系统下,如何区分相同PID VID 的USB-HID设备


    一、前言

    最近项目中,再次使用到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, 后后续操作中,根据这连个就可以区分出来。代码如下:

    1. // 2. 打开设备
    2. ret = libusb_open(dev, &handle);
    3. if (ret != LIBUSB_SUCCESS)
    4. {
    5. PrintError(ret);
    6. return -999;
    7. }
    8. // 3. 查看设备PID , VID 是否为目标的PIV 和 VID
    9. if (desc.idVendor != cmpVID || desc.idProduct != cmpPID)
    10. {
    11. //不是目标设备,退出
    12. ret = -999;
    13. goto Finish;
    14. }
    15. // 3.1 保存ID
    16. usbDeviceInfo->idVendor = desc.idVendor;
    17. usbDeviceInfo->idProduct = desc.idProduct;
    18. // 4. 发现目标设备, 保存设备描述符
    19. memset(&usbDeviceInfo->deviceDescriptor, 0, sizeof(libusb_device_descriptor));
    20. memcpy(&usbDeviceInfo->deviceDescriptor, &desc, sizeof(libusb_device_descriptor));
    21. // 4.1 保存设备路径
    22. bus = libusb_get_bus_number(dev);
    23. address = libusb_get_device_address(dev);
    24. //保存总线位置
    25. usbDeviceInfo->bus = bus;
    26. usbDeviceInfo->address = address;
    27. // 4.2 路径
    28. memset(usbDeviceInfo->devicePath, 0, sizeof(usbDeviceInfo->devicePath));
    29. 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);
    30. // 5. 获取设备序列号
    31. if (desc.iSerialNumber)
    32. {
    33. ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *)stringBuffer, sizeof(stringBuffer));
    34. if (ret > 0)
    35. {
    36. //保存序列号
    37. memset(usbDeviceInfo->serialNumber, 0, sizeof(usbDeviceInfo->serialNumber));
    38. strcpy(usbDeviceInfo->serialNumber, stringBuffer);
    39. }
    40. else
    41. {
    42. //失败
    43. PrintError(ret);
    44. ret = -1;
    45. goto Finish;
    46. }
    47. }

    综上,根据上述,将多个USB-HID设备插入,相同的PID 和 VID 设备,如何区分,并找到目标设备。

    终于完成记录,一个月之前说要写,拖到今天。。。。。。。。。。。

    /**
     *         ┏┓   ┏┓+ +
     *        ┏┛┻━━━┛┻┓ + +
     *        ┃       ┃
     *        ┃   ━   ┃ ++ + + +
     *        ████━████ ┃+
     *        ┃       ┃ +
     *        ┃   ┻   ┃
     *        ┃       ┃ + +
     *        ┗━┓   ┏━┛
     *          ┃   ┃
     *          ┃   ┃ + + + +
     *          ┃   ┃    Code is far away from bug with the animal protecting
     *          ┃   ┃ +    神兽保佑,代码无bug
     *          ┃   ┃
     *          ┃   ┃  +
     *          ┃    ┗━━━┓ + +
     *          ┃        ┣┓
     *          ┃        ┏┛
     *          ┗┓┓┏━┳┓┏┛ + + + +
     *           ┃┫┫ ┃┫┫
     *           ┗┻┛ ┗┻┛+ + + +
     *
     * @author chenxi
     * @date 2022年9月4日12:10:293
     */
    ————————————————
     

  • 相关阅读:
    WebSocket 协议详解
    表压0.1~0.6MPa范围内0.1%超高精度压力控制解决方案及其考核试验结果
    Kotlin 协程 (7/7篇) - 在Android中的使用
    react-to-vue使用教程
    SSM+校园社团平台 毕业设计-附源码251554
    go 极简后台管理-二次开发
    基于单片机的智能数字电子秤proteus仿真设计
    Window10安装PHP7.4
    Python居然开始抄作业了,这次抄的是Rust
    rnacos——用rust重新实现的nacos开源配置、注册中心服务
  • 原文地址:https://blog.csdn.net/gd6321374/article/details/126686582