Merge pull request #776 from dhalbert/hid_gamepad

HID gamepad support
This commit is contained in:
Dan Halbert 2018-04-24 14:27:04 -04:00 committed by GitHub
commit 8cadcc8e83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 325 additions and 16 deletions

View File

@ -35,12 +35,27 @@
#include "genhdr/autogen_usb_descriptor.h"
// Buffers are report size + 1 to include the Report ID prefix byte if needed.
#ifdef USB_HID_REPORT_LENGTH_KEYBOARD
static uint8_t keyboard_report_buffer[USB_HID_REPORT_LENGTH_KEYBOARD + 1];
#endif
#ifdef USB_HID_REPORT_ID_MOUSE
static uint8_t mouse_report_buffer[USB_HID_REPORT_LENGTH_MOUSE + 1];
#endif
#ifdef USB_HID_REPORT_ID_CONSUMER
static uint8_t consumer_report_buffer[USB_HID_REPORT_LENGTH_CONSUMER + 1];
#endif
#ifdef USB_HID_REPORT_ID_SYS_CONTROL
static uint8_t sys_control_report_buffer[USB_HID_REPORT_LENGTH_SYS_CONTROL + 1];
#endif
#ifdef USB_HID_REPORT_ID_GAMEPAD
static uint8_t gamepad_report_buffer[USB_HID_REPORT_LENGTH_GAMEPAD + 1];
#endif
#ifdef USB_HID_REPORT_ID_DIGITIZER
static uint8_t digitizer_report_buffer[USB_HID_REPORT_LENGTH_DIGITIZER + 1];
#endif
usb_hid_device_obj_t usb_hid_devices[USB_HID_NUM_DEVICES] = {
#ifdef USB_HID_REPORT_LENGTH_KEYBOARD
{
.base = { .type = &usb_hid_device_type },
.report_buffer = keyboard_report_buffer,
@ -50,6 +65,8 @@ usb_hid_device_obj_t usb_hid_devices[USB_HID_NUM_DEVICES] = {
.usage_page = 0x01,
.usage = 0x06,
},
#endif
#ifdef USB_HID_REPORT_ID_MOUSE
{
.base = { .type = &usb_hid_device_type },
.report_buffer = mouse_report_buffer,
@ -59,6 +76,8 @@ usb_hid_device_obj_t usb_hid_devices[USB_HID_NUM_DEVICES] = {
.usage_page = 0x01,
.usage = 0x02,
},
#endif
#ifdef USB_HID_REPORT_ID_CONSUMER
{
.base = { .type = &usb_hid_device_type },
.report_buffer = consumer_report_buffer,
@ -68,6 +87,8 @@ usb_hid_device_obj_t usb_hid_devices[USB_HID_NUM_DEVICES] = {
.usage_page = 0x0C,
.usage = 0x01,
},
#endif
#ifdef USB_HID_REPORT_ID_SYS_CONTROL
{
.base = { .type = &usb_hid_device_type },
.report_buffer = sys_control_report_buffer,
@ -77,6 +98,29 @@ usb_hid_device_obj_t usb_hid_devices[USB_HID_NUM_DEVICES] = {
.usage_page = 0x01,
.usage = 0x80,
},
#endif
#ifdef USB_HID_REPORT_ID_GAMEPAD
{
.base = { .type = &usb_hid_device_type },
.report_buffer = gamepad_report_buffer,
.endpoint = USB_HID_ENDPOINT_IN,
.report_id = USB_HID_REPORT_ID_GAMEPAD,
.report_length = USB_HID_REPORT_LENGTH_GAMEPAD,
.usage_page = 0x01,
.usage = 0x05,
},
#endif
#ifdef USB_HID_REPORT_ID_DIGITIZER
{
.base = { .type = &usb_hid_device_type },
.report_buffer = digitizer_report_buffer,
.endpoint = USB_HID_ENDPOINT_IN,
.report_id = USB_HID_REPORT_ID_DIGITIZER,
.report_length = USB_HID_REPORT_LENGTH_DIGITIZER,
.usage_page = 0x0D,
.usage = 0x02,
},
#endif
};
@ -86,9 +130,23 @@ mp_obj_tuple_t common_hal_usb_hid_devices = {
},
.len = USB_HID_NUM_DEVICES,
.items = {
#if USB_HID_NUM_DEVICES >= 1
(mp_obj_t) &usb_hid_devices[0],
#endif
#if USB_HID_NUM_DEVICES >= 2
(mp_obj_t) &usb_hid_devices[1],
#endif
#if USB_HID_NUM_DEVICES >= 3
(mp_obj_t) &usb_hid_devices[2],
#endif
#if USB_HID_NUM_DEVICES >= 4
(mp_obj_t) &usb_hid_devices[3],
#endif
#if USB_HID_NUM_DEVICES >= 5
(mp_obj_t) &usb_hid_devices[4],
#endif
#if USB_HID_NUM_DEVICES >= 6
(mp_obj_t) &usb_hid_devices[5],
#endif
}
};

View File

@ -7,6 +7,7 @@ import sys
sys.path.append("../../tools/usb_descriptor")
from adafruit_usb_descriptor import cdc, hid, msc, standard, util
import hid_report_descriptors
parser = argparse.ArgumentParser(description='Generate USB descriptors.')
parser.add_argument('--manufacturer', type=str,
@ -122,19 +123,29 @@ msc_interfaces = [
standard.EndpointDescriptor(
description="MSC in",
bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK),
bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
bInterval=0),
standard.EndpointDescriptor(
description="MSC out",
bEndpointAddress=0x1 | standard.EndpointDescriptor.DIRECTION_OUT,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK)
bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
bInterval=0)
]
)
]
hid_report_descriptor = hid.ReportDescriptor.MOUSE_KEYBOARD_CONSUMER_SYS_CONTROL_REPORT
hid_report_ids = hid.ReportDescriptor.REPORT_IDS
hid_report_lengths = hid.ReportDescriptor.REPORT_LENGTHS
hid_max_report_length = max(hid_report_lengths.values())
# Include only these HID devices.
# DIGITIZER works on Linux but conflicts with MOUSE, so leave it out for now.
hid_devices = ("KEYBOARD", "MOUSE", "CONSUMER", "GAMEPAD")
combined_hid_report_descriptor = hid.ReportDescriptor(
description="MULTIDEVICE",
report_descriptor=b''.join(
hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor for name in hid_devices ))
hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices }
hid_report_lengths_dict = { name: hid_report_descriptors.REPORT_LENGTHS[name] for name in hid_devices }
hid_max_report_length = max(hid_report_lengths_dict.values())
# ASF4 expects keyboard and generic devices to have both in and out endpoints,
# and will fail (possibly silently) if both are not supplied.
@ -142,12 +153,13 @@ hid_endpoint_in_descriptor = standard.EndpointDescriptor(
description="HID in",
bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
bInterval=0x02)
bInterval=10)
hid_endpoint_out_descriptor = standard.EndpointDescriptor(
description="HID out",
bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_OUT,
bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT)
bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
bInterval=10)
hid_interfaces = [
standard.InterfaceDescriptor(
@ -159,7 +171,7 @@ hid_interfaces = [
subdescriptors=[
hid.HIDDescriptor(
description="HID",
wDescriptorLength=len(bytes(hid_report_descriptor))),
wDescriptorLength=len(bytes(combined_hid_report_descriptor))),
hid_endpoint_in_descriptor,
hid_endpoint_out_descriptor,
]
@ -274,7 +286,7 @@ uint8_t hid_report_descriptor[{HID_REPORT_DESCRIPTOR_LENGTH}];
"""
.format(SERIAL_NUMBER_OFFSET=serial_number_offset,
SERIAL_NUMBER_LENGTH=args.serial_number_length,
HID_REPORT_DESCRIPTOR_LENGTH=len(bytes(hid_report_descriptor)),
HID_REPORT_DESCRIPTOR_LENGTH=len(bytes(combined_hid_report_descriptor)),
HID_ENDPOINT_IN_ADDRESS=hex(hid_endpoint_in_descriptor.bEndpointAddress),
HID_ENDPOINT_OUT_ADDRESS=hex(hid_endpoint_out_descriptor.bEndpointAddress)))
@ -294,7 +306,7 @@ for interface in interfaces:
h_file.write("\n")
# #define the report ID's used in the combined HID descriptor
for name, id in hid_report_ids.items():
for name, id in hid_report_ids_dict.items():
h_file.write("""\
#define USB_HID_REPORT_ID_{NAME} {ID}
""".format(NAME=name,
@ -303,7 +315,7 @@ for name, id in hid_report_ids.items():
h_file.write("\n")
# #define the report sizes used in the combined HID descriptor
for name, length in hid_report_lengths.items():
for name, length in hid_report_lengths_dict.items():
h_file.write("""\
#define USB_HID_REPORT_LENGTH_{NAME} {LENGTH}
""".format(NAME=name,
@ -314,7 +326,7 @@ h_file.write("\n")
h_file.write("""\
#define USB_HID_NUM_DEVICES {NUM_DEVICES}
#define USB_HID_MAX_REPORT_LENGTH {MAX_LENGTH}
""".format(NUM_DEVICES=len(hid_report_lengths),
""".format(NUM_DEVICES=len(hid_report_lengths_dict),
MAX_LENGTH=hid_max_report_length))
@ -322,9 +334,9 @@ h_file.write("""\
# Write out the report descriptor and info
c_file.write("""\
uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{
""".format(HID_DESCRIPTOR_LENGTH=len(bytes(hid_report_descriptor))))
""".format(HID_DESCRIPTOR_LENGTH=len(bytes(combined_hid_report_descriptor))))
for b in bytes(hid_report_descriptor):
for b in bytes(combined_hid_report_descriptor):
c_file.write("0x{:02x}, ".format(b))
c_file.write("""
};

View File

@ -0,0 +1,239 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Dan Halbert for Adafruit Industries
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import struct
"""
HID specific descriptors
========================
* Author(s): Dan Halbert
"""
from adafruit_usb_descriptor import hid
REPORT_IDS = {
"KEYBOARD" : 1,
"MOUSE" : 2,
"CONSUMER" : 3,
"SYS_CONTROL" : 4,
"GAMEPAD" : 5,
"DIGITIZER" : 6,
}
# Byte count for each kind of report. Length does not include report ID in first byte.
REPORT_LENGTHS = {
"KEYBOARD" : 8,
"MOUSE" : 4,
"CONSUMER" : 2,
"SYS_CONTROL" : 1,
"GAMEPAD" : 6,
"DIGITIZER" : 5,
}
KEYBOARD_WITH_ID = hid.ReportDescriptor(
description="KEYBOARD",
report_descriptor=bytes([
# Regular keyboard
0x05, 0x01, # Usage Page (Generic Desktop)
0x09, 0x06, # Usage (Keyboard)
0xA1, 0x01, # Collection (Application)
0x85, REPORT_IDS["KEYBOARD"], # Report ID (1)
0x05, 0x07, # Usage Page (Keyboard)
0x19, 224, # Usage Minimum (224)
0x29, 231, # Usage Maximum (231)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x75, 0x01, # Report Size (1)
0x95, 0x08, # Report Count (8)
0x81, 0x02, # Input (Data, Variable, Absolute)
0x81, 0x01, # Input (Constant)
0x19, 0x00, # Usage Minimum (0)
0x29, 101, # Usage Maximum (101)
0x15, 0x00, # Logical Minimum (0)
0x25, 101, # Logical Maximum (101)
0x75, 0x08, # Report Size (8)
0x95, 0x06, # Report Count (6)
0x81, 0x00, # Input (Data, Array)
0x05, 0x08, # Usage Page (LED)
0x19, 0x01, # Usage Minimum (1)
0x29, 0x05, # Usage Maximum (5)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x75, 0x01, # Report Size (1)
0x95, 0x05, # Report Count (5)
0x91, 0x02, # Output (Data, Variable, Absolute)
0x95, 0x03, # Report Count (3)
0x91, 0x01, # Output (Constant)
0xC0, # End Collection
]))
MOUSE_WITH_ID = hid.ReportDescriptor(
description="MOUSE",
report_descriptor=bytes([
# Regular mouse
0x05, 0x01, # Usage Page (Generic Desktop)
0x09, 0x02, # Usage (Mouse)
0xA1, 0x01, # Collection (Application)
0x09, 0x01, # Usage (Pointer)
0xA1, 0x00, # Collection (Physical)
0x85, REPORT_IDS["MOUSE"], # Report ID (n)
0x05, 0x09, # Usage Page (Button)
0x19, 0x01, # Usage Minimum (0x01)
0x29, 0x05, # Usage Maximum (0x05)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x95, 0x05, # Report Count (5)
0x75, 0x01, # Report Size (1)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, # Report Count (1)
0x75, 0x03, # Report Size (3)
0x81, 0x01, # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x30, # Usage (X)
0x09, 0x31, # Usage (Y)
0x15, 0x81, # Logical Minimum (-127)
0x25, 0x7F, # Logical Maximum (127)
0x75, 0x08, # Report Size (8)
0x95, 0x02, # Report Count (2)
0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x38, # Usage (Wheel)
0x15, 0x81, # Logical Minimum (-127)
0x25, 0x7F, # Logical Maximum (127)
0x75, 0x08, # Report Size (8)
0x95, 0x01, # Report Count (1)
0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
0xC0, # End Collection
]))
CONSUMER_WITH_ID = hid.ReportDescriptor(
description="CONSUMER",
report_descriptor=bytes([
# Consumer ("multimedia") keys
0x05, 0x0C, # Usage Page (Consumer)
0x09, 0x01, # Usage (Consumer Control)
0xA1, 0x01, # Collection (Application)
0x85, REPORT_IDS["CONSUMER"], # Report ID (n)
0x75, 0x10, # Report Size (16)
0x95, 0x01, # Report Count (1)
0x15, 0x01, # Logical Minimum (1)
0x26, 0x8C, 0x02, # Logical Maximum (652)
0x19, 0x01, # Usage Minimum (Consumer Control)
0x2A, 0x8C, 0x02, # Usage Maximum (AC Send)
0x81, 0x00, # Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
]))
SYS_CONTROL_WITH_ID = hid.ReportDescriptor(
description="SYS_CONTROL",
report_descriptor=bytes([
# Power controls
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x80, # Usage (Sys Control)
0xA1, 0x01, # Collection (Application)
0x85, REPORT_IDS["SYS_CONTROL"], # Report ID (n)
0x75, 0x02, # Report Size (2)
0x95, 0x01, # Report Count (1)
0x15, 0x01, # Logical Minimum (1)
0x25, 0x03, # Logical Maximum (3)
0x09, 0x82, # Usage (Sys Sleep)
0x09, 0x81, # Usage (Sys Power Down)
0x09, 0x83, # Usage (Sys Wake Up)
0x81, 0x60, # Input (Data,Array,Abs,No Wrap,Linear,No Preferred State,Null State)
0x75, 0x06, # Report Size (6)
0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
]))
GAMEPAD_WITH_ID = hid.ReportDescriptor(
description="GAMEPAD",
report_descriptor=bytes([
# Gamepad with 16 buttons and two joysticks
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x05, # Usage (Game Pad)
0xA1, 0x01, # Collection (Application)
0x85, REPORT_IDS["GAMEPAD"], # Report ID (n)
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,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x15, 0x81, # Logical Minimum (-127)
0x25, 0x7F, # Logical Maximum (127)
0x09, 0x30, # Usage (X)
0x09, 0x31, # Usage (Y)
0x09, 0x32, # Usage (Z)
0x09, 0x35, # Usage (Rz)
0x75, 0x08, # Report Size (8)
0x95, 0x04, # Report Count (4)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
]))
DIGITIZER_WITH_ID = hid.ReportDescriptor(
description="DIGITIZER",
report_descriptor=bytes([
# Digitizer (used as an absolute pointer)
0x05, 0x0D, # Usage Page (Digitizers)
0x09, 0x02, # Usage (Pen)
0xA1, 0x01, # Collection (Application)
0x85, REPORT_IDS["DIGITIZER"], # Report ID (n)
0x09, 0x01, # Usage (Stylus)
0xA1, 0x00, # Collection (Physical)
0x09, 0x32, # Usage (In-Range)
0x09, 0x42, # Usage (Tip Switch)
0x09, 0x44, # Usage (Barrel Switch)
0x09, 0x45, # Usage (Eraser Switch)
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)
0x75, 0x04, # Report Size (4) -- Filler
0x95, 0x01, # Report Count (1) -- Filler
0x81, 0x01, # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xff, 0x7f, # Logical Maximum (32767)
0x09, 0x30, # Usage (X)
0x09, 0x31, # Usage (Y)
0x75, 0x10, # Report Size (16)
0x95, 0x02, # Report Count (2)
0x81, 0x02, # Input (Data,Var,Abs)
0xC0, # End Collection
0xC0, # End Collection
]))
# Byte count for each kind of report. Length does not include report ID in first byte.
REPORT_DESCRIPTORS = {
"KEYBOARD" : KEYBOARD_WITH_ID,
"MOUSE" : MOUSE_WITH_ID,
"CONSUMER" : CONSUMER_WITH_ID,
"SYS_CONTROL" : SYS_CONTROL_WITH_ID,
"GAMEPAD" : GAMEPAD_WITH_ID,
"DIGITIZER" : DIGITIZER_WITH_ID,
}

@ -1 +1 @@
Subproject commit 0ccd1935d666bcffc3fd5941ba06bd9273d72e0c
Subproject commit 2507847031a0395465956539253cbfa27f87511e