libusb 连接到设备正常,中断传输导致 LIBUSB_ERROR_IO
libusb connects to device fine, interrupt transfer results in 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;
}
问题最终出在设备端的 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
};
我创建了一个基于 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;
}
问题最终出在设备端的 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
};