Search code examples
c++windowswritefilehidapi

hidapi: Sending packet smaller than caps.OutputReportByteLength


I am working with a device (the wiimote) that takes commands through the DATA pipe, and only accepts command packets that are EXACTLY as long as the command itself. For example, it will accept:

0x11 0x10

but it will not accept:

0x11 0x10 0x00 0x00 0x00 ... etc.

This is a problem on windows, as WriteFile() on windows requires that the byte[] passed to it is at least as long as caps.OutputReportByteLength. On mac, where this limitation isn't present, my code works correctly. Here is the code from hid.c that causes this issue:

/* Make sure the right number of bytes are passed to WriteFile. Windows
   expects the number of bytes which are in the _longest_ report (plus
   one for the report number) bytes even if the data is a report
   which is shorter than that. Windows gives us this value in
   caps.OutputReportByteLength. If a user passes in fewer bytes than this,
   create a temporary buffer which is the proper size. */
if (length >= dev->output_report_length) {
    /* The user passed the right number of bytes. Use the buffer as-is. */
    buf = (unsigned char *) data;
} else {
    /* Create a temporary buffer and copy the user's data
       into it, padding the rest with zeros. */
    buf = (unsigned char *) malloc(dev->output_report_length);
    memcpy(buf, data, length);
    memset(buf + length, 0, dev->output_report_length - length);
    length = dev->output_report_length;
}
res = WriteFile(dev->device_handle, buf, length, NULL, &ol);

Removing the above code, as mentioned in the comments, results in an error from WriteFile().

Is there any way that I can pass data to the device of arbitrary size? Thanks in advance for any assistance.


Solution

  • Solved. I used a solution similar to the guys over at Dolphin, a Wii emulator. Apparently, on the Microsoft bluetooth stack, WriteFile() doesn't work correctly, causing the Wiimote to return with an error. By using HidD_SetOutputReport() on the MS stack and WriteFile() on the BlueSoleil stack, I was able to successfully connect to the device (at least on my machine).

    I haven't tested this on the BlueSoleil stack, but Dolphin is using this method so it is safe to say it works.

    Here is a gist containing an ugly implementation of this fix: https://gist.github.com/Flafla2/d261a156ea2e3e3c1e5c