Преглед изворни кода

Merge pull request #638 from hathach/add-gamepad

Enhance HID Gamepad with DPad/Hat
Ha Thach пре 5 година
родитељ
комит
ac4555b361

+ 29 - 0
examples/device/hid_composite/src/main.c

@@ -183,6 +183,35 @@ void hid_task(void)
       if (has_consumer_key) tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &empty_key, 2);
       has_consumer_key = false;
     }
+
+    // delay a bit before sending next report
+    board_delay(10);
+  }
+
+  /*------------- Gamepad -------------*/
+  if ( tud_hid_ready() )
+  {
+    // use to avoid send multiple consecutive zero report for keyboard
+    static bool has_gamepad_key = false;
+
+    hid_gamepad_report_t report =
+    {
+      .x   = 0, .y = 0, .z = 0, .rz = 0, .rx = 0, .ry = 0,
+      .hat = 0, .buttons = 0
+    };
+
+    if ( btn )
+    {
+      report.hat = GAMEPAD_HAT_UP;
+      tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report));
+
+      has_gamepad_key = true;
+    }else
+    {
+      report.hat = GAMEPAD_HAT_CENTERED;
+      if (has_gamepad_key) tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report));
+      has_gamepad_key = false;
+    }
   }
 }
 

+ 3 - 2
examples/device/hid_composite/src/usb_descriptors.c

@@ -75,7 +75,8 @@ uint8_t const desc_hid_report[] =
 {
   TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD         )),
   TUD_HID_REPORT_DESC_MOUSE   ( HID_REPORT_ID(REPORT_ID_MOUSE            )),
-  TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(REPORT_ID_CONSUMER_CONTROL ))
+  TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(REPORT_ID_CONSUMER_CONTROL )),
+  TUD_HID_REPORT_DESC_GAMEPAD ( HID_REPORT_ID(REPORT_ID_GAMEPAD          ))
 };
 
 // Invoked when received GET HID REPORT DESCRIPTOR
@@ -105,7 +106,7 @@ uint8_t const desc_configuration[] =
   // Config number, interface count, string index, total length, attribute, power in mA
   TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
-  // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
+  // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
   TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
 };
 

+ 1 - 0
examples/device/hid_composite/src/usb_descriptors.h

@@ -30,6 +30,7 @@ enum
   REPORT_ID_KEYBOARD = 1,
   REPORT_ID_MOUSE,
   REPORT_ID_CONSUMER_CONTROL,
+  REPORT_ID_GAMEPAD
 };
 
 #endif /* USB_DESCRIPTORS_H_ */

+ 1 - 1
examples/device/hid_composite_freertos/src/usb_descriptors.c

@@ -105,7 +105,7 @@ uint8_t const desc_configuration[] =
   // Config number, interface count, string index, total length, attribute, power in mA
   TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
-  // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
+  // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
   TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
 };
 

+ 6 - 6
examples/device/hid_multiple_interface/src/usb_descriptors.c

@@ -118,7 +118,7 @@ uint8_t const desc_configuration[] =
   // Config number, interface count, string index, total length, attribute, power in mA
   TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
-  // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
+  // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
   TUD_HID_DESCRIPTOR(ITF_NUM_HID1, 4, HID_PROTOCOL_NONE, sizeof(desc_hid_report1), EPNUM_HID1, CFG_TUD_HID_EP_BUFSIZE, 10),
   TUD_HID_DESCRIPTOR(ITF_NUM_HID2, 5, HID_PROTOCOL_NONE, sizeof(desc_hid_report2), EPNUM_HID2, CFG_TUD_HID_EP_BUFSIZE, 10)
 };
@@ -140,11 +140,11 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
 char const* string_desc_arr [] =
 {
   (const char[]) { 0x09, 0x04 },  // 0: is supported language is English (0x0409)
-  "TinyUSB",                              // 1: Manufacturer
-  "TinyUSB Device",                 // 2: Product
-  "123456",                                // 3: Serials, should use chip ID
-  "Keyboard Interface",             // 4: Interface 1 String
-  "Mouse Interface",                 // 5: Interface 2 String
+  "TinyUSB",                      // 1: Manufacturer
+  "TinyUSB Device",               // 2: Product
+  "123456",                       // 3: Serials, should use chip ID
+  "Keyboard Interface",           // 4: Interface 1 String
+  "Mouse Interface",              // 5: Interface 2 String
 };
 
 static uint16_t _desc_str[32];

+ 91 - 0
src/class/hid/hid.h

@@ -143,6 +143,97 @@ typedef enum
 
 /** @} */
 
+//--------------------------------------------------------------------+
+// GAMEPAD
+//--------------------------------------------------------------------+
+/** \addtogroup ClassDriver_HID_Gamepad Gamepad
+ *  @{ */
+
+/* From https://www.kernel.org/doc/html/latest/input/gamepad.html
+          ____________________________              __
+         / [__ZL__]          [__ZR__] \               |
+        / [__ TL __]        [__ TR __] \              | Front Triggers
+     __/________________________________\__         __|
+    /                                  _   \          |
+   /      /\           __             (N)   \         |
+  /       ||      __  |MO|  __     _       _ \        | Main Pad
+ |    <===DP===> |SE|      |ST|   (W) -|- (E) |       |
+  \       ||    ___          ___       _     /        |
+  /\      \/   /   \        /   \     (S)   /\      __|
+ /  \________ | LS  | ____ |  RS | ________/  \       |
+|         /  \ \___/ /    \ \___/ /  \         |      | Control Sticks
+|        /    \_____/      \_____/    \        |    __|
+|       /                              \       |
+ \_____/                                \_____/
+
+     |________|______|    |______|___________|
+       D-Pad    Left       Right   Action Pad
+               Stick       Stick
+
+                 |_____________|
+                    Menu Pad
+
+  Most gamepads have the following features:
+  - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST.
+  - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right.
+  - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START.
+  - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also
+  provide a digital button if you press them.
+  - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons
+  are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right.
+  - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors.
+ */
+
+/// HID Gamepad Protocol Report.
+typedef struct TU_ATTR_PACKED
+{
+  int8_t  x;         ///< Delta x  movement of left analog-stick
+  int8_t  y;         ///< Delta y  movement of left analog-stick
+  int8_t  z;         ///< Delta z  movement of right analog-joystick
+  int8_t  rz;        ///< Delta Rz movement of right analog-joystick
+  int8_t  rx;        ///< Delta Rx movement of analog left trigger
+  int8_t  ry;        ///< Delta Ry movement of analog right trigger
+  uint8_t hat;       ///< Buttons mask for currently pressed buttons in the DPad/hat
+  uint16_t buttons;  ///< Buttons mask for currently pressed buttons
+}hid_gamepad_report_t;
+
+/// Standard Gamepad Buttons Bitmap (from Linux input event codes)
+typedef enum
+{
+  GAMEPAD_BUTTON_A      = TU_BIT(0),  ///< A/South button
+  GAMEPAD_BUTTON_B      = TU_BIT(1),  ///< B/East button
+  GAMEPAD_BUTTON_C      = TU_BIT(2),  ///< C button
+  GAMEPAD_BUTTON_X      = TU_BIT(3),  ///< X/North button
+  GAMEPAD_BUTTON_Y      = TU_BIT(4),  ///< Y/West button
+  GAMEPAD_BUTTON_Z      = TU_BIT(5),  ///< Z button
+  GAMEPAD_BUTTON_TL     = TU_BIT(6),  ///< L1 button
+  GAMEPAD_BUTTON_TR     = TU_BIT(7),  ///< R1 button
+  GAMEPAD_BUTTON_TL2    = TU_BIT(8),  ///< L2 button
+  GAMEPAD_BUTTON_TR2    = TU_BIT(9),  ///< R2 button
+  GAMEPAD_BUTTON_SELECT = TU_BIT(10), ///< Select button
+  GAMEPAD_BUTTON_START  = TU_BIT(11), ///< Start button
+  GAMEPAD_BUTTON_MODE   = TU_BIT(12), ///< Mode button
+  GAMEPAD_BUTTON_THUMBL = TU_BIT(13), ///< L3 button
+  GAMEPAD_BUTTON_THUMBR = TU_BIT(14), ///< R3 button
+//GAMEPAD_BUTTON_       = TU_BIT(15), ///< Undefined button
+}hid_gamepad_button_bm_t;
+
+/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes)
+typedef enum
+{
+  GAMEPAD_HAT_CENTERED   = 0,  ///< DPAD_CENTERED
+  GAMEPAD_HAT_UP         = 1,  ///< DPAD_UP
+  GAMEPAD_HAT_UP_RIGHT   = 2,  ///< DPAD_UP_RIGHT
+  GAMEPAD_HAT_RIGHT      = 3,  ///< DPAD_RIGHT
+  GAMEPAD_HAT_DOWN_RIGHT = 4,  ///< DPAD_DOWN_RIGHT
+  GAMEPAD_HAT_DOWN       = 5,  ///< DPAD_DOWN
+  GAMEPAD_HAT_DOWN_LEFT  = 6,  ///< DPAD_DOWN_LEFT
+  GAMEPAD_HAT_LEFT       = 7,  ///< DPAD_LEFT
+  GAMEPAD_HAT_UP_LEFT    = 8,  ///< DPAD_UP_LEFT
+}hid_gamepad_hat_t;
+
+/// @}
+
 //--------------------------------------------------------------------+
 // MOUSE
 //--------------------------------------------------------------------+

+ 20 - 7
src/class/hid/hid_device.c

@@ -107,9 +107,6 @@ bool tud_hid_n_boot_mode(uint8_t itf)
   return _hidd_itf[itf].boot_mode;
 }
 
-//--------------------------------------------------------------------+
-// KEYBOARD API
-//--------------------------------------------------------------------+
 bool tud_hid_n_keyboard_report(uint8_t itf, uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
 {
   hid_keyboard_report_t report;
@@ -127,10 +124,8 @@ bool tud_hid_n_keyboard_report(uint8_t itf, uint8_t report_id, uint8_t modifier,
   return tud_hid_n_report(itf, report_id, &report, sizeof(report));
 }
 
-//--------------------------------------------------------------------+
-// MOUSE APPLICATION API
-//--------------------------------------------------------------------+
-bool tud_hid_n_mouse_report(uint8_t itf, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
+bool tud_hid_n_mouse_report(uint8_t itf, uint8_t report_id,
+                            uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
 {
   hid_mouse_report_t report =
   {
@@ -144,6 +139,24 @@ bool tud_hid_n_mouse_report(uint8_t itf, uint8_t report_id, uint8_t buttons, int
   return tud_hid_n_report(itf, report_id, &report, sizeof(report));
 }
 
+bool tud_hid_n_gamepad_report(uint8_t itf, uint8_t report_id,
+                              int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint16_t buttons)
+{
+  hid_gamepad_report_t report =
+  {
+    .x       = x,
+    .y       = y,
+    .z       = z,
+    .rz      = rz,
+    .rx      = rx,
+    .ry      = ry,
+    .hat     = hat,
+    .buttons = buttons,
+  };
+
+  return tud_hid_n_report(itf, report_id, &report, sizeof(report));
+}
+
 //--------------------------------------------------------------------+
 // USBD-CLASS API
 //--------------------------------------------------------------------+

+ 34 - 16
src/class/hid/hid_device.h

@@ -71,6 +71,10 @@ bool tud_hid_n_keyboard_report(uint8_t itf, uint8_t report_id, uint8_t modifier,
 // use template layout report as defined by hid_mouse_report_t
 bool tud_hid_n_mouse_report(uint8_t itf, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
 
+// Gamepad: convenient helper to send mouse report if application
+// use template layout report TUD_HID_REPORT_DESC_GAMEPAD
+bool tud_hid_n_gamepad_report(uint8_t itf, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint16_t buttons);
+
 //--------------------------------------------------------------------+
 // Application API (Single Port)
 //--------------------------------------------------------------------+
@@ -119,6 +123,8 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t idle_rate);
 
 #endif
 
+// TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t itf, );
+
 
 //--------------------------------------------------------------------+
 // Inline Functions
@@ -301,14 +307,37 @@ static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8
   HID_COLLECTION_END \
 
 // Gamepad Report Descriptor Template
-// with 16 buttons and 2 joysticks with following layout
-// | Button Map (2 bytes) |  X | Y | Z | Rz
+// with 16 buttons, 2 joysticks and 1 hat/dpad with following layout
+// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (2 bytes) |
 #define TUD_HID_REPORT_DESC_GAMEPAD(...) \
-  HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP     )        ,\
-  HID_USAGE      ( HID_USAGE_DESKTOP_GAMEPAD  )        ,\
-  HID_COLLECTION ( HID_COLLECTION_APPLICATION )        ,\
+  HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP     )                 ,\
+  HID_USAGE      ( HID_USAGE_DESKTOP_GAMEPAD  )                 ,\
+  HID_COLLECTION ( HID_COLLECTION_APPLICATION )                 ,\
     /* Report ID if any */\
     __VA_ARGS__ \
+    /* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ \
+    HID_USAGE_PAGE   ( HID_USAGE_PAGE_DESKTOP                 ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_X                    ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_Y                    ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_Z                    ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_RZ                   ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_RX                   ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_RY                   ) ,\
+    HID_LOGICAL_MIN  ( 0x81                                   ) ,\
+    HID_LOGICAL_MAX  ( 0x7f                                   ) ,\
+    HID_REPORT_COUNT ( 6                                      ) ,\
+    HID_REPORT_SIZE  ( 8                                      ) ,\
+    HID_INPUT        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
+    /* 8 bit DPad/Hat Button Map  */ \
+    HID_USAGE_PAGE   ( HID_USAGE_PAGE_DESKTOP                 ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_HAT_SWITCH           ) ,\
+    HID_LOGICAL_MIN  ( 1                                      ) ,\
+    HID_LOGICAL_MAX  ( 8                                      ) ,\
+    HID_PHYSICAL_MIN ( 0                                      ) ,\
+    HID_PHYSICAL_MAX_N ( 315, 2                               ) ,\
+    HID_REPORT_COUNT ( 1                                      ) ,\
+    HID_REPORT_SIZE  ( 8                                      ) ,\
+    HID_INPUT        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
     /* 16 bit Button Map */ \
     HID_USAGE_PAGE   ( HID_USAGE_PAGE_BUTTON                  ) ,\
     HID_USAGE_MIN    ( 1                                      ) ,\
@@ -318,17 +347,6 @@ static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8
     HID_REPORT_COUNT ( 16                                     ) ,\
     HID_REPORT_SIZE  ( 1                                      ) ,\
     HID_INPUT        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
-    /* X, Y, Z, Rz (min -127, max 127 ) */ \
-    HID_USAGE_PAGE   ( HID_USAGE_PAGE_DESKTOP                 ) ,\
-    HID_LOGICAL_MIN  ( 0x81                                   ) ,\
-    HID_LOGICAL_MAX  ( 0x7f                                   ) ,\
-    HID_USAGE        ( HID_USAGE_DESKTOP_X                    ) ,\
-    HID_USAGE        ( HID_USAGE_DESKTOP_Y                    ) ,\
-    HID_USAGE        ( HID_USAGE_DESKTOP_Z                    ) ,\
-    HID_USAGE        ( HID_USAGE_DESKTOP_RZ                   ) ,\
-    HID_REPORT_COUNT ( 4                                      ) ,\
-    HID_REPORT_SIZE  ( 8                                      ) ,\
-    HID_INPUT        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
   HID_COLLECTION_END \
 
 // HID Generic Input & Output