libusb_Qt使用

本文介绍了如何在Qt项目中使用Libusb库,包括从GitHub下载库、在.pro文件中设置编译参数以及在C++代码中获取和操作USB设备的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Libusb

libusb_github
在这里插入图片描述
建议直接下载库,编译好麻烦

QT调用

.pro文件添加:

win32: LIBS += -L$$PWD/LIB/libusb/x64/ -llibusb-1.0

.cpp调用即可

#include "LIB/libusb/libusb.h"
void class_name::fun(){
	/* 1.  */
    libusb_init(NULL);
    /**/
    struct libusb_device **device_list;
    int num_devices = libusb_get_device_list(NULL, &device_list);
    /**/
    for (int i = 0; i < num_devices; i++)
    {
            struct libusb_device *dev = device_list[i];
            struct libusb_device_descriptor dev_desc;
            libusb_get_device_descriptor(dev, &dev_desc);
            int id_vendor =  dev_desc.idVendor;
            int id_product = dev_desc.idProduct;
            qDebug() << "id_vendor="<<id_vendor;
            qDebug() << "id_product="<<id_product;

            /**/
            struct libusb_device_handle *dev_handle = NULL;
            libusb_open(dev, &dev_handle);  //or
            dev_handle = libusb_open_device_with_vid_pid(NULL, 0x0525, 0xa4a0);
    }
}
分析我的是否合理void HidReader::run() { running = true; if (libusb_init(&ctx) < 0) { qDebug() << "libusb 初始化失败!"; return; } dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID); if (!dev_handle) { qDebug() << "无法打开 HID 设备!"; libusb_exit(ctx); return; } // 选择接口0 int r = libusb_claim_interface(dev_handle, 0); if (r != LIBUSB_SUCCESS) { qDebug() << "无法声明接口! 错误代码:" << r; libusb_close(dev_handle); libusb_exit(ctx); return; } unsigned char buffer[64]; // 报告 ID (1 字节) + 数据 (64 字节) int actual_length; qDebug() << "HID 监听线程启动..."; QByteArray lastData; // 记录上次收到的数据 QByteArray data; while (running) { int r = libusb_interrupt_transfer(dev_handle, ENDPOINT_IN, buffer, REPORT_SIZE + 1, &actual_length, 1000); if (r == LIBUSB_SUCCESS) { uint8_t report_id = buffer[0]; switch(report_id) { case 0x1B: data = QByteArray((char*)buffer, actual_length); if (data != lastData) { // 过滤掉重复数据 lastData = data; emit dataReceived(data); } break; case 0x1C: data = QByteArray((char*)buffer, actual_length); if (data != lastData) { // 过滤掉重复数据 lastData = data; emit dataReceived(data); } break; default: qDebug() << "未知报告类型:" << report_id; } } else if (r == LIBUSB_ERROR_TIMEOUT) { continue; // 超时不影响 } else { qDebug() << "HID 读取失败! 错误代码:" << r; running = false; } } libusb_release_interface(dev_handle, 0); libusb_close(dev_handle); libusb_exit(ctx); qDebug() << "HID 监听线程退出!"; }
03-08
<think>嗯,用户给了一段C++代码,是关于使用libusb库进行HID设备通信的。我需要分析这段代码的合理性。首先,我得仔细看一下代码的结构和各个部分的功能。 首先,用户定义了一个HidReader类的run()方法,这是QThread的执行函数。代码一开始设置running为true,然后初始化libusb上下文。如果初始化失败,就输出错误信息并返回。这部分看起来没问题,libusb_init确实需要先调用,正确检查返回值是必要的。 接下来尝试打开指定Vendor ID和Product ID的设备。如果dev_handle为空,说明打开失败,这里会清理上下文并返回。这里也没有问题,libusb_open_device_with_vid_pid是正确的用法。不过可能需要确认VENDOR_ID和PRODUCT_ID是否正确定义了,但代码里没给出,所以这里假设没问题。 然后声明接口0,使用libusb_claim_interface。如果失败,就关闭设备并退出。这也是标准操作,正确。不过需要注意,如果设备有多个接口,可能需要处理更多情况,但这里只处理接口0,可能用户确定设备的情况,所以没问题。 接着定义了一个缓冲区buffer,大小是64字节,注释说是报告ID(1字节)+数据(64字节),所以总大小应该是65字节?但代码里REPORT_SIZE +1,如果REPORT_SIZE是64的话,那buffer的大小正确。不过这里要看REPORT_SIZE的定义,假设是64的话,buffer的大小正确,否则可能需要调整。不过用户代码里buffer是64字节,可能存在问题,因为报告ID占1字节,后面数据64字节的话,总长度应该是65,所以buffer应该是65字节?这里可能是个bug。例如,如果REPORT_SIZE是64,那么libusb_interrupt_transfer的第三个参数是buffer,大小是REPORT_SIZE+1=65,但buffer本身只有64字节,会导致缓冲区溢出,引发问题。这可能是代码中的一个错误。 然后进入主循环,使用libusb_interrupt_transfer读取数据。端点ENDPOINT_IN需要确认是否正确。这里参数是REPORT_SIZE +1,即65字节,但buffer的大小只有64,所以这里会导致写入越界,可能破坏栈数据,导致崩溃或不可预知的行为。这显然是一个严重的问题。 在处理接收数据时,检查返回状态是否为LIBUSB_SUCCESS。如果是,提取报告ID,然后根据0x1B和0x1C进行处理。这里用switch-case结构,没问题。但每个case里将buffer转换为QByteArray时,使用了actual_length,这是正确的,因为actual_length是实际传输的字节数。不过需要注意的是,报告ID是buffer的第一个字节,所以数据部分应该是buffer+1的位置,但用户代码中直接将整个buffer(包括报告ID)发送出去了。如果上层需要处理数据部分,可能需要排除报告ID,否则可能包含多余的信息。不过具体要看应用场景,如果确实需要报告ID,那没问题。 过滤重复数据的逻辑是通过比较当前数据和lastData,如果不同才emit信号。这可以避免重复处理相同数据,是合理的优化。 处理错误方面,如果是超时错误,继续循环,其他错误则停止运行。这也符合常规做法,超时是正常现象,不需要退出。 在退出时,释放接口、关闭设备、退出libusb上下文,这些都是正确的资源释放步骤,避免内存泄漏。 总结问题点: 1. 缓冲区大小可能不足:buffer[64]但传输请求65字节,导致溢出。 2. 报告ID处理是否正确?可能将报告ID包含在发送的数据中,是否需要去除? 3. 没有处理热插拔或设备断开的情况,比如在运行过程中设备被拔掉,libusb_interrupt_transfer可能会返回错误,此时可能需要重新初始化设备,而不仅仅是退出。但当前代码在错误时设置running=false,结束线程,这可能不够健壮。 4. 是否需要在每次循环中检查running标志?比如在长时间等待传输时,可能无法及时退出。但这里设置的超时是1000毫秒,所以每次循环会检查running,应该没问题。 5. 是否有必要在libusb_init之后设置libusb的日志级别或调试选项,以便更详细的错误信息? 6. 多线程安全性:如果其他线程调用了HidReader的析构或停止方法,是否正确地同步running变量?这里running是布尔型,可能需用原子操作或互斥锁,但代码中未显示。例如,在另一个线程中设置running=false,但这里可能没有内存屏障,导致线程无法及时看到变化。不过Qt的信号槽机制通常是线程安全的,如果通过信号触发停止,可能没问题,但需确认。 改进建议: 1. 修正缓冲区大小,例如声明为buffer[65],以容纳报告ID+64字节数据。 2. 检查REPORT_SIZE的定义,确保其正确性。 3. 在数据传输时,可能需要将报告ID和数据部分分开处理,例如emit dataReceived(QByteArray((char*)(buffer+1), actual_length -1)),这样上层只处理有效数据。 4. 添加对设备断开情况的处理,例如尝试重新连接。 5. 确保running变量的线程安全性,使用QAtomicInt或QMutex保护。 6. 在libusb_init之后,调用libusb_set_debug设置日志级别,帮助调试。 7. 检查端点ENDPOINT_IN是否正确,确保它是输入端点且类型正确(INTERRUPT)。</think>以下是对代码的合理性分析及改进建议,按实现逻辑分步说明: --- ### **一、基础逻辑分析** 1. **设备初始化流程** - ✅ 正确使用`libusb_init`初始化上下文 - ✅ 通过`libusb_open_device_with_vid_pid`精准匹配设备 - ✅ 声明接口和错误回滚逻辑完善(释放接口->关闭设备->退出上下文) 2. **数据传输部分** - ✅ 使用`libusb_interrupt_transfer`进行中断传输符合HID设备特性 - ✅ 通过`running`标志位控制线程启停 - ✅ 过滤重复数据逻辑合理(`lastData`比对) 3. **资源释放** - ✅ 退出时释放接口、关闭设备、清理上下文,避免内存泄漏 --- ### **二、潜在问题及优化建议** #### **1. 缓冲区溢出风险** ```cpp unsigned char buffer[64]; // 实际需要 65 字节 int r = libusb_interrupt_transfer(..., buffer, REPORT_SIZE + 1, ...); ``` - **问题**:若`REPORT_SIZE=64`,则传输需要65字节,但`buffer`仅分配64字节,导致溢出。 - **修复**: ```cpp unsigned char buffer[65]; // 报告ID(1) + 数据(64) ``` #### **2. 报告ID处理争议** ```cpp data = QByteArray((char*)buffer, actual_length); ``` - **问题**:数据包含报告ID,若上层仅需有效载荷需调整。 - **建议**: ```cpp QByteArray payload = QByteArray((char*)(buffer + 1), actual_length - 1); ``` #### **3. 线程安全性缺陷** ```cpp bool running; // 非原子操作,多线程读写可能不同步 ``` - **风险**:多线程环境下`running`状态可能延迟生效。 - **修复**: ```cpp QAtomicInteger<bool> running; // 使用原子操作 ``` #### **4. 设备重连缺失** - **现象**:设备断开后线程直接退出,无重连机制。 - **建议**:在错误处理分支添加重试逻辑,或通过信号通知外部重建连接。 --- ### **三、改进后代码片段** ```cpp // 修复缓冲区大小和原子操作 QAtomicInteger<bool> running; // 头文件中声明 void HidReader::run() { running.store(true); unsigned char buffer[65]; // 修正为65字节 while (running.load()) { int r = libusb_interrupt_transfer(..., buffer, sizeof(buffer), ...); // 错误处理中增加重连逻辑 } } ``` --- ### **四、总结** - **合理性**:基础通信框架正确,但存在**缓冲区溢出和线程安全隐患**需优先修复。 - **扩展性**:可增加`libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL)`辅助调试。 - **健壮性**:建议补充设备热插拔支持(参考`LIBUSB_HOTPLUG_EVENT`)。 建议优先修复缓冲区溢出问题以保证稳定性,再逐步优化异常处理机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值