小工具知识网

当前位置: 首页 > 行业知识 > (libusb) usb口自动刷新

行业知识

(libusb) usb口自动刷新

2026-11-07 02:36:52 来源:互联网转载

文章目录

  • libusb
  • 自动刷新程序Code
    • 目录结构
    • Code
      • 项目文件
      • `usb`包
      • `code`包
      • 效果
      • 描述
        • 重置reset
        • 热拔插
        • 使用
        • END

          libusb

          在���作USB相关内容时,有一个比较著名的库就是libusb。

          官方网址:libusb

          下载:

          • 下载源码
          • 官方编好的库
          • github:Releases · libusb/libusb (github.com)

            使用:libusb: Application Programming Interface (sourceforge.io)

            • Functions
            • Structures
            • Enums

              自动刷新程序Code

              这里介绍一个基于libusb自动刷新usb的demo。

              目录结构

              • 3rdparty包
                • libusb的头文件和库
                • 这里采用官方编好的现成的库
                • usb包
                  • 基于C++对libusb的封装
                  • 此包为纯C++代码
                  • code包
                    • 基于Qt的ui和线程
                      E:.└─usbReset    │  main.cpp    │  usbReset.pro    │    ├─3rdparty    │  └─libusb    │      ├─include    │      │  └─libusb-1.0    │      │          libusb.h    │      │    │      └─MinGW32    │          ├─dll    │          │      libusb-1.0.dll    │          │      libusb-1.0.dll.a    │          │    │          └─static    │                  libusb-1.0.a    │    ├─code    │      THREAD_TimerUsb.cpp    │      THREAD_TimerUsb.h    │      WIDGET_Main.cpp    │      WIDGET_Main.h    │      WIDGET_Main.ui    │    └─usb            usb.pri            USB_Hotplug.cpp            USB_Hotplug.h            USB_Reset.cpp            USB_Reset.h

                      Code

                      项目文件

                      usbReset.pro

                      QT += coreQT += widgets#CONFIG += consoleCONFIG += c++17DESTDIR = $$PWD/bininclude($$PWD/usb/usb.pri)INCLUDEPATH += $$PWD/codeHEADERS += \    code/THREAD_TimerUsb.h \    code/WIDGET_Main.hSOURCES += \    main.cpp \    code/THREAD_TimerUsb.cpp \    code/WIDGET_Main.cppFORMS += \    code/WIDGET_Main.ui

                      usb/usb.pri

                      # 链接到libusb(采用静态库)INCLUDEPATH += $$PWD/../3rdparty/libusb/includeHEADERS += $$PWD/../3rdparty/include/libusb/libusb-1.0/libusb.hLIBS += -L$$PWD/../3rdparty/libusb/MinGW32/static/ -llibusb-1.0# 当前封装的包INCLUDEPATH += $$PWD/..HEADERS += \    $$PWD/USB_Hotplug.h \    $$PWD/USB_Reset.hSOURCES += \    $$PWD/USB_Hotplug.cpp \    $$PWD/USB_Reset.cpp

                      main.cpp

                      #include #include "WIDGET_Main.h"int main(int argc, char *argv[]) {    QApplication app(argc, argv);    MainWidget form;    form.show();    return app.exec();}

                      usb包

                      USB_Reset.h

                      #ifndef MYUSB_H_1682212693#define MYUSB_H_1682212693extern "C" {#include "libusb-1.0/libusb.h"}#include #include namespace USB {class Reset final {public:    inline static const int EMPTY_POINTER_INT = 114514;private:    /// for init & exit    static libusb_context* context;    static uint32_t        obj_count;public:    static int Reset_context();private:    char str[1024]{};public:    /// libusb_init()    Reset();    /// libusb_exit()    ~Reset();public:    ::std::vector Show_device();public:    libusb_device_descriptor Find_descriptByidVendor(uint32_t Vendor);public:    /**     * vendor -> device* -> handle*     * handle* -> reset     * handle* -> close     */    libusb_device*        Find_deviceByidVendor(uint32_t Vendor);    libusb_device_handle* Get_handleByOpenDevice(libusb_device* device);    int  Reset_usbByHandle(libusb_device_handle* device_handle);    void Close_deviceByHandle(libusb_device_handle* device_handle);};}  // namespace USB#endif  // MYUSB_H_1682212693

                      USB_Reset.cpp

                      #include "USB_Reset.h"namespace USB {/** * @brief UsbBase::context * static data * context: 所有对象共享这一个全局的上下文对象 * obj_count: 引用计数 */libusb_context* Reset::context   = nullptr;uint32_t        Reset::obj_count = 0;/** * @brief UsbBase::Reset_context * @return * static 重置上下文 */int Reset::Reset_context() {    /// 有实体对象才重置 context    if (0 != obj_count) {        if (nullptr != context) {            libusb_exit(context);            context = nullptr;        }        return libusb_init(&context);    }    return LIBUSB_SUCCESS;}/** * @brief UsbBase::UsbBase * constructor * 上下文的init * 维护引用计数 */Reset::Reset() {    /// 查看版本号    const struct libusb_version* version = libusb_get_version();    printf(">>>Libusb-Version:%s\n", version->describe);    printf(">>>Libusb-Version:%d.%d.%d.%d\n",           version->major,           version->minor,           version->micro,           version->nano           );    /// 第一个对象,或者之前没有注册成功    if (0 == obj_count || nullptr == context) {        if (int res = libusb_init(&context); res != 0) {            sprintf(str, "fail to init: %d\n", res);            /// TODO            /// 根据实际情况,日志、断言、异常等            /// TODO        }    }    obj_count += 1;}/** * @brief UsbBase::~UsbBase * distructor * 维护引用计数 * 上下文的退出 */Reset::~Reset() {    obj_count += -1;    if (0 == obj_count) {        if (nullptr != context) {            libusb_exit(context);            context = nullptr;        }    }}/** * @brief UsbBase::show_device * just show device-list message */::std::vector Reset::Show_device() {    ::std::vector messageList;    messageList.push_back(        "********************** show device-list message BEGIN "        "**********************");    /// help data    libusb_device** deviceList = nullptr;    libusb_get_device_list(nullptr, &deviceList);    for (int i = 0; deviceList[i] != nullptr; i += 1) {        auto                            device = deviceList[i];        struct libusb_device_descriptor descript;        int ret = libusb_get_device_descriptor(device, &descript);        if (LIBUSB_SUCCESS != ret) {            continue;        }        sprintf(str,                "*"                "idVendor:%6d "                "idProduct:%6d "                "bDeviceClass:%6d "                "(bus:%3d, device:%3d)"                "*",                descript.idVendor, descript.idProduct, descript.bDeviceClass,                libusb_get_bus_number(device),                libusb_get_device_address(device));        messageList.push_back(str);    }    messageList.push_back(        "********************** show device-list message END "        "************************");    return messageList;}/** * @brief MyUsb::Find_descriptByidVendor * @param idVendor * @return * 获取设备描述对象 */libusb_device_descriptor Reset::Find_descriptByidVendor(uint32_t idVendor) {    /// ret    libusb_device_descriptor descriptor;    /// help data    libusb_device_handle* deviceHandle = nullptr;    libusb_device**       deviceList   = nullptr;    libusb_get_device_list(nullptr, &deviceList);    for (int i = 0; deviceList[i] != nullptr; i += 1) {        auto device = deviceList[i];        int  ret    = libusb_get_device_descriptor(device, &descriptor);        if (LIBUSB_SUCCESS != ret) {            continue;        }        if (descriptor.idVendor == idVendor) {            const int isOpen = libusb_open(device, &deviceHandle);            if (LIBUSB_SUCCESS == isOpen) {                libusb_close(deviceHandle);                break;            }        }    }    return descriptor;}/** * @brief UsbBase::Find_deviceByidVendor * @param Vendor * @return * 获取device */libusb_device* Reset::Find_deviceByidVendor(uint32_t Vendor) {    /// ret    libusb_device* device = nullptr;    /// help data    libusb_device_handle* deviceHandle = nullptr;    libusb_device**       deviceList   = nullptr;    libusb_get_device_list(nullptr, &deviceList);    for (int i = 0; deviceList[i] != nullptr; i += 1) {        device = deviceList[i];        libusb_device_descriptor descriptor;        int ret = libusb_get_device_descriptor(device, &descriptor);        if (LIBUSB_SUCCESS != ret) {            continue;        }        if (descriptor.idVendor == Vendor) {            const int isOpen = libusb_open(device, &deviceHandle);            if (LIBUSB_SUCCESS == isOpen) {                libusb_close(deviceHandle);                break;            } else {                device = nullptr;            }        } else {            device = nullptr;        }    }    return device;}/** * @brief UsbBase::Get_handleByOpenDevice * @param device * @return * 根据传入的设备指针 * 通过open操作 * 获取句柄指针 */libusb_device_handle* Reset::Get_handleByOpenDevice(libusb_device* device) {    if (nullptr == device) {        return nullptr;    }    libusb_device_handle* deviceHandle = nullptr;    const int             isOpen       = libusb_open(device, &deviceHandle);    if (LIBUSB_SUCCESS == isOpen) {        return deviceHandle;    } else {        return nullptr;    }}/** * @brief UsbBase::Reset_usbByHandle * @param device_handle * @return * 通过句柄重置设备 * 为0则表示成功 */int Reset::Reset_usbByHandle(libusb_device_handle* device_handle) {    if (nullptr == device_handle) {        return EMPTY_POINTER_INT;    }    const int isReset = libusb_reset_device(device_handle);    //! TODO if (isReset ?= 0) => log    return isReset;}/** * @brief UsbBase::Close_deviceByHandle * @param device_handle * 手动通过句柄指针关闭设备 */void Reset::Close_deviceByHandle(libusb_device_handle* device_handle) {    if (nullptr == device_handle) {        return;    }    libusb_close(device_handle);}}  // namespace USB

                      USB_Hotplug.h

                      #ifndef HOTPLUG_H_27452998650#define HOTPLUG_H_27452998650extern "C" {#include "libusb-1.0/libusb.h"}namespace USB {class Hotplug final {private:    static libusb_device_handle *m_deviceHandle;private:    static int LIBUSB_CALL usb_arrived_callback(struct libusb_context *ctx, struct libusb_device  *dev, libusb_hotplug_event   event, void *userdata);    static int LIBUSB_CALL usb_left_callback(struct libusb_context *ctx,                                             struct libusb_device  *dev,                                             libusb_hotplug_event   event,                                             void                  *userdata);private:    char str[1024]{};private:    libusb_hotplug_callback_handle usb_arrived_handle;    libusb_hotplug_callback_handle usb_left_handle;    libusb_context                *context = nullptr;private:    uint32_t m_regiest_vendor      = LIBUSB_HOTPLUG_MATCH_ANY;    uint32_t m_regiest_product     = LIBUSB_HOTPLUG_MATCH_ANY;    uint32_t m_regiest_deviceClass = LIBUSB_HOTPLUG_MATCH_ANY;private:    Hotplug();public:    Hotplug(uint32_t vendor, uint32_t product, uint32_t deviceClass);    ~Hotplug();public:    int Register_arrived();    int Register_left();};}  // namespace USB#endif  // HOTPLUG_H_27452998650

                      USB_Hotplug.cpp

                      #include "USB_Hotplug.h"#include namespace USB {/** * @brief Hotplug::m_deviceHandle * 主要用于静态的回调函数 */libusb_device_handle *Hotplug::m_deviceHandle = nullptr;/** * @brief Hotplug::usb_arrived_callback * @param ctx * @param dev * @param event * @param userdata * @return * 热拔插 arrive 的回调 */int Hotplug::usb_arrived_callback(libusb_context *ctx, libusb_device *dev,                                  libusb_hotplug_event event, void *userdata) {    struct libusb_device_handle    *handle;    struct libusb_device_descriptor desc;    unsigned char                   buf[512];    int                             rc;    libusb_get_device_descriptor(dev, &desc);    printf("Add usb device: \n");    printf("\tCLASS(0x%x) SUBCLASS(0x%x) PROTOCOL(0x%x)\n", desc.bDeviceClass,           desc.bDeviceSubClass, desc.bDeviceProtocol);    printf("\tVENDOR(0x%x) PRODUCT(0x%x)\n", desc.idVendor, desc.idProduct);    rc = libusb_open(dev, &handle);    if (LIBUSB_SUCCESS != rc) {        printf("Could not open USB device\n");        return 0;    }    memset(buf, 0, sizeof(buf));    rc = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, buf,                                            sizeof(buf));    if (rc  

                      code包

                      WIDGET_Main.h

                      #ifndef FORM_H_27453073957#define FORM_H_27453073957#include #include #include #include "THREAD_TimerUsb.h"namespace Ui {class MainWidget;}class MainWidget : public QWidget {    Q_OBJECTprivate:    QScopedPointer ui;private:    TimerUsb m_usb;public:    explicit MainWidget(QWidget *parent = nullptr);    ~MainWidget();private:    void show_usbDeviceMsgAll();    void start_work();};#endif  // FORM_H_27453073957

                      WIDGET_Main.cpp

                      #include "WIDGET_Main.h"#include #include #include #include #include "ui_WIDGET_Main.h"#include "usb/USB_Reset.h"QWidget         *g_widgetDisplayBoard = nullptr;QtMessageHandler g_oldMessageHandler  = nullptr;QMutex           g_dispalyMutex;/** * debug 重定向 */void newDebugHandlerFunc(QtMsgType type, const QMessageLogContext &context, const QString &msg) {    QMutexLocker locker(&g_dispalyMutex);    if (g_widgetDisplayBoard) {        dynamic_cast(g_widgetDisplayBoard)->append(msg);    } else {        g_oldMessageHandler(type, context, msg);    }}/** * @brief MainWidget::MainWidget * @param parent * 1. debug重定向 * 2. connect */MainWidget::MainWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MainWidget{}) {    ui->setupUi(this);    setWindowTitle("usb controller");    /// debug -> widget    {        g_widgetDisplayBoard       = ui->textEdit;        g_oldMessageHandler = qInstallMessageHandler(newDebugHandlerFunc);    }    /// connect    {        connect(ui->btn_showAll, &QPushButton::clicked, this,                &MainWidget::show_usbDeviceMsgAll);        connect(ui->btn_clear, &QPushButton::clicked, ui->textEdit,                &QTextEdit::clear);        connect(ui->btn_start, &QPushButton::clicked, this,                &MainWidget::start_work);        connect(&m_usb, &TimerUsb::signal_message, this,                [](const QString &msg) { qInfo()  show_usbDeviceMsgAll(); }}/** * @brief MainWidget::~MainWidget * 将线程安全关闭 */MainWidget::~MainWidget() {    if (m_usb.isRunning()) {        m_usb.quit();        m_usb.wait();    }}/** * @brief MainWidget::show_usbDeviceMsgAll * 展示所有usb设备的信息 * 因为设计的是通用库 * 因此返回的是std::vector    for (auto &&s : USB::Reset().Show_device()) {        qDebug()     uint   vendor = ui-edit_Vendor-text().toUInt();    double time   = ui->edit_timeout->text().toDouble();    m_usb.Set_usbDeviceVendor(vendor);    m_usb.Set_timerInterval(time * 1000);    m_usb.Set_timerStart();    if (false == m_usb.isRunning()) {        qDebug()     Q_OBJECTprivate:    uint32_t m_usbDeviceVendor = 0;private:    QTimer m_timer;    int    m_timerIntervalMsec = 1500;public:    TimerUsb();public:    void Set_usbDeviceVendor(uint32_t vendor);public:    void Set_timerInterval(int msec = 1500);    void Set_timerStart();    void Set_timerStop();    bool Is_timerRunning();protected:    void run() override;signals:    void signal_message(const QString&);};#endif  // THREADUSB_H_70403004403    Set_timerInterval();}/** * @brief ThreadUsb::Set_usbDeviceVendor * @param vendor * 根据 vendor 查询设备 */void TimerUsb::Set_usbDeviceVendor(uint32_t vendor) {    this-m_usbDeviceVendor = vendor;}/** * @brief ThreadUsb::Set_timerInterval * @param msec * 设置reset间隔 */void TimerUsb::Set_timerInterval(int msec) {    this-m_timerIntervalMsec = msec;    m_timer.setInterval(m_timerIntervalMsec);}/** * @brief TimerUsb::Set_timerStart * 启动定时器,但不启动线程 */void TimerUsb::Set_timerStart() {    this->m_timer.start();}/** * @brief TimerUsb::Set_timerStop * 关闭定时器,但不关闭线程 */void TimerUsb::Set_timerStop() {    this->m_timer.stop();}/** * @brief TimerUsb::Is_timerRunning * @return * 定时器是否运行 */bool TimerUsb::Is_timerRunning() {    return this->m_timer.isActive();}/** * @brief ThreadUsb::run * 定时器timeout一次,usb-reset一次 */void TimerUsb::run() {    USB::Reset     usb;    libusb_device* device = nullptr;    /// 为了防止刚启动的时候没有获得    /// 高强度轮询获取    const size_t loopDeviceCount   = 1e5 + 10;    const size_t loopContextPeriod = 1e3;    for (size_t i = 0; i m_usbDeviceVendor);        if (nullptr != device) {            break;        } else {            if (i % loopContextPeriod == 0) {                DEBUG_MODEL("device is null & context resert");                USB::Reset::Reset_context();            }        }    }    if (nullptr == device) {        DEBUG_MODEL("libusb_device is null & Thread end!");        return;    } else {        DEBUG_MODEL("libusb_device require ok!");    }    libusb_device_handle* handle = usb.Get_handleByOpenDevice(device);    if (handle == nullptr) {        DEBUG_MODEL("libusb_device require is null & Thread end!");        return ;    } else {        DEBUG_MODEL("libusb_device_handle require ok!");    }    auto con = connect(&this->m_timer, &QTimer::timeout, [&]() {        int res = usb.Reset_usbByHandle(handle);        if (LIBUSB_SUCCESS == res) {            DEBUG_MODEL("reset Success");        } else {            DEBUG_MODEL("reset Error; errorType = " + QString::number(res));        }        /// 句柄不归还,持续重置        // usb.Close_deviceByHandle(handle);    });    /// 开启事件循环    exec();    this->m_timer.stop();    disconnect(con);}

                      效果

                      界面功能比较简单,基本就是widget中的代码,设置好vendor和倒计时后点击开始即可。

                      目前身边没有可以测试的usb设备,因此不展示具体效果。

                      其中USB::Reset是经过测试可用的。

                      描述

                      本demo主要就是libusb的封装,然后是对于封装的简单调用。

                      重置reset

                      基本思路:vendor->device*->handle*

                      然后使用handle*进行reset和最后的close。

                      • 获取device*
                        • 获取设备序列libusb_get_device_list()
                        • 遍历序列,获取每个设备的描述信息libusb_get_device_descriptor()
                        • 对比描述信息,确认是哪个device*。并测试是否能正常open。
                        • 获取handle*
                          • 通过libusb_open()即测试打开的同时就能获取
                          • 使用handle*进行reset
                            • 使用libusb_reset_device()
                            • 关闭handle*
                              • 使用libusb_close()

                                注意:有的vendor是一样的编号,请根据实际的情景和需求改变具体的查找规则。

                                热拔插

                                热拔插部分没有测试,不做重点描述。

                                但是基本原理就是注册拔&插的回调函数。

                                libusb_hotplug_register_callback()

                                • 标记:LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
                                • 标记:LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT

                                  使用

                                  全在QThread::run()函数中。

                                  在实际作用时,可能因为物理设备实际问题,导致设备指针和句柄的获取失败。

                                  因此可以设置一个比较大的循环,无脑获取多次,直到获取成功,但若多次获取失败,则直接视为失败了。

                                  然后启动一个定时器,

                                  注意:请不要close句柄。因为设备的实际请款,可能关闭后就再获取不到了,只要不随便乱插,设备标号和句柄是不会变的,因此直接保留好。直到真正不需要时再关闭(根据实际业务和逻辑需求)。




                                  END

上一篇:服务器怎么访问客户端?

下一篇:单位网站怎么建设?