I "created" a very basic USB device of communication class using an STM32 (f446re) that simply sends a sentence every second. Now I am writing a program to read the said sentence on the computer the device is connected to. I decided to use libusb library as it is apparently cross-platform and it seemed fairly easy to use.
I wrote my little program on Linux as it is the OS I use to code, I can provide details on the code if you want me to but basically I:
After setting some custom udev rule with my VID and PID it worked perfectly fine.
So I decided to try it on Windows and the first issue I encountered was a LIBUSB_ERROR_NOT_SUPPORTED when trying to open the device. After some googling I found out that USB CDC has no driver by default on Windows or whatever (unlike Mass Storage devices and Human Machine Interface devices) so I had to install some generic USB driver like WinUSB. So I did, using a software called Zadig, I also removed the code to detach kernel driver because I had to apparently and now I can open the device but the transfer fails with LIBUSB_ERROR_NOT_FOUND.
I have tried many things and none worked, here is the full log with debug level set to 4 starting from the opening of the device:
[ 0.077542] [00005830] libusb: debug [libusb_open] open 3.2
[ 0.078566] [000022f0] libusb: debug [libusb_claim_interface] interface 0
[ 0.078694] [000022f0] libusb: debug [winusbx_claim_interface] claimed interface 0
[ 0.079206] [000022f0] libusb: debug [windows_assign_endpoints] (re)assigned endpoint 82 to interface 0
[ 0.079853] [00000280] libusb: debug [windows_iocp_thread] ignoring overlapped 000000FB54DFF8D0 for handle 000002181F1A3310
[ 0.080480] [00000280] libusb: debug [windows_iocp_thread] ignoring overlapped 000000FB54DFF8D0 for handle 000002181F1A3310
[ 0.081122] [000022f0] libusb: debug [libusb_submit_transfer] transfer 000002181F1930E0
[ 0.081842] [00000280] libusb: debug [windows_iocp_thread] ignoring overlapped 000000FB54DFF8D0 for handle 000002181F1A3310
[ 0.085782] [000022f0] libusb: debug [add_to_flying_list] arm timer for timeout in 2000ms (first in line)
[ 0.086302] [00000280] libusb: debug [windows_iocp_thread] ignoring overlapped 000000FB54DFF8D0 for handle 000002181F1A3310
[ 0.086975] [000022f0] libusb: error [winusbx_submit_bulk_transfer] unable to match endpoint to an open interface - cancelling transfer
[ 0.087657] [00000280] libusb: debug [windows_iocp_thread] ignoring overlapped 000000FB54DFF9B0 for handle 000002181F1A3310
[ 0.088588] [000022f0] libusb: debug [arm_timer_for_next_timeout] no timeouts, disarming timer
Failed to submit bulk transfer: LIBUSB_ERROR_NOT_FOUND
[ 0.091200] [000022f0] libusb: debug [libusb_free_transfer] transfer 000002181F1930E0
[ 0.091677] [000022f0] libusb: debug [libusb_release_interface] interface 0
I don't understand shit, including the fact that it says "(re)assigned endpoint 82" even though in my code the endpoint is set to 81 because this is the endpoint my USB device is sending data through.
I can post details on the USB device using USBView or send parts of the code if needed.
EDIT (add some code):
void LIBUSB_CALL bulk_callback(struct libusb_transfer* transfer) {
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
std::cout << "Bulk transfer completed successfully. Received " << transfer->actual_length << " bytes" << std::endl;
// Re-submit the transfer for continuous reception
int error = libusb_submit_transfer(transfer);
if (error < 0) {
std::cerr << "Error re-submitting transfer: " << libusb_error_name(error) << std::endl;
}
} else {
std::cerr << "Transfer failed with status: " << libusb_error_name(transfer->status) << std::endl;
libusb_free_transfer(transfer);
}
}
int main() {
int error = libusb_open(device, &m_selected_device);
if (error < 0) {
m_working = false;
std::cerr << "Error: failed to open device: " << libusb_error_name(error) << std::endl;
return;
}
error = libusb_claim_interface(m_selected_device, INTERFACE_NUMBER); // 0
if (error < 0) {
std::cerr << "Error claiming interface: " << libusb_error_name(error) << std::endl;
return;
}
// Communication here
struct libusb_transfer* transfer = libusb_alloc_transfer(0);
if (!transfer) {
m_error = true;
std::cerr << "Failed to allocate transfer" << std::endl;
libusb_release_interface(m_selected_device, INTERFACE_NUMBER);
clean_up();
return;
}
// Allocate a buffer for receiving data
unsigned char* buffer = (unsigned char*) malloc(TRANSFER_SIZE);
if (!buffer) {
std::cerr << "Failed to allocate buffer" << std::endl;
libusb_free_transfer(transfer);
libusb_release_interface(m_selected_device, INTERFACE_NUMBER);
clean_up();
return;
}
// Fill the bulk transfer with the endpoint, buffer, size, and callback
libusb_fill_bulk_transfer(
transfer,
m_selected_device,
ENDPOINT_IN, // 0x81
buffer,
TRANSFER_SIZE, // 64
bulk_callback,
NULL,
TIMEOUT
);
// Submit the transfer to the USB stack
error = libusb_submit_transfer(transfer);
if (error < 0) {
std::cerr << "Failed to submit bulk transfer: " << libusb_error_name(error) << std::endl;
free(buffer);
libusb_free_transfer(transfer);
libusb_release_interface(m_selected_device, INTERFACE_NUMBER);
clean_up();
return;
}
// Main loop
while (m_working) {
error = libusb_handle_events(m_context);
if (error < 0) {
std::cerr << "Error handling events: " << libusb_error_name(error) << std::endl;
break;
}
}
error = libusb_release_interface(m_selected_device, INTERFACE_NUMBER);
if (error < 0) {
std::cerr << "Error releasing interface: " << libusb_error_name(error) << std::endl;
}
free(buffer);
if (m_selected_device) {
libusb_close(m_selected_device);
m_selected_device = NULL;
}
return 0;
}
The actual problem was a wrong interface number. My only guess is that there is some sort of error correction that differs in behavior on Windows and on Linux. On Linux it corrected the interface number from 0 to 1 (which was the actual interface I was sending data through) so the program worked but on Windows it corrected the endpoint number in the wrong interface and this is why it said endpoint 0x82 in the log and this is also why it did not work.