Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: USB Descriptor packet fun!

  1. #1
    Junior Member
    Join Date
    Dec 2017
    Posts
    2

    USB Descriptor packet fun!

    Hey PRJC,


    I'm using teensy 3.2 to create a joystick, and have a need to remove all unused axes and buttons/switches from what appears when connected through USB. I've been following along with what Kenton was doing on his blog (https://hamaluik.com/posts/making-a-...-hid-joystick/), but I loose him somewhere in that process, and would like to try just modifying the bare minimums.

    I started off doing exactly the same things he did, and couldn't get my code to compile. I started backtracking to just things that I'd need, and am at the stage where I'd like to be able to figure out where the structure of the usb descriptor file packet is made. I'm just trying to change the descriptor file for the joystick so that there are 3 axes, and 4 buttons total. The files I'm modifying are usb_desc.h and usb_desc.c.

    static uint8_t joystick_report_desc[] = {
    0x05, 0x01, // USAGE_PAGE (Generic Desktop)
    0x09, 0x04, // USAGE (Joystick)
    0xa1, 0x01, // COLLECTION (Application)
    0x09, 0x04, // USAGE (Joystick)
    0xa1, 0x00, // COLLECTION (Physical)
    0x09, 0x30, // USAGE (X)
    0x09, 0x31, // USAGE (Y)
    0x09, 0x32, // USAGE (Z)
    0x75, 0x06, // REPORT_SIZE (6)
    0x95, 0x03, // REPORT_COUNT (3)
    0x45, 0x7f, // PHYSICAL_MAXIMUM (127)
    0x35, 0x81, // PHYSICAL_MINIMUM (-127)
    0x81, 0x02, // INPUT (Data,Var,Abs)
    0x05, 0x09, // USAGE_PAGE (Button)
    0x19, 0x01, // USAGE_MINIMUM (Button 1)
    0x29, 0x04, // USAGE_MAXIMUM (Button 4)
    0x15, 0x00, // LOGICAL_MINIMUM (0)
    0x25, 0x01, // LOGICAL_MAXIMUM (1)
    0x75, 0x01, // REPORT_SIZE (1)
    0x95, 0x04, // REPORT_COUNT (4)
    0x81, 0x02, // INPUT (Data,Var,Abs)
    0xc0, // END_COLLECTION
    0xc0 // END_COLLECTION
    };

    I know that this isn't the only area that needs to change, and I was wondering if anybody has any further resources on this?
    Thanks a bunch!

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,536
    Others can probably answer this better than I can, I have played more at the other end of trying to get these to work with the USB Host code.

    But some of things that I would guess include;
    Code:
    static uint8_t joystick_report_desc[] = {
    0x05, 0x01, // USAGE_PAGE (Generic Desktop)
    0x09, 0x04, // USAGE (Joystick)
    0xa1, 0x01, // COLLECTION (Application)
    0x09, 0x04, // USAGE (Joystick)
    0xa1, 0x00, // COLLECTION (Physical)
    0x09, 0x30, // USAGE (X)
    0x09, 0x31, // USAGE (Y)
    0x09, 0x32, // USAGE (Z)
    0x75, 0x06, // REPORT_SIZE (6)
    0x95, 0x03, // REPORT_COUNT (3)
    0x45, 0x7f, // PHYSICAL_MAXIMUM (127)
    0x35, 0x81, // PHYSICAL_MINIMUM (-127)
    0x81, 0x02, // INPUT (Data,Var,Abs)
    0x05, 0x09, // USAGE_PAGE (Button)
    0x19, 0x01, // USAGE_MINIMUM (Button 1)
    0x29, 0x04, // USAGE_MAXIMUM (Button 4)
    0x15, 0x00, // LOGICAL_MINIMUM (0)
    0x25, 0x01, // LOGICAL_MAXIMUM (1)
    0x75, 0x01, // REPORT_SIZE (1)
    0x95, 0x04, // REPORT_COUNT (4)
    0x81, 0x02, // INPUT (Data,Var,Abs)
    0xc0, // END_COLLECTION
    0xc0 // END_COLLECTION
    };
    Report size of 6 is wrong (6 bits) as you have min/max of 127/-127 so should be 8 (or min/max need to change...

    But then you may have to muck with usb_desc.h in the cores\teensy3 to change things like
    Code:
      #define JOYSTICK_SIZE         12	//  12 = normal, 64 = extreme joystick
    Then I believe you also need to then update the usb_joystick.h and usb_joystick.c in the cores\teensy3 directory.
    To handle the packing of the data into the outgoing USB packet. Currently it looks like this code is setup only to handle
    JOYSTICK_SIZE==12 or ==64, so you would need to add a new section.

    Also the code assumes that the buttons are the first thing in the packet and you have the X, Y, Z as the first ones so again you need to adjust that code to pack the data into the format that you need.

    Plus make sure that it is not packing data for several of the Axis that you don't have, like Xrotate, Yrotate, ...

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    17,628
    HID gives you a lot of flexibility to define your data, but you must transmit packets that match the data format you define.

    On top of that, there are 2 issues with Windows.

    1: Windows loves a cache USB info in the Windows Registry. When you change the descriptor, often you need to increment the BCD version field or change the PID or VID numbers to get Windows to use the descriptors rather than the old info from its registry.

    2: Windows imposes an extra requirement that the entire HID report must add up to a multiple of 8 bits. The one you posted has three 6 bit axes and four 1 bit buttons, which adds up to 22 bits. To make this work, you'd need to add a constant input with 2 more bits. You'd add something like this:

    Code:
            0x95, 0x01,                     //   Report Count (1),
            0x75, 0x02,                     //   Report Size (2),
            0x81, 0x03,                     //   Input (Constant),
    Of course, when you transmit the packet, the number of bytes must exactly match the data. If you send the wrong number, Windows will not work with your device at all.

    The HID report descriptor Teensyduino uses for Joystick has 10 bit per axis. Maybe you have some good reason to reduce to only 6 bits? If you go this route, you'll need to edit usb_joystick.h and usb_joystick.c to pack the data into the correct 6 bits. But this is less critical. As long as you transmit the correct number of bytes, the PC will recognize your device and it will just do weird things because the data is wrong.

  4. #4
    Junior Member
    Join Date
    Dec 2017
    Posts
    2
    Thank you for your responses.

    I'm seeing all kinds of different data as to how many bits are being output.

    Right now, I can get the descriptor to work with one axis and 4 buttons. but if I try to add the 2nd axis, I cannot get it to work. See any problems with my new descriptor?
    Code:
        0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
        0x09, 0x04,                    // USAGE (Joystick)
        0xa1, 0x01,                    // COLLECTION (Application)
        0x09, 0x04,                    //   USAGE (Joystick)
        0xa1, 0x00,                    //   COLLECTION (Physical)
        0x05, 0x09,                    //     USAGE_PAGE (Button)
        0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
        0x29, 0x04,                    //     USAGE_MAXIMUM (Button 4)
        0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
        0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
        0x95, 0x20,                    //     REPORT_COUNT (32)
        0x75, 0x01,                    //     REPORT_SIZE (1)
        0x81, 0x02,                    //     INPUT (Data,Var,Abs)
        0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
        0x09, 0x30,                    //     USAGE (X)
        0x09, 0x31,                    //     USAGE (Y)
        0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
        0x26, 0xff, 0x00,              //     LOGICAL_MAXIMUM (255)
        0x75, 0x0a,                    //     REPORT_SIZE (10)
        0x95, 0x02,                    //     REPORT_COUNT (2)
        0x81, 0x02,                    //     INPUT (Data,Var,Abs)
        0x75, 0x0c,                    //     REPORT_SIZE (12)
        0x95, 0x01,                    //     REPORT_COUNT (1)
        0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
        0xc0,                          //   END_COLLECTION
        0xc0                           // END_COLLECTION


    Here is the crux of my joystick.h file.

    Code:
    int usb_joystick_send(void);
    extern uint32_t usb_joystick_data[(JOYSTICK_SIZE+3)/4];
    
    #if JOYSTICK_SIZE == 5
    	void button(uint8_t button, bool val) {
    		if (--button >= 4) return;
    		if (val) usb_joystick_data[0] |= (1 << button);
    		else usb_joystick_data[0] &= ~(1 << button);
    		if (!manual_mode) usb_joystick_send();
    	}
    	void X(unsigned int val) {
    		if (val > 1023) val = 1023;
    		usb_joystick_data[1] = (usb_joystick_data[1] & 0xFFFFFC00) | (val);
    		if (!manual_mode) usb_joystick_send();
    	}
    	void Y(unsigned int val) {
    		if (val > 1023) val = 1023;
    		Serial.println(val);
    		usb_joystick_data[1] = (usb_joystick_data[1] & 0xFFF003FF) | (val << 10);
    		if (!manual_mode) usb_joystick_send();
    I guess my question is how to combine the dummy values with the data in the descriptor file. I'm doing something wrong there, and I've tried a bunch of configurations, and can't figure out how to combine them correctly.
    Last edited by timonemycat; 12-12-2017 at 10:59 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •