Initial project setup
This commit is contained in:
131
managed_components/espressif__esp_tinyusb/test_apps/README.md
Normal file
131
managed_components/espressif__esp_tinyusb/test_apps/README.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# CI target runner setup
|
||||
|
||||
To allow a Docker container, running on a CI target runner, to access USB devices connected to the CI target runner, some modifications must be made.
|
||||
In our case, it's an `RPI` target runner.
|
||||
|
||||
The main idea comes from this response on [stackoverflow](https://stackoverflow.com/a/66427245/19840830). The same approach is also recommended in the official Docker [documentation](https://docs.docker.com/reference/cli/docker/container/run/#device-cgroup-rule)
|
||||
|
||||
|
||||
### Following changes shall be made on a CI target runner
|
||||
|
||||
- [`UDEV rules`](#udev-rules)
|
||||
- [`Docker tty script`](#docker-tty-script)
|
||||
- [`Logging`](#logging)
|
||||
- [`Running a docker container`](#running-a-docker-container)
|
||||
- [`GitHub CI target runner setup`](#github-ci-target-runner-setup)
|
||||
- [`GitLab CI target runner setup`](#gitlab-ci-target-runner-setup)
|
||||
|
||||
## UDEV rules
|
||||
|
||||
- This UDEV rule will trigger a `docker_tty.sh` script every time a USB device is connected, disconnected, or enumerated by the host machine (CI target runner)
|
||||
- Location: `/etc/udev/rules.d/99-docker-tty.rules`
|
||||
- `99-docker-tty.rules` file content:
|
||||
|
||||
``` sh
|
||||
ACTION=="add", SUBSYSTEM=="tty", RUN+="/usr/local/bin/docker_tty.sh 'added' '%E{DEVNAME}' '%M' '%m'"
|
||||
ACTION=="remove", SUBSYSTEM=="tty", RUN+="/usr/local/bin/docker_tty.sh 'removed' '%E{DEVNAME}' '%M' '%m'"
|
||||
```
|
||||
|
||||
## Docker tty script
|
||||
|
||||
- This `.sh` script, triggered by the UDEV rule above, will propagate USB devices to a running Docker container.
|
||||
- Location: `/usr/local/bin/docker_tty.sh`
|
||||
- `docker_tty.sh` file content:
|
||||
|
||||
``` sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Log the USB event with parameters
|
||||
echo "USB event: $1 $2 $3 $4" >> /tmp/docker_tty.log
|
||||
|
||||
# Find a running Docker container (using the first one found)
|
||||
docker_name=$(docker ps --format "{{.Names}}" | head -n 1)
|
||||
|
||||
# Check if a container was found
|
||||
if [ ! -z "$docker_name" ]; then
|
||||
if [ "$1" == "added" ]; then
|
||||
docker exec -u 0 "$docker_name" mknod $2 c $3 $4
|
||||
docker exec -u 0 "$docker_name" chmod -R 777 $2
|
||||
echo "Adding $2 to Docker container $docker_name" >> /tmp/docker_tty.log
|
||||
else
|
||||
docker exec -u 0 "$docker_name" rm $2
|
||||
echo "Removing $2 from Docker container $docker_name" >> /tmp/docker_tty.log
|
||||
fi
|
||||
else
|
||||
echo "No running Docker containers found." >> /tmp/docker_tty.log
|
||||
fi
|
||||
```
|
||||
|
||||
### Making the script executable
|
||||
|
||||
Don't forget to make the created script executable:
|
||||
``` sh
|
||||
root@~$ chmod +x /usr/local/bin/docker_tty.sh
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
- The `docker_tty.sh` script logs information about the USB devices it processes.
|
||||
- Location: `/tmp/docker_tty.log`
|
||||
- Example of a log from the `docker_tty.log` file, showing a flow of the `pytest_usb_device.py` test
|
||||
|
||||
```
|
||||
USB event: added /dev/ttyACM0 166 0
|
||||
USB event: added /dev/ttyACM1 166 1
|
||||
Adding /dev/ttyACM0 to Docker container d5e5c774174b435b8befea864f8fcb7f_python311bookworm_6a975d
|
||||
Adding /dev/ttyACM1 to Docker container d5e5c774174b435b8befea864f8fcb7f_python311bookworm_6a975d
|
||||
USB event: removed /dev/ttyACM0 166 0
|
||||
USB event: removed /dev/ttyACM1 166 1
|
||||
```
|
||||
|
||||
## Running a docker container
|
||||
|
||||
### Check Major and Minor numbers of connected devices
|
||||
|
||||
Check the Major and Minor numbers assigned by the Linux kernel to devices that you want the Docker container to access.
|
||||
In our case, we want to access `/dev/ttyUSB0`, `/dev/ttyACM0` and `/dev/ttyACM1`
|
||||
|
||||
`/dev/ttyUSB0`: Major 188, Minor 0
|
||||
``` sh
|
||||
peter@BrnoRPIG007:~ $ ls -l /dev/ttyUSB0
|
||||
crw-rw-rw- 1 root dialout 188, 0 Nov 12 11:08 /dev/ttyUSB0
|
||||
```
|
||||
|
||||
`/dev/ttyACM0` and `/dev/ttyACM1`: Major 166, Minor 0 (1)
|
||||
``` sh
|
||||
peter@BrnoRPIG007:~ $ ls -l /dev/ttyACM0
|
||||
crw-rw---- 1 root dialout 166, 0 Nov 13 10:26 /dev/ttyACM0
|
||||
peter@BrnoRPIG007:~ $ ls -l /dev/ttyACM1
|
||||
crw-rw---- 1 root dialout 166, 1 Nov 13 10:26 /dev/ttyACM1
|
||||
```
|
||||
|
||||
### Run a docker container
|
||||
|
||||
Run a Docker container with the following extra options:
|
||||
``` sh
|
||||
docker run --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 166:* rmw' --privileged ..
|
||||
```
|
||||
- `--device-cgroup-rule='c 188:* rmw'`: allow access to `ttyUSBx` (Major 188, all Minors)
|
||||
- `--device-cgroup-rule='c 166:* rmw'`: allow access to `ttyACMx` (Major 166, all Minors)
|
||||
|
||||
## GitHub CI target runner setup
|
||||
|
||||
To apply these changes to a GitHub target runner a `.yml` file used to run a Docker container for pytest must be modified. The Docker container is then run with the following options:
|
||||
|
||||
``` yaml
|
||||
container:
|
||||
image: python:3.11-bookworm
|
||||
options: --privileged --device-cgroup-rule="c 188:* rmw" --device-cgroup-rule="c 166:* rmw"
|
||||
```
|
||||
|
||||
## GitLab CI target runner setup
|
||||
|
||||
To apply these changes to a GitLab runner the `config.toml` file located at `/etc/gitlab-runner/config.toml` on each GitLab target runner must be modified.
|
||||
|
||||
According to GitLab's [documentation](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersdocker-section) the `[runners.docker]` section of the `config.toml` file should include the `device_cgroup_rules` parameter:
|
||||
|
||||
``` toml
|
||||
[runners.docker]
|
||||
...
|
||||
device_cgroup_rules = ["c 188:* rmw", "c 166:* rmw"]
|
||||
```
|
||||
@@ -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_cdc)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-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 "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_cdc_acm.h"
|
||||
#include "vfs_tinyusb.h"
|
||||
|
||||
#define VFS_PATH "/dev/usb-cdc1"
|
||||
|
||||
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)),
|
||||
TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, (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)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB CDC testcase
|
||||
*
|
||||
* This is not a 'standard' testcase, as it never exits. The testcase runs in a loop where it echoes back all the data received.
|
||||
*
|
||||
* - Init TinyUSB with standard CDC device and configuration descriptors
|
||||
* - Init 2 CDC-ACM interfaces
|
||||
* - Map CDC1 to Virtual File System
|
||||
* - In a loop: Read data from CDC0 and CDC1. Echo received data back
|
||||
*
|
||||
* Note: CDC0 appends 'novfs' to echoed data, so the host (test runner) can easily determine which port is which.
|
||||
*/
|
||||
TEST_CASE("tinyusb_cdc", "[esp_tinyusb][cdc]")
|
||||
{
|
||||
// Install TinyUSB driver
|
||||
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
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
// 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));
|
||||
|
||||
// Init CDC 1
|
||||
acm_cfg.cdc_port = TINYUSB_CDC_ACM_1;
|
||||
acm_cfg.callback_rx = NULL;
|
||||
TEST_ASSERT_FALSE(tusb_cdc_acm_initialized(TINYUSB_CDC_ACM_1));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tusb_cdc_acm_init(&acm_cfg));
|
||||
TEST_ASSERT_TRUE(tusb_cdc_acm_initialized(TINYUSB_CDC_ACM_1));
|
||||
|
||||
// Install VFS to CDC 1
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_vfs_tusb_cdc_register(TINYUSB_CDC_ACM_1, VFS_PATH));
|
||||
esp_vfs_tusb_cdc_set_rx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||
esp_vfs_tusb_cdc_set_tx_line_endings(ESP_LINE_ENDINGS_LF);
|
||||
FILE *cdc = fopen(VFS_PATH, "r+");
|
||||
TEST_ASSERT_NOT_NULL(cdc);
|
||||
|
||||
uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1];
|
||||
while (true) {
|
||||
size_t b = fread(buf, 1, sizeof(buf), cdc);
|
||||
if (b > 0) {
|
||||
printf("Intf VFS, RX %d bytes\n", b);
|
||||
//ESP_LOG_BUFFER_HEXDUMP("test", buf, b, ESP_LOG_INFO);
|
||||
fwrite(buf, 1, b, cdc);
|
||||
}
|
||||
vTaskDelay(1);
|
||||
|
||||
size_t rx_size = 0;
|
||||
int itf = 0;
|
||||
ESP_ERROR_CHECK(tinyusb_cdcacm_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE, &rx_size));
|
||||
if (rx_size > 0) {
|
||||
printf("Intf %d, RX %d bytes\n", itf, rx_size);
|
||||
|
||||
// Add 'novfs' to reply so the host can identify the port
|
||||
strcpy((char *)&buf[rx_size - 2], "novfs\r\n");
|
||||
tinyusb_cdcacm_write_queue(itf, buf, rx_size + sizeof("novfs") - 1);
|
||||
|
||||
tinyusb_cdcacm_write_flush(itf, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
from time import sleep
|
||||
from serial import Serial, SerialException
|
||||
from serial.tools.list_ports import comports
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_device_cdc(dut) -> None:
|
||||
'''
|
||||
Running the test locally:
|
||||
1. Build the testa app for your DUT (ESP32-S2 or S3)
|
||||
2. Connect you DUT to your test runner (local machine) with USB port and flashing port
|
||||
3. Run `pytest --target esp32s3`
|
||||
|
||||
Test procedure:
|
||||
1. Run the test on the DUT
|
||||
2. Expect 2 Virtual COM Ports in the system
|
||||
3. Open both comports and send some data. Expect echoed data
|
||||
'''
|
||||
dut.expect_exact('Press ENTER to see the list of tests.')
|
||||
dut.write('[cdc]')
|
||||
dut.expect_exact('TinyUSB: TinyUSB Driver installed')
|
||||
sleep(2) # Some time for the OS to enumerate our USB device
|
||||
|
||||
# Find devices with Espressif TinyUSB VID/PID
|
||||
s = []
|
||||
ports = comports()
|
||||
|
||||
for port, _, hwid in ports:
|
||||
if '303A:4002' in hwid:
|
||||
s.append(port)
|
||||
|
||||
if len(s) != 2:
|
||||
raise Exception('TinyUSB COM port not found')
|
||||
|
||||
try:
|
||||
with Serial(s[0]) as cdc0:
|
||||
with Serial(s[1]) as cdc1:
|
||||
# Write dummy string and check for echo
|
||||
cdc0.write('text\r\n'.encode())
|
||||
res = cdc0.readline()
|
||||
assert b'text' in res
|
||||
if b'novfs' in res:
|
||||
novfs_cdc = cdc0
|
||||
vfs_cdc = cdc1
|
||||
|
||||
cdc1.write('text\r\n'.encode())
|
||||
res = cdc1.readline()
|
||||
assert b'text' in res
|
||||
if b'novfs' in res:
|
||||
novfs_cdc = cdc1
|
||||
vfs_cdc = cdc0
|
||||
|
||||
# Write more than MPS, check that the transfer is not divided
|
||||
novfs_cdc.write(bytes(100))
|
||||
dut.expect_exact("Intf 0, RX 100 bytes")
|
||||
|
||||
# Write more than RX buffer, check correct reception
|
||||
novfs_cdc.write(bytes(600))
|
||||
transfer_len1 = int(dut.expect(r'Intf 0, RX (\d+) bytes')[1].decode())
|
||||
transfer_len2 = int(dut.expect(r'Intf 0, RX (\d+) bytes')[1].decode())
|
||||
assert transfer_len1 + transfer_len2 == 600
|
||||
|
||||
# The VFS is setup for CRLF RX and LF TX
|
||||
vfs_cdc.write('text\r\n'.encode())
|
||||
res = vfs_cdc.readline()
|
||||
assert b'text\n' in res
|
||||
|
||||
return
|
||||
|
||||
except SerialException as e:
|
||||
print(f"SerialException occurred: {e}")
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
raise
|
||||
@@ -0,0 +1,18 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_MSC_ENABLED=n
|
||||
CONFIG_TINYUSB_CDC_ENABLED=y
|
||||
CONFIG_TINYUSB_CDC_COUNT=2
|
||||
CONFIG_TINYUSB_HID_COUNT=0
|
||||
|
||||
# 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
|
||||
@@ -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_configuration_descriptor)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 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();
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 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 "esp_system.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
|
||||
static const char *TAG = "config_test";
|
||||
|
||||
#define TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS 1000
|
||||
#define TEARDOWN_DEVICE_DETACH_DELAY_MS 1000
|
||||
|
||||
// ========================= TinyUSB descriptors ===============================
|
||||
|
||||
// Here we need to create dual CDC device, to match the CONFIG_TINYUSB_CDC_COUNT from sdkconfig.defaults
|
||||
static const uint16_t cdc_desc_config_len = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN;
|
||||
static const uint8_t test_fs_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, CFG_TUD_CDC * 2, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, 64),
|
||||
#if CFG_TUD_CDC > 1
|
||||
TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, 64),
|
||||
#endif
|
||||
};
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
static const uint8_t test_hs_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 4, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, 512),
|
||||
TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, 512),
|
||||
};
|
||||
|
||||
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 const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_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 = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
// ========================== Private logic ====================================
|
||||
SemaphoreHandle_t wait_mount = NULL;
|
||||
|
||||
/**
|
||||
* @brief Creates test additional resources.
|
||||
*
|
||||
* Is called before start test to create/init internal resources.
|
||||
*/
|
||||
static bool __test_init(void)
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
return (wait_mount != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Indicates device connection event.
|
||||
*
|
||||
* Is called in tud_mount callback.
|
||||
*/
|
||||
static void __test_conn(void)
|
||||
{
|
||||
if (wait_mount) {
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Awaits device connection event.
|
||||
*
|
||||
* Is used for waiting the event in test logic.
|
||||
* Timeout could be configured via TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS define.
|
||||
*/
|
||||
static esp_err_t __test_wait_conn(void)
|
||||
{
|
||||
if (!wait_mount) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return ( xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS))
|
||||
? ESP_OK
|
||||
: ESP_ERR_TIMEOUT );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases test resources.
|
||||
*
|
||||
* Is called in the end of the test to release internal resources.
|
||||
*/
|
||||
static void __test_release(void)
|
||||
{
|
||||
if (wait_mount) {
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief One round of setup configuration for TinyUSB.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Init internal resources
|
||||
* 2. Installs TinyUSB with provided configuration
|
||||
* 3. Waits for the connection event from the Host
|
||||
* 4. Gives some extra time for Host to configure the device (configures via TEARDOWN_DEVICE_DETACH_DELAY_MS)
|
||||
* 5. Uninstall TinyUSB
|
||||
* 6. Release internal resources
|
||||
*
|
||||
* Is called in the end of the test to release internal resources.
|
||||
*/
|
||||
static void __test_tinyusb_set_config(const tinyusb_config_t *tusb_cfg)
|
||||
{
|
||||
TEST_ASSERT_EQUAL(true, __test_init());
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(tusb_cfg));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn());
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DETACH_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
__test_release();
|
||||
}
|
||||
|
||||
// ========================== Callbacks ========================================
|
||||
/**
|
||||
* @brief TinyUSB callback for device mount.
|
||||
*
|
||||
* @note
|
||||
* For Linux-based Hosts: Reflects the SetConfiguration() request from the Host Driver.
|
||||
* For Win-based Hosts: SetConfiguration() request is present only with available Class in device descriptor.
|
||||
*/
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s", __FUNCTION__);
|
||||
__test_conn();
|
||||
}
|
||||
|
||||
// ============================= Tests =========================================
|
||||
/**
|
||||
* @brief TinyUSB Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration without specifying any parameters.
|
||||
* Configuration & descriptors are provided by esp_tinyusb wrapper.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_all_default", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = NULL,
|
||||
.configuration_descriptor = NULL,
|
||||
#if (CONFIG_TINYUSB_RHPORT_HS)
|
||||
.hs_configuration_descriptor = NULL,
|
||||
#endif // CONFIG_TINYUSB_RHPORT_HS
|
||||
};
|
||||
// Install TinyUSB driver
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration with specifying only device descriptor.
|
||||
* For High-speed qualifier descriptor as well.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_device", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.configuration_descriptor = NULL,
|
||||
#if (CONFIG_TINYUSB_RHPORT_HS)
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#endif // CONFIG_TINYUSB_RHPORT_HS
|
||||
};
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration with specifying device & configuration descriptors.
|
||||
*
|
||||
* For High-speed:
|
||||
* - HS configuration descriptor is not provided by user (legacy compatibility) and default HS config descriptor is using when possible.
|
||||
* - Qualifier descriptor.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_device_and_config", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.configuration_descriptor = test_fs_configuration_descriptor,
|
||||
#if (CONFIG_TINYUSB_RHPORT_HS)
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#endif // CONFIG_TINYUSB_RHPORT_HS
|
||||
};
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
|
||||
#if (CONFIG_IDF_TARGET_ESP32P4)
|
||||
/**
|
||||
* @brief TinyUSB High-speed Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration with specifying device & HS configuration descriptor only.
|
||||
* FS configuration descriptor is not provided by user (legacy compatibility) and default configuration descriptor for FS is using when possible.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_device_and_hs_config_only", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.configuration_descriptor = NULL,
|
||||
.hs_configuration_descriptor = test_hs_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
};
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB High-speed Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration with specifying all descriptors by user.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_all_configured", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.fs_configuration_descriptor = test_fs_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_hs_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
};
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
#endif // CONFIG_IDF_TARGET_ESP32P4
|
||||
|
||||
#endif // SOC_USB_OTG_SUPPORTED
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_device_configuration(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='config')
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_CDC_ENABLED=y
|
||||
CONFIG_TINYUSB_CDC_COUNT=2
|
||||
|
||||
# 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
|
||||
@@ -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_dconn_detection)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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 "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_tasks.h"
|
||||
|
||||
#define DEVICE_DETACH_TEST_ROUNDS 10
|
||||
#define DEVICE_DETACH_ROUND_DELAY_MS 1000
|
||||
|
||||
#if (CONFIG_IDF_TARGET_ESP32P4)
|
||||
#define USB_SRP_BVALID_IN_IDX USB_SRP_BVALID_PAD_IN_IDX
|
||||
#endif // CONFIG_IDF_TARGET_ESP32P4
|
||||
|
||||
/* TinyUSB descriptors
|
||||
********************************************************************* */
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
|
||||
static unsigned int dev_mounted = 0;
|
||||
static unsigned int dev_umounted = 0;
|
||||
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_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 = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
/**
|
||||
* @attention Tests relying on this callback only pass on Linux USB Host!
|
||||
*
|
||||
* This callback is issued after SetConfiguration command from USB Host.
|
||||
* However, Windows issues SetConfiguration only after a USB driver was assigned to the device.
|
||||
* So in case you are implementing a Vendor Specific class, or your device has 0 interfaces, this callback is not issued on Windows host.
|
||||
*/
|
||||
printf("%s\n", __FUNCTION__);
|
||||
dev_mounted++;
|
||||
}
|
||||
|
||||
// Invoked when device is unmounted
|
||||
void tud_umount_cb(void)
|
||||
{
|
||||
printf("%s\n", __FUNCTION__);
|
||||
dev_umounted++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Disconnect Detection test case
|
||||
*
|
||||
* This is specific artificial test for verifying the disconnection detection event.
|
||||
* Normally, this event comes as a result of detaching USB device from the port and disappearing the VBUS voltage.
|
||||
* In this test case, we use GPIO matrix and connect the signal to the ZERO or ONE constant inputs.
|
||||
* Connection to constant ONE input emulates the attachment to the USB Host port (appearing VBUS).
|
||||
* Connection to constant ZERO input emulates the detachment from the USB Host port (removing VBUS).
|
||||
*
|
||||
* Test logic:
|
||||
* - Install TinyUSB Device stack without any class
|
||||
* - In cycle:
|
||||
* - Emulate the detachment, get the tud_umount_cb(), increase the dev_umounted value
|
||||
* - Emulate the attachment, get the tud_mount_cb(), increase the dev_mounted value
|
||||
* - Verify that dev_umounted == dev_mounted
|
||||
* - Verify that dev_mounted == DEVICE_DETACH_TEST_ROUNDS, where DEVICE_DETACH_TEST_ROUNDS - amount of rounds
|
||||
* - Uninstall TinyUSB Device stack
|
||||
*
|
||||
*/
|
||||
TEST_CASE("dconn_detection", "[esp_tinyusb][dconn]")
|
||||
{
|
||||
unsigned int rounds = DEVICE_DETACH_TEST_ROUNDS;
|
||||
|
||||
// Install TinyUSB driver
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
|
||||
dev_mounted = 0;
|
||||
dev_umounted = 0;
|
||||
|
||||
while (rounds--) {
|
||||
// LOW to emulate disconnect USB device
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_SRP_BVALID_IN_IDX, false);
|
||||
vTaskDelay(pdMS_TO_TICKS(DEVICE_DETACH_ROUND_DELAY_MS));
|
||||
// HIGH to emulate connect USB device
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false);
|
||||
vTaskDelay(pdMS_TO_TICKS(DEVICE_DETACH_ROUND_DELAY_MS));
|
||||
}
|
||||
|
||||
// Verify
|
||||
TEST_ASSERT_EQUAL(dev_umounted, dev_mounted);
|
||||
TEST_ASSERT_EQUAL(DEVICE_DETACH_TEST_ROUNDS, dev_mounted);
|
||||
|
||||
// Cleanup
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
}
|
||||
#endif // SOC_USB_OTG_SUPPORTED
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
#@pytest.mark.usb_device Disable in CI: unavailable teardown for P4
|
||||
def test_usb_device_dconn_detection(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='dconn')
|
||||
@@ -0,0 +1,18 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_MSC_ENABLED=n
|
||||
CONFIG_TINYUSB_CDC_ENABLED=n
|
||||
CONFIG_TINYUSB_CDC_COUNT=0
|
||||
CONFIG_TINYUSB_HID_COUNT=0
|
||||
|
||||
# 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
|
||||
@@ -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_default_task_without_init)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 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();
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 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"
|
||||
|
||||
static const char *TAG = "default_task";
|
||||
|
||||
SemaphoreHandle_t wait_mount = NULL;
|
||||
|
||||
#define TEARDOWN_DEVICE_DELAY_MS 1000
|
||||
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_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 = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Task specific testcase
|
||||
*
|
||||
* Scenario:
|
||||
* 1. Install TinyUSB driver
|
||||
* 2. Wait tud_mount_cb() until TUSB_DEVICE_DELAY_MS
|
||||
* 3. Wait TUSB_DEVICE_DELAY_MS
|
||||
* 4. Teardown TinyUSB
|
||||
* 5. Release resources
|
||||
*/
|
||||
TEST_CASE("tinyusb_default_task_with_init", "[esp_tinyusb][tusb_task]")
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount);
|
||||
|
||||
// TinyUSB driver configuration
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_DELAY_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Remove primitives
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_default_task_with_init(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='tusb_task')
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB
|
||||
CONFIG_TINYUSB_NO_DEFAULT_TASK=n
|
||||
CONFIG_TINYUSB_INIT_IN_DEFAULT_TASK=n
|
||||
|
||||
# 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
|
||||
@@ -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_default_task_with_init)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 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();
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 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"
|
||||
|
||||
static const char *TAG = "default_task_with_init";
|
||||
|
||||
SemaphoreHandle_t wait_mount = NULL;
|
||||
|
||||
#define TEARDOWN_DEVICE_DELAY_MS 1000
|
||||
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_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 = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Task specific testcase
|
||||
*
|
||||
* Scenario:
|
||||
* 1. Install TinyUSB driver
|
||||
* 2. Wait tud_mount_cb() until TUSB_DEVICE_DELAY_MS
|
||||
* 3. Wait TUSB_DEVICE_DELAY_MS
|
||||
* 4. Teardown TinyUSB
|
||||
* 5. Release resources
|
||||
*/
|
||||
TEST_CASE("tinyusb_default_task_with_init", "[esp_tinyusb][tusb_task]")
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount);
|
||||
|
||||
// TinyUSB driver configuration
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_DELAY_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Remove primitives
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_default_task_with_init(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='tusb_task')
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB
|
||||
CONFIG_TINYUSB_NO_DEFAULT_TASK=n
|
||||
CONFIG_TINYUSB_INIT_IN_DEFAULT_TASK=y
|
||||
|
||||
# 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
|
||||
@@ -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_external_task_without_init)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 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();
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 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"
|
||||
|
||||
static const char *TAG = "external_task";
|
||||
|
||||
static SemaphoreHandle_t wait_mount = NULL;
|
||||
static TaskHandle_t s_test_tusb_tskh;
|
||||
|
||||
#define TUSB_DEVICE_DELAY_MS 1000
|
||||
#define TUSB_EXTERNAL_TASK_SIZE 4096
|
||||
#define TUSB_EXTERNAL_TASK_PRIO 5
|
||||
#define TUSB_EXTERNAL_TASK_AFFINITY 0x7FFFFFFF /* FREERTOS_NO_AFFINITY */
|
||||
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_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 = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This top level thread processes all usb events and invokes callbacks
|
||||
*/
|
||||
static void test_tusb_external_task(void *arg)
|
||||
{
|
||||
ESP_LOGD(TAG, "External TinyUSB task started");
|
||||
while (1) { // RTOS forever loop
|
||||
tud_task();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Task specific testcase
|
||||
*
|
||||
* Scenario:
|
||||
* 1. Install TinyUSB driver
|
||||
* 2. Create external TinyUSB task for tud_task()
|
||||
* 3. Wait tud_mount_cb() until TUSB_DEVICE_DELAY_MS
|
||||
* 4. Wait TUSB_DEVICE_DELAY_MS
|
||||
* 5. Teardown TinyUSB
|
||||
* 6. Release resources
|
||||
*
|
||||
* @note If run the task before installing the tinyusb driver, the external task will lead to cpu starvation.
|
||||
*/
|
||||
TEST_CASE("tinyusb_external_task", "[esp_tinyusb][tusb_task]")
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount);
|
||||
|
||||
// TinyUSB driver configuration
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Create an external task for tinyusb device stack
|
||||
xTaskCreate(test_tusb_external_task,
|
||||
"TinyUSB",
|
||||
TUSB_EXTERNAL_TASK_SIZE,
|
||||
NULL,
|
||||
TUSB_EXTERNAL_TASK_PRIO,
|
||||
&s_test_tusb_tskh);
|
||||
TEST_ASSERT_NOT_NULL(s_test_tusb_tskh);
|
||||
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TUSB_DEVICE_DELAY_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TUSB_DEVICE_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Remove primitives
|
||||
vTaskDelete(s_test_tusb_tskh);
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_external_task_internal_init(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='tusb_task')
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB
|
||||
CONFIG_TINYUSB_NO_DEFAULT_TASK=y
|
||||
CONFIG_TINYUSB_INIT_IN_DEFAULT_TASK=n
|
||||
|
||||
# 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
|
||||
@@ -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)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#define TEARDOWN_DEVICE_INIT_DELAY_MS 1000
|
||||
#define TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS 1000
|
||||
#define TEARDOWN_DEVICE_DETACH_DELAY_MS 1000
|
||||
|
||||
#define TEARDOWN_AMOUNT 10
|
||||
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_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 = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Teardown specific testcase
|
||||
*
|
||||
* Scenario:
|
||||
* 1. Install TinyUSB device without any class
|
||||
* 2. Wait SetConfiguration() (tud_mount_cb)
|
||||
* 3. If attempts == 0 goto step 8
|
||||
* 4. Wait TEARDOWN_DEVICE_DETACH_DELAY_MS
|
||||
* 5. Uninstall TinyUSB device
|
||||
* 6. Wait TEARDOWN_DEVICE_INIT_DELAY_MS
|
||||
* 7. Decrease attempts by 1, goto step 3
|
||||
* 8. Wait TEARDOWN_DEVICE_DETACH_DELAY_MS
|
||||
* 9. Uninstall TinyUSB device
|
||||
*/
|
||||
TEST_CASE("tinyusb_teardown", "[esp_tinyusb][teardown]")
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount);
|
||||
|
||||
// TinyUSB driver configuration
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
|
||||
// Teardown routine
|
||||
int attempts = TEARDOWN_AMOUNT;
|
||||
while (attempts--) {
|
||||
// Keep device attached
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DETACH_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_INIT_DELAY_MS));
|
||||
// Reconnect
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
}
|
||||
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DETACH_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Remove primitives
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
import subprocess
|
||||
from time import sleep, time
|
||||
|
||||
class DeviceNotFoundError(Exception):
|
||||
"""Custom exception for device not found within the timeout period."""
|
||||
pass
|
||||
|
||||
def tusb_dev_in_list(vid, pid):
|
||||
try:
|
||||
output = subprocess.check_output(["lsusb"], text=True)
|
||||
search_string = f"{vid}:{pid}"
|
||||
return search_string in output
|
||||
except Exception as e:
|
||||
print(f"Error while executing lsusb: {e}")
|
||||
raise
|
||||
|
||||
def wait_tusb_dev_appeared(vid, pid, timeout):
|
||||
start_time = time()
|
||||
while True:
|
||||
if tusb_dev_in_list(vid, pid):
|
||||
return True
|
||||
if time() - start_time > timeout:
|
||||
raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} not found within {timeout} seconds.")
|
||||
sleep(0.5)
|
||||
|
||||
def wait_tusb_dev_removed(vid, pid, timeout):
|
||||
start_time = time()
|
||||
while True:
|
||||
if not tusb_dev_in_list(vid, pid):
|
||||
return True
|
||||
if time() - start_time > timeout:
|
||||
raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} wasn't removed within {timeout} seconds.")
|
||||
sleep(0.5)
|
||||
|
||||
def tusb_device_teardown(iterations, timeout):
|
||||
TUSB_VID = "303a" # Espressif TinyUSB VID
|
||||
TUSB_PID = "4002" # Espressif TinyUSB VID
|
||||
|
||||
for i in range(iterations):
|
||||
# Wait until the device is present
|
||||
print(f"Waiting for device ...")
|
||||
wait_tusb_dev_appeared(TUSB_VID, TUSB_PID, timeout)
|
||||
print("Device detected.")
|
||||
|
||||
# Wait until the device is removed
|
||||
print("Waiting for the device to be removed...")
|
||||
wait_tusb_dev_removed(TUSB_VID, TUSB_PID, timeout)
|
||||
print("Device removed.")
|
||||
print("Monitoring completed.")
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_teardown_device(dut: IdfDut) -> 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
|
||||
|
||||
try:
|
||||
tusb_device_teardown(10, 10) # Teardown tusb device: amount, timeout
|
||||
|
||||
except DeviceNotFoundError as e:
|
||||
print(f"Error: {e}")
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
raise
|
||||
@@ -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
|
||||
9
managed_components/espressif__esp_tinyusb/test_apps/vendor/CMakeLists.txt
vendored
Normal file
9
managed_components/espressif__esp_tinyusb/test_apps/vendor/CMakeLists.txt
vendored
Normal file
@@ -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_vendor_specific)
|
||||
4
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/CMakeLists.txt
vendored
Normal file
4
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
5
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/idf_component.yml
vendored
Normal file
5
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/idf_component.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
48
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/test_app_main.c
vendored
Normal file
48
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/test_app_main.c
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
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");
|
||||
|
||||
// We don't check memory leaks here because we cannot uninstall TinyUSB yet
|
||||
unity_run_menu();
|
||||
}
|
||||
71
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/test_vendor.c
vendored
Normal file
71
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/test_vendor.c
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
|
||||
static const char *TAG = "vendor_test";
|
||||
|
||||
char buffer_in[64];
|
||||
#if (TUSB_VERSION_MINOR >= 17)
|
||||
void tud_vendor_rx_cb(uint8_t itf, uint8_t const *buffer, uint16_t bufsize)
|
||||
#else
|
||||
void tud_vendor_rx_cb(uint8_t itf)
|
||||
#endif // TUSB_VERSION_MINOR
|
||||
{
|
||||
ESP_LOGI(TAG, "tud_vendor_rx_cb(itf=%d)", itf);
|
||||
int available = tud_vendor_n_available(itf);
|
||||
int read = tud_vendor_n_read(itf, buffer_in, available);
|
||||
ESP_LOGI(TAG, "actual read: %d. buffer message: %s", read, buffer_in);
|
||||
}
|
||||
|
||||
// Invoked when a control transfer occurred on an interface of this class
|
||||
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
|
||||
{
|
||||
// nothing to with DATA & ACK stage
|
||||
if (stage != CONTROL_STAGE_SETUP) {
|
||||
return true;
|
||||
}
|
||||
// stall unknown request
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Vendor specific testcase
|
||||
*/
|
||||
TEST_CASE("tinyusb_vendor", "[esp_tinyusb][vendor]")
|
||||
{
|
||||
// Install TinyUSB driver
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = NULL,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = NULL,
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = NULL,
|
||||
#else
|
||||
.configuration_descriptor = NULL,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
96
managed_components/espressif__esp_tinyusb/test_apps/vendor/pytest_vendor.py
vendored
Normal file
96
managed_components/espressif__esp_tinyusb/test_apps/vendor/pytest_vendor.py
vendored
Normal file
@@ -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 usb.core
|
||||
import usb.util
|
||||
from time import sleep
|
||||
|
||||
|
||||
def find_interface_by_index(device, interface_index):
|
||||
'''
|
||||
Function to find the interface by index
|
||||
'''
|
||||
for cfg in device:
|
||||
for intf in cfg:
|
||||
if intf.bInterfaceNumber == interface_index:
|
||||
return intf
|
||||
return None
|
||||
|
||||
|
||||
def send_data_to_intf(VID, PID, interface_index):
|
||||
'''
|
||||
Find a device, its interface and dual BULK endpoints
|
||||
Send some data to it
|
||||
'''
|
||||
# Find the USB device by VID and PID
|
||||
dev = usb.core.find(idVendor=VID, idProduct=PID)
|
||||
if dev is None:
|
||||
raise ValueError("Device not found")
|
||||
|
||||
# Find the interface by index
|
||||
intf = find_interface_by_index(dev, interface_index)
|
||||
if intf is None:
|
||||
raise ValueError(f"Interface with index {interface_index} not found")
|
||||
|
||||
if intf:
|
||||
def ep_read(len):
|
||||
try:
|
||||
return ep_in.read(len, 100)
|
||||
except:
|
||||
return None
|
||||
def ep_write(buf):
|
||||
try:
|
||||
ep_out.write(buf, 100)
|
||||
except:
|
||||
pass
|
||||
|
||||
maximum_packet_size = 64
|
||||
|
||||
ep_in = usb.util.find_descriptor(intf, custom_match = \
|
||||
lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)
|
||||
|
||||
ep_out = usb.util.find_descriptor(intf, custom_match = \
|
||||
lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
|
||||
|
||||
#print(ep_in)
|
||||
#print(ep_out)
|
||||
buf = "IF{}\n".format(interface_index).encode('utf-8')
|
||||
ep_write(bytes(buf))
|
||||
|
||||
ep_read(maximum_packet_size)
|
||||
else:
|
||||
print("NOT found")
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
#@pytest.mark.usb_device Disable in CI, for now, not possible to run this test in Docker container
|
||||
def test_usb_device_vendor(dut: IdfDut) -> None:
|
||||
'''
|
||||
Running the test locally:
|
||||
1. Build the test app for your DUT
|
||||
2. Connect you DUT to your test runner (local machine) with USB port and flashing port
|
||||
3. Run `pytest --target esp32s3`
|
||||
|
||||
Important note: On Windows you must manually assign a driver the device, otherwise it will never be configured.
|
||||
On Linux this is automatic
|
||||
|
||||
Test procedure:
|
||||
1. Run the test on the DUT
|
||||
2. Expect 2 Vendor specific interfaces in the system
|
||||
3. Send some data to it, check log output
|
||||
'''
|
||||
dut.run_all_single_board_cases(group='vendor')
|
||||
|
||||
sleep(2) # Wait until the device is enumerated
|
||||
|
||||
VID = 0x303A # Replace with your device's Vendor ID
|
||||
PID = 0x4040 # Replace with your device's Product ID
|
||||
|
||||
send_data_to_intf(VID, PID, 0)
|
||||
dut.expect_exact('vendor_test: actual read: 4. buffer message: IF0')
|
||||
send_data_to_intf(VID, PID, 1)
|
||||
dut.expect_exact('vendor_test: actual read: 4. buffer message: IF1')
|
||||
15
managed_components/espressif__esp_tinyusb/test_apps/vendor/sdkconfig.defaults
vendored
Normal file
15
managed_components/espressif__esp_tinyusb/test_apps/vendor/sdkconfig.defaults
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_VENDOR_COUNT=2
|
||||
|
||||
# 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
|
||||
Reference in New Issue
Block a user