Author Topic: Which HID usage type would be best?  (Read 12167 times)

locodog

  • Member
  • ***
  • Posts: 8
Which HID usage type would be best?
« on: January 12, 2014, 06:36:00 pm »
Hello there chaps, I am making a HID dj controller with 128 single bit buttons and 48 analogue dials (pots) at 8 bit resolution.

I am very new to this type of prototyping but I'm learning as I go. Fortunately a lot of the coding for firmware creation has been done here UnoJoy

I am following the example there and expanding, so I edited
dataForController_t.h
UnoJoy.C
usb_gamepad.h
usb_gamepad.c

It is composing the HID report in usb_gamepad.c  (is this the descriptor? I'm unsure) that I am having trouble with.

What HID usage type would be best for 128 buttons at 1 bit each and 48 dials (ADC) at 8 bit each?

Here is part of my code (which I know is wrong but I am stumped)


Code: [Select]
static const uint8_t PROGMEM device_descriptor[] = {
18, // bLength                    //I SHOULD CHANGE THIS TO 64?
1, // bDescriptorType
0x10, 0x01, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
ENDPOINT0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
0x00, 0x01, // bcdDevice
1, // iManufacturer
2, // iProduct
0, // iSerialNumber
1 // bNumConfigurations
};


static const uint8_t PROGMEM gamepad_hid_report_desc[] = {
0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
0x09, 0x05,        // USAGE (Gamepad)
0xa1, 0x01,        // COLLECTION (Application)
0x15, 0x00,        //   LOGICAL_MINIMUM (0)
0x25, 0x01,        //   LOGICAL_MAXIMUM (1)
0x35, 0x00,        //   PHYSICAL_MINIMUM (0)
0x45, 0x01,        //   PHYSICAL_MAXIMUM (1)
0x75, 0x01,        //   REPORT_SIZE (1)
0x95, 0x80,        //   REPORT_COUNT (128)
0x05, 0x09,        //   USAGE_PAGE (Button)
0x19, 0x01,        //   USAGE_MINIMUM (Button 1)
0x29, 0x80,        //   USAGE_MAXIMUM (Button 128)
0x81, 0x02,        //   INPUT (Data,Var,Abs)
0x05, 0x01,        //   USAGE_PAGE (Generic Desktop)
0x26, 0xff, 0x00,  //   LOGICAL_MAXIMUM (255)
0x46, 0xff, 0x00,  //   PHYSICAL_MAXIMUM (255)
0x09, 0x30,        //   USAGE (X)                                  //HERE IS WHERE I DERPED OUT, COULD I HAVE 48*X AXIS'?
0x09, 0x31,        //   USAGE (Y)
0x09, 0x32,        //   USAGE (Z)
0x09, 0x35,        //   USAGE (Rz)
0x75, 0x08,        //   REPORT_SIZE (8)
0x95, 0x30,        //   REPORT_COUNT (48)
0xc0               // END_COLLECTION
};



If required I can add my edited files or provide more information.

Thanks for reading and any guidance, locodog
« Last Edit: January 12, 2014, 08:06:32 pm by locodog »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Which HID usage type would be best?
« Reply #1 on: January 13, 2014, 12:11:25 pm »
What problem are you having with it? Does the host PC detect and enumerate the device? If so, what happens when you try to use it?

locodog

  • Member
  • ***
  • Posts: 8
Re: Which HID usage type would be best?
« Reply #2 on: January 13, 2014, 01:53:46 pm »
Thanks for the reply

When I plug it in to the pc it is detected as a HID gamepad in device manager but when I put it into my HID trace program, it can be seen but it doesn't submit a report (I assume that is what enumerate means) until I unplug it, (then a report is submitted [enumerated  :-\ ])

My problem (from lack of knowledge/understand) is how best to adapt the 3rd party source files to something that suits my needs.
I think the rest of my edits are sound (Unojoy.h, usb_gamepad.h and dataForController_t.h), I know what I have done in usb_gamepad.c
is incorrect

I have read enough to add a button to a mouse or a axis to a joystick, but this many inputs is outside the scope of these usage types,

Here is a large chunk of my usb_gamepad.c   if anyone would be kind enough to look it over (pretty please)
 
Code: [Select]
#define USB_GAMEPAD_PRIVATE_INCLUDE

#include "usb_gamepad.h"

/**************************************************************************
 *
 *  Configurable Options
 *
 **************************************************************************/

// You can change these to give your code its own name.
#define STR_MANUFACTURER L"OpenChord X RMIT Exertion Games Lab"
#define STR_PRODUCT L"UnoJoy Joystick"
//#define STR_MANUFACTURER L"SEGA"
//#define STR_PRODUCT L"VIRTUA STICK High Grade"


// Mac OS-X and Linux automatically load the correct drivers.  On
// Windows, even though the driver is supplied by Microsoft, an
// INF file is needed to load the driver.  These numbers need to
// match the INF file.
#define VENDOR_ID 0x10C4
#define PRODUCT_ID 0x82C0


// USB devices are supposed to implement a halt feature, which is
// rarely (if ever) used.  If you comment this line out, the halt
// code will be removed, saving 102 bytes of space (gcc 4.3.0).
// This is not strictly USB compliant, but works with all major
// operating systems.
//#define SUPPORT_ENDPOINT_HALT



/**************************************************************************
 *
 *  Endpoint Buffer Configuration
 *
 **************************************************************************/

#define ENDPOINT0_SIZE 64

#define GAMEPAD_INTERFACE 0
#define GAMEPAD_ENDPOINT 1
#define GAMEPAD_SIZE 64
#define GAMEPAD_BUFFER EP_SINGLE_BUFFER //EP_DOUBLE_BUFFER

static const uint8_t PROGMEM endpoint_config_table[] = {
1, EP_TYPE_INTERRUPT_IN,  EP_SIZE(GAMEPAD_SIZE) | GAMEPAD_BUFFER,
0,
0,
0
};


/**************************************************************************
 *
 *  Descriptor Data
 *
 **************************************************************************/

// Descriptors are the data that your computer reads when it auto-detects
// this USB device (called "enumeration" in USB lingo).  The most commonly
// changed items are editable at the top of this file.  Changing things
// in here should only be done by those who've read chapter 9 of the USB
// spec and relevant portions of any USB class specifications!


static const uint8_t PROGMEM device_descriptor[] = {
18, // bLength             // Should this be 64? 128bits & 48bytes
1, // bDescriptorType
0x10, 0x01, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
ENDPOINT0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
0x00, 0x01, // bcdDevice
1, // iManufacturer
2, // iProduct
0, // iSerialNumber
1 // bNumConfigurations
};

static const uint8_t PROGMEM gamepad_hid_report_desc[] = {    //between here and
0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
0x09, 0x05,        // USAGE (Gamepad)
0xa1, 0x01,        // COLLECTION (Application)
0x15, 0x00,        //   LOGICAL_MINIMUM (0)
0x25, 0x01,        //   LOGICAL_MAXIMUM (1)
0x35, 0x00,        //   PHYSICAL_MINIMUM (0)
0x45, 0x01,        //   PHYSICAL_MAXIMUM (1)
0x75, 0x01,        //   REPORT_SIZE (1)
0x95, 0x80,        //   REPORT_COUNT (128)
0x05, 0x09,        //   USAGE_PAGE (Button)
0x19, 0x01,        //   USAGE_MINIMUM (Button 1)
0x29, 0x80,        //   USAGE_MAXIMUM (Button 128)
0x81, 0x02,        //   INPUT (Data,Var,Abs)              //upto here I think is ok
0x05, 0x01,        //   USAGE_PAGE (Generic Desktop)   
0x26, 0xff, 0x00,  //   LOGICAL_MAXIMUM (255)
0x46, 0xff, 0x00,  //   PHYSICAL_MAXIMUM (255)     
0x09, 0x30,        //   USAGE (X)                            //here is where I derped out
0x09, 0x31,        //   USAGE (Y)                            // could I just drop these 4 usages?
0x09, 0x32,        //   USAGE (Z)
0x09, 0x35,        //   USAGE (Rz)
0x75, 0x08,        //   REPORT_SIZE (8)
0x95, 0x30,        //   REPORT_COUNT (48)
0xc0               // END_COLLECTION
};


#define CONFIG1_DESC_SIZE (9+9+9+7)          //   I have no idea what anything below this line is about
#define GAMEPAD_HID_DESC_OFFSET (9+9)         
static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
1, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0x80, // bmAttributes
50, // bMaxPower
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
GAMEPAD_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass (0x00 = No Boot)
0x00, // bInterfaceProtocol (0x00 = No Protocol)
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(gamepad_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
GAMEPAD_SIZE, 0, // wMaxPacketSize
10 // bInterval
};

// If you're desperate for a little extra code memory, these strings
// can be completely removed if iManufacturer, iProduct, iSerialNumber
// in the device desciptor are changed to zeros.
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
int16_t wString[];
};
static const struct usb_string_descriptor_struct PROGMEM string0 = {
4,
3,
{0x0409}
};
static const struct usb_string_descriptor_struct PROGMEM string1 = {
sizeof(STR_MANUFACTURER),
3,
STR_MANUFACTURER
};
static const struct usb_string_descriptor_struct PROGMEM string2 = {
sizeof(STR_PRODUCT),
3,
STR_PRODUCT
};

// This table defines which descriptor data is sent for each specific
// request from the host (in wValue and wIndex).
static const struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2100, GAMEPAD_INTERFACE, config1_descriptor+GAMEPAD_HID_DESC_OFFSET, 9},
{0x2200, GAMEPAD_INTERFACE, gamepad_hid_report_desc, sizeof(gamepad_hid_report_desc)},
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
{0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}
};
« Last Edit: January 13, 2014, 02:33:33 pm by locodog »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Which HID usage type would be best?
« Reply #3 on: January 13, 2014, 02:18:07 pm »
If the device appears in Device Manager without errors, it has enumerated successfully.

A protocol analyzer will show the traffic on the bus. Even a software-only analyzer might be useful here.

http://www.lvr.com/development_tools.htm#analyzers

Otherwise, my suggestion would be to start with working code, which you seem to have, and make incremental changes.

locodog

  • Member
  • ***
  • Posts: 8
Re: Which HID usage type would be best?
« Reply #4 on: January 13, 2014, 03:41:52 pm »
Thanks but the problem still stands I can add buttons and dials right up to the end of the scope of the usage type, then I'm lost.

I need to understand a generic type report

Could I skip the usages like this?
Code: [Select]
static const uint8_t PROGMEM gamepad_hid_report_desc[] = {
0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
0x09, 0x05,        // USAGE (Gamepad)
0xa1, 0x01,        // COLLECTION (Application)
0x15, 0x00,        //   LOGICAL_MINIMUM (0)
0x25, 0x01,        //   LOGICAL_MAXIMUM (1)
0x35, 0x00,        //   PHYSICAL_MINIMUM (0)
0x45, 0x01,        //   PHYSICAL_MAXIMUM (1)
0x75, 0x01,        //   REPORT_SIZE (1)
0x95, 0x80,        //   REPORT_COUNT (128)
0x05, 0x09,        //   USAGE_PAGE (Button)
0x19, 0x01,        //   USAGE_MINIMUM (Button 1)
0x29, 0x80,        //   USAGE_MAXIMUM (Button 128)
0x81, 0x02,        //   INPUT (Data,Var,Abs)
0x05, 0x01,        //   USAGE_PAGE (Generic Desktop)
0x26, 0xff, 0x00,  //   LOGICAL_MAXIMUM (255)
0x46, 0xff, 0x00,  //   PHYSICAL_MAXIMUM (255)
      
        COULD I JUST HAVE NO USAGE TYPES?

0x75, 0x08,        //   REPORT_SIZE (8)
0x95, 0x30,        //   REPORT_COUNT (48)
0xc0               // END_COLLECTION


Also does bLenght need changing as the number of inputs increases?

Code: [Select]

static const uint8_t PROGMEM device_descriptor[] = {
18, // bLength             // Should this be 64? 128bits & 48bytes
1, // bDescriptorType
0x10, 0x01, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
ENDPOINT0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
0x00, 0x01, // bcdDevice
1, // iManufacturer
2, // iProduct
0, // iSerialNumber
1 // bNumConfigurations
};



« Last Edit: January 13, 2014, 03:57:52 pm by locodog »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Which HID usage type would be best?
« Reply #5 on: January 13, 2014, 06:35:15 pm »
From the HID spec:

A Report descriptor must
include each of the following items to describe a control’s data (all other items are
optional):
Input (Output or Feature)
Usage
Usage Page
Logical Minimum
Logical Maximum
Report Size
Report Count

See the HID spec and Usage Tables documents:

http://www.usb.org/developers/docs/docs/hidpage/

bLength in the device descriptor is the length of the device descriptor, always 18.


locodog

  • Member
  • ***
  • Posts: 8
Re: Which HID usage type would be best?
« Reply #6 on: January 13, 2014, 09:49:37 pm »
Thanks a lot, I can only read so much of the HID usage pdf before I glaze over, I never did spot that bare minimum list,

In my defence it's tricky when approaching a new topic to figure out what's pertinent

Right now I know the direction to travel so I can now do as you say and build up incrementally. Thanks.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Which HID usage type would be best?
« Reply #7 on: January 13, 2014, 10:12:33 pm »
The HID report formats are not easy to grasp. The Usages are required because they tell the host computer what to do with the data.

locodog

  • Member
  • ***
  • Posts: 8
Re: Which HID usage type would be best?
« Reply #8 on: January 14, 2014, 04:48:31 am »
Ah, right erm (I thought when you said usages you meant the type that is next to usage page) can I repeat usages?

Like this?  (feels doubtful)
Code: [Select]
0x09, 0x30,        //   USAGE (X)
0x09, 0x30,        //   USAGE (X)
0x09, 0x30,        //   USAGE (X)

like I've said, I would like 48 8bit inputs, I have a hunch that there is no gamepad/joystick/simulation controller that will fit the bill,

How about  

Vendor defined, or undefined? (I have yet to find a worked example after lots of searching)

 From what I can see in the HID descriptor tool there are 16 things that appear suitable for analogue inputs under the generic desktop (x,y,z,rx,ry,rz, silder, dial wheel, vx, vy, vz, vbrx vbry vbrz, vno) could l repeat this list (3 times) somehow?

Or could I take all the 0x codes for various analogue usage, (like from helicopter controls and flight controls etc) and write it up manually?

Thanks for your patience.
« Last Edit: January 14, 2014, 05:39:22 am by locodog »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Which HID usage type would be best?
« Reply #9 on: January 14, 2014, 08:09:20 pm »
Besides making sure the report descriptor complies with the HID specs, if you want the capabilities to work without a vendor-provided filter driver or application, you will need to stick to controls that Windows or whatever OSes your device will use supports. A vendor-defined usage needs a vendor-provided application or driver that knows what to do with the data.

These might help:

http://msdn.microsoft.com/en-us/library/windows/desktop/ee416842%28v=vs.85%29.aspx

http://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/

locodog

  • Member
  • ***
  • Posts: 8
Re: Which HID usage type would be best?
« Reply #10 on: January 14, 2014, 10:18:06 pm »
Thanks I've already seen both links, direct input (directx) won't cut it (8 analogue inputs and 32 buttons max, I think I read somewhere) although because of the eleccelerator site I have realised I could make the device represent 3 controllers, which is a hack but it appears short of paying someone to write the firmware, (which isn't a option) or reverting to midi (I'd really rather not), that's my only option.

Hmmm I've learnt a lot but very little has been useful.  :-\

One final shot in the dark, is there a (premade) software option to takes serial data from a com port and emulates HID on the pc?

*edit* or will that introduce excessive latency?


 *crosses fingers*
« Last Edit: January 15, 2014, 06:05:11 am by locodog »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Which HID usage type would be best?
« Reply #11 on: January 15, 2014, 09:37:35 am »
Serial to HID, if you could find something to do that, wouldn't eliminate the need for a functioning report descriptor with the capabilities you're looking for.

If you don't want to provide a filter driver, you'll need to stick with what Windows supports.

locodog

  • Member
  • ***
  • Posts: 8
Re: Which HID usage type would be best?
« Reply #12 on: January 16, 2014, 04:59:38 am »
It appears there isn't a software option, lots of HID to serial. Nothing for serial to HID, It looks like it will have to be midi,  >:(