tud_hid_report_complete_cb() API
update hid composite to make use of tud_hid_report_complete_cb() for sending reports when possible.
This commit is contained in:
		| @@ -1,5 +1,11 @@ | |||||||
| # TinyUSB Changelog | # TinyUSB Changelog | ||||||
|  |  | ||||||
|  | ## WIP | ||||||
|  |  | ||||||
|  | - Fix dropping MIDI sysex message when fifo is full | ||||||
|  | - Add DPad/Hat support for HID Gamepad | ||||||
|  | - Add tud_hid_report_complete_cb() API | ||||||
|  |  | ||||||
| ## 0.8.0 - 2021.02.05 | ## 0.8.0 - 2021.02.05 | ||||||
|  |  | ||||||
| ### Device Controller Driver | ### Device Controller Driver | ||||||
|   | |||||||
| @@ -104,6 +104,98 @@ void tud_resume_cb(void) | |||||||
| // USB HID | // USB HID | ||||||
| //--------------------------------------------------------------------+ | //--------------------------------------------------------------------+ | ||||||
|  |  | ||||||
|  | static void send_hid_report(uint8_t report_id, uint32_t btn) | ||||||
|  | { | ||||||
|  |   // skip if hid is not ready yet | ||||||
|  |   if ( !tud_hid_ready() ) return; | ||||||
|  |  | ||||||
|  |   switch(report_id) | ||||||
|  |   { | ||||||
|  |     case REPORT_ID_KEYBOARD: | ||||||
|  |     { | ||||||
|  |       // use to avoid send multiple consecutive zero report for keyboard | ||||||
|  |       static bool has_keyboard_key = false; | ||||||
|  |  | ||||||
|  |       if ( btn ) | ||||||
|  |       { | ||||||
|  |         uint8_t keycode[6] = { 0 }; | ||||||
|  |         keycode[0] = HID_KEY_A; | ||||||
|  |  | ||||||
|  |         tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode); | ||||||
|  |         has_keyboard_key = true; | ||||||
|  |       }else | ||||||
|  |       { | ||||||
|  |         // send empty key report if previously has key pressed | ||||||
|  |         if (has_keyboard_key) tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); | ||||||
|  |         has_keyboard_key = false; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     break; | ||||||
|  |  | ||||||
|  |     case REPORT_ID_MOUSE: | ||||||
|  |     { | ||||||
|  |       int8_t const delta = 5; | ||||||
|  |  | ||||||
|  |       // no button, right + down, no scroll, no pan | ||||||
|  |       tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0); | ||||||
|  |     } | ||||||
|  |     break; | ||||||
|  |  | ||||||
|  |     case REPORT_ID_CONSUMER_CONTROL: | ||||||
|  |     { | ||||||
|  |       // use to avoid send multiple consecutive zero report | ||||||
|  |       static bool has_consumer_key = false; | ||||||
|  |  | ||||||
|  |       if ( btn ) | ||||||
|  |       { | ||||||
|  |         // volume down | ||||||
|  |         uint16_t volume_down = HID_USAGE_CONSUMER_VOLUME_DECREMENT; | ||||||
|  |         tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &volume_down, 2); | ||||||
|  |         has_consumer_key = true; | ||||||
|  |       }else | ||||||
|  |       { | ||||||
|  |         // send empty key report (release key) if previously has key pressed | ||||||
|  |         uint16_t empty_key = 0; | ||||||
|  |         if (has_consumer_key) tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &empty_key, 2); | ||||||
|  |         has_consumer_key = false; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     break; | ||||||
|  |  | ||||||
|  |     case REPORT_ID_GAMEPAD: | ||||||
|  |     { | ||||||
|  |       // 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; | ||||||
|  |         report.buttons = GAMEPAD_BUTTON_A; | ||||||
|  |         tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report)); | ||||||
|  |  | ||||||
|  |         has_gamepad_key = true; | ||||||
|  |       }else | ||||||
|  |       { | ||||||
|  |         report.hat = GAMEPAD_HAT_CENTERED; | ||||||
|  |         report.buttons = 0; | ||||||
|  |         if (has_gamepad_key) tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report)); | ||||||
|  |         has_gamepad_key = false; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     break; | ||||||
|  |  | ||||||
|  |     default: break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..) | ||||||
|  | // tud_hid_report_complete_cb() is used to send the next report after previous one is complete | ||||||
| void hid_task(void) | void hid_task(void) | ||||||
| { | { | ||||||
|   // Poll every 10ms |   // Poll every 10ms | ||||||
| @@ -121,97 +213,26 @@ void hid_task(void) | |||||||
|     // Wake up host if we are in suspend mode |     // Wake up host if we are in suspend mode | ||||||
|     // and REMOTE_WAKEUP feature is enabled by host |     // and REMOTE_WAKEUP feature is enabled by host | ||||||
|     tud_remote_wakeup(); |     tud_remote_wakeup(); | ||||||
|   } |   }else | ||||||
|  |  | ||||||
|   /*------------- Mouse -------------*/ |  | ||||||
|   if ( tud_hid_ready() ) |  | ||||||
|   { |   { | ||||||
|     if ( btn ) |     // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() | ||||||
|     { |     send_hid_report(REPORT_ID_KEYBOARD, btn); | ||||||
|       int8_t const delta = 5; |  | ||||||
|  |  | ||||||
|       // no button, right + down, no scroll pan |  | ||||||
|       tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0); |  | ||||||
|  |  | ||||||
|       // delay a bit before sending keyboard report |  | ||||||
|       board_delay(10); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|   /*------------- Keyboard -------------*/ | // Invoked when sent REPORT successfully to host | ||||||
|   if ( tud_hid_ready() ) | // Application can use this to send the next report | ||||||
|  | // Note: For composite reports, report[0] is report ID | ||||||
|  | void tud_hid_report_complete_cb(uint8_t itf, uint8_t const* report, uint8_t len) | ||||||
|  | { | ||||||
|  |   (void) itf; | ||||||
|  |   (void) len; | ||||||
|  |  | ||||||
|  |   uint8_t next_report_id = report[0] + 1; | ||||||
|  |  | ||||||
|  |   if (next_report_id < REPORT_ID_COUNT) | ||||||
|   { |   { | ||||||
|     // use to avoid send multiple consecutive zero report for keyboard |     send_hid_report(next_report_id, board_button_read()); | ||||||
|     static bool has_key = false; |  | ||||||
|  |  | ||||||
|     if ( btn ) |  | ||||||
|     { |  | ||||||
|       uint8_t keycode[6] = { 0 }; |  | ||||||
|       keycode[0] = HID_KEY_A; |  | ||||||
|  |  | ||||||
|       tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode); |  | ||||||
|  |  | ||||||
|       has_key = true; |  | ||||||
|     }else |  | ||||||
|     { |  | ||||||
|       // send empty key report if previously has key pressed |  | ||||||
|       if (has_key) tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); |  | ||||||
|       has_key = false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // delay a bit before sending consumer report |  | ||||||
|     board_delay(10); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /*------------- Consume Control -------------*/ |  | ||||||
|   if ( tud_hid_ready() ) |  | ||||||
|   { |  | ||||||
|     // use to avoid send multiple consecutive zero report |  | ||||||
|     static bool has_consumer_key = false; |  | ||||||
|  |  | ||||||
|     if ( btn ) |  | ||||||
|     { |  | ||||||
|       // volume down |  | ||||||
|       uint16_t volume_down = HID_USAGE_CONSUMER_VOLUME_DECREMENT; |  | ||||||
|       tud_hid_report(REPORT_ID_CONSUMER_CONTROL, &volume_down, 2); |  | ||||||
|  |  | ||||||
|       has_consumer_key = true; |  | ||||||
|     }else |  | ||||||
|     { |  | ||||||
|       // send empty key report (release key) if previously has key pressed |  | ||||||
|       uint16_t empty_key = 0; |  | ||||||
|       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; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -107,7 +107,7 @@ uint8_t const desc_configuration[] = | |||||||
|   TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), |   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 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) |   TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 2) | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Invoked when received GET CONFIGURATION DESCRIPTOR | // Invoked when received GET CONFIGURATION DESCRIPTOR | ||||||
|   | |||||||
| @@ -30,7 +30,8 @@ enum | |||||||
|   REPORT_ID_KEYBOARD = 1, |   REPORT_ID_KEYBOARD = 1, | ||||||
|   REPORT_ID_MOUSE, |   REPORT_ID_MOUSE, | ||||||
|   REPORT_ID_CONSUMER_CONTROL, |   REPORT_ID_CONSUMER_CONTROL, | ||||||
|   REPORT_ID_GAMEPAD |   REPORT_ID_GAMEPAD, | ||||||
|  |   REPORT_ID_COUNT | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif /* USB_DESCRIPTORS_H_ */ | #endif /* USB_DESCRIPTORS_H_ */ | ||||||
|   | |||||||
| @@ -381,14 +381,24 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ | |||||||
|   uint8_t itf = 0; |   uint8_t itf = 0; | ||||||
|   hidd_interface_t * p_hid = _hidd_itf; |   hidd_interface_t * p_hid = _hidd_itf; | ||||||
|  |  | ||||||
|   for ( ; ; itf++, p_hid++) |   // Identify which interface to use | ||||||
|  |   for (itf = 0; itf < CFG_TUD_HID; itf++) | ||||||
|   { |   { | ||||||
|     if (itf >= TU_ARRAY_SIZE(_hidd_itf)) return false; |     p_hid = &_hidd_itf[itf]; | ||||||
|  |     if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break; | ||||||
|     if ( ep_addr == p_hid->ep_out ) break; |  | ||||||
|   } |   } | ||||||
|  |   TU_ASSERT(itf < CFG_TUD_HID); | ||||||
|  |  | ||||||
|   if (ep_addr == p_hid->ep_out) |   // Sent report successfully | ||||||
|  |   if (ep_addr == p_hid->ep_in) | ||||||
|  |   { | ||||||
|  |     if (tud_hid_report_complete_cb) | ||||||
|  |     { | ||||||
|  |       tud_hid_report_complete_cb(itf, p_hid->epin_buf, (uint8_t) xferred_bytes); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   // Received report | ||||||
|  |   else if (ep_addr == p_hid->ep_out) | ||||||
|   { |   { | ||||||
|     tud_hid_set_report_cb( |     tud_hid_set_report_cb( | ||||||
|         #if CFG_TUD_HID > 1 |         #if CFG_TUD_HID > 1 | ||||||
|   | |||||||
| @@ -123,7 +123,10 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t idle_rate); | |||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t itf, ); | // Invoked when sent REPORT successfully to host | ||||||
|  | // Application can use this to send the next report | ||||||
|  | // Note: For composite reports, report[0] is report ID | ||||||
|  | TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t itf, uint8_t const* report, uint8_t len); | ||||||
|  |  | ||||||
|  |  | ||||||
| //--------------------------------------------------------------------+ | //--------------------------------------------------------------------+ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 hathach
					hathach