I am sending data over usb with libusb_bulk_transfer
, with something like this:
int sent = 0;
int bulk_result = libusb_bulk_transfer(handle, endpoint_out->bEndpointAddress, buffer,
buffer_len, &sent, 5000);
and I receive those transfers on the other side in Kotlin (Android).
Most of the time, it works: I send a buffer of side, say, 289 bytes, and on the other side I receive 289 bytes.
Sometimes, however, I receive too much. Say I send 1536 bytes, and I receive 1719 bytes.
My understanding (e.g. from here) is that "A bulk transfer is considered complete when it has transferred the exact amount of data requested, transferred a packet less than the maximum endpoint size, or transferred a zero-length packet".
And because 1536 is a multiple of 64 (and all the wrong packets I receive are multiples of 64), I thought that this was my issue. So I went for sending a zero-length packet after I send a buffer that is a multiple of the maximum endpoint size. And I duly noted that the maximum endpoint size is not necessarily 64, so I wanted to detect it.
Here is my "solution":
int sent = 0;
int bulk_result = libusb_bulk_transfer(handle, endpoint_out->bEndpointAddress, buffer,
buffer_len, &sent, 5000);
if (sent % get_usb_packet_size() == 0) {
libusb_bulk_transfer(handle, endpoint_out->bEndpointAddress, nullptr, 0, &sent, 5000);
}
With the simple get_usb_packet_size()
below, which happens to be 256:
int get_usb_packet_size() { return endpoint_out->wMaxPacketSize; }
Still, that does not seem to work! The return code of both libusb_bulk_transfer
is 0 (success), the first one says it sent buffer_len
bytes (as expected), and the second one says it sent 0 bytes (as expected).
But my receiver still receives packets that are longer than what is expected. I tried using 64 instead of 256 (therefore sending more zero-length packets), but I still get that same problem.
What am I missing?
The issue was due to concurrency: two threads were calling my code above, and therefore sometimes one thread would not have time to send the zero-length packet right after its packet.
So this actually seems to work:
int sent = 0;
int bulk_result = libusb_bulk_transfer(handle, endpoint_out->bEndpointAddress, buffer,
buffer_len, &sent, 5000);
if (sent % get_usb_packet_size() == 0) {
libusb_bulk_transfer(handle, endpoint_out->bEndpointAddress, nullptr, 0, &sent, 5000);
}
with
int get_usb_packet_size() { return endpoint_out->wMaxPacketSize; }