Emulating multiple HID devices on one Microcontroller?

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
BrainSlugs83
Posts: 6
Joined: Sun Mar 20, 2016 4:30 am

Emulating multiple HID devices on one Microcontroller?

Post by BrainSlugs83 » Tue Oct 25, 2016 12:29 am

Hey guys,

I recently built a USB adapter for a console gamepad. I was hoping to extend it to support multiple gamepads -- and while just adding more buttons and axises to the USB descriptor works (at least, with some games), it will still only show up as a single gamepad to the PC (so, other games don't work as well).

Instead, I would like to report the device as being multiple HID gamepads -- this seems like it should be something we can do in the descriptor, right?

My project is basically a heavily modified version of the HID mouse example (it just reports a gamepad instead of a mouse, and then does actual polling of the gamepad to report back the state).

How should I attempt to accomplish this? -- What if I wanted to report two mice for example? -- i.e. how would I modify the HID descriptor in main.c (in the mouse example) to accomplish this?

Am I barking up the wrong tree? -- Can it be done with HID descriptors alone? -- Or do I need to do something with multiple end points instead?

EDIT:
FYI, my current HID descriptor (which crams two gamepads worth of inputs into one device) is as follows:

Code: Select all

PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] =
{
    0x05, 0x01,               //   USAGE_PAGE (Generic Desktop)
    0x09, 0x05,               //   USAGE (Game Pad)

    0xa1, 0x01,               //   COLLECTION (Application)

    0x09, 0x01,               //   USAGE (Pointer)
    0xa1, 0x00,               //   COLLECTION (Physical)
    0x09, 0x30,               //      USAGE (X)
    0x09, 0x31,               //      USAGE (Y)
    0x15, 0x00,               //      LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,         //      LOGICAL_MAXIMUM (255)
    0x75, 0x08,               //      REPORT_SIZE (8)
    0x95, 0x02,               //      REPORT_COUNT (2)
    0x81, 0x02,               //      INPUT (Data,Var,Abs)
    0xc0,                     //   END_COLLECTION

    0x09, 0x01,               //   USAGE (Pointer)
    0xa1, 0x00,               //   COLLECTION (Physical)
    0x09, 0x32,               //      USAGE (X)
    0x09, 0x33,               //      USAGE (Y)
    0x15, 0x00,               //      LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,         //      LOGICAL_MAXIMUM (255)
    0x75, 0x08,               //      REPORT_SIZE (8)
    0x95, 0x02,               //      REPORT_COUNT (2)
    0x81, 0x02,               //      INPUT (Data,Var,Abs)
    0xc0,                     //   END_COLLECTION

    0x05, 0x09,               //   USAGE_PAGE (Button)
    0x19, 0x01,               //   USAGE_MINIMUM (Button 1)
    0x29, 0x10,               //   USAGE_MAXIMUM (Button 16)
    0x15, 0x00,               //   LOGICAL_MINIMUM (0)
    0x25, 0x01,               //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,               //   REPORT_SIZE (1)
    0x95, 0x10,               //   REPORT_COUNT (16)
    0x81, 0x02,               //   INPUT (Data,Var,Abs)

    0xc0,                     //   END_COLLECTION
};

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: Emulating multiple HID devices on one Microcontroller?

Post by ulao » Mon Nov 07, 2016 5:06 am

yes you can do that but only in windows. Seems most linux based OS's will not enumerate.

To do this you just use multiple ID's.

0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)

0xa1, 0x01, // COLLECTION (Application)

0x85,0x01, // Report ID 1 <-------------------

0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION

0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x32, // USAGE (X)
0x09, 0x33, // USAGE (Y)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION

0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x10, // USAGE_MAXIMUM (Button 16)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x10, // REPORT_COUNT (16)
0x81, 0x02, // INPUT (Data,Var,Abs)

0xc0, // END_COLLECTION



0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)

0xa1, 0x01, // COLLECTION (Application)

0x85,0x02, // Report ID 2 <-------------------

0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION

0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x32, // USAGE (X)
0x09, 0x33, // USAGE (Y)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION

0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x10, // USAGE_MAXIMUM (Button 16)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x10, // REPORT_COUNT (16)
0x81, 0x02, // INPUT (Data,Var,Abs)

0xc0, // END_COLLECTION

Post Reply