行业知识
(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 += 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_1682212693USB_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 USBUSB_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_27452998650USB_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 (rccode包
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_27453073957WIDGET_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
- 使用libusb_close()
- 获取device*
- 基于Qt的ui和线程
- 3rdparty包
上一篇:服务器怎么访问客户端?
下一篇:单位网站怎么建设?