This article focuses on how to use the existing USB code library and HID report descriptor info to implement joystick functionality. Human readable HID report descriptor and report information can be easily obtained using USBHID_desc.pde sketch – see previous article for details. This information will help you getting field details such as size and count info. Also, if you don’t have Arduino Mega or 2560 to run USBHID_desc, report descriptor for your device can be obtained using one of many PC tools known as USB analyzers, or even the official usb.org device verification tool. This article is written by Alex Glushchenko – a developer behind second revision of USB Host Library as well as majority of device support code.
As you may already know report is a data structure used by HID device to return the information about the certain device parameters such as joystick coordinates or button events, or receive new settings such as switching on/off LEDs on keyboard.
Report descriptor is a data structure which describes report or reports, if there are few in number, field sequence, sizes and counts. Each report descriptor consists of several items. Each item describes some field property. I am not going too deep into details on items, explaining only the most important ones which are absolutely necessary in writing your own report parser.
The items usually describe type of field (input/output/feature), minimum, maximum field values, units, value meaning (usage) etc.
The joystick I’m using can be seen on title picture (click on it to make it bigger). Here is how my joystick report descriptor looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | Usage Page Gen Desktop Ctrls(01) Usage Game Pad Collection Application Collection Logical Report Size(08) Report Count(05) Logical Min(00) Logical Max(FF00) Physical Min(00) Physical Max(FF00) Usage X Usage Y Usage Z Usage Z Usage Rz Input(00000010) Report Size(04) Report Count(01) Logical Max(07) Physical Max(3B01) Unit(14) Usage Hat Switch Input(01000010) Unit(00) Report Size(01) Report Count(0C) Logical Max(01) Physical Max(01) Usage Page Button(09) Usage Min(01) Usage Max(0C) Input(00000010) Usage Page Undef(00) Report Size(01) Report Count(08) Logical Max(01) Physical Max(01) Usage Input(00000010) End Collection Collection Logical Report Size(08) Report Count(07) Physical Max(FF00) Logical Max(FF00) Usage Output(00000010) End Collection End Collection |
It may look puzzling at first sight, but soon it is going to look more clear to you. HID specification makes it possible for any host to know exactly what the certain report field means by introducing usages and usage tables.
Usage table specifies all possible controls and device setting IDs for a given class of devices, such as game controllers.
So, analyzing report descriptor dump you have to pay attention to usage table, usage, report size, report count, input and output items.
Now let’s see what we have in the dump. First we have five (line 6) input (line 16) fields X, Y, Z, Z, Rz for Game Pad (lines 11-15), 8-bit in size each (line 5), followed by 4-bit Hat Switch field, 12 buttons, 1-bit each, 8-bit field with unknown usage. 64 bit in total which is 8 bytes. You don’t have to calculate Output items unless you plan to make use of output report.
Now let me explain some details. Each report field or group of fields with the same properties is described by a number of items. Each field explanation ends with an Input, Output or Feature item. Take another look at the dump. Game Pad fields are five in number which is specified by Report Count(05), 8 bit in size Report Size(08) and individual usages for X, Y, Z, Z and Rz. Hat Switch is one field 4-bit in size, 12 buttons are described by Usage Page Button(09) and usage range specified by Usage Min(01) and Usage Max(0C).
Now you know how to interpret report descriptor dump. Let’s go down to code. There is a sample sketch called USBHIDJoystick.pde which we are going to look at. Just make sure you have the latest version of the USB Host library downloaded. With the current version of the USB Host library you do not have to write all the code from scratch, use HIDUniversal class to reuse the main functionality responsible for USB interaction. You have to inherit HIDReportParser class to implement report parser functionality and provide its address by SetReportParser method to HIDUniversal class instance. Files hidjoystickrptparser.h and hidjoystickrptparser.cpp contain all the interesting code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | struct GamePadEventData { uint8_t X, Y, Z1, Z2, Rz; }; class JoystickEvents { public: virtual void OnGamePadChanged(const GamePadEventData *evt); virtual void OnHatSwitch(uint8_t hat); virtual void OnButtonUp(uint8_t but_id); virtual void OnButtonDn(uint8_t but_id); }; #define RPT_GEMEPAD_LEN 5 class JoystickReportParser : public HIDReportParser { JoystickEvents *joyEvents; uint8_t oldPad[RPT_GEMEPAD_LEN]; uint8_t oldHat; uint16_t oldButtons; public: JoystickReportParser(JoystickEvents *evt); virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); }; |
Now consider Parse() method functionality. Because the event buffer allocated for the report is pretty large and the size of my joystick report is only 8 byte long, Parse() is called only once per each report.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | void JoystickReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { bool match = true; // Checking if there are changes in report since the method was last called for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++) if (buf[i] != oldPad[i]) { match = false; break; } // Calling Game Pad event handler if (!match && joyEvents) { joyEvents->OnGamePadChanged((const GamePadEventData*)buf); for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i]; } uint8_t hat = (buf[5] & 0xF); // Calling Hat Switch event handler if (hat != oldHat && joyEvents) { joyEvents->OnHatSwitch(hat); oldHat = hat; } uint16_t buttons = (0x0000 | buf[6]); buttons <<= 4; buttons |= (buf[5] >> 4); uint16_t changes = (buttons ^ oldButtons); // Calling Button Event Handler for every button changed if (changes) { for (uint8_t i=0; i<0x0C; i++) { uint16_t mask = (0x0001 << i); if (((mask & changes) > 0) && joyEvents) if ((buttons & mask) > 0) joyEvents->OnButtonDn(i+1); else joyEvents->OnButtonUp(i+1); } oldButtons = buttons; } } |
The logic is the same for all report fields. First the report buffer is checked against the previously saved one for the data changes. If changes found the appropriate event handler is invoked with the current state data passed as a function argument. In case of Game Pad the current state data is passed as structure pointer. In case of the Hat Switch the current state is passed as integer value.
Handling buttons is a bit more complicated. Lines 30-33 are responsible for finding out which buttons have changed their states since the last Parse() call. Cycling through each bit of the mask we find out the current state of the changed button. If the button is pressed, OnButtonDn() event handler is called. If the button released, OnButtonUp() event handler is called.
If your joystick report has different structure, all you have to do is modify the Parse method to change fields offsets and sizes. Pretty simple, isn’t it?
The last component of the code is actual event handlers. In this example they simply output game pad, hat switch and button states to the serial console. Again, the body of each function can easily be modified to perform something more useful.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) { Serial.print("X: "); PrintHex<uint8_t>(evt->X); Serial.print("\tY: "); PrintHex<uint8_t>(evt->Y); Serial.print("\tZ: "); PrintHex<uint8_t>(evt->Z1); Serial.print("\tZ: "); PrintHex<uint8_t>(evt->Z2); Serial.print("\tRz: "); PrintHex<uint8_t>(evt->Rz); Serial.println(""); } void JoystickEvents::OnHatSwitch(uint8_t hat) { Serial.print("Hat Switch: "); PrintHex<uint8_t>(hat); Serial.println(""); } void JoystickEvents::OnButtonUp(uint8_t but_id) { Serial.print("Up: "); Serial.println(but_id, DEC); } void JoystickEvents::OnButtonDn(uint8_t but_id) { Serial.print("Dn: "); Serial.println(but_id, DEC); } |
The full text of Arduino sketch plus parsers/callbacks is available on GitHub. The code works with USB Host Shield 2.0, it has been tested on Arduino UNO, Mega, as well as Mega 2560. Unlike USBHID_desc this code takes just a little more than 16K of program space. The joystick I use is a random eBay unit (note from Oleg: I have a wireless HID joystick which looks quite differently from this one, however, the report descriptor is the same. If you have similar one, try it – it may work with this code without any modifications). If you’re shopping for a joystick, make sure it has analog game pads, otherwise you will only see values 0×00, 0×80 and 0xff from them. Also, all HID devices are picky about power, if you see strange behaviour while running your Arduino from USB the first thing to do is switch to external supply.
Try this code and if you see any issues or errors, please leave a comment. Also, if you have other HID devices you’d like me to cover, please let me know.
Related posts:
- Using Logitech Extreme 3D Pro joystick with Arduino HID library
- CueCat meets Arduino, works with HID boot code
- Visualizing HID device reports and report descriptors
- Bluetooth code for Arduino USB Host
- Arduino USB Host – Peripherals.
- Exchanging data between USB devices and Android phone using Arduino and USB Host shield
- PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 2
- HID support for USB Host Shield Library 2.0 released
- Arduino USB Host – USB Descriptors.
- Arduino USB host – Pre-prototyping.

Can you add Arm_mouse project to the examples of USBHIDBootKbd examples ?!!!!!
every day opening the site and waiting … i swear that i tried to make that work o rev 2.0 but i cant i a beginner in this …. why you don’t want to do that !!!
sorry i mean usbhidbootmouse examples
Works like charm… nice work.
I’m comfortable within arduino’s processing environment, but I get lost within C++. Is there any way to access the button states from within arduino’s loop() function?
I realize I can go in and change the code within the event handlers, and I’ve been playing around with it, but don’t completely grok it yet. Is there any way to access the button states from within my pde file as the code is written now? I just want to do some simple state checking, and I’m having a hard time understanding the C++ code, ie:
void loop(){
Serial.print("X: ");
PrintHex(JoystickEvents::X);
}
How far off am I?
I figured it out. It took me a few hours, but I was able to do it. I would still appreciate your feedback. I’m sure there’s a way to do this better, but this works.
In case anyone else is interested, this is how I did it:
In the header file, I gave the JoystickEvents class a few more members – one for each of the buttons:
class JoystickEvents
{
public:
virtual void OnGamePadChanged(const GamePadEventData *evt);
virtual void OnHatSwitch(uint8_t hat);
virtual void OnButtonUp(uint8_t but_id);
virtual void OnButtonDn(uint8_t but_id);
uint8_t X;
uint8_t Y;
// ... etc.
};
Then, I changed the event handler to populate those variables instead of printing:
void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt)
{
X = evt->X;
Y = evt->Y;
}
Now, in my PDE file, I can access the member variables:
void loop(){
Usb.Task();
float freq = map(JoyEvents.X, 0, 0xFF, 30.0f, 250.0f);
}
This will work; the better way to do it is to use callbacks directly.
I’m not sure where to post this, but I have a USB HID magentic card swiper that is USB – shows up the following:
0000: 05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
0010: 75 01 95 08 81 02 95 01 75 08 81 01 95 05 75 01
0020: 05 08 19 01 29 05 91 02 95 01 75 03 91 01 95 06
0030: 75 08 15 00 25 68 05 07 19 00 29 68 81 00 C0
Usage Page Gen Desktop Ctrls(01)
Usage Keypad
Collection Application
Usage Page Kbrd/Keypad(07)
Usage Min(E0)
Usage Max(E7)
Logical Min(00)
Logical Max(01)
Report Size(01)
Report Count(08)
Input(00000010)
Report Count(01)
Report Size(08)
Input(00000001)
Report Count(05)
Report Size(01)
Usage Page LEDs(08)
Usage Min(01)
Usage Max(05)
Output(00000010)
Report Count(01)
Report Size(03)
Output(00000001)
Report Count(06)
Report Size(08)
Logical Min(00)
Logical Max(68)
Usage Page Kbrd/Keypad(07)
Usage Min(00)
Usage Max(68)
Input(00000000)
End Collection
but when I attempt to use it as a boot keyboard – it returns 0x0D (hrJERR) – I was wondering if you had any direction that I could look at…it does work under windows/mac (but only after a reboot actually)
Maybe it doesn’t support boot protocol? Can you post configuration descriptor as well?
I’m trying to get my Arduino Mega to communicate over USB (not over BT) with my Sony DS3 USB/BT game controller using your USB Host 2.0 shield.
I can successfully build and run the USBHID_desc sketch which yields the device report far below.
But when I build and run the USBHIDJoystick example, the code prints out the following:
Start
HU Init
Addr:1
NC:1
Cnf:1
HU configured
and never prints anything else.
I tweaked the parser code based on my understanding of the buf[] layout for my controller, but still nothing gets printed no matter what button I push or joystick I bend.
After fiddling around with it all day, I’ve determined that the parser never gets called. I put a Serial.println(“In Parser”) at the very beginning of the parser code but the line never gets printed.
I added a Serial.println(“In parser constructor”) just after the oldPad is filled with 0xD, and I DO see that get printed at the beginning so something is working.
Any ideas what I’m doing wrong?
Device Report
————-
Start
HU Init
Addr:1
NC:1
Cnf:1
HU configured
0000: 05 01 09 04 A1 01 A1 02 85 01 75 08 95 01 15 00
0010: 26 FF 00 81 03 75 01 95 13 15 00 25 01 35 00 45
0020: 01 05 09 19 01 29 13 81 02 75 01 95 0D 06 00 FF
0030: 81 03 15 00 26 FF 00 05 01 09 01 A1 00 75 08 95
0040: 04 35 00 46 FF 00 09 30 09 31 09 32 09 35 81 02
0050: C0 05 01 75 08 95 27 09 01 81 02 75 08 95 30 09
0060: 01 91 02 75 08 95 30 09 01 B1 02 C0 A1 02 85 02
0070: 75 08 95 30 09 01 B1 02 C0 A1 02 85 EE 75 08 95
Usage Page Gen Desktop Ctrls(01)
Usage Game Pad
Collection Application
Collection Logical
Report Id(01)
Report Size(08)
Report Count(01)
Logical Min(00)
Logical Max(FF00)
Input(00000011)
Report Size(01)
Report Count(13)
Logical Min(00)
Logical Max(01)
Physical Min(00)
Physical Max(01)
Usage Page Button(09)
Usage Min(01)
Usage Max(13)
Input(00000010)
Report Size(01)
Report Count(0D)
Usage Page Undef(00)
Input(00000011)
Logical Min(00)
Logical Max(FF00)
Usage Page Gen Desktop Ctrls(01)
Usage Pointer
Collection Physical
Report Size(08)
Report Count(04)
Physical Min(00)
Physical Max(FF00)
Usage X
Usage Y
Usage Z
Usage Rz
Input(00000010)
End Collection
Usage Page Gen Desktop Ctrls(01)
Report Size(08)
Report Count(27)
Usage Pointer
Input(00000010)
Report Size(08)
Report Count(30)
Usage Pointer
Output(00000010)
Report Size(08)
Report Count(30)
Usage Pointer
Feature(00000010)
End Collection
Collection Logical
Report Id(02)
Report Size(08)
Report Count(30)
Usage Pointer
Feature(00000010)
End Collection
Collection Logical
Report Id(EE)
Report Size(08)
Report Count
I played with DS3 connected to a PC. It looks like this device won’t generate reports by itself like other HID devices but needs some command sent to it first.
Thanks Oleg!
I think I found the command that you reference:
try
{
//request the PS3 controller to send button presses etc back
//Host to device (0×00) | Class (0×20) | Interface (0×01), Set Report (0×09), Report Type (Feature 0×03) – Report ID (0xF4), Host to device (0×00) – Endpoint 0 (0×00), data, dataoffset, datalength
raw.SendSetupTransfer(0×21, 0×09, 0x03F4, 0×0000, buf, 0×00, 0×04);
}
But I’m not sure where/when/how to send this command. I’m thinking I’d just tack it into my loop() function just after the call to Usb.Task(). But I don’t know what command to use…
I’ll keep digging, but if you have a simple answer, that would be FANTASTIC!
Alan
hi,
I have to transmit data from host –> device to control a device
for that we have to pass following things in “send report function”,
Report ID
Report type
Report length
What are these and how to find it.
I am very new in USBH.
Thanks for help..
Krunal
Check out the PS3USB library at this line: https://github.com/felis/USB_Host_Shield_2.0/blob/master/PS3USB.cpp#L422.
All this information can be found in report descriptor.
I added this to loop():
void loop()
{
Usb.Task();
if (nextPoll <= millis()) {
nextPoll = millis() + 5000;
Hid.SetReport(0, 1, 3, 0xf4, 0, 0);
Serial.println("SetReport sent");
Serial.println(Usb.getUsbTaskState());
}
}
I see the "SetReport sent" followed by "144" (USB_STATE_RUNNING) print 6 times and then the output stops.
No change in behavior. My parser never gets called.
Alan
I managed to get it going finally.
I was on the right track with the previous code. But I wasn’t formatting the SetReport message properly. And you only have to send it once.
Here is what I ended up with:
uint8_t feature_F4_report[4] = { 0×42, 0x0c, 0×00, 0×00 };
uint8_t startDelay = millis() + 5000;
void loop()
{
Usb.Task();
if ((Usb.getUsbTaskState() == USB_STATE_RUNNING) && startDelay && (startDelay <= millis())) {
Hid.SetReport(0, 0, 3, 0xf4, 4, feature_F4_report);
startDelay = 0;
}
}
Because of continuous equivocation on the LSB values of the joysticks, as well as the accelerometer values, a new buffer of changed data is sent by the controller almost all the time. Consequently I had to comment out the code in the HIDUniversal::Poll() routine that does a hexdump of the buffer.
As I mentioned before, I had to do some morphing of the buffer parser you provided to match the format of the buffer coming from the DS3.
Things are working well now!
Thanks for you help.
Alan
Thanks for sharing!
Hid.SetReport(0, 0, 3, 0xf4, 4, feature_F4_report);
Alan, how did you discover parameters for the SetReport function call?
I am trying to read data from a weather station receiver WS3081, and I can do it from the PC if I send 8 bytes
I need to send $A1 $00 $20 $20 $A1 $00 $20 $20 and i am not sure of the function call parameters.
Also the USB_desc program tells me the EndPoint is $81 as does some working C code.
Yet this endpont is not set in the table of valid endpoints and when is try to do a SetReport(0×81 ,…. the rcode comes backs as DB which is USB_ERROR_EP_NOT_FOUND_IN_TBL.
Any clues?
Hi Whereswally,
I’m doing something similar to yourself, I want to read the data from a WH1081 weather station & then format & publish this data to wunderground.com without the use of a pc. I’ve just started with mine & have got a list of the memory map & instruction list(similar to yours, same instructions). Only starting the Arduino part now, got the USB_desc program to work & report the interface description but from here I have no idea how to actually send the request to the WH1081 & receive back data from it! Did you get yours working?
Thanks,
Wexican
I found the secret setReport command documented here:
http://www.circuitsathome.com/mcu/programming/ps3-and-wiimote-game-controllers-on-the-arduino-host-shield-part-2
Alan
Looks like PS3 Controller USB support has been officially pulled into the library codebase:
http://www.circuitsathome.com/mcu/arduino/interfacing-ps3-controllers-via-usb
This is very good news.
Hello,
Before i user the first version of USB HOST SHIELD board(sparkfun) and a SAITEK X45 all was ok.
Now i use ADK Board and try tou get data from joystick.
I gt this
Read : 8
90E008FFAF00AD00
Read : 3
220000
Datas were split in two parts 8 + 3 which make my 11 Bytes struct
struct GamePadEventData
{
byte Part1;
byte Part2;
byte Part3;
byte Throlle;
byte Dial;
byte RZ;
byte RX;
byte Buttons;
byte Reserved;
byte Hat1;
byte Hat2;
};
How can i threat all in one loop?
Thanks
I understand the maxPktSize < Reportlength
maxPktSize = 8 and reportlength = 11
How can i do?
Thanks
François
Ok i hardly code for waiting 11 Bytes in array before send it in the Poll method!
An idea?
thanks.
Hi guys,
I am playing around with the USB Host shield 2.0. Thanks for development. Its very cool!
HID_test and HID_desc works good, but now I am trying to do my own sketch based on USBHIDJoystick.
As I am not familiar with bitshift etc I am not shure how to adapt the code. I have a 3 Axis, 6 Buttons Loogitech Wingman Attack 2.
The HIDdesc output looks like this:
Usage Page Gen Desktop Ctrls(01)
Usage Game Pad
Collection Application
Collection Logical
Logical Min(00)
Logical Max(FF00)
Physical Min(00)
Physical Max(FF00)
Report Size(08)
Report Count(03)
Usage X
Usage Y
Usage Z
Input(00000010)
Logical Max(01)
Physical Max(01)
Report Size(01)
Report Count(06)
Usage Page Button(09)
Usage Min(01)
Usage Max(06)
Input(00000010)
Report Count(02)
Input(00000001)
End Collection
Collection Logical
Logical Max(FF00)
Physical Max(FF00)
Report Size(08)
Report Count(04)
Usage Page Undef(00)
Usage
Feature(00000010)
End Collection
End Collection
I changed struct GamePadEventData to X, Y, Z and RPT_GEMEPAD_LEN to 3, but I think I have to change something in the button parsing…
Can you help me?
Thanks
Kai
Hi, Kai,
According to the dump you’ve sent you have three fields for X,Y,Z coordinates and one-byte field for 6 buttons (the last two bits, if I am not mistaken, is an alignment). Here is how you should change the code:
void JoystickReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{
bool match = true;
// Checking if there are changes in report since the method was last called
for (uint8_t i=0; iOnGamePadChanged((const GamePadEventData*)buf);
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i];
}
uint8_t buttons = (0x00 | buf[3]);
uint8_t changes = (buttons ^ oldButtons);
// Calling Button Event Handler for every button changed
if (changes)
{
for (uint8_t i=0; i<0x06; i++)
{
uint16_t mask = (0x01 < 0) && joyEvents)
if ((buttons & mask) > 0)
joyEvents->OnButtonDn(i+1);
else
joyEvents->OnButtonUp(i+1);
}
oldButtons = buttons;
}
}
I hope it’s going to work with your joystick.
Thank you, it works!
Can you tell me, what this if for which seems not to be required in my case?
buttons <> 4);
buttons <> 4);
If you mean code from method JoystickReportParser::Parse numbered from 30 through 33 up in the article, these are bit shift operations done to extract one-bit button fields from two separate bytes. If you look at the dump at the beginning of the article you will see that button data is following five eight-bit coordinate fields and one four-bit hat switch field, so out of 12 (0x0C) one-bit button fields six are coming in sixth byte of the report buffer and the rest in seventh byte. To put all of them together into two-byte (uint16_t) variable I had to put the high byte first (line 30), then shift all its bits four bits left (line 31), then put lower four bits using OR operation from sixth byte previously shifted so that the high four button bits become low ones(line 31). At the end of the day we have the variable buttons where the first twelve bits correspond to button states.
In your case you have three one-byte coordinate fields followed by six one-byte button fields which are fit in one byte, so the above mention code is not needed for your joystick.
Just another thing: When I am trying to call a function defined below the main loop within the JoystickEvents::OnGamePadChanged or JoystickEvents::OnButtonUp etc the complier says, that the function isnt declared in the scope.
Can you tell me, how to manage this?
JoystickEvent class is defined in hidjoystickrptparser.h and implemented in hidjoystickrptparser.cpp, so when parsing those two files the compiler knows nothing about other files which are not included by #include statement. To get your code up and running you have to put your function either into hidjoystickrptparser.cpp, or put it into separate yourfile.h and yourfile.cpp files and then add #include “yourfile.h” in hidjoystickrptparser.cpp.
Can someone help me with a perplexing problem? I tried the USBHID_desc sketch on my USB keyboard and all normal keys were captured fine. However, all of the media keys (e.g., volumne, mute, play, FF, etc.) are not being detected by the host shield. However, plugging the keyboard directly into the computer works fine. I checked the usage table and it corresponds to 0×07 which is standard keyboard table. Anyone can shed some light into this? Greatly appreciated, thanks!!
NC:1
Cnf:1
HU configured
0000: 05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
0010: 75 01 95 08 81 02 05 08 09 4B 81 02 95 05 05 08
0020: 19 01 29 05 91 02 95 01 75 03 91 01 95 06 75 08
0030: 15 00 26 A4 00 05 07 19 00 2A A4 00 81 00 C0
Usage Page Gen Desktop Ctrls(01)
Usage Keypad
Collection Application
Usage Page Kbrd/Keypad(07)
Usage Min(E0)
Usage Max(E7)
Logical Min(00)
Logical Max(01)
Report Size(01)
Report Count(08)
Input(00000010)
Usage Page LEDs(08)
Usage Gen Ind
Input(00000010)
Report Count(05)
Usage Page LEDs(08)
Usage Min(01)
Usage Max(05)
Output(00000010)
Report Count(01)
Report Size(03)
Output(00000001)
Report Count(06)
Report Size(08)
Logical Min(00)
Logical Max(A400)
Usage Page Kbrd/Keypad(07)
Usage Min(00)
Usage Max(A400)
Input(00000000)
End Collection
For media keys, you need to use report protocol. If you init you keyboard as boot device media keys won’t be visible in the descriptor.
oleg, appreciate your kind reply. I’m quite new to this Arduino programming and hope you can give me a bit more info/direction on how I should initialise it in report protocol mode. The only code that I used to initialise the keyboard is based off the keyboard example code in the USB Host Shield library as follows:
delay( 200 );
next_time = millis() + 5000;
Keyboard2.SetReportParser(0, (HIDReportParser*)&Prs);
Note that I initialised the keyboard object as Keyboard2 becoz Keyboard is a reserved object in the Leonardo due to its built-in HID capabilities.
Thanks in advanced!
Have you tried this sketch already? -> https://github.com/felis/USB_Host_Shield_2.0/blob/master/examples/HID/USBHID_desc/USBHID_desc.pde
Yes I did. The output is as per what I posted up there. The media keys did not generate a “report” but the other keys worked fine.
I was wondering if there was a code that can be used to get the Logitech extreme 3d pro to get it to move autonomously. I have this project that is racking my brain and I can not find anything to help me