Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(esp_tinyusb): Added tusb_teardown() call while tinyusb_driver_uninstall() #39

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions device/esp_tinyusb/include/tinyusb.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ typedef struct {
*/
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config);

/**
* @brief This is an all-in-one helper function, including:
* 1. Stops the task to handle usb events
* 2. TinyUSB stack tearing down
* 2. Freeing resources after descriptors preparation
* 3. Deletes USB PHY
*
* @retval ESP_FAIL Uninstall driver or tinyusb stack failed because of internal error
* @retval ESP_OK Uninstall driver, tinyusb stack and USB PHY successfully
*/
esp_err_t tinyusb_driver_uninstall(void);

#ifdef __cplusplus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,5 @@ TEST_CASE("bvalid_signal", "[esp_tinyusb][usb_device]")

// Cleanup
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task());
}
#endif // SOC_USB_OTG_SUPPORTED
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ TEST_CASE("descriptors_config_all_default", "[esp_tinyusb][usb_device]")
TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn());
// Cleanup
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task());
__test_free();
}

Expand All @@ -163,7 +162,6 @@ TEST_CASE("descriptors_config_device", "[esp_tinyusb][usb_device]")
TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn());
// Cleanup
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task());
__test_free();
}

Expand All @@ -186,7 +184,6 @@ TEST_CASE("descriptors_config_device_and_config", "[esp_tinyusb][usb_device]")
TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn());
// Cleanup
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task());
__test_free();
}

Expand All @@ -208,7 +205,6 @@ TEST_CASE("descriptors_config_device_and_fs_config_only", "[esp_tinyusb][usb_dev
TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn());
// Cleanup
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task());
__test_free();
}

Expand All @@ -229,7 +225,6 @@ TEST_CASE("descriptors_config_device_and_hs_config_only", "[esp_tinyusb][usb_dev
TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn());
// Cleanup
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task());
__test_free();
}

Expand All @@ -250,7 +245,6 @@ TEST_CASE("descriptors_config_all_configured", "[esp_tinyusb][usb_device]")
TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn());
// Cleanup
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
TEST_ASSERT_EQUAL(ESP_OK, tusb_stop_task());
__test_free();
}
#endif // TUD_OPT_HIGH_SPEED
Expand Down
9 changes: 9 additions & 0 deletions device/esp_tinyusb/test_apps/teardown_device/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)

project(test_app_teardown_device)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
idf_component_register(SRC_DIRS .
INCLUDE_DIRS .
REQUIRES unity
WHOLE_ARCHIVE)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_tinyusb:
version: "*"
override_path: "../../../"
62 changes: 62 additions & 0 deletions device/esp_tinyusb/test_apps/teardown_device/main/test_app_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "unity_test_runner.h"
#include "unity_test_utils_memory.h"

void app_main(void)
{
/*
_ _ _
| | (_) | |
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
| |______ __/ |
|_|______| |___/
_____ _____ _____ _____
|_ _| ___/ ___|_ _|
| | | |__ \ `--. | |
| | | __| `--. \ | |
| | | |___/\__/ / | |
\_/ \____/\____/ \_/
*/

printf(" _ _ _ \n");
printf(" | | (_) | | \n");
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
printf(" | |______ __/ | \n");
printf(" |_|______| |___/ \n");
printf(" _____ _____ _____ _____ \n");
printf("|_ _| ___/ ___|_ _| \n");
printf(" | | | |__ \\ `--. | | \n");
printf(" | | | __| `--. \\ | | \n");
printf(" | | | |___/\\__/ / | | \n");
printf(" \\_/ \\____/\\____/ \\_/ \n");

unity_utils_setup_heap_record(80);
unity_utils_set_leak_level(128);
unity_run_menu();
}

/* setUp runs before every test */
void setUp(void)
{
unity_utils_record_free_mem();
}

/* tearDown runs after every test */
void tearDown(void)
{
unity_utils_evaluate_leaks();
}
167 changes: 167 additions & 0 deletions device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "soc/soc_caps.h"
// #if SOC_USB_OTG_SUPPORTED

//
#include <stdio.h>
#include <string.h>
//
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
//
#include "esp_system.h"
#include "esp_log.h"
#include "esp_err.h"
//
#include "unity.h"
#include "tinyusb.h"
#include "tusb_cdc_acm.h"

static const char *TEARDOWN_CMD = "teardown";
// Delay between device connection, required for the Host to handle device disconnection/connection without errors
#define TEARDOWN_DELAY_MS 2000
#define TEARDOWN_AMOUNT 10

static const tusb_desc_device_t cdc_device_descriptor = {
.bLength = sizeof(cdc_device_descriptor),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_ESPRESSIF_VID,
.idProduct = 0x4002,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};

static const uint16_t cdc_desc_config_len = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN;
static const uint8_t cdc_desc_configuration[] = {
TUD_CONFIG_DESCRIPTOR(1, 4, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, (TUD_OPT_HIGH_SPEED ? 512 : 64)),
};

#if (TUD_OPT_HIGH_SPEED)
static const tusb_desc_device_qualifier_t device_qualifier = {
.bLength = sizeof(tusb_desc_device_qualifier_t),
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.bNumConfigurations = 0x01,
.bReserved = 0
};
#endif // TUD_OPT_HIGH_SPEED

static QueueHandle_t rx_queue;
static uint8_t rx_buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1];

typedef struct {
int itf; // Interface number
uint8_t data[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1]; // Data buffer
size_t len; // Number of bytes received
} rx_pkt_t;

static void test_rx_enqueue_pkt(int itf, uint8_t *buf, size_t size)
{
rx_pkt_t rx_pkt = {
.itf = itf,
.len = size,
};
memcpy(rx_pkt.data, buf, size);
xQueueSend(rx_queue, &rx_pkt, 0);
}

static void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event)
{
size_t rx_size = 0;
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_cdcacm_read(itf, rx_buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE, &rx_size));
test_rx_enqueue_pkt(itf, rx_buf, rx_size);
}

/**
* @brief TinyUSB Teardown specific testcase
*/
TEST_CASE("tinyusb_teardown", "[esp_tinyusb][teardown]")
{
rx_pkt_t rx_pkt;
// Create FreeRTOS primitives
rx_queue = xQueueCreate(5, sizeof(rx_pkt_t));
TEST_ASSERT(rx_queue);

// TinyUSB driver configuration
const tinyusb_config_t tusb_cfg = {
.device_descriptor = &cdc_device_descriptor,
.string_descriptor = NULL,
.string_descriptor_count = 0,
.external_phy = false,
#if (TUD_OPT_HIGH_SPEED)
.fs_configuration_descriptor = cdc_desc_configuration,
.hs_configuration_descriptor = cdc_desc_configuration,
.qualifier_descriptor = &device_qualifier,
#else
.configuration_descriptor = cdc_desc_configuration,
#endif // TUD_OPT_HIGH_SPEED
};

// TinyUSB ACM Driver configuration
tinyusb_config_cdcacm_t acm_cfg = {
.usb_dev = TINYUSB_USBDEV_0,
.cdc_port = TINYUSB_CDC_ACM_0,
.rx_unread_buf_sz = 64,
.callback_rx = &tinyusb_cdc_rx_callback,
.callback_rx_wanted_char = NULL,
.callback_line_state_changed = NULL,
.callback_line_coding_changed = NULL
};
int attempts = TEARDOWN_AMOUNT;
while (1) {
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DELAY_MS));
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
// Init CDC 0
TEST_ASSERT_FALSE(tusb_cdc_acm_initialized(TINYUSB_CDC_ACM_0));
TEST_ASSERT_EQUAL(ESP_OK, tusb_cdc_acm_init(&acm_cfg));
TEST_ASSERT_TRUE(tusb_cdc_acm_initialized(TINYUSB_CDC_ACM_0));

// Wait for the pytest poke
while (1) {
if (xQueueReceive(rx_queue, &rx_pkt, portMAX_DELAY)) {
if (rx_pkt.len) {
/* echoed back */
TEST_ASSERT_EQUAL(rx_pkt.len, tinyusb_cdcacm_write_queue(rx_pkt.itf, rx_pkt.data, rx_pkt.len));
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_cdcacm_write_flush(rx_pkt.itf, pdMS_TO_TICKS(100)));
if (strncmp(TEARDOWN_CMD, (const char *) rx_pkt.data, rx_pkt.len) == 0) {
// Wait for the host
attempts--;
break;
}
}
}
}
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DELAY_MS));
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_cdcacm_unregister_callback(TINYUSB_CDC_ACM_0, CDC_EVENT_RX));
TEST_ASSERT_EQUAL(ESP_OK, tusb_cdc_acm_deinit(TINYUSB_CDC_ACM_0));
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());

if (attempts == 0) {
break;
}
}
// Remove primitives
vQueueDelete(rx_queue);
// All attempts should be completed
TEST_ASSERT_EQUAL(0, attempts);
}

// #endif
Loading
Loading