首页 > 解决方案 > libusb 连接到设备正常,中断传输导致 LIBUSB_ERROR_IO

问题描述

我创建了一个基于 STM32 的 USB 设备,它在原型设计期间与 Python 完美配合。我目前正在尝试将其移植到 C++/Qt 进行生产。我已经将 libusb 与 Qt 集成,并且可以成功打开和关闭设备并读取设备的字符串和描述符。但是,当我尝试向设备发送任何中断 OUT 传输或接收中断 IN 传输时,设备上什么都没有,应用程序中出现 ERROR_IO (-1)。

#define HIL_USB_VID     0x0483
#define HIL_USB_PID     0x572b
#define HIL_USB_OUT_EP  0x01
#define HIL_USB_IN_EP   0x81
#define HIL_PKT_LENGTH  64
#define HIL_PKT_TIMEOUT 100
#define USB_CONFIG_NUM  1
#define USB_IFACE_NUM   0

HILInterface::HILInterface()
{
    this->handle = NULL;
    this->worker = NULL;
}

HILInterface::~HILInterface()
{
    this->disconnect();
}

bool HILInterface::connectMjolnir() {
    if (libusb_init(NULL) < 0)
    {
        qDebug() << "Failed to initialize libusb";
        return false;
    }
    this->handle = libusb_open_device_with_vid_pid(NULL, HIL_USB_VID, HIL_USB_PID);
    if (NULL == this->handle) {
        qDebug() << "Failed to open HIL interface";
        return false;
    }
    int needToDetach = libusb_kernel_driver_active(this->handle, USB_IFACE_NUM);
    if (LIBUSB_SUCCESS == needToDetach || LIBUSB_ERROR_NOT_SUPPORTED == needToDetach) {
        qDebug() << "No need to detach HIL interface from OS";
    } else {
        if (LIBUSB_SUCCESS != libusb_detach_kernel_driver(this->handle, USB_IFACE_NUM)) {
            qDebug() << "Failed to detach HIL interface from OS";
            this->disconnect();
            return false;
        }
    }
    if (LIBUSB_SUCCESS != libusb_set_configuration(this->handle, USB_CONFIG_NUM)) {
        qDebug() << "Failed to set-configuration on HIL interface";
        this->disconnect();
        return false;
    }
    if (LIBUSB_SUCCESS != libusb_claim_interface(this->handle, USB_IFACE_NUM))
    {
        qDebug() << "Failed to claim HIL interface";
        this->disconnect();
        return false;
    }
    qDebug() << "HIL interface connected successfully";
    unsigned char strDesc[256];
    struct libusb_device_descriptor desc;
    struct libusb_config_descriptor ** conDesc = NULL;
    libusb_get_device_descriptor(libusb_get_device(this->handle), &desc);
    libusb_get_string_descriptor_ascii(this->handle, desc.iManufacturer, strDesc, 256);
    qDebug() << "HIL Manufacturer:" << (char*)strDesc;
    libusb_get_string_descriptor_ascii(this->handle, desc.iProduct, strDesc, 256);
    qDebug() << "HIL Product:" << (char*)strDesc;
    libusb_get_string_descriptor_ascii(this->handle, desc.iSerialNumber, strDesc, 256);
    qDebug() << "HIL Serial Number:" << (char*)strDesc;
    this->worker = new HILInterfaceThread();
    this->worker->moveToThread(&workerThread);
    connect(&workerThread, &QThread::finished, this->worker, &QObject::deleteLater);
    connect(this, &HILInterface::startReceiveThread, this->worker, &HILInterfaceThread::run);
    this->worker->handle = this->handle;
    workerThread.start();
    emit startReceiveThread();
    return true;
}

bool HILInterface::disconnectMjolnir() {
    if (NULL == this->handle) {
        return false;
    }
    workerThread.terminate();
    workerThread.wait();
    libusb_release_interface(this->handle, USB_IFACE_NUM);
    libusb_attach_kernel_driver(this->handle, USB_IFACE_NUM);
    libusb_close(this->handle);
    this->handle = NULL;
    libusb_exit(NULL);
    return true;
}

bool HILInterface::sendCommand(uint8_t * msgBuffer, uint16_t msgLen) {
    if (NULL == this->handle) {
        return false;
    }
    int xferCount = 0;
    int errorCode = libusb_interrupt_transfer(this->handle, HIL_USB_OUT_EP, msgBuffer, msgLen, &xferCount, HIL_PKT_TIMEOUT);
    if (LIBUSB_SUCCESS == errorCode) {
        if (HIL_PKT_LENGTH == xferCount) {
            return true;
        }
    }
    return false;
}

标签: qtusblibusblibusb-1.0

解决方案


问题最终出在设备端的 HID 描述符上,而不是 libusb 代码。这是最终使用上述代码的 HID 描述符:

__ALIGN_BEGIN static uint8_t USBD_HID_ReportDesc[HID_REPORT_DESC_SIZE]  __ALIGN_END =
{
        0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
        0x09, 0x01,        // Usage (0x01)
        0xA1, 0x01,        // Collection (Application)
        0x19, 0x01,        //   Usage Minimum (0x01)
        0x29, 0x40,        //   Usage Maximum (0x40)
        0x15, 0x00,        //   Logical Minimum (0)
        0x26, 0xFF, 0x00,  //   Logical Maximum (255)
        0x75, 0x08,        //   Report Size (8)
        0x95, 0x40,        //   Report Count (64)
        0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x19, 0x01,        //   Usage Minimum (0x01)
        0x29, 0x40,        //   Usage Maximum (0x40)
        0x91, 0x00,        //   Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,              // End Collection

        // 29 bytes
};

推荐阅读