main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2019 Ha Thach (tinyusb.org)
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. *
  24. */
  25. /* This example current worked and tested with following controller
  26. * - Sony DualShock 4 [CUH-ZCT2x] VID = 0x054c, PID = 0x09cc
  27. */
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include "bsp/board.h"
  32. #include "tusb.h"
  33. // English
  34. #define LANGUAGE_ID 0x0409
  35. //--------------------------------------------------------------------+
  36. // MACRO CONSTANT TYPEDEF PROTYPES
  37. //--------------------------------------------------------------------+
  38. void led_blinking_task(void);
  39. static void print_utf16(uint16_t *temp_buf, size_t buf_len);
  40. void print_device_descriptor(tuh_xfer_t* xfer);
  41. void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
  42. tusb_desc_device_t desc_device;
  43. /*------------- MAIN -------------*/
  44. int main(void)
  45. {
  46. board_init();
  47. printf("TinyUSB Host HID Controller Example\r\n");
  48. tusb_init();
  49. while (1)
  50. {
  51. // tinyusb host task
  52. tuh_task();
  53. led_blinking_task();
  54. }
  55. return 0;
  56. }
  57. /*------------- TinyUSB Callbacks -------------*/
  58. // Invoked when device is mounted (configured)
  59. void tuh_mount_cb (uint8_t daddr)
  60. {
  61. printf("Device attached, address = %d\r\n", daddr);
  62. // Get Device Descriptor sync API
  63. // TODO: invoking control trannsfer now has issue with mounting hub with multiple devices attached, fix later
  64. tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
  65. }
  66. /// Invoked when device is unmounted (bus reset/unplugged)
  67. void tuh_umount_cb(uint8_t daddr)
  68. {
  69. printf("Device removed, address = %d\r\n", daddr);
  70. }
  71. //--------------------------------------------------------------------+
  72. // Device Descriptor
  73. //--------------------------------------------------------------------+
  74. void print_device_descriptor(tuh_xfer_t* xfer)
  75. {
  76. if ( XFER_RESULT_SUCCESS != xfer->result )
  77. {
  78. printf("Failed to get device descriptor\r\n");
  79. return;
  80. }
  81. uint8_t const daddr = xfer->daddr;
  82. printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct);
  83. printf("Device Descriptor:\r\n");
  84. printf(" bLength %u\r\n" , desc_device.bLength);
  85. printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType);
  86. printf(" bcdUSB %04x\r\n" , desc_device.bcdUSB);
  87. printf(" bDeviceClass %u\r\n" , desc_device.bDeviceClass);
  88. printf(" bDeviceSubClass %u\r\n" , desc_device.bDeviceSubClass);
  89. printf(" bDeviceProtocol %u\r\n" , desc_device.bDeviceProtocol);
  90. printf(" bMaxPacketSize0 %u\r\n" , desc_device.bMaxPacketSize0);
  91. printf(" idVendor 0x%04x\r\n" , desc_device.idVendor);
  92. printf(" idProduct 0x%04x\r\n" , desc_device.idProduct);
  93. printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice);
  94. // Get String descriptor using Sync API
  95. uint16_t temp_buf[128];
  96. printf(" iManufacturer %u " , desc_device.iManufacturer);
  97. if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)) )
  98. {
  99. print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
  100. }
  101. printf("\r\n");
  102. printf(" iProduct %u " , desc_device.iProduct);
  103. if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
  104. {
  105. print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
  106. }
  107. printf("\r\n");
  108. printf(" iSerialNumber %u " , desc_device.iSerialNumber);
  109. if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
  110. {
  111. print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
  112. }
  113. printf("\r\n");
  114. printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations);
  115. // Get configuration descriptor with sync API
  116. if (XFER_RESULT_SUCCESS == tuh_descriptor_get_configuration_sync(daddr, 0, temp_buf, sizeof(temp_buf)) )
  117. {
  118. parse_config_descriptor(daddr, (tusb_desc_configuration_t*) temp_buf);
  119. }
  120. }
  121. //--------------------------------------------------------------------+
  122. // Configuration Descriptor
  123. //--------------------------------------------------------------------+
  124. // count total length of an interface
  125. uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
  126. void open_hid_interface(uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
  127. {
  128. // len = interface + hid + n*endpoints
  129. uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
  130. // corrupted descriptor
  131. if (max_len < drv_len) return;
  132. uint8_t const *p_desc = (uint8_t const *) desc_itf;
  133. // HID descriptor
  134. p_desc = tu_desc_next(p_desc);
  135. // Endpoint descriptor
  136. tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
  137. for(int i = 0; i < desc_itf->bNumEndpoints; i++)
  138. {
  139. if (TUSB_DESC_ENDPOINT != desc_ep->bDescriptorType) return;
  140. if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
  141. {
  142. //usbh_edpt_open(rhport, dev_addr, desc_ep);
  143. }
  144. }
  145. }
  146. // simple configuration parser to open and listen to HID Endpoint IN
  147. void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
  148. {
  149. uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
  150. uint8_t const* p_desc = tu_desc_next(desc_cfg);
  151. // parse each interfaces
  152. while( p_desc < desc_end )
  153. {
  154. uint8_t assoc_itf_count = 1;
  155. // Class will always starts with Interface Association (if any) and then Interface descriptor
  156. if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
  157. {
  158. tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
  159. assoc_itf_count = desc_iad->bInterfaceCount;
  160. p_desc = tu_desc_next(p_desc); // next to Interface
  161. }
  162. // must be interface from now
  163. if( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) return;
  164. tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
  165. uint16_t const drv_len = count_interface_total_len(desc_itf, assoc_itf_count, desc_end-p_desc);
  166. // probably corrupted descriptor
  167. if(drv_len < sizeof(tusb_desc_interface_t)) return;
  168. // only open and listen to HID endpoint IN
  169. if (desc_itf->bInterfaceClass == TUSB_CLASS_HID)
  170. {
  171. open_hid_interface(dev_addr, desc_itf, drv_len);
  172. }
  173. // next Interface or IAD descriptor
  174. p_desc += drv_len;
  175. }
  176. }
  177. uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len)
  178. {
  179. uint8_t const* p_desc = (uint8_t const*) desc_itf;
  180. uint16_t len = 0;
  181. while (itf_count--)
  182. {
  183. // Next on interface desc
  184. len += tu_desc_len(desc_itf);
  185. p_desc = tu_desc_next(p_desc);
  186. while (len < max_len)
  187. {
  188. // return on IAD regardless of itf count
  189. if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len;
  190. if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
  191. ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 )
  192. {
  193. break;
  194. }
  195. len += tu_desc_len(p_desc);
  196. p_desc = tu_desc_next(p_desc);
  197. }
  198. }
  199. return len;
  200. }
  201. //--------------------------------------------------------------------+
  202. // Blinking Task
  203. //--------------------------------------------------------------------+
  204. void led_blinking_task(void)
  205. {
  206. const uint32_t interval_ms = 1000;
  207. static uint32_t start_ms = 0;
  208. static bool led_state = false;
  209. // Blink every interval ms
  210. if ( board_millis() - start_ms < interval_ms) return; // not enough time
  211. start_ms += interval_ms;
  212. board_led_write(led_state);
  213. led_state = 1 - led_state; // toggle
  214. }
  215. //--------------------------------------------------------------------+
  216. // Helper
  217. //--------------------------------------------------------------------+
  218. static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
  219. // TODO: Check for runover.
  220. (void)utf8_len;
  221. // Get the UTF-16 length out of the data itself.
  222. for (size_t i = 0; i < utf16_len; i++) {
  223. uint16_t chr = utf16[i];
  224. if (chr < 0x80) {
  225. *utf8++ = chr & 0xff;
  226. } else if (chr < 0x800) {
  227. *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
  228. *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
  229. } else {
  230. // TODO: Verify surrogate.
  231. *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
  232. *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
  233. *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
  234. }
  235. // TODO: Handle UTF-16 code points that take two entries.
  236. }
  237. }
  238. // Count how many bytes a utf-16-le encoded string will take in utf-8.
  239. static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
  240. size_t total_bytes = 0;
  241. for (size_t i = 0; i < len; i++) {
  242. uint16_t chr = buf[i];
  243. if (chr < 0x80) {
  244. total_bytes += 1;
  245. } else if (chr < 0x800) {
  246. total_bytes += 2;
  247. } else {
  248. total_bytes += 3;
  249. }
  250. // TODO: Handle UTF-16 code points that take two entries.
  251. }
  252. return total_bytes;
  253. }
  254. static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
  255. size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
  256. size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
  257. _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
  258. ((uint8_t*) temp_buf)[utf8_len] = '\0';
  259. printf((char*)temp_buf);
  260. }