Skip to content

Commit 3f44d4a

Browse files
committed
feature(test_apps): Added initial msc_storage test application
1 parent 597ce0b commit 3f44d4a

File tree

8 files changed

+312
-0
lines changed

8 files changed

+312
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# The following lines of boilerplate have to be in your project's
2+
# CMakeLists in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.16)
4+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
5+
6+
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
7+
idf_build_set_property(MINIMAL_BUILD ON)
8+
9+
project(test_app_msc_storage)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
idf_component_register(SRC_DIRS .
2+
INCLUDE_DIRS .
3+
REQUIRES unity
4+
WHOLE_ARCHIVE)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## IDF Component Manager Manifest File
2+
dependencies:
3+
espressif/esp_tinyusb:
4+
version: "*"
5+
override_path: "../../../"
6+
espressif/tinyusb:
7+
path: /home/roman-esp/workspace/Espressif/tinyusb
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdio.h>
8+
#include <string.h>
9+
#include "unity.h"
10+
#include "freertos/FreeRTOS.h"
11+
#include "freertos/task.h"
12+
#include "unity_test_runner.h"
13+
#include "unity_test_utils_memory.h"
14+
#include "test_device.h"
15+
16+
/* setUp runs before every test */
17+
void setUp(void)
18+
{
19+
unity_utils_record_free_mem();
20+
test_device_setup();
21+
}
22+
23+
/* tearDown runs after every test */
24+
void tearDown(void)
25+
{
26+
// Short delay to allow task to be cleaned up
27+
vTaskDelay(10);
28+
test_device_release();
29+
unity_utils_evaluate_leaks();
30+
}
31+
32+
33+
void app_main(void)
34+
{
35+
/*
36+
_ _ _
37+
| | (_) | |
38+
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
39+
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
40+
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
41+
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
42+
| |______ __/ |
43+
|_|______| |___/
44+
_____ _____ _____ _____
45+
|_ _| ___/ ___|_ _|
46+
| | | |__ \ `--. | |
47+
| | | __| `--. \ | |
48+
| | | |___/\__/ / | |
49+
\_/ \____/\____/ \_/
50+
*/
51+
52+
printf(" _ _ _ \n");
53+
printf(" | | (_) | | \n");
54+
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
55+
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
56+
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
57+
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
58+
printf(" | |______ __/ | \n");
59+
printf(" |_|______| |___/ \n");
60+
printf(" _____ _____ _____ _____ \n");
61+
printf("|_ _| ___/ ___|_ _| \n");
62+
printf(" | | | |__ \\ `--. | | \n");
63+
printf(" | | | __| `--. \\ | | \n");
64+
printf(" | | | |___/\\__/ / | | \n");
65+
printf(" \\_/ \\____/\\____/ \\_/ \n");
66+
67+
unity_utils_setup_heap_record(80);
68+
unity_utils_set_leak_level(128);
69+
unity_run_menu();
70+
}
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "soc/soc_caps.h"
8+
9+
#if SOC_USB_OTG_SUPPORTED
10+
//
11+
#include <stdio.h>
12+
#include <string.h>
13+
//
14+
#include "freertos/FreeRTOS.h"
15+
#include "freertos/task.h"
16+
#include "freertos/semphr.h"
17+
//
18+
#include "esp_system.h"
19+
#include "esp_log.h"
20+
#include "esp_err.h"
21+
//
22+
#include "unity.h"
23+
#include "tinyusb.h"
24+
#include "tusb_msc_storage.h"
25+
//
26+
27+
28+
static SemaphoreHandle_t wait_mount = NULL;
29+
30+
#define TUSB_DEVICE_DELAY_MS 1000
31+
#define TEST_STORAGE_MEDIA_SPIFLASH 1 // Use SPI Flash as storage media
32+
33+
void test_device_setup(void)
34+
{
35+
wait_mount = xSemaphoreCreateBinary();
36+
TEST_ASSERT_NOT_NULL(wait_mount);
37+
}
38+
39+
void test_device_release(void)
40+
{
41+
TEST_ASSERT_NOT_NULL(wait_mount);
42+
vSemaphoreDelete(wait_mount);
43+
}
44+
45+
void test_device_wait(void)
46+
{
47+
// Wait for tud_mount_cb() to be called
48+
TEST_ASSERT_EQUAL_MESSAGE(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TUSB_DEVICE_DELAY_MS)), "No tusb_mount_cb() in time");
49+
// Delay to allow finish the enumeration
50+
// Disable this delay could lead to potential race conditions when the tud_task() is pinned to another CPU
51+
vTaskDelay(pdMS_TO_TICKS(250));
52+
}
53+
54+
// ========================== TinyUSB General Device Descriptors ===============================
55+
56+
#define EPNUM_MSC 1
57+
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN)
58+
59+
60+
static tusb_desc_device_t test_device_descriptor = {
61+
.bLength = sizeof(test_device_descriptor),
62+
.bDescriptorType = TUSB_DESC_DEVICE,
63+
.bcdUSB = 0x0200,
64+
.bDeviceClass = TUSB_CLASS_MISC,
65+
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
66+
.bDeviceProtocol = MISC_PROTOCOL_IAD,
67+
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
68+
.idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
69+
.idProduct = 0x4002,
70+
.bcdDevice = 0x100,
71+
.iManufacturer = 0x01,
72+
.iProduct = 0x02,
73+
.iSerialNumber = 0x03,
74+
.bNumConfigurations = 0x01
75+
};
76+
77+
static uint8_t const test_fs_configuration_desc[] = {
78+
// Config number, interface count, string index, total length, attribute, power in mA
79+
TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
80+
81+
// Interface number, string index, EP Out & EP In address, EP size
82+
// TUD_MSC_DESCRIPTOR(0, 0, 0x01, 0x81, 64),
83+
};
84+
85+
#if (TUD_OPT_HIGH_SPEED)
86+
static const tusb_desc_device_qualifier_t test_device_qualifier = {
87+
.bLength = sizeof(tusb_desc_device_qualifier_t),
88+
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
89+
.bcdUSB = 0x0200,
90+
.bDeviceClass = TUSB_CLASS_MISC,
91+
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
92+
.bDeviceProtocol = MISC_PROTOCOL_IAD,
93+
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
94+
.bNumConfigurations = 0x01,
95+
.bReserved = 0
96+
};
97+
98+
static uint8_t const test_hs_configuration_desc[] = {
99+
// Config number, interface count, string index, total length, attribute, power in mA
100+
TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
101+
102+
// Interface number, string index, EP Out & EP In address, EP size
103+
// TUD_MSC_DESCRIPTOR(0, 0, 0x01, 0x81, 512),
104+
};
105+
#endif // TUD_OPT_HIGH_SPEED
106+
107+
static char const *string_desc_arr[] = {
108+
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
109+
"TinyUSB", // 1: Manufacturer
110+
"TinyUSB Device", // 2: Product
111+
"123456", // 3: Serials
112+
"Test MSC Class", // 4. MSC
113+
};
114+
115+
// ========================== Callbacks ========================================
116+
/**
117+
* @brief TinyUSB callback for device mount.
118+
*
119+
* @note
120+
* For Linux-based Hosts: Reflects the SetConfiguration() request from the Host Driver.
121+
* For Win-based Hosts: SetConfiguration() request is present only with available Class in device descriptor.
122+
*/
123+
// void tud_mount_cb(void)
124+
// {
125+
// xSemaphoreGive(wait_mount);
126+
// }
127+
128+
static esp_err_t storage_init_spiflash(wl_handle_t *wl_handle)
129+
{
130+
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, NULL);
131+
if (data_partition == NULL) {
132+
return ESP_ERR_NOT_FOUND;
133+
}
134+
return wl_mount(data_partition, wl_handle);
135+
}
136+
137+
138+
TEST_CASE("run MSC class", "[esp_tinyusb_msc][init]")
139+
{
140+
#ifdef TEST_STORAGE_MEDIA_SPIFLASH
141+
static wl_handle_t wl_handle = WL_INVALID_HANDLE;
142+
ESP_ERROR_CHECK(storage_init_spiflash(&wl_handle));
143+
144+
const tinyusb_msc_spiflash_config_t config_spi = {
145+
.wl_handle = wl_handle,
146+
// .callback_mount_changed = storage_mount_changed_cb, /* First way to register the callback. This is while initializing the storage. */
147+
.mount_config.max_files = 5,
148+
};
149+
ESP_ERROR_CHECK(tinyusb_msc_storage_init_spiflash(&config_spi));
150+
// ESP_ERROR_CHECK(tinyusb_msc_register_callback(TINYUSB_MSC_EVENT_MOUNT_CHANGED, storage_mount_changed_cb)); /* Other way to register the callback i.e. registering using separate API. If the callback had been already registered, it will be overwritten. */
151+
#else // TEST_STORAGE_MEDIA_SPIFLASH
152+
static sdmmc_card_t *card = NULL;
153+
ESP_ERROR_CHECK(storage_init_sdmmc(&card));
154+
155+
const tinyusb_msc_sdmmc_config_t config_sdmmc = {
156+
.card = card,
157+
// .callback_mount_changed = storage_mount_changed_cb, /* First way to register the callback. This is while initializing the storage. */
158+
.mount_config.max_files = 5,
159+
};
160+
ESP_ERROR_CHECK(tinyusb_msc_storage_init_sdmmc(&config_sdmmc));
161+
// ESP_ERROR_CHECK(tinyusb_msc_register_callback(TINYUSB_MSC_EVENT_MOUNT_CHANGED, storage_mount_changed_cb)); /* Other way to register the callback i.e. registering using separate API. If the callback had been already registered, it will be overwritten. */
162+
#endif // TEST_STORAGE_MEDIA_SPIFLASH
163+
164+
// Install TinyUSB driver
165+
const tinyusb_config_t tusb_cfg = {
166+
.device_descriptor = &test_device_descriptor,
167+
.string_descriptor = string_desc_arr,
168+
.string_descriptor_count = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]),
169+
.external_phy = false,
170+
#if (TUD_OPT_HIGH_SPEED)
171+
.fs_configuration_descriptor = test_fs_configuration_desc,
172+
.hs_configuration_descriptor = test_hs_configuration_desc,
173+
.qualifier_descriptor = &test_device_qualifier,
174+
#else
175+
.configuration_descriptor = test_configuration_descriptor,
176+
#endif // TUD_OPT_HIGH_SPEED
177+
};
178+
179+
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
180+
test_device_wait();
181+
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
182+
}
183+
#endif // SOC_USB_OTG_SUPPORTED
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @brief Test device setup
9+
*/
10+
void test_device_setup(void);
11+
12+
/**
13+
* @brief Test device release
14+
*/
15+
void test_device_release(void);
16+
17+
/**
18+
* @brief Test device wait
19+
*
20+
* Waits the tusb_mount_cb() which indicates the device connected to the Host and enumerated.
21+
*/
22+
void test_device_wait(void);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
# SPDX-License-Identifier: Apache-2.0
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Configure TinyUSB, it will be used to mock USB devices
2+
CONFIG_TINYUSB_MSC_ENABLED=y
3+
4+
# Disable watchdogs, they'd get triggered during unity interactive menu
5+
CONFIG_ESP_INT_WDT=n
6+
CONFIG_ESP_TASK_WDT=n
7+
8+
# Run-time checks of Heap and Stack
9+
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
10+
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
11+
CONFIG_COMPILER_STACK_CHECK=y
12+
13+
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
14+
15+
CONFIG_COMPILER_CXX_EXCEPTIONS=y

0 commit comments

Comments
 (0)