编译安装
libusb先编译安装,有个点说一下,我是在aarch64上运行的,所以交叉编译了,如果在x86上可以不用管这几个选项,默认就行了,udev有点难装,但好像不影响,可以disable。
./configure --host=aarch64-linux-gnu --prefix=/your_install_path CC=your_gcc_path/aarch64-linux-gnu-gcc CXX=your_g++_path/aarch64-linux-gnu-g++ --disable-udev
代码示例
示例接入设备为扫码枪
- 支持热插拔功能。
- 支持插入扫码枪后进行其他操作,
doSomthing()。 - 在
checkDevice()中可以根据bInterfaceClass和bInterfaceProtocol自定义接入设备类型。 - 可以直接在
libusb_hotplug_register_callback中设置vendor_id和product_id固定设备。
BarcodeScanner.h
#include <libusb-1.0/libusb.h>
// #include<..> 缺啥补啥
#define BUFFER_SIZE 16 // 缓冲区大小
#define TIMEOUT 10000 // 超时时间 (ms)
#define ENDPOINT 0x81 // 端点地址
/* libusb 函数的宏处理错误 */
#define CHECK_LIBUSB_ERROR(rc, msg) \
if (rc != LIBUSB_SUCCESS) { \
fprintf(stderr, "ERROR: %s failed: %s\n", msg, libusb_error_name(rc)); \
return 0; \
}
class BarcodeScanner {
public:
BarcodeScanner();
~BarcodeScanner();
// 启动设备扫描
void startScanning();
private:
// 查找扫码枪设备
static int checkDevice(libusb_device *dev);
// 释放内核驱动
static int detachKernelDriver(libusb_device_handle *handle);
// 热插拔回调函数
static int hotplugCallback(struct libusb_context *ctx,
struct libusb_device *dev,
libusb_hotplug_event event, void *userData);
// 想做的操作
static void doSomething(libusb_context *&ctx,
libusb_device_handle *handle);
private:
static libusb_context *m_hotplugCtx;
static libusb_hotplug_callback_handle m_hotplugHandle;
static bool m_keepRunning;
BarcodeScanner.cpp
#include "BarcodeScanner.h"
libusb_context *BarcodeScanner::m_hotplugCtx = nullptr;
libusb_hotplug_callback_handle BarcodeScanner::m_hotplugHandle = 0;
bool BarcodeScanner::m_keepRunning = true;
BarcodeScanner::BarcodeScanner() { libusb_init(&m_hotplugCtx); }
BarcodeScanner::~BarcodeScanner() {
if (m_hotplugCtx) {
libusb_exit(m_hotplugCtx);
}
}
int BarcodeScanner::checkDevice(libusb_device *dev) {
struct libusb_device_descriptor desc {};
int rc = libusb_get_device_descriptor(dev, &desc);
CHECK_LIBUSB_ERROR(rc, "libusb_get_device_descriptor")
// 遍历接口并检查 bInterfaceClass 和 bInterfaceProtocol
for (int i = 0; i < desc.bNumConfigurations; i++) {
struct libusb_config_descriptor *config;
rc = libusb_get_config_descriptor(dev, i, &config);
CHECK_LIBUSB_ERROR(rc, "libusb_get_config_descriptor")
for (int j = 0; j < config->bNumInterfaces; j++) {
const struct libusb_interface *inter = &config->interface[j];
for (int k = 0; k < inter->num_altsetting; k++) {
const struct libusb_interface_descriptor *interdesc =
&inter->altsetting[k];
if (interdesc->bInterfaceClass == 3 &&
interdesc->bInterfaceProtocol ==
1) { // HID class 和 keyboard protocol
libusb_free_config_descriptor(config);
return 1; // 找到了设备
}
}
}
libusb_free_config_descriptor(config);
}
return 0;
}
int BarcodeScanner::detachKernelDriver(libusb_device_handle *handle) {
int rc;
for (int i = 0; i < 1; i++) {
rc = libusb_kernel_driver_active(handle, i);
if (rc == 1) {
rc = libusb_detach_kernel_driver(handle, i);
if (rc != LIBUSB_SUCCESS) {
fprintf(stderr, "ERROR: Failed to detach kernel driver: %s\n",
libusb_error_name(rc));
return 0;
}
}
}
return 1;
}
void BarcodeScanner::doSomething(libusb_context *&ctx,
libusb_device_handle *handle) {
unsigned char data[BUFFER_SIZE];
memset(data, 0, sizeof(data));
int actualLength = 0;
int ret;
// 释放内核驱动
int rc = detachKernelDriver(handle);
if (!rc) {
return;
}
while (true) {
memset(data, 0, BUFFER_SIZE);
libusb_set_debug(ctx, 3);
ret = libusb_interrupt_transfer(handle, ENDPOINT, data, BUFFER_SIZE,
&actualLength, TIMEOUT);
if (ret == LIBUSB_SUCCESS) {
// do ....
}
/* 根据情况判断是否停止
m_keep = true;
m_keep = false;
*/
}
}
int BarcodeScanner::hotplugCallback(struct libusb_context *ctx,
struct libusb_device *dev,
libusb_hotplug_event event,
void *userData) {
libusb_device_handle *device_handle = nullptr;
libusb_context *device_ctx = nullptr;
libusb_init(&device_ctx);
int rc;
if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
printf("INFO: Device connected\n");
// 获取所有已连接的 USB 设备的列表
libusb_device **list;
ssize_t cnt = libusb_get_device_list(device_ctx, &list);
if (cnt < 0) {
printf("ERROR: Error getting device list\n");
return 0;
}
// 遍历所有连接的设备并检查所需的设备
int found_device = 0;
for (ssize_t i = 0; i < cnt; i++) {
if (checkDevice(list[i])) {
rc = libusb_open(list[i], &device_handle);
if (rc == LIBUSB_SUCCESS) {
printf("INFO: Please start scanning!\n");
found_device = 1;
// 做操作
m_keepRunning = false;
do_something(device_ctx, device_handle);
// 若结束
if (!m_keepRunning) {
libusb_close(device_handle);
device_handle = nullptr;
libusb_exit(device_ctx);
libusb_exit(ctx);
exit(0);
}
}
}
}
// 释放设备列表
libusb_free_device_list(list, 1);
if (!found_device) {
printf("WARNING: Barcode scanner device not found\n");
}
} else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
printf("INFO: Device disconnected\n");
// 如果设备处于打开状态则关闭设备
if (device_handle) {
libusb_exit(device_ctx);
libusb_close(device_handle);
device_handle = nullptr;
printf("INFO: Device closed\n");
printf(
"INFO: Operation paused, waiting for the barcode scanner to "
"reconnect\n");
}
}
return 0;
}
void BarcodeScanner::startScanning() {
libusb_hotplug_register_callback(
m_hotplugCtx,
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, hotplugCallback,
nullptr, &m_hotplugHandle);
while (m_keepRunning) {
libusb_handle_events(m_hotplugCtx);
}
}
main.cpp
#include "BarcodeScanner.h"
int main() {
BarcodeScanner scanner;
scanner.startScanning();
return 0;
}
CMakeLists.txt
include_directories(${CMAKE_CURRENT_LIST_DIR}/../libusb/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/../libusb/lib)
set(LIB_SRC BarcodeScanner.cpp)
add_library(scan STATIC ${LIB_SRC})
find_library(LIBUSB_LIBRARY
NAMES usb-1.0)
set(LIBS
scan
usb-1.0
pthread
)
add_executable(BarcodeScanner main.cpp)
add_dependencies(BarcodeScanner scan)
target_link_libraries(BarcodeScanner ${LIBS})