Search code examples
usblibusblibusb-1.0

Bulk transfer sending too much (multiple of usb packet?)


Problem I am trying to solve

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 solution that does not work

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?


Solution

  • 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; }