usb: Add USB Host Library sudden disconnect tests

pull/6613/merge
Darian Leung 2021-10-27 15:50:21 +08:00
rodzic 6a12e28333
commit 54b6c902d3
14 zmienionych plików z 435 dodań i 70 usunięć

Wyświetl plik

@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/usb_wrap_struct.h"
#include "test_usb_common.h"
void test_usb_force_conn_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);
}
usb_wrap_dev_t *wrap = &USB_WRAP;
if (connected) {
//Disable test mode to return to previous internal PHY configuration
wrap->test_conf.test_enable = 0;
} else {
/*
Mimic a disconnection by using the internal PHY's test mode.
Force Output Enable to 1 (even if the controller isn't outputting). With test_tx_dp and test_tx_dm set to 0,
this will look like a disconnection.
*/
wrap->test_conf.val = 0;
wrap->test_conf.test_usb_wrap_oe = 1;
wrap->test_conf.test_enable = 1;
}
}

Wyświetl plik

@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
/**
* @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_force_conn_state(bool connected, TickType_t delay_ticks);

Wyświetl plik

@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
@ -20,6 +12,8 @@
// ---------------------------------------------------- MSC SCSI -------------------------------------------------------
const char *MSC_CLIENT_TAG = "MSC Client";
void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, bool is_read, int offset, int num_sectors, uint32_t tag)
{
cbw->dCBWSignature = 0x43425355; //Fixed value

Wyświetl plik

@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
This header contains bare-bone mock implementations of some device classes in order to test various layers of the USB
@ -29,6 +21,8 @@ extern "C" {
// ---------------------------------------------------- MSC SCSI -------------------------------------------------------
const char *MSC_CLIENT_TAG;
/*
Note: The mock MSC SCSI tests requires that USB flash drive be connected. The flash drive should...

Wyświetl plik

@ -18,6 +18,7 @@
#include "usb_private.h"
#include "usb/usb_types_ch9.h"
#include "test_hcd_common.h"
#include "test_usb_common.h"
#define PORT_NUM 1
#define EVENT_QUEUE_LEN 5
@ -135,28 +136,6 @@ int test_hcd_get_num_pipe_events(hcd_pipe_handle_t pipe_hdl)
// ----------------------------------------------- Driver/Port Related -------------------------------------------------
void test_hcd_force_conn_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);
}
usb_wrap_dev_t *wrap = &USB_WRAP;
if (connected) {
//Disable test mode to return to previous internal PHY configuration
wrap->test_conf.test_enable = 0;
} else {
/*
Mimic a disconnection by using the internal PHY's test mode.
Force Output Enable to 1 (even if the controller isn't outputting). With test_tx_dp and test_tx_dm set to 0,
this will look like a disconnection.
*/
wrap->test_conf.val = 0;
wrap->test_conf.test_usb_wrap_oe = 1;
wrap->test_conf.test_enable = 1;
}
}
hcd_port_handle_t test_hcd_setup(void)
{
//Create a queue for port callback to queue up port events
@ -178,7 +157,7 @@ hcd_port_handle_t test_hcd_setup(void)
TEST_ASSERT_EQUAL(ESP_OK, hcd_port_init(PORT_NUM, &port_config, &port_hdl));
TEST_ASSERT_NOT_EQUAL(NULL, port_hdl);
TEST_ASSERT_EQUAL(HCD_PORT_STATE_NOT_POWERED, hcd_port_get_state(port_hdl));
test_hcd_force_conn_state(false, 0); //Force disconnected state on PHY
test_usb_force_conn_state(false, 0); //Force disconnected state on PHY
return port_hdl;
}
@ -201,7 +180,7 @@ usb_speed_t test_hcd_wait_for_conn(hcd_port_handle_t port_hdl)
TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISCONNECTED, hcd_port_get_state(port_hdl));
//Wait for connection event
printf("Waiting for connection\n");
test_hcd_force_conn_state(true, pdMS_TO_TICKS(100)); //Allow for connected state on PHY
test_usb_force_conn_state(true, pdMS_TO_TICKS(100)); //Allow for connected state on PHY
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_STATE_DISABLED, hcd_port_get_state(port_hdl));
@ -230,7 +209,7 @@ void test_hcd_wait_for_disconn(hcd_port_handle_t port_hdl, bool already_disabled
}
//Wait for a safe disconnect
printf("Waiting for disconnection\n");
test_hcd_force_conn_state(false, pdMS_TO_TICKS(100)); //Force disconnected state on PHY
test_usb_force_conn_state(false, pdMS_TO_TICKS(100)); //Force disconnected state on PHY
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_STATE_RECOVERY, hcd_port_get_state(port_hdl));

Wyświetl plik

@ -48,14 +48,6 @@ int test_hcd_get_num_pipe_events(hcd_pipe_handle_t pipe_hdl);
// ----------------------------------------------- Driver/Port Related -------------------------------------------------
/**
* @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_hcd_force_conn_state(bool connected, TickType_t delay_ticks);
/**
* @brief Sets up the HCD and initializes an HCD port.
*
@ -73,7 +65,7 @@ void test_hcd_teardown(hcd_port_handle_t port_hdl);
/**
* @brief Wait for a connection on an HCD port
*
* @note This function will internally call test_hcd_force_conn_state() to allow for a connection
* @note This function will internally call test_usb_force_conn_state() to allow for a connection
*
* @param port_hdl Port handle
* @return usb_speed_t Speed of the connected device
@ -83,7 +75,7 @@ usb_speed_t test_hcd_wait_for_conn(hcd_port_handle_t port_hdl);
/**
* @brief Wait for a disconnection on an HCD port
*
* @note This fucntion will internally call test_hcd_force_conn_state() to force a disconnection
* @note This fucntion will internally call test_usb_force_conn_state() to force a disconnection
*
* @param port_hdl Port handle
* @param already_disabled Whether the HCD port is already in the disabled state

Wyświetl plik

@ -11,6 +11,7 @@
#include "unity.h"
#include "test_utils.h"
#include "test_usb_mock_classes.h"
#include "test_usb_common.h"
#include "test_hcd_common.h"
#define NUM_URBS 3
@ -154,7 +155,7 @@ TEST_CASE("Test HCD isochronous pipe sudden disconnect", "[hcd][ignore]")
}
//Add a short delay to let the transfers run for a bit
esp_rom_delay_us(POST_ENQUEUE_DELAY_US);
test_hcd_force_conn_state(false, 0);
test_usb_force_conn_state(false, 0);
//Disconnect event should have occurred. Handle the port event
test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION);
TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl));

Wyświetl plik

@ -10,6 +10,7 @@
#include "unity.h"
#include "esp_rom_sys.h"
#include "test_utils.h"
#include "test_usb_common.h"
#include "test_hcd_common.h"
#define TEST_DEV_ADDR 0
@ -65,7 +66,7 @@ TEST_CASE("Test HCD port sudden disconnect", "[hcd][ignore]")
}
//Add a short delay to let the transfers run for a bit
esp_rom_delay_us(POST_ENQUEUE_DELAY_US);
test_hcd_force_conn_state(false, 0);
test_usb_force_conn_state(false, 0);
//Disconnect event should have occurred. Handle the port event
test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION);
TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl));
@ -304,7 +305,7 @@ static void concurrent_task(void *arg)
xSemaphoreTake(sync_sem, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(10)); //Give a short delay let reset command start in main thread
//Force a disconnection
test_hcd_force_conn_state(false, 0);
test_usb_force_conn_state(false, 0);
vTaskDelay(portMAX_DELAY); //Block forever and wait to be deleted
}

Wyświetl plik

@ -15,3 +15,5 @@ typedef struct {
} msc_client_test_param_t;
void msc_client_async_seq_task(void *arg);
void msc_client_async_dconn_task(void *arg);

Wyświetl plik

@ -0,0 +1,246 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "test_usb_mock_classes.h"
#include "test_usb_common.h"
#include "msc_client.h"
#include "usb/usb_host.h"
#include "unity.h"
#include "test_utils.h"
/*
Implementation of an asynchronous MSC client used for USB Host disconnection test.
- The MSC client will:
- Register itself as a client
- Receive USB_HOST_CLIENT_EVENT_NEW_DEV event message, and open the device
- Allocate IN and OUT transfer objects for MSC SCSI transfers
- Trigger a single MSC SCSI transfer
- Split the data stage into multiple transfers (so that the endpoint multiple queued up transfers)
- Cause a disconnection mid-way through the data stage
- All of the transfers should be automatically deqeueud
- Then a USB_HOST_CLIENT_EVENT_DEV_GONE event should occur afterwards
- Free transfer objects
- Close device
- Deregister MSC client
*/
#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
#define MSC_CLIENT_MAX_EVENT_MSGS 5
typedef enum {
TEST_STAGE_WAIT_CONN,
TEST_STAGE_DEV_OPEN,
TEST_STAGE_MSC_RESET,
TEST_STAGE_MSC_CBW,
TEST_STAGE_MSC_DATA_DCONN,
TEST_STAGE_DEV_CLOSE,
} test_stage_t;
typedef struct {
msc_client_test_param_t test_param;
test_stage_t cur_stage;
test_stage_t next_stage;
uint8_t dev_addr_to_open;
usb_host_client_handle_t client_hdl;
usb_device_handle_t dev_hdl;
int num_data_transfers;
int event_count;
} msc_client_obj_t;
static void msc_reset_cbw_transfer_cb(usb_transfer_t *transfer)
{
msc_client_obj_t *msc_obj = (msc_client_obj_t *)transfer->context;
//We expect the reset and CBW transfers to complete with no issues
TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, transfer->status);
TEST_ASSERT_EQUAL(transfer->num_bytes, transfer->actual_num_bytes);
switch (msc_obj->cur_stage) {
case TEST_STAGE_MSC_RESET:
msc_obj->next_stage = TEST_STAGE_MSC_CBW;
break;
case TEST_STAGE_MSC_CBW:
msc_obj->next_stage = TEST_STAGE_MSC_DATA_DCONN;
break;
default:
abort();
break;
}
}
static void msc_data_transfer_cb(usb_transfer_t *transfer)
{
//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);
if (transfer->status == USB_TRANSFER_STATUS_COMPLETED) {
TEST_ASSERT_EQUAL(transfer->num_bytes, transfer->actual_num_bytes);
} else {
TEST_ASSERT_EQUAL(0, transfer->actual_num_bytes);
}
msc_client_obj_t *msc_obj = (msc_client_obj_t *)transfer->context;
msc_obj->event_count++;
//If all transfers dequeued and device gone event occurred. Go to next stage
if (msc_obj->event_count >= msc_obj->num_data_transfers + 1) {
msc_obj->next_stage = TEST_STAGE_DEV_CLOSE;
}
}
static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg)
{
msc_client_obj_t *msc_obj = (msc_client_obj_t *)arg;
switch (event_msg->event) {
case USB_HOST_CLIENT_EVENT_NEW_DEV:
TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, msc_obj->cur_stage);
msc_obj->next_stage = TEST_STAGE_DEV_OPEN;
msc_obj->dev_addr_to_open = event_msg->new_dev.address;
break;
case USB_HOST_CLIENT_EVENT_DEV_GONE:
msc_obj->event_count++;
//If all transfers dequeued and device gone event occurred. Go to next stage
if (msc_obj->event_count >= msc_obj->num_data_transfers + 1) {
msc_obj->next_stage = TEST_STAGE_DEV_CLOSE;
}
break;
default:
abort(); //Should never occur in this test
break;
}
}
void msc_client_async_dconn_task(void *arg)
{
msc_client_obj_t msc_obj;
memcpy(&msc_obj.test_param, arg, sizeof(msc_client_test_param_t));
msc_obj.cur_stage = TEST_STAGE_WAIT_CONN;
msc_obj.next_stage = TEST_STAGE_WAIT_CONN;
msc_obj.dev_addr_to_open = 0;
msc_obj.client_hdl = NULL;
msc_obj.dev_hdl = NULL;
msc_obj.num_data_transfers = msc_obj.test_param.num_sectors_per_xfer / MOCK_MSC_SCSI_SECTOR_SIZE;
msc_obj.event_count = 0;
//Register client
usb_host_client_config_t client_config = {
.client_event_callback = msc_client_event_cb,
.callback_arg = (void *)&msc_obj,
.max_num_event_msg = MSC_CLIENT_MAX_EVENT_MSGS,
};
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &msc_obj.client_hdl));
//Allocate transfers
usb_transfer_t *xfer_out; //Must be large enough to contain CBW and MSC reset control transfer
usb_transfer_t *xfer_in[msc_obj.num_data_transfers]; //We manually split the data stage into multiple transfers
size_t xfer_out_size = MAX(sizeof(mock_msc_bulk_cbw_t), sizeof(usb_setup_packet_t));
size_t xfer_in_size = MOCK_MSC_SCSI_SECTOR_SIZE;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(xfer_out_size, 0, &xfer_out));
xfer_out->context = (void *)&msc_obj;
for (int i = 0; i < msc_obj.num_data_transfers; i++) {
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(xfer_in_size, 0, &xfer_in[i]));
xfer_in[i]->context = (void *)&msc_obj;
}
//Wait to be started by main thread
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
ESP_LOGD(MSC_CLIENT_TAG, "Starting");
bool exit_loop = false;
bool skip_event_handling = false;
while (!exit_loop) {
if (!skip_event_handling) {
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_handle_events(msc_obj.client_hdl, portMAX_DELAY));
}
skip_event_handling = false;
if (msc_obj.cur_stage == msc_obj.next_stage) {
continue;
}
msc_obj.cur_stage = msc_obj.next_stage;
switch (msc_obj.cur_stage) {
case TEST_STAGE_DEV_OPEN: {
ESP_LOGD(MSC_CLIENT_TAG, "Open");
//Open the device
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr_to_open, &msc_obj.dev_hdl));
//Target our transfers to the device
xfer_out->device_handle = msc_obj.dev_hdl;
xfer_out->callback = msc_reset_cbw_transfer_cb;
for (int i = 0; i < msc_obj.num_data_transfers; i++) {
xfer_in[i]->device_handle = msc_obj.dev_hdl;
xfer_in[i]->callback = msc_data_transfer_cb;
}
//Check the VID/PID of the opened device
const usb_device_desc_t *device_desc;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc));
TEST_ASSERT_EQUAL(msc_obj.test_param.idVendor, device_desc->idVendor);
TEST_ASSERT_EQUAL(msc_obj.test_param.idProduct, device_desc->idProduct);
//Claim the MSC interface
TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(msc_obj.client_hdl, msc_obj.dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING));
msc_obj.next_stage = TEST_STAGE_MSC_RESET;
skip_event_handling = true; //Need to execute TEST_STAGE_MSC_RESET
break;
}
case TEST_STAGE_MSC_RESET: {
ESP_LOGD(MSC_CLIENT_TAG, "MSC Reset");
//Send an MSC SCSI interface reset
MOCK_MSC_SCSI_REQ_INIT_RESET((usb_setup_packet_t *)xfer_out->data_buffer, MOCK_MSC_SCSI_INTF_NUMBER);
xfer_out->num_bytes = sizeof(usb_setup_packet_t);
xfer_out->bEndpointAddress = 0;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit_control(msc_obj.client_hdl, xfer_out));
//Next stage set from transfer callback
break;
}
case TEST_STAGE_MSC_CBW: {
ESP_LOGD(MSC_CLIENT_TAG, "CBW");
mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)xfer_out->data_buffer, true, 0, msc_obj.test_param.num_sectors_per_xfer, msc_obj.test_param.msc_scsi_xfer_tag);
xfer_out->num_bytes = sizeof(mock_msc_bulk_cbw_t);
xfer_out->bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR;
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_out));
//Next stage set from transfer callback
break;
}
case TEST_STAGE_MSC_DATA_DCONN: {
ESP_LOGD(MSC_CLIENT_TAG, "Data and disconnect");
//Setup the Data IN transfers
for (int i = 0; i < msc_obj.num_data_transfers; i++) {
xfer_in[i]->num_bytes = usb_round_up_to_mps(MOCK_MSC_SCSI_SECTOR_SIZE, MOCK_MSC_SCSI_BULK_EP_MPS);
xfer_in[i]->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR;
}
//Submit those transfers
for (int i = 0; i < msc_obj.num_data_transfers; i++) {
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in[i]));
}
//Trigger a disconnect
test_usb_force_conn_state(false, 0);
//Next stage set from transfer callback
break;
}
case TEST_STAGE_DEV_CLOSE: {
ESP_LOGD(MSC_CLIENT_TAG, "Close");
TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(msc_obj.client_hdl, msc_obj.dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER));
TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl));
exit_loop = true;
break;
}
default:
abort();
break;
}
}
//Free transfers
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(xfer_out));
for (int i = 0; i < msc_obj.num_data_transfers; i++) {
TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(xfer_in[i]));
}
//Deregister the client
TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(msc_obj.client_hdl));
ESP_LOGD(MSC_CLIENT_TAG, "Done");
vTaskDelete(NULL);
}

Wyświetl plik

@ -6,10 +6,9 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "test_usb_mock_classes.h"
@ -38,8 +37,6 @@ Implementation of an MSC client used for USB Host Tests
#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
#define MSC_CLIENT_MAX_EVENT_MSGS 5
const char *MSC_CLIENT_TAG = "MSC Client";
typedef enum {
TEST_STAGE_WAIT_CONN,
TEST_STAGE_DEV_OPEN,

Wyświetl plik

@ -8,6 +8,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "test_usb_mock_classes.h"
#include "msc_client.h"

Wyświetl plik

@ -0,0 +1,111 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "test_usb_common.h"
#include "test_usb_mock_classes.h"
#include "msc_client.h"
#include "ctrl_client.h"
#include "usb/usb_host.h"
#include "unity.h"
#include "test_utils.h"
// --------------------------------------------------- Test Cases ------------------------------------------------------
//Safe approximation of time it takes to connect and enumerate the device
#define TEST_FORCE_DCONN_DELAY_MS 400
static void trigger_dconn_timer_cb(TimerHandle_t xTimer)
{
printf("Forcing Sudden Disconnect\n");
test_usb_force_conn_state(false, 0);
}
TEST_CASE("Test USB Host sudden disconnection (no client)", "[usb_host][ignore]")
{
//Install USB Host Library
usb_host_config_t host_config = {
.intr_flags = ESP_INTR_FLAG_LEVEL1,
};
ESP_ERROR_CHECK(usb_host_install(&host_config));
printf("Installed\n");
//Allocate timer to force disconnection after a short delay
TimerHandle_t timer_hdl = xTimerCreate("dconn",
pdMS_TO_TICKS(TEST_FORCE_DCONN_DELAY_MS),
pdFALSE,
NULL,
trigger_dconn_timer_cb);
TEST_ASSERT_NOT_EQUAL(NULL, timer_hdl);
TEST_ASSERT_EQUAL(pdPASS, xTimerStart(timer_hdl, portMAX_DELAY));
while (1) {
//Start handling system events
uint32_t event_flags;
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
printf("All devices cleaned up\n");
break;
}
}
//Cleanup timer
TEST_ASSERT_EQUAL(pdPASS, xTimerDelete(timer_hdl, portMAX_DELAY));
//Clean up USB Host
ESP_ERROR_CHECK(usb_host_uninstall());
}
#define TEST_FORCE_DCONN_NUM_TRANSFERS 3
#define TEST_MSC_SCSI_TAG 0xDEADBEEF
TEST_CASE("Test USB Host sudden disconnection (single client)", "[usb_host][ignore]")
{
//Install USB Host
usb_host_config_t host_config = {
.intr_flags = ESP_INTR_FLAG_LEVEL1,
};
ESP_ERROR_CHECK(usb_host_install(&host_config));
printf("Installed\n");
//Create task to run client that communicates with MSC SCSI interface
msc_client_test_param_t params = {
.num_sectors_to_read = 1, //Unused by disconnect MSC client
.num_sectors_per_xfer = TEST_FORCE_DCONN_NUM_TRANSFERS * MOCK_MSC_SCSI_SECTOR_SIZE,
.msc_scsi_xfer_tag = TEST_MSC_SCSI_TAG,
.idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR,
.idProduct = MOCK_MSC_SCSI_DEV_ID_PRODUCT,
};
TaskHandle_t task_hdl;
xTaskCreatePinnedToCore(msc_client_async_dconn_task, "async", 4096, (void *)&params, 2, &task_hdl, 0);
//Start the task
xTaskNotifyGive(task_hdl);
bool all_clients_gone = false;
bool all_dev_free = false;
while (!all_clients_gone || !all_dev_free) {
//Start handling system events
uint32_t event_flags;
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
printf("No more clients\n");
all_clients_gone = true;
}
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
printf("All device's freed\n");
all_dev_free = true;
}
}
//Short delay to allow task to be cleaned up
vTaskDelay(10);
//Clean up USB Host
ESP_ERROR_CHECK(usb_host_uninstall());
}

Wyświetl plik

@ -2538,8 +2538,6 @@ components/unity/include/unity_fixture_extras.h
components/unity/include/unity_test_runner.h
components/unity/unity_port_esp32.c
components/unity/unity_runner.c
components/usb/test/common/test_usb_mock_classes.c
components/usb/test/common/test_usb_mock_classes.h
components/usb/test/hcd/test_hcd_ctrl.c
components/vfs/include/esp_vfs_common.h
components/vfs/include/esp_vfs_eventfd.h