Merge branch 'feature/usb_host_enum_testing' into 'master'

feature(usb_host): Added test app for edge cases in stages during enumeration process

See merge request espressif/esp-idf!31421
This commit is contained in:
Roman Leonov 2025-02-14 20:04:57 +08:00
commit bf944b7463
15 changed files with 3335 additions and 0 deletions

View File

@ -0,0 +1,11 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS "../common")
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(test_app_enum)

View File

@ -0,0 +1,349 @@
| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- |
# USB: Enumeration Driver - Local Test with emulated device based on TinyUSB
## Introduction
To verify the process how Enumeration Driver handles different scenarios the artificial approach of emulation USB device with TinyUSB is used.
This test helps to verify all possible scenarios of detaching device under the enumeration process.
## Key Terms
**Mocked Device** - A esp32-cpu based board, which represents the USB device, build on TinyUSB component (**tud_teardown()** feature is required, thus the version of the component should be higher than v0.17.0). The Mocked Device is used to emulate different scenarios with ability of controlling the USB Enumeration flow and detach the Mocked Device when necessary.
**Host** - A esp32-cpu based board with USB Host functionality. Used to verify the part of the USB Host Library - Enumeration Driver.
## Test Hardware requirements
For testing purpose two esp32-cpu based hardware with USB-OTG support are required (One for Host, one for Device (mocked dev)):
```
+----------------+
| USB Host Board |
| +------------+ | USB
| | USB-to-UART|========++
| +------------+ | ||
| +------------+ | \/
| | USB OTG | | \/
| +------------+ | || +-----------------+
+-------||-------+ ++==| |
/\ | PC Host |
/\ USB | (Test runner) |
+-------||-------+ ++==| |
| || | || +-----------------+
| +------------+ | /\
| | USB OTG | | /\
| +------------+ | ||
| +------------+ | ||
| | USB-to-UART|========++
| +------------+ | USB
| USB Dev Board |
| (mocked dev) |
+----------------+
```
## Mocked Device
Implementation could be found in [mock_dev.c](main/mock_dev.c) and [mock_dev.h](main/mock_dev.h).
The Mocked Device has a Final State Machine (FSM), which could be configured to stop at any stage and run the teardown process after. This flow represents the emulation of device detachment.
FSM is described in the **mock_dev_stage_t** structure and could be found in [mock_dev.h](main/mock_dev.h).
Available stages:
- Request Short Device Descriptor
- Request Full Device Descriptor
- Request Short Configuration Descriptor
- Request Full Configuration Descriptor
- Request Short LANGID Table
- Request Full LANDID Table
- Request Short Manufacturer String Descriptor
- Request Full Manufacturer String Descriptor
- Request Short Product String Descriptor
- Request Full Product String Descriptor
- Request Short Serial String Descriptor
- Request Full Serial String Descriptor
- Set configuration
Not covered stages:
- Device Reset (First and Second)
- Set Address
These stages are handled internally in TinyUSB and there is no user callbacks available. That means, that without specific changes in the TinyUSB component code, it is impossible to achieve emulation of device detaching during these stages.
### Mocked Device - Stages
To specify the descriptor, which should be used on every stage, there is a possibility to configure the pointer at every stage.
Example of fully-defined non-detachable Mocked Device configuration:
``` c
static const tusb_desc_device_t mock_device_desc = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = 64,
.idVendor = 0x0001,
.idProduct = 0x0002,
.bcdDevice = 0x0000,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
static const uint8_t mock_config_desc[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUD_CONFIG_DESC_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
};
static const char *mock_langid_str_desc = {
(char[]){0x09, 0x04}, // 0: LANGID
};
static const char *mock_manu_str_desc = {
"Espressif", // 1: Manufacturer
};
static const char *mock_prod_str_desc = {
"Enum Testing", // 2: Product
};
static const char *mock_ser_str_desc = {
"123456", // 3: Serials, should use chip ID
};
TEST_CASE("enum::complete", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
// Test remained logic
}
```
Every stage can be stopped with providing the special flag **stop_test**.
To specify the test, provide the following configuration to teardown the Mocked Device after getting the request:
```
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
```
If we want to emulate the device detachment during the requesting of Full Device Descriptor, we can change the test configuration accordingly:
```
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
```
### USB Host Library
To verify the USB Host Library - Enumeration Driver, **usb_host_lib** example is used.
## Run Test
When all the hardware have been configured and prepared, the Test can be run via following commands. As the Test requires both Host and Device parts, the following description will be for Host and Device.
The description is provided, assuming that the test is run under Linux and Host board has a /dev/ttyACM0 path, Mocked Device has a /dev/ttyUSB0 path, and we are in the esp-idf root folder.
To run the pytest, esp-idf must be installed and configured with ```--enable-pytest```.
### Prepare Host
Host part is controlled by visual control of debug output from the Host.
The following description is based on the usb_host_lib example as the application on the Host side.
To run the example on the Host:
```bash
cd examples/peripherals/usb/host/usb_host_lib
idf.py set-target esp32s3
idf.py -p /dev/ttyACM0 flash monitor
```
### Run Mocked Device
To run the Device part:
```bash
cd components/usb/test_apps/enum
idf.py set-target esp32s3
idf.py build
pytest --target=esp32s3 --port=/dev/ttyUSB0
```
After running the pytest on the device, the debug output from the Host works as the usb_host_lib example:
```
I (270) main_task: Started on CPU0
I (280) main_task: Calling app_main()
I (280) USB host lib: USB host library example
I (280) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
I (290) USB host lib: Installing USB Host Library
I (320) CLASS: Registering Client
I (700) CLASS: Opening device at address 1
I (700) CLASS: Getting device information
I (700) CLASS: Full speed
I (700) CLASS: Parent info:
I (700) CLASS: Port: ROOT
I (700) CLASS: bConfigurationValue 1
I (700) CLASS: Getting device descriptor
*** Device descriptor ***
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0xef
bDeviceSubClass 0x2
bDeviceProtocol 0x1
bMaxPacketSize0 64
idVendor 0x1
idProduct 0x2
bcdDevice 0.00
iManufacturer 1
iProduct 2
iSerialNumber 3
bNumConfigurations 1
I (90980) CLASS: Getting config descriptor
*** Configuration descriptor ***
bLength 9
bDescriptorType 2
wTotalLength 9
bNumInterfaces 0
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
bMaxPower 100mA
I (91000) CLASS: Getting Manufacturer string descriptor
Espressif
I (91010) CLASS: Getting Product string descriptor
Enum Testing
I (91020) CLASS: Getting Serial Number string descriptor
123456
```
Which means that the Mocked Device is connected to Host and the enumeration process was completed.
Different scenarios are being tested during the test run, so there could be errors in the log
That means, that the device emulates the specific behavior, to cause this error.
Important things are:
- During the test there must be no KERNEL PANIC, CPU reset etc. (not to miss the reset, it is better to configure the Panic handler behaviour to: Print registers and halt)
- The Host application should be responsive after the test. (In terms of usb_host_lib example, that means handle new device connection and show the descriptors from the connected device).
"Normal" test flow error are:
```
E (116330) USBH: Dev 28 EP 0 STALL
```
Or
```
E (96200) ENUM: Short dev desc has wrong bDescriptorType
E (96200) ENUM: [0:0] CHECK_SHORT_DEV_DESC FAILED
E (96820) ENUM: Full dev desc has wrong bDescriptorType
E (96820) ENUM: [0:0] CHECK_FULL_DEV_DESC FAILED
W (97470) ENUM: Device has more than 1 configuration
E (97470) USBH: Dev 16 EP 0 STALL
E (97470) ENUM: Bad transfer status 4: CHECK_SHORT_CONFIG_DESC
E (97470) ENUM: [0:0] CHECK_SHORT_CONFIG_DESC FAILED
W (98120) ENUM: [0:0] Unexpected (8) device response length (expected 16)
E (98120) ENUM: Device returned less bytes than requested
E (98120) ENUM: [0:0] CHECK_SHORT_CONFIG_DESC FAILED
W (98770) ENUM: [0:0] Unexpected (8) device response length (expected 17)
E (98770) ENUM: Device returned less bytes than requested
E (98770) ENUM: [0:0] CHECK_FULL_CONFIG_DESC FAILED
E (99420) ENUM: Short config desc has wrong bDescriptorType
E (99420) ENUM: [0:0] CHECK_SHORT_CONFIG_DESC FAILED
E (100080) ENUM: Full config desc has wrong bDescriptorType
E (100080) ENUM: [0:0] CHECK_FULL_CONFIG_DESC FAILED
E (100660) USBH: Dev 0 EP 0 STALL
E (100660) ENUM: Bad transfer status 4: CHECK_SHORT_DEV_DESC
E (100660) ENUM: [0:0] CHECK_SHORT_DEV_DESC FAILED
E (101280) USBH: Dev 16 EP 0 STALL
E (101280) ENUM: Bad transfer status 4: CHECK_FULL_DEV_DESC
E (101280) ENUM: [0:0] CHECK_FULL_DEV_DESC FAILED
E (101930) USBH: Dev 16 EP 0 STALL
E (101930) ENUM: Bad transfer status 4: CHECK_SHORT_CONFIG_DESC
E (101930) ENUM: [0:0] CHECK_SHORT_CONFIG_DESC FAILED
E (102580) USBH: Dev 16 EP 0 STALL
E (102580) ENUM: Bad transfer status 4: CHECK_FULL_CONFIG_DESC
E (102580) ENUM: [0:0] CHECK_FULL_CONFIG_DESC FAILED
E (103230) USBH: Dev 16 EP 0 STALL
```
Or
```
E (121120) USBH: Dev 33 EP 0 STALL
E (121120) ENUM: Bad transfer status 4: CHECK_CONFIG
E (121120) ENUM: [0:0] CHECK_CONFIG FAILED
```

View File

@ -0,0 +1,19 @@
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
PRIV_INCLUDE_DIRS "."
REQUIRES usb unity
WHOLE_ARCHIVE)
# Determine whether tinyusb is fetched from component registry or from local path
idf_build_get_property(build_components BUILD_COMPONENTS)
if(tinyusb IN_LIST build_components)
set(tinyusb_name tinyusb) # Local component
else()
set(tinyusb_name espressif__tinyusb) # Managed component
endif()
# Pass tusb_config.h from this component to TinyUSB
idf_component_get_property(tusb_lib ${tinyusb_name} COMPONENT_LIB)
target_include_directories(${tusb_lib} PRIVATE ".")

View File

@ -0,0 +1,10 @@
menu "ENUM:: test configuration"
config TINYUSB_DEBUG_LEVEL
int "TinyUSB log level (0-3)"
default 1
range 0 3
help
Specify verbosity of TinyUSB log output.
endmenu

View File

@ -0,0 +1,5 @@
## IDF Component Manager Manifest File
dependencies:
espressif/tinyusb:
version: '>=0.17.0'
public: true

View File

@ -0,0 +1,246 @@
/*
* SPDX-FileCopyrightText: 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_rom_gpio.h"
#include "soc/gpio_sig_map.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "tusb.h"
#include "mock_dev.h"
#define DEVICE_MOUNT_TIMEOUT_MS 5000
#define DEVICE_TASK_SIZE 4096
#define DEVICE_TASK_PRIO 5
#define DEVICE_TASK_AFFINITY 0x7FFFFFFF
#define DEVICE_MAX_DESC_BUF_SIZE 32
#if (CONFIG_IDF_TARGET_ESP32P4)
#define USB_SRP_BVALID_IN_IDX USB_SRP_BVALID_PAD_IN_IDX
#endif // CONFIG_IDF_TARGET_ESP32P4
//
// Test configuration
//
static SemaphoreHandle_t mock_device_test_stop = NULL;
static TaskHandle_t mock_device_task_hdl = NULL;
static mock_dev_cfg_t *mock_dev_cfg;
//
// Device connect/disconnect emulation
//
static void mock_dev_insert(void)
{
if (mock_dev_cfg && mock_dev_cfg->conn_dconn.enabled) {
// 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(mock_dev_cfg->conn_dconn.delay_ms));
}
}
static void mock_dev_remove(void)
{
if (mock_dev_cfg && mock_dev_cfg->conn_dconn.enabled) {
// 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(mock_dev_cfg->conn_dconn.delay_ms));
}
}
//
// TinyUSB driver related logic
//
#ifndef tusb_teardown
#warning "Teardown feature is not available, please use tinyUSB component with tusb_teardown() support"
#endif // tusb_teardown
static void mock_device_task(void *arg)
{
// RTOS forever loop
while (1) {
tud_task();
}
}
bool mock_dev_setup(mock_dev_cfg_t *cfg)
{
// Create semaphore
mock_device_test_stop = xSemaphoreCreateBinary();
if (mock_device_test_stop == NULL) {
return false;
}
// Init tusb device stack
if (!tusb_init()) {
return false;
}
// Create task for device stack handling
xTaskCreatePinnedToCore(mock_device_task,
"TinyUSB Device task",
DEVICE_TASK_SIZE,
NULL,
DEVICE_TASK_PRIO,
&mock_device_task_hdl,
DEVICE_TASK_AFFINITY);
if (mock_device_task_hdl == NULL) {
return false;
}
// Configure mock USB device
mock_dev_cfg = cfg;
mock_dev_cfg->enumeration.curr_stage = MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC;
// Insert mock USB device
mock_dev_insert();
return true;
}
esp_err_t mock_dev_wait_flag(void)
{
if (!mock_device_test_stop) {
return ESP_ERR_INVALID_STATE;
}
return (xSemaphoreTake(mock_device_test_stop, pdMS_TO_TICKS(DEVICE_MOUNT_TIMEOUT_MS))
? ESP_OK
: ESP_ERR_TIMEOUT);
}
void mock_dev_release(void)
{
// Short delay to allow device to show up
vTaskDelay(10);
// Remove mock USB device
mock_dev_remove();
// Uninstall TinyUSB driver
tusb_teardown();
// Delete device handling task
if (mock_device_task_hdl) {
vTaskDelete(mock_device_task_hdl);
mock_device_task_hdl = NULL;
}
// Delete semaphore
if (mock_device_test_stop) {
vSemaphoreDelete(mock_device_test_stop);
}
mock_dev_cfg = NULL;
}
//
// TinyUSB callbacks
//
// Basic
uint8_t const *tud_descriptor_device_cb(void)
{
printf("\t <- Device Descriptor request\n");
mock_dev_stage_data_t *stage_config = &mock_dev_cfg->enumeration.stage_config[mock_dev_cfg->enumeration.curr_stage];
if (stage_config->stop_test) {
xSemaphoreGive(mock_device_test_stop);
}
mock_dev_cfg->enumeration.curr_stage++;
return stage_config->desc;
}
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
{
printf("\t <- Configuration Descriptor request, index=%d\n", index);
mock_dev_stage_data_t *stage_config = &mock_dev_cfg->enumeration.stage_config[mock_dev_cfg->enumeration.curr_stage];
if (stage_config->stop_test) {
xSemaphoreGive(mock_device_test_stop);
}
mock_dev_cfg->enumeration.curr_stage++;
return stage_config->desc;
}
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
uint8_t chr_count;
static uint16_t _desc_str[DEVICE_MAX_DESC_BUF_SIZE];
printf("\t <- String Descriptor request, index=%d, langid=%#x\n", index, langid);
mock_dev_stage_data_t *stage_config = &mock_dev_cfg->enumeration.stage_config[mock_dev_cfg->enumeration.curr_stage];
if (stage_config->stop_test) {
xSemaphoreGive(mock_device_test_stop);
}
mock_dev_cfg->enumeration.curr_stage++;
if (stage_config->str_desc == NULL) {
// Move to Set configuration stage
mock_dev_cfg->enumeration.curr_stage = MOCK_DEV_STAGE_SET_CONFIG;
return NULL;
}
if (index == 0) {
memcpy(&_desc_str[1], stage_config->str_desc, 2);
chr_count = 1;
} else {
const char *str = stage_config->str_desc;
chr_count = strnlen(str, DEVICE_MAX_DESC_BUF_SIZE - 1); // Buffer len - header
// Convert ASCII string into UTF-16
for (uint8_t i = 0; i < chr_count; i++) {
_desc_str[1 + i] = str[i];
}
}
// First byte is length in bytes (including header), second byte is descriptor type (TUSB_DESC_STRING)
_desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2);
return _desc_str;
}
// Advanced
uint8_t const * tud_descriptor_bos_cb(void)
{
printf("\t <- BOS Descriptor request\n");
return NULL;
}
#if (TUD_OPT_HIGH_SPEED)
uint8_t const *tud_descriptor_device_qualifier_cb(void)
{
return NULL;
}
uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
return NULL;
}
#endif // TUD_OPT_HIGH_SPEED
void tud_mount_cb(void)
{
printf("\t <- Device enabled\n");
if (mock_device_test_stop) {
xSemaphoreGive(mock_device_test_stop);
}
}
void tud_umount_cb(void)
{
printf("\t <- Device disabled\n");
}
void tud_suspend_cb(bool remote_wakeup_en)
{
printf("\t <- Device suspend\n");
}
void tud_resume_cb(void)
{
printf("\t <- Device resume\n");
}
#endif // SOC_USB_OTG_SUPPORTED

View File

@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
//
// TinyUSB helpers to mock the device
//
typedef enum {
MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC = 0x00,
MOCK_DEV_STAGE_REQ_FULL_DEV_DESC,
MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC,
MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC,
MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE,
MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE,
MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC,
MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC,
MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC,
MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC,
MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC,
MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC,
MOCK_DEV_STAGE_SET_CONFIG,
MOCK_DEV_STAGE_MAX
} mock_dev_stage_t;
typedef struct {
union {
const uint8_t *desc;
const char *str_desc;
};
bool stop_test;
} mock_dev_stage_data_t;
typedef struct {
// connection/disconnection emulation
struct {
bool enabled;
uint32_t delay_ms;
} conn_dconn;
// enumeration logic
struct {
mock_dev_stage_t curr_stage;
mock_dev_stage_data_t stage_config[MOCK_DEV_STAGE_MAX];
} enumeration;
} mock_dev_cfg_t;
/**
* @brief Setup the Mock device
*
* @param[in] mock_dev_cfg Mock device configuration
*
* @note During the setup procedure:
* - Create semaphore
* - Init TinyUSB device stack
* - Create task for device stack handling
* - Configure the Mock device
* - Set current stage to MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC
* - Insert Mock device (Emulate physical connection, if conn_dconn parameter was enabled during configuration)
*
* @return
* - true if mock device configured successfully and ready
* - false if mock device hasn't been configured
*/
bool mock_dev_setup(mock_dev_cfg_t *mock_dev_cfg);
/**
* @brief Wait the stop flag
*
* @note The stop flag is the semaphore mock_device_test_stop, which is triggered by:
* - Stop flag configuration parameter for mock device
* - tud_mount_cb(void)
*
* @return Error code value
* - ESP_ERR_INVALID_STATE if mock device hasn't been started
* - ESP_ERR_TIMEOUT if timeout has occurred
* - ESP_OK if there was no error during test stop
*/
esp_err_t mock_dev_wait_flag(void);
/**
* @brief Release the Mock device
*
* @note During the release process:
* - Short delay to allow device to show up
* - Remove mock USB device (Emulate physical disconnection, if conn_dconn parameter was enabled during configuration)
* - Uninstall TinyUSB driver
* - Delete device handling task
* - Delete semaphore
* - Flush Mock device configuration
*/
void mock_dev_release(void);

View File

@ -0,0 +1,276 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "tusb.h"
#include "mock_dev.h"
#define DEVICE_CONN_DCONN_DELAY_MS 50
//
// Mock Device Descriptors definitions
//
static const tusb_desc_device_t mock_device_desc = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = 64,
.idVendor = 0x0001,
.idProduct = 0x0002,
.bcdDevice = 0x0000,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
static const uint8_t mock_config_desc[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUD_CONFIG_DESC_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
};
static const char *mock_langid_str_desc = {
(char[]){0x09, 0x04}, // 0: LANGID
};
static const char *mock_manu_str_desc = {
"Espressif", // 1: Manufacturer
};
static const char *mock_prod_str_desc = {
"Enum Testing", // 2: Product
};
static const char *mock_ser_str_desc = {
"123456", // 3: Serials, should use chip ID
};
//
// Test cases
//
/**
* @brief Test Device enumeration process: 200 attempts in a row
*
* @note Test takes around 2 minutes
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait enumeration complete
* 3. Uninstall TinyUSB device stack
* 4. Increase counter
* 5. Repeat step 1 if i < 200
* 6. assert(counter == 200)
*/
TEST_CASE("enum::assign_device_address_200", "[mock_enum_device]")
{
uint16_t counter = 0;
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
for (uint16_t i = 0; i < 200; i++) {
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
counter++;
}
TEST_ASSERT_EQUAL(counter, 200);
}
/**
* @brief Test Device enumeration process: 2000 attempts in a row
*
* @note: Test takes around 10 minutes
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait enumeration complete
* 3. Uninstall TinyUSB device stack
* 4. Increase counter
* 5. Repeat step 1 if i < 2000
* 6. assert(counter == 2000)
*/
TEST_CASE("enum::assign_device_address_2000", "[mock_enum_device_manual]")
{
uint16_t counter = 0;
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
for (uint16_t i = 0; i < 2000; i++) {
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
counter++;
}
TEST_ASSERT_EQUAL(counter, 2000);
}
/**
* @brief Test Device enumeration process: 200 attempts in a row + emulate disconnection via bvalid signal
*
* @note: Test takes around 2 minutes
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait enumeration complete
* 3. Uninstall TinyUSB device stack
* 4. Increase counter
* 5. Repeat step 1 if i < 200
* 6. assert(counter == 200)
*/
TEST_CASE("enum::assign_device_address_200_with_power_cycle", "[mock_enum_device]")
{
uint16_t counter = 0;
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
for (uint16_t i = 0; i < 200; i++) {
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
counter++;
}
TEST_ASSERT_EQUAL(counter, 200);
}

View File

@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "unity_test_utils_memory.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_private/usb_phy.h"
#include "unity.h"
static usb_phy_handle_t phy_hdl = NULL;
void setUp(void)
{
unity_utils_record_free_mem();
// Configure USB PHY for USB Device
usb_phy_config_t phy_config = {
.controller = USB_PHY_CTRL_OTG,
.target = USB_PHY_TARGET_INT,
.otg_mode = USB_OTG_MODE_DEVICE,
};
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_new_phy(&phy_config, &phy_hdl), "Failed to init USB Device PHY");
}
void tearDown(void)
{
// Short delay to allow task to be cleaned up
vTaskDelay(10);
// Deinitialize the internal USB PHY
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Failed to delete USB Device PHY");
phy_hdl = NULL;
unity_utils_evaluate_leaks();
}
void app_main(void)
{
// ____ ___ ___________________ __ __
// | | \/ _____/\______ \ _/ |_ ____ _______/ |_
// | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\.
// | | / / \ | | \ | | \ ___/ \___ \ | |
// |______/ /_______ / |______ / |__| \___ >____ > |__|
// \/ \/ \/ \/
printf(" ____ ___ ___________________ __ __ \r\n");
printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n");
printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n");
printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n");
printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n");
printf(" \\/ \\/ \\/ \\/ \r\n");
unity_utils_setup_heap_record(80);
unity_utils_set_leak_level(128);
unity_run_menu();
}

View File

@ -0,0 +1,302 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "tusb.h"
#include "mock_dev.h"
//
// Mock Device Descriptors definitions
//
static const tusb_desc_device_t mock_device_desc = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = 64,
.idVendor = 0x0001,
.idProduct = 0x0002,
.bcdDevice = 0x0000,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
static const tusb_desc_device_t mock_device_desc_invalid_bDescriptor_type = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = 0x00,
};
static const tusb_desc_device_t mock_device_desc_bNumConfiguration_2 = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bNumConfigurations = 0x02,
};
static const tusb_desc_configuration_t mock_config_desc_unexpected_response_length_less = {
.bLength = sizeof(tusb_desc_configuration_t),
.wTotalLength = 0,
};
static const tusb_desc_configuration_t mock_config_desc_invalid_bDescriptor_type = {
.bLength = sizeof(tusb_desc_configuration_t),
.wTotalLength = sizeof(tusb_desc_configuration_t),
};
static const tusb_desc_configuration_t mock_config_desc = {
.bLength = sizeof(tusb_desc_configuration_t),
.bDescriptorType = TUSB_DESC_CONFIGURATION,
.wTotalLength = sizeof(tusb_desc_configuration_t),
.bNumInterfaces = 0,
.bConfigurationValue = 1,
.bmAttributes = TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
.bMaxPower = 0x50,
};
//
// Test cases
//
/**
* @brief Cancel enumeration: SHORT_DEV_DESC stage, invalid bDescriptorType field in the Device Descriptor
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Return Device Descriptor with invalid bDescriptorType filed
* 4. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::CHECK_SHORT_DEV_DESC_invalid_bDescriptorType", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc_invalid_bDescriptor_type,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief Cancel enumeration: FULL_DEV_DESC stage, invalid bDescriptorType field in the Device Descriptor
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Return correct short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 5. Return full Device Descriptor with invalid bDescriptorType filed
* 6. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::CHECK_FULL_DEV_DESC_invalid_bDescriptorType", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc_invalid_bDescriptor_type,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief Cancel enumeration: Device has more that 1 Configuration
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Return correct short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 5. Return full Device Descriptor with bNumConfiguration=2
* 6. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::CHECK_FULL_DEV_DESC_bNumConfigurations=2", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc_bNumConfiguration_2,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief Cancel enumeration: short Configuration Descriptor unexpected length
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Return correct short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 5. Return correct full Device Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Return short Configuration Descriptor with unexpected length (less), wTotalLength=0
* 8. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::CHECK_SHORT_CONFIG_DESC_unexpected_response_length_(less)", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = (const uint8_t *) &mock_config_desc_unexpected_response_length_less,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief Cancel enumeration: full Configuration Descriptor unexpected length
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Return correct short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 5. Return correct full Device Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Return short Configuration Descriptor
* 8. Wait Get Configuration Descriptor request
* 9. Return full Configuration Descriptor with unexpected length (less), wTotalLength=0
* 10. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::CHECK_FULL_CONFIG_DESC_unexpected_response_length_(less)", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = (const uint8_t *) &mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = (const uint8_t *) &mock_config_desc_unexpected_response_length_less,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief Cancel enumeration: short Configuration Descriptor wrong bDescriptorType
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Return correct short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 5. Return correct full Device Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Return short Configuration Descriptor with wrong bDescriptorType=0
* 8. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::CHECK_SHORT_CONFIG_DESC_invalid_bDescriptorType", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = (const uint8_t *) &mock_config_desc_invalid_bDescriptor_type,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief Cancel enumeration: full Configuration Descriptor wrong bDescriptorType
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Return correct short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 5. Return correct full Device Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Return short Configuration Descriptor
* 8. Wait Get Configuration Descriptor request
* 7. Return full Configuration Descriptor with wrong bDescriptorType=0
* 8. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::CHECK_FULL_CONFIG_DESC_invalid_bDescriptorType", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = (const uint8_t *) &mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = (const uint8_t *) &mock_config_desc_invalid_bDescriptor_type,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}

View File

@ -0,0 +1,905 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "tusb.h"
#include "mock_dev.h"
//
// Mock Device Descriptors definitions
//
static const tusb_desc_device_t mock_device_desc = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = 64,
.idVendor = 0x0001,
.idProduct = 0x0002,
.bcdDevice = 0x0000,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
static const uint8_t mock_config_desc[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUD_CONFIG_DESC_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
};
static const char *mock_langid_str_desc = {
(char[]){0x09, 0x04}, // 0: LANGID
};
static const char *mock_manu_str_desc = {
"Espressif", // 1: Manufacturer
};
static const char *mock_prod_str_desc = {
"Enum Testing", // 2: Product
};
static const char *mock_ser_str_desc = {
"123456", // 3: Serials, should use chip ID
};
//
// Test cases
//
/**
* @brief STALL Get short Device Descriptor request (S/W teardown)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. STALL EP0
* 4. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_DEV_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full Device Descriptor request (S/W teardown)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. STALL EP0
* 4. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_DEV_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short Configuration Descriptor request (S/W teardown)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. STALL EP0
* 6. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_CONFIG_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full Configuration Descriptor request (S/W teardown)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. STALL EP0
* 8. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_CONFIG_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short String Descriptor - LANGID (S/W teardown)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. STALL EP0
* 10. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_LANGID_TABLE_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full String Descriptor - LANGID (S/W teardown)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. STALL EP0
* 10. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_LANGID_TABLE_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short String Descriptor - Manufacturer (S/W teardown)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufactirer)
* 13. STALL EP0
* 14. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_MANU_STR_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full String Descriptor - Manufacturer (S/W teardown)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufactirer)
* 13. Reply with short String Descriptor (Manufactirer)
* 14. Wait Get String Descriptor request (Manufactirer)
* 15. STALL EP0
* 16. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_MANU_STR_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short String Descriptor - Product (S/W teardown)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. STALL EP0
* 18. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_PROD_STR_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full String Descriptor - Product (S/W teardown)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. STALL EP0
* 20. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_PROD_STR_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short String Descriptor - Serial (S/W teardown)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. Reply with full String Descriptor (Product)
* 20. Wait Get String Descriptor request (Serial)
* 21. STALL EP0
* 22. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_SER_STR_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full String Descriptor - Serial (S/W teardown)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. Reply with full String Descriptor (Product)
* 20. Wait Get String Descriptor request (Serial)
* 21. Reply with short String Descriptor (Serial)
* 22. Wait Get String Descriptor request (Serial)
* 23. STALL EP0
* 24. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_SER_STR_DESC_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Set Configuration (S/W teardown)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. Reply with full String Descriptor (Product)
* 20. Wait Get String Descriptor request (Serial)
* 21. Reply with short String Descriptor (Serial)
* 22. Wait Get String Descriptor request (Serial)
* 23. Reply with full String Descriptor (Serial)
* 24. Wait Set Configuration request
* 25. STALL EP0
* 26. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::SET_CONFIG_STALLed", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = NULL,
.stop_test = true,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief Regular Device enumeration routine (S/W teardown)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. Reply with full String Descriptor (Product)
* 20. Wait Get String Descriptor request (Serial)
* 21. Reply with short String Descriptor (Serial)
* 22. Wait Get String Descriptor request (Serial)
* 23. Reply with full String Descriptor (Serial)
* 24. Wait Set Configuration request
* 25. Acknowledge Configuration setup
* 26. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::complete", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}

View File

@ -0,0 +1,964 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "tusb.h"
#include "mock_dev.h"
#define DEVICE_CONN_DCONN_DELAY_MS 250
//
// Mock Device Descriptors definitions
//
static const tusb_desc_device_t mock_device_desc = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = 64,
.idVendor = 0x0001,
.idProduct = 0x0002,
.bcdDevice = 0x0000,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
static const uint8_t mock_config_desc[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUD_CONFIG_DESC_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
};
static const char *mock_langid_str_desc = {
(char[]){0x09, 0x04}, // 0: LANGID
};
static const char *mock_manu_str_desc = {
"Espressif", // 1: Manufacturer
};
static const char *mock_prod_str_desc = {
"Enum Testing", // 2: Product
};
static const char *mock_ser_str_desc = {
"123456", // 3: Serials, should use chip ID
};
//
// Test cases
//
/**
* @brief STALL Get short Device Descriptor request (S/W teardown + emulate disconnection via bvalid signal)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. STALL EP0
* 4. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_DEV_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full Device Descriptor request (S/W teardown + emulate disconnection via bvalid signal)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. STALL EP0
* 4. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_DEV_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short Configuration Descriptor request (S/W teardown + emulate disconnection via bvalid signal)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. STALL EP0
* 6. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_CONFIG_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full Configuration Descriptor request (S/W teardown + emulate disconnection via bvalid signal)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. STALL EP0
* 8. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_CONFIG_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = NULL,
.stop_test = true,
},
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short String Descriptor - LANGID (S/W teardown + emulate disconnection via bvalid signal)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. STALL EP0
* 10. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_LANGID_TABLE_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full String Descriptor - LANGID (S/W teardown + emulate disconnection via bvalid signal)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. STALL EP0
* 10. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_LANGID_TABLE_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short String Descriptor - Manufacturer (S/W teardown + emulate disconnection via bvalid signal)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufactirer)
* 13. STALL EP0
* 14. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_MANU_STR_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full String Descriptor - Manufacturer (S/W teardown + emulate disconnection via bvalid signal)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufactirer)
* 13. Reply with short String Descriptor (Manufactirer)
* 14. Wait Get String Descriptor request (Manufactirer)
* 15. STALL EP0
* 16. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_MANU_STR_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short String Descriptor - Product (S/W teardown + emulate disconnection via bvalid signal)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. STALL EP0
* 18. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_PROD_STR_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full String Descriptor - Product (S/W teardown + emulate disconnection via bvalid signal)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. STALL EP0
* 20. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_PROD_STR_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get short String Descriptor - Serial (S/W teardown + emulate disconnection via bvalid signal)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. Reply with full String Descriptor (Product)
* 20. Wait Get String Descriptor request (Serial)
* 21. STALL EP0
* 22. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_SHORT_SER_STR_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Get full String Descriptor - Serial (S/W teardown + emulate disconnection via bvalid signal)
*
* @note STALL Get String Descriptor request is allowed (means device doesn't have string descriptor)
* Thus, mock_dev_cfg.stop_test parameter is not used.
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. Reply with full String Descriptor (Product)
* 20. Wait Get String Descriptor request (Serial)
* 21. Reply with short String Descriptor (Serial)
* 22. Wait Get String Descriptor request (Serial)
* 23. STALL EP0
* 24. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::GET_FULL_SER_STR_DESC_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = NULL,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief STALL Set Configuration (S/W teardown + emulate disconnection via bvalid signal)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. Reply with full String Descriptor (Product)
* 20. Wait Get String Descriptor request (Serial)
* 21. Reply with short String Descriptor (Serial)
* 22. Wait Get String Descriptor request (Serial)
* 23. Reply with full String Descriptor (Serial)
* 24. Wait Set Configuration request
* 25. STALL EP0
* 26. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::SET_CONFIG_STALLed_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = NULL,
.stop_test = true,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}
/**
* @brief Regular Device enumeration routine (S/W teardown + emulate disconnection via bvalid signal)
*
* Scenario:
* 1. Install TinyUSB device stack
* 2. Wait for Get Device Descriptor request
* 3. Reply with short Device Descriptor
* 4. Wait for Get Device Descriptor request
* 3. Reply with full Device Descriptor
* 4. Wait Get Configuration Descriptor request
* 5. Reply with short Configuration Descriptor
* 6. Wait Get Configuration Descriptor request
* 7. Reply with full Configuration Descriptor
* 8. Wait Get String Descriptor request (LANGID)
* 9. Reply with short String Descriptor (LANGID)
* 10. Wait Get String Descriptor request (LANGID)
* 11. Reply with full String Descriptor (LANGID)
* 12. Wait Get String Descriptor request (Manufacturer)
* 13. Reply with short String Descriptor (Manufacturer)
* 14. Wait Get String Descriptor request (Manufacturer)
* 15. Reply with full String Descriptor (Manufacturer)
* 16. Wait Get String Descriptor request (Product)
* 17. Reply with short String Descriptor (Product)
* 18. Wait Get String Descriptor request (Product)
* 19. Reply with full String Descriptor (Product)
* 20. Wait Get String Descriptor request (Serial)
* 21. Reply with short String Descriptor (Serial)
* 22. Wait Get String Descriptor request (Serial)
* 23. Reply with full String Descriptor (Serial)
* 24. Wait Set Configuration request
* 25. Acknowledge Configuration setup
* 26. Uninstall TinyUSB device stack
*/
TEST_CASE("enum::complete_with_conn_dconn", "[mock_enum_device]")
{
mock_dev_cfg_t mock_dev_cfg = {
.conn_dconn = {
.enabled = true,
.delay_ms = DEVICE_CONN_DCONN_DELAY_MS,
},
.enumeration = {
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_DEV_DESC] = {
.desc = (const uint8_t *) &mock_device_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_CONFIG_DESC] = {
.desc = mock_config_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_CONFIG_DESC] = {
.desc = mock_config_desc,
},
// String Descriptors
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_LANGID_TABLE] = {
.str_desc = mock_langid_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_MANU_STR_DESC] = {
.str_desc = mock_manu_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_PROD_STR_DESC] = {
.str_desc = mock_prod_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_SHORT_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_REQ_FULL_SER_STR_DESC] = {
.str_desc = mock_ser_str_desc,
},
.stage_config[MOCK_DEV_STAGE_SET_CONFIG] = {
.desc = mock_config_desc,
}
},
};
TEST_ASSERT_EQUAL(true, mock_dev_setup(&mock_dev_cfg));
TEST_ASSERT_EQUAL(ESP_OK, mock_dev_wait_flag());
mock_dev_release();
}

View File

@ -0,0 +1,74 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
//
// TinyUSB Port selection
//
#if (CONFIG_IDF_TARGET_ESP32P4)
#define CONFIG_TINYUSB_RHPORT_HS
#endif // CONFIG_IDF_TARGET_ESP32P4
//
// TinyUSB Debug
//
#define CFG_TUSB_DEBUG CONFIG_TINYUSB_DEBUG_LEVEL
//
// TinyUSB Peripheral Port selection (build-time)
//
#ifdef CONFIG_TINYUSB_RHPORT_HS
# define CFG_TUSB_RHPORT1_MODE OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED
#else
# define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED
#endif
//
// TinyUSB OS
//
#define CFG_TUSB_OS OPT_OS_FREERTOS
//
// TinyUSB specific memory attributes
//
//
// DCD DWC2 Mode
//
#define CFG_TUD_DWC2_SLAVE_ENABLE 0 // We don't use Slave/IRQ mode in this test
//
// DMA & Cache
//
// DMA Mode has a priority over Slave/IRQ mode and will be used if hardware supports it
#define CFG_TUD_DWC2_DMA_ENABLE 1 // Enable DMA
#if CONFIG_CACHE_L1_CACHE_LINE_SIZE
// To enable the dcd_dcache clean/invalidate/clean_invalidate calls
# define CFG_TUD_MEM_DCACHE_ENABLE 1
#define CFG_TUD_MEM_DCACHE_LINE_SIZE CONFIG_CACHE_L1_CACHE_LINE_SIZE
// NOTE: starting with esp-idf v5.3 there is specific attribute present: DRAM_DMA_ALIGNED_ATTR
# define CFG_TUSB_MEM_SECTION __attribute__((aligned(CONFIG_CACHE_L1_CACHE_LINE_SIZE))) DRAM_ATTR
#else
# define CFG_TUD_MEM_CACHE_ENABLE 0
# define CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) DRAM_ATTR
#endif // CONFIG_CACHE_L1_CACHE_LINE_SIZE
//
// TinyUSB DEVICE CONFIGURATION
//
#define CFG_TUD_ENABLED 1 // Enable Device stack
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32s3
@pytest.mark.temp_skip_ci(targets=['esp32s3'], reason='only to run locally')
def test_usb_enum(dut: Dut) -> None:
dut.run_all_single_board_cases(group='mock_enum_device', timeout=250) # some tests take more than default timeout

View File

@ -0,0 +1,8 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
# CONFIG_ESP_TASK_WDT_INIT is not set
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
# CONFIG_UNITY_ENABLE_FLOAT is not set
# CONFIG_UNITY_ENABLE_DOUBLE is not set
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y