-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(teardown_test): Added the test_app for teardowning the cdc de…
…vice
- Loading branch information
Showing
7 changed files
with
389 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
4 changes: 4 additions & 0 deletions
4
device/esp_tinyusb/test_apps/teardown_device/main/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
5 changes: 5 additions & 0 deletions
5
device/esp_tinyusb/test_apps/teardown_device/main/idf_component.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
62
device/esp_tinyusb/test_apps/teardown_device/main/test_app_main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
197 changes: 197 additions & 0 deletions
197
device/esp_tinyusb/test_apps/teardown_device/main/test_teardown.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
/* | ||
* 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 "freertos/semphr.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 *TAG = "teardown"; | ||
|
||
SemaphoreHandle_t wait_mount = NULL; | ||
SemaphoreHandle_t wait_terminal = NULL; | ||
SemaphoreHandle_t wait_command = NULL; | ||
|
||
static uint8_t rx_buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1]; | ||
static uint8_t tx_buf[CONFIG_TINYUSB_CDC_TX_BUFSIZE + 1] = { 0 }; | ||
|
||
#define TEARDOWN_CMD_KEY 0xAA | ||
#define TEARDOWN_RPL_KEY 0x55 | ||
#define TEARDOWN_CMD_RPL_SIZE ((TUD_OPT_HIGH_SPEED ? 512 : 64)) | ||
#define TEARDOWN_ATTACH_TIMEOUT_MS 5000 | ||
#define TEARDOWN_COMMAND_TIMEOUT_MS 5000 | ||
#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, 2, 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 void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event) | ||
{ | ||
// Something was received | ||
xSemaphoreGive(wait_command); | ||
} | ||
|
||
/** | ||
* @brief CDC device line change callback | ||
* | ||
* CDC device signals, that the DTR, RTS states changed | ||
* | ||
* @param[in] itf CDC device index | ||
* @param[in] event CDC event type | ||
*/ | ||
void tinyusb_cdc_line_state_changed_callback(int itf, cdcacm_event_t *event) | ||
{ | ||
int dtr = event->line_state_changed_data.dtr; | ||
int rts = event->line_state_changed_data.rts; | ||
ESP_LOGD(TAG, "Line state changed on channel %d: DTR:%d, RTS:%d", itf, dtr, rts); | ||
|
||
// Terminal: | ||
// dtr==1 && rts==1 - connected | ||
// dtr==0 && rts==0 - disconnected | ||
xSemaphoreGive(wait_terminal); | ||
} | ||
|
||
// Invoked when device is mounted | ||
void tud_mount_cb(void) | ||
{ | ||
xSemaphoreGive(wait_mount); | ||
} | ||
|
||
/** | ||
* @brief TinyUSB Teardown specific testcase | ||
*/ | ||
TEST_CASE("tinyusb_teardown", "[esp_tinyusb][teardown]") | ||
{ | ||
size_t rx_size = 0; | ||
|
||
wait_mount = xSemaphoreCreateBinary(); | ||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount); | ||
wait_command = xSemaphoreCreateBinary(); | ||
TEST_ASSERT_NOT_EQUAL(NULL, wait_command); | ||
wait_terminal = xSemaphoreCreateBinary(); | ||
TEST_ASSERT_NOT_EQUAL(NULL, wait_terminal); | ||
|
||
// Prep reply | ||
for (int i = 0; i < TEARDOWN_CMD_RPL_SIZE; i++) { | ||
tx_buf[i] = TEARDOWN_RPL_KEY; | ||
} | ||
|
||
// 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 | ||
const 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 = &tinyusb_cdc_line_state_changed_callback, | ||
.callback_line_coding_changed = NULL | ||
}; | ||
|
||
int attempts = TEARDOWN_AMOUNT; | ||
// TODO: Run the test while attempts not 0 or the timeout occurred | ||
while (attempts) { | ||
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 usb event | ||
ESP_LOGD(TAG, "wait dev mounted..."); | ||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_ATTACH_TIMEOUT_MS))); | ||
ESP_LOGD(TAG, "wait terminal connection..."); | ||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_terminal, pdMS_TO_TICKS(TEARDOWN_ATTACH_TIMEOUT_MS))); | ||
// Wait for the command | ||
ESP_LOGD(TAG, "wait command..."); | ||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_command, pdMS_TO_TICKS(TEARDOWN_COMMAND_TIMEOUT_MS))); | ||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_cdcacm_read(TINYUSB_CDC_ACM_0, rx_buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE, &rx_size)); | ||
for (int i = 0; i < TEARDOWN_CMD_RPL_SIZE; i++) { | ||
TEST_ASSERT_EQUAL(TEARDOWN_CMD_KEY, rx_buf[i]); | ||
} | ||
ESP_LOGD(TAG, "command received"); | ||
// Reply the response sequence | ||
ESP_LOGD(TAG, "send response..."); | ||
TEST_ASSERT_EQUAL(TEARDOWN_CMD_RPL_SIZE, tinyusb_cdcacm_write_queue(TINYUSB_CDC_ACM_0, tx_buf, TEARDOWN_CMD_RPL_SIZE)); | ||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_cdcacm_write_flush(TINYUSB_CDC_ACM_0, pdMS_TO_TICKS(1000))); | ||
ESP_LOGD(TAG, "wait for terminal disconnection"); | ||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_terminal, pdMS_TO_TICKS(TEARDOWN_ATTACH_TIMEOUT_MS))); | ||
// Teardown | ||
attempts--; | ||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_cdcacm_unregister_callback(TINYUSB_CDC_ACM_0, CDC_EVENT_RX)); | ||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_cdcacm_unregister_callback(TINYUSB_CDC_ACM_0, CDC_EVENT_LINE_STATE_CHANGED)); | ||
TEST_ASSERT_EQUAL(ESP_OK, tusb_cdc_acm_deinit(TINYUSB_CDC_ACM_0)); | ||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall()); | ||
} | ||
// Remove primitives | ||
vSemaphoreDelete(wait_mount); | ||
vSemaphoreDelete(wait_command); | ||
// All attempts should be completed | ||
TEST_ASSERT_EQUAL(0, attempts); | ||
} | ||
|
||
#endif |
96 changes: 96 additions & 0 deletions
96
device/esp_tinyusb/test_apps/teardown_device/pytest_teardown_device.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
import pytest | ||
from pytest_embedded_idf.dut import IdfDut | ||
import serial | ||
from serial.tools.list_ports import comports | ||
from time import sleep, time | ||
|
||
|
||
@pytest.mark.esp32s2 | ||
@pytest.mark.esp32s3 | ||
@pytest.mark.esp32p4 | ||
@pytest.mark.usb_device | ||
|
||
def get_tusb_cdc_device(vid, pid): | ||
ports = comports() | ||
for cdc in ports: | ||
if cdc.vid == vid and cdc.pid == pid: | ||
return cdc.device | ||
return None | ||
|
||
def wait_for_tusb_cdc(vid, pid, timeout=30): | ||
start_time = time() | ||
while time() - start_time < timeout: | ||
sleep(0.5) # Check every 0.5 seconds | ||
tusb_cdc = get_tusb_cdc_device(vid, pid) | ||
if tusb_cdc: | ||
return tusb_cdc | ||
return None | ||
|
||
def teardown_device(key_len, amount): | ||
TUSB_VID = 0x303A # Espressif TinyUSB VID | ||
TUSB_PID = 0x4002 # Espressif TinyUSB VID | ||
|
||
# Command to send and expected response | ||
COMMAND = b'\xAA' * key_len | ||
EXPECTED_RESPONSE = b'\x55' * key_len | ||
|
||
# Number of iterations, must be equal to ITERATIONS in the test application | ||
ITERATIONS = amount | ||
|
||
for i in range(ITERATIONS): | ||
print(f"Iteration {i+1} of {ITERATIONS}") | ||
|
||
# Wait for the device to appear | ||
print("Waiting for the device to connect...") | ||
tusb_cdc = wait_for_tusb_cdc(TUSB_VID, TUSB_PID) | ||
if not tusb_cdc: | ||
print("Error: Device did not appear within the timeout period.") | ||
assert True | ||
|
||
try: | ||
# Open the serial port | ||
with serial.Serial(port=tusb_cdc, baudrate=9600, timeout=1) as cdc: | ||
print(f"Opened port: {tusb_cdc}") | ||
# Send the key command | ||
res = cdc.write(COMMAND) | ||
assert res == key_len | ||
# Get the response | ||
res = cdc.readline() | ||
assert len(res) == key_len | ||
# Explicitly close the cdc | ||
cdc.close() | ||
# Check if the response matches the expected response | ||
if res == EXPECTED_RESPONSE: | ||
print("Response matches expected value.") | ||
else: | ||
print(f"Sent {len(COMMAND)}: {COMMAND.hex().upper()}") | ||
print(f"Received {len(res)}: {res.hex().upper()}") | ||
raise Exception("Error: Response does not match expected value.") | ||
|
||
except serial.SerialException as e: | ||
print(f"Error communicating with the serial port: {e}") | ||
raise | ||
|
||
# Wait for the device to disconnect | ||
print("Waiting for the device to disconnect...") | ||
while get_tusb_cdc_device(TUSB_VID, TUSB_PID): | ||
sleep(0.1) # Poll every 0.1 second while tinyusb cdc dev still in list | ||
|
||
print("Finished all iterations.") | ||
|
||
def test_usb_teardown_device(dut) -> None: | ||
dut.expect_exact('Press ENTER to see the list of tests.') | ||
dut.write('[teardown]') | ||
dut.expect_exact('TinyUSB: TinyUSB Driver installed') | ||
sleep(2) # Some time for the OS to enumerate our USB device | ||
if dut.target == 'esp32p4': | ||
MPS = 512 | ||
else: | ||
MPS = 64 | ||
# On Linux, the serial port kept opened, while len==MPS, https://github.com/pyserial/pyserial/issues/753 | ||
# that can be seen via Beagle: CDC OUT transaction appears only when terminal is closed. | ||
teardown_device(MPS, 10) # Teardown tusb device 10 times | ||
|
16 changes: 16 additions & 0 deletions
16
device/esp_tinyusb/test_apps/teardown_device/sdkconfig.defaults
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Configure TinyUSB, it will be used to mock USB devices | ||
CONFIG_TINYUSB_CDC_ENABLED=y | ||
CONFIG_TINYUSB_CDC_COUNT=1 | ||
|
||
# Disable watchdogs, they'd get triggered during unity interactive menu | ||
CONFIG_ESP_INT_WDT=n | ||
CONFIG_ESP_TASK_WDT=n | ||
|
||
# Run-time checks of Heap and Stack | ||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y | ||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y | ||
CONFIG_COMPILER_STACK_CHECK=y | ||
|
||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y | ||
|
||
CONFIG_COMPILER_CXX_EXCEPTIONS=y |