(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│└─usbusb.priUSB_Hotplug.cppUSB_Hotplug.hUSB_Reset.cppUSB_Reset.h
Code
项目文件
usbReset.pro
QT += core
QT += widgets#CONFIG += console
CONFIG += c++17DESTDIR = $$PWD/bininclude($$PWD/usb/usb.pri)INCLUDEPATH += $$PWD/code
HEADERS += \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/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.hSOURCES += \$$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_1682212693extern "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 & exitstatic 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() {/// 有实体对象才重置 contextif (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 datalibusb_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) {/// retlibusb_device_descriptor descriptor;/// help datalibusb_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) {/// retlibusb_device* device = nullptr;/// help datalibusb_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) => logreturn 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 <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_OBJECTprivate: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
相关文章:
(libusb) usb口自动刷新
文章目录 libusb自动刷新程序Code目录结构Code项目文件usb包code包 效果描述重置reset热拔插使用 END libusb 在操作USB相关内容时,有一个比较著名的库就是libusb。 官方网址:libusb 下载: 下载源码官方编好的库github:Release…...
NLP(一)——概述
参考书: 《speech and language processing》《统计自然语言处理》 宗成庆 语言是思维的载体,自然语言处理相比其他信号较为特别 word2vec用到c语言 Question 预训练语言模型和其他模型的区别? 预训练模型是指在大规模数据上进行预训练的模型,通常…...
智慧公厕:打造智慧城市的环卫明珠
在城市建设中,公共卫生设施的完善和智能化一直是重要环节。而智慧公厕作为智慧城市建设的重要组成部分,发挥着不可替代的作用。本文以智慧公厕源头实力厂家广州中期科技有限公司,大量精品案例现场实景实图,解读智慧公厕如何助力打…...
[LeetBook]【学习日记】寻找链表相交节点
来源于「Krahets」的《图解算法数据结构》 https://leetcode.cn/leetbook/detail/illustration-of-algorithm/ 本题与主站 160 题相同:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ 训练计划 V 某教练同时带教两位学员,分别以…...
【Python】OpenCV-使用ResNet50进行图像分类
使用ResNet50进行图像分类 如何使用ResNet50模型对图像进行分类。 import os import cv2 import numpy as np from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input, decode_predictions from tensorflow.keras.preprocessing import image# 设置…...
TypeError: `dumps_kwargs` keyword arguments are no longer supported
TypeError: dumps_kwargs keyword arguments are no longer supported 1. 问题描述2. 解决方法 1. 问题描述 使用 FastChat 启动私有大语言模型,通过一些 UI 工具进行访问时,报以下错误。 略 2024-02-29 09:26:14 | ERROR | stderr | yield f"…...
设计模式学习笔记 - 设计原则 - 3.里氏替换原则,它和多态的区别是什么?
前言 今天来学习 SOLID 中的 L:里氏替换原则。它的英文翻译是 Liskov Substitution Principle,缩写为 LSP。 英文原话是: Functions that use points of references of base classes must be able to use objects of derived classes withou…...
java实现图片转pdf,并通过流的方式进行下载(前后端分离)
首先需要导入相关依赖,由于具体依赖本人也不是记得很清楚了,所以简短的说一下。 iText:PDF 操作库,用于创建和操作 PDF 文件。可通过 Maven 或 Gradle 引入 iText 依赖。 MultipartFile:Spring 框架中处理文件上传的类…...
如何系统的学习Python——Python的基本语法
学习Python的基本语法是入门的第一步,以下是一些常见的基本语法概念: 注释: 用#符号来添加单行注释,或使用三引号(或""")来添加多行注释。 # 这是一个单行注释 这是 多行 注释 变量和数据类型: 变量用…...
相机,棱镜和光场
一、成像方法 Imaging Synthesis Capture 1.Synthesis(图形学上)合成:比如之前学过的光线追踪或者光栅化 2.Capture(捕捉):把真实世界存在的东西捕捉成为照片 二、相机 1.小孔成像 利用小孔成像的相…...
【图像版权】论文阅读:CRMW 图像隐写术+压缩算法
不可见水印 前言背景介绍ai大模型水印生成产物不可见水印CRMW 在保护深度神经网络模型知识产权方面与现有防御机制有何不同?使用图像隐写术和压缩算法为神经网络模型生成水印数据集有哪些优势?特征一致性训练如何发挥作用,将水印数据集嵌入到…...
代码随想录算法训练营第31天—贪心算法05 | ● 435. 无重叠区间 ● *763.划分字母区间 ● *56. 合并区间
435. 无重叠区间 https://programmercarl.com/0435.%E6%97%A0%E9%87%8D%E5%8F%A0%E5%8C%BA%E9%97%B4.html 考点 贪心算法重叠区间 我的思路 先按照区间左坐标进行排序,方便后续处理进行for循环,循环范围是0到倒数第二个元素如果当前区间和下一区间重叠…...
2024《》
vue-cli到哪做了那些事 vue-cli是vue.js的脚手架,用于自动生成vue.jswebpack的项目模板,快速搭建Vue.js项目。 vue cli内置了webpack的一些功能,这些是用webpack打包时需要我们自己配置的,例如: 1.ES6代码转换成ES5代…...
【Web】Java反序列化之从CC3看TemplatesImpl的利用
目录 关于TemplatesImpl 关于TemplatesImpl加载字节码 CC3链分析 纯CC3demo 根据CC3改CC6 关于TemplatesImpl TemplatesImpl 是 Java 中的一个类,通常与 Java 反序列化漏洞相关的攻击中被使用。该类位于 Java 标准库中的 javax.xml.transform 包下。 在 Java…...
【Elasticsearch索引】Recovery恢复索引
文章目录 索引恢复恢复列表获取恢复信息响应详细信息正在进行的恢复响应解析高级设置 本地分片恢复事务日志 索引恢复 索引恢复提供了对正在进行的索引分片恢复的洞察。恢复状态可以针对特定的索引报告,也可以在集群范围内报告。 恢复列表 recovery命令是索引分片…...
如何在 Linux 中快速清空文件而不删除它们?
在Linux系统中,清空文件而不删除它们是一种常见的需求,特别是在需要保留文件结构或权限的情况下。本文将详细介绍如何在Linux环境中快速清空文件内容的多种方法,以及每种方法的优缺点。清空文件通常涉及到文件内容的擦除,但并不涉…...
SpringBoot 配置文件${variable:default}用法
${variable:default}用法,variable是变量名,default是默认值。如果配置文件中未指定该变量的值,则会使用默认值来替代。 解释代码: ip: ${NACOS_IP:nacos.ip} 该yaml函数是一个配置项,用来指定Nacos服务器的IP地…...
CUDA学习笔记02:测试程序hello world
参考资料 Win10下在VS2019中配置使用CUDA进行加速的C项目 (配置.h文件,.dll以及.lib文件等)_vs2019 cuda-CSDN博客 配置流程 1. 新建一个一般的项目 2. 项目建好后,在项目里添加.cu测试文件 测试的.cu文件命名为cuda_utils.cu&…...
2023年第十四届蓝桥杯大赛软件类省赛C/C++大学A组真题
2023年第十四届蓝桥杯大赛软件类省赛C/C大学A组部分真题和题解分享 文章目录 蓝桥杯2023年第十四届省赛真题-平方差思路题解 蓝桥杯2023年第十四届省赛真题-更小的数思路题解 蓝桥杯2023年第十四届省赛真题-颜色平衡树思路题解 蓝桥杯2023年第十四届省赛真题-买瓜思路题解 蓝桥…...
项目部署发布
目录 上传数据库 修改代码中的数据源配置 修改配置文件中的日志级别和日志目录 打包程序 编辑编辑 上传程序 查看进程是否在运行 以及端口 云服务器开放端口(项目所需要的端口) 上传数据库 通过xshell控制服务器 创建目录 mkdir bit_forum 然后进入该目录 查看路…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
