test_hcd_common.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include "freertos/FreeRTOS.h"
  9. #include "freertos/semphr.h"
  10. #include "test_utils.h"
  11. #include "soc/usb_wrap_struct.h"
  12. #include "esp_intr_alloc.h"
  13. #include "esp_err.h"
  14. #include "esp_attr.h"
  15. #include "esp_rom_gpio.h"
  16. #include "hcd.h"
  17. #include "usb_private.h"
  18. #include "usb/usb_types_ch9.h"
  19. #include "test_hcd_common.h"
  20. #include "test_usb_common.h"
  21. #define PORT_NUM 1
  22. #define EVENT_QUEUE_LEN 5
  23. #define ENUM_ADDR 1 //Device address to use for tests that enumerate the device
  24. #define ENUM_CONFIG 1 //Device configuration number to use for tests that enumerate the device
  25. typedef struct {
  26. hcd_port_handle_t port_hdl;
  27. hcd_port_event_t port_event;
  28. } port_event_msg_t;
  29. typedef struct {
  30. hcd_pipe_handle_t pipe_hdl;
  31. hcd_pipe_event_t pipe_event;
  32. } pipe_event_msg_t;
  33. // ---------------------------------------------------- Private --------------------------------------------------------
  34. /**
  35. * @brief HCD port callback. Registered when initializing an HCD port
  36. *
  37. * @param port_hdl Port handle
  38. * @param port_event Port event that triggered the callback
  39. * @param user_arg User argument
  40. * @param in_isr Whether callback was called in an ISR context
  41. * @return true ISR should yield after this callback returns
  42. * @return false No yield required (non-ISR context calls should always return false)
  43. */
  44. static bool port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port_event, void *user_arg, bool in_isr)
  45. {
  46. //We store the port's queue handle in the port's context variable
  47. void *port_ctx = hcd_port_get_context(port_hdl);
  48. QueueHandle_t port_evt_queue = (QueueHandle_t)port_ctx;
  49. TEST_ASSERT(in_isr); //Current HCD implementation should never call a port callback in a task context
  50. port_event_msg_t msg = {
  51. .port_hdl = port_hdl,
  52. .port_event = port_event,
  53. };
  54. BaseType_t xTaskWoken = pdFALSE;
  55. xQueueSendFromISR(port_evt_queue, &msg, &xTaskWoken);
  56. return (xTaskWoken == pdTRUE);
  57. }
  58. /**
  59. * @brief HCD pipe callback. Registered when allocating a HCD pipe
  60. *
  61. * @param pipe_hdl Pipe handle
  62. * @param pipe_event Pipe event that triggered the callback
  63. * @param user_arg User argument
  64. * @param in_isr Whether the callback was called in an ISR context
  65. * @return true ISR should yield after this callback returns
  66. * @return false No yield required (non-ISR context calls should always return false)
  67. */
  68. static bool pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr)
  69. {
  70. QueueHandle_t pipe_evt_queue = (QueueHandle_t)user_arg;
  71. pipe_event_msg_t msg = {
  72. .pipe_hdl = pipe_hdl,
  73. .pipe_event = pipe_event,
  74. };
  75. if (in_isr) {
  76. BaseType_t xTaskWoken = pdFALSE;
  77. xQueueSendFromISR(pipe_evt_queue, &msg, &xTaskWoken);
  78. return (xTaskWoken == pdTRUE);
  79. } else {
  80. xQueueSend(pipe_evt_queue, &msg, portMAX_DELAY);
  81. return false;
  82. }
  83. }
  84. // ------------------------------------------------- HCD Event Test ----------------------------------------------------
  85. void test_hcd_expect_port_event(hcd_port_handle_t port_hdl, hcd_port_event_t expected_event)
  86. {
  87. //Get the port event queue from the port's context variable
  88. QueueHandle_t port_evt_queue = (QueueHandle_t)hcd_port_get_context(port_hdl);
  89. TEST_ASSERT_NOT_EQUAL(NULL, port_evt_queue);
  90. //Wait for port callback to send an event message
  91. port_event_msg_t msg;
  92. xQueueReceive(port_evt_queue, &msg, portMAX_DELAY);
  93. //Check the contents of that event message
  94. TEST_ASSERT_EQUAL(port_hdl, msg.port_hdl);
  95. TEST_ASSERT_EQUAL(expected_event, msg.port_event);
  96. printf("\t-> Port event\n");
  97. }
  98. void test_hcd_expect_pipe_event(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t expected_event)
  99. {
  100. //Get the pipe's event queue from the pipe's context variable
  101. QueueHandle_t pipe_evt_queue = (QueueHandle_t)hcd_pipe_get_context(pipe_hdl);
  102. TEST_ASSERT_NOT_EQUAL(NULL, pipe_evt_queue);
  103. //Wait for pipe callback to send an event message
  104. pipe_event_msg_t msg;
  105. xQueueReceive(pipe_evt_queue, &msg, portMAX_DELAY);
  106. //Check the contents of that event message
  107. TEST_ASSERT_EQUAL(pipe_hdl, msg.pipe_hdl);
  108. TEST_ASSERT_EQUAL(expected_event, msg.pipe_event);
  109. }
  110. int test_hcd_get_num_port_events(hcd_port_handle_t port_hdl)
  111. {
  112. //Get the port event queue from the port's context variable
  113. QueueHandle_t port_evt_queue = (QueueHandle_t)hcd_port_get_context(port_hdl);
  114. TEST_ASSERT_NOT_EQUAL(NULL, port_evt_queue);
  115. return EVENT_QUEUE_LEN - uxQueueSpacesAvailable(port_evt_queue);
  116. }
  117. int test_hcd_get_num_pipe_events(hcd_pipe_handle_t pipe_hdl)
  118. {
  119. //Get the pipe's event queue from the pipe's context variable
  120. QueueHandle_t pipe_evt_queue = (QueueHandle_t)hcd_pipe_get_context(pipe_hdl);
  121. TEST_ASSERT_NOT_EQUAL(NULL, pipe_evt_queue);
  122. return EVENT_QUEUE_LEN - uxQueueSpacesAvailable(pipe_evt_queue);
  123. }
  124. // ----------------------------------------------- Driver/Port Related -------------------------------------------------
  125. hcd_port_handle_t test_hcd_setup(void)
  126. {
  127. //Create a queue for port callback to queue up port events
  128. QueueHandle_t port_evt_queue = xQueueCreate(EVENT_QUEUE_LEN, sizeof(port_event_msg_t));
  129. TEST_ASSERT_NOT_EQUAL(NULL, port_evt_queue);
  130. //Install HCD
  131. hcd_config_t hcd_config = {
  132. .intr_flags = ESP_INTR_FLAG_LEVEL1,
  133. };
  134. TEST_ASSERT_EQUAL(ESP_OK, hcd_install(&hcd_config));
  135. //Initialize a port
  136. hcd_port_config_t port_config = {
  137. .fifo_bias = HCD_PORT_FIFO_BIAS_BALANCED,
  138. .callback = port_callback,
  139. .callback_arg = (void *)port_evt_queue,
  140. .context = (void *)port_evt_queue,
  141. };
  142. hcd_port_handle_t port_hdl;
  143. TEST_ASSERT_EQUAL(ESP_OK, hcd_port_init(PORT_NUM, &port_config, &port_hdl));
  144. TEST_ASSERT_NOT_EQUAL(NULL, port_hdl);
  145. TEST_ASSERT_EQUAL(HCD_PORT_STATE_NOT_POWERED, hcd_port_get_state(port_hdl));
  146. test_usb_force_conn_state(false, 0); //Force disconnected state on PHY
  147. return port_hdl;
  148. }
  149. void test_hcd_teardown(hcd_port_handle_t port_hdl)
  150. {
  151. //Get the queue handle from the port's context variable
  152. QueueHandle_t port_evt_queue = (QueueHandle_t)hcd_port_get_context(port_hdl);
  153. TEST_ASSERT_NOT_EQUAL(NULL, port_evt_queue);
  154. //Deinitialize a port
  155. TEST_ASSERT_EQUAL(ESP_OK, hcd_port_deinit(port_hdl));
  156. //Uninstall the HCD
  157. TEST_ASSERT_EQUAL(ESP_OK, hcd_uninstall());
  158. vQueueDelete(port_evt_queue);
  159. }
  160. usb_speed_t test_hcd_wait_for_conn(hcd_port_handle_t port_hdl)
  161. {
  162. //Power ON the port
  163. TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_ON));
  164. TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISCONNECTED, hcd_port_get_state(port_hdl));
  165. //Wait for connection event
  166. printf("Waiting for connection\n");
  167. test_usb_force_conn_state(true, pdMS_TO_TICKS(100)); //Allow for connected state on PHY
  168. test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_CONNECTION);
  169. TEST_ASSERT_EQUAL(HCD_PORT_EVENT_CONNECTION, hcd_port_handle_event(port_hdl));
  170. TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl));
  171. //Reset newly connected device
  172. printf("Resetting\n");
  173. TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_RESET));
  174. TEST_ASSERT_EQUAL(HCD_PORT_STATE_ENABLED, hcd_port_get_state(port_hdl));
  175. //Get speed of connected
  176. usb_speed_t port_speed;
  177. TEST_ASSERT_EQUAL(ESP_OK, hcd_port_get_speed(port_hdl, &port_speed));
  178. if (port_speed == USB_SPEED_FULL) {
  179. printf("Full speed enabled\n");
  180. } else {
  181. printf("Low speed enabled\n");
  182. }
  183. return port_speed;
  184. }
  185. void test_hcd_wait_for_disconn(hcd_port_handle_t port_hdl, bool already_disabled)
  186. {
  187. if (!already_disabled) {
  188. //Disable the device
  189. printf("Disabling\n");
  190. TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_DISABLE));
  191. TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl));
  192. }
  193. //Wait for a safe disconnect
  194. printf("Waiting for disconnection\n");
  195. test_usb_force_conn_state(false, pdMS_TO_TICKS(100)); //Force disconnected state on PHY
  196. test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION);
  197. TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl));
  198. TEST_ASSERT_EQUAL(HCD_PORT_STATE_RECOVERY, hcd_port_get_state(port_hdl));
  199. //Power down the port
  200. TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_OFF));
  201. TEST_ASSERT_EQUAL(HCD_PORT_STATE_NOT_POWERED, hcd_port_get_state(port_hdl));
  202. }
  203. // ---------------------------------------------- Pipe Setup/Tear-down -------------------------------------------------
  204. hcd_pipe_handle_t test_hcd_pipe_alloc(hcd_port_handle_t port_hdl, const usb_ep_desc_t *ep_desc, uint8_t dev_addr, usb_speed_t dev_speed)
  205. {
  206. //Create a queue for pipe callback to queue up pipe events
  207. QueueHandle_t pipe_evt_queue = xQueueCreate(EVENT_QUEUE_LEN, sizeof(pipe_event_msg_t));
  208. TEST_ASSERT_NOT_EQUAL(NULL, pipe_evt_queue);
  209. printf("Creating pipe\n");
  210. hcd_pipe_config_t pipe_config = {
  211. .callback = pipe_callback,
  212. .callback_arg = (void *)pipe_evt_queue,
  213. .context = (void *)pipe_evt_queue,
  214. .ep_desc = ep_desc,
  215. .dev_addr = dev_addr,
  216. .dev_speed = dev_speed,
  217. };
  218. hcd_pipe_handle_t pipe_hdl;
  219. TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_alloc(port_hdl, &pipe_config, &pipe_hdl));
  220. TEST_ASSERT_NOT_EQUAL(NULL, pipe_hdl);
  221. return pipe_hdl;
  222. }
  223. void test_hcd_pipe_free(hcd_pipe_handle_t pipe_hdl)
  224. {
  225. //Get the pipe's event queue from its context variable
  226. QueueHandle_t pipe_evt_queue = (QueueHandle_t)hcd_pipe_get_context(pipe_hdl);
  227. TEST_ASSERT_NOT_EQUAL(NULL, pipe_evt_queue);
  228. //Free the pipe and queue
  229. TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_free(pipe_hdl));
  230. vQueueDelete(pipe_evt_queue);
  231. }
  232. urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size)
  233. {
  234. //Allocate a URB and data buffer
  235. urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (num_isoc_packets * sizeof(usb_isoc_packet_desc_t)), MALLOC_CAP_DEFAULT);
  236. uint8_t *data_buffer = heap_caps_malloc(data_buffer_size, MALLOC_CAP_DMA);
  237. TEST_ASSERT_NOT_EQUAL(NULL, urb);
  238. TEST_ASSERT_NOT_EQUAL(NULL, data_buffer);
  239. //Initialize URB and underlying transfer structure. Need to cast to dummy due to const fields
  240. usb_transfer_dummy_t *transfer_dummy = (usb_transfer_dummy_t *)&urb->transfer;
  241. transfer_dummy->data_buffer = data_buffer;
  242. transfer_dummy->num_isoc_packets = num_isoc_packets;
  243. return urb;
  244. }
  245. void test_hcd_free_urb(urb_t *urb)
  246. {
  247. //Free data buffer of the transfer
  248. heap_caps_free(urb->transfer.data_buffer);
  249. //Free the URB
  250. heap_caps_free(urb);
  251. }
  252. uint8_t test_hcd_enum_device(hcd_pipe_handle_t default_pipe)
  253. {
  254. //We need to create a URB for the enumeration control transfers
  255. urb_t *urb = test_hcd_alloc_urb(0, sizeof(usb_setup_packet_t) + 256);
  256. usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)urb->transfer.data_buffer;
  257. //Get the device descriptor (note that device might only return 8 bytes)
  258. USB_SETUP_PACKET_INIT_GET_DEVICE_DESC(setup_pkt);
  259. urb->transfer.num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_device_desc_t);
  260. TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb));
  261. test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE);
  262. TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe));
  263. TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status);
  264. //Update the MPS of the default pipe
  265. usb_device_desc_t *device_desc = (usb_device_desc_t *)(urb->transfer.data_buffer + sizeof(usb_setup_packet_t));
  266. TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_update_mps(default_pipe, device_desc->bMaxPacketSize0));
  267. //Send a set address request
  268. USB_SETUP_PACKET_INIT_SET_ADDR(setup_pkt, ENUM_ADDR); //We only support one device for now so use address 1
  269. urb->transfer.num_bytes = sizeof(usb_setup_packet_t);
  270. TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb));
  271. test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE);
  272. TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe));
  273. TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status);
  274. //Update address of default pipe
  275. TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_update_dev_addr(default_pipe, ENUM_ADDR));
  276. //Send a set configuration request
  277. USB_SETUP_PACKET_INIT_SET_CONFIG(setup_pkt, ENUM_CONFIG);
  278. urb->transfer.num_bytes = sizeof(usb_setup_packet_t);
  279. TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb));
  280. test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE);
  281. TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe));
  282. TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status);
  283. //Free URB
  284. test_hcd_free_urb(urb);
  285. return ENUM_ADDR;
  286. }