USB Descriptor for multiple Throttle

274 views Asked by At

I would like to have a USB Joystick that is connected to a PIC microcontroller. It works fine with just one throttle and several buttons and two axis.

How can I add another throttle descriptor ?

Here is the current one

const unsigned int USB_VENDOR_ID = 0x1234;
const unsigned int USB_PRODUCT_ID = 0x0001;
const char USB_SELF_POWER = 0x80;            // Self powered 0xC0,  0x80 bus powered
const char USB_MAX_POWER = 50;               // Bus power required in units of 2 mA
const char HID_INPUT_REPORT_BYTES = 64;
const char HID_OUTPUT_REPORT_BYTES = 64;
const char EP_IN_INTERVAL = 1;
const char EP_OUT_INTERVAL = 1;
// diske noconst char EP_IN_INTERVAL = 1;
const char USB_INTERRUPT = 0;
const char USB_TRANSFER_TYPE = 0x03;         //0x03 Interrupt
const char USB_HID_EP = 1;
const char USB_HID_RPT_SIZE = 78;

/* Device Descriptor */
const struct {
    char bLength;               // bLength         - Descriptor size in bytes (12h)
    char bDescriptorType;       // bDescriptorType - The constant DEVICE (01h)
    unsigned int bcdUSB;        // bcdUSB          - USB specification release number (BCD)
    char bDeviceClass;          // bDeviceClass    - Class Code
    char bDeviceSubClass;       // bDeviceSubClass - Subclass code
    char bDeviceProtocol;       // bDeviceProtocol - Protocol code
    char bMaxPacketSize0;       // bMaxPacketSize0 - Maximum packet size for endpoint 0
    unsigned int idVendor;      // idVendor        - Vendor ID
    unsigned int idProduct;     // idProduct       - Product ID
    unsigned int bcdDevice;     // bcdDevice       - Device release number (BCD)
    char iManufacturer;         // iManufacturer   - Index of string descriptor for the manufacturer
    char iProduct;              // iProduct        - Index of string descriptor for the product.
    char iSerialNumber;         // iSerialNumber   - Index of string descriptor for the serial number.
    char bNumConfigurations;    // bNumConfigurations - Number of possible configurations
} device_dsc = {
      0x12,                   // bLength
      0x01,                   // bDescriptorType
      0x0200,                 // bcdUSB
      0x00,                   // bDeviceClass
      0x00,                   // bDeviceSubClass
      0x00,                   // bDeviceProtocol
      8,                      // bMaxPacketSize0
      USB_VENDOR_ID,          // idVendor
      USB_PRODUCT_ID,         // idProduct
      0x0020,                 // bcdDevice
      0x01,                   // iManufacturer
      0x02,                   // iProduct
      0x03,                   // iSerialNumber
      0x01                    // bNumConfigurations
  };

/* Configuration 1 Descriptor */
const char configDescriptor1[]= {
    // Configuration Descriptor
    0x09,                   // bLength             - Descriptor size in bytes
    0x02,                   // bDescriptorType     - The constant CONFIGURATION (02h)
    0x29,0x00,              // wTotalLength        - The number of bytes in the configuration descriptor and all of its subordinate descriptors
    1,                      // bNumInterfaces      - Number of interfaces in the configuration
    1,                      // bConfigurationValue - Identifier for Set Configuration and Get Configuration requests
    0,                      // iConfiguration      - Index of string descriptor for the configuration
    USB_SELF_POWER,         // bmAttributes        - Self/bus power and remote wakeup settings
    USB_MAX_POWER,          // bMaxPower           - Bus power required in units of 2 mA

    // Interface Descriptor
    0x09,                   // bLength - Descriptor size in bytes (09h)
    0x04,                   // bDescriptorType - The constant Interface (04h)
    0,                      // bInterfaceNumber - Number identifying this interface
    0,                      // bAlternateSetting - A number that identifies a descriptor with alternate settings for this bInterfaceNumber.
    2,                      // bNumEndpoint - Number of endpoints supported not counting endpoint zero
    0x03,                   // bInterfaceClass - Class code
    0,                      // bInterfaceSubclass - Subclass code
    0,                      // bInterfaceProtocol - Protocol code
    0,                      // iInterface - Interface string index

    // HID Class-Specific Descriptor
    0x09,                   // bLength - Descriptor size in bytes.
    0x21,                   // bDescriptorType - This descriptor's type: 21h to indicate the HID class.
    0x01,0x01,              // bcdHID - HID specification release number (BCD).
    0x00,                   // bCountryCode - Numeric expression identifying the country for localized hardware (BCD) or 00h.
    1,                      // bNumDescriptors - Number of subordinate report and physical descriptors.
    0x22,                   // bDescriptorType - The type of a class-specific descriptor that follows
    USB_HID_RPT_SIZE,0x00,  // wDescriptorLength - Total length of the descriptor identified above.

    // Endpoint Descriptor
    0x07,                   // bLength - Descriptor size in bytes (07h)
    0x05,                   // bDescriptorType - The constant Endpoint (05h)
    USB_HID_EP | 0x80,      // bEndpointAddress - Endpoint number and direction
    USB_TRANSFER_TYPE,      // bmAttributes - Transfer type and supplementary information
    0x40,0x00,              // wMaxPacketSize - Maximum packet size supported
    EP_IN_INTERVAL,         // bInterval - Service interval or NAK rate

    // Endpoint Descriptor
    0x07,                   // bLength - Descriptor size in bytes (07h)
    0x05,                   // bDescriptorType - The constant Endpoint (05h)
    USB_HID_EP,             // bEndpointAddress - Endpoint number and direction
    USB_TRANSFER_TYPE,      // bmAttributes - Transfer type and supplementary information
    0x40,0x00,              // wMaxPacketSize - Maximum packet size supported
    EP_OUT_INTERVAL         // bInterval - Service interval or NAK rate
};

const struct {
  char report[USB_HID_RPT_SIZE];
}
hid_rpt_desc =

     {0x05, 0x01, // USAGE_PAGE (Generic Desktop)
     0x15, 0x00, // LOGICAL_MINIMUM (0)
     0x09, 0x04, // USAGE (Joystick)
     0xA1, 0x01, // COLLECTION (Application)
     0x05, 0x02, // USAGE_PAGE (Simulation Controls)
     0x09, 0xBB, // USAGE (Throttle)
     0x15, 0x00, // LOGICAL_MINIMUM (0)
     0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255)
     0x75, 0x08, // REPORT_SIZE (8)
     0x95, 0x01, // REPORT_COUNT (1)
     0x81, 0x02, // INPUT (Data Var Abs)
     0x05, 0x01, // USAGE_PAGE (Generic Desktop)
     0x09, 0x01, // USAGE (Pointer)
     0xA1, 0x00, // COLLECTION (Physical)
     0x09, 0x30, // USAGE (X)
     0x09, 0x31, // USAGE (Y)
     0x95, 0x02, // REPORT_COUNT (2)
     0x81, 0x02, // INPUT (Data Var Abs)}
     0xC0, // END_COLLECTION
     0x09, 0x39, // USAGE (Hat switch)
     0x15, 0x00, // LOGICAL_MINIMUM (0)
     0x25, 0x03, // LOGICAL_MAXIMUM (3)
     0x35, 0x00, // PHYSICAL_MINIMUM (0)
     0x46, 0x0E, 0x01, // PHYSICAL_MAXIMUM (270)
     0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
     0x75, 0x04, // REPORT_SIZE (4)
     0x95, 0x01, // REPORT_COUNT (1)
     0x81, 0x02, // INPUT (Data Var Abs)
     0x05, 0x09, // USAGE_PAGE (Button)
     0x19, 0x01, // USAGE_MINIMUM (Button 1)
     0x29, 0x0A, // USAGE_MAXIMUM (Button 10)
      0x15, 0x00, // LOGICAL_MINIMUM (0)
      0x25, 0x01, // LOGICAL_MAXIMUM (1)
      0x75, 0x01, // REPORT_SIZE (1)
      0x95, 0x0C, // REPORT_COUNT (12) 2 bits added to switch report count
                  // so bytes are even. Bytes must be even.
      0x55, 0x00, // UNIT_EXPONENT (0)
      0x65, 0x00, // UNIT (None)
      0x81, 0x02, // INPUT (Data Var Abs)
0xC0 // END_COLLECTION
  };

//Language code string descriptor
const struct {
  char bLength;
  char bDscType;
  unsigned int string[1];
  } strd1 = {
      4,
      0x03,
      {0x0409}
    };

  const struct{
//Manufacturer string descriptor
  char bLength;
  char bDscType;
  unsigned int string[4];
  }strd2={
    10,           //sizeof this descriptor string
    0x03,
    {'N','X','R','T'}
  };

//Product string descriptor
const struct{
  char bLength;
  char bDscType;
  unsigned int string[13];
}strd3={
    28,          //sizeof this descriptor string
    0x03,
    {'N','X','R','T','-','J','o','y','s','t','i','c','k'}
 };

//Array of configuration descriptors
const char* USB_config_dsc_ptr[1];

//Array of string descriptors
const char* USB_string_dsc_ptr[3];

void USB_Init_Desc(){
  USB_config_dsc_ptr[0] = &configDescriptor1;
  USB_string_dsc_ptr[0] = (const char*)&strd1;
  USB_string_dsc_ptr[1] = (const char*)&strd2;
  USB_string_dsc_ptr[2] = (const char*)&strd3;

}
1

There are 1 answers

0
Raptyr On

This is a multi-throttle descriptor that I've written for the ARDUINO Leonardo that shows multiple throttles on Windows 10. Please be aware though that Windows 10 only accepts 8 axis and 128 buttons per joystick device - so this descriptor will work with X, Y, Rudder, Left Brake, Right Brake, and 3 throttles max (I usually use 2) I've collected all the USB HID values into #define values to make it more readable. (I'm not including those here). You can find the full library at https://github.com/Raptyr/FlightControl

uint8_t descriptor[150];
int descriptorIndex = 0;
#define DESCRIPTOR(_array,_index,label,value) _array[_index++] = label;_array[_index++] = value;
#define DESCRIPTOR1(_array,_index,label) _array[_index++] = label;
#define DESCRIPTOR3(_array,_index,label,value1,value2) _array[_index++] = label; _array[_index++] = value1;_array[_index++] = value2;
DESCRIPTOR(descriptor, descriptorIndex, USAGE_PAGE, PAGE_GENERIC_DESKTOP)
DESCRIPTOR(descriptor, descriptorIndex, USAGE, GENERIC_JOYSTICK)
DESCRIPTOR(descriptor, descriptorIndex, COLLECTION, COLLECTION_APPLICATION)
DESCRIPTOR(descriptor, descriptorIndex, REPORT_ID, _hidReportID)
if (_buttonCount > 0)
{
    uint8_t buttonsInLastByte = _buttonCount % 8;
    uint8_t paddingBits = buttonsInLastByte > 0 ? 8 - buttonsInLastByte : 0;
    DESCRIPTOR(descriptor,descriptorIndex,USAGE_PAGE,PAGE_BUTTON)
    DESCRIPTOR(descriptor,descriptorIndex,USAGE_MIN,01)
    DESCRIPTOR(descriptor,descriptorIndex,USAGE_MAX,_buttonCount)
    DESCRIPTOR(descriptor,descriptorIndex,LOGICAL_MIN,0)
    DESCRIPTOR(descriptor,descriptorIndex,LOGICAL_MAX,1)
    DESCRIPTOR(descriptor,descriptorIndex,REPORT_SIZE,1)
    DESCRIPTOR(descriptor,descriptorIndex,REPORT_COUNT,_buttonCount)
    DESCRIPTOR(descriptor,descriptorIndex,UNIT_EXP,0)
    DESCRIPTOR(descriptor,descriptorIndex,UNIT,0)
    DESCRIPTOR(descriptor,descriptorIndex,INPUT,IO_DATA | IO_VARIABLE | IO_ABSOLUTE)
    if (paddingBits > 0)
    {
        DESCRIPTOR(descriptor,descriptorIndex,REPORT_SIZE,1)
        DESCRIPTOR(descriptor,descriptorIndex,REPORT_COUNT,paddingBits)
        DESCRIPTOR(descriptor,descriptorIndex,INPUT,IO_CONSTANT | IO_VARIABLE | IO_ABSOLUTE)
    }
}
DESCRIPTOR(descriptor, descriptorIndex, USAGE_PAGE, PAGE_GENERIC_DESKTOP)
DESCRIPTOR(descriptor, descriptorIndex, USAGE, GENERIC_POINTER)
DESCRIPTOR3(descriptor, descriptorIndex, LOGICAL_MIN16, 0x01, 0x80)
DESCRIPTOR3(descriptor, descriptorIndex, LOGICAL_MAX16, 0xFF, 0x7F)
DESCRIPTOR(descriptor, descriptorIndex, REPORT_SIZE, 0x10)
DESCRIPTOR(descriptor, descriptorIndex, REPORT_COUNT, _useBrakes ? 0x04 : 0x02)
DESCRIPTOR(descriptor, descriptorIndex, COLLECTION, COLLECTION_PHYSICAL)
DESCRIPTOR(descriptor, descriptorIndex, USAGE, GENERIC_X)
DESCRIPTOR(descriptor, descriptorIndex, USAGE, GENERIC_Y)
if (_useBrakes)
{
    DESCRIPTOR(descriptor, descriptorIndex,USAGE,GENERIC_RX)
    DESCRIPTOR(descriptor, descriptorIndex,USAGE,GENERIC_RY)
}
DESCRIPTOR(descriptor, descriptorIndex, INPUT, IO_DATA | IO_VARIABLE | IO_ABSOLUTE)
DESCRIPTOR1(descriptor, descriptorIndex, END_COLLECTION)
if (_useRudder || _throttleCount > 0)
{
    uint8_t simulationCount = (_useRudder ? 1 : 0) + _throttleCount;
    DESCRIPTOR(descriptor, descriptorIndex, USAGE_PAGE, PAGE_SIMULATION_CONTROLS)
    DESCRIPTOR3(descriptor, descriptorIndex, LOGICAL_MIN16, 0x01, 0x80)
    DESCRIPTOR3(descriptor, descriptorIndex, LOGICAL_MAX16, 0xFF, 0x7F)
    DESCRIPTOR(descriptor, descriptorIndex, REPORT_SIZE, 0x10)
    DESCRIPTOR(descriptor, descriptorIndex, REPORT_COUNT, simulationCount)
    DESCRIPTOR(descriptor, descriptorIndex, COLLECTION, COLLECTION_PHYSICAL)
    if (_useRudder)
    {
        DESCRIPTOR(descriptor, descriptorIndex, USAGE, SIMULATION_RUDDER)
    }
    if (_throttleCount > 0)
    {
        for (uint8_t i = 0; i < _throttleCount; i++)
        {
            DESCRIPTOR(descriptor, descriptorIndex, USAGE, SIMULATION_THROTTLE)
        }
    }
    DESCRIPTOR(descriptor, descriptorIndex, INPUT, IO_DATA | IO_VARIABLE | IO_ABSOLUTE)
    DESCRIPTOR1(descriptor, descriptorIndex, END_COLLECTION)
}
DESCRIPTOR1(descriptor, descriptorIndex, END_COLLECTION)