class_driver.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Unlicense OR CC0-1.0
  5. */
  6. #include <stdlib.h>
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/semphr.h"
  9. #include "esp_log.h"
  10. #include "usb/usb_host.h"
  11. #define CLIENT_NUM_EVENT_MSG 5
  12. typedef enum {
  13. ACTION_OPEN_DEV = 0x01,
  14. ACTION_GET_DEV_INFO = 0x02,
  15. ACTION_GET_DEV_DESC = 0x04,
  16. ACTION_GET_CONFIG_DESC = 0x08,
  17. ACTION_GET_STR_DESC = 0x10,
  18. ACTION_CLOSE_DEV = 0x20,
  19. ACTION_EXIT = 0x40,
  20. ACTION_RECONNECT = 0x80,
  21. } action_t;
  22. typedef struct {
  23. usb_host_client_handle_t client_hdl;
  24. uint8_t dev_addr;
  25. usb_device_handle_t dev_hdl;
  26. uint32_t actions;
  27. } class_driver_t;
  28. static const char *TAG = "CLASS";
  29. static class_driver_t *s_driver_obj;
  30. static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg)
  31. {
  32. class_driver_t *driver_obj = (class_driver_t *)arg;
  33. switch (event_msg->event) {
  34. case USB_HOST_CLIENT_EVENT_NEW_DEV:
  35. if (driver_obj->dev_addr == 0) {
  36. driver_obj->dev_addr = event_msg->new_dev.address;
  37. //Open the device next
  38. driver_obj->actions |= ACTION_OPEN_DEV;
  39. }
  40. break;
  41. case USB_HOST_CLIENT_EVENT_DEV_GONE:
  42. if (driver_obj->dev_hdl != NULL) {
  43. //Cancel any other actions and close the device next
  44. driver_obj->actions = ACTION_CLOSE_DEV;
  45. }
  46. break;
  47. default:
  48. //Should never occur
  49. abort();
  50. }
  51. }
  52. static void action_open_dev(class_driver_t *driver_obj)
  53. {
  54. assert(driver_obj->dev_addr != 0);
  55. ESP_LOGI(TAG, "Opening device at address %d", driver_obj->dev_addr);
  56. ESP_ERROR_CHECK(usb_host_device_open(driver_obj->client_hdl, driver_obj->dev_addr, &driver_obj->dev_hdl));
  57. //Get the device's information next
  58. driver_obj->actions &= ~ACTION_OPEN_DEV;
  59. driver_obj->actions |= ACTION_GET_DEV_INFO;
  60. }
  61. static void action_get_info(class_driver_t *driver_obj)
  62. {
  63. assert(driver_obj->dev_hdl != NULL);
  64. ESP_LOGI(TAG, "Getting device information");
  65. usb_device_info_t dev_info;
  66. ESP_ERROR_CHECK(usb_host_device_info(driver_obj->dev_hdl, &dev_info));
  67. ESP_LOGI(TAG, "\t%s speed", (dev_info.speed == USB_SPEED_LOW) ? "Low" : "Full");
  68. ESP_LOGI(TAG, "\tbConfigurationValue %d", dev_info.bConfigurationValue);
  69. //Todo: Print string descriptors
  70. //Get the device descriptor next
  71. driver_obj->actions &= ~ACTION_GET_DEV_INFO;
  72. driver_obj->actions |= ACTION_GET_DEV_DESC;
  73. }
  74. static void action_get_dev_desc(class_driver_t *driver_obj)
  75. {
  76. assert(driver_obj->dev_hdl != NULL);
  77. ESP_LOGI(TAG, "Getting device descriptor");
  78. const usb_device_desc_t *dev_desc;
  79. ESP_ERROR_CHECK(usb_host_get_device_descriptor(driver_obj->dev_hdl, &dev_desc));
  80. usb_print_device_descriptor(dev_desc);
  81. //Get the device's config descriptor next
  82. driver_obj->actions &= ~ACTION_GET_DEV_DESC;
  83. driver_obj->actions |= ACTION_GET_CONFIG_DESC;
  84. }
  85. static void action_get_config_desc(class_driver_t *driver_obj)
  86. {
  87. assert(driver_obj->dev_hdl != NULL);
  88. ESP_LOGI(TAG, "Getting config descriptor");
  89. const usb_config_desc_t *config_desc;
  90. ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(driver_obj->dev_hdl, &config_desc));
  91. usb_print_config_descriptor(config_desc, NULL);
  92. //Get the device's string descriptors next
  93. driver_obj->actions &= ~ACTION_GET_CONFIG_DESC;
  94. driver_obj->actions |= ACTION_GET_STR_DESC;
  95. }
  96. static void action_get_str_desc(class_driver_t *driver_obj)
  97. {
  98. assert(driver_obj->dev_hdl != NULL);
  99. usb_device_info_t dev_info;
  100. ESP_ERROR_CHECK(usb_host_device_info(driver_obj->dev_hdl, &dev_info));
  101. if (dev_info.str_desc_manufacturer) {
  102. ESP_LOGI(TAG, "Getting Manufacturer string descriptor");
  103. usb_print_string_descriptor(dev_info.str_desc_manufacturer);
  104. }
  105. if (dev_info.str_desc_product) {
  106. ESP_LOGI(TAG, "Getting Product string descriptor");
  107. usb_print_string_descriptor(dev_info.str_desc_product);
  108. }
  109. if (dev_info.str_desc_serial_num) {
  110. ESP_LOGI(TAG, "Getting Serial Number string descriptor");
  111. usb_print_string_descriptor(dev_info.str_desc_serial_num);
  112. }
  113. //Nothing to do until the device disconnects
  114. driver_obj->actions &= ~ACTION_GET_STR_DESC;
  115. }
  116. static void action_close_dev(class_driver_t *driver_obj)
  117. {
  118. ESP_ERROR_CHECK(usb_host_device_close(driver_obj->client_hdl, driver_obj->dev_hdl));
  119. driver_obj->dev_hdl = NULL;
  120. driver_obj->dev_addr = 0;
  121. //We need to connect a new device
  122. driver_obj->actions &= ~ACTION_CLOSE_DEV;
  123. driver_obj->actions |= ACTION_RECONNECT;
  124. }
  125. void class_driver_task(void *arg)
  126. {
  127. class_driver_t driver_obj = {0};
  128. ESP_LOGI(TAG, "Registering Client");
  129. usb_host_client_config_t client_config = {
  130. .is_synchronous = false, //Synchronous clients currently not supported. Set this to false
  131. .max_num_event_msg = CLIENT_NUM_EVENT_MSG,
  132. .async = {
  133. .client_event_callback = client_event_cb,
  134. .callback_arg = (void *) &driver_obj,
  135. },
  136. };
  137. ESP_ERROR_CHECK(usb_host_client_register(&client_config, &driver_obj.client_hdl));
  138. s_driver_obj = &driver_obj;
  139. while (1) {
  140. if (driver_obj.actions == 0) {
  141. usb_host_client_handle_events(driver_obj.client_hdl, portMAX_DELAY);
  142. } else {
  143. if (driver_obj.actions & ACTION_OPEN_DEV) {
  144. action_open_dev(&driver_obj);
  145. }
  146. if (driver_obj.actions & ACTION_GET_DEV_INFO) {
  147. action_get_info(&driver_obj);
  148. }
  149. if (driver_obj.actions & ACTION_GET_DEV_DESC) {
  150. action_get_dev_desc(&driver_obj);
  151. }
  152. if (driver_obj.actions & ACTION_GET_CONFIG_DESC) {
  153. action_get_config_desc(&driver_obj);
  154. }
  155. if (driver_obj.actions & ACTION_GET_STR_DESC) {
  156. action_get_str_desc(&driver_obj);
  157. }
  158. if (driver_obj.actions & ACTION_CLOSE_DEV) {
  159. action_close_dev(&driver_obj);
  160. }
  161. if (driver_obj.actions & ACTION_EXIT) {
  162. break;
  163. }
  164. if (driver_obj.actions & ACTION_RECONNECT) {
  165. driver_obj.actions = 0;
  166. }
  167. }
  168. }
  169. ESP_LOGI(TAG, "Deregistering Client");
  170. ESP_ERROR_CHECK(usb_host_client_deregister(driver_obj.client_hdl));
  171. vTaskSuspend(NULL);
  172. }
  173. void class_driver_client_deregister(void)
  174. {
  175. if (s_driver_obj->dev_hdl != NULL) {
  176. s_driver_obj->actions = ACTION_CLOSE_DEV;
  177. }
  178. s_driver_obj->actions |= ACTION_EXIT;
  179. // Unblock, exit the loop and proceed to deregister client
  180. ESP_ERROR_CHECK(usb_host_client_unblock(s_driver_obj->client_hdl));
  181. }