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