It always starts with a prototype...

Some days ago, while crafting a quick prototype on top of an Arduino Leonardo board, we noticed that the USB HID emulation part of the core (Arduino) libraries was always enabled.

In short, the above means that:

  • Whether you need to use the USD HID emulation or not, the related code is always compiled and "active", wasting some of your precious Flash memory.
  • The Arduino core libraries will always report the same hardwired USB HID report descriptor to the USB host.
  • The hardwired HID report descriptor identifies the Leonardo itself as both a mouse and a keyboard.

For our prototype, the described behaviour was problematic, not because of the wasted resources, but because the host, an Nexus 7 Android tablet, was recognizing the Leonardo as a keyboard capable USB device. To our surprise, when Android detects an external USB keyboard, it disables by default its own virtual keyboard (!). The result is a quite unusable tablet.

As there is no officially documented way to disable the USB HID keyboard emulation in Arduino, I made a quick patch to the core libraries. Hurrah for the open source software!

What is the purpose of the USB HID report descriptor?

According to the official USB documentation "Device Class Definition for Human Interface Devices (HID) Version 1.11",

A Report descriptor describes each piece of data that the device generates and what the data is actually measuring.

The report descriptor itself is a compact list (array) of bytes, which the USB device sends to the USB host during the enumeration process. Unless you really need to work at very low level or want to create your own custom HID peripheral, you should no require to understand or modify the individual bytes composing the descriptor.

In case you need to know about the very specific meaning of each item in the report descriptor, don't be afraid to go straight to the source, the official USB HID documentation. It is openly available (check the URL below) and easier to understand that you may have initially thought. In contrast with other standards documentation, it is a fairly short and well written document.

Disabling a section of the report descriptor

This patch works with the Arduino core libraries included with the latest version of the software, 1.6.5-r3 at the time of this writing. However, it should work also with older versions (1.5.8 or higher).

We will be slightly modifying a single file from the core libraries, Hid.cpp, located under Arduino/hardware/arduino/avr/cores/arduino/. If you open this file with a text editor, you will notice a constant array of bytes named _hidReportDescriptor, which is where the actual USB HID report descriptor is defined.

The array has three sections, each one of them starting with a comment, corresponding to Mouse, Keyboard and raw data.

const u8 _hidReportDescriptor[] = {  
    //  Mouse
    [...some lines omitted...]
    //  Keyboard
    [...some lines omitted...]
 #ifdef RAWHID_ENABLED
    //  RAW HID
    [...some lines omitted...]
 #endif
};

In the code above, you can clearly see that the Raw section can be enabled by defining the macro constant RAWHID_ENABLED. If you check the beginning of the HID.cpp file, you can read:

//#define RAWHID_ENABLED

Which means that, by default, your Arduino core library does not define the constant RAWID_ENABLED.

You can check the original Arduino file here.

Hands on making the actual changes

Under OS X, if you installed the Arduino software as a bundled (packaged) application, you can find the file HID.cpp by executing these steps:

  1. Open a Finder and go to your Applications folder.
  2. Right click on the file Arduino.app and click on "Show Package Contents".
  3. Navigate to Contents/Java/hardware/arduino/avr/cores/arduino/HID.cpp

Under Windows, the path should look similar to
...\arduino-1.6.0\Arduino\hardware\arduino\avr\cores\arduino\HID.cpp

Now we are ready to make the appropriate changes to the HID.cpp file. First, we will add a pair of #ifdef/#endif delimiters around the Keyboard section of the constant, like this:

 const u8 _hidReportDescriptor[] = {
    //  Mouse
    [...some lines omitted...]
 #ifdef KEYBOARD_ENABLED
    //  Keyboard
    [...some lines omitted...]
 #endif
 #ifdef RAWHID_ENABLED
    //  RAW HID
    [...some lines omitted...]
 #endif
};

Then, we will add a line near the top of the file, undefining the macro constant KEYBOARD_ENABLED. With this we are effectively disabling the USB HID Keyboard emulation of our Arduino.

//#define KEYBOARD_ENABLED

You can check the updated file at our github. To enable the keyboard again, you just need to uncomment this last line.

Beware that:

  1. You will have to modify the file HID.cpp each time that you want to change the USB HID behaviour and before you compile your Arduino code.
  2. It is very easy to forget about this file and the changes you made to it and then, starting a new USB HID Arduino project and not getting the results you were expecting...

The Arduino community comes to the rescue

You can bet many other Arduino users were annoyed with this issue: USB HID emulation not being easily configurable from your sketch code.

When I was pushing the patch above to the official Arduino code base, I was informed by the community developers that a new pluggable USB emulation component was in development. It is scheduled (hopefully) for the next-to-come version 1.6.6.

In the meantime, you can check how the issue is being worked out at the Arduino project github... and even premier the new code!

In the future version, should you want to enable only the Mouse USB HID emulation, for example, you will simply add at the beginning of your sketch,
#include "Mouse.h" #include "HID.h"

To know more

You can check out some useful references:


If you liked this content and don't want to miss future articles, you can subscribe to our mailing list and get notified!

About the Author