libusb使用

833 阅读3分钟

编译安装

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

代码示例

示例接入设备为扫码枪

  1. 支持热插拔功能。
  2. 支持插入扫码枪后进行其他操作,doSomthing()
  3. checkDevice()中可以根据bInterfaceClassbInterfaceProtocol自定义接入设备类型。
  4. 可以直接在libusb_hotplug_register_callback中设置vendor_idproduct_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})