Teensy 4.1 | USB Host | Joystick - How to retrieve button press data separately?

Hello all,
I'm new to the USBHost_t36 library and i'm a little lost in regards to retrieving button data from a Joystick i have connected to a Teensy 4.1.

Using the Joystick.ino example, it detects the HID Joystick i'm using, it also reads the data from the xyz axis (different ranges, but will worry about that later), but when it comes to buttons, it outputs a sum of the button readings (imagine - one button press outputs buttons: 100, the second button would output buttons: 200, if i press both the output is buttons: 300). I've been looking through the code and i can't figure out where/why is that happening.

Using the HIDDeviceInfo.ino example, it also detects the Joystick and reads the data all in separate - 1s and 0s for the button presses, instead of what might be analog readings for the Joystick.ino example, but that's not really an issue.

So, my question is - is there a wiki that i could look at to try to figure out how to get the buttons inputs separated in the Joystick.ino example and develop that further for the project i'm aiming to use this with, or is there someone who's able to throw some pointers so i'm able to get this sorted?

If there's any more info/details that i can provide, please let me know.
(new to the forum too)

Thanks in advance!
 
Today in the morning I started modifying the HIDDeviceInfo.ino example, to fit better the use case I have in mind. Mapped the 15 buttons my joystick has and have all 4 axis working too.
 
when it comes to buttons, it outputs a sum of the button readings (imagine - one button press outputs buttons: 100, the second button would output buttons: 200, if i press both the output is buttons: 300). I've been looking through the code and i can't figure out where/why is that happening.
It's not a sum, it's a bitmask. Each bit position in the value represents a separate button. You can use logical AND operations to easily check the state of individual buttons.
 
Ah, that makes sense. Thanks for the response!
As I got around it with the second example, I'll keep the separated buttons/axis data in arrays, which, to me, keeps logic a little more straight forward and doesn't add much to the existing code.
 
The format of the data is dictated by the report descriptor that the device returns to us. For example, if you build a teensy as a USB type that includes Joystick, it will return back a descriptor that looks something like: (From usb_desc.c)
Code:
#if JOYSTICK_SIZE == 12
static uint8_t joystick_report_desc[] = {
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x04,                     // Usage (Joystick)
        0xA1, 0x01,                     // Collection (Application)
        0x15, 0x00,                     //   Logical Minimum (0)
        0x25, 0x01,                     //   Logical Maximum (1)
        0x75, 0x01,                     //   Report Size (1)
        0x95, 0x20,                     //   Report Count (32)
        0x05, 0x09,                     //   Usage Page (Button)
        0x19, 0x01,                     //   Usage Minimum (Button #1)
        0x29, 0x20,                     //   Usage Maximum (Button #32)
        0x81, 0x02,                     //   Input (variable,absolute)
        0x15, 0x00,                     //   Logical Minimum (0)
        0x25, 0x07,                     //   Logical Maximum (7)
        0x35, 0x00,                     //   Physical Minimum (0)
        0x46, 0x3B, 0x01,               //   Physical Maximum (315)
        0x75, 0x04,                     //   Report Size (4)
        0x95, 0x01,                     //   Report Count (1)
        0x65, 0x14,                     //   Unit (20)
        0x05, 0x01,                     //   Usage Page (Generic Desktop)
        0x09, 0x39,                     //   Usage (Hat switch)
        0x81, 0x42,                     //   Input (variable,absolute,null_state)
        0x05, 0x01,                     //   Usage Page (Generic Desktop)
        0x09, 0x01,                     //   Usage (Pointer)
        0xA1, 0x00,                     //   Collection ()
        0x15, 0x00,                     //     Logical Minimum (0)
        0x26, 0xFF, 0x03,               //     Logical Maximum (1023)
        0x75, 0x0A,                     //     Report Size (10)
        0x95, 0x04,                     //     Report Count (4)
        0x09, 0x30,                     //     Usage (X)
        0x09, 0x31,                     //     Usage (Y)
        0x09, 0x32,                     //     Usage (Z)
        0x09, 0x35,                     //     Usage (Rz)
        0x81, 0x02,                     //     Input (variable,absolute)
        0xC0,                           //   End Collection
        0x15, 0x00,                     //   Logical Minimum (0)
        0x26, 0xFF, 0x03,               //   Logical Maximum (1023)
        0x75, 0x0A,                     //   Report Size (10)
        0x95, 0x02,                     //   Report Count (2)
        0x09, 0x36,                     //   Usage (Slider)
        0x09, 0x36,                     //   Usage (Slider)
        0x81, 0x02,                     //   Input (variable,absolute)
        0xC0                            // End Collection
};
#elif JOYSTICK_SIZE == 64
The USBHIDParser class within USBHost_t36 parses this data and uses it to parse each of the packets coming in.
And assuming you have an object who is derived from USBHIDInput, that has claimed the appropriate report, the
HID parser object will do calls into your object with the different fields.

I developed the HIDDeviceInfo sketch as often times, someone would wish to support or for us to support some different
HID device, the code in these classes also understand the HID report and the main goal was to then to decode that
data and print it out. It also prints out other things like the descriptors and the like.

For some of this stuff, one needs to read through some of the different USB specifications and the like>
Or example there are several documents describing HID up at:

One such document is the HID Usage Table document: https://www.usb.org/sites/default/files/hut1_5.pdf
This describes what many of these fields are above in the Joystick Report Descriptor. For example.
Code:
0x05, 0x01,                     //   Usage Page (Generic Desktop)
...
        0x09, 0x30,                     //     Usage (X)
        0x09, 0x31,                     //     Usage (Y)
        0x09, 0x32,                     //     Usage (Z)
        0x09, 0x35,                     //     Usage (Rz)
We know that these fields are X, Y, Z, Rz, as the line Usage Page 1
1726405811535.png


Which is what was used to generate the code in that sketch (HIDDumper.cpp)
Code:
void HIDDumpController::printUsageInfo(uint8_t usage_page, uint16_t usage) {
  switch (usage_page) {
    case 1:  // Generic Desktop control:
      switch (usage) {
        case 0x02: Serial.print("(Mouse)"); break;
        case 0x04: Serial.print("(Joystick)"); break;
        case 0x06: Serial.print("(Keyboard)"); break;

        case 0x30: Serial.print("(X)"); break;
        case 0x31: Serial.print("(Y)"); break;
        case 0x32: Serial.print("(Z)"); break;
        case 0x33: Serial.print("(Rx)"); break;
        case 0x34: Serial.print("(Ry)"); break;
        case 0x35: Serial.print("(Rz)"); break;
        case 0x36: Serial.print("(Slider)"); break;
        case 0x37: Serial.print("(Dial)"); break;
        case 0x38: Serial.print("(Wheel)"); break;
        case 0x39: Serial.print("(Hat)"); break;
...
Sorry, probably more information than you were asking for...
 
That's good info. Thanks!

Is the usb_desc.c from the Joystick library?
I haven't looked into that lib as, in this project, i'm aimed at using the joystick as a standalone controller - no pc..

The HIDDumper.cpp is what i modified slightly to get a more readable output on the Serial and have the arrays with the data i need.
 
Is the usb_desc.c from the Joystick library?
This file is part of the Teensy 4 core.
That is it is in the ...\cores\teensy4 directory.
This report descriptor and the corresponding code usb_joystick.c (and .h) in the same directory are also included in those builds
when the USB type includes joystick in it...
1726428432180.png


Which I roughly highlighted in the above image.
 
Finally got a display delivered and some time to come back to this..
Had a few little hickups to integrate the usbhost with the display (ili9341 3.2" with touch), but got around to have it working. Tested your lib for the display, @KurtE - thanks for the work done, it's nice and simplifies some of what i've done on my own to avoid flickering on the base lib.
Then back to topic - the separation of the buttons inputs - went back to basics and studied/refreshed the bitmasks - thanks @jmarsh - and got that sorted too.
 

Attachments

  • PXL_20241103_003357669.jpg
    PXL_20241103_003357669.jpg
    257.3 KB · Views: 18
Back
Top