Merge branch 'feat/usb_disconnect_api_backport_v5.2' into 'release/v5.2'

refactor(usb): Update HCD tests to use port power off for disconnections backport v5.2

See merge request espressif/esp-idf!33526
This commit is contained in:
morris
2024-10-17 17:00:59 +08:00
18 changed files with 127 additions and 133 deletions

View File

@@ -369,8 +369,8 @@ reset_err:
p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER; p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER;
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_ACTION_ROOT_REQ; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_ACTION_ROOT_REQ;
break; break;
case ROOT_PORT_STATE_ENABLED: case ROOT_PORT_STATE_NOT_POWERED: // The user turned off ports' power. Indicate to USBH that the device is gone
// There is an enabled (active) device. We need to indicate to USBH that the device is gone case ROOT_PORT_STATE_ENABLED: // There is an enabled (active) device. Indicate to USBH that the device is gone
port_has_device = true; port_has_device = true;
break; break;
default: default:
@@ -408,12 +408,21 @@ static void root_port_req(hcd_port_handle_t root_port_hdl)
if (port_reqs & PORT_REQ_RECOVER) { if (port_reqs & PORT_REQ_RECOVER) {
ESP_LOGD(HUB_DRIVER_TAG, "Recovering root port"); ESP_LOGD(HUB_DRIVER_TAG, "Recovering root port");
ESP_ERROR_CHECK(hcd_port_recover(p_hub_driver_obj->constant.root_port_hdl)); ESP_ERROR_CHECK(hcd_port_recover(p_hub_driver_obj->constant.root_port_hdl));
// In case the port's power was turned off with usb_host_lib_set_root_port_power(false)
// we will not turn on the power during port recovery
HUB_DRIVER_ENTER_CRITICAL();
const root_port_state_t root_state = p_hub_driver_obj->dynamic.root_port_state;
HUB_DRIVER_EXIT_CRITICAL();
if (root_state != ROOT_PORT_STATE_NOT_POWERED) {
ESP_ERROR_CHECK(hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON)); ESP_ERROR_CHECK(hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON));
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_POWERED; p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_POWERED;
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
} }
} }
}
static esp_err_t root_port_recycle(void) static esp_err_t root_port_recycle(void)
{ {
@@ -572,15 +581,18 @@ esp_err_t hub_root_stop(void)
{ {
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE); HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE);
HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.root_port_state != ROOT_PORT_STATE_NOT_POWERED, ESP_ERR_INVALID_STATE); if (p_hub_driver_obj->dynamic.root_port_state == ROOT_PORT_STATE_NOT_POWERED) {
// The HUB was already stopped by usb_host_lib_set_root_port_power(false)
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
esp_err_t ret; return ESP_OK;
ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_OFF); }
if (ret == ESP_OK) {
HUB_DRIVER_ENTER_CRITICAL();
p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_NOT_POWERED; p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_NOT_POWERED;
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
}
// HCD_PORT_CMD_POWER_OFF will only fail if the port is already powered_off
// This should never happen, so we assert ret == ESP_OK
const esp_err_t ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_OFF);
assert(ret == ESP_OK);
return ret; return ret;
} }

View File

@@ -101,10 +101,13 @@ typedef void (*usb_host_client_event_cb_t)(const usb_host_client_event_msg_t *ev
* Configuration structure of the USB Host Library. Provided in the usb_host_install() function * Configuration structure of the USB Host Library. Provided in the usb_host_install() function
*/ */
typedef struct { typedef struct {
bool skip_phy_setup; /**< If set, the USB Host Library will not configure the USB PHY thus allowing the user bool skip_phy_setup; /**< If set, the USB Host Library will not configure the USB PHY thus allowing
to manually configure the USB PHY before calling usb_host_install(). Users should the user to manually configure the USB PHY before calling usb_host_install().
set this if they want to use an external USB PHY. Otherwise, the USB Host Library Users should set this if they want to use an external USB PHY. Otherwise,
will automatically configure the internal USB PHY */ the USB Host Library will automatically configure the internal USB PHY */
bool root_port_unpowered; /**< If set, the USB Host Library will not power on the root port on installation.
This allows users to power on the root port manually by calling
usb_host_lib_set_root_port_power(). */
int intr_flags; /**< Interrupt flags for the underlying ISR used by the USB Host stack */ int intr_flags; /**< Interrupt flags for the underlying ISR used by the USB Host stack */
usb_host_enum_filter_cb_t enum_filter_cb; /**< Enumeration filter callback. Enable CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK usb_host_enum_filter_cb_t enum_filter_cb; /**< Enumeration filter callback. Enable CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
to use this feature. Set to NULL otherwise. */ to use this feature. Set to NULL otherwise. */
@@ -206,6 +209,23 @@ esp_err_t usb_host_lib_unblock(void);
*/ */
esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret); esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret);
/**
* @brief Power the root port ON or OFF
*
* - Powering ON the root port will allow device connections to occur
* - Powering OFF the root port will disconnect all devices downstream off the root port and prevent
* any further device connections.
*
* @note If 'usb_host_config_t.root_port_unpowered' was set on USB Host Library installation, users must call this
* function to power ON the root port before any device connections can occur.
*
* @param[in] enable True to power the root port ON, false to power OFF
* @return
* - ESP_OK: Root port power enabled/disabled
* - ESP_ERR_INVALID_STATE: Root port already powered or HUB driver not installed
*/
esp_err_t usb_host_lib_set_root_port_power(bool enable);
// ------------------------------------------------ Client Functions --------------------------------------------------- // ------------------------------------------------ Client Functions ---------------------------------------------------
/** /**

View File

@@ -2,6 +2,5 @@ idf_component_register(SRCS "dev_hid.c"
"dev_isoc.c" "dev_isoc.c"
"dev_msc.c" "dev_msc.c"
"mock_msc.c" "mock_msc.c"
"test_usb_common.c"
INCLUDE_DIRS "." INCLUDE_DIRS "."
REQUIRES usb unity) REQUIRES usb unity)

View File

@@ -1,46 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "hal/usb_phy_types.h"
#include "esp_private/usb_phy.h"
#include "test_usb_common.h"
#include "unity.h"
static usb_phy_handle_t phy_hdl = NULL;
void test_usb_init_phy(void)
{
// Initialize the internal USB PHY to connect to the USB OTG peripheral
usb_phy_config_t phy_config = {
.controller = USB_PHY_CTRL_OTG,
.target = USB_PHY_TARGET_INT,
.otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device
.ext_io_conf = NULL,
.otg_io_conf = NULL,
};
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_new_phy(&phy_config, &phy_hdl), "Failed to init USB PHY");
}
void test_usb_deinit_phy(void)
{
// Deinitialize the internal USB PHY
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Failed to delete PHY");
phy_hdl = NULL;
}
void test_usb_set_phy_state(bool connected, TickType_t delay_ticks)
{
if (delay_ticks > 0) {
// Delay of 0 ticks causes a yield. So skip if delay_ticks is 0.
vTaskDelay(delay_ticks);
}
ESP_ERROR_CHECK(usb_phy_action(phy_hdl, (connected) ? USB_PHY_ACTION_HOST_ALLOW_CONN : USB_PHY_ACTION_HOST_FORCE_DISCONN));
}

View File

@@ -1,26 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
/**
* @brief Initialize the internal USB PHY and USB Controller for USB Host testing
*/
void test_usb_init_phy(void);
/**
* @brief Deinitialize the internal USB PHY and USB Controller after USB Host testing
*/
void test_usb_deinit_phy(void);
/**
* @brief For the USB PHY into the connected or disconnected state
*
* @param connected For into connected state if true, disconnected if false
* @param delay_ticks Delay in ticks before forcing state
*/
void test_usb_set_phy_state(bool connected, TickType_t delay_ticks);

View File

@@ -17,8 +17,8 @@
#include "hcd.h" #include "hcd.h"
#include "usb_private.h" #include "usb_private.h"
#include "usb/usb_types_ch9.h" #include "usb/usb_types_ch9.h"
#include "esp_private/usb_phy.h"
#include "test_hcd_common.h" #include "test_hcd_common.h"
#include "test_usb_common.h"
#include "mock_msc.h" #include "mock_msc.h"
#include "unity.h" #include "unity.h"
@@ -38,6 +38,7 @@ typedef struct {
} pipe_event_msg_t; } pipe_event_msg_t;
hcd_port_handle_t port_hdl = NULL; hcd_port_handle_t port_hdl = NULL;
static usb_phy_handle_t phy_hdl = NULL;
// ---------------------------------------------------- Private -------------------------------------------------------- // ---------------------------------------------------- Private --------------------------------------------------------
@@ -144,7 +145,21 @@ int test_hcd_get_num_pipe_events(hcd_pipe_handle_t pipe_hdl)
hcd_port_handle_t test_hcd_setup(void) hcd_port_handle_t test_hcd_setup(void)
{ {
test_usb_init_phy(); // Initialize the internal USB PHY and USB Controller for testing // Deinitialize PHY from previous failed test
if (phy_hdl != NULL) {
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Failed to delete PHY");
phy_hdl = NULL;
}
// Initialize the internal USB PHY to connect to the USB OTG peripheral
usb_phy_config_t phy_config = {
.controller = USB_PHY_CTRL_OTG,
.target = USB_PHY_TARGET_INT,
.otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device
.ext_io_conf = NULL,
.otg_io_conf = NULL,
};
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_new_phy(&phy_config, &phy_hdl), "Failed to init USB PHY");
// Create a queue for port callback to queue up port events // Create a queue for port callback to queue up port events
QueueHandle_t port_evt_queue = xQueueCreate(EVENT_QUEUE_LEN, sizeof(port_event_msg_t)); QueueHandle_t port_evt_queue = xQueueCreate(EVENT_QUEUE_LEN, sizeof(port_event_msg_t));
TEST_ASSERT_NOT_NULL(port_evt_queue); TEST_ASSERT_NOT_NULL(port_evt_queue);
@@ -163,8 +178,6 @@ hcd_port_handle_t test_hcd_setup(void)
hcd_port_handle_t port_hdl; hcd_port_handle_t port_hdl;
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_init(PORT_NUM, &port_config, &port_hdl)); TEST_ASSERT_EQUAL(ESP_OK, hcd_port_init(PORT_NUM, &port_config, &port_hdl));
TEST_ASSERT_NOT_NULL(port_hdl); TEST_ASSERT_NOT_NULL(port_hdl);
TEST_ASSERT_EQUAL(HCD_PORT_STATE_NOT_POWERED, hcd_port_get_state(port_hdl));
test_usb_set_phy_state(false, 0); // Force disconnected state on PHY
return port_hdl; return port_hdl;
} }
@@ -181,17 +194,18 @@ void test_hcd_teardown(hcd_port_handle_t port_hdl)
// Uninstall the HCD // Uninstall the HCD
TEST_ASSERT_EQUAL(ESP_OK, hcd_uninstall()); TEST_ASSERT_EQUAL(ESP_OK, hcd_uninstall());
vQueueDelete(port_evt_queue); vQueueDelete(port_evt_queue);
test_usb_deinit_phy(); // Deinitialize the internal USB PHY after testing // Deinitialize the internal USB PHY
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Failed to delete PHY");
phy_hdl = NULL;
} }
usb_speed_t test_hcd_wait_for_conn(hcd_port_handle_t port_hdl) usb_speed_t test_hcd_wait_for_conn(hcd_port_handle_t port_hdl)
{ {
// Power ON the port // Power ON the port. This should allow for connections to occur
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_ON)); TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_ON));
TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISCONNECTED, hcd_port_get_state(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISCONNECTED, hcd_port_get_state(port_hdl));
// Wait for connection event // Wait for connection event
printf("Waiting for connection\n"); printf("Waiting for connection\n");
test_usb_set_phy_state(true, pdMS_TO_TICKS(100)); // Allow for connected state on PHY
test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_CONNECTION); test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_CONNECTION);
TEST_ASSERT_EQUAL(HCD_PORT_EVENT_CONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_CONNECTION, hcd_port_handle_event(port_hdl));
TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl));
@@ -218,9 +232,10 @@ void test_hcd_wait_for_disconn(hcd_port_handle_t port_hdl, bool already_disabled
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_DISABLE)); TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_DISABLE));
TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl));
} }
// Wait for a safe disconnect
printf("Waiting for disconnection\n"); printf("Waiting for disconnection\n");
test_usb_set_phy_state(false, pdMS_TO_TICKS(100)); // Force disconnected state on PHY // Power-off the port to trigger a disconnection
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_OFF));
// Wait for the port disconnection event
test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION); test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION);
TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl));
TEST_ASSERT_EQUAL(HCD_PORT_STATE_RECOVERY, hcd_port_get_state(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_RECOVERY, hcd_port_get_state(port_hdl));

View File

@@ -53,6 +53,8 @@ int test_hcd_get_num_pipe_events(hcd_pipe_handle_t pipe_hdl);
/** /**
* @brief Sets up the HCD and initializes an HCD port. * @brief Sets up the HCD and initializes an HCD port.
* *
* The HCD port is left in the HCD_PORT_STATE_NOT_POWERED state
*
* @return hcd_port_handle_t Port handle * @return hcd_port_handle_t Port handle
*/ */
hcd_port_handle_t test_hcd_setup(void); hcd_port_handle_t test_hcd_setup(void);
@@ -67,7 +69,7 @@ void test_hcd_teardown(hcd_port_handle_t port_hdl);
/** /**
* @brief Wait for a connection on an HCD port * @brief Wait for a connection on an HCD port
* *
* @note This function will internally call test_usb_set_phy_state() to allow for a connection * @note HCD_PORT_CMD_POWER_ON is called internally to allow connections
* *
* @param port_hdl Port handle * @param port_hdl Port handle
* @return usb_speed_t Speed of the connected device * @return usb_speed_t Speed of the connected device
@@ -77,7 +79,7 @@ usb_speed_t test_hcd_wait_for_conn(hcd_port_handle_t port_hdl);
/** /**
* @brief Wait for a disconnection on an HCD port * @brief Wait for a disconnection on an HCD port
* *
* @note This fucntion will internally call test_usb_set_phy_state() to force a disconnection * @note HCD_PORT_CMD_POWER_OFF is called internally to force a disconnection
* *
* @param port_hdl Port handle * @param port_hdl Port handle
* @param already_disabled Whether the HCD port is already in the disabled state * @param already_disabled Whether the HCD port is already in the disabled state

View File

@@ -12,7 +12,6 @@
#include "unity.h" #include "unity.h"
#include "dev_isoc.h" #include "dev_isoc.h"
#include "usb/usb_types_ch9.h" #include "usb/usb_types_ch9.h"
#include "test_usb_common.h"
#include "test_hcd_common.h" #include "test_hcd_common.h"
#define NUM_URBS 3 #define NUM_URBS 3
@@ -261,7 +260,8 @@ TEST_CASE("Test HCD isochronous pipe sudden disconnect", "[isoc][full_speed]")
} }
// Add a short delay to let the transfers run for a bit // Add a short delay to let the transfers run for a bit
esp_rom_delay_us(POST_ENQUEUE_DELAY_US); esp_rom_delay_us(POST_ENQUEUE_DELAY_US);
test_usb_set_phy_state(false, 0); // Power-off the port to trigger a disconnection
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_OFF));
// Disconnect event should have occurred. Handle the port event // Disconnect event should have occurred. Handle the port event
test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION); test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION);
TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl));

View File

@@ -9,7 +9,6 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "unity.h" #include "unity.h"
#include "esp_rom_sys.h" #include "esp_rom_sys.h"
#include "test_usb_common.h"
#include "test_hcd_common.h" #include "test_hcd_common.h"
#define TEST_DEV_ADDR 0 #define TEST_DEV_ADDR 0
@@ -64,7 +63,8 @@ TEST_CASE("Test HCD port sudden disconnect", "[port][low_speed][full_speed]")
} }
// Add a short delay to let the transfers run for a bit // Add a short delay to let the transfers run for a bit
esp_rom_delay_us(POST_ENQUEUE_DELAY_US); esp_rom_delay_us(POST_ENQUEUE_DELAY_US);
test_usb_set_phy_state(false, 0); // Power-off the port to trigger a disconnection
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_OFF));
// Disconnect event should have occurred. Handle the port event // Disconnect event should have occurred. Handle the port event
test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION); test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION);
TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl));
@@ -267,8 +267,8 @@ static void concurrent_task(void *arg)
SemaphoreHandle_t sync_sem = (SemaphoreHandle_t) arg; SemaphoreHandle_t sync_sem = (SemaphoreHandle_t) arg;
xSemaphoreTake(sync_sem, portMAX_DELAY); xSemaphoreTake(sync_sem, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(10)); // Give a short delay let reset command start in main thread vTaskDelay(pdMS_TO_TICKS(10)); // Give a short delay let reset command start in main thread
// Force a disconnection // Power-off the port to trigger a disconnection
test_usb_set_phy_state(false, 0); TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_OFF));
vTaskDelay(portMAX_DELAY); // Block forever and wait to be deleted vTaskDelay(portMAX_DELAY); // Block forever and wait to be deleted
} }
@@ -291,7 +291,8 @@ TEST_CASE("Test HCD port command bailout", "[port][low_speed][full_speed]")
// Attempt to resume the port. But the concurrent task should override this with a disconnection event // Attempt to resume the port. But the concurrent task should override this with a disconnection event
printf("Attempting to resume\n"); printf("Attempting to resume\n");
xSemaphoreGive(sync_sem); // Trigger concurrent task xSemaphoreGive(sync_sem); // Trigger concurrent task
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_RESPONSE, hcd_port_command(port_hdl, HCD_PORT_CMD_RESUME)); vTaskDelay(pdMS_TO_TICKS(20)); // Short delay for concurrent task to trigger disconnection
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, hcd_port_command(port_hdl, HCD_PORT_CMD_RESUME));
// Check that concurrent task triggered a sudden disconnection // Check that concurrent task triggered a sudden disconnection
test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION); test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION);

View File

@@ -10,7 +10,6 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "test_usb_common.h"
#include "dev_msc.h" #include "dev_msc.h"
#include "ctrl_client.h" #include "ctrl_client.h"
#include "usb/usb_host.h" #include "usb/usb_host.h"

View File

@@ -14,7 +14,6 @@
#include "esp_log.h" #include "esp_log.h"
#include "mock_msc.h" #include "mock_msc.h"
#include "dev_msc.h" #include "dev_msc.h"
#include "test_usb_common.h"
#include "msc_client.h" #include "msc_client.h"
#include "usb/usb_types_ch9.h" #include "usb/usb_types_ch9.h"
#include "usb/usb_host.h" #include "usb/usb_host.h"
@@ -89,8 +88,10 @@ static void msc_data_transfer_cb(usb_transfer_t *transfer)
// The data stage should have either completed, or failed due to the disconnection. // The data stage should have either completed, or failed due to the disconnection.
TEST_ASSERT(transfer->status == USB_TRANSFER_STATUS_COMPLETED || transfer->status == USB_TRANSFER_STATUS_NO_DEVICE); TEST_ASSERT(transfer->status == USB_TRANSFER_STATUS_COMPLETED || transfer->status == USB_TRANSFER_STATUS_NO_DEVICE);
if (transfer->status == USB_TRANSFER_STATUS_COMPLETED) { if (transfer->status == USB_TRANSFER_STATUS_COMPLETED) {
printf("Data transfer completed\n");
TEST_ASSERT_EQUAL(transfer->num_bytes, transfer->actual_num_bytes); TEST_ASSERT_EQUAL(transfer->num_bytes, transfer->actual_num_bytes);
} else { } else {
printf("Data transfer NOT completed: No device\n");
TEST_ASSERT_EQUAL(0, transfer->actual_num_bytes); TEST_ASSERT_EQUAL(0, transfer->actual_num_bytes);
} }
msc_client_obj_t *msc_obj = (msc_client_obj_t *)transfer->context; msc_client_obj_t *msc_obj = (msc_client_obj_t *)transfer->context;
@@ -239,7 +240,7 @@ void msc_client_async_dconn_task(void *arg)
break; break;
} }
case TEST_STAGE_MSC_DATA_DCONN: { case TEST_STAGE_MSC_DATA_DCONN: {
ESP_LOGD(MSC_CLIENT_TAG, "Data and disconnect"); ESP_LOGD(MSC_CLIENT_TAG, "Data (%d transfers) and disconnect", msc_obj.num_data_transfers);
// Setup the Data IN transfers // Setup the Data IN transfers
const usb_ep_desc_t *in_ep_desc = dev_msc_get_in_ep_desc(msc_obj.dev_speed); const usb_ep_desc_t *in_ep_desc = dev_msc_get_in_ep_desc(msc_obj.dev_speed);
const int bulk_ep_mps = USB_EP_DESC_GET_MPS(in_ep_desc); const int bulk_ep_mps = USB_EP_DESC_GET_MPS(in_ep_desc);
@@ -251,8 +252,8 @@ void msc_client_async_dconn_task(void *arg)
for (int i = 0; i < msc_obj.num_data_transfers; i++) { for (int i = 0; i < msc_obj.num_data_transfers; i++) {
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in[i])); TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in[i]));
} }
// Trigger a disconnect // Trigger a disconnect by powering OFF the root port
test_usb_set_phy_state(false, 0); usb_host_lib_set_root_port_power(false);
// Next stage set from transfer callback // Next stage set from transfer callback
break; break;
} }
@@ -260,12 +261,16 @@ void msc_client_async_dconn_task(void *arg)
ESP_LOGD(MSC_CLIENT_TAG, "Close"); ESP_LOGD(MSC_CLIENT_TAG, "Close");
TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(msc_obj.client_hdl, msc_obj.dev_hdl, msc_obj.dev_info->bInterfaceNumber)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(msc_obj.client_hdl, msc_obj.dev_hdl, msc_obj.dev_info->bInterfaceNumber));
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl));
dconn_iter++; vTaskDelay(10); // Yield to USB Host task so it can handle the disconnection
if (dconn_iter < TEST_DCONN_ITERATIONS) {
// The device has disconnected and it's disconnection has been handled
printf("Dconn iter %d done\n", dconn_iter);
if (++dconn_iter < TEST_DCONN_ITERATIONS) {
// Start the next test iteration by going back to TEST_STAGE_WAIT_CONN and reenabling connections // Start the next test iteration by going back to TEST_STAGE_WAIT_CONN and reenabling connections
msc_obj.next_stage = TEST_STAGE_WAIT_CONN; msc_obj.next_stage = TEST_STAGE_WAIT_CONN;
skip_event_handling = true; // Need to execute TEST_STAGE_WAIT_CONN skip_event_handling = true; // Need to execute TEST_STAGE_WAIT_CONN
test_usb_set_phy_state(true, 0); // Allow connections again by powering ON the root port
usb_host_lib_set_root_port_power(true);
} else { } else {
exit_loop = true; exit_loop = true;
} }

View File

@@ -14,7 +14,6 @@
#include "esp_log.h" #include "esp_log.h"
#include "dev_msc.h" #include "dev_msc.h"
#include "mock_msc.h" #include "mock_msc.h"
#include "test_usb_common.h"
#include "msc_client.h" #include "msc_client.h"
#include "usb/usb_host.h" #include "usb/usb_host.h"
#include "unity.h" #include "unity.h"
@@ -177,8 +176,9 @@ void msc_client_async_enum_task(void *arg)
enum_iter++; enum_iter++;
if (enum_iter < TEST_ENUM_ITERATIONS) { if (enum_iter < TEST_ENUM_ITERATIONS) {
// Start the next test iteration by disconnecting the device, then going back to TEST_STAGE_WAIT_CONN stage // Start the next test iteration by disconnecting the device, then going back to TEST_STAGE_WAIT_CONN stage
test_usb_set_phy_state(false, 0); usb_host_lib_set_root_port_power(false);
test_usb_set_phy_state(true, 0); vTaskDelay(10); // Yield to USB Host task so it can handle the disconnection
usb_host_lib_set_root_port_power(true);
msc_obj.next_stage = TEST_STAGE_WAIT_CONN; msc_obj.next_stage = TEST_STAGE_WAIT_CONN;
skip_event_handling = true; // Need to execute TEST_STAGE_WAIT_CONN skip_event_handling = true; // Need to execute TEST_STAGE_WAIT_CONN
} else { } else {

View File

@@ -12,7 +12,6 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "test_usb_common.h"
#include "mock_msc.h" #include "mock_msc.h"
#include "dev_msc.h" #include "dev_msc.h"
#include "msc_client.h" #include "msc_client.h"

View File

@@ -11,7 +11,6 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "test_usb_common.h"
#include "multiconf_client.h" #include "multiconf_client.h"
#include "mock_msc.h" #include "mock_msc.h"
#include "dev_msc.h" #include "dev_msc.h"

View File

@@ -9,7 +9,6 @@
#include "unity_test_utils_memory.h" #include "unity_test_utils_memory.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "test_usb_common.h"
#include "dev_msc.h" #include "dev_msc.h"
#include "usb/usb_host.h" #include "usb/usb_host.h"
@@ -17,10 +16,10 @@ void setUp(void)
{ {
unity_utils_record_free_mem(); unity_utils_record_free_mem();
dev_msc_init(); dev_msc_init();
test_usb_init_phy(); // Initialize the internal USB PHY and USB Controller for testing
// Install USB Host // Install USB Host
usb_host_config_t host_config = { usb_host_config_t host_config = {
.skip_phy_setup = true, // test_usb_init_phy() will already have setup the internal USB PHY for us .skip_phy_setup = false,
.root_port_unpowered = false,
.intr_flags = ESP_INTR_FLAG_LEVEL1, .intr_flags = ESP_INTR_FLAG_LEVEL1,
}; };
ESP_ERROR_CHECK(usb_host_install(&host_config)); ESP_ERROR_CHECK(usb_host_install(&host_config));
@@ -32,10 +31,10 @@ void tearDown(void)
// Short delay to allow task to be cleaned up // Short delay to allow task to be cleaned up
vTaskDelay(10); vTaskDelay(10);
// Clean up USB Host // Clean up USB Host
printf("USB Host uninstall\n");
ESP_ERROR_CHECK(usb_host_uninstall()); ESP_ERROR_CHECK(usb_host_uninstall());
// Short delay to allow task to be cleaned up after client uninstall // Short delay to allow task to be cleaned up after client uninstall
vTaskDelay(10); vTaskDelay(10);
test_usb_deinit_phy(); // Deinitialize the internal USB PHY after testing
unity_utils_evaluate_leaks(); unity_utils_evaluate_leaks();
} }

View File

@@ -10,7 +10,6 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "test_usb_common.h"
#include "dev_msc.h" #include "dev_msc.h"
#include "msc_client.h" #include "msc_client.h"
#include "ctrl_client.h" #include "ctrl_client.h"
@@ -252,8 +251,9 @@ TEST_CASE("Test USB Host async API", "[usb_host][full_speed][low_speed]")
client0_dev_hdl, client0_dev_hdl,
dev_info->bInterfaceNumber)); dev_info->bInterfaceNumber));
// Trigger a disconnect by powering OFF the root port
usb_host_lib_set_root_port_power(false);
// Wait until the device disconnects and the clients receive the event // Wait until the device disconnects and the clients receive the event
test_usb_set_phy_state(false, 0);
while (!(client0_stage == CLIENT_TEST_STAGE_DCONN && client1_stage == CLIENT_TEST_STAGE_DCONN)) { while (!(client0_stage == CLIENT_TEST_STAGE_DCONN && client1_stage == CLIENT_TEST_STAGE_DCONN)) {
usb_host_lib_handle_events(0, NULL); usb_host_lib_handle_events(0, NULL);
usb_host_client_handle_events(client0_hdl, 0); usb_host_client_handle_events(client0_hdl, 0);

View File

@@ -9,7 +9,6 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "test_usb_common.h"
#include "mock_msc.h" #include "mock_msc.h"
#include "dev_msc.h" #include "dev_msc.h"
#include "msc_client.h" #include "msc_client.h"
@@ -49,7 +48,8 @@ TEST_CASE("Test USB Host sudden disconnection (no client)", "[usb_host][full_spe
// We've just connected. Trigger a disconnect // We've just connected. Trigger a disconnect
connected = true; connected = true;
printf("Forcing Sudden Disconnect\n"); printf("Forcing Sudden Disconnect\n");
test_usb_set_phy_state(false, 0); // Trigger a disconnect by powering OFF the root port
usb_host_lib_set_root_port_power(false);
} }
} }
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
@@ -58,7 +58,8 @@ TEST_CASE("Test USB Host sudden disconnection (no client)", "[usb_host][full_spe
if (++dconn_iter < TEST_DCONN_NO_CLIENT_ITERATIONS) { if (++dconn_iter < TEST_DCONN_NO_CLIENT_ITERATIONS) {
// Start next iteration // Start next iteration
connected = false; connected = false;
test_usb_set_phy_state(true, 0); // Allow connections again by powering ON the root port
usb_host_lib_set_root_port_power(true);
} else { } else {
break; break;
} }

View File

@@ -545,8 +545,11 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
p_host_lib_obj = host_lib_obj; p_host_lib_obj = host_lib_obj;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
if (!config->root_port_unpowered) {
// Start the root hub // Start the root hub
ESP_ERROR_CHECK(hub_root_start()); ESP_ERROR_CHECK(hub_root_start());
}
ret = ESP_OK; ret = ESP_OK;
return ret; return ret;
@@ -699,6 +702,18 @@ esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret)
return ESP_OK; return ESP_OK;
} }
esp_err_t usb_host_lib_set_root_port_power(bool enable)
{
esp_err_t ret;
if (enable) {
ret = hub_root_start();
} else {
ret = hub_root_stop();
}
return ret;
}
// ------------------------------------------------ Client Functions --------------------------------------------------- // ------------------------------------------------ Client Functions ---------------------------------------------------
// ----------------------- Private ------------------------- // ----------------------- Private -------------------------