(libusb) usb口自动刷新

文章目录

  • 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 += core
QT += widgets

#CONFIG += console
CONFIG += c++17

DESTDIR = $$PWD/bin

include($$PWD/usb/usb.pri)

INCLUDEPATH += $$PWD/code
HEADERS += \
    code/THREAD_TimerUsb.h \
    code/WIDGET_Main.h

SOURCES += \
    main.cpp \
    code/THREAD_TimerUsb.cpp \
    code/WIDGET_Main.cpp

FORMS += \
    code/WIDGET_Main.ui

usb/usb.pri

# 链接到libusb(采用静态库)
INCLUDEPATH += $$PWD/../3rdparty/libusb/include
HEADERS += $$PWD/../3rdparty/include/libusb/libusb-1.0/libusb.h
LIBS += -L$$PWD/../3rdparty/libusb/MinGW32/static/ -llibusb-1.0

# 当前封装的包
INCLUDEPATH += $$PWD/..
HEADERS += \
    $$PWD/USB_Hotplug.h \
    $$PWD/USB_Reset.h

SOURCES += \
    $$PWD/USB_Hotplug.cpp \
    $$PWD/USB_Reset.cpp

main.cpp

#include <QApplication>

#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_1682212693

extern "C" {
#include "libusb-1.0/libusb.h"
}
#include <string>
#include <vector>

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<::std::string> 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<::std::string> Reset::Show_device() {
    ::std::vector<::std::string> 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_27452998650

extern "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 <iostream>

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 < 0) {
        printf("Get Manufacturer failed\n");
    } else {
        printf("\tManufacturer: %s\n", buf);
    }

    memset(buf, 0, sizeof(buf));
    rc = libusb_get_string_descriptor_ascii(handle, desc.iProduct, buf,
                                            sizeof(buf));
    if (rc < 0) {
        printf("Get Product failed\n");
    } else {
        printf("\tProduct: %s\n", buf);
    }

    memset(buf, 0, sizeof(buf));
    rc = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, buf,
                                            sizeof(buf));
    if (rc < 0) {
        printf("Get SerialNumber failed\n");
    } else {
        printf("\tSerialNumber: %s\n", buf);
    }
    libusb_close(handle);

    return 0;
}

/**
 * @brief Hotplug::usb_left_callback
 * @param ctx
 * @param dev
 * @param event
 * @param userdata
 * @return
 * 热拔插left的回调
 */
int Hotplug::usb_left_callback(libusb_context *ctx, libusb_device *dev,
                               libusb_hotplug_event event, void *userdata) {
    struct libusb_device_descriptor desc;
    libusb_get_device_descriptor(dev, &desc);
    const int isReset = libusb_reset_device(m_deviceHandle);
    return isReset;
}

/**
 * @brief Hotplug::Hotplug
 * 构造的时候init
 */
Hotplug::Hotplug() {
    libusb_init(&context);
}

/**
 * @brief Hotplug::Hotplug
 * @param vendor
 * @param product
 * 委托构造
 */
Hotplug::Hotplug(uint32_t vendor, uint32_t product, uint32_t deviceClass) : Hotplug() {
    /// data
    {
        m_regiest_vendor      = vendor;
        m_regiest_product     = product;
        m_regiest_deviceClass = deviceClass;
    }

    /// find
    {
        libusb_device **m_deviceList;
        libusb_get_device_list(nullptr, &m_deviceList);
        for (int i = 0; m_deviceList[i] != nullptr; i += 1) {
            auto                            device = m_deviceList[i];
            struct libusb_device_descriptor descript;
            int ret = libusb_get_device_descriptor(device, &descript);
            if (ret < 0) {
                sprintf(
                    str,
                    "Error libusb_get_device_descriptor idx = %d res = %d\n", i,
                    ret);
            }

            if (descript.idVendor == vendor && descript.idProduct == product) {
                const int isOpen =
                    libusb_open(m_deviceList[i], &m_deviceHandle);
                if (LIBUSB_SUCCESS == isOpen) {
                    break;
                }
            }
        }
    }  /// find

    /// test
    {
        Register_arrived();
        Register_left();
    }
}

/**
 * @brief Hotplug::~Hotplug
 * 析构的时候注销和释放句柄
 */
Hotplug::~Hotplug() {
    libusb_hotplug_deregister_callback(context, usb_arrived_handle);
    libusb_hotplug_deregister_callback(context, usb_left_handle);
    libusb_exit(context);
}

/**
 * @brief Hotplug::Register_arrived
 * @return
 * 注册热拔插arrive
 */
int Hotplug::Register_arrived() {
    int res = libusb_hotplug_register_callback(
        context, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, LIBUSB_HOTPLUG_NO_FLAGS,
        m_regiest_vendor, m_regiest_product, m_regiest_deviceClass,
        Hotplug::usb_arrived_callback, NULL, &usb_arrived_handle);
    return res;
}

/**
 * @brief Hotplug::Register_left
 * @return
 * 注册热拔插left
 */
int Hotplug::Register_left() {
    int res = libusb_hotplug_register_callback(
        context, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, LIBUSB_HOTPLUG_NO_FLAGS,
        m_regiest_vendor, m_regiest_product, m_regiest_deviceClass,
        Hotplug::usb_left_callback, NULL, &usb_left_handle);
    return res;
}
}  // namespace USB

code

WIDGET_Main.h

#ifndef FORM_H_27453073957
#define FORM_H_27453073957

#include <QScopedPointer>
#include <QVector>
#include <QWidget>

#include "THREAD_TimerUsb.h"

namespace Ui {
class MainWidget;
}

class MainWidget : public QWidget {
    Q_OBJECT

private:
    QScopedPointer<Ui::MainWidget> 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 <QDebug>
#include <QMutex>
#include <QThread>
#include <QTimer>

#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<QTextEdit *>(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() << msg; });
    }

    /// before exe
    { show_usbDeviceMsgAll(); }
}

/**
 * @brief MainWidget::~MainWidget
 * 将线程安全关闭
 */
MainWidget::~MainWidget() {
    if (m_usb.isRunning()) {
        m_usb.quit();
        m_usb.wait();
    }
}

/**
 * @brief MainWidget::show_usbDeviceMsgAll
 * 展示所有usb设备的信息
 * 因为设计的是通用库
 * 因此返回的是std::vector<std::string>
 */
void MainWidget::show_usbDeviceMsgAll() {
    for (auto &&s : USB::Reset().Show_device()) {
        qDebug() << s.c_str();
    }
}

/**
 * @brief MainWidget::start_work
 * 检测线程启动
 */
void MainWidget::start_work() {
    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() << "=== start before ===";
        m_usb.start();
        qDebug() << "=== start after ===";
    }
}

WIDGET_Main.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWidget</class>
 <widget class="QWidget" name="MainWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>726</width>
    <height>480</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>UsbForm</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QTextEdit" name="textEdit">
     <property name="styleSheet">
      <string notr="true"/>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QWidget" name="widget" native="true">
     <layout class="QGridLayout" name="gridLayout">
      <item row="0" column="1">
       <widget class="QLineEdit" name="edit_Vendor">
        <property name="font">
         <font>
          <pointsize>12</pointsize>
         </font>
        </property>
        <property name="text">
         <string>8746</string>
        </property>
       </widget>
      </item>
      <item row="0" column="0">
       <widget class="QLabel" name="label_Vendor">
        <property name="font">
         <font>
          <pointsize>12</pointsize>
         </font>
        </property>
        <property name="text">
         <string>目标Vendor</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QLabel" name="label_timeout">
        <property name="font">
         <font>
          <pointsize>12</pointsize>
         </font>
        </property>
        <property name="text">
         <string>倒计时(秒)</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QLineEdit" name="edit_timeout">
        <property name="font">
         <font>
          <pointsize>12</pointsize>
         </font>
        </property>
        <property name="text">
         <string>2</string>
        </property>
       </widget>
      </item>
      <item row="2" column="0">
       <widget class="QPushButton" name="btn_showAll">
        <property name="font">
         <font>
          <pointsize>18</pointsize>
         </font>
        </property>
        <property name="text">
         <string>设备usb列表</string>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QPushButton" name="btn_clear">
        <property name="font">
         <font>
          <pointsize>18</pointsize>
         </font>
        </property>
        <property name="text">
         <string>清空列表</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="QPushButton" name="btn_start">
     <property name="font">
      <font>
       <pointsize>18</pointsize>
      </font>
     </property>
     <property name="text">
      <string>开始</string>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

THREAD_TimerUsb.h

#ifndef THREADUSB_H_70403004403
#define THREADUSB_H_70403004403

#include <QThread>
#include <QTimer>

class TimerUsb : public QThread {
    Q_OBJECT
private:
    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

THREAD_TimerUsb.cpp

#include "THREAD_TimerUsb.h"

#include <QDebug>
#include <QTimer>

#include "usb/USB_Reset.h"

#if 0
#define DEBUG_MODEL qInfo() <<
#else
#define DEBUG_MODEL emit this->signal_message
#endif

/**
 * @brief ThreadUsb::ThreadUsb
 * construct
 */
TimerUsb::TimerUsb() {
    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 < loopDeviceCount; i += 1) {
        device = usb.Find_deviceByidVendor(this->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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/427265.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

招聘人才小程序源码系统:多城市招聘平台+招聘会+职场咨询 带完整的搭建教程以及安装代码包

移动互联网的飞速发展&#xff0c;线上招聘已成为企业和求职者之间的重要桥梁。为了满足多城市、多行业、多岗位的招聘需求&#xff0c;以及提供一站式的求职服务&#xff0c;小编给大家分享一款“招聘人才小程序源码系统”。该系统不仅整合了多城市的招聘平台资源&#xff0c;…

C++:函数模板整理

函数模板: 找到函数相同的实现思路&#xff0c;区别于函数的参数类型。 使用函数模板使得函数可容纳不同类型的参数实现函数功能&#xff0c;而不是当类型不同时便编译大量类型不同的函数&#xff0c;产生大量重复代码和内存占用 函数模板格式&#xff1a; template<typ…

Linxu自动化构建工具make/Makefile究竟时什么?

Linxu自动化构建工具make/Makefile究竟时什么&#xff1f; 一、简介二、makefile文件制作&#xff08;简洁版&#xff09;2.1 源文件2.2 makefile如何制作2.2.1 依赖关系、依赖方法2.2.3 伪目标&#xff08;清理文件资源&#xff09; 三、make/Makefile自动化原理3.1 伪目标为什…

Lua 篇(一)— 安装运行Hello World

目录 前言一、Lua 是什么&#xff1f;二、Lua和C#的区别三、安装 LuaLinux 系统上安装Mac OS X 系统上安装Window 系统上安装emmyluaRider 安装(推荐) 四、Lua学习资料 前言 Lua 是一种轻量级的嵌入式脚本语言&#xff0c;它可以与 C 语言无缝集成&#xff0c;提供了强大的编程…

程序员的金三银四求职宝典:如何在关键时期脱颖而出?

个人主页&#xff1a;17_Kevin-CSDN博客 随着春天的脚步渐近&#xff0c;程序员们的求职热潮也随之而来。在这个被称为“金三银四”的招聘季&#xff0c;如何从众多求职者中脱颖而出&#xff0c;成为了许多程序员关注的焦点。本文将为你提供一份全面的求职宝典&#xff0c;助你…

程序员眼中的“祖传代码”

引言 在IT界&#xff0c;特别是在Java项目中&#xff0c;“祖传代码”通常指的是那些经过长时间积累、由多位开发者共同维护、且蕴含深厚技术沉淀的代码片段或模块。这些代码可能存在于项目的核心模块&#xff0c;也可能是一些辅助性的工具类。它们承载着项目的历史&#xff0…

vulhub中Wordpress 4.6 任意命令执行漏洞复现

由于Mysql初始化需要一段时间&#xff0c;所以请等待。成功运行后&#xff0c;访问http://your-ip:8080/打开站点&#xff0c;初始化管理员用户名和密码后即可使用&#xff08;数据库等已经配置好&#xff0c;且不会自动更新&#xff09;。 发送如下数据包&#xff0c;可见/tmp…

Kyuubi之Share Level

文章目录 Kyuubi介绍Spark thriftServer的问题Kyuubi架构 共享域参数CONNECTIONUSERGROUPSERVER Kyuubi介绍 Spark thriftServer的问题 STS面临以下的问题&#xff1a; 无法适应多租户场景。STS后端引擎仅仅启动一个application提供服务&#xff0c;提交用户和队列均为固定。…

Linux:Kubernetes(k8s)基础理论笔记(1)

我笔记来源的图片以及共享至GitHub&#xff0c;本章纯理论。这是k8s中部分的基础理论 &#x1f447; KALItarro/k8spdf: 这个里面只有一个pdf文件 (github.com)https://github.com/KALItarro/k8spdf&#x1f446; 什么是kubernetes kubernetes 是一个开源的&#xff0c;用于管…

TikTok企业认证教程:提升账号可信度的必备步骤

TikTok企业认证是TikTok平台用来验证账号真实性和权威性的方式。通过企业认证之后&#xff0c;企业能在TikTok上获得官方标识&#xff0c;可以增强品牌的专业形象&#xff0c;也有利于提升用户对企业内容的信任度。而且通过TikTok企业认证还可以解锁高级功能&#xff0c;如数据…

第105讲:Mycat垂直分表实战:从规划到解决问题的完整指南

文章目录 1.垂直分表的背景2.垂直分表案例实战2.1.垂直分表规划2.2.配置Mycat实现垂直分表2.3.重启Mycat2.4.在Mycat命令行中导入数据结构2.5.查看由Mycat分表后每个分片上存储的表2.6.Mycat垂直分表后可能遇到的问题2.7.垂直分表完成 1.垂直分表的背景 我们的商城系统数据库&…

基于springboot实现乐器社区网站系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现乐器社区网站系统演示 摘要 音乐一直以来都是人们非常喜爱的一种休闲娱乐的方式&#xff0c;人们在聆听音乐时可以全身心的进行放松&#xff0c;从音乐中可以获得认同感&#xff0c;可以与音乐进行情感的交流。而音乐的组成形式也是多样的&#xff0c;现代…

AP8854 DC-DC降压恒压 12V 6A过EMI线路图 宽电压电源管理IC

产品描述 AP8854 一款宽电压范围降压型 DC-D电源管理芯片&#xff0c;内部集成使能开关控制、基准电源、误差放大器、过热保护、限流保护、短路保护等功能&#xff0c;非常适合宽电压输入降压使用。AP8854 带使能控制&#xff0c;可以大大节省外围器件&#xff0c;更加适合电池…

六、继承(一)

1 继承的引入 以往我们想分别实现描述学生、老师的类&#xff0c;可能会这样子做&#xff1a; class Student {string _name;string _number;int _tel;int id;string _address;int _age; }; class Teacher {string _name;int _level;int _tel;int id;string _address;int _ag…

Hackthebox - Authority

#ansible #Certify 赛博雨天&#xff1a;https://yutianqaq.github.io/ Recon smb smbmap -H 10.10.11.222 -u 挂载 smb 到 kali mount -t cifs //10.10.11.222/Development ./smb -o usernamesmb 在 cat smb/Automation/Ansible/PWM/defaults/main.yml 得到 ansible 的加…

循环队列与循环双端队列

文章目录 前言循环队列循环双端队列 前言 1、学习循环队列和循环双端队列能加深我们对队列的理解&#xff0c;提高我们的编程能力。 2、本文循环队列使用的是数组&#xff0c;循环双端队列用的是双向链表 3、题目连接&#xff1a;设计循环队列 &#xff0c;设计循环双端队列。 …

2024高频前端面试题 HTML 和 CSS 篇

JS和ES6 篇&#xff1a; ​​​​​​​2024高频前端面试题 JavaScript 和 ES6 篇-CSDN博客 一 . HTML 篇 1. H5有什么新特性 1) 语义化标签 用正确的标签做正确的事情。 html 语义化让页面的内容结构化&#xff0c;结构更清晰&#xff0c;便于对浏览器、搜索引擎解析&…

Springboot实现缓存预热

很多时候我们代码中使用缓存时都是先判断缓存中没有数据我们再读取数据库而有则直接使用缓存数据&#xff0c;而在系统冷启动(当系统重启或新启动时&#xff0c;缓存是空的&#xff0c;这被称为冷启动)时&#xff0c;我们毫无意外都是直接获取数据库的内容&#xff0c;这时候缓…

Pytorch Geometric 将表格数据集(CSV 文件)转换为图形数据集

导 读 如今图数据集正在以惊人的速度出现&#xff0c;所有化学分子、社交网络和推荐系统主要以图数据结构的形式存储数据 有需要的朋友关注公众号【小Z的科研日常】&#xff0c;获取更多内容。 01、如何转换CSV文件至图形数据结构 确定图形数据所需的基本信息 节点&#xff08;…

ViT的若干细节

之前只看了ViT的大概结构&#xff0c;具体的模型细节和代码实现知之甚少。随着ViT逐渐成为CV领域的backbone&#xff0c;有必要重新审视下。 patch -> token 为了将图片处理成序列格式&#xff0c;很自然地想到将图片分割成一个个patch&#xff0c;再把patch处理成token。 …
最新文章