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 *)&params, 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