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

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

See merge request espressif/esp-idf!33527
This commit is contained in:
morris 2024-09-28 10:50:46 +08:00
commit a5ed03eb85
21 changed files with 148 additions and 152 deletions

View File

@ -62,7 +62,7 @@
// FS: Must be 2-64. HS: Must be 8-256. See USB-OTG databook Table 5-47 // FS: Must be 2-64. HS: Must be 8-256. See USB-OTG databook Table 5-47
#define XFER_LIST_LEN_INTR FRAME_LIST_LEN #define XFER_LIST_LEN_INTR FRAME_LIST_LEN
#define XFER_LIST_LEN_ISOC 64 // Implement longer ISOC transfer list to give us enough space for additional timing margin #define XFER_LIST_LEN_ISOC 64 // Implement longer ISOC transfer list to give us enough space for additional timing margin
#define XFER_LIST_ISOC_MARGIN 2 // The 1st ISOC transfer is scheduled 2 (micro)frames later so we have enough timing margin #define XFER_LIST_ISOC_MARGIN 3 // The 1st ISOC transfer is scheduled 3 (micro)frames later so we have enough timing margin
// ------------------------ Flags -------------------------- // ------------------------ Flags --------------------------

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,10 +408,19 @@ 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));
ESP_ERROR_CHECK(hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON));
// 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(); HUB_DRIVER_ENTER_CRITICAL();
p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_POWERED; const root_port_state_t root_state = p_hub_driver_obj->dynamic.root_port_state;
HUB_DRIVER_EXIT_CRITICAL(); 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));
HUB_DRIVER_ENTER_CRITICAL();
p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_POWERED;
HUB_DRIVER_EXIT_CRITICAL();
}
} }
} }
@ -570,15 +579,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) {
HUB_DRIVER_EXIT_CRITICAL(); // The HUB was already stopped by usb_host_lib_set_root_port_power(false)
esp_err_t ret;
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;
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
return ESP_OK;
} }
p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_NOT_POWERED;
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,13 +101,16 @@ 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 */
int intr_flags; /**< Interrupt flags for the underlying ISR used by the USB Host stack */ bool root_port_unpowered; /**< If set, the USB Host Library will not power on the root port on installation.
usb_host_enum_filter_cb_t enum_filter_cb; /**< Enumeration filter callback. Enable CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK This allows users to power on the root port manually by calling
to use this feature. Set to NULL otherwise. */ usb_host_lib_set_root_port_power(). */
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
to use this feature. Set to NULL otherwise. */
} usb_host_config_t; } usb_host_config_t;
/** /**
@ -187,6 +190,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

@ -53,7 +53,7 @@ Procedure:
#define TEST_NUM_SECTORS_TOTAL 10 #define TEST_NUM_SECTORS_TOTAL 10
#define TEST_NUM_SECTORS_PER_XFER 2 #define TEST_NUM_SECTORS_PER_XFER 2
TEST_CASE("Test HCD bulk pipe URBs", "[bulk][full_speed]") TEST_CASE("Test HCD bulk pipe URBs", "[bulk][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)

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));
@ -217,9 +231,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

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -33,7 +33,7 @@ Procedure:
- Expect URB to be USB_TRANSFER_STATUS_CANCELED or USB_TRANSFER_STATUS_COMPLETED - Expect URB to be USB_TRANSFER_STATUS_CANCELED or USB_TRANSFER_STATUS_COMPLETED
- Teardown - Teardown
*/ */
TEST_CASE("Test HCD control pipe URBs", "[ctrl][low_speed][full_speed]") TEST_CASE("Test HCD control pipe URBs", "[ctrl][low_speed][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
@ -110,7 +110,7 @@ TEST_CASE("Test HCD control pipe URBs", "[ctrl][low_speed][full_speed]")
/* /*
Test HCD control pipe STALL condition, abort, and clear Test HCD control pipe STALL condition, abort, and clear
@todo this test is not passing with low-speed: test with bus analyzer @todo this test is not passing with low-speed: test with bus analyzer IDF-10995
Purpose: Purpose:
- Test that a control pipe can react to a STALL (i.e., a HCD_PIPE_EVENT_ERROR_STALL event) - Test that a control pipe can react to a STALL (i.e., a HCD_PIPE_EVENT_ERROR_STALL event)
@ -128,7 +128,7 @@ Procedure:
- Dequeue URBs - Dequeue URBs
- Teardown - Teardown
*/ */
TEST_CASE("Test HCD control pipe STALL", "[ctrl][full_speed]") TEST_CASE("Test HCD control pipe STALL", "[ctrl][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
@ -217,6 +217,8 @@ TEST_CASE("Test HCD control pipe STALL", "[ctrl][full_speed]")
/* /*
Test control pipe run-time halt and clear Test control pipe run-time halt and clear
@todo this test is not passing on P4: test with bus analyzer IDF-10996
Purpose: Purpose:
- Test that a control pipe can be halted with HCD_PIPE_CMD_HALT whilst there are ongoing URBs - Test that a control pipe can be halted with HCD_PIPE_CMD_HALT whilst there are ongoing URBs
- Test that a control pipe can be un-halted with a HCD_PIPE_CMD_CLEAR - Test that a control pipe can be un-halted with a HCD_PIPE_CMD_CLEAR

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
@ -40,7 +39,7 @@ Procedure:
- Teardown - Teardown
*/ */
TEST_CASE("Test HCD isochronous pipe URBs", "[isoc][full_speed]") TEST_CASE("Test HCD isochronous pipe URBs", "[isoc][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
// The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing // The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing
@ -115,7 +114,7 @@ Procedure:
- Deallocate URBs - Deallocate URBs
- Teardown - Teardown
*/ */
TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]") TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
// The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing // The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing
@ -164,7 +163,7 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]")
} }
// Add a delay so we start scheduling the transactions at different time in USB frame // Add a delay so we start scheduling the transactions at different time in USB frame
esp_rom_delay_us(ENQUEUE_DELAY * interval + ENQUEUE_DELAY * channel); esp_rom_delay_us(ENQUEUE_DELAY * (interval - 1) + ENQUEUE_DELAY * channel);
// Enqueue URBs // Enqueue URBs
for (int i = 0; i < NUM_URBS; i++) { for (int i = 0; i < NUM_URBS; i++) {
@ -227,7 +226,7 @@ Procedure:
- Free both pipes - Free both pipes
- Teardown - Teardown
*/ */
TEST_CASE("Test HCD isochronous pipe sudden disconnect", "[isoc][full_speed]") TEST_CASE("Test HCD isochronous pipe sudden disconnect", "[isoc][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
// The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing // The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing
@ -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
@ -31,7 +30,7 @@ Procedure:
- Trigger the port disconnection event - Trigger the port disconnection event
- Teardown port and HCD - Teardown port and HCD
*/ */
TEST_CASE("Test HCD port disconnect event, port enabled", "[port][low_speed][full_speed]") TEST_CASE("Test HCD port disconnect event, port enabled", "[port][low_speed][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
printf("Connected %s speed device \n", (char*[]) { printf("Connected %s speed device \n", (char*[]) {
@ -64,7 +63,7 @@ Procedure:
- Teardown port and HCD - Teardown port and HCD
*/ */
TEST_CASE("Test HCD port sudden disconnect", "[port][low_speed][full_speed]") TEST_CASE("Test HCD port sudden disconnect", "[port][low_speed][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
@ -87,7 +86,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));
@ -153,7 +153,7 @@ Procedure:
- Cleanup default pipe - Cleanup default pipe
- Trigger disconnection and teardown - Trigger disconnection and teardown
*/ */
TEST_CASE("Test HCD port suspend and resume", "[port][low_speed][full_speed]") TEST_CASE("Test HCD port suspend and resume", "[port][low_speed][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
@ -207,7 +207,7 @@ Procedure:
- Check that a disconnection still works after disable - Check that a disconnection still works after disable
- Teardown - Teardown
*/ */
TEST_CASE("Test HCD port disable", "[port][low_speed][full_speed]") TEST_CASE("Test HCD port disable", "[port][low_speed][full_speed][high_speed]")
{ {
usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
@ -290,12 +290,12 @@ 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
} }
TEST_CASE("Test HCD port command bailout", "[port][low_speed][full_speed]") TEST_CASE("Test HCD port command bailout", "[port][low_speed][full_speed][high_speed]")
{ {
test_hcd_wait_for_conn(port_hdl); // Trigger a connection test_hcd_wait_for_conn(port_hdl); // Trigger a connection
vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS)
@ -314,7 +314,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"
@ -182,7 +181,7 @@ static void test_async_client_cb(const usb_host_client_event_msg_t *event_msg, v
} }
} }
TEST_CASE("Test USB Host async API", "[usb_host][full_speed][low_speed]") TEST_CASE("Test USB Host async API", "[usb_host][low_speed][full_speed][high_speed]")
{ {
// Register two clients // Register two clients
client_test_stage_t client0_stage = CLIENT_TEST_STAGE_NONE; client_test_stage_t client0_stage = CLIENT_TEST_STAGE_NONE;
@ -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"
@ -34,7 +33,7 @@ Procedure:
#define TEST_DCONN_NO_CLIENT_ITERATIONS 3 #define TEST_DCONN_NO_CLIENT_ITERATIONS 3
TEST_CASE("Test USB Host sudden disconnection (no client)", "[usb_host][full_speed][low_speed]") TEST_CASE("Test USB Host sudden disconnection (no client)", "[usb_host][low_speed][full_speed][high_speed]")
{ {
bool connected = false; bool connected = false;
int dconn_iter = 0; int dconn_iter = 0;
@ -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;
} }
@ -82,7 +83,7 @@ Procedure:
#define TEST_FORCE_DCONN_NUM_TRANSFERS 3 #define TEST_FORCE_DCONN_NUM_TRANSFERS 3
#define TEST_MSC_SCSI_TAG 0xDEADBEEF #define TEST_MSC_SCSI_TAG 0xDEADBEEF
TEST_CASE("Test USB Host sudden disconnection (single client)", "[usb_host][full_speed]") TEST_CASE("Test USB Host sudden disconnection (single client)", "[usb_host][full_speed][high_speed]")
{ {
// Create task to run client that communicates with MSC SCSI interface // Create task to run client that communicates with MSC SCSI interface
const dev_msc_info_t *dev_info = dev_msc_get_info(); const dev_msc_info_t *dev_info = dev_msc_get_info();
@ -131,7 +132,7 @@ Procedure:
#define TEST_ENUM_ITERATIONS 3 #define TEST_ENUM_ITERATIONS 3
TEST_CASE("Test USB Host enumeration", "[usb_host][full_speed]") TEST_CASE("Test USB Host enumeration", "[usb_host][full_speed][high_speed]")
{ {
// Create task to run client that checks the enumeration of the device // Create task to run client that checks the enumeration of the device
TaskHandle_t task_hdl; TaskHandle_t task_hdl;

View File

@ -540,8 +540,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();
// Start the root hub if (!config->root_port_unpowered) {
ESP_ERROR_CHECK(hub_root_start()); // Start the root hub
ESP_ERROR_CHECK(hub_root_start());
}
ret = ESP_OK; ret = ESP_OK;
return ret; return ret;
@ -694,6 +697,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 -------------------------