Просмотр исходного кода

fix SET_PROTOCOl, update hid host behavior for default boot interface

hathach 4 лет назад
Родитель
Сommit
efc12ae7d4
2 измененных файлов с 108 добавлено и 70 удалено
  1. 100 66
      examples/host/cdc_msc_hid/src/hid_app.c
  2. 8 4
      src/class/hid/hid_host.c

+ 100 - 66
examples/host/cdc_msc_hid/src/hid_app.c

@@ -39,11 +39,15 @@
 static uint8_t const keycode2ascii[128][2] =  { HID_KEYCODE_TO_ASCII };
 
 // Each HID instance can has multiple reports
-static uint8_t _report_count[CFG_TUH_HID];
-static tuh_hid_report_info_t _report_info_arr[CFG_TUH_HID][MAX_REPORT];
+static struct
+{
+  uint8_t report_count;
+  tuh_hid_report_info_t report_info[MAX_REPORT];
+}hid_info[CFG_TUH_HID];
 
 static void process_kbd_report(hid_keyboard_report_t const *report);
 static void process_mouse_report(hid_mouse_report_t const * report);
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
 
 void hid_app_task(void)
 {
@@ -61,13 +65,19 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
 {
   printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
 
-  // Interface protocol
-  const char* protocol_str[] = { "None", "Keyboard", "Mouse" }; // hid_protocol_type_t
-  uint8_t const interface_protocol = tuh_hid_interface_protocol(dev_addr, instance);
+  // Interface protocol (hid_interface_protocol_enum_t)
+  const char* protocol_str[] = { "None", "Keyboard", "Mouse" };
+  uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
+
+  printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]);
 
-  // Parse report descriptor with built-in parser
-  _report_count[instance] = tuh_hid_parse_report_descriptor(_report_info_arr[instance], MAX_REPORT, desc_report, desc_len);
-  printf("HID has %u reports and interface protocol = %s\r\n", _report_count[instance], protocol_str[interface_protocol]);
+  // By default host stack will use activate boot protocol on supported interface.
+  // Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
+  if ( itf_protocol == HID_ITF_PROTOCOL_NONE )
+  {
+    hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
+    printf("HID has %u reports \r\n", hid_info[instance].report_count);
+  }
 }
 
 // Invoked when device with hid interface is un-mounted
@@ -79,66 +89,24 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
 // Invoked when received report from device via interrupt endpoint
 void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
 {
-  (void) dev_addr;
+  uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
 
-  uint8_t const rpt_count = _report_count[instance];
-  tuh_hid_report_info_t* rpt_info_arr = _report_info_arr[instance];
-  tuh_hid_report_info_t* rpt_info = NULL;
-
-  if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0)
-  {
-    // Simple report without report ID as 1st byte
-    rpt_info = &rpt_info_arr[0];
-  }else
+  switch (itf_protocol)
   {
-    // Composite report, 1st byte is report ID, data starts from 2nd byte
-    uint8_t const rpt_id = report[0];
-
-    // Find report id in the arrray
-    for(uint8_t i=0; i<rpt_count; i++)
-    {
-      if (rpt_id == rpt_info_arr[i].report_id )
-      {
-        rpt_info = &rpt_info_arr[i];
-        break;
-      }
-    }
-
-    report++;
-    len--;
-  }
-
-  if (!rpt_info)
-  {
-    printf("Couldn't find the report info for this report !\r\n");
-    return;
-  }
-
-  // For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples:
-  // - Keyboard                     : Desktop, Keyboard
-  // - Mouse                        : Desktop, Mouse
-  // - Gamepad                      : Desktop, Gamepad
-  // - Consumer Control (Media Key) : Consumer, Consumer Control
-  // - System Control (Power key)   : Desktop, System Control
-  // - Generic (vendor)             : 0xFFxx, xx
-  if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP )
-  {
-    switch (rpt_info->usage)
-    {
-      case HID_USAGE_DESKTOP_KEYBOARD:
-        TU_LOG1("HID receive keyboard report\r\n");
-        // Assume keyboard follow boot report layout
-        process_kbd_report( (hid_keyboard_report_t const*) report );
-      break;
-
-      case HID_USAGE_DESKTOP_MOUSE:
-        TU_LOG1("HID receive mouse report\r\n");
-        // Assume mouse follow boot report layout
-        process_mouse_report( (hid_mouse_report_t const*) report );
-      break;
-
-      default: break;
-    }
+    case HID_ITF_PROTOCOL_KEYBOARD:
+      TU_LOG2("HID receive boot keyboard report\r\n");
+      process_kbd_report( (hid_keyboard_report_t const*) report );
+    break;
+
+    case HID_ITF_PROTOCOL_MOUSE:
+      TU_LOG2("HID receive boot mouse report\r\n");
+      process_mouse_report( (hid_mouse_report_t const*) report );
+    break;
+
+    default:
+      // Generic report requires matching ReportID and contents with previous parsed report info
+      process_generic_report(dev_addr, instance, report, len);
+    break;
   }
 }
 
@@ -243,3 +211,69 @@ static void process_mouse_report(hid_mouse_report_t const * report)
   //------------- cursor movement -------------//
   cursor_movement(report->x, report->y, report->wheel);
 }
+
+//--------------------------------------------------------------------+
+// Generic Report
+//--------------------------------------------------------------------+
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
+{
+  uint8_t const rpt_count = hid_info[instance].report_count;
+  tuh_hid_report_info_t* rpt_info_arr = hid_info[instance].report_info;
+  tuh_hid_report_info_t* rpt_info = NULL;
+
+  if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0)
+  {
+    // Simple report without report ID as 1st byte
+    rpt_info = &rpt_info_arr[0];
+  }else
+  {
+    // Composite report, 1st byte is report ID, data starts from 2nd byte
+    uint8_t const rpt_id = report[0];
+
+    // Find report id in the arrray
+    for(uint8_t i=0; i<rpt_count; i++)
+    {
+      if (rpt_id == rpt_info_arr[i].report_id )
+      {
+        rpt_info = &rpt_info_arr[i];
+        break;
+      }
+    }
+
+    report++;
+    len--;
+  }
+
+  if (!rpt_info)
+  {
+    printf("Couldn't find the report info for this report !\r\n");
+    return;
+  }
+
+  // For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples:
+  // - Keyboard                     : Desktop, Keyboard
+  // - Mouse                        : Desktop, Mouse
+  // - Gamepad                      : Desktop, Gamepad
+  // - Consumer Control (Media Key) : Consumer, Consumer Control
+  // - System Control (Power key)   : Desktop, System Control
+  // - Generic (vendor)             : 0xFFxx, xx
+  if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP )
+  {
+    switch (rpt_info->usage)
+    {
+      case HID_USAGE_DESKTOP_KEYBOARD:
+        TU_LOG1("HID receive keyboard report\r\n");
+        // Assume keyboard follow boot report layout
+        process_kbd_report( (hid_keyboard_report_t const*) report );
+      break;
+
+      case HID_USAGE_DESKTOP_MOUSE:
+        TU_LOG1("HID receive mouse report\r\n");
+        // Assume mouse follow boot report layout
+        process_mouse_report( (hid_mouse_report_t const*) report );
+      break;
+
+      default: break;
+    }
+  }
+}

+ 8 - 4
src/class/hid/hid_host.c

@@ -327,7 +327,7 @@ bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
 // Force device to work in BOOT protocol
 static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
 {
-  // Stall is a valid response for SET_PROTOCOL, therefore we could ignore its result
+  // Stall is a valid response for SET_IDLE, therefore we could ignore its result
   (void) result;
 
   uint8_t const itf_num     = (uint8_t) request->wIndex;
@@ -347,7 +347,7 @@ static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const *
     .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
     .wValue   = HID_PROTOCOL_BOOT,
     .wIndex   = hid_itf->itf_num,
-    .wLength  = 1
+    .wLength  = 0
   };
 
   TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_get_report_desc) );
@@ -356,8 +356,12 @@ static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const *
 
 static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
 {
-  // Stall is a valid response for SET_IDLE, therefore we could ignore its result
-  (void) result;
+  // We can be here after SET_IDLE or SET_PROTOCOL (boot device)
+  // Trigger assert if result is not successful with set protocol
+  if ( request->bRequest != HID_REQ_CONTROL_SET_IDLE )
+  {
+    TU_ASSERT(result == XFER_RESULT_SUCCESS);
+  }
 
   uint8_t const itf_num     = (uint8_t) request->wIndex;
   uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);