1 /* 2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #include <stdio.h> 8 #include "freertos/FreeRTOS.h" 9 #include "freertos/task.h" 10 #include "esp_err.h" 11 #include "esp_intr_alloc.h" 12 #include "test_usb_common.h" 13 #include "test_usb_mock_classes.h" 14 #include "msc_client.h" 15 #include "ctrl_client.h" 16 #include "usb/usb_host.h" 17 #include "unity.h" 18 #include "test_utils.h" 19 20 // --------------------------------------------------- Test Cases ------------------------------------------------------ 21 22 /* 23 Test USB Host Library Sudden Disconnection Handling (no clients) 24 Purpose: 25 - Test that sudden disconnections are handled properly when there are no clients 26 - Test that devices can reconnect after a sudden disconnection has been handled by the USB Host Library 27 28 Procedure: 29 - Install USB Host Library 30 - Wait for connection (and enumeration) to occur 31 - Force a disconnection, then wait for disconnection to be handled (USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) 32 - Allow connections again, and repeat test for multiple iterations 33 */ 34 35 #define TEST_DCONN_NO_CLIENT_ITERATIONS 3 36 37 TEST_CASE("Test USB Host sudden disconnection (no client)", "[usb_host][ignore]") 38 { 39 test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing 40 //Install USB Host Library 41 usb_host_config_t host_config = { 42 .skip_phy_setup = true, //test_usb_init_phy() will already have setup the internal USB PHY for us 43 .intr_flags = ESP_INTR_FLAG_LEVEL1, 44 }; 45 ESP_ERROR_CHECK(usb_host_install(&host_config)); 46 printf("Installed\n"); 47 48 bool connected = false; 49 int dconn_iter = 0; 50 while (1) { 51 //Start handling system events 52 uint32_t event_flags; 53 usb_host_lib_handle_events(portMAX_DELAY, &event_flags); 54 if (!connected) { 55 usb_host_lib_info_t lib_info; 56 TEST_ASSERT_EQUAL(ESP_OK, usb_host_lib_info(&lib_info)); 57 if (lib_info.num_devices == 1) { 58 //We've just connected. Trigger a disconnect 59 connected = true; 60 printf("Forcing Sudden Disconnect\n"); 61 test_usb_set_phy_state(false, 0); 62 } 63 } 64 if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { 65 //The device has disconnected and it's disconnection has been handled 66 printf("Dconn iter %d done\n", dconn_iter); 67 if (++dconn_iter < TEST_DCONN_NO_CLIENT_ITERATIONS) { 68 //Start next iteration 69 connected = false; 70 test_usb_set_phy_state(true, 0); 71 } else { 72 break; 73 } 74 } 75 } 76 77 //Clean up USB Host 78 ESP_ERROR_CHECK(usb_host_uninstall()); 79 test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing 80 } 81 82 /* 83 Test USB Host Library Sudden Disconnection Handling (with client) 84 Purpose: 85 - Test that sudden disconnections are handled properly when there are registered clients 86 - Test that devices can reconnect after a sudden disconnection has been handled by the USB Host Library 87 88 Procedure: 89 - Install USB Host Library 90 - Create a task to run an MSC client 91 - Start the MSC disconnect client task. It will open the device then force a disconnect for multiple iterations 92 - Wait for USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS and USB_HOST_LIB_EVENT_FLAGS_ALL_FREE before uninstalling 93 */ 94 95 #define TEST_FORCE_DCONN_NUM_TRANSFERS 3 96 #define TEST_MSC_SCSI_TAG 0xDEADBEEF 97 98 TEST_CASE("Test USB Host sudden disconnection (single client)", "[usb_host][ignore]") 99 { 100 test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing 101 //Install USB Host 102 usb_host_config_t host_config = { 103 .skip_phy_setup = true, //test_usb_init_phy() will already have setup the internal USB PHY for us 104 .intr_flags = ESP_INTR_FLAG_LEVEL1, 105 }; 106 ESP_ERROR_CHECK(usb_host_install(&host_config)); 107 printf("Installed\n"); 108 109 //Create task to run client that communicates with MSC SCSI interface 110 msc_client_test_param_t params = { 111 .num_sectors_to_read = 1, //Unused by disconnect MSC client 112 .num_sectors_per_xfer = TEST_FORCE_DCONN_NUM_TRANSFERS * MOCK_MSC_SCSI_SECTOR_SIZE, 113 .msc_scsi_xfer_tag = TEST_MSC_SCSI_TAG, 114 .idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR, 115 .idProduct = MOCK_MSC_SCSI_DEV_ID_PRODUCT, 116 }; 117 TaskHandle_t task_hdl; 118 xTaskCreatePinnedToCore(msc_client_async_dconn_task, "async", 4096, (void *)¶ms, 2, &task_hdl, 0); 119 //Start the task 120 xTaskNotifyGive(task_hdl); 121 122 bool all_clients_gone = false; 123 bool all_dev_free = false; 124 while (!all_clients_gone || !all_dev_free) { 125 //Start handling system events 126 uint32_t event_flags; 127 usb_host_lib_handle_events(portMAX_DELAY, &event_flags); 128 if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { 129 printf("No more clients\n"); 130 all_clients_gone = true; 131 } 132 if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { 133 printf("All device's freed\n"); 134 all_dev_free = true; 135 } 136 } 137 138 //Short delay to allow task to be cleaned up 139 vTaskDelay(10); 140 //Clean up USB Host 141 ESP_ERROR_CHECK(usb_host_uninstall()); 142 test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing 143 } 144 145 /* 146 Test USB Host Library Enumeration 147 Purpose: 148 - Test that the USB Host Library enumerates device correctly 149 150 Procedure: 151 - Install USB Host Library 152 - Create a task to run an MSC client 153 - Start the MSC enumeration client task. It will: 154 - Wait for device connection 155 - Open the device 156 - Check details of the device's enumeration 157 - Disconnect the device, and repeat the steps above for multiple iterations. 158 - Wait for USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS and USB_HOST_LIB_EVENT_FLAGS_ALL_FREE before uninstalling 159 */ 160 161 #define TEST_ENUM_ITERATIONS 3 162 163 TEST_CASE("Test USB Host enumeration", "[usb_host][ignore]") 164 { 165 test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing 166 //Install USB Host 167 usb_host_config_t host_config = { 168 .skip_phy_setup = true, //test_usb_init_phy() will already have setup the internal USB PHY for us 169 .intr_flags = ESP_INTR_FLAG_LEVEL1, 170 }; 171 ESP_ERROR_CHECK(usb_host_install(&host_config)); 172 printf("Installed\n"); 173 174 //Create task to run client that checks the enumeration of the device 175 TaskHandle_t task_hdl; 176 xTaskCreatePinnedToCore(msc_client_async_enum_task, "async", 6144, NULL, 2, &task_hdl, 0); 177 //Start the task 178 xTaskNotifyGive(task_hdl); 179 180 bool all_clients_gone = false; 181 bool all_dev_free = false; 182 while (!all_clients_gone || !all_dev_free) { 183 //Start handling system events 184 uint32_t event_flags; 185 usb_host_lib_handle_events(portMAX_DELAY, &event_flags); 186 if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { 187 printf("No more clients\n"); 188 TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_device_free_all()); 189 all_clients_gone = true; 190 } 191 if (all_clients_gone && event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { 192 all_dev_free = true; 193 } 194 } 195 196 //Short delay to allow task to be cleaned up 197 vTaskDelay(10); 198 //Clean up USB Host 199 ESP_ERROR_CHECK(usb_host_uninstall()); 200 test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing 201 } 202