|
29 | 29 |
|
30 | 30 | #define MULTIPLE_THREADS_TASKS_NUM 5 |
31 | 31 |
|
32 | | -static int nb_of_success = 0; |
| 32 | +static SemaphoreHandle_t sem_done = NULL; |
| 33 | +TaskHandle_t test_task_handles[MULTIPLE_THREADS_TASKS_NUM]; |
| 34 | + |
| 35 | +// Unlocked spinlock, ready to use |
| 36 | +static portMUX_TYPE _spinlock = portMUX_INITIALIZER_UNLOCKED; |
| 37 | +static volatile int nb_of_success = 0; |
33 | 38 |
|
34 | 39 | static void test_task_install(void *arg) |
35 | 40 | { |
36 | | - TaskHandle_t parent_task_handle = (TaskHandle_t)arg; |
37 | | - |
| 41 | + (void) arg; |
38 | 42 | // Install TinyUSB driver |
39 | 43 | tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG(test_device_event_handler); |
40 | 44 | tusb_cfg.phy.skip_setup = true; // Skip phy setup to allow multiple tasks to install the driver |
41 | 45 |
|
| 46 | + // Wait to be started by main thread |
| 47 | + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); |
| 48 | + |
42 | 49 | if (tinyusb_driver_install(&tusb_cfg) == ESP_OK) { |
43 | 50 | test_device_wait(); |
44 | 51 | TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); |
| 52 | + taskENTER_CRITICAL(&_spinlock); |
45 | 53 | nb_of_success++; |
| 54 | + taskEXIT_CRITICAL(&_spinlock); |
46 | 55 | } |
47 | 56 |
|
48 | 57 | // Notify the parent task that the task completed the job |
49 | | - xTaskNotifyGive(parent_task_handle); |
| 58 | + xSemaphoreGive(sem_done); |
50 | 59 | // Delete task |
51 | 60 | vTaskDelete(NULL); |
52 | 61 | } |
53 | 62 |
|
54 | | -// ============================= Tests ========================================= |
55 | 63 |
|
56 | | -/** |
57 | | - * @brief TinyUSB Task specific testcase |
58 | | - * |
59 | | - * Scenario: Trying to install driver from several tasks |
60 | | - * Note: when skip_phy_setup = false, the task access will be determined by the first task install the phy |
61 | | - */ |
62 | | -TEST_CASE("Multitask: Install", "[runtime_config][full_speed][high_speed]") |
| 64 | +static void test_task_uninstall(void *arg) |
| 65 | +{ |
| 66 | + (void) arg; |
| 67 | + // Wait to be started by main thread |
| 68 | + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); |
| 69 | + |
| 70 | + if (tinyusb_driver_uninstall() == ESP_OK) { |
| 71 | + taskENTER_CRITICAL(&_spinlock); |
| 72 | + nb_of_success++; |
| 73 | + taskEXIT_CRITICAL(&_spinlock); |
| 74 | + } |
| 75 | + |
| 76 | + // Notify the parent task that the task completed the job |
| 77 | + xSemaphoreGive(sem_done); |
| 78 | + // Delete task |
| 79 | + vTaskDelete(NULL); |
| 80 | +} |
| 81 | + |
| 82 | +// USB PHY |
| 83 | + |
| 84 | +static usb_phy_handle_t test_init_phy(void) |
63 | 85 | { |
64 | 86 | usb_phy_handle_t phy_hdl = NULL; |
65 | | - // Install the PHY externally |
66 | 87 | usb_phy_config_t phy_conf = { |
67 | 88 | .controller = USB_PHY_CTRL_OTG, |
68 | 89 | .target = USB_PHY_TARGET_INT, |
69 | 90 | .otg_mode = USB_OTG_MODE_DEVICE, |
70 | 91 | }; |
71 | 92 | TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_new_phy(&phy_conf, &phy_hdl), "Unable to install USB PHY "); |
| 93 | + return phy_hdl; |
| 94 | +} |
| 95 | + |
| 96 | +static void test_deinit_phy(usb_phy_handle_t phy_hdl) |
| 97 | +{ |
| 98 | + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Unable to delete USB PHY "); |
| 99 | +} |
72 | 100 |
|
| 101 | +// ============================= Tests ========================================= |
| 102 | + |
| 103 | +/** |
| 104 | + * @brief TinyUSB Task specific testcase |
| 105 | + * |
| 106 | + * Scenario: Trying to install driver from several tasks |
| 107 | + * Note: when phy.skip_setup = false, the task access will be determined by the first task install the phy |
| 108 | + */ |
| 109 | +TEST_CASE("Multitask: Install", "[runtime_config][default]") |
| 110 | +{ |
| 111 | + usb_phy_handle_t phy_hdl = test_init_phy(); |
| 112 | + |
| 113 | + // Create counting semaphore to wait for all tasks to complete |
| 114 | + sem_done = xSemaphoreCreateCounting(MULTIPLE_THREADS_TASKS_NUM, 0); |
| 115 | + TEST_ASSERT_NOT_NULL(sem_done); |
| 116 | + |
| 117 | + // No task are running yet |
73 | 118 | nb_of_success = 0; |
| 119 | + |
74 | 120 | // Create tasks that will start the driver |
75 | 121 | for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) { |
76 | | - TEST_ASSERT_EQUAL(pdTRUE, xTaskCreate(test_task_install, |
| 122 | + TEST_ASSERT_EQUAL(pdPASS, xTaskCreate(test_task_install, |
77 | 123 | "InstallTask", |
78 | 124 | 4096, |
79 | | - (void *) xTaskGetCurrentTaskHandle(), |
| 125 | + NULL, |
80 | 126 | 4 + i, |
81 | | - NULL)); |
| 127 | + &test_task_handles[i])); |
| 128 | + } |
| 129 | + |
| 130 | + // Start all tasks |
| 131 | + for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) { |
| 132 | + xTaskNotifyGive(test_task_handles[i]); |
| 133 | + } |
| 134 | + |
| 135 | + // Wait for all tasks to complete |
| 136 | + for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) { |
| 137 | + TEST_ASSERT_EQUAL_MESSAGE(pdTRUE, xSemaphoreTake(sem_done, pdMS_TO_TICKS(5000)), "Not all tasks completed in time"); |
82 | 138 | } |
83 | 139 |
|
84 | | - // Wait until all tasks are finished |
85 | | - vTaskDelay(pdMS_TO_TICKS(5000)); |
86 | | - // Check if all tasks finished, we should get all notification from the tasks |
87 | | - TEST_ASSERT_EQUAL_MESSAGE(MULTIPLE_THREADS_TASKS_NUM, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(5000)), "Not all tasks finished"); |
88 | 140 | // There should be only one task that was able to install the driver |
89 | 141 | TEST_ASSERT_EQUAL_MESSAGE(1, nb_of_success, "Only one task should be able to install the driver"); |
90 | 142 | // Clean-up |
91 | | - TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Unable to delete PHY"); |
| 143 | + test_deinit_phy(phy_hdl); |
| 144 | + vSemaphoreDelete(sem_done); |
| 145 | +} |
| 146 | + |
| 147 | +TEST_CASE("Multitask: Uninstall", "[runtime_config][default]") |
| 148 | +{ |
| 149 | + usb_phy_handle_t phy_hdl = test_init_phy(); |
| 150 | + // Create counting semaphore to wait for all tasks to complete |
| 151 | + sem_done = xSemaphoreCreateCounting(MULTIPLE_THREADS_TASKS_NUM, 0); |
| 152 | + TEST_ASSERT_NOT_NULL(sem_done); |
| 153 | + |
| 154 | + // No task are running yet |
| 155 | + nb_of_success = 0; |
| 156 | + |
| 157 | + // Install the driver once |
| 158 | + tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG(test_device_event_handler); |
| 159 | + tusb_cfg.phy.skip_setup = true; // Skip phy setup to allow multiple tasks |
| 160 | + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, tinyusb_driver_install(&tusb_cfg), "Unable to install TinyUSB driver "); |
| 161 | + // Create tasks that will uninstall the driver |
| 162 | + for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) { |
| 163 | + TEST_ASSERT_EQUAL(pdPASS, xTaskCreate(test_task_uninstall, |
| 164 | + "UninstallTask", |
| 165 | + 4096, |
| 166 | + NULL, |
| 167 | + 4 + i, |
| 168 | + &test_task_handles[i])); |
| 169 | + } |
| 170 | + |
| 171 | + // Start all tasks |
| 172 | + for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) { |
| 173 | + xTaskNotifyGive(test_task_handles[i]); |
| 174 | + } |
| 175 | + // Wait for all tasks to complete |
| 176 | + for (int i = 0; i < MULTIPLE_THREADS_TASKS_NUM; i++) { |
| 177 | + TEST_ASSERT_EQUAL_MESSAGE(pdTRUE, xSemaphoreTake(sem_done, pdMS_TO_TICKS(5000)), "Not all tasks completed in time"); |
| 178 | + } |
| 179 | + |
| 180 | + // There should be only one task that was able to uninstall the driver |
| 181 | + TEST_ASSERT_EQUAL_MESSAGE(1, nb_of_success, "Only one task should be able to uninstall the driver"); |
| 182 | + |
| 183 | + // Clean-up |
| 184 | + test_deinit_phy(phy_hdl); |
| 185 | + vSemaphoreDelete(sem_done); |
92 | 186 | } |
93 | 187 |
|
| 188 | + |
94 | 189 | #endif // SOC_USB_OTG_SUPPORTED |
0 commit comments