当前位置: 首页 > news >正文

【Linux C/C++开发】libusb库操作-获取USB设备信息

前言

        USB设备比较常见,lisusb是开源的USB操作库,多个平台都可用(python也封装有libusb模块),以下分享linux下的USB消息获取。

关联博文

https://blog.csdn.net/liangyuna8787/article/details/153978124?spm=1001.2014.3001.5502https://blog.csdn.net/liangyuna8787/article/details/153978124?spm=1001.2014.3001.5502 之前分享了在Linux下,响应插入/拔插USB设备事件,但推送的信息不够详细,以下通过libusb库获取详细的信息。

获取USB设备信息

函数名称

所属类别

功能描述

返回值说明

使用场景

libusb_init()

库初始化

初始化 libusb 库,创建上下文

0 成功,<0 错误码

程序启动时初始化 USB 库

libusb_exit()

库清理

清理 libusb 资源,关闭上下文

程序退出时清理资源

libusb_open_device_with_vid_pid()

设备操作

通过 VID/PID 打开指定设备

设备句柄或 NULL

根据厂商ID和产品ID打开特定设备

libusb_get_device()

设备信息

从设备句柄获取设备对象

对应的设备对象

获取设备基本信息时需要

libusb_get_device_descriptor()

设备描述符

获取设备描述符信息

0 成功,<0 错误码

读取设备的基本信息(VID/PID等)

libusb_close()

设备操作

关闭 USB 设备句柄

设备使用完毕后释放资源

libusb_get_device_list()

设备枚举

获取系统中所有 USB 设备列表

设备数量或错误码

枚举所有连接的 USB 设备

libusb_free_device_list()

资源释放

释放设备列表占用的内存

设备列表使用完毕后清理内存

libusb_open()

设备操作

打开指定的 USB 设备

0 成功,<0 错误码

打开特定设备进行通信

libusb_get_string_descriptor_ascii()

字符串操作

获取字符串描述符(ASCII格式)

实际读取长度或错误码

读取设备名称、厂商信息等字符串

libusb_get_bus_number()

拓扑信息

获取设备所在的总线号

总线编号

设备定位和识别

libusb_get_device_address()

拓扑信息

获取设备在总线上的地址

设备地址

设备定位和识别

libusb_get_config_descriptor()

配置描述符

获取设备的配置描述符

0 成功,<0 错误码

读取设备的接口和端点配置信息

libusb_free_config_descriptor()

资源释放

释放配置描述符内存

配置描述符使用完毕后清理内存

下面提供打包为so动态库的源码,动态库提供了两个核心功能:通过vidpid获取USB设备信息和获取区别USB设备信息

//USBDeviceInfo.h
#ifndef USB_DEVICE_INFO_H
#define USB_DEVICE_INFO_H#include <cstdint>
#include <set>
#include <string>
#include <vector>#ifdef __cplusplus
extern "C" {
#endif//USB设备信息结构体
typedef struct UsbMsg {uint16_t vid;                   //厂商IDuint16_t pid;                   //产品IDuint8_t Bus;                    //总线号uint8_t Device;                 //设备地址std::set<uint8_t> subclass_set; //设备子类集合std::string name;               //设备名称uint16_t Version;               //USB版本
} stUsbMsg;void* create_usb_device_info();
void destroy_usb_device_info(void* obj);
bool usb_device_info_initialize(void* obj);
void usb_device_info_cleanup(void* obj);
stUsbMsg usb_device_info_get_device_info(void* obj, uint16_t vendorId, uint16_t productId);
void usb_device_info_get_all_devices(void* obj, stUsbMsg** devices, size_t* count);
void free_usb_devices_array(stUsbMsg* devices, size_t count);
const char* usb_device_info_get_class_name(void* obj, uint8_t class_code);#ifdef __cplusplus
}
#endif#endif //USB_DEVICE_INFO_H
// USBDeviceInfo.cpp
#include "USBDeviceInfo.h"
#include <libusb-1.0/libusb.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstring>// USB设备信息实现类
class USBDeviceInfoImpl {
public:// 构造函数:初始化上下文为nullptrUSBDeviceInfoImpl() : context(nullptr) {}// 析构函数:自动清理资源~USBDeviceInfoImpl() {cleanup();}// 根据设备类代码获取设备类名称const std::string get_device_class_name(uint8_t class_code) {switch (class_code) {case 0x00: return "接口定义类";        // 设备类在接口描述符中定义case 0x01: return "音频设备";          // 音频设备类case 0x02: return "通信设备";          // 通信设备类(CDC)case 0x03: return "HID设备";           // 人机接口设备case 0x05: return "物理设备";          // 物理设备类case 0x06: return "图像设备";          // 图像设备类(如摄像头)case 0x07: return "打印机";            // 打印机设备类case 0x08: return "大容量存储设备";    // 大容量存储设备(U盘、移动硬盘)case 0x09: return "集线器";            // USB集线器case 0x0A: return "CDC数据设备";       // CDC数据设备case 0x0B: return "智能卡设备";        // 智能卡读卡器case 0x0D: return "内容安全设备";      // 内容安全设备case 0x0E: return "视频设备";          // 视频设备类case 0x0F: return "个人医疗设备";      // 个人医疗设备case 0x10: return "音频/视频设备";     // 音频视频设备类case 0xDC: return "诊断设备";          // 诊断设备类case 0xE0: return "无线控制器";        // 无线控制器(蓝牙、WiFi等)case 0xEF: return "杂项设备";          // 杂项设备类case 0xFE: return "特定应用设备";      // 特定应用设备case 0xFF: return "厂商自定义设备";    // 厂商自定义设备类default: return "未知设备类";          // 未知的设备类代码}}// 初始化libusb库bool initialize() {// 初始化libusb上下文int result = libusb_init(&context);if (result != 0) {std::cerr << "初始化libusb失败: " << libusb_error_name(result) << std::endl;return false;}return true;}// 清理libusb资源void cleanup() {if (context) {libusb_exit(context);  // 释放libusb上下文context = nullptr;     // 重置指针为空}}// 根据VID和PID获取特定设备信息stUsbMsg getDeviceInfo(uint16_t vendorId, uint16_t productId) {stUsbMsg result;  // 创建返回结果结构体// 通过VID和PID打开设备libusb_device_handle* deviceHandle = libusb_open_device_with_vid_pid(context, vendorId, productId);if (!deviceHandle) {return result;  // 打开失败返回空结果}// 获取设备对象libusb_device* device = libusb_get_device(deviceHandle);libusb_device_descriptor descriptor;// 获取设备描述符int ret = libusb_get_device_descriptor(device, &descriptor);if (ret == 0) {// 成功获取描述符,格式化设备信息result = formatDeviceInfo(deviceHandle, descriptor, device);}// 关闭设备句柄libusb_close(deviceHandle);return result;}// 获取系统中所有USB设备信息std::vector<stUsbMsg> getAllDevices() {std::vector<stUsbMsg> devices;  // 设备信息列表libusb_device** deviceList;     // 设备列表指针// 获取USB设备列表ssize_t count = libusb_get_device_list(context, &deviceList);if (count < 0) {return devices;  // 获取失败返回空列表}// 遍历所有设备for (ssize_t i = 0; i < count; ++i) {libusb_device_descriptor desc;// 获取设备描述符if (libusb_get_device_descriptor(deviceList[i], &desc) == 0) {libusb_device_handle* handle;// 打开设备以获取更多信息if (libusb_open(deviceList[i], &handle) == 0) {// 格式化设备信息并添加到列表devices.push_back(formatDeviceInfo(handle, desc, deviceList[i]));libusb_close(handle);  // 关闭设备句柄}}}// 释放设备列表内存libusb_free_device_list(deviceList, 1);return devices;}private:libusb_context* context;  // libusb上下文指针// 将16位数值转换为16进制字符串(4位宽度)std::string toHex(uint16_t value) {std::stringstream ss;ss << std::hex << std::setw(4) << std::setfill('0') << value;return ss.str();}// 获取字符串描述符std::string getStringDescriptor(libusb_device_handle* handle, uint8_t index) {if (index == 0) return "";  // 索引为0表示无字符串描述符unsigned char buffer[256];  // 字符串缓冲区// 获取ASCII格式的字符串描述符int length = libusb_get_string_descriptor_ascii(handle, index, buffer, sizeof(buffer));if (length > 0) {// 成功获取字符串,转换为std::stringreturn std::string(reinterpret_cast<char*>(buffer), length);}return "";  // 获取失败返回空字符串}// 格式化设备信息为stUsbMsg结构stUsbMsg formatDeviceInfo(libusb_device_handle* handle, const libusb_device_descriptor& desc, libusb_device* dev) {std::set<uint8_t> subclass_set;  // 子类集合(去重)subclass_set.clear();stUsbMsg result;  // 返回结果结构体// 获取总线号和设备地址result.Bus = libusb_get_bus_number(dev);result.Device = libusb_get_device_address(dev);// 获取USB版本、厂商ID、产品IDresult.Version = desc.bcdUSB;result.vid = desc.idVendor;result.pid = desc.idProduct;// 尝试获取设备名称(按优先级:制造商→产品→序列号)std::string usbname = getStringDescriptor(handle, desc.iManufacturer);if(usbname == "") usbname = getStringDescriptor(handle, desc.iProduct);if(usbname == "") usbname = getStringDescriptor(handle, desc.iSerialNumber);result.name = usbname;// 获取配置描述符以分析接口信息libusb_config_descriptor* config;int ret = libusb_get_config_descriptor(dev, 0, &config);  // 获取第一个配置if (ret == 0 && config) {// 遍历所有接口for (int i = 0; i < config->bNumInterfaces; i++) {const libusb_interface* interface = &config->interface[i];// 遍历接口的所有备用设置for (int j = 0; j < interface->num_altsetting; j++) {const libusb_interface_descriptor* iface_desc = &interface->altsetting[j];uint8_t subclass = iface_desc->bInterfaceClass;  // 获取接口类代码subclass_set.insert(subclass);  // 添加到集合(自动去重)}}// 释放配置描述符内存libusb_free_config_descriptor(config);}// 设置子类集合result.subclass_set = subclass_set;return result;}
};// C风格接口实现(用于C语言或其他语言调用)
extern "C" {// 创建USB设备信息对象
void* create_usb_device_info() {return new USBDeviceInfoImpl();  // 返回新创建的对象指针
}// 销毁USB设备信息对象
void destroy_usb_device_info(void* obj) {delete static_cast<USBDeviceInfoImpl*>(obj);  // 删除对象并释放内存
}// 初始化USB设备信息库
bool usb_device_info_initialize(void* obj) {return static_cast<USBDeviceInfoImpl*>(obj)->initialize();
}// 清理USB设备信息库资源
void usb_device_info_cleanup(void* obj) {static_cast<USBDeviceInfoImpl*>(obj)->cleanup();
}// 根据VID和PID获取特定设备信息
stUsbMsg usb_device_info_get_device_info(void* obj, uint16_t vendorId, uint16_t productId) {return static_cast<USBDeviceInfoImpl*>(obj)->getDeviceInfo(vendorId, productId);
}// 获取所有USB设备信息(返回数组形式)
void usb_device_info_get_all_devices(void* obj, stUsbMsg** devices, size_t* count) {// 获取设备列表vectorstd::vector<stUsbMsg> devList = static_cast<USBDeviceInfoImpl*>(obj)->getAllDevices();*count = devList.size();  // 设置设备数量// 动态分配数组内存*devices = new stUsbMsg[*count];// 将vector内容复制到数组for (size_t i = 0; i < *count; ++i) {(*devices)[i] = devList[i];}
}// 释放USB设备信息数组内存
void free_usb_devices_array(stUsbMsg* devices, size_t count) {delete[] devices;  // 释放动态分配的数组
}// 根据设备类代码获取类名称(C字符串形式)
const char* usb_device_info_get_class_name(void* obj, uint8_t class_code) {static std::string result;  // 静态变量保证返回的C字符串有效result = static_cast<USBDeviceInfoImpl*>(obj)->get_device_class_name(class_code);return result.c_str();  // 返回C风格字符串
}} // extern "C"

makefile文件内容如下:

DEBUG_FLAGS= -fPIC -g -D__MUTEX
LIB_FLAGS=
SO_OBJ=libusbDevinfo.so
CC=g++$(SO_OBJ):USBDeviceInfo.cpp$(CC) -shared -o $(SO_OBJ) USBDeviceInfo.cpp $(DEBUG_FLAGS) $(LIB_FLAGS).PHONEY:cleanclean:rm *.so *.o $(SO_OBJ) -f

执行make之后,生成动态库libusbDevinfo.so,下面是引用libusbDevinfo.so的示例代码:

//main.cpp
#include "USBDeviceInfo.h"
#include <iostream>
#include <iomanip>
#include <vector>void show_device_info(const stUsbMsg& device) {std::cout << "┌─ USB设备信息" << std::endl;std::cout << "├─ 厂商ID: 0x" << std::hex << std::setw(4) << std::setfill('0') << device.vid << std::endl;std::cout << "├─ 产品ID: 0x" << std::hex << std::setw(4) << std::setfill('0') << device.pid << std::endl;std::cout << "├─ 总线号: " << std::dec << static_cast<int>(device.Bus) << std::endl;std::cout << "├─ 设备地址: " << static_cast<int>(device.Device) << std::endl;//显示USB版本uint16_t usbVersion = device.Version;uint8_t majorVersion = (usbVersion >> 8) & 0xFF;uint8_t minorVersion = usbVersion & 0xFF;std::cout << "├─ USB版本: " << static_cast<int>(majorVersion) << "." << static_cast<int>(minorVersion) << std::endl;std::cout << "├─ 设备名称: " << (device.name.empty() ? "未知" : device.name) << std::endl;std::cout << "└─ 设备类型: ";for (const auto& subclass : device.subclass_set) {std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(subclass) << " ";std::cout << std::endl << std::endl;}
}int main() {std::cout << "=== USB设备信息动态库测试 ===" << std::endl;//创建USB设备信息对象void* usbInfo = create_usb_device_info();if (!usbInfo) {std::cerr << "创建USB设备信息对象失败" << std::endl;return 1;}//初始化if (!usb_device_info_initialize(usbInfo)) {std::cerr << "初始化libusb失败" << std::endl;destroy_usb_device_info(usbInfo);return 1;}std::cout << "\n1. 查询特定设备测试" << std::endl;std::cout << "----------------------------------------" << std::endl;//测试查询特定设备uint16_t targetVid = 0x0BDA;  //Realtekuint16_t targetPid = 0x5161;  //示例设备stUsbMsg device = usb_device_info_get_device_info(usbInfo, targetVid, targetPid);show_device_info(device);std::cout << "2. 枚举所有USB设备测试" << std::endl;std::cout << "----------------------------------------" << std::endl;//测试枚举所有设备stUsbMsg* devices = nullptr;size_t deviceCount = 0;usb_device_info_get_all_devices(usbInfo, &devices, &deviceCount);std::cout << "发现 " << deviceCount << " 个USB设备" << std::endl;for (size_t i = 0; i < deviceCount; ++i) {std::cout << "设备 " << (i + 1) << ":" << std::endl;show_device_info(devices[i]);}//释放设备数组free_usb_devices_array(devices, deviceCount);std::cout << "3. 设备类名称查询测试" << std::endl;std::cout << "----------------------------------------" << std::endl;//测试设备类名称查询uint8_t testClasses[] = {0x03, 0x08, 0x09, 0xFF};for (auto classCode : testClasses) {const char* className = usb_device_info_get_class_name(usbInfo, classCode);std::cout << "设备类 0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(classCode);std::cout << ": " << className << std::endl;}//清理资源usb_device_info_cleanup(usbInfo);destroy_usb_device_info(usbInfo);std::cout << "=== 测试完成 ===" << std::endl;return 0;
}

使用以下命令行进行编译:

g++ -o main main.cpp -L. -lusbDevinfo -lusb-1.0

输出如下:

http://www.dtcms.com/a/610393.html

相关文章:

  • LeetCode 刷题【154. 寻找旋转排序数组中的最小值 II】
  • 大视频秒级同步:高性能跨系统视频数据迁移实战方案
  • 手机网站制作哪家公司好wordpress 查件
  • 优化 TDengine IDMP 面板编辑的几种方法​
  • 定制开发AI智能名片S2B2C预约服务小程序的定制开发与优势分析
  • 哪个做网站平台好电子商务与网站建设实践论文
  • 填充每个节点的下一个右侧节点指针(一)
  • 基于RFSOC47DR的射频采集卡
  • 东莞齐诺做网站网站做服装那个平台好一点
  • 长春模板网站建设企业网站开发难吗
  • 国外网站不需要备案吗看wordpress导出文章
  • DeepSeek-OCR私有化部署—从零构建OCR服务环境
  • Navicat 17 连接 SQL Server 后在导航栏中没有显示数据库表对象,如何解决?
  • 官方网站下载手电筒网站设置在哪
  • 如何建设阿里巴巴网站东莞现代建设有限公司
  • 【openGauss】让gsql和sqlplus输出包含有SQL及数据的完全一致的文本文件
  • LingJing(灵境)桌面级靶场平台新增靶机:加密攻防新挑战:encrypt-labs靶场,全面提升安全研究者的实战能力!
  • 高通SMD450 pop音问题回顾
  • 【LeetCode】将 x 减到 0 的最小操作数
  • Spring Boot 2.7.x 至 2.7.18 及更旧的版本,漏洞说明
  • GEO:抢占AI流量新入口,让品牌成为智能问答中的“标准答案”
  • 钓鱼网站免费空间公司做网站有意义么
  • 单片机超轻量级多任务操作系统实战指南
  • 如何下载各个版本MacOS系统安装包
  • 【Docker安装】Windows10专业版安装教程
  • 等差数列前n项的和
  • 库尔勒市建设路街道办网站邢台网站建设网络优化
  • 网站报301错误重庆妇科医院免费咨询
  • Opengl绘制流程
  • 使用AI来介绍AI