Initial project setup
This commit is contained in:
13
.devcontainer/Dockerfile
Normal file
13
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
||||
ARG DOCKER_TAG=latest
|
||||
FROM espressif/idf:${DOCKER_TAG}
|
||||
|
||||
ENV LC_ALL=C.UTF-8
|
||||
ENV LANG=C.UTF-8
|
||||
|
||||
RUN apt-get update -y && apt-get install udev -y
|
||||
|
||||
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
|
||||
|
||||
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
|
||||
|
||||
CMD ["/bin/bash", "-c"]
|
||||
21
.devcontainer/devcontainer.json
Normal file
21
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "ESP-IDF QEMU",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"terminal.integrated.defaultProfile.linux": "bash",
|
||||
"idf.espIdfPath": "/opt/esp/idf",
|
||||
"idf.toolsPath": "/opt/esp",
|
||||
"idf.gitPath": "/usr/bin/git"
|
||||
},
|
||||
"extensions": [
|
||||
"espressif.esp-idf-extension",
|
||||
"espressif.esp-idf-web"
|
||||
]
|
||||
}
|
||||
},
|
||||
"runArgs": ["--privileged"]
|
||||
}
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
build/
|
||||
sdkconfig
|
||||
sdkconfig.old
|
||||
23
.vscode/c_cpp_properties.json
vendored
Normal file
23
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ESP-IDF",
|
||||
"compilerPath": "${config:idf.toolsPath}/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc",
|
||||
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
|
||||
"includePath": [
|
||||
"${config:idf.espIdfPath}/components/**",
|
||||
"${config:idf.espIdfPathWin}/components/**",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${config:idf.espIdfPath}/components",
|
||||
"${config:idf.espIdfPathWin}/components",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "gdbtarget",
|
||||
"request": "attach",
|
||||
"name": "Eclipse CDT GDB Adapter"
|
||||
},
|
||||
{
|
||||
"type": "espidf",
|
||||
"name": "Launch",
|
||||
"request": "launch"
|
||||
}
|
||||
]
|
||||
}
|
||||
19
.vscode/settings.json
vendored
Normal file
19
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"C_Cpp.intelliSenseEngine": "default",
|
||||
"idf.espIdfPath": "/Users/tarassivas/esp/v5.5.1/esp-idf",
|
||||
"idf.pythonInstallPath": "/Users/tarassivas/radioconda/bin/python",
|
||||
"idf.openOcdConfigs": [
|
||||
"board/esp32s3-builtin.cfg"
|
||||
],
|
||||
"idf.port": "/dev/tty.BLTH",
|
||||
"idf.toolsPath": "/Users/tarassivas/.espressif",
|
||||
"idf.customExtraVars": {
|
||||
"IDF_TARGET": "esp32s3"
|
||||
},
|
||||
"clangd.path": "/Users/tarassivas/.espressif/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/clangd",
|
||||
"clangd.arguments": [
|
||||
"--background-index",
|
||||
"--query-driver=/Users/tarassivas/.espressif/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc",
|
||||
"--compile-commands-dir=${workspaceFolder}/build"
|
||||
]
|
||||
}
|
||||
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(watch-watch)
|
||||
58
README.md
Normal file
58
README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# watch-watch
|
||||
|
||||
watch-watch — вбудована система на ESP32-S3 для нагляду за п’ятьма силовими модулями на базі Raspberry Pi 5. ESP32-S3 керує DC/DC перетворювачами через сигнали `EN`, а також надає USB CLI інтерфейс для налаштування та діагностики без окремого UART.
|
||||
|
||||
## Основні можливості
|
||||
- **Керування каналами живлення**: 5 незалежних ліній `EN` (GPIO 2, 4, 5, 18, 19), які можна увімкнути, вимкнути або перемкнути з коду чи CLI.
|
||||
- **Послідовний автотест**: у `app_main` реалізовано базову логіку — канали вмикаються по черзі з інтервалом 4 с, що дозволяє перевірити всі DC/DC.
|
||||
- **Нативний USB-CLI**: ESP32-S3 підключається до Raspberry Pi 5 по USB і стає CDC ACM пристроєм; командний інтерфейс дозволяє керувати каналами та дивитись стан у реальному часі.
|
||||
- **Модульна архітектура**: окремі компоненти `dcdc_controller` і `usb_cdc_cli` спрощують розширення (телеметрія, автоматизація, протоколи зв’язку).
|
||||
|
||||
## Структура проєкту
|
||||
```
|
||||
├── main
|
||||
│ ├── main.c // базова логіка, ініціалізація модулів
|
||||
│ ├── dcdc_controller.c/.h // API керування DC/DC каналами
|
||||
│ ├── usb_cdc_cli.c/.h // TinyUSB CLI для Raspberry Pi 5
|
||||
│ └── idf_component.yml // залежність на espressif/esp_tinyusb
|
||||
├── sdkconfig // конфігурація (опції TinyUSB увімкнені)
|
||||
└── README.md // цей файл
|
||||
```
|
||||
|
||||
## GPIO-призначення каналів
|
||||
|
||||
| Канал | GPIO | Призначення |
|
||||
|-------|------|-----------------------|
|
||||
| 0 | 2 | Модуль живлення #1 |
|
||||
| 1 | 4 | Модуль живлення #2 |
|
||||
| 2 | 5 | Модуль живлення #3 |
|
||||
| 3 | 18 | Модуль живлення #4 |
|
||||
| 4 | 19 | Модуль живлення #5 |
|
||||
|
||||
> Піни можна змінити в `main/dcdc_controller.c`, масив `s_dcdc_gpio_map`.
|
||||
|
||||
## USB CDC CLI
|
||||
Після підключення ESP32-S3 до Raspberry Pi 5 з’являється USB-пристрій (CDC ACM). У CLI доступні команди:
|
||||
|
||||
| Команда | Опис |
|
||||
|------------------|------------------------------------|
|
||||
| `help` | довідка по командам |
|
||||
| `status` | поточний стан усіх каналів |
|
||||
| `enable <n>` | увімкнути канал `n` (0..4) |
|
||||
| `disable <n>` | вимкнути канал `n` |
|
||||
| `toggle <n>` | перемкнути канал `n` |
|
||||
|
||||
CLI з’являється після того, як Raspberry Pi встановить DTR (наприклад, через `screen`, `picocom` або власний скрипт).
|
||||
|
||||
## Збірка та конфігурація
|
||||
1. Встановіть ESP-IDF v5.5.1 (шлях `IDF_PATH` має вказувати на `/Users/tarassivas/esp/v5.5.1/esp-idf`).
|
||||
2. Один раз виконайте `idf.py reconfigure`, щоб підвантажити залежності з `idf_component.yml`.
|
||||
3. Переконайтеся, що в `sdkconfig` увімкнено:
|
||||
- `CONFIG_TINYUSB_CDC_ENABLED=y`
|
||||
- `CONFIG_TINYUSB_CDC_RX_BUFSIZE=128` (або інше значення за вашим сценарієм).
|
||||
4. Зберіть проєкт: `idf.py build`, прошийте `idf.py flash`, переглядайте лог `idf.py monitor`.
|
||||
|
||||
## Подальший розвиток
|
||||
1. Додати протокол обміну з Raspberry Pi (наприклад, командний набір через USB CLI або окреме IPC).
|
||||
2. Включити зворотній зв’язок: вимір напруги/струму, датчики температури для кожного DC/DC.
|
||||
3. Розширити CLI (макроси, сценарії, логування станів) та інтегрувати з продакшн-скриптами.
|
||||
39
dependencies.lock
Normal file
39
dependencies.lock
Normal file
@@ -0,0 +1,39 @@
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
component_hash: 6a50305bc61c7a361da8c0833642be824e92dacb0a6001719a832a4e96e471bf
|
||||
dependencies:
|
||||
- name: idf
|
||||
require: private
|
||||
version: '>=5.0'
|
||||
- name: espressif/tinyusb
|
||||
registry_url: https://components.espressif.com
|
||||
require: public
|
||||
version: '>=0.14.2'
|
||||
source:
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
version: 1.7.6~2
|
||||
espressif/tinyusb:
|
||||
component_hash: 5ea9d3b6d6b0734a0a0b3491967aa0e1bece2974132294dbda5dd2839b247bfa
|
||||
dependencies:
|
||||
- name: idf
|
||||
require: private
|
||||
version: '>=5.0'
|
||||
source:
|
||||
registry_url: https://components.espressif.com
|
||||
type: service
|
||||
targets:
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
- esp32p4
|
||||
- esp32h4
|
||||
version: 0.19.0~2
|
||||
idf:
|
||||
source:
|
||||
type: idf
|
||||
version: 5.5.1
|
||||
direct_dependencies:
|
||||
- espressif/esp_tinyusb
|
||||
manifest_hash: 5a05c0273068b434734dee09d2c2ea1da5ef6181b054b4a9d51531ebb931282d
|
||||
target: esp32s3
|
||||
version: 2.0.0
|
||||
4
main/CMakeLists.txt
Normal file
4
main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
"dcdc_controller.c"
|
||||
"usb_cdc_cli.c"
|
||||
INCLUDE_DIRS ".")
|
||||
106
main/dcdc_controller.c
Normal file
106
main/dcdc_controller.c
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "dcdc_controller.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "dcdc";
|
||||
|
||||
static const gpio_num_t s_dcdc_gpio_map[DCDC_CHANNEL_COUNT] = {
|
||||
GPIO_NUM_2,
|
||||
GPIO_NUM_4,
|
||||
GPIO_NUM_5,
|
||||
GPIO_NUM_18,
|
||||
GPIO_NUM_19,
|
||||
};
|
||||
|
||||
static bool s_initialized;
|
||||
static bool s_channel_state[DCDC_CHANNEL_COUNT];
|
||||
|
||||
static bool dcdc_is_channel_valid(dcdc_channel_t channel)
|
||||
{
|
||||
return channel >= DCDC_CHANNEL_0 && channel < DCDC_CHANNEL_COUNT;
|
||||
}
|
||||
|
||||
esp_err_t dcdc_init(void)
|
||||
{
|
||||
if (s_initialized) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
gpio_config_t cfg = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pin_bit_mask = 0,
|
||||
};
|
||||
|
||||
for (int i = 0; i < DCDC_CHANNEL_COUNT; ++i) {
|
||||
cfg.pin_bit_mask = 1ULL << s_dcdc_gpio_map[i];
|
||||
esp_err_t err = gpio_config(&cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Не вдалося налаштувати GPIO %d (канал %d): %s",
|
||||
(int)s_dcdc_gpio_map[i], i, esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_set_level(s_dcdc_gpio_map[i], 0));
|
||||
s_channel_state[i] = false;
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
ESP_LOGI(TAG, "DCDC контролер ініціалізовано, каналів: %d", DCDC_CHANNEL_COUNT);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dcdc_set_state(dcdc_channel_t channel, bool enabled)
|
||||
{
|
||||
if (!dcdc_is_channel_valid(channel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = gpio_set_level(s_dcdc_gpio_map[channel], enabled ? 1 : 0);
|
||||
if (err == ESP_OK) {
|
||||
s_channel_state[channel] = enabled;
|
||||
ESP_LOGI(TAG, "Канал %d -> %s", channel, enabled ? "ON" : "OFF");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t dcdc_enable(dcdc_channel_t channel)
|
||||
{
|
||||
return dcdc_set_state(channel, true);
|
||||
}
|
||||
|
||||
esp_err_t dcdc_disable(dcdc_channel_t channel)
|
||||
{
|
||||
return dcdc_set_state(channel, false);
|
||||
}
|
||||
|
||||
esp_err_t dcdc_toggle(dcdc_channel_t channel)
|
||||
{
|
||||
if (!dcdc_is_channel_valid(channel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return dcdc_set_state(channel, !s_channel_state[channel]);
|
||||
}
|
||||
|
||||
bool dcdc_get_state(dcdc_channel_t channel)
|
||||
{
|
||||
if (!dcdc_is_channel_valid(channel)) {
|
||||
return false;
|
||||
}
|
||||
return s_channel_state[channel];
|
||||
}
|
||||
|
||||
size_t dcdc_channel_count(void)
|
||||
{
|
||||
return DCDC_CHANNEL_COUNT;
|
||||
}
|
||||
|
||||
gpio_num_t dcdc_get_gpio(dcdc_channel_t channel)
|
||||
{
|
||||
if (!dcdc_is_channel_valid(channel)) {
|
||||
return GPIO_NUM_NC;
|
||||
}
|
||||
return s_dcdc_gpio_map[channel];
|
||||
}
|
||||
25
main/dcdc_controller.h
Normal file
25
main/dcdc_controller.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#define DCDC_CHANNEL_COUNT 5
|
||||
|
||||
typedef enum {
|
||||
DCDC_CHANNEL_0 = 0,
|
||||
DCDC_CHANNEL_1,
|
||||
DCDC_CHANNEL_2,
|
||||
DCDC_CHANNEL_3,
|
||||
DCDC_CHANNEL_4,
|
||||
} dcdc_channel_t;
|
||||
|
||||
esp_err_t dcdc_init(void);
|
||||
esp_err_t dcdc_set_state(dcdc_channel_t channel, bool enabled);
|
||||
esp_err_t dcdc_enable(dcdc_channel_t channel);
|
||||
esp_err_t dcdc_disable(dcdc_channel_t channel);
|
||||
esp_err_t dcdc_toggle(dcdc_channel_t channel);
|
||||
bool dcdc_get_state(dcdc_channel_t channel);
|
||||
size_t dcdc_channel_count(void);
|
||||
gpio_num_t dcdc_get_gpio(dcdc_channel_t channel);
|
||||
3
main/idf_component.yml
Normal file
3
main/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb: "^1"
|
||||
42
main/main.c
Normal file
42
main/main.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "dcdc_controller.h"
|
||||
#include "usb_cdc_cli.h"
|
||||
|
||||
static const char *TAG = "watch-watch";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
if (dcdc_init() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Помилка ініціалізації DCDC контролера");
|
||||
return;
|
||||
}
|
||||
|
||||
if (usb_cdc_cli_init() != ESP_OK) {
|
||||
ESP_LOGW(TAG, "USB CDC CLI недоступний");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "USB CDC CLI запущено");
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Початок послідовного ввімкнення каналів з інтервалом 4 с");
|
||||
const TickType_t on_time = pdMS_TO_TICKS(4000);
|
||||
|
||||
size_t prev_channel = DCDC_CHANNEL_COUNT - 1;
|
||||
while (true) {
|
||||
for (size_t ch = 0; ch < dcdc_channel_count(); ++ch) {
|
||||
if (prev_channel != ch) {
|
||||
dcdc_disable(prev_channel);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "-> Ввімкнення каналу %d", (int)ch);
|
||||
dcdc_enable(ch);
|
||||
vTaskDelay(on_time);
|
||||
|
||||
prev_channel = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
296
main/usb_cdc_cli.c
Normal file
296
main/usb_cdc_cli.c
Normal file
@@ -0,0 +1,296 @@
|
||||
#include "usb_cdc_cli.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "dcdc_controller.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_cdc_acm.h"
|
||||
|
||||
#define CLI_LINE_MAX_LEN 128
|
||||
#define CLI_QUEUE_LEN 8
|
||||
|
||||
#ifndef CONFIG_TINYUSB_CDC_RX_BUFSIZE
|
||||
#define CONFIG_TINYUSB_CDC_RX_BUFSIZE 64
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
size_t length;
|
||||
uint8_t data[CONFIG_TINYUSB_CDC_RX_BUFSIZE];
|
||||
} usb_cli_msg_t;
|
||||
|
||||
static const char *TAG = "usb_cli";
|
||||
|
||||
static QueueHandle_t s_cli_queue;
|
||||
static bool s_cli_initialized;
|
||||
static bool s_host_ready;
|
||||
|
||||
static void usb_cli_task(void *arg);
|
||||
static void usb_cli_process_line(char *line);
|
||||
static void usb_cli_prompt(void);
|
||||
|
||||
static void usb_cli_write_raw(const char *data, size_t len)
|
||||
{
|
||||
if (!s_host_ready || len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tinyusb_cdcacm_write_queue(TINYUSB_CDC_ACM_0, (uint8_t *)data, len) == ESP_OK) {
|
||||
esp_err_t err = tinyusb_cdcacm_write_flush(TINYUSB_CDC_ACM_0, 0);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "CDC flush error: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_cli_printf(const char *fmt, ...)
|
||||
{
|
||||
if (!s_host_ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[192];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int len = vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
if (len > 0) {
|
||||
if (len >= (int)sizeof(buffer)) {
|
||||
len = (int)sizeof(buffer) - 1;
|
||||
}
|
||||
usb_cli_write_raw(buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *PROMPT = "\r\nwatch> ";
|
||||
|
||||
static char *usb_cli_trim(char *str)
|
||||
{
|
||||
while (*str && isspace((unsigned char)*str)) {
|
||||
str++;
|
||||
}
|
||||
char *end = str + strlen(str);
|
||||
while (end > str && isspace((unsigned char)*(end - 1))) {
|
||||
*(--end) = '\0';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static bool usb_cli_parse_channel(const char *token, dcdc_channel_t *channel)
|
||||
{
|
||||
if (!token) {
|
||||
return false;
|
||||
}
|
||||
char *end = NULL;
|
||||
long val = strtol(token, &end, 10);
|
||||
if (end == token || val < 0 || val >= DCDC_CHANNEL_COUNT) {
|
||||
return false;
|
||||
}
|
||||
*channel = (dcdc_channel_t)val;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void usb_cli_print_status(void)
|
||||
{
|
||||
usb_cli_printf("\r\nСтан каналів:\r\n");
|
||||
for (size_t i = 0; i < dcdc_channel_count(); ++i) {
|
||||
dcdc_channel_t ch = (dcdc_channel_t)i;
|
||||
usb_cli_printf(" - CH%u: %s (GPIO %d)\r\n",
|
||||
(unsigned)i,
|
||||
dcdc_get_state(ch) ? "ON" : "OFF",
|
||||
(int)dcdc_get_gpio(ch));
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_cli_prompt(void)
|
||||
{
|
||||
usb_cli_write_raw(PROMPT, strlen(PROMPT));
|
||||
}
|
||||
|
||||
static void usb_cli_handle_switch(const char *cmd, char *args)
|
||||
{
|
||||
dcdc_channel_t channel;
|
||||
char *ctx = NULL;
|
||||
char *channel_str = strtok_r(args, " ", &ctx);
|
||||
if (!usb_cli_parse_channel(channel_str, &channel)) {
|
||||
usb_cli_printf("\r\nНевірний номер каналу\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = ESP_OK;
|
||||
if (strcasecmp(cmd, "enable") == 0) {
|
||||
err = dcdc_enable(channel);
|
||||
} else if (strcasecmp(cmd, "disable") == 0) {
|
||||
err = dcdc_disable(channel);
|
||||
} else {
|
||||
err = dcdc_toggle(channel);
|
||||
}
|
||||
|
||||
if (err != ESP_OK) {
|
||||
usb_cli_printf("\r\nПомилка керування каналом: %s\r\n", esp_err_to_name(err));
|
||||
} else {
|
||||
usb_cli_printf("\r\nКанал %d -> %s\r\n", channel,
|
||||
dcdc_get_state(channel) ? "ON" : "OFF");
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_cli_process_line(char *line)
|
||||
{
|
||||
char *trimmed = usb_cli_trim(line);
|
||||
if (*trimmed == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
char *save_ptr = NULL;
|
||||
char *cmd = strtok_r(trimmed, " ", &save_ptr);
|
||||
if (!cmd) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcasecmp(cmd, "help") == 0) {
|
||||
usb_cli_printf(
|
||||
"\r\nДоступні команди:\r\n"
|
||||
" help - показати довідку\r\n"
|
||||
" status - стан всіх каналів\r\n"
|
||||
" enable <n> - увімкнути канал n\r\n"
|
||||
" disable <n> - вимкнути канал n\r\n"
|
||||
" toggle <n> - перемкнути канал n\r\n");
|
||||
} else if (strcasecmp(cmd, "status") == 0) {
|
||||
usb_cli_print_status();
|
||||
} else if (strcasecmp(cmd, "enable") == 0 ||
|
||||
strcasecmp(cmd, "disable") == 0 ||
|
||||
strcasecmp(cmd, "toggle") == 0) {
|
||||
usb_cli_handle_switch(cmd, save_ptr);
|
||||
} else {
|
||||
usb_cli_printf("\r\nНевідома команда '%s'\r\n", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_cli_task(void *arg)
|
||||
{
|
||||
usb_cli_msg_t msg;
|
||||
char line[CLI_LINE_MAX_LEN];
|
||||
size_t line_len = 0;
|
||||
|
||||
while (xQueueReceive(s_cli_queue, &msg, portMAX_DELAY)) {
|
||||
for (size_t i = 0; i < msg.length; ++i) {
|
||||
char ch = (char)msg.data[i];
|
||||
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
if (line_len > 0) {
|
||||
line[line_len] = '\0';
|
||||
usb_cli_process_line(line);
|
||||
line_len = 0;
|
||||
}
|
||||
usb_cli_prompt();
|
||||
} else if (ch == 0x7F || ch == '\b') {
|
||||
if (line_len > 0) {
|
||||
line_len--;
|
||||
}
|
||||
} else if (isprint((unsigned char)ch)) {
|
||||
if (line_len < CLI_LINE_MAX_LEN - 1) {
|
||||
line[line_len++] = ch;
|
||||
} else {
|
||||
usb_cli_printf("\r\nРядок занадто довгий\r\n");
|
||||
line_len = 0;
|
||||
usb_cli_prompt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_cdc_rx_callback(int itf, cdcacm_event_t *event)
|
||||
{
|
||||
if (!s_cli_queue) {
|
||||
return;
|
||||
}
|
||||
|
||||
usb_cli_msg_t msg = { 0 };
|
||||
size_t rx_size = 0;
|
||||
esp_err_t ret = tinyusb_cdcacm_read(itf, msg.data, sizeof(msg.data), &rx_size);
|
||||
if (ret == ESP_OK && rx_size > 0) {
|
||||
msg.length = rx_size;
|
||||
if (xQueueSend(s_cli_queue, &msg, 0) != pdTRUE) {
|
||||
ESP_LOGW(TAG, "CLI queue overflow, втрачено %u байт", (unsigned)rx_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_cdc_line_state_changed_callback(int itf, cdcacm_event_t *event)
|
||||
{
|
||||
const bool dtr = event->line_state_changed_data.dtr;
|
||||
const bool rts = event->line_state_changed_data.rts;
|
||||
ESP_LOGI(TAG, "CDC лінія %d змінилась: DTR=%d RTS=%d", itf, dtr, rts);
|
||||
s_host_ready = dtr;
|
||||
if (s_host_ready) {
|
||||
usb_cli_printf("\r\nwatch-watch CLI готовий. Надрукуйте 'help'.\r\n");
|
||||
usb_cli_prompt();
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t usb_cdc_cli_init(void)
|
||||
{
|
||||
if (s_cli_initialized) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
s_cli_queue = xQueueCreate(CLI_QUEUE_LEN, sizeof(usb_cli_msg_t));
|
||||
if (!s_cli_queue) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
if (xTaskCreate(usb_cli_task, "usb_cli", 4096, NULL, 5, NULL) != pdPASS) {
|
||||
vQueueDelete(s_cli_queue);
|
||||
s_cli_queue = NULL;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = NULL,
|
||||
.string_descriptor = NULL,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = NULL,
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = NULL,
|
||||
#else
|
||||
.configuration_descriptor = NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
ESP_RETURN_ON_ERROR(tinyusb_driver_install(&tusb_cfg), TAG, "TinyUSB init failed");
|
||||
|
||||
const tinyusb_config_cdcacm_t acm_cfg = {
|
||||
.usb_dev = TINYUSB_USBDEV_0,
|
||||
.cdc_port = TINYUSB_CDC_ACM_0,
|
||||
.rx_unread_buf_sz = CONFIG_TINYUSB_CDC_RX_BUFSIZE,
|
||||
.callback_rx = usb_cdc_rx_callback,
|
||||
.callback_rx_wanted_char = NULL,
|
||||
.callback_line_state_changed = NULL,
|
||||
.callback_line_coding_changed = NULL,
|
||||
};
|
||||
|
||||
ESP_RETURN_ON_ERROR(tusb_cdc_acm_init(&acm_cfg), TAG, "CDC init failed");
|
||||
ESP_RETURN_ON_ERROR(
|
||||
tinyusb_cdcacm_register_callback(TINYUSB_CDC_ACM_0,
|
||||
CDC_EVENT_LINE_STATE_CHANGED,
|
||||
usb_cdc_line_state_changed_callback),
|
||||
TAG,
|
||||
"Line state callback error");
|
||||
|
||||
s_cli_initialized = true;
|
||||
ESP_LOGI(TAG, "USB CDC CLI ініціалізовано");
|
||||
return ESP_OK;
|
||||
}
|
||||
11
main/usb_cdc_cli.h
Normal file
11
main/usb_cdc_cli.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Ініціалізує USB CDC CLI, підключений до Raspberry Pi 5.
|
||||
*
|
||||
* Модуль запускає TinyUSB CDC ACM та фонове завдання, яке читає рядки з
|
||||
* USB-консолі та надає команди для керування DC/DC каналами.
|
||||
*/
|
||||
esp_err_t usb_cdc_cli_init(void);
|
||||
@@ -0,0 +1 @@
|
||||
6a50305bc61c7a361da8c0833642be824e92dacb0a6001719a832a4e96e471bf
|
||||
107
managed_components/espressif__esp_tinyusb/CHANGELOG.md
Normal file
107
managed_components/espressif__esp_tinyusb/CHANGELOG.md
Normal file
@@ -0,0 +1,107 @@
|
||||
## 1.7.6~2
|
||||
|
||||
- esp_tinyusb: Added support for IDF 6.0 after removal of the USB component
|
||||
|
||||
## 1.7.6~1
|
||||
|
||||
- esp_tinyusb: Added documentation to README.md
|
||||
|
||||
## 1.7.6
|
||||
|
||||
- MSC: Fixed the possibility to use SD/MMC storage with large capacity (more than 4 GB)
|
||||
|
||||
## 1.7.5
|
||||
|
||||
- esp_tinyusb: Provide forward compatibility with IDF 6.0
|
||||
|
||||
## 1.7.4
|
||||
|
||||
- MSC: WL Sector runtime check during spiflash init (fix for build time error check)
|
||||
|
||||
## 1.7.3 [yanked]
|
||||
|
||||
- MSC: Improved transfer speed to SD cards and SPI flash
|
||||
|
||||
## 1.7.2
|
||||
|
||||
- esp_tinyusb: Fixed crash on logging from ISR
|
||||
- PHY: Fixed crash with external_phy=true configuration
|
||||
|
||||
## 1.7.1
|
||||
|
||||
- NCM: Changed default NTB config to decrease DRAM memory usage (fix for DRAM overflow on ESP32S2)
|
||||
|
||||
## 1.7.0 [yanked]
|
||||
|
||||
- NCM: Added possibility to configure NCM Transfer Blocks (NTB) via menuconfig
|
||||
- esp_tinyusb: Added option to select TinyUSB peripheral on esp32p4 via menuconfig (USB_PHY_SUPPORTS_P4_OTG11 in esp-idf is required)
|
||||
- esp_tinyusb: Fixed uninstall tinyusb driver with not default task configuration
|
||||
|
||||
## 1.6.0
|
||||
|
||||
- CDC-ACM: Fixed memory leak on deinit
|
||||
- esp_tinyusb: Added Teardown
|
||||
|
||||
## 1.5.0
|
||||
|
||||
- esp_tinyusb: Added DMA mode option to tinyusb DCD DWC2 configuration
|
||||
- esp_tinyusb: Changed the default affinity mask of the task to CPU1
|
||||
|
||||
## 1.4.5
|
||||
|
||||
- CDC-ACM: Fixed memory leak at VFS unregister
|
||||
- Vendor specific: Provided default configuration
|
||||
|
||||
## 1.4.4
|
||||
|
||||
- esp_tinyusb: Added HighSpeed and Qualifier device descriptors in tinyusb configuration
|
||||
- CDC-ACM: Removed MIN() definition if already defined
|
||||
- MSC: Fixed EP size selecting in default configuration descriptor
|
||||
|
||||
## 1.4.3
|
||||
|
||||
- esp_tinyusb: Added ESP32P4 support (HS only)
|
||||
|
||||
## 1.4.2
|
||||
|
||||
- MSC: Fixed maximum files open
|
||||
- Added uninstall function
|
||||
|
||||
## 1.4.0
|
||||
|
||||
- MSC: Fixed integer overflows
|
||||
- CDC-ACM: Removed intermediate RX ringbuffer
|
||||
- CDC-ACM: Increased default FIFO size to 512 bytes
|
||||
- CDC-ACM: Fixed Virtual File System binding
|
||||
|
||||
## 1.3.0
|
||||
|
||||
- Added NCM extension
|
||||
|
||||
## 1.2.1 - 1.2.2
|
||||
|
||||
- Minor bugfixes
|
||||
|
||||
## 1.2.0
|
||||
|
||||
- Added MSC extension for accessing SPI Flash on memory card https://github.com/espressif/idf-extra-components/commit/a8c00d7707ba4ceeb0970c023d702c7768dba3dc
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- Added support for NCM, ECM/RNDIS, DFU and Bluetooth TinyUSB drivers https://github.com/espressif/idf-extra-components/commit/79f35c9b047b583080f93a63310e2ee7d82ef17b
|
||||
|
||||
## 1.0.4
|
||||
|
||||
- Cleaned up string descriptors handling https://github.com/espressif/idf-extra-components/commit/046cc4b02f524d5c7e3e56480a473cfe844dc3d6
|
||||
|
||||
## 1.0.2 - 1.0.3
|
||||
|
||||
- Minor bugfixes
|
||||
|
||||
## 1.0.1
|
||||
|
||||
- CDC-ACM: Return ESP_OK if there is nothing to flush https://github.com/espressif/idf-extra-components/commit/388ff32eb09aa572d98c54cb355f1912ce42707c
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- Initial version based on [esp-idf v4.4.3](https://github.com/espressif/esp-idf/tree/v4.4.3/components/tinyusb)
|
||||
1
managed_components/espressif__esp_tinyusb/CHECKSUMS.json
Normal file
1
managed_components/espressif__esp_tinyusb/CHECKSUMS.json
Normal file
File diff suppressed because one or more lines are too long
59
managed_components/espressif__esp_tinyusb/CMakeLists.txt
Normal file
59
managed_components/espressif__esp_tinyusb/CMakeLists.txt
Normal file
@@ -0,0 +1,59 @@
|
||||
set(srcs
|
||||
"descriptors_control.c"
|
||||
"tinyusb.c"
|
||||
"usb_descriptors.c"
|
||||
)
|
||||
|
||||
set(priv_req "")
|
||||
|
||||
if(${IDF_VERSION_MAJOR} LESS 6)
|
||||
list(APPEND priv_req "usb")
|
||||
endif()
|
||||
|
||||
if(NOT CONFIG_TINYUSB_NO_DEFAULT_TASK)
|
||||
list(APPEND srcs "tusb_tasks.c")
|
||||
endif() # CONFIG_TINYUSB_NO_DEFAULT_TASK
|
||||
|
||||
if(CONFIG_TINYUSB_CDC_ENABLED)
|
||||
list(APPEND srcs
|
||||
"cdc.c"
|
||||
"tusb_cdc_acm.c"
|
||||
)
|
||||
if(CONFIG_VFS_SUPPORT_IO)
|
||||
list(APPEND srcs
|
||||
"tusb_console.c"
|
||||
"vfs_tinyusb.c"
|
||||
)
|
||||
endif() # CONFIG_VFS_SUPPORT_IO
|
||||
endif() # CONFIG_TINYUSB_CDC_ENABLED
|
||||
|
||||
if(CONFIG_TINYUSB_MSC_ENABLED)
|
||||
list(APPEND srcs
|
||||
tusb_msc_storage.c
|
||||
)
|
||||
endif() # CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
if(CONFIG_TINYUSB_NET_MODE_NCM)
|
||||
list(APPEND srcs
|
||||
tinyusb_net.c
|
||||
)
|
||||
endif() # CONFIG_TINYUSB_NET_MODE_NCM
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "include_private"
|
||||
PRIV_REQUIRES ${priv_req}
|
||||
REQUIRES fatfs vfs
|
||||
)
|
||||
|
||||
# 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 "include")
|
||||
379
managed_components/espressif__esp_tinyusb/Kconfig
Normal file
379
managed_components/espressif__esp_tinyusb/Kconfig
Normal file
@@ -0,0 +1,379 @@
|
||||
menu "TinyUSB Stack"
|
||||
config TINYUSB_DEBUG_LEVEL
|
||||
int "TinyUSB log level (0-3)"
|
||||
default 1
|
||||
range 0 3
|
||||
help
|
||||
Specify verbosity of TinyUSB log output.
|
||||
|
||||
choice TINYUSB_RHPORT
|
||||
prompt "USB Peripheral"
|
||||
default TINYUSB_RHPORT_HS if IDF_TARGET_ESP32P4
|
||||
default TINYUSB_RHPORT_FS
|
||||
help
|
||||
Allows set the USB Peripheral Controller for TinyUSB.
|
||||
|
||||
- High-speed (USB OTG2.0 Peripheral for High-, Full- and Low-speed)
|
||||
- Full-speed (USB OTG1.1 Peripheral for Full- and Low-speed)
|
||||
|
||||
config TINYUSB_RHPORT_HS
|
||||
bool "OTG2.0"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config TINYUSB_RHPORT_FS
|
||||
bool "OTG1.1"
|
||||
endchoice
|
||||
|
||||
menu "TinyUSB DCD"
|
||||
choice TINYUSB_MODE
|
||||
prompt "DCD Mode"
|
||||
default TINYUSB_MODE_DMA
|
||||
help
|
||||
TinyUSB DCD DWC2 Driver supports two modes: Slave mode (based on IRQ) and Buffer DMA mode.
|
||||
|
||||
config TINYUSB_MODE_SLAVE
|
||||
bool "Slave/IRQ"
|
||||
config TINYUSB_MODE_DMA
|
||||
bool "Buffer DMA"
|
||||
endchoice
|
||||
endmenu # "TinyUSB DCD"
|
||||
|
||||
menu "TinyUSB task configuration"
|
||||
config TINYUSB_NO_DEFAULT_TASK
|
||||
bool "Do not create a TinyUSB task"
|
||||
default n
|
||||
help
|
||||
This option allows to not create the FreeRTOS task during the driver initialization.
|
||||
User will have to handle TinyUSB events manually.
|
||||
|
||||
config TINYUSB_TASK_PRIORITY
|
||||
int "TinyUSB task priority"
|
||||
default 5
|
||||
depends on !TINYUSB_NO_DEFAULT_TASK
|
||||
help
|
||||
Set the priority of the default TinyUSB main task.
|
||||
|
||||
config TINYUSB_TASK_STACK_SIZE
|
||||
int "TinyUSB task stack size (bytes)"
|
||||
default 4096
|
||||
depends on !TINYUSB_NO_DEFAULT_TASK
|
||||
help
|
||||
Set the stack size of the default TinyUSB main task.
|
||||
|
||||
choice TINYUSB_TASK_AFFINITY
|
||||
prompt "TinyUSB task affinity"
|
||||
default TINYUSB_TASK_AFFINITY_CPU1 if !FREERTOS_UNICORE
|
||||
default TINYUSB_TASK_AFFINITY_NO_AFFINITY
|
||||
depends on !TINYUSB_NO_DEFAULT_TASK
|
||||
help
|
||||
Allows setting TinyUSB tasks affinity, i.e. whether the task is pinned to
|
||||
CPU0, pinned to CPU1, or allowed to run on any CPU.
|
||||
|
||||
config TINYUSB_TASK_AFFINITY_NO_AFFINITY
|
||||
bool "No affinity"
|
||||
config TINYUSB_TASK_AFFINITY_CPU0
|
||||
bool "CPU0"
|
||||
config TINYUSB_TASK_AFFINITY_CPU1
|
||||
bool "CPU1"
|
||||
depends on !FREERTOS_UNICORE
|
||||
endchoice
|
||||
|
||||
config TINYUSB_TASK_AFFINITY
|
||||
hex
|
||||
default FREERTOS_NO_AFFINITY if TINYUSB_TASK_AFFINITY_NO_AFFINITY
|
||||
default 0x0 if TINYUSB_TASK_AFFINITY_CPU0
|
||||
default 0x1 if TINYUSB_TASK_AFFINITY_CPU1
|
||||
|
||||
config TINYUSB_INIT_IN_DEFAULT_TASK
|
||||
bool "Initialize TinyUSB stack within the default TinyUSB task"
|
||||
default n
|
||||
depends on !TINYUSB_NO_DEFAULT_TASK
|
||||
help
|
||||
Run TinyUSB stack initialization just after starting the default TinyUSB task.
|
||||
This is especially useful in multicore scenarios, when we need to pin the task
|
||||
to a specific core and, at the same time initialize TinyUSB stack
|
||||
(i.e. install interrupts) on the same core.
|
||||
endmenu # "TinyUSB task configuration"
|
||||
|
||||
menu "Descriptor configuration"
|
||||
comment "You can provide your custom descriptors via tinyusb_driver_install()"
|
||||
config TINYUSB_DESC_USE_ESPRESSIF_VID
|
||||
bool "VID: Use Espressif's vendor ID"
|
||||
default y
|
||||
help
|
||||
Enable this option, USB device will use Espressif's vendor ID as its VID.
|
||||
This is helpful at product develop stage.
|
||||
|
||||
config TINYUSB_DESC_CUSTOM_VID
|
||||
hex "VID: Custom vendor ID"
|
||||
default 0x1234
|
||||
depends on !TINYUSB_DESC_USE_ESPRESSIF_VID
|
||||
help
|
||||
Custom Vendor ID.
|
||||
|
||||
config TINYUSB_DESC_USE_DEFAULT_PID
|
||||
bool "PID: Use a default PID assigned to TinyUSB"
|
||||
default y
|
||||
help
|
||||
Default TinyUSB PID assigning uses values 0x4000...0x4007.
|
||||
|
||||
config TINYUSB_DESC_CUSTOM_PID
|
||||
hex "PID: Custom product ID"
|
||||
default 0x5678
|
||||
depends on !TINYUSB_DESC_USE_DEFAULT_PID
|
||||
help
|
||||
Custom Product ID.
|
||||
|
||||
config TINYUSB_DESC_BCD_DEVICE
|
||||
hex "bcdDevice"
|
||||
default 0x0100
|
||||
help
|
||||
Version of the firmware of the USB device.
|
||||
|
||||
config TINYUSB_DESC_MANUFACTURER_STRING
|
||||
string "Manufacturer name"
|
||||
default "Espressif Systems"
|
||||
help
|
||||
Name of the manufacturer of the USB device.
|
||||
|
||||
config TINYUSB_DESC_PRODUCT_STRING
|
||||
string "Product name"
|
||||
default "Espressif Device"
|
||||
help
|
||||
Name of the USB device.
|
||||
|
||||
config TINYUSB_DESC_SERIAL_STRING
|
||||
string "Serial string"
|
||||
default "123456"
|
||||
help
|
||||
Serial number of the USB device.
|
||||
|
||||
config TINYUSB_DESC_CDC_STRING
|
||||
depends on TINYUSB_CDC_ENABLED
|
||||
string "CDC Device String"
|
||||
default "Espressif CDC Device"
|
||||
help
|
||||
Name of the CDC device.
|
||||
|
||||
config TINYUSB_DESC_MSC_STRING
|
||||
depends on TINYUSB_MSC_ENABLED
|
||||
string "MSC Device String"
|
||||
default "Espressif MSC Device"
|
||||
help
|
||||
Name of the MSC device.
|
||||
endmenu # "Descriptor configuration"
|
||||
|
||||
menu "Massive Storage Class (MSC)"
|
||||
config TINYUSB_MSC_ENABLED
|
||||
bool "Enable TinyUSB MSC feature"
|
||||
default n
|
||||
help
|
||||
Enable TinyUSB MSC feature.
|
||||
|
||||
config TINYUSB_MSC_BUFSIZE
|
||||
depends on TINYUSB_MSC_ENABLED
|
||||
int "MSC FIFO size"
|
||||
default 512 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 8192 if IDF_TARGET_ESP32P4
|
||||
range 64 8192 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
range 64 32768 if IDF_TARGET_ESP32P4
|
||||
help
|
||||
MSC FIFO size, in bytes.
|
||||
|
||||
config TINYUSB_MSC_MOUNT_PATH
|
||||
depends on TINYUSB_MSC_ENABLED
|
||||
string "Mount Path"
|
||||
default "/data"
|
||||
help
|
||||
MSC Mount Path of storage.
|
||||
|
||||
menu "TinyUSB FAT Format Options"
|
||||
choice TINYUSB_FAT_FORMAT_TYPE
|
||||
prompt "FatFS Format Type"
|
||||
default TINYUSB_FAT_FORMAT_ANY
|
||||
help
|
||||
Select the FAT filesystem type used when formatting storage.
|
||||
|
||||
config TINYUSB_FAT_FORMAT_ANY
|
||||
bool "FM_ANY - Automatically select from FAT12/FAT16/FAT32"
|
||||
|
||||
config TINYUSB_FAT_FORMAT_FAT
|
||||
bool "FM_FAT - Allow only FAT12/FAT16"
|
||||
|
||||
config TINYUSB_FAT_FORMAT_FAT32
|
||||
bool "FM_FAT32 - Force FAT32 only"
|
||||
|
||||
config TINYUSB_FAT_FORMAT_EXFAT
|
||||
bool "FM_EXFAT - Force exFAT (requires exFAT enabled)"
|
||||
|
||||
endchoice
|
||||
|
||||
config TINYUSB_FAT_FORMAT_SFD
|
||||
bool "FM_SFD - Use SFD (no partition table)"
|
||||
default n
|
||||
help
|
||||
Format as a Super Floppy Disk (no partition table).
|
||||
This is typical for USB flash drives and small volumes.
|
||||
endmenu
|
||||
|
||||
endmenu # "Massive Storage Class"
|
||||
|
||||
menu "Communication Device Class (CDC)"
|
||||
config TINYUSB_CDC_ENABLED
|
||||
bool "Enable TinyUSB CDC feature"
|
||||
default n
|
||||
help
|
||||
Enable TinyUSB CDC feature.
|
||||
|
||||
config TINYUSB_CDC_COUNT
|
||||
int "CDC Channel Count"
|
||||
default 1
|
||||
range 1 2
|
||||
depends on TINYUSB_CDC_ENABLED
|
||||
help
|
||||
Number of independent serial ports.
|
||||
|
||||
config TINYUSB_CDC_RX_BUFSIZE
|
||||
depends on TINYUSB_CDC_ENABLED
|
||||
int "CDC FIFO size of RX channel"
|
||||
default 512
|
||||
range 64 10000
|
||||
help
|
||||
CDC FIFO size of RX channel.
|
||||
|
||||
config TINYUSB_CDC_TX_BUFSIZE
|
||||
depends on TINYUSB_CDC_ENABLED
|
||||
int "CDC FIFO size of TX channel"
|
||||
default 512
|
||||
help
|
||||
CDC FIFO size of TX channel.
|
||||
endmenu # "Communication Device Class"
|
||||
|
||||
menu "Musical Instrument Digital Interface (MIDI)"
|
||||
config TINYUSB_MIDI_COUNT
|
||||
int "TinyUSB MIDI interfaces count"
|
||||
default 0
|
||||
range 0 2
|
||||
help
|
||||
Setting value greater than 0 will enable TinyUSB MIDI feature.
|
||||
endmenu # "Musical Instrument Digital Interface (MIDI)"
|
||||
|
||||
menu "Human Interface Device Class (HID)"
|
||||
config TINYUSB_HID_COUNT
|
||||
int "TinyUSB HID interfaces count"
|
||||
default 0
|
||||
range 0 4
|
||||
help
|
||||
Setting value greater than 0 will enable TinyUSB HID feature.
|
||||
endmenu # "HID Device Class (HID)"
|
||||
|
||||
menu "Device Firmware Upgrade (DFU)"
|
||||
choice TINYUSB_DFU_MODE
|
||||
prompt "DFU mode"
|
||||
default TINYUSB_DFU_MODE_NONE
|
||||
help
|
||||
Select which DFU driver you want to use.
|
||||
|
||||
config TINYUSB_DFU_MODE_DFU
|
||||
bool "DFU"
|
||||
|
||||
config TINYUSB_DFU_MODE_DFU_RUNTIME
|
||||
bool "DFU Runtime"
|
||||
|
||||
config TINYUSB_DFU_MODE_NONE
|
||||
bool "None"
|
||||
endchoice
|
||||
config TINYUSB_DFU_BUFSIZE
|
||||
depends on TINYUSB_DFU_MODE_DFU
|
||||
int "DFU XFER BUFFSIZE"
|
||||
default 512
|
||||
help
|
||||
DFU XFER BUFFSIZE.
|
||||
endmenu # Device Firmware Upgrade (DFU)
|
||||
|
||||
menu "Bluetooth Host Class (BTH)"
|
||||
config TINYUSB_BTH_ENABLED
|
||||
bool "Enable TinyUSB BTH feature"
|
||||
default n
|
||||
help
|
||||
Enable TinyUSB BTH feature.
|
||||
|
||||
config TINYUSB_BTH_ISO_ALT_COUNT
|
||||
depends on TINYUSB_BTH_ENABLED
|
||||
int "BTH ISO ALT COUNT"
|
||||
default 0
|
||||
help
|
||||
BTH ISO ALT COUNT.
|
||||
endmenu # "Bluetooth Host Device Class"
|
||||
|
||||
menu "Network driver (ECM/NCM/RNDIS)"
|
||||
choice TINYUSB_NET_MODE
|
||||
prompt "Network mode"
|
||||
default TINYUSB_NET_MODE_NONE
|
||||
help
|
||||
Select network driver you want to use.
|
||||
|
||||
config TINYUSB_NET_MODE_ECM_RNDIS
|
||||
bool "ECM/RNDIS"
|
||||
|
||||
config TINYUSB_NET_MODE_NCM
|
||||
bool "NCM"
|
||||
|
||||
config TINYUSB_NET_MODE_NONE
|
||||
bool "None"
|
||||
endchoice
|
||||
|
||||
config TINYUSB_NCM_OUT_NTB_BUFFS_COUNT
|
||||
int "Number of NCM NTB buffers for reception side"
|
||||
depends on TINYUSB_NET_MODE_NCM
|
||||
default 3
|
||||
range 1 6
|
||||
help
|
||||
Number of NTB buffers for reception side.
|
||||
Can be increased to improve performance and stability with the cost of additional RAM requirements.
|
||||
Helps to mitigate "tud_network_can_xmit: request blocked" warning message when running NCM device.
|
||||
|
||||
config TINYUSB_NCM_IN_NTB_BUFFS_COUNT
|
||||
int "Number of NCM NTB buffers for transmission side"
|
||||
depends on TINYUSB_NET_MODE_NCM
|
||||
default 3
|
||||
range 1 6
|
||||
help
|
||||
Number of NTB buffers for transmission side.
|
||||
Can be increased to improve performance and stability with the cost of additional RAM requirements.
|
||||
Helps to mitigate "tud_network_can_xmit: request blocked" warning message when running NCM device.
|
||||
|
||||
config TINYUSB_NCM_OUT_NTB_BUFF_MAX_SIZE
|
||||
int "NCM NTB Buffer size for reception size"
|
||||
depends on TINYUSB_NET_MODE_NCM
|
||||
default 3200
|
||||
range 1600 10240
|
||||
help
|
||||
Size of NTB buffers on the reception side. The minimum size used by Linux is 2048 bytes.
|
||||
NTB buffer size must be significantly larger than the MTU (Maximum Transmission Unit).
|
||||
The typical default MTU size for Ethernet is 1500 bytes, plus an additional packet overhead.
|
||||
To improve performance, the NTB buffer size should be large enough to fit multiple MTU-sized
|
||||
frames in a single NTB buffer and it's length should be multiple of 4.
|
||||
|
||||
config TINYUSB_NCM_IN_NTB_BUFF_MAX_SIZE
|
||||
int "NCM NTB Buffer size for transmission size"
|
||||
depends on TINYUSB_NET_MODE_NCM
|
||||
default 3200
|
||||
range 1600 10240
|
||||
help
|
||||
Size of NTB buffers on the transmission side. The minimum size used by Linux is 2048 bytes.
|
||||
NTB buffer size must be significantly larger than the MTU (Maximum Transmission Unit).
|
||||
The typical default MTU size for Ethernet is 1500 bytes, plus an additional packet overhead.
|
||||
To improve performance, the NTB buffer size should be large enough to fit multiple MTU-sized
|
||||
frames in a single NTB buffer and it's length should be multiple of 4.
|
||||
|
||||
endmenu # "Network driver (ECM/NCM/RNDIS)"
|
||||
|
||||
menu "Vendor Specific Interface"
|
||||
config TINYUSB_VENDOR_COUNT
|
||||
int "TinyUSB Vendor specific interfaces count"
|
||||
default 0
|
||||
range 0 2
|
||||
help
|
||||
Setting value greater than 0 will enable TinyUSB Vendor specific feature.
|
||||
endmenu # "Vendor Specific Interface"
|
||||
endmenu # "TinyUSB Stack"
|
||||
202
managed_components/espressif__esp_tinyusb/LICENSE
Normal file
202
managed_components/espressif__esp_tinyusb/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
166
managed_components/espressif__esp_tinyusb/README.md
Normal file
166
managed_components/espressif__esp_tinyusb/README.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Espressif's additions to TinyUSB
|
||||
|
||||
[](https://components.espressif.com/components/espressif/esp_tinyusb)
|
||||
|
||||
This component adds features to TinyUSB that help users with integrating TinyUSB with their ESP-IDF application.
|
||||
|
||||
It contains:
|
||||
* Configuration of USB device and string descriptors
|
||||
* USB Serial Device (CDC-ACM) with optional Virtual File System support
|
||||
* Input and output streams through USB Serial Device. This feature is available only when Virtual File System support is enabled.
|
||||
* Other USB classes (MIDI, MSC, HID…) support directly via TinyUSB
|
||||
* VBUS monitoring for self-powered devices
|
||||
* SPI Flash or sd-card access via MSC USB device Class.
|
||||
|
||||
## How to use?
|
||||
|
||||
This component is distributed via [IDF component manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html). Just add `idf_component.yml` file to your main component with the following content:
|
||||
|
||||
``` yaml
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
esp_tinyusb: "~1.0.0"
|
||||
```
|
||||
|
||||
Or simply run:
|
||||
```
|
||||
idf.py add-dependency esp_tinyusb~1.0.0
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Hardware-related documentation could be found in [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/usb_device.html).
|
||||
|
||||
### Device Stack Structure
|
||||
|
||||
The Device Stack is built on top of TinyUSB and provides:
|
||||
|
||||
- Custom USB descriptor support
|
||||
- Serial device (CDC-ACM) support
|
||||
- Standard stream redirection through the serial device
|
||||
- Storage media support (SPI-Flash and SD-Card) for USB MSC Class
|
||||
- A dedicated task for TinyUSB servicing
|
||||
|
||||
### Configuration Options
|
||||
|
||||
Configure the Device Stack using `menuconfig`:
|
||||
|
||||
- TinyUSB log verbosity
|
||||
- Device Stack task options
|
||||
- Default device/string descriptor options
|
||||
- Class-specific options
|
||||
|
||||
### Descriptor Configuration
|
||||
|
||||
Configure USB descriptors using the `tinyusb_config_t` structure:
|
||||
|
||||
- `device_descriptor`
|
||||
- `string_descriptor`
|
||||
- `configuration_descriptor` (full-speed)
|
||||
- For high-speed devices: `fs_configuration_descriptor`, `hs_configuration_descriptor`, `qualifier_descriptor`
|
||||
|
||||
If any descriptor field is set to `NULL`, default descriptors (based on menuconfig) are used.
|
||||
|
||||
### Installation
|
||||
|
||||
Install the Device Stack by calling `tinyusb_driver_install` with a `tinyusb_config_t` structure. Members set to `0` or `NULL` use default values.
|
||||
|
||||
```c
|
||||
const tinyusb_config_t partial_init = {
|
||||
.device_descriptor = NULL,
|
||||
.string_descriptor = NULL,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = NULL,
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = NULL,
|
||||
#else
|
||||
.configuration_descriptor = NULL,
|
||||
#endif
|
||||
};
|
||||
```
|
||||
|
||||
### Self-Powered Device
|
||||
|
||||
Self-powered devices must monitor VBUS voltage. Use a GPIO pin with a voltage divider or comparator to detect VBUS state. Set `self_powered = true` and assign the VBUS monitor GPIO in `tinyusb_config_t`.
|
||||
|
||||
### USB Serial Device (CDC-ACM)
|
||||
|
||||
If enabled, initialize the USB Serial Device with `tusb_cdc_acm_init` and a `tinyusb_config_cdcacm_t` structure:
|
||||
|
||||
```c
|
||||
const tinyusb_config_cdcacm_t acm_cfg = {
|
||||
.usb_dev = TINYUSB_USBDEV_0,
|
||||
.cdc_port = TINYUSB_CDC_ACM_0,
|
||||
.rx_unread_buf_sz = 64,
|
||||
.callback_rx = NULL,
|
||||
.callback_rx_wanted_char = NULL,
|
||||
.callback_line_state_changed = NULL,
|
||||
.callback_line_coding_changed = NULL
|
||||
};
|
||||
tusb_cdc_acm_init(&acm_cfg);
|
||||
```
|
||||
|
||||
Redirect standard I/O streams to USB with `esp_tusb_init_console` and revert with `esp_tusb_deinit_console`.
|
||||
|
||||
### USB Mass Storage Device (MSC)
|
||||
|
||||
If enabled, initialize storage media for MSC:
|
||||
|
||||
**SPI-Flash Example:**
|
||||
```c
|
||||
static esp_err_t storage_init_spiflash(wl_handle_t *wl_handle) {
|
||||
// ... partition and mount logic ...
|
||||
}
|
||||
storage_init_spiflash(&wl_handle);
|
||||
|
||||
const tinyusb_msc_spiflash_config_t config_spi = {
|
||||
.wl_handle = wl_handle
|
||||
};
|
||||
tinyusb_msc_storage_init_spiflash(&config_spi);
|
||||
```
|
||||
|
||||
**SD-Card Example:**
|
||||
```c
|
||||
static esp_err_t storage_init_sdmmc(sdmmc_card_t **card) {
|
||||
// ... SDMMC host and slot config ...
|
||||
}
|
||||
storage_init_sdmmc(&card);
|
||||
|
||||
const tinyusb_msc_sdmmc_config_t config_sdmmc = {
|
||||
.card = card
|
||||
};
|
||||
tinyusb_msc_storage_init_sdmmc(&config_sdmmc);
|
||||
```
|
||||
|
||||
### MSC Performance Optimization
|
||||
|
||||
- **Single-buffer approach:** Buffer size is set via `CONFIG_TINYUSB_MSC_BUFSIZE`.
|
||||
- **Performance:** SD cards offer higher throughput than internal SPI flash due to architectural constraints.
|
||||
|
||||
**Performance Table (ESP32-S3):**
|
||||
|
||||
| FIFO Size | Read Speed | Write Speed |
|
||||
|-----------|------------|-------------|
|
||||
| 512 B | 0.566 MB/s | 0.236 MB/s |
|
||||
| 8192 B | 0.925 MB/s | 0.928 MB/s |
|
||||
|
||||
**Performance Table (ESP32-P4):**
|
||||
|
||||
| FIFO Size | Read Speed | Write Speed |
|
||||
|-----------|------------|-------------|
|
||||
| 512 B | 1.174 MB/s | 0.238 MB/s |
|
||||
| 8192 B | 4.744 MB/s | 2.157 MB/s |
|
||||
| 32768 B | 5.998 MB/s | 4.485 MB/s |
|
||||
|
||||
**Performance Table (ESP32-S2, SPI Flash):**
|
||||
|
||||
| FIFO Size | Write Speed |
|
||||
|-----------|-------------|
|
||||
| 512 B | 5.59 KB/s |
|
||||
| 8192 B | 21.54 KB/s |
|
||||
|
||||
**Note:** Internal SPI flash is for demonstration only; use SD cards or external flash for higher performance.
|
||||
|
||||
## Examples
|
||||
You can find examples in [ESP-IDF on GitHub](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/device).
|
||||
109
managed_components/espressif__esp_tinyusb/cdc.c
Normal file
109
managed_components/espressif__esp_tinyusb/cdc.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_check.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "tusb.h"
|
||||
#include "cdc.h"
|
||||
|
||||
#define CDC_INTF_NUM CFG_TUD_CDC // number of cdc blocks
|
||||
static esp_tusb_cdc_t *cdc_obj[CDC_INTF_NUM] = {};
|
||||
static const char *TAG = "tusb_cdc";
|
||||
|
||||
esp_tusb_cdc_t *tinyusb_cdc_get_intf(int itf_num)
|
||||
{
|
||||
if (itf_num >= CDC_INTF_NUM || itf_num < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return cdc_obj[itf_num];
|
||||
}
|
||||
|
||||
static esp_err_t cdc_obj_check(int itf, bool expected_inited, tusb_class_code_t expected_type)
|
||||
{
|
||||
esp_tusb_cdc_t *this_itf = tinyusb_cdc_get_intf(itf);
|
||||
|
||||
bool inited = (this_itf != NULL);
|
||||
ESP_RETURN_ON_FALSE(expected_inited == inited, ESP_ERR_INVALID_STATE, TAG, "Wrong state of the interface. Expected state: %s", expected_inited ? "initialized" : "not initialized");
|
||||
ESP_RETURN_ON_FALSE(!(inited && (expected_type != -1) && !(this_itf->type == expected_type)), ESP_ERR_INVALID_STATE, TAG, "Wrong type of the interface. Should be : 0x%x (tusb_class_code_t)", expected_type);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t tusb_cdc_comm_init(int itf)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(cdc_obj_check(itf, false, -1), TAG, "cdc_obj_check failed");
|
||||
cdc_obj[itf] = calloc(1, sizeof(esp_tusb_cdc_t));
|
||||
if (cdc_obj[itf] != NULL) {
|
||||
cdc_obj[itf]->type = TUSB_CLASS_CDC;
|
||||
ESP_LOGD(TAG, "CDC Comm class initialized");
|
||||
return ESP_OK;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "CDC Comm initialization error");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t tusb_cdc_deinit_comm(int itf)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(cdc_obj_check(itf, true, TUSB_CLASS_CDC), TAG, "cdc_obj_check failed");
|
||||
free(cdc_obj[itf]);
|
||||
cdc_obj[itf] = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t tusb_cdc_data_init(int itf)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(cdc_obj_check(itf, false, TUSB_CLASS_CDC_DATA), TAG, "cdc_obj_check failed");
|
||||
cdc_obj[itf] = calloc(1, sizeof(esp_tusb_cdc_t));
|
||||
if (cdc_obj[itf] != NULL) {
|
||||
cdc_obj[itf]->type = TUSB_CLASS_CDC_DATA;
|
||||
ESP_LOGD(TAG, "CDC Data class initialized");
|
||||
return ESP_OK;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "CDC Data initialization error");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t tusb_cdc_deinit_data(int itf)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(cdc_obj_check(itf, true, TUSB_CLASS_CDC_DATA), TAG, "cdc_obj_check failed");
|
||||
free(cdc_obj[itf]);
|
||||
cdc_obj[itf] = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t tinyusb_cdc_init(int itf, const tinyusb_config_cdc_t *cfg)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(cdc_obj_check(itf, false, -1), TAG, "cdc_obj_check failed");
|
||||
|
||||
ESP_LOGD(TAG, "Init CDC %d", itf);
|
||||
if (cfg->cdc_class == TUSB_CLASS_CDC) {
|
||||
ESP_RETURN_ON_ERROR(tusb_cdc_comm_init(itf), TAG, "tusb_cdc_comm_init failed");
|
||||
cdc_obj[itf]->cdc_subclass.comm_subclass = cfg->cdc_subclass.comm_subclass;
|
||||
} else {
|
||||
ESP_RETURN_ON_ERROR(tusb_cdc_data_init(itf), TAG, "tusb_cdc_data_init failed");
|
||||
cdc_obj[itf]->cdc_subclass.data_subclass = cfg->cdc_subclass.data_subclass;
|
||||
}
|
||||
cdc_obj[itf]->usb_dev = cfg->usb_dev;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t tinyusb_cdc_deinit(int itf)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(cdc_obj_check(itf, true, -1), TAG, "cdc_obj_check failed");
|
||||
|
||||
ESP_LOGD(TAG, "Deinit CDC %d", itf);
|
||||
if (cdc_obj[itf]->type == TUSB_CLASS_CDC) {
|
||||
ESP_RETURN_ON_ERROR(tusb_cdc_deinit_comm(itf), TAG, "tusb_cdc_deinit_comm failed");
|
||||
} else if (cdc_obj[itf]->type == TUSB_CLASS_CDC_DATA) {
|
||||
ESP_RETURN_ON_ERROR(tusb_cdc_deinit_data(itf), TAG, "tusb_cdc_deinit_data failed");
|
||||
} else {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
294
managed_components/espressif__esp_tinyusb/descriptors_control.c
Normal file
294
managed_components/espressif__esp_tinyusb/descriptors_control.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_err.h"
|
||||
#include "descriptors_control.h"
|
||||
#include "usb_descriptors.h"
|
||||
|
||||
#define MAX_DESC_BUF_SIZE 32 // Max length of string descriptor (can be extended, USB supports lengths up to 255 bytes)
|
||||
|
||||
static const char *TAG = "tusb_desc";
|
||||
|
||||
// =============================================================================
|
||||
// STRUCTS
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Descriptor pointers for tinyusb descriptor requests callbacks
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
const tusb_desc_device_t *dev; /*!< Pointer to device descriptor */
|
||||
union {
|
||||
const uint8_t *cfg; /*!< Pointer to FullSpeed configuration descriptor when device one-speed only */
|
||||
const uint8_t *fs_cfg; /*!< Pointer to FullSpeed configuration descriptor when device support HighSpeed */
|
||||
};
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
const uint8_t *hs_cfg; /*!< Pointer to HighSpeed configuration descriptor */
|
||||
const tusb_desc_device_qualifier_t *qualifier; /*!< Pointer to Qualifier descriptor */
|
||||
uint8_t *other_speed; /*!< Pointer for other speed configuration descriptor */
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
const char *str[USB_STRING_DESCRIPTOR_ARRAY_SIZE]; /*!< Pointer to array of UTF-8 strings */
|
||||
int str_count; /*!< Number of descriptors in str */
|
||||
} tinyusb_descriptor_config_t;
|
||||
|
||||
static tinyusb_descriptor_config_t s_desc_cfg;
|
||||
|
||||
// =============================================================================
|
||||
// CALLBACKS
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET DEVICE DESCRIPTOR.
|
||||
* Descriptor contents must exist long enough for transfer to complete
|
||||
*
|
||||
* @return Pointer to device descriptor
|
||||
*/
|
||||
uint8_t const *tud_descriptor_device_cb(void)
|
||||
{
|
||||
assert(s_desc_cfg.dev);
|
||||
return (uint8_t const *)s_desc_cfg.dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET CONFIGURATION DESCRIPTOR.
|
||||
* Descriptor contents must exist long enough for transfer to complete
|
||||
*
|
||||
* @param[in] index Index of required configuration
|
||||
* @return Pointer to configuration descriptor
|
||||
*/
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
(void)index; // Unused, this driver supports only 1 configuration
|
||||
assert(s_desc_cfg.cfg);
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
// HINT: cfg and fs_cfg are union, no need to assert(fs_cfg)
|
||||
assert(s_desc_cfg.hs_cfg);
|
||||
// Return configuration descriptor based on Host speed
|
||||
return (TUSB_SPEED_HIGH == tud_speed_get())
|
||||
? s_desc_cfg.hs_cfg
|
||||
: s_desc_cfg.fs_cfg;
|
||||
#else
|
||||
return s_desc_cfg.cfg;
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
}
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
/**
|
||||
* @brief Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
|
||||
* Descriptor contents must exist long enough for transfer to complete
|
||||
* If not highspeed capable stall this request
|
||||
*/
|
||||
uint8_t const *tud_descriptor_device_qualifier_cb(void)
|
||||
{
|
||||
assert(s_desc_cfg.qualifier);
|
||||
return (uint8_t const *)s_desc_cfg.qualifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET OTHER SPEED CONFIGURATION DESCRIPTOR request
|
||||
* Descriptor contents must exist long enough for transfer to complete
|
||||
* Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
|
||||
*/
|
||||
uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index)
|
||||
{
|
||||
assert(s_desc_cfg.other_speed);
|
||||
|
||||
const uint8_t *other_speed = (TUSB_SPEED_HIGH == tud_speed_get())
|
||||
? s_desc_cfg.fs_cfg
|
||||
: s_desc_cfg.hs_cfg;
|
||||
|
||||
memcpy(s_desc_cfg.other_speed,
|
||||
other_speed,
|
||||
((tusb_desc_configuration_t *)other_speed)->wTotalLength);
|
||||
|
||||
((tusb_desc_configuration_t *)s_desc_cfg.other_speed)->bDescriptorType = TUSB_DESC_OTHER_SPEED_CONFIG;
|
||||
return s_desc_cfg.other_speed;
|
||||
}
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET STRING DESCRIPTOR request
|
||||
*
|
||||
* @param[in] index Index of required descriptor
|
||||
* @param[in] langid Language of the descriptor
|
||||
* @return Pointer to UTF-16 string descriptor
|
||||
*/
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
(void) langid; // Unused, this driver supports only one language in string descriptors
|
||||
assert(s_desc_cfg.str);
|
||||
uint8_t chr_count;
|
||||
static uint16_t _desc_str[MAX_DESC_BUF_SIZE];
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], s_desc_cfg.str[0], 2);
|
||||
chr_count = 1;
|
||||
} else {
|
||||
if (index >= USB_STRING_DESCRIPTOR_ARRAY_SIZE) {
|
||||
ESP_LOGW(TAG, "String index (%u) is out of bounds, check your string descriptor", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (s_desc_cfg.str[index] == NULL) {
|
||||
ESP_LOGW(TAG, "String index (%u) points to NULL, check your string descriptor", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *str = s_desc_cfg.str[index];
|
||||
chr_count = strnlen(str, 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;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Driver functions
|
||||
// =============================================================================
|
||||
esp_err_t tinyusb_set_descriptors(const tinyusb_config_t *config)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
assert(config);
|
||||
const char **pstr_desc;
|
||||
// Flush descriptors control struct
|
||||
memset(&s_desc_cfg, 0x00, sizeof(tinyusb_descriptor_config_t));
|
||||
// Parse configuration and save descriptors's pointer
|
||||
// Select Device Descriptor
|
||||
if (config->device_descriptor == NULL) {
|
||||
ESP_LOGW(TAG, "No Device descriptor provided, using default.");
|
||||
s_desc_cfg.dev = &descriptor_dev_default;
|
||||
} else {
|
||||
s_desc_cfg.dev = config->device_descriptor;
|
||||
}
|
||||
|
||||
// Select FullSpeed configuration descriptor
|
||||
if (config->configuration_descriptor == NULL) {
|
||||
// Default configuration descriptor must be provided for the following classes
|
||||
#if (CFG_TUD_HID > 0 || CFG_TUD_MIDI > 0 || CFG_TUD_ECM_RNDIS > 0 || CFG_TUD_DFU > 0 || CFG_TUD_DFU_RUNTIME > 0 || CFG_TUD_BTH > 0)
|
||||
ESP_GOTO_ON_FALSE(config->configuration_descriptor, ESP_ERR_INVALID_ARG, fail, TAG, "Configuration descriptor must be provided for this device");
|
||||
#else
|
||||
ESP_LOGW(TAG, "No FullSpeed configuration descriptor provided, using default.");
|
||||
s_desc_cfg.cfg = descriptor_fs_cfg_default;
|
||||
#endif
|
||||
} else {
|
||||
s_desc_cfg.cfg = config->configuration_descriptor;
|
||||
}
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
// High Speed
|
||||
if (config->hs_configuration_descriptor == NULL) {
|
||||
// Default configuration descriptor must be provided for the following classes
|
||||
#if (CFG_TUD_HID > 0 || CFG_TUD_MIDI > 0 || CFG_TUD_ECM_RNDIS > 0 || CFG_TUD_DFU > 0 || CFG_TUD_DFU_RUNTIME > 0 || CFG_TUD_BTH > 0)
|
||||
ESP_GOTO_ON_FALSE(config->hs_configuration_descriptor, ESP_ERR_INVALID_ARG, fail, TAG, "HighSpeed configuration descriptor must be provided for this device");
|
||||
#else
|
||||
ESP_LOGW(TAG, "No HighSpeed configuration descriptor provided, using default.");
|
||||
s_desc_cfg.hs_cfg = descriptor_hs_cfg_default;
|
||||
#endif
|
||||
} else {
|
||||
s_desc_cfg.hs_cfg = config->hs_configuration_descriptor;
|
||||
}
|
||||
|
||||
// HS and FS cfg desc should be equal length
|
||||
ESP_GOTO_ON_FALSE(((tusb_desc_configuration_t *)s_desc_cfg.hs_cfg)->wTotalLength ==
|
||||
((tusb_desc_configuration_t *)s_desc_cfg.fs_cfg)->wTotalLength,
|
||||
ESP_ERR_INVALID_ARG, fail, TAG, "HighSpeed and FullSpeed configuration descriptors must be same length");
|
||||
|
||||
// Qualifier Descriptor
|
||||
if (config->qualifier_descriptor == NULL) {
|
||||
ESP_GOTO_ON_FALSE((s_desc_cfg.dev == &descriptor_dev_default), ESP_ERR_INVALID_ARG, fail, TAG, "Qualifier descriptor must be present (Device Descriptor not default).");
|
||||
// Get default qualifier if device descriptor is default
|
||||
ESP_LOGW(TAG, "No Qulifier descriptor provided, using default.");
|
||||
s_desc_cfg.qualifier = &descriptor_qualifier_default;
|
||||
} else {
|
||||
s_desc_cfg.qualifier = config->qualifier_descriptor;
|
||||
}
|
||||
|
||||
// Other Speed buffer allocate
|
||||
s_desc_cfg.other_speed = calloc(1, ((tusb_desc_configuration_t *)s_desc_cfg.hs_cfg)->wTotalLength);
|
||||
ESP_GOTO_ON_FALSE(s_desc_cfg.other_speed, ESP_ERR_NO_MEM, fail, TAG, "Other speed memory allocation error");
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
// Select String Descriptors and count them
|
||||
if (config->string_descriptor == NULL) {
|
||||
ESP_LOGW(TAG, "No String descriptors provided, using default.");
|
||||
pstr_desc = descriptor_str_default;
|
||||
while (descriptor_str_default[++s_desc_cfg.str_count] != NULL);
|
||||
} else {
|
||||
pstr_desc = config->string_descriptor;
|
||||
s_desc_cfg.str_count = (config->string_descriptor_count != 0)
|
||||
? config->string_descriptor_count
|
||||
: 8; // '8' is for backward compatibility with esp_tinyusb v1.0.0. Do NOT remove!
|
||||
}
|
||||
|
||||
ESP_GOTO_ON_FALSE(s_desc_cfg.str_count <= USB_STRING_DESCRIPTOR_ARRAY_SIZE, ESP_ERR_NOT_SUPPORTED, fail, TAG, "String descriptors exceed limit");
|
||||
memcpy(s_desc_cfg.str, pstr_desc, s_desc_cfg.str_count * sizeof(pstr_desc[0]));
|
||||
|
||||
ESP_LOGI(TAG, "\n"
|
||||
"┌─────────────────────────────────┐\n"
|
||||
"│ USB Device Descriptor Summary │\n"
|
||||
"├───────────────────┬─────────────┤\n"
|
||||
"│bDeviceClass │ %-4u │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│bDeviceSubClass │ %-4u │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│bDeviceProtocol │ %-4u │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│bMaxPacketSize0 │ %-4u │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│idVendor │ %-#10x │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│idProduct │ %-#10x │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│bcdDevice │ %-#10x │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│iManufacturer │ %-#10x │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│iProduct │ %-#10x │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│iSerialNumber │ %-#10x │\n"
|
||||
"├───────────────────┼─────────────┤\n"
|
||||
"│bNumConfigurations │ %-#10x │\n"
|
||||
"└───────────────────┴─────────────┘",
|
||||
s_desc_cfg.dev->bDeviceClass, s_desc_cfg.dev->bDeviceSubClass,
|
||||
s_desc_cfg.dev->bDeviceProtocol, s_desc_cfg.dev->bMaxPacketSize0,
|
||||
s_desc_cfg.dev->idVendor, s_desc_cfg.dev->idProduct, s_desc_cfg.dev->bcdDevice,
|
||||
s_desc_cfg.dev->iManufacturer, s_desc_cfg.dev->iProduct, s_desc_cfg.dev->iSerialNumber,
|
||||
s_desc_cfg.dev->bNumConfigurations);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
fail:
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
free(s_desc_cfg.other_speed);
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tinyusb_set_str_descriptor(const char *str, int str_idx)
|
||||
{
|
||||
assert(str_idx < USB_STRING_DESCRIPTOR_ARRAY_SIZE);
|
||||
s_desc_cfg.str[str_idx] = str;
|
||||
}
|
||||
|
||||
void tinyusb_free_descriptors(void)
|
||||
{
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
assert(s_desc_cfg.other_speed);
|
||||
free(s_desc_cfg.other_speed);
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
}
|
||||
13
managed_components/espressif__esp_tinyusb/idf_component.yml
Normal file
13
managed_components/espressif__esp_tinyusb/idf_component.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
dependencies:
|
||||
idf: '>=5.0'
|
||||
tinyusb:
|
||||
public: true
|
||||
version: '>=0.14.2'
|
||||
description: Espressif's additions to TinyUSB
|
||||
documentation: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/usb_device.html
|
||||
repository: git://github.com/espressif/esp-usb.git
|
||||
repository_info:
|
||||
commit_sha: c0be948c1acc6ee1f7ef00ab183c571971fccefd
|
||||
path: device/esp_tinyusb
|
||||
url: https://github.com/espressif/esp-usb/tree/master/device/esp_tinyusb
|
||||
version: 1.7.6~2
|
||||
85
managed_components/espressif__esp_tinyusb/include/tinyusb.h
Normal file
85
managed_components/espressif__esp_tinyusb/include/tinyusb.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "tusb.h"
|
||||
#include "tinyusb_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configuration structure of the TinyUSB core
|
||||
*
|
||||
* USB specification mandates self-powered devices to monitor USB VBUS to detect connection/disconnection events.
|
||||
* If you want to use this feature, connected VBUS to any free GPIO through a voltage divider or voltage comparator.
|
||||
* The voltage divider output should be (0.75 * Vdd) if VBUS is 4.4V (lowest valid voltage at device port).
|
||||
* The comparator thresholds should be set with hysteresis: 4.35V (falling edge) and 4.75V (raising edge).
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
const tusb_desc_device_t *device_descriptor; /*!< Pointer to a device descriptor. If set to NULL, the TinyUSB device will use a default device descriptor whose values are set in Kconfig */
|
||||
const tusb_desc_device_t *descriptor __attribute__((deprecated)); /*!< Alias to `device_descriptor` for backward compatibility */
|
||||
};
|
||||
const char **string_descriptor; /*!< Pointer to array of string descriptors. If set to NULL, TinyUSB device will use a default string descriptors whose values are set in Kconfig */
|
||||
int string_descriptor_count; /*!< Number of descriptors in above array */
|
||||
bool external_phy; /*!< Should USB use an external PHY */
|
||||
union {
|
||||
struct {
|
||||
const uint8_t *configuration_descriptor; /*!< Pointer to a configuration descriptor. If set to NULL, TinyUSB device will use a default configuration descriptor whose values are set in Kconfig */
|
||||
};
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
struct {
|
||||
const uint8_t *fs_configuration_descriptor; /*!< Pointer to a FullSpeed configuration descriptor. If set to NULL, TinyUSB device will use a default configuration descriptor whose values are set in Kconfig */
|
||||
};
|
||||
};
|
||||
const uint8_t *hs_configuration_descriptor; /*!< Pointer to a HighSpeed configuration descriptor. If set to NULL, TinyUSB device will use a default configuration descriptor whose values are set in Kconfig */
|
||||
const tusb_desc_device_qualifier_t *qualifier_descriptor; /*!< Pointer to a qualifier descriptor */
|
||||
#else
|
||||
};
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
bool self_powered; /*!< This is a self-powered USB device. USB VBUS must be monitored. */
|
||||
int vbus_monitor_io; /*!< GPIO for VBUS monitoring. Ignored if not self_powered. */
|
||||
} tinyusb_config_t;
|
||||
|
||||
/**
|
||||
* @brief This is an all-in-one helper function, including:
|
||||
* 1. USB device driver initialization
|
||||
* 2. Descriptors preparation
|
||||
* 3. TinyUSB stack initialization
|
||||
* 4. Creates and start a task to handle usb events
|
||||
*
|
||||
* @note Don't change Custom descriptor, but if it has to be done,
|
||||
* Suggest to define as follows in order to match the Interface Association Descriptor (IAD):
|
||||
* bDeviceClass = TUSB_CLASS_MISC,
|
||||
* bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
*
|
||||
* @param config tinyusb stack specific configuration
|
||||
* @retval ESP_ERR_INVALID_ARG Install driver and tinyusb stack failed because of invalid argument
|
||||
* @retval ESP_FAIL Install driver and tinyusb stack failed because of internal error
|
||||
* @retval ESP_OK Install driver and tinyusb stack successfully
|
||||
*/
|
||||
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief This is an all-in-one helper function, including:
|
||||
* 1. Stops the task to handle usb events
|
||||
* 2. TinyUSB stack tearing down
|
||||
* 2. Freeing resources after descriptors preparation
|
||||
* 3. Deletes USB PHY
|
||||
*
|
||||
* @retval ESP_FAIL Uninstall driver or tinyusb stack failed because of internal error
|
||||
* @retval ESP_OK Uninstall driver, tinyusb stack and USB PHY successfully
|
||||
*/
|
||||
esp_err_t tinyusb_driver_uninstall(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "tinyusb_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if (CONFIG_TINYUSB_NET_MODE_NONE != 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief On receive callback type
|
||||
*/
|
||||
typedef esp_err_t (*tusb_net_rx_cb_t)(void *buffer, uint16_t len, void *ctx);
|
||||
|
||||
/**
|
||||
* @brief Free Tx buffer callback type
|
||||
*/
|
||||
typedef void (*tusb_net_free_tx_cb_t)(void *buffer, void *ctx);
|
||||
|
||||
/**
|
||||
* @brief On init callback type
|
||||
*/
|
||||
typedef void (*tusb_net_init_cb_t)(void *ctx);
|
||||
|
||||
/**
|
||||
* @brief ESP TinyUSB NCM driver configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t mac_addr[6]; /*!< MAC address. Must be 6 bytes long. */
|
||||
tusb_net_rx_cb_t on_recv_callback; /*!< TinyUSB receive data callbeck */
|
||||
tusb_net_free_tx_cb_t free_tx_buffer; /*!< User function for freeing the Tx buffer.
|
||||
* - could be NULL, if user app is responsible for freeing the buffer
|
||||
* - must be used in asynchronous send mode
|
||||
* - is only called if the used tinyusb_net_send...() function returns ESP_OK
|
||||
* - in sync mode means that the packet was accepted by TinyUSB
|
||||
* - in async mode means that the packet was queued to be processed in TinyUSB task
|
||||
*/
|
||||
tusb_net_init_cb_t on_init_callback; /*!< TinyUSB init network callback */
|
||||
void *user_context; /*!< User context to be passed to any of the callback */
|
||||
} tinyusb_net_config_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize TinyUSB NET driver
|
||||
*
|
||||
* @param[in] usb_dev USB device to use
|
||||
* @param[in] cfg Configuration of the driver
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t tinyusb_net_init(tinyusb_usbdev_t usb_dev, const tinyusb_net_config_t *cfg);
|
||||
|
||||
/**
|
||||
* @brief TinyUSB NET driver send data synchronously
|
||||
*
|
||||
* @note It is possible to use sync and async send interchangeably.
|
||||
* This function needs some synchronization primitives, so using sync mode (even once) uses more heap
|
||||
*
|
||||
* @param[in] buffer USB send data
|
||||
* @param[in] len Send data len
|
||||
* @param[in] buff_free_arg Pointer to be passed to the free_tx_buffer() callback
|
||||
* @param[in] timeout Send data len
|
||||
* @return ESP_OK on success == packet has been consumed by tusb and would be eventually freed
|
||||
* by free_tx_buffer() callback (if non null)
|
||||
* ESP_ERR_TIMEOUT on timeout
|
||||
* ESP_ERR_INVALID_STATE if tusb not initialized, ESP_ERR_NO_MEM on alloc failure
|
||||
*/
|
||||
esp_err_t tinyusb_net_send_sync(void *buffer, uint16_t len, void *buff_free_arg, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief TinyUSB NET driver send data asynchronously
|
||||
*
|
||||
* @note If using asynchronous sends, you must free the buffer using free_tx_buffer() callback.
|
||||
* @note It is possible to use sync and async send interchangeably.
|
||||
* @note Async flavor of the send is useful when the USB stack runs faster than the caller,
|
||||
* since we have no control over the transmitted packets, if they get accepted or discarded.
|
||||
*
|
||||
* @param[in] buffer USB send data
|
||||
* @param[in] len Send data len
|
||||
* @param[in] buff_free_arg Pointer to be passed to the free_tx_buffer() callback
|
||||
* @return ESP_OK on success == packet has been consumed by tusb and will be freed
|
||||
* by free_tx_buffer() callback (if non null)
|
||||
* ESP_ERR_INVALID_STATE if tusb not initialized
|
||||
*/
|
||||
esp_err_t tinyusb_net_send_async(void *buffer, uint16_t len, void *buff_free_arg);
|
||||
|
||||
#endif // (CONFIG_TINYUSB_NET_MODE_NONE != 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define USB_ESPRESSIF_VID 0x303A
|
||||
|
||||
typedef enum {
|
||||
TINYUSB_USBDEV_0,
|
||||
} tinyusb_usbdev_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
206
managed_components/espressif__esp_tinyusb/include/tusb_cdc_acm.h
Normal file
206
managed_components/espressif__esp_tinyusb/include/tusb_cdc_acm.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "tinyusb_types.h"
|
||||
#include "class/cdc/cdc.h"
|
||||
|
||||
#if (CONFIG_TINYUSB_CDC_ENABLED != 1)
|
||||
#error "TinyUSB CDC driver must be enabled in menuconfig"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief CDC ports available to setup
|
||||
*/
|
||||
typedef enum {
|
||||
TINYUSB_CDC_ACM_0 = 0x0,
|
||||
TINYUSB_CDC_ACM_1,
|
||||
TINYUSB_CDC_ACM_MAX
|
||||
} tinyusb_cdcacm_itf_t;
|
||||
|
||||
/* Callbacks and events
|
||||
********************************************************************* */
|
||||
|
||||
/**
|
||||
* @brief Data provided to the input of the `callback_rx_wanted_char` callback
|
||||
*/
|
||||
typedef struct {
|
||||
char wanted_char; /*!< Wanted character */
|
||||
} cdcacm_event_rx_wanted_char_data_t;
|
||||
|
||||
/**
|
||||
* @brief Data provided to the input of the `callback_line_state_changed` callback
|
||||
*/
|
||||
typedef struct {
|
||||
bool dtr; /*!< Data Terminal Ready (DTR) line state */
|
||||
bool rts; /*!< Request To Send (RTS) line state */
|
||||
} cdcacm_event_line_state_changed_data_t;
|
||||
|
||||
/**
|
||||
* @brief Data provided to the input of the `line_coding_changed` callback
|
||||
*/
|
||||
typedef struct {
|
||||
cdc_line_coding_t const *p_line_coding; /*!< New line coding value */
|
||||
} cdcacm_event_line_coding_changed_data_t;
|
||||
|
||||
/**
|
||||
* @brief Types of CDC ACM events
|
||||
*/
|
||||
typedef enum {
|
||||
CDC_EVENT_RX,
|
||||
CDC_EVENT_RX_WANTED_CHAR,
|
||||
CDC_EVENT_LINE_STATE_CHANGED,
|
||||
CDC_EVENT_LINE_CODING_CHANGED
|
||||
} cdcacm_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief Describes an event passing to the input of a callbacks
|
||||
*/
|
||||
typedef struct {
|
||||
cdcacm_event_type_t type; /*!< Event type */
|
||||
union {
|
||||
cdcacm_event_rx_wanted_char_data_t rx_wanted_char_data; /*!< Data input of the `callback_rx_wanted_char` callback */
|
||||
cdcacm_event_line_state_changed_data_t line_state_changed_data; /*!< Data input of the `callback_line_state_changed` callback */
|
||||
cdcacm_event_line_coding_changed_data_t line_coding_changed_data; /*!< Data input of the `line_coding_changed` callback */
|
||||
};
|
||||
} cdcacm_event_t;
|
||||
|
||||
/**
|
||||
* @brief CDC-ACM callback type
|
||||
*/
|
||||
typedef void(*tusb_cdcacm_callback_t)(int itf, cdcacm_event_t *event);
|
||||
|
||||
/*********************************************************************** Callbacks and events*/
|
||||
/* Other structs
|
||||
********************************************************************* */
|
||||
|
||||
/**
|
||||
* @brief Configuration structure for CDC-ACM
|
||||
*/
|
||||
typedef struct {
|
||||
tinyusb_usbdev_t usb_dev; /*!< Usb device to set up */
|
||||
tinyusb_cdcacm_itf_t cdc_port; /*!< CDC port */
|
||||
size_t rx_unread_buf_sz __attribute__((deprecated("This parameter is not used any more. Configure RX buffer in menuconfig.")));
|
||||
tusb_cdcacm_callback_t callback_rx; /*!< Pointer to the function with the `tusb_cdcacm_callback_t` type that will be handled as a callback */
|
||||
tusb_cdcacm_callback_t callback_rx_wanted_char; /*!< Pointer to the function with the `tusb_cdcacm_callback_t` type that will be handled as a callback */
|
||||
tusb_cdcacm_callback_t callback_line_state_changed; /*!< Pointer to the function with the `tusb_cdcacm_callback_t` type that will be handled as a callback */
|
||||
tusb_cdcacm_callback_t callback_line_coding_changed; /*!< Pointer to the function with the `tusb_cdcacm_callback_t` type that will be handled as a callback */
|
||||
} tinyusb_config_cdcacm_t;
|
||||
|
||||
/*********************************************************************** Other structs*/
|
||||
/* Public functions
|
||||
********************************************************************* */
|
||||
/**
|
||||
* @brief Initialize CDC ACM. Initialization will be finished with
|
||||
* the `tud_cdc_line_state_cb` callback
|
||||
*
|
||||
* @param[in] cfg Configuration structure
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t tusb_cdc_acm_init(const tinyusb_config_cdcacm_t *cfg);
|
||||
|
||||
/**
|
||||
* @brief De-initialize CDC ACM.
|
||||
*
|
||||
* @param[in] itf Index of CDC interface
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t tusb_cdc_acm_deinit(int itf);
|
||||
|
||||
/**
|
||||
* @brief Register a callback invoking on CDC event. If the callback had been
|
||||
* already registered, it will be overwritten
|
||||
*
|
||||
* @param[in] itf Index of CDC interface
|
||||
* @param[in] event_type Type of registered event for a callback
|
||||
* @param[in] callback Callback function
|
||||
* @return esp_err_t - ESP_OK or ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t tinyusb_cdcacm_register_callback(tinyusb_cdcacm_itf_t itf,
|
||||
cdcacm_event_type_t event_type,
|
||||
tusb_cdcacm_callback_t callback);
|
||||
|
||||
/**
|
||||
* @brief Unregister a callback invoking on CDC event
|
||||
*
|
||||
* @param[in] itf Index of CDC interface
|
||||
* @param[in] event_type Type of registered event for a callback
|
||||
* @return esp_err_t - ESP_OK or ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t tinyusb_cdcacm_unregister_callback(tinyusb_cdcacm_itf_t itf, cdcacm_event_type_t event_type);
|
||||
|
||||
/**
|
||||
* @brief Sent one character to a write buffer
|
||||
*
|
||||
* @param[in] itf Index of CDC interface
|
||||
* @param[in] ch Character to send
|
||||
* @return size_t - amount of queued bytes
|
||||
*/
|
||||
size_t tinyusb_cdcacm_write_queue_char(tinyusb_cdcacm_itf_t itf, char ch);
|
||||
|
||||
/**
|
||||
* @brief Write data to write buffer
|
||||
*
|
||||
* @param[in] itf Index of CDC interface
|
||||
* @param[in] in_buf Data
|
||||
* @param[in] in_size Data size in bytes
|
||||
* @return size_t - amount of queued bytes
|
||||
*/
|
||||
size_t tinyusb_cdcacm_write_queue(tinyusb_cdcacm_itf_t itf, const uint8_t *in_buf, size_t in_size);
|
||||
|
||||
/**
|
||||
* @brief Flush data in write buffer of CDC interface
|
||||
*
|
||||
* Use `tinyusb_cdcacm_write_queue` to add data to the buffer
|
||||
*
|
||||
* WARNING! TinyUSB can block output Endpoint for several RX callbacks, after will do additional flush
|
||||
* after the each transfer. That can leads to the situation when you requested a flush, but it will fail until
|
||||
* one of the next callbacks ends.
|
||||
* SO USING OF THE FLUSH WITH TIMEOUTS IN CALLBACKS IS NOT RECOMMENDED - YOU CAN GET A LOCK FOR THE TIMEOUT
|
||||
*
|
||||
* @param[in] itf Index of CDC interface
|
||||
* @param[in] timeout_ticks Transfer timeout. Set to zero for non-blocking mode
|
||||
* @return - ESP_OK All data flushed
|
||||
* - ESP_ERR_TIMEOUT Time out occurred in blocking mode
|
||||
* - ESP_NOT_FINISHED The transfer is still in progress in non-blocking mode
|
||||
*/
|
||||
esp_err_t tinyusb_cdcacm_write_flush(tinyusb_cdcacm_itf_t itf, uint32_t timeout_ticks);
|
||||
|
||||
/**
|
||||
* @brief Receive data from CDC interface
|
||||
*
|
||||
* @param[in] itf Index of CDC interface
|
||||
* @param[out] out_buf Data buffer
|
||||
* @param[in] out_buf_sz Data buffer size in bytes
|
||||
* @param[out] rx_data_size Number of bytes written to out_buf
|
||||
* @return esp_err_t ESP_OK, ESP_FAIL or ESP_ERR_INVALID_STATE
|
||||
*/
|
||||
esp_err_t tinyusb_cdcacm_read(tinyusb_cdcacm_itf_t itf, uint8_t *out_buf, size_t out_buf_sz, size_t *rx_data_size);
|
||||
|
||||
/**
|
||||
* @brief Check if the CDC interface is initialized
|
||||
*
|
||||
* @param[in] itf Index of CDC interface
|
||||
* @return - true Initialized
|
||||
* - false Not Initialized
|
||||
*/
|
||||
bool tusb_cdc_acm_initialized(tinyusb_cdcacm_itf_t itf);
|
||||
|
||||
/*********************************************************************** Public functions*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
185
managed_components/espressif__esp_tinyusb/include/tusb_config.h
Normal file
185
managed_components/espressif__esp_tinyusb/include/tusb_config.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Ha Thach (tinyusb.org),
|
||||
* SPDX-FileContributor: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org),
|
||||
* Additions Copyright (c) 2020, Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tusb_option.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_CDC_ENABLED
|
||||
# define CONFIG_TINYUSB_CDC_ENABLED 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_CDC_COUNT
|
||||
# define CONFIG_TINYUSB_CDC_COUNT 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_MSC_ENABLED
|
||||
# define CONFIG_TINYUSB_MSC_ENABLED 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_HID_COUNT
|
||||
# define CONFIG_TINYUSB_HID_COUNT 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_MIDI_COUNT
|
||||
# define CONFIG_TINYUSB_MIDI_COUNT 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_VENDOR_COUNT
|
||||
# define CONFIG_TINYUSB_VENDOR_COUNT 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_NET_MODE_ECM_RNDIS
|
||||
# define CONFIG_TINYUSB_NET_MODE_ECM_RNDIS 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_NET_MODE_NCM
|
||||
# define CONFIG_TINYUSB_NET_MODE_NCM 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_DFU_MODE_DFU
|
||||
# define CONFIG_TINYUSB_DFU_MODE_DFU 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_DFU_MODE_DFU_RUNTIME
|
||||
# define CONFIG_TINYUSB_DFU_MODE_DFU_RUNTIME 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_BTH_ENABLED
|
||||
# define CONFIG_TINYUSB_BTH_ENABLED 0
|
||||
# define CONFIG_TINYUSB_BTH_ISO_ALT_COUNT 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINYUSB_DEBUG_LEVEL
|
||||
# define CONFIG_TINYUSB_DEBUG_LEVEL 0
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// DCD DWC2 Mode
|
||||
// ------------------------------------------------------------------------
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE 1 // Enable Slave/IRQ by default
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// DMA & Cache
|
||||
// ------------------------------------------------------------------------
|
||||
#ifdef CONFIG_TINYUSB_MODE_DMA
|
||||
// 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
|
||||
#endif // CONFIG_TINYUSB_MODE_DMA
|
||||
|
||||
#define CFG_TUSB_OS OPT_OS_FREERTOS
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
# define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
# define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
// Debug Level
|
||||
#define CFG_TUSB_DEBUG CONFIG_TINYUSB_DEBUG_LEVEL
|
||||
#define CFG_TUSB_DEBUG_PRINTF esp_rom_printf // TinyUSB can print logs from ISR, so we must use esp_rom_printf()
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE CONFIG_TINYUSB_CDC_RX_BUFSIZE
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE CONFIG_TINYUSB_CDC_TX_BUFSIZE
|
||||
|
||||
// MSC Buffer size of Device Mass storage
|
||||
#define CFG_TUD_MSC_BUFSIZE CONFIG_TINYUSB_MSC_BUFSIZE
|
||||
|
||||
// MIDI macros
|
||||
#define CFG_TUD_MIDI_EP_BUFSIZE 64
|
||||
#define CFG_TUD_MIDI_EPSIZE CFG_TUD_MIDI_EP_BUFSIZE
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE 64
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE 64
|
||||
|
||||
// Vendor FIFO size of TX and RX
|
||||
#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
// DFU macros
|
||||
#define CFG_TUD_DFU_XFER_BUFSIZE CONFIG_TINYUSB_DFU_BUFSIZE
|
||||
|
||||
// Number of BTH ISO alternatives
|
||||
#define CFG_TUD_BTH_ISO_ALT_COUNT CONFIG_TINYUSB_BTH_ISO_ALT_COUNT
|
||||
|
||||
// Enabled device class driver
|
||||
#define CFG_TUD_CDC CONFIG_TINYUSB_CDC_COUNT
|
||||
#define CFG_TUD_MSC CONFIG_TINYUSB_MSC_ENABLED
|
||||
#define CFG_TUD_HID CONFIG_TINYUSB_HID_COUNT
|
||||
#define CFG_TUD_MIDI CONFIG_TINYUSB_MIDI_COUNT
|
||||
#define CFG_TUD_VENDOR CONFIG_TINYUSB_VENDOR_COUNT
|
||||
#define CFG_TUD_ECM_RNDIS CONFIG_TINYUSB_NET_MODE_ECM_RNDIS
|
||||
#define CFG_TUD_NCM CONFIG_TINYUSB_NET_MODE_NCM
|
||||
#define CFG_TUD_DFU CONFIG_TINYUSB_DFU_MODE_DFU
|
||||
#define CFG_TUD_DFU_RUNTIME CONFIG_TINYUSB_DFU_MODE_DFU_RUNTIME
|
||||
#define CFG_TUD_BTH CONFIG_TINYUSB_BTH_ENABLED
|
||||
|
||||
// NCM NET Mode NTB buffers configuration
|
||||
#define CFG_TUD_NCM_OUT_NTB_N CONFIG_TINYUSB_NCM_OUT_NTB_BUFFS_COUNT
|
||||
#define CFG_TUD_NCM_IN_NTB_N CONFIG_TINYUSB_NCM_IN_NTB_BUFFS_COUNT
|
||||
#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE CONFIG_TINYUSB_NCM_OUT_NTB_BUFF_MAX_SIZE
|
||||
#define CFG_TUD_NCM_IN_NTB_MAX_SIZE CONFIG_TINYUSB_NCM_IN_NTB_BUFF_MAX_SIZE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Redirect output to the USB serial
|
||||
* @param cdc_intf - interface number of TinyUSB's CDC
|
||||
*
|
||||
* @return esp_err_t - ESP_OK, ESP_FAIL or an error code
|
||||
*/
|
||||
esp_err_t esp_tusb_init_console(int cdc_intf);
|
||||
|
||||
/**
|
||||
* @brief Switch log to the default output
|
||||
* @param cdc_intf - interface number of TinyUSB's CDC
|
||||
*
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t esp_tusb_deinit_console(int cdc_intf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include "esp_err.h"
|
||||
#include "wear_levelling.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
#include "driver/sdmmc_host.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Data provided to the input of the `callback_mount_changed` and `callback_premount_changed` callback
|
||||
*/
|
||||
typedef struct {
|
||||
bool is_mounted; /*!< Flag if storage is mounted or not */
|
||||
} tinyusb_msc_event_mount_changed_data_t;
|
||||
|
||||
/**
|
||||
* @brief Types of MSC events
|
||||
*/
|
||||
typedef enum {
|
||||
TINYUSB_MSC_EVENT_MOUNT_CHANGED, /*!< Event type AFTER mount/unmount operation is successfully finished */
|
||||
TINYUSB_MSC_EVENT_PREMOUNT_CHANGED /*!< Event type BEFORE mount/unmount operation is started */
|
||||
} tinyusb_msc_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief Describes an event passing to the input of a callbacks
|
||||
*/
|
||||
typedef struct {
|
||||
tinyusb_msc_event_type_t type; /*!< Event type */
|
||||
union {
|
||||
tinyusb_msc_event_mount_changed_data_t mount_changed_data; /*!< Data input of the callback */
|
||||
};
|
||||
} tinyusb_msc_event_t;
|
||||
|
||||
/**
|
||||
* @brief MSC callback that is delivered whenever a specific event occurs.
|
||||
*/
|
||||
typedef void(*tusb_msc_callback_t)(tinyusb_msc_event_t *event);
|
||||
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
/**
|
||||
* @brief Configuration structure for sdmmc initialization
|
||||
*
|
||||
* User configurable parameters that are used while
|
||||
* initializing the sdmmc media.
|
||||
*/
|
||||
typedef struct {
|
||||
sdmmc_card_t *card; /*!< Pointer to sdmmc card configuration structure */
|
||||
tusb_msc_callback_t callback_mount_changed; /*!< Pointer to the function callback that will be delivered AFTER mount/unmount operation is successfully finished */
|
||||
tusb_msc_callback_t callback_premount_changed; /*!< Pointer to the function callback that will be delivered BEFORE mount/unmount operation is started */
|
||||
const esp_vfs_fat_mount_config_t mount_config; /*!< FATFS mount config */
|
||||
} tinyusb_msc_sdmmc_config_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configuration structure for spiflash initialization
|
||||
*
|
||||
* User configurable parameters that are used while
|
||||
* initializing the SPI Flash media.
|
||||
*/
|
||||
typedef struct {
|
||||
wl_handle_t wl_handle; /*!< Pointer to spiflash wera-levelling handle */
|
||||
tusb_msc_callback_t callback_mount_changed; /*!< Pointer to the function callback that will be delivered AFTER mount/unmount operation is successfully finished */
|
||||
tusb_msc_callback_t callback_premount_changed; /*!< Pointer to the function callback that will be delivered BEFORE mount/unmount operation is started */
|
||||
const esp_vfs_fat_mount_config_t mount_config; /*!< FATFS mount config */
|
||||
} tinyusb_msc_spiflash_config_t;
|
||||
|
||||
/**
|
||||
* @brief Register storage type spiflash with tinyusb driver
|
||||
*
|
||||
* @param config pointer to the spiflash configuration
|
||||
* @return esp_err_t
|
||||
* - ESP_OK, if success;
|
||||
* - ESP_ERR_NO_MEM, if there was no memory to allocate storage components;
|
||||
* - ESP_ERR_NOT_SUPPORTED, if wear leveling sector size CONFIG_WL_SECTOR_SIZE is bigger than
|
||||
* the tinyusb MSC buffer size CONFIG_TINYUSB_MSC_BUFSIZE
|
||||
*/
|
||||
esp_err_t tinyusb_msc_storage_init_spiflash(const tinyusb_msc_spiflash_config_t *config);
|
||||
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
/**
|
||||
* @brief Register storage type sd-card with tinyusb driver
|
||||
*
|
||||
* @param config pointer to the sd card configuration
|
||||
* @return esp_err_t
|
||||
* - ESP_OK, if success;
|
||||
* - ESP_ERR_NO_MEM, if there was no memory to allocate storage components;
|
||||
*/
|
||||
esp_err_t tinyusb_msc_storage_init_sdmmc(const tinyusb_msc_sdmmc_config_t *config);
|
||||
#endif
|
||||
/**
|
||||
* @brief Deregister storage with tinyusb driver and frees the memory
|
||||
*
|
||||
*/
|
||||
void tinyusb_msc_storage_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Register a callback invoking on MSC event. If the callback had been
|
||||
* already registered, it will be overwritten
|
||||
*
|
||||
* @param event_type - type of registered event for a callback
|
||||
* @param callback - callback function
|
||||
* @return esp_err_t - ESP_OK or ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t tinyusb_msc_register_callback(tinyusb_msc_event_type_t event_type,
|
||||
tusb_msc_callback_t callback);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unregister a callback invoking on MSC event.
|
||||
*
|
||||
* @param event_type - type of registered event for a callback
|
||||
* @return esp_err_t - ESP_OK or ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t tinyusb_msc_unregister_callback(tinyusb_msc_event_type_t event_type);
|
||||
|
||||
/**
|
||||
* @brief Mount the storage partition locally on the firmware application.
|
||||
*
|
||||
* Get the available drive number. Register spi flash partition.
|
||||
* Connect POSIX and C standard library IO function with FATFS.
|
||||
* Mounts the partition.
|
||||
* This API is used by the firmware application. If the storage partition is
|
||||
* mounted by this API, host (PC) can't access the storage via MSC.
|
||||
* When this function is called from the tinyusb callback functions, care must be taken
|
||||
* so as to make sure that user callbacks must be completed within a
|
||||
* specific time. Otherwise, MSC device may re-appear again on Host.
|
||||
*
|
||||
* @param base_path path prefix where FATFS should be registered
|
||||
* @return esp_err_t
|
||||
* - ESP_OK, if success;
|
||||
* - ESP_ERR_NOT_FOUND if the maximum count of volumes is already mounted
|
||||
* - ESP_ERR_NO_MEM if not enough memory or too many VFSes already registered;
|
||||
*/
|
||||
esp_err_t tinyusb_msc_storage_mount(const char *base_path);
|
||||
|
||||
/**
|
||||
* @brief Unmount the storage partition from the firmware application.
|
||||
*
|
||||
* Unmount the partition. Unregister diskio driver.
|
||||
* Unregister the SPI flash partition.
|
||||
* Finally, Un-register FATFS from VFS.
|
||||
* After this function is called, storage device can be seen (recognized) by host (PC).
|
||||
* When this function is called from the tinyusb callback functions, care must be taken
|
||||
* so as to make sure that user callbacks must be completed within a specific time.
|
||||
* Otherwise, MSC device may not appear on Host.
|
||||
*
|
||||
* @return esp_err_t
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if FATFS is not registered in VFS
|
||||
*/
|
||||
esp_err_t tinyusb_msc_storage_unmount(void);
|
||||
|
||||
/**
|
||||
* @brief Get number of sectors in storage media
|
||||
*
|
||||
* @return usable size, in bytes
|
||||
*/
|
||||
uint32_t tinyusb_msc_storage_get_sector_count(void);
|
||||
|
||||
/**
|
||||
* @brief Get sector size of storage media
|
||||
*
|
||||
* @return sector count
|
||||
*/
|
||||
uint32_t tinyusb_msc_storage_get_sector_size(void);
|
||||
|
||||
/**
|
||||
* @brief Get status if storage media is exposed over USB to Host
|
||||
*
|
||||
* @return bool
|
||||
* - true, if the storage media is exposed to Host
|
||||
* - false, if the stoarge media is mounted on application (not exposed to Host)
|
||||
*/
|
||||
bool tinyusb_msc_storage_in_use_by_usb_host(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This helper function creates and starts a task which wraps `tud_task()`.
|
||||
*
|
||||
* The wrapper function basically wraps tud_task and some log.
|
||||
* Default parameters: stack size and priority as configured, argument = NULL, not pinned to any core.
|
||||
* If you have more requirements for this task, you can create your own task which calls tud_task as the last step.
|
||||
*
|
||||
* @retval ESP_OK run tinyusb main task successfully
|
||||
* @retval ESP_FAIL run tinyusb main task failed of internal error or initialization within the task failed when TINYUSB_INIT_IN_DEFAULT_TASK=y
|
||||
* @retval ESP_FAIL initialization within the task failed if CONFIG_TINYUSB_INIT_IN_DEFAULT_TASK is enabled
|
||||
* @retval ESP_ERR_INVALID_STATE tinyusb main task has been created before
|
||||
*/
|
||||
esp_err_t tusb_run_task(void);
|
||||
|
||||
/**
|
||||
* @brief This helper function stops and destroys the task created by `tusb_run_task()`
|
||||
*
|
||||
* @retval ESP_OK stop and destroy tinyusb main task successfully
|
||||
* @retval ESP_ERR_INVALID_STATE tinyusb main task hasn't been created yet
|
||||
*/
|
||||
esp_err_t tusb_stop_task(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_vfs_common.h" // For esp_line_endings_t definitions
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define VFS_TUSB_MAX_PATH 16
|
||||
#define VFS_TUSB_PATH_DEFAULT "/dev/tusb_cdc"
|
||||
|
||||
/**
|
||||
* @brief Register TinyUSB CDC at VFS with path
|
||||
*
|
||||
* Know limitation:
|
||||
* In case there are multiple CDC interfaces in the system, only one of them can be registered to VFS.
|
||||
*
|
||||
* @param[in] cdc_intf Interface number of TinyUSB's CDC
|
||||
* @param[in] path Path where the CDC will be registered, `/dev/tusb_cdc` will be used if left NULL.
|
||||
* @return esp_err_t ESP_OK or ESP_FAIL
|
||||
*/
|
||||
esp_err_t esp_vfs_tusb_cdc_register(int cdc_intf, char const *path);
|
||||
|
||||
/**
|
||||
* @brief Unregister TinyUSB CDC from VFS
|
||||
*
|
||||
* @param[in] path Path where the CDC will be unregistered if NULL will be used `/dev/tusb_cdc`
|
||||
* @return esp_err_t ESP_OK or ESP_FAIL
|
||||
*/
|
||||
esp_err_t esp_vfs_tusb_cdc_unregister(char const *path);
|
||||
|
||||
/**
|
||||
* @brief Set the line endings to sent
|
||||
*
|
||||
* This specifies the conversion between newlines ('\n', LF) on stdout and line
|
||||
* endings sent:
|
||||
*
|
||||
* - ESP_LINE_ENDINGS_CRLF: convert LF to CRLF
|
||||
* - ESP_LINE_ENDINGS_CR: convert LF to CR
|
||||
* - ESP_LINE_ENDINGS_LF: no modification
|
||||
*
|
||||
* @param[in] mode line endings to send
|
||||
*/
|
||||
void esp_vfs_tusb_cdc_set_tx_line_endings(esp_line_endings_t mode);
|
||||
|
||||
/**
|
||||
* @brief Set the line endings expected to be received
|
||||
*
|
||||
* This specifies the conversion between line endings received and
|
||||
* newlines ('\n', LF) passed into stdin:
|
||||
*
|
||||
* - ESP_LINE_ENDINGS_CRLF: convert CRLF to LF
|
||||
* - ESP_LINE_ENDINGS_CR: convert CR to LF
|
||||
* - ESP_LINE_ENDINGS_LF: no modification
|
||||
*
|
||||
* @param[in] mode line endings expected
|
||||
*/
|
||||
void esp_vfs_tusb_cdc_set_rx_line_endings(esp_line_endings_t mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "tusb.h"
|
||||
#include "tinyusb_types.h"
|
||||
|
||||
/* CDC classification
|
||||
********************************************************************* */
|
||||
typedef enum {
|
||||
TINYUSB_CDC_DATA = 0x00,
|
||||
} cdc_data_sublcass_type_t; // CDC120 specification
|
||||
|
||||
/* Note:other classification is represented in the file components\tinyusb\tinyusb\src\class\cdc\cdc.h */
|
||||
|
||||
/*********************************************************************** CDC classification*/
|
||||
/* Structs
|
||||
********************************************************************* */
|
||||
typedef struct {
|
||||
tinyusb_usbdev_t usb_dev; /*!< USB device to set up */
|
||||
tusb_class_code_t cdc_class; /*!< CDC device class : Communications or Data device */
|
||||
union {
|
||||
cdc_comm_sublcass_type_t comm_subclass; /*!< Communications device subclasses: ACM, ECM, etc. */
|
||||
cdc_data_sublcass_type_t data_subclass; /*!< Data device has only one subclass.*/
|
||||
} cdc_subclass; /*!< CDC device subclass according to Class Definitions for Communications Devices the CDC v.1.20 */
|
||||
} tinyusb_config_cdc_t; /*!< Main configuration structure of a CDC device */
|
||||
|
||||
typedef struct {
|
||||
tinyusb_usbdev_t usb_dev; /*!< USB device used for the instance */
|
||||
tusb_class_code_t type;
|
||||
union {
|
||||
cdc_comm_sublcass_type_t comm_subclass; /*!< Communications device subclasses: ACM, ECM, etc. */
|
||||
cdc_data_sublcass_type_t data_subclass; /*!< Data device has only one subclass.*/
|
||||
} cdc_subclass; /*!< CDC device subclass according to Class Definitions for Communications Devices the CDC v.1.20 */
|
||||
void *subclass_obj; /*!< Dynamically allocated subclass specific object */
|
||||
} esp_tusb_cdc_t;
|
||||
/*********************************************************************** Structs*/
|
||||
/* Functions
|
||||
********************************************************************* */
|
||||
/**
|
||||
* @brief Initializing CDC basic object
|
||||
* @param itf - number of a CDC object
|
||||
* @param cfg - CDC configuration structure
|
||||
*
|
||||
* @return esp_err_t ESP_OK or ESP_FAIL
|
||||
*/
|
||||
esp_err_t tinyusb_cdc_init(int itf, const tinyusb_config_cdc_t *cfg);
|
||||
|
||||
|
||||
/**
|
||||
* @brief De-initializing CDC. Clean its objects
|
||||
* @param itf - number of a CDC object
|
||||
* @return esp_err_t ESP_OK, ESP_ERR_INVALID_ARG, ESP_ERR_INVALID_STATE
|
||||
*
|
||||
*/
|
||||
esp_err_t tinyusb_cdc_deinit(int itf);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return interface of a CDC device
|
||||
*
|
||||
* @param itf_num
|
||||
* @return esp_tusb_cdc_t* pointer to the interface or (NULL) on error
|
||||
*/
|
||||
esp_tusb_cdc_t *tinyusb_cdc_get_intf(int itf_num);
|
||||
/*********************************************************************** Functions*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tinyusb.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define USB_STRING_DESCRIPTOR_ARRAY_SIZE 8 // Max 8 string descriptors for a device. LANGID, Manufacturer, Product, Serial number + 4 user defined
|
||||
|
||||
/**
|
||||
* @brief Parse tinyusb configuration and prepare the device configuration pointer list to configure tinyusb driver
|
||||
*
|
||||
* @attention All descriptors passed to this function must exist for the duration of USB device lifetime
|
||||
*
|
||||
* @param[in] config tinyusb stack specific configuration
|
||||
* @retval ESP_ERR_INVALID_ARG Default configuration descriptor is provided only for CDC, MSC and NCM classes
|
||||
* @retval ESP_ERR_NO_MEM Memory allocation error
|
||||
* @retval ESP_OK Descriptors configured without error
|
||||
*/
|
||||
esp_err_t tinyusb_set_descriptors(const tinyusb_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Set specific string descriptor
|
||||
*
|
||||
* @attention The descriptor passed to this function must exist for the duration of USB device lifetime
|
||||
*
|
||||
* @param[in] str UTF-8 string
|
||||
* @param[in] str_idx String descriptor index
|
||||
*/
|
||||
void tinyusb_set_str_descriptor(const char *str, int str_idx);
|
||||
|
||||
/**
|
||||
* @brief Free memory allocated during tinyusb_set_descriptors
|
||||
*
|
||||
*/
|
||||
void tinyusb_free_descriptors(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Device descriptor generated from Kconfig
|
||||
*
|
||||
* This descriptor is used by default.
|
||||
* The user can provide their own device descriptor via tinyusb_driver_install() call
|
||||
*/
|
||||
extern const tusb_desc_device_t descriptor_dev_default;
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
/**
|
||||
* @brief Qualifier Device descriptor generated from Kconfig
|
||||
*
|
||||
* This descriptor is used by default.
|
||||
* The user can provide their own descriptor via tinyusb_driver_install() call
|
||||
*/
|
||||
extern const tusb_desc_device_qualifier_t descriptor_qualifier_default;
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
/**
|
||||
* @brief Array of string descriptors generated from Kconfig
|
||||
*
|
||||
* This descriptor is used by default.
|
||||
* The user can provide their own descriptor via tinyusb_driver_install() call
|
||||
*/
|
||||
extern const char *descriptor_str_default[];
|
||||
|
||||
/**
|
||||
* @brief FullSpeed configuration descriptor generated from Kconfig
|
||||
* This descriptor is used by default.
|
||||
* The user can provide their own FullSpeed configuration descriptor via tinyusb_driver_install() call
|
||||
*/
|
||||
extern const uint8_t descriptor_fs_cfg_default[];
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
/**
|
||||
* @brief HighSpeed Configuration descriptor generated from Kconfig
|
||||
*
|
||||
* This descriptor is used by default.
|
||||
* The user can provide their own HighSpeed configuration descriptor via tinyusb_driver_install() call
|
||||
*/
|
||||
extern const uint8_t descriptor_hs_cfg_default[];
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
uint8_t tusb_get_mac_string_id(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
2
managed_components/espressif__esp_tinyusb/sbom.yml
Normal file
2
managed_components/espressif__esp_tinyusb/sbom.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
supplier: 'Organization: Espressif Systems (Shanghai) CO LTD'
|
||||
originator: 'Organization: Espressif Systems (Shanghai) CO LTD'
|
||||
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
project(libusb_test
|
||||
LANGUAGES C
|
||||
)
|
||||
|
||||
add_executable(libusb_test libusb_test.c)
|
||||
target_link_libraries(libusb_test -lusb-1.0)
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#define TINYUSB_VENDOR 0x303A
|
||||
#define TINYUSB_PRODUCT 0x4002
|
||||
|
||||
#define DESC_TYPE_DEVICE_QUALIFIER 0x06
|
||||
#define DESC_TYOE_OTHER_SPEED_CONFIG 0x07
|
||||
|
||||
// Buffer for descriptor data
|
||||
unsigned char buffer[512] = { 0 };
|
||||
|
||||
// USB Other Speed Configuration Descriptor
|
||||
typedef struct __attribute__ ((packed))
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint16_t wTotalLength ; ///< Total length of data returned
|
||||
|
||||
uint8_t bNumInterfaces ; ///< Number of interfaces supported by this speed configuration
|
||||
uint8_t bConfigurationValue ; ///< Value to use to select configuration
|
||||
uint8_t iConfiguration ; ///< Index of string descriptor
|
||||
uint8_t bmAttributes ; ///< Same as Configuration descriptor
|
||||
uint8_t bMaxPower ; ///< Same as Configuration descriptor
|
||||
} desc_other_speed_t;
|
||||
|
||||
// USB Device Qualifier Descriptor
|
||||
typedef struct __attribute__ ((packed))
|
||||
{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Device Qualifier Type
|
||||
uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00)
|
||||
|
||||
uint8_t bDeviceClass ; ///< Class Code
|
||||
uint8_t bDeviceSubClass ; ///< SubClass Code
|
||||
uint8_t bDeviceProtocol ; ///< Protocol Code
|
||||
|
||||
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for other speed
|
||||
uint8_t bNumConfigurations ; ///< Number of Other-speed Configurations
|
||||
uint8_t bReserved ; ///< Reserved for future use, must be zero
|
||||
} desc_device_qualifier_t;
|
||||
|
||||
// printf helpers
|
||||
static void _print_device_qulifier_desc(unsigned char *buffer, int length);
|
||||
static void _print_other_speed_desc(unsigned char *buffer, int length);
|
||||
|
||||
//
|
||||
// MAIN
|
||||
//
|
||||
int main()
|
||||
{
|
||||
libusb_context *context = NULL;
|
||||
int rc = 0;
|
||||
|
||||
rc = libusb_init(&context);
|
||||
assert(rc == 0);
|
||||
libusb_device_handle *dev_handle = libusb_open_device_with_vid_pid(context,
|
||||
TINYUSB_VENDOR,
|
||||
TINYUSB_PRODUCT);
|
||||
|
||||
if (dev_handle != NULL) {
|
||||
printf("TinyUSB Device has been found\n");
|
||||
|
||||
// Test Qualifier Descriprtor
|
||||
// 1. Get Qualifier Descriptor
|
||||
// 2. print descriptor data
|
||||
rc = libusb_get_descriptor(dev_handle, DESC_TYPE_DEVICE_QUALIFIER, 0, buffer, 512);
|
||||
_print_device_qulifier_desc(buffer, rc);
|
||||
|
||||
// Test Other Speed Descriptor
|
||||
// 1. Get Other Speed Descriptor
|
||||
// 2. print descriptor data
|
||||
rc = libusb_get_descriptor(dev_handle, DESC_TYOE_OTHER_SPEED_CONFIG, 0, buffer, 512);
|
||||
_print_other_speed_desc(buffer, rc);
|
||||
|
||||
libusb_close(dev_handle);
|
||||
} else {
|
||||
printf("TinyUSB Device has NOT been found\n");
|
||||
}
|
||||
|
||||
libusb_exit(context);
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
static void _print_device_qulifier_desc(unsigned char *buffer, int length)
|
||||
{
|
||||
assert(buffer);
|
||||
desc_device_qualifier_t *qualifier_desc = (desc_device_qualifier_t *) buffer;
|
||||
printf("========= Device Qualifier ========== \n");
|
||||
printf("\t bLength: %d \n", qualifier_desc->bLength);
|
||||
printf("\t bDescriptorType: %d (%#x)\n", qualifier_desc->bDescriptorType, qualifier_desc->bDescriptorType);
|
||||
printf("\t bcdUSB: %d (%#x) \n", qualifier_desc->bcdUSB, qualifier_desc->bcdUSB);
|
||||
printf("\t bDeviceClass: %d (%#x) \n", qualifier_desc->bDeviceClass, qualifier_desc->bDeviceClass);
|
||||
printf("\t bDeviceSubClass: %d \n", qualifier_desc->bDeviceSubClass);
|
||||
printf("\t bDeviceProtocol: %d \n", qualifier_desc->bDeviceProtocol);
|
||||
printf("\t bMaxPacketSize0: %d \n", qualifier_desc->bMaxPacketSize0);
|
||||
printf("\t bNumConfigurations: %d \n", qualifier_desc->bNumConfigurations);
|
||||
}
|
||||
|
||||
static void _print_other_speed_desc(unsigned char *buffer, int length)
|
||||
{
|
||||
assert(buffer);
|
||||
desc_other_speed_t *other_speed = (desc_other_speed_t *) buffer;
|
||||
printf("============ Other Speed ============ \n");
|
||||
printf("\t bLength: %d \n", other_speed->bLength);
|
||||
printf("\t bDescriptorType: %d (%#x) \n", other_speed->bDescriptorType, other_speed->bDescriptorType);
|
||||
printf("\t wTotalLength: %d \n", other_speed->wTotalLength);
|
||||
printf("\t bNumInterfaces: %d \n", other_speed->bNumInterfaces);
|
||||
printf("\t bConfigurationValue: %d \n", other_speed->bConfigurationValue);
|
||||
printf("\t iConfiguration: %d \n", other_speed->iConfiguration);
|
||||
printf("\t bmAttributes: %d (%#x) \n", other_speed->bmAttributes, other_speed->bmAttributes);
|
||||
printf("\t bMaxPower: %d (%#x) \n", other_speed->bMaxPower, other_speed->bMaxPower);
|
||||
}
|
||||
131
managed_components/espressif__esp_tinyusb/test_apps/README.md
Normal file
131
managed_components/espressif__esp_tinyusb/test_apps/README.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# CI target runner setup
|
||||
|
||||
To allow a Docker container, running on a CI target runner, to access USB devices connected to the CI target runner, some modifications must be made.
|
||||
In our case, it's an `RPI` target runner.
|
||||
|
||||
The main idea comes from this response on [stackoverflow](https://stackoverflow.com/a/66427245/19840830). The same approach is also recommended in the official Docker [documentation](https://docs.docker.com/reference/cli/docker/container/run/#device-cgroup-rule)
|
||||
|
||||
|
||||
### Following changes shall be made on a CI target runner
|
||||
|
||||
- [`UDEV rules`](#udev-rules)
|
||||
- [`Docker tty script`](#docker-tty-script)
|
||||
- [`Logging`](#logging)
|
||||
- [`Running a docker container`](#running-a-docker-container)
|
||||
- [`GitHub CI target runner setup`](#github-ci-target-runner-setup)
|
||||
- [`GitLab CI target runner setup`](#gitlab-ci-target-runner-setup)
|
||||
|
||||
## UDEV rules
|
||||
|
||||
- This UDEV rule will trigger a `docker_tty.sh` script every time a USB device is connected, disconnected, or enumerated by the host machine (CI target runner)
|
||||
- Location: `/etc/udev/rules.d/99-docker-tty.rules`
|
||||
- `99-docker-tty.rules` file content:
|
||||
|
||||
``` sh
|
||||
ACTION=="add", SUBSYSTEM=="tty", RUN+="/usr/local/bin/docker_tty.sh 'added' '%E{DEVNAME}' '%M' '%m'"
|
||||
ACTION=="remove", SUBSYSTEM=="tty", RUN+="/usr/local/bin/docker_tty.sh 'removed' '%E{DEVNAME}' '%M' '%m'"
|
||||
```
|
||||
|
||||
## Docker tty script
|
||||
|
||||
- This `.sh` script, triggered by the UDEV rule above, will propagate USB devices to a running Docker container.
|
||||
- Location: `/usr/local/bin/docker_tty.sh`
|
||||
- `docker_tty.sh` file content:
|
||||
|
||||
``` sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Log the USB event with parameters
|
||||
echo "USB event: $1 $2 $3 $4" >> /tmp/docker_tty.log
|
||||
|
||||
# Find a running Docker container (using the first one found)
|
||||
docker_name=$(docker ps --format "{{.Names}}" | head -n 1)
|
||||
|
||||
# Check if a container was found
|
||||
if [ ! -z "$docker_name" ]; then
|
||||
if [ "$1" == "added" ]; then
|
||||
docker exec -u 0 "$docker_name" mknod $2 c $3 $4
|
||||
docker exec -u 0 "$docker_name" chmod -R 777 $2
|
||||
echo "Adding $2 to Docker container $docker_name" >> /tmp/docker_tty.log
|
||||
else
|
||||
docker exec -u 0 "$docker_name" rm $2
|
||||
echo "Removing $2 from Docker container $docker_name" >> /tmp/docker_tty.log
|
||||
fi
|
||||
else
|
||||
echo "No running Docker containers found." >> /tmp/docker_tty.log
|
||||
fi
|
||||
```
|
||||
|
||||
### Making the script executable
|
||||
|
||||
Don't forget to make the created script executable:
|
||||
``` sh
|
||||
root@~$ chmod +x /usr/local/bin/docker_tty.sh
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
- The `docker_tty.sh` script logs information about the USB devices it processes.
|
||||
- Location: `/tmp/docker_tty.log`
|
||||
- Example of a log from the `docker_tty.log` file, showing a flow of the `pytest_usb_device.py` test
|
||||
|
||||
```
|
||||
USB event: added /dev/ttyACM0 166 0
|
||||
USB event: added /dev/ttyACM1 166 1
|
||||
Adding /dev/ttyACM0 to Docker container d5e5c774174b435b8befea864f8fcb7f_python311bookworm_6a975d
|
||||
Adding /dev/ttyACM1 to Docker container d5e5c774174b435b8befea864f8fcb7f_python311bookworm_6a975d
|
||||
USB event: removed /dev/ttyACM0 166 0
|
||||
USB event: removed /dev/ttyACM1 166 1
|
||||
```
|
||||
|
||||
## Running a docker container
|
||||
|
||||
### Check Major and Minor numbers of connected devices
|
||||
|
||||
Check the Major and Minor numbers assigned by the Linux kernel to devices that you want the Docker container to access.
|
||||
In our case, we want to access `/dev/ttyUSB0`, `/dev/ttyACM0` and `/dev/ttyACM1`
|
||||
|
||||
`/dev/ttyUSB0`: Major 188, Minor 0
|
||||
``` sh
|
||||
peter@BrnoRPIG007:~ $ ls -l /dev/ttyUSB0
|
||||
crw-rw-rw- 1 root dialout 188, 0 Nov 12 11:08 /dev/ttyUSB0
|
||||
```
|
||||
|
||||
`/dev/ttyACM0` and `/dev/ttyACM1`: Major 166, Minor 0 (1)
|
||||
``` sh
|
||||
peter@BrnoRPIG007:~ $ ls -l /dev/ttyACM0
|
||||
crw-rw---- 1 root dialout 166, 0 Nov 13 10:26 /dev/ttyACM0
|
||||
peter@BrnoRPIG007:~ $ ls -l /dev/ttyACM1
|
||||
crw-rw---- 1 root dialout 166, 1 Nov 13 10:26 /dev/ttyACM1
|
||||
```
|
||||
|
||||
### Run a docker container
|
||||
|
||||
Run a Docker container with the following extra options:
|
||||
``` sh
|
||||
docker run --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 166:* rmw' --privileged ..
|
||||
```
|
||||
- `--device-cgroup-rule='c 188:* rmw'`: allow access to `ttyUSBx` (Major 188, all Minors)
|
||||
- `--device-cgroup-rule='c 166:* rmw'`: allow access to `ttyACMx` (Major 166, all Minors)
|
||||
|
||||
## GitHub CI target runner setup
|
||||
|
||||
To apply these changes to a GitHub target runner a `.yml` file used to run a Docker container for pytest must be modified. The Docker container is then run with the following options:
|
||||
|
||||
``` yaml
|
||||
container:
|
||||
image: python:3.11-bookworm
|
||||
options: --privileged --device-cgroup-rule="c 188:* rmw" --device-cgroup-rule="c 166:* rmw"
|
||||
```
|
||||
|
||||
## GitLab CI target runner setup
|
||||
|
||||
To apply these changes to a GitLab runner the `config.toml` file located at `/etc/gitlab-runner/config.toml` on each GitLab target runner must be modified.
|
||||
|
||||
According to GitLab's [documentation](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersdocker-section) the `[runners.docker]` section of the `config.toml` file should include the `device_cgroup_rules` parameter:
|
||||
|
||||
``` toml
|
||||
[runners.docker]
|
||||
...
|
||||
device_cgroup_rules = ["c 188:* rmw", "c 166:* rmw"]
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_app_cdc)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
_ _ _
|
||||
| | (_) | |
|
||||
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
|
||||
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
|
||||
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
|
||||
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
|
||||
| |______ __/ |
|
||||
|_|______| |___/
|
||||
_____ _____ _____ _____
|
||||
|_ _| ___/ ___|_ _|
|
||||
| | | |__ \ `--. | |
|
||||
| | | __| `--. \ | |
|
||||
| | | |___/\__/ / | |
|
||||
\_/ \____/\____/ \_/
|
||||
*/
|
||||
|
||||
printf(" _ _ _ \n");
|
||||
printf(" | | (_) | | \n");
|
||||
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
|
||||
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
|
||||
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
|
||||
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
|
||||
printf(" | |______ __/ | \n");
|
||||
printf(" |_|______| |___/ \n");
|
||||
printf(" _____ _____ _____ _____ \n");
|
||||
printf("|_ _| ___/ ___|_ _| \n");
|
||||
printf(" | | | |__ \\ `--. | | \n");
|
||||
printf(" | | | __| `--. \\ | | \n");
|
||||
printf(" | | | |___/\\__/ / | | \n");
|
||||
printf(" \\_/ \\____/\\____/ \\_/ \n");
|
||||
|
||||
unity_utils_setup_heap_record(80);
|
||||
unity_utils_set_leak_level(128);
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
/* setUp runs before every test */
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
/* tearDown runs after every test */
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks();
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_cdc_acm.h"
|
||||
#include "vfs_tinyusb.h"
|
||||
|
||||
#define VFS_PATH "/dev/usb-cdc1"
|
||||
|
||||
static const tusb_desc_device_t cdc_device_descriptor = {
|
||||
.bLength = sizeof(cdc_device_descriptor),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = USB_ESPRESSIF_VID,
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
static const uint16_t cdc_desc_config_len = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN;
|
||||
static const uint8_t cdc_desc_configuration[] = {
|
||||
TUD_CONFIG_DESCRIPTOR(1, 4, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, (TUD_OPT_HIGH_SPEED ? 512 : 64)),
|
||||
TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, (TUD_OPT_HIGH_SPEED ? 512 : 64)),
|
||||
};
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
static const tusb_desc_device_qualifier_t device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0
|
||||
};
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
static void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB CDC testcase
|
||||
*
|
||||
* This is not a 'standard' testcase, as it never exits. The testcase runs in a loop where it echoes back all the data received.
|
||||
*
|
||||
* - Init TinyUSB with standard CDC device and configuration descriptors
|
||||
* - Init 2 CDC-ACM interfaces
|
||||
* - Map CDC1 to Virtual File System
|
||||
* - In a loop: Read data from CDC0 and CDC1. Echo received data back
|
||||
*
|
||||
* Note: CDC0 appends 'novfs' to echoed data, so the host (test runner) can easily determine which port is which.
|
||||
*/
|
||||
TEST_CASE("tinyusb_cdc", "[esp_tinyusb][cdc]")
|
||||
{
|
||||
// Install TinyUSB driver
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &cdc_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = cdc_desc_configuration,
|
||||
.hs_configuration_descriptor = cdc_desc_configuration,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = cdc_desc_configuration,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
|
||||
tinyusb_config_cdcacm_t acm_cfg = {
|
||||
.usb_dev = TINYUSB_USBDEV_0,
|
||||
.cdc_port = TINYUSB_CDC_ACM_0,
|
||||
.rx_unread_buf_sz = 64,
|
||||
.callback_rx = &tinyusb_cdc_rx_callback,
|
||||
.callback_rx_wanted_char = NULL,
|
||||
.callback_line_state_changed = NULL,
|
||||
.callback_line_coding_changed = NULL
|
||||
};
|
||||
|
||||
// Init CDC 0
|
||||
TEST_ASSERT_FALSE(tusb_cdc_acm_initialized(TINYUSB_CDC_ACM_0));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tusb_cdc_acm_init(&acm_cfg));
|
||||
TEST_ASSERT_TRUE(tusb_cdc_acm_initialized(TINYUSB_CDC_ACM_0));
|
||||
|
||||
// Init CDC 1
|
||||
acm_cfg.cdc_port = TINYUSB_CDC_ACM_1;
|
||||
acm_cfg.callback_rx = NULL;
|
||||
TEST_ASSERT_FALSE(tusb_cdc_acm_initialized(TINYUSB_CDC_ACM_1));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tusb_cdc_acm_init(&acm_cfg));
|
||||
TEST_ASSERT_TRUE(tusb_cdc_acm_initialized(TINYUSB_CDC_ACM_1));
|
||||
|
||||
// Install VFS to CDC 1
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_vfs_tusb_cdc_register(TINYUSB_CDC_ACM_1, VFS_PATH));
|
||||
esp_vfs_tusb_cdc_set_rx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||
esp_vfs_tusb_cdc_set_tx_line_endings(ESP_LINE_ENDINGS_LF);
|
||||
FILE *cdc = fopen(VFS_PATH, "r+");
|
||||
TEST_ASSERT_NOT_NULL(cdc);
|
||||
|
||||
uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1];
|
||||
while (true) {
|
||||
size_t b = fread(buf, 1, sizeof(buf), cdc);
|
||||
if (b > 0) {
|
||||
printf("Intf VFS, RX %d bytes\n", b);
|
||||
//ESP_LOG_BUFFER_HEXDUMP("test", buf, b, ESP_LOG_INFO);
|
||||
fwrite(buf, 1, b, cdc);
|
||||
}
|
||||
vTaskDelay(1);
|
||||
|
||||
size_t rx_size = 0;
|
||||
int itf = 0;
|
||||
ESP_ERROR_CHECK(tinyusb_cdcacm_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE, &rx_size));
|
||||
if (rx_size > 0) {
|
||||
printf("Intf %d, RX %d bytes\n", itf, rx_size);
|
||||
|
||||
// Add 'novfs' to reply so the host can identify the port
|
||||
strcpy((char *)&buf[rx_size - 2], "novfs\r\n");
|
||||
tinyusb_cdcacm_write_queue(itf, buf, rx_size + sizeof("novfs") - 1);
|
||||
|
||||
tinyusb_cdcacm_write_flush(itf, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
from time import sleep
|
||||
from serial import Serial, SerialException
|
||||
from serial.tools.list_ports import comports
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_device_cdc(dut) -> None:
|
||||
'''
|
||||
Running the test locally:
|
||||
1. Build the testa app for your DUT (ESP32-S2 or S3)
|
||||
2. Connect you DUT to your test runner (local machine) with USB port and flashing port
|
||||
3. Run `pytest --target esp32s3`
|
||||
|
||||
Test procedure:
|
||||
1. Run the test on the DUT
|
||||
2. Expect 2 Virtual COM Ports in the system
|
||||
3. Open both comports and send some data. Expect echoed data
|
||||
'''
|
||||
dut.expect_exact('Press ENTER to see the list of tests.')
|
||||
dut.write('[cdc]')
|
||||
dut.expect_exact('TinyUSB: TinyUSB Driver installed')
|
||||
sleep(2) # Some time for the OS to enumerate our USB device
|
||||
|
||||
# Find devices with Espressif TinyUSB VID/PID
|
||||
s = []
|
||||
ports = comports()
|
||||
|
||||
for port, _, hwid in ports:
|
||||
if '303A:4002' in hwid:
|
||||
s.append(port)
|
||||
|
||||
if len(s) != 2:
|
||||
raise Exception('TinyUSB COM port not found')
|
||||
|
||||
try:
|
||||
with Serial(s[0]) as cdc0:
|
||||
with Serial(s[1]) as cdc1:
|
||||
# Write dummy string and check for echo
|
||||
cdc0.write('text\r\n'.encode())
|
||||
res = cdc0.readline()
|
||||
assert b'text' in res
|
||||
if b'novfs' in res:
|
||||
novfs_cdc = cdc0
|
||||
vfs_cdc = cdc1
|
||||
|
||||
cdc1.write('text\r\n'.encode())
|
||||
res = cdc1.readline()
|
||||
assert b'text' in res
|
||||
if b'novfs' in res:
|
||||
novfs_cdc = cdc1
|
||||
vfs_cdc = cdc0
|
||||
|
||||
# Write more than MPS, check that the transfer is not divided
|
||||
novfs_cdc.write(bytes(100))
|
||||
dut.expect_exact("Intf 0, RX 100 bytes")
|
||||
|
||||
# Write more than RX buffer, check correct reception
|
||||
novfs_cdc.write(bytes(600))
|
||||
transfer_len1 = int(dut.expect(r'Intf 0, RX (\d+) bytes')[1].decode())
|
||||
transfer_len2 = int(dut.expect(r'Intf 0, RX (\d+) bytes')[1].decode())
|
||||
assert transfer_len1 + transfer_len2 == 600
|
||||
|
||||
# The VFS is setup for CRLF RX and LF TX
|
||||
vfs_cdc.write('text\r\n'.encode())
|
||||
res = vfs_cdc.readline()
|
||||
assert b'text\n' in res
|
||||
|
||||
return
|
||||
|
||||
except SerialException as e:
|
||||
print(f"SerialException occurred: {e}")
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
raise
|
||||
@@ -0,0 +1,18 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_MSC_ENABLED=n
|
||||
CONFIG_TINYUSB_CDC_ENABLED=y
|
||||
CONFIG_TINYUSB_CDC_COUNT=2
|
||||
CONFIG_TINYUSB_HID_COUNT=0
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_app_configuration_descriptor)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
_ _ _
|
||||
| | (_) | |
|
||||
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
|
||||
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
|
||||
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
|
||||
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
|
||||
| |______ __/ |
|
||||
|_|______| |___/
|
||||
_____ _____ _____ _____
|
||||
|_ _| ___/ ___|_ _|
|
||||
| | | |__ \ `--. | |
|
||||
| | | __| `--. \ | |
|
||||
| | | |___/\__/ / | |
|
||||
\_/ \____/\____/ \_/
|
||||
*/
|
||||
|
||||
printf(" _ _ _ \n");
|
||||
printf(" | | (_) | | \n");
|
||||
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
|
||||
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
|
||||
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
|
||||
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
|
||||
printf(" | |______ __/ | \n");
|
||||
printf(" |_|______| |___/ \n");
|
||||
printf(" _____ _____ _____ _____ \n");
|
||||
printf("|_ _| ___/ ___|_ _| \n");
|
||||
printf(" | | | |__ \\ `--. | | \n");
|
||||
printf(" | | | __| `--. \\ | | \n");
|
||||
printf(" | | | |___/\\__/ / | | \n");
|
||||
printf(" \\_/ \\____/\\____/ \\_/ \n");
|
||||
|
||||
unity_utils_setup_heap_record(80);
|
||||
unity_utils_set_leak_level(128);
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
/* setUp runs before every test */
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
/* tearDown runs after every test */
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks();
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
|
||||
static const char *TAG = "config_test";
|
||||
|
||||
#define TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS 1000
|
||||
#define TEARDOWN_DEVICE_DETACH_DELAY_MS 1000
|
||||
|
||||
// ========================= TinyUSB descriptors ===============================
|
||||
|
||||
// Here we need to create dual CDC device, to match the CONFIG_TINYUSB_CDC_COUNT from sdkconfig.defaults
|
||||
static const uint16_t cdc_desc_config_len = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN;
|
||||
static const uint8_t test_fs_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, CFG_TUD_CDC * 2, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, 64),
|
||||
#if CFG_TUD_CDC > 1
|
||||
TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, 64),
|
||||
#endif
|
||||
};
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
static const uint8_t test_hs_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 4, 0, cdc_desc_config_len, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
TUD_CDC_DESCRIPTOR(0, 4, 0x81, 8, 0x02, 0x82, 512),
|
||||
TUD_CDC_DESCRIPTOR(2, 4, 0x83, 8, 0x04, 0x84, 512),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_qualifier_t device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0
|
||||
};
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_device_descriptor),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
// ========================== Private logic ====================================
|
||||
SemaphoreHandle_t wait_mount = NULL;
|
||||
|
||||
/**
|
||||
* @brief Creates test additional resources.
|
||||
*
|
||||
* Is called before start test to create/init internal resources.
|
||||
*/
|
||||
static bool __test_init(void)
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
return (wait_mount != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Indicates device connection event.
|
||||
*
|
||||
* Is called in tud_mount callback.
|
||||
*/
|
||||
static void __test_conn(void)
|
||||
{
|
||||
if (wait_mount) {
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Awaits device connection event.
|
||||
*
|
||||
* Is used for waiting the event in test logic.
|
||||
* Timeout could be configured via TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS define.
|
||||
*/
|
||||
static esp_err_t __test_wait_conn(void)
|
||||
{
|
||||
if (!wait_mount) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return ( xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS))
|
||||
? ESP_OK
|
||||
: ESP_ERR_TIMEOUT );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases test resources.
|
||||
*
|
||||
* Is called in the end of the test to release internal resources.
|
||||
*/
|
||||
static void __test_release(void)
|
||||
{
|
||||
if (wait_mount) {
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief One round of setup configuration for TinyUSB.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Init internal resources
|
||||
* 2. Installs TinyUSB with provided configuration
|
||||
* 3. Waits for the connection event from the Host
|
||||
* 4. Gives some extra time for Host to configure the device (configures via TEARDOWN_DEVICE_DETACH_DELAY_MS)
|
||||
* 5. Uninstall TinyUSB
|
||||
* 6. Release internal resources
|
||||
*
|
||||
* Is called in the end of the test to release internal resources.
|
||||
*/
|
||||
static void __test_tinyusb_set_config(const tinyusb_config_t *tusb_cfg)
|
||||
{
|
||||
TEST_ASSERT_EQUAL(true, __test_init());
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(tusb_cfg));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, __test_wait_conn());
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DETACH_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
__test_release();
|
||||
}
|
||||
|
||||
// ========================== Callbacks ========================================
|
||||
/**
|
||||
* @brief TinyUSB callback for device mount.
|
||||
*
|
||||
* @note
|
||||
* For Linux-based Hosts: Reflects the SetConfiguration() request from the Host Driver.
|
||||
* For Win-based Hosts: SetConfiguration() request is present only with available Class in device descriptor.
|
||||
*/
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s", __FUNCTION__);
|
||||
__test_conn();
|
||||
}
|
||||
|
||||
// ============================= Tests =========================================
|
||||
/**
|
||||
* @brief TinyUSB Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration without specifying any parameters.
|
||||
* Configuration & descriptors are provided by esp_tinyusb wrapper.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_all_default", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = NULL,
|
||||
.configuration_descriptor = NULL,
|
||||
#if (CONFIG_TINYUSB_RHPORT_HS)
|
||||
.hs_configuration_descriptor = NULL,
|
||||
#endif // CONFIG_TINYUSB_RHPORT_HS
|
||||
};
|
||||
// Install TinyUSB driver
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration with specifying only device descriptor.
|
||||
* For High-speed qualifier descriptor as well.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_device", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.configuration_descriptor = NULL,
|
||||
#if (CONFIG_TINYUSB_RHPORT_HS)
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#endif // CONFIG_TINYUSB_RHPORT_HS
|
||||
};
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration with specifying device & configuration descriptors.
|
||||
*
|
||||
* For High-speed:
|
||||
* - HS configuration descriptor is not provided by user (legacy compatibility) and default HS config descriptor is using when possible.
|
||||
* - Qualifier descriptor.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_device_and_config", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.configuration_descriptor = test_fs_configuration_descriptor,
|
||||
#if (CONFIG_TINYUSB_RHPORT_HS)
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#endif // CONFIG_TINYUSB_RHPORT_HS
|
||||
};
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
|
||||
#if (CONFIG_IDF_TARGET_ESP32P4)
|
||||
/**
|
||||
* @brief TinyUSB High-speed Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration with specifying device & HS configuration descriptor only.
|
||||
* FS configuration descriptor is not provided by user (legacy compatibility) and default configuration descriptor for FS is using when possible.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_device_and_hs_config_only", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.configuration_descriptor = NULL,
|
||||
.hs_configuration_descriptor = test_hs_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
};
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB High-speed Configuration test case.
|
||||
*
|
||||
* Verifies:
|
||||
* Configuration with specifying all descriptors by user.
|
||||
*/
|
||||
TEST_CASE("descriptors_config_all_configured", "[esp_tinyusb][usb_device][config]")
|
||||
{
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.fs_configuration_descriptor = test_fs_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_hs_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
};
|
||||
__test_tinyusb_set_config(&tusb_cfg);
|
||||
}
|
||||
#endif // CONFIG_IDF_TARGET_ESP32P4
|
||||
|
||||
#endif // SOC_USB_OTG_SUPPORTED
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_device_configuration(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='config')
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_CDC_ENABLED=y
|
||||
CONFIG_TINYUSB_CDC_COUNT=2
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_app_dconn_detection)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
_ _ _
|
||||
| | (_) | |
|
||||
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
|
||||
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
|
||||
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
|
||||
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
|
||||
| |______ __/ |
|
||||
|_|______| |___/
|
||||
_____ _____ _____ _____
|
||||
|_ _| ___/ ___|_ _|
|
||||
| | | |__ \ `--. | |
|
||||
| | | __| `--. \ | |
|
||||
| | | |___/\__/ / | |
|
||||
\_/ \____/\____/ \_/
|
||||
*/
|
||||
|
||||
printf(" _ _ _ \n");
|
||||
printf(" | | (_) | | \n");
|
||||
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
|
||||
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
|
||||
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
|
||||
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
|
||||
printf(" | |______ __/ | \n");
|
||||
printf(" |_|______| |___/ \n");
|
||||
printf(" _____ _____ _____ _____ \n");
|
||||
printf("|_ _| ___/ ___|_ _| \n");
|
||||
printf(" | | | |__ \\ `--. | | \n");
|
||||
printf(" | | | __| `--. \\ | | \n");
|
||||
printf(" | | | |___/\\__/ / | | \n");
|
||||
printf(" \\_/ \\____/\\____/ \\_/ \n");
|
||||
|
||||
unity_utils_setup_heap_record(80);
|
||||
unity_utils_set_leak_level(128);
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
/* setUp runs before every test */
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
/* tearDown runs after every test */
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks();
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_tasks.h"
|
||||
|
||||
#define DEVICE_DETACH_TEST_ROUNDS 10
|
||||
#define DEVICE_DETACH_ROUND_DELAY_MS 1000
|
||||
|
||||
#if (CONFIG_IDF_TARGET_ESP32P4)
|
||||
#define USB_SRP_BVALID_IN_IDX USB_SRP_BVALID_PAD_IN_IDX
|
||||
#endif // CONFIG_IDF_TARGET_ESP32P4
|
||||
|
||||
/* TinyUSB descriptors
|
||||
********************************************************************* */
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
|
||||
static unsigned int dev_mounted = 0;
|
||||
static unsigned int dev_umounted = 0;
|
||||
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_device_descriptor),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
static const tusb_desc_device_qualifier_t device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0
|
||||
};
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
/**
|
||||
* @attention Tests relying on this callback only pass on Linux USB Host!
|
||||
*
|
||||
* This callback is issued after SetConfiguration command from USB Host.
|
||||
* However, Windows issues SetConfiguration only after a USB driver was assigned to the device.
|
||||
* So in case you are implementing a Vendor Specific class, or your device has 0 interfaces, this callback is not issued on Windows host.
|
||||
*/
|
||||
printf("%s\n", __FUNCTION__);
|
||||
dev_mounted++;
|
||||
}
|
||||
|
||||
// Invoked when device is unmounted
|
||||
void tud_umount_cb(void)
|
||||
{
|
||||
printf("%s\n", __FUNCTION__);
|
||||
dev_umounted++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Disconnect Detection test case
|
||||
*
|
||||
* This is specific artificial test for verifying the disconnection detection event.
|
||||
* Normally, this event comes as a result of detaching USB device from the port and disappearing the VBUS voltage.
|
||||
* In this test case, we use GPIO matrix and connect the signal to the ZERO or ONE constant inputs.
|
||||
* Connection to constant ONE input emulates the attachment to the USB Host port (appearing VBUS).
|
||||
* Connection to constant ZERO input emulates the detachment from the USB Host port (removing VBUS).
|
||||
*
|
||||
* Test logic:
|
||||
* - Install TinyUSB Device stack without any class
|
||||
* - In cycle:
|
||||
* - Emulate the detachment, get the tud_umount_cb(), increase the dev_umounted value
|
||||
* - Emulate the attachment, get the tud_mount_cb(), increase the dev_mounted value
|
||||
* - Verify that dev_umounted == dev_mounted
|
||||
* - Verify that dev_mounted == DEVICE_DETACH_TEST_ROUNDS, where DEVICE_DETACH_TEST_ROUNDS - amount of rounds
|
||||
* - Uninstall TinyUSB Device stack
|
||||
*
|
||||
*/
|
||||
TEST_CASE("dconn_detection", "[esp_tinyusb][dconn]")
|
||||
{
|
||||
unsigned int rounds = DEVICE_DETACH_TEST_ROUNDS;
|
||||
|
||||
// Install TinyUSB driver
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
|
||||
dev_mounted = 0;
|
||||
dev_umounted = 0;
|
||||
|
||||
while (rounds--) {
|
||||
// LOW to emulate disconnect USB device
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_SRP_BVALID_IN_IDX, false);
|
||||
vTaskDelay(pdMS_TO_TICKS(DEVICE_DETACH_ROUND_DELAY_MS));
|
||||
// HIGH to emulate connect USB device
|
||||
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false);
|
||||
vTaskDelay(pdMS_TO_TICKS(DEVICE_DETACH_ROUND_DELAY_MS));
|
||||
}
|
||||
|
||||
// Verify
|
||||
TEST_ASSERT_EQUAL(dev_umounted, dev_mounted);
|
||||
TEST_ASSERT_EQUAL(DEVICE_DETACH_TEST_ROUNDS, dev_mounted);
|
||||
|
||||
// Cleanup
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
}
|
||||
#endif // SOC_USB_OTG_SUPPORTED
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
#@pytest.mark.usb_device Disable in CI: unavailable teardown for P4
|
||||
def test_usb_device_dconn_detection(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='dconn')
|
||||
@@ -0,0 +1,18 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_MSC_ENABLED=n
|
||||
CONFIG_TINYUSB_CDC_ENABLED=n
|
||||
CONFIG_TINYUSB_CDC_COUNT=0
|
||||
CONFIG_TINYUSB_HID_COUNT=0
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_app_default_task_without_init)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
_ _ _
|
||||
| | (_) | |
|
||||
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
|
||||
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
|
||||
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
|
||||
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
|
||||
| |______ __/ |
|
||||
|_|______| |___/
|
||||
_____ _____ _____ _____
|
||||
|_ _| ___/ ___|_ _|
|
||||
| | | |__ \ `--. | |
|
||||
| | | __| `--. \ | |
|
||||
| | | |___/\__/ / | |
|
||||
\_/ \____/\____/ \_/
|
||||
*/
|
||||
|
||||
printf(" _ _ _ \n");
|
||||
printf(" | | (_) | | \n");
|
||||
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
|
||||
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
|
||||
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
|
||||
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
|
||||
printf(" | |______ __/ | \n");
|
||||
printf(" |_|______| |___/ \n");
|
||||
printf(" _____ _____ _____ _____ \n");
|
||||
printf("|_ _| ___/ ___|_ _| \n");
|
||||
printf(" | | | |__ \\ `--. | | \n");
|
||||
printf(" | | | __| `--. \\ | | \n");
|
||||
printf(" | | | |___/\\__/ / | | \n");
|
||||
printf(" \\_/ \\____/\\____/ \\_/ \n");
|
||||
|
||||
unity_utils_setup_heap_record(80);
|
||||
unity_utils_set_leak_level(128);
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
/* setUp runs before every test */
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
/* tearDown runs after every test */
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks();
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
//
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
//
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
//
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
|
||||
static const char *TAG = "default_task";
|
||||
|
||||
SemaphoreHandle_t wait_mount = NULL;
|
||||
|
||||
#define TEARDOWN_DEVICE_DELAY_MS 1000
|
||||
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_device_descriptor),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
static const tusb_desc_device_qualifier_t device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0
|
||||
};
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Task specific testcase
|
||||
*
|
||||
* Scenario:
|
||||
* 1. Install TinyUSB driver
|
||||
* 2. Wait tud_mount_cb() until TUSB_DEVICE_DELAY_MS
|
||||
* 3. Wait TUSB_DEVICE_DELAY_MS
|
||||
* 4. Teardown TinyUSB
|
||||
* 5. Release resources
|
||||
*/
|
||||
TEST_CASE("tinyusb_default_task_with_init", "[esp_tinyusb][tusb_task]")
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount);
|
||||
|
||||
// TinyUSB driver configuration
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_DELAY_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Remove primitives
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_default_task_with_init(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='tusb_task')
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB
|
||||
CONFIG_TINYUSB_NO_DEFAULT_TASK=n
|
||||
CONFIG_TINYUSB_INIT_IN_DEFAULT_TASK=n
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_app_default_task_with_init)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
_ _ _
|
||||
| | (_) | |
|
||||
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
|
||||
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
|
||||
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
|
||||
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
|
||||
| |______ __/ |
|
||||
|_|______| |___/
|
||||
_____ _____ _____ _____
|
||||
|_ _| ___/ ___|_ _|
|
||||
| | | |__ \ `--. | |
|
||||
| | | __| `--. \ | |
|
||||
| | | |___/\__/ / | |
|
||||
\_/ \____/\____/ \_/
|
||||
*/
|
||||
|
||||
printf(" _ _ _ \n");
|
||||
printf(" | | (_) | | \n");
|
||||
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
|
||||
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
|
||||
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
|
||||
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
|
||||
printf(" | |______ __/ | \n");
|
||||
printf(" |_|______| |___/ \n");
|
||||
printf(" _____ _____ _____ _____ \n");
|
||||
printf("|_ _| ___/ ___|_ _| \n");
|
||||
printf(" | | | |__ \\ `--. | | \n");
|
||||
printf(" | | | __| `--. \\ | | \n");
|
||||
printf(" | | | |___/\\__/ / | | \n");
|
||||
printf(" \\_/ \\____/\\____/ \\_/ \n");
|
||||
|
||||
unity_utils_setup_heap_record(80);
|
||||
unity_utils_set_leak_level(128);
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
/* setUp runs before every test */
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
/* tearDown runs after every test */
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks();
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
//
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
//
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
//
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
|
||||
static const char *TAG = "default_task_with_init";
|
||||
|
||||
SemaphoreHandle_t wait_mount = NULL;
|
||||
|
||||
#define TEARDOWN_DEVICE_DELAY_MS 1000
|
||||
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_device_descriptor),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
static const tusb_desc_device_qualifier_t device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0
|
||||
};
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Task specific testcase
|
||||
*
|
||||
* Scenario:
|
||||
* 1. Install TinyUSB driver
|
||||
* 2. Wait tud_mount_cb() until TUSB_DEVICE_DELAY_MS
|
||||
* 3. Wait TUSB_DEVICE_DELAY_MS
|
||||
* 4. Teardown TinyUSB
|
||||
* 5. Release resources
|
||||
*/
|
||||
TEST_CASE("tinyusb_default_task_with_init", "[esp_tinyusb][tusb_task]")
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount);
|
||||
|
||||
// TinyUSB driver configuration
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_DELAY_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Remove primitives
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_default_task_with_init(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='tusb_task')
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB
|
||||
CONFIG_TINYUSB_NO_DEFAULT_TASK=n
|
||||
CONFIG_TINYUSB_INIT_IN_DEFAULT_TASK=y
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_app_external_task_without_init)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
_ _ _
|
||||
| | (_) | |
|
||||
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
|
||||
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
|
||||
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
|
||||
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
|
||||
| |______ __/ |
|
||||
|_|______| |___/
|
||||
_____ _____ _____ _____
|
||||
|_ _| ___/ ___|_ _|
|
||||
| | | |__ \ `--. | |
|
||||
| | | __| `--. \ | |
|
||||
| | | |___/\__/ / | |
|
||||
\_/ \____/\____/ \_/
|
||||
*/
|
||||
|
||||
printf(" _ _ _ \n");
|
||||
printf(" | | (_) | | \n");
|
||||
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
|
||||
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
|
||||
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
|
||||
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
|
||||
printf(" | |______ __/ | \n");
|
||||
printf(" |_|______| |___/ \n");
|
||||
printf(" _____ _____ _____ _____ \n");
|
||||
printf("|_ _| ___/ ___|_ _| \n");
|
||||
printf(" | | | |__ \\ `--. | | \n");
|
||||
printf(" | | | __| `--. \\ | | \n");
|
||||
printf(" | | | |___/\\__/ / | | \n");
|
||||
printf(" \\_/ \\____/\\____/ \\_/ \n");
|
||||
|
||||
unity_utils_setup_heap_record(80);
|
||||
unity_utils_set_leak_level(128);
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
/* setUp runs before every test */
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
/* tearDown runs after every test */
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks();
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
//
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
//
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
//
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
|
||||
static const char *TAG = "external_task";
|
||||
|
||||
static SemaphoreHandle_t wait_mount = NULL;
|
||||
static TaskHandle_t s_test_tusb_tskh;
|
||||
|
||||
#define TUSB_DEVICE_DELAY_MS 1000
|
||||
#define TUSB_EXTERNAL_TASK_SIZE 4096
|
||||
#define TUSB_EXTERNAL_TASK_PRIO 5
|
||||
#define TUSB_EXTERNAL_TASK_AFFINITY 0x7FFFFFFF /* FREERTOS_NO_AFFINITY */
|
||||
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_device_descriptor),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
static const tusb_desc_device_qualifier_t device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0
|
||||
};
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This top level thread processes all usb events and invokes callbacks
|
||||
*/
|
||||
static void test_tusb_external_task(void *arg)
|
||||
{
|
||||
ESP_LOGD(TAG, "External TinyUSB task started");
|
||||
while (1) { // RTOS forever loop
|
||||
tud_task();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Task specific testcase
|
||||
*
|
||||
* Scenario:
|
||||
* 1. Install TinyUSB driver
|
||||
* 2. Create external TinyUSB task for tud_task()
|
||||
* 3. Wait tud_mount_cb() until TUSB_DEVICE_DELAY_MS
|
||||
* 4. Wait TUSB_DEVICE_DELAY_MS
|
||||
* 5. Teardown TinyUSB
|
||||
* 6. Release resources
|
||||
*
|
||||
* @note If run the task before installing the tinyusb driver, the external task will lead to cpu starvation.
|
||||
*/
|
||||
TEST_CASE("tinyusb_external_task", "[esp_tinyusb][tusb_task]")
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount);
|
||||
|
||||
// TinyUSB driver configuration
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Create an external task for tinyusb device stack
|
||||
xTaskCreate(test_tusb_external_task,
|
||||
"TinyUSB",
|
||||
TUSB_EXTERNAL_TASK_SIZE,
|
||||
NULL,
|
||||
TUSB_EXTERNAL_TASK_PRIO,
|
||||
&s_test_tusb_tskh);
|
||||
TEST_ASSERT_NOT_NULL(s_test_tusb_tskh);
|
||||
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TUSB_DEVICE_DELAY_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TUSB_DEVICE_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Remove primitives
|
||||
vTaskDelete(s_test_tusb_tskh);
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_external_task_internal_init(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='tusb_task')
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB
|
||||
CONFIG_TINYUSB_NO_DEFAULT_TASK=y
|
||||
CONFIG_TINYUSB_INIT_IN_DEFAULT_TASK=n
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_app_teardown_device)
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
_ _ _
|
||||
| | (_) | |
|
||||
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
|
||||
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
|
||||
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
|
||||
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
|
||||
| |______ __/ |
|
||||
|_|______| |___/
|
||||
_____ _____ _____ _____
|
||||
|_ _| ___/ ___|_ _|
|
||||
| | | |__ \ `--. | |
|
||||
| | | __| `--. \ | |
|
||||
| | | |___/\__/ / | |
|
||||
\_/ \____/\____/ \_/
|
||||
*/
|
||||
|
||||
printf(" _ _ _ \n");
|
||||
printf(" | | (_) | | \n");
|
||||
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
|
||||
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
|
||||
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
|
||||
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
|
||||
printf(" | |______ __/ | \n");
|
||||
printf(" |_|______| |___/ \n");
|
||||
printf(" _____ _____ _____ _____ \n");
|
||||
printf("|_ _| ___/ ___|_ _| \n");
|
||||
printf(" | | | |__ \\ `--. | | \n");
|
||||
printf(" | | | __| `--. \\ | | \n");
|
||||
printf(" | | | |___/\\__/ / | | \n");
|
||||
printf(" \\_/ \\____/\\____/ \\_/ \n");
|
||||
|
||||
unity_utils_setup_heap_record(80);
|
||||
unity_utils_set_leak_level(128);
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
/* setUp runs before every test */
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
/* tearDown runs after every test */
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks();
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
//
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
//
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
//
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_cdc_acm.h"
|
||||
|
||||
static const char *TAG = "teardown";
|
||||
|
||||
SemaphoreHandle_t wait_mount = NULL;
|
||||
|
||||
#define TEARDOWN_DEVICE_INIT_DELAY_MS 1000
|
||||
#define TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS 1000
|
||||
#define TEARDOWN_DEVICE_DETACH_DELAY_MS 1000
|
||||
|
||||
#define TEARDOWN_AMOUNT 10
|
||||
|
||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN)
|
||||
static uint8_t const test_configuration_descriptor[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
static const tusb_desc_device_t test_device_descriptor = {
|
||||
.bLength = sizeof(test_device_descriptor),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers
|
||||
.idProduct = 0x4002,
|
||||
.bcdDevice = 0x100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
static const tusb_desc_device_qualifier_t device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0
|
||||
};
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
xSemaphoreGive(wait_mount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Teardown specific testcase
|
||||
*
|
||||
* Scenario:
|
||||
* 1. Install TinyUSB device without any class
|
||||
* 2. Wait SetConfiguration() (tud_mount_cb)
|
||||
* 3. If attempts == 0 goto step 8
|
||||
* 4. Wait TEARDOWN_DEVICE_DETACH_DELAY_MS
|
||||
* 5. Uninstall TinyUSB device
|
||||
* 6. Wait TEARDOWN_DEVICE_INIT_DELAY_MS
|
||||
* 7. Decrease attempts by 1, goto step 3
|
||||
* 8. Wait TEARDOWN_DEVICE_DETACH_DELAY_MS
|
||||
* 9. Uninstall TinyUSB device
|
||||
*/
|
||||
TEST_CASE("tinyusb_teardown", "[esp_tinyusb][teardown]")
|
||||
{
|
||||
wait_mount = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, wait_mount);
|
||||
|
||||
// TinyUSB driver configuration
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = &test_device_descriptor,
|
||||
.string_descriptor = NULL,
|
||||
.string_descriptor_count = 0,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = test_configuration_descriptor,
|
||||
.hs_configuration_descriptor = test_configuration_descriptor,
|
||||
.qualifier_descriptor = &device_qualifier,
|
||||
#else
|
||||
.configuration_descriptor = test_configuration_descriptor,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
|
||||
// Teardown routine
|
||||
int attempts = TEARDOWN_AMOUNT;
|
||||
while (attempts--) {
|
||||
// Keep device attached
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DETACH_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_INIT_DELAY_MS));
|
||||
// Reconnect
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
// Wait for the usb event
|
||||
ESP_LOGD(TAG, "wait mount...");
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(wait_mount, pdMS_TO_TICKS(TEARDOWN_DEVICE_ATTACH_TIMEOUT_MS)));
|
||||
ESP_LOGD(TAG, "mounted");
|
||||
}
|
||||
|
||||
// Teardown
|
||||
vTaskDelay(pdMS_TO_TICKS(TEARDOWN_DEVICE_DETACH_DELAY_MS));
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_uninstall());
|
||||
// Remove primitives
|
||||
vSemaphoreDelete(wait_mount);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
import subprocess
|
||||
from time import sleep, time
|
||||
|
||||
class DeviceNotFoundError(Exception):
|
||||
"""Custom exception for device not found within the timeout period."""
|
||||
pass
|
||||
|
||||
def tusb_dev_in_list(vid, pid):
|
||||
try:
|
||||
output = subprocess.check_output(["lsusb"], text=True)
|
||||
search_string = f"{vid}:{pid}"
|
||||
return search_string in output
|
||||
except Exception as e:
|
||||
print(f"Error while executing lsusb: {e}")
|
||||
raise
|
||||
|
||||
def wait_tusb_dev_appeared(vid, pid, timeout):
|
||||
start_time = time()
|
||||
while True:
|
||||
if tusb_dev_in_list(vid, pid):
|
||||
return True
|
||||
if time() - start_time > timeout:
|
||||
raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} not found within {timeout} seconds.")
|
||||
sleep(0.5)
|
||||
|
||||
def wait_tusb_dev_removed(vid, pid, timeout):
|
||||
start_time = time()
|
||||
while True:
|
||||
if not tusb_dev_in_list(vid, pid):
|
||||
return True
|
||||
if time() - start_time > timeout:
|
||||
raise DeviceNotFoundError(f"Device with VID: 0x{vid:04x}, PID: 0x{pid:04x} wasn't removed within {timeout} seconds.")
|
||||
sleep(0.5)
|
||||
|
||||
def tusb_device_teardown(iterations, timeout):
|
||||
TUSB_VID = "303a" # Espressif TinyUSB VID
|
||||
TUSB_PID = "4002" # Espressif TinyUSB VID
|
||||
|
||||
for i in range(iterations):
|
||||
# Wait until the device is present
|
||||
print(f"Waiting for device ...")
|
||||
wait_tusb_dev_appeared(TUSB_VID, TUSB_PID, timeout)
|
||||
print("Device detected.")
|
||||
|
||||
# Wait until the device is removed
|
||||
print("Waiting for the device to be removed...")
|
||||
wait_tusb_dev_removed(TUSB_VID, TUSB_PID, timeout)
|
||||
print("Device removed.")
|
||||
print("Monitoring completed.")
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.usb_device
|
||||
def test_usb_teardown_device(dut: IdfDut) -> None:
|
||||
dut.expect_exact('Press ENTER to see the list of tests.')
|
||||
dut.write('[teardown]')
|
||||
dut.expect_exact('TinyUSB: TinyUSB Driver installed')
|
||||
sleep(2) # Some time for the OS to enumerate our USB device
|
||||
|
||||
try:
|
||||
tusb_device_teardown(10, 10) # Teardown tusb device: amount, timeout
|
||||
|
||||
except DeviceNotFoundError as e:
|
||||
print(f"Error: {e}")
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
raise
|
||||
@@ -0,0 +1,16 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_CDC_ENABLED=y
|
||||
CONFIG_TINYUSB_CDC_COUNT=1
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
9
managed_components/espressif__esp_tinyusb/test_apps/vendor/CMakeLists.txt
vendored
Normal file
9
managed_components/espressif__esp_tinyusb/test_apps/vendor/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_app_vendor_specific)
|
||||
4
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/CMakeLists.txt
vendored
Normal file
4
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRC_DIRS .
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
5
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/idf_component.yml
vendored
Normal file
5
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/idf_component.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
48
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/test_app_main.c
vendored
Normal file
48
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/test_app_main.c
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
_ _ _
|
||||
| | (_) | |
|
||||
___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__
|
||||
/ _ \/ __| '_ \| __| | '_ \| | | | | | / __| '_ \
|
||||
| __/\__ \ |_) | |_| | | | | |_| | |_| \__ \ |_) |
|
||||
\___||___/ .__/ \__|_|_| |_|\__, |\__,_|___/_.__/
|
||||
| |______ __/ |
|
||||
|_|______| |___/
|
||||
_____ _____ _____ _____
|
||||
|_ _| ___/ ___|_ _|
|
||||
| | | |__ \ `--. | |
|
||||
| | | __| `--. \ | |
|
||||
| | | |___/\__/ / | |
|
||||
\_/ \____/\____/ \_/
|
||||
*/
|
||||
|
||||
printf(" _ _ _ \n");
|
||||
printf(" | | (_) | | \n");
|
||||
printf(" ___ ___ _ __ | |_ _ _ __ _ _ _ _ ___| |__ \n");
|
||||
printf(" / _ \\/ __| '_ \\| __| | '_ \\| | | | | | / __| '_ \\ \n");
|
||||
printf("| __/\\__ \\ |_) | |_| | | | | |_| | |_| \\__ \\ |_) |\n");
|
||||
printf(" \\___||___/ .__/ \\__|_|_| |_|\\__, |\\__,_|___/_.__/ \n");
|
||||
printf(" | |______ __/ | \n");
|
||||
printf(" |_|______| |___/ \n");
|
||||
printf(" _____ _____ _____ _____ \n");
|
||||
printf("|_ _| ___/ ___|_ _| \n");
|
||||
printf(" | | | |__ \\ `--. | | \n");
|
||||
printf(" | | | __| `--. \\ | | \n");
|
||||
printf(" | | | |___/\\__/ / | | \n");
|
||||
printf(" \\_/ \\____/\\____/ \\_/ \n");
|
||||
|
||||
// We don't check memory leaks here because we cannot uninstall TinyUSB yet
|
||||
unity_run_menu();
|
||||
}
|
||||
71
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/test_vendor.c
vendored
Normal file
71
managed_components/espressif__esp_tinyusb/test_apps/vendor/main/test_vendor.c
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "unity.h"
|
||||
#include "tinyusb.h"
|
||||
|
||||
static const char *TAG = "vendor_test";
|
||||
|
||||
char buffer_in[64];
|
||||
#if (TUSB_VERSION_MINOR >= 17)
|
||||
void tud_vendor_rx_cb(uint8_t itf, uint8_t const *buffer, uint16_t bufsize)
|
||||
#else
|
||||
void tud_vendor_rx_cb(uint8_t itf)
|
||||
#endif // TUSB_VERSION_MINOR
|
||||
{
|
||||
ESP_LOGI(TAG, "tud_vendor_rx_cb(itf=%d)", itf);
|
||||
int available = tud_vendor_n_available(itf);
|
||||
int read = tud_vendor_n_read(itf, buffer_in, available);
|
||||
ESP_LOGI(TAG, "actual read: %d. buffer message: %s", read, buffer_in);
|
||||
}
|
||||
|
||||
// Invoked when a control transfer occurred on an interface of this class
|
||||
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
|
||||
{
|
||||
// nothing to with DATA & ACK stage
|
||||
if (stage != CONTROL_STAGE_SETUP) {
|
||||
return true;
|
||||
}
|
||||
// stall unknown request
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TinyUSB Vendor specific testcase
|
||||
*/
|
||||
TEST_CASE("tinyusb_vendor", "[esp_tinyusb][vendor]")
|
||||
{
|
||||
// Install TinyUSB driver
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false,
|
||||
.device_descriptor = NULL,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = NULL,
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = NULL,
|
||||
#else
|
||||
.configuration_descriptor = NULL,
|
||||
#endif // TUD_OPT_HIGH_SPEED
|
||||
};
|
||||
TEST_ASSERT_EQUAL(ESP_OK, tinyusb_driver_install(&tusb_cfg));
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
96
managed_components/espressif__esp_tinyusb/test_apps/vendor/pytest_vendor.py
vendored
Normal file
96
managed_components/espressif__esp_tinyusb/test_apps/vendor/pytest_vendor.py
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
import usb.core
|
||||
import usb.util
|
||||
from time import sleep
|
||||
|
||||
|
||||
def find_interface_by_index(device, interface_index):
|
||||
'''
|
||||
Function to find the interface by index
|
||||
'''
|
||||
for cfg in device:
|
||||
for intf in cfg:
|
||||
if intf.bInterfaceNumber == interface_index:
|
||||
return intf
|
||||
return None
|
||||
|
||||
|
||||
def send_data_to_intf(VID, PID, interface_index):
|
||||
'''
|
||||
Find a device, its interface and dual BULK endpoints
|
||||
Send some data to it
|
||||
'''
|
||||
# Find the USB device by VID and PID
|
||||
dev = usb.core.find(idVendor=VID, idProduct=PID)
|
||||
if dev is None:
|
||||
raise ValueError("Device not found")
|
||||
|
||||
# Find the interface by index
|
||||
intf = find_interface_by_index(dev, interface_index)
|
||||
if intf is None:
|
||||
raise ValueError(f"Interface with index {interface_index} not found")
|
||||
|
||||
if intf:
|
||||
def ep_read(len):
|
||||
try:
|
||||
return ep_in.read(len, 100)
|
||||
except:
|
||||
return None
|
||||
def ep_write(buf):
|
||||
try:
|
||||
ep_out.write(buf, 100)
|
||||
except:
|
||||
pass
|
||||
|
||||
maximum_packet_size = 64
|
||||
|
||||
ep_in = usb.util.find_descriptor(intf, custom_match = \
|
||||
lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)
|
||||
|
||||
ep_out = usb.util.find_descriptor(intf, custom_match = \
|
||||
lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
|
||||
|
||||
#print(ep_in)
|
||||
#print(ep_out)
|
||||
buf = "IF{}\n".format(interface_index).encode('utf-8')
|
||||
ep_write(bytes(buf))
|
||||
|
||||
ep_read(maximum_packet_size)
|
||||
else:
|
||||
print("NOT found")
|
||||
|
||||
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32p4
|
||||
#@pytest.mark.usb_device Disable in CI, for now, not possible to run this test in Docker container
|
||||
def test_usb_device_vendor(dut: IdfDut) -> None:
|
||||
'''
|
||||
Running the test locally:
|
||||
1. Build the test app for your DUT
|
||||
2. Connect you DUT to your test runner (local machine) with USB port and flashing port
|
||||
3. Run `pytest --target esp32s3`
|
||||
|
||||
Important note: On Windows you must manually assign a driver the device, otherwise it will never be configured.
|
||||
On Linux this is automatic
|
||||
|
||||
Test procedure:
|
||||
1. Run the test on the DUT
|
||||
2. Expect 2 Vendor specific interfaces in the system
|
||||
3. Send some data to it, check log output
|
||||
'''
|
||||
dut.run_all_single_board_cases(group='vendor')
|
||||
|
||||
sleep(2) # Wait until the device is enumerated
|
||||
|
||||
VID = 0x303A # Replace with your device's Vendor ID
|
||||
PID = 0x4040 # Replace with your device's Product ID
|
||||
|
||||
send_data_to_intf(VID, PID, 0)
|
||||
dut.expect_exact('vendor_test: actual read: 4. buffer message: IF0')
|
||||
send_data_to_intf(VID, PID, 1)
|
||||
dut.expect_exact('vendor_test: actual read: 4. buffer message: IF1')
|
||||
15
managed_components/espressif__esp_tinyusb/test_apps/vendor/sdkconfig.defaults
vendored
Normal file
15
managed_components/espressif__esp_tinyusb/test_apps/vendor/sdkconfig.defaults
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Configure TinyUSB, it will be used to mock USB devices
|
||||
CONFIG_TINYUSB_VENDOR_COUNT=2
|
||||
|
||||
# Disable watchdogs, they'd get triggered during unity interactive menu
|
||||
CONFIG_ESP_INT_WDT=n
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
# Run-time checks of Heap and Stack
|
||||
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
112
managed_components/espressif__esp_tinyusb/tinyusb.c
Normal file
112
managed_components/espressif__esp_tinyusb/tinyusb.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_private/usb_phy.h"
|
||||
#include "tinyusb.h"
|
||||
#include "descriptors_control.h"
|
||||
#include "tusb.h"
|
||||
#include "tusb_tasks.h"
|
||||
|
||||
const static char *TAG = "TinyUSB";
|
||||
static usb_phy_handle_t phy_hdl;
|
||||
|
||||
// For the tinyusb component without tusb_teardown() implementation
|
||||
#ifndef tusb_teardown
|
||||
# define tusb_teardown() (true)
|
||||
#endif // tusb_teardown
|
||||
|
||||
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "Config can't be NULL");
|
||||
|
||||
// Configure USB PHY
|
||||
usb_phy_config_t phy_conf = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
.otg_mode = USB_OTG_MODE_DEVICE,
|
||||
#if (USB_PHY_SUPPORTS_P4_OTG11)
|
||||
.otg_speed = (TUD_OPT_HIGH_SPEED) ? USB_PHY_SPEED_HIGH : USB_PHY_SPEED_FULL,
|
||||
#else
|
||||
#if (CONFIG_IDF_TARGET_ESP32P4 && CONFIG_TINYUSB_RHPORT_FS)
|
||||
#error "USB PHY for OTG1.1 is not supported, please update your esp-idf."
|
||||
#endif // IDF_TARGET_ESP32P4 && CONFIG_TINYUSB_RHPORT_FS
|
||||
#endif // USB_PHY_SUPPORTS_P4_OTG11
|
||||
};
|
||||
|
||||
/*
|
||||
Following ext. PHY IO configuration is here to provide compatibility with IDFv5.x releases,
|
||||
where ext. PHY IOs were mapped to predefined GPIOs.
|
||||
In reality, ESP32-S2 and ESP32-S3 can map ext. PHY IOs to any GPIOs.
|
||||
This option is implemented in esp_tinyusb v2.0.0 and later.
|
||||
*/
|
||||
usb_phy_ext_io_conf_t ext_io_conf;
|
||||
// Use memset to be compatible with IDF < 5.4.1 where suspend_n_io_num and fs_edge_sel_io_num were added
|
||||
memset(&ext_io_conf, -1, sizeof(usb_phy_ext_io_conf_t));
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
ext_io_conf.vp_io_num = 33;
|
||||
ext_io_conf.vm_io_num = 34;
|
||||
ext_io_conf.rcv_io_num = 35;
|
||||
ext_io_conf.oen_io_num = 36;
|
||||
ext_io_conf.vpo_io_num = 37;
|
||||
ext_io_conf.vmo_io_num = 38;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
ext_io_conf.vp_io_num = 42;
|
||||
ext_io_conf.vm_io_num = 41;
|
||||
ext_io_conf.rcv_io_num = 21;
|
||||
ext_io_conf.oen_io_num = 40;
|
||||
ext_io_conf.vpo_io_num = 39;
|
||||
ext_io_conf.vmo_io_num = 38;
|
||||
#endif // IDF_TARGET_ESP32S3
|
||||
|
||||
if (config->external_phy) {
|
||||
phy_conf.target = USB_PHY_TARGET_EXT;
|
||||
phy_conf.ext_io_conf = &ext_io_conf;
|
||||
|
||||
/*
|
||||
There is a bug in esp-idf that does not allow device speed selection
|
||||
when External PHY is used.
|
||||
Remove this when proper fix is implemented in IDF-11144
|
||||
*/
|
||||
phy_conf.otg_speed = USB_PHY_SPEED_UNDEFINED;
|
||||
} else {
|
||||
phy_conf.target = USB_PHY_TARGET_INT;
|
||||
}
|
||||
|
||||
// OTG IOs config
|
||||
const usb_phy_otg_io_conf_t otg_io_conf = USB_PHY_SELF_POWERED_DEVICE(config->vbus_monitor_io);
|
||||
if (config->self_powered) {
|
||||
phy_conf.otg_io_conf = &otg_io_conf;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(usb_new_phy(&phy_conf, &phy_hdl), TAG, "Install USB PHY failed");
|
||||
|
||||
// Descriptors config
|
||||
ESP_RETURN_ON_ERROR(tinyusb_set_descriptors(config), TAG, "Descriptors config failed");
|
||||
|
||||
// Init
|
||||
#if !CONFIG_TINYUSB_INIT_IN_DEFAULT_TASK
|
||||
ESP_RETURN_ON_FALSE(tusb_init(), ESP_FAIL, TAG, "Init TinyUSB stack failed");
|
||||
#endif
|
||||
#if !CONFIG_TINYUSB_NO_DEFAULT_TASK
|
||||
ESP_RETURN_ON_ERROR(tusb_run_task(), TAG, "Run TinyUSB task failed");
|
||||
#endif
|
||||
ESP_LOGI(TAG, "TinyUSB Driver installed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t tinyusb_driver_uninstall(void)
|
||||
{
|
||||
#if !CONFIG_TINYUSB_NO_DEFAULT_TASK
|
||||
ESP_RETURN_ON_ERROR(tusb_stop_task(), TAG, "Unable to stop TinyUSB task");
|
||||
#endif // !CONFIG_TINYUSB_NO_DEFAULT_TASK
|
||||
ESP_RETURN_ON_FALSE(tusb_teardown(), ESP_ERR_NOT_FINISHED, TAG, "Unable to teardown TinyUSB");
|
||||
tinyusb_free_descriptors();
|
||||
ESP_RETURN_ON_ERROR(usb_del_phy(phy_hdl), TAG, "Unable to delete PHY");
|
||||
return ESP_OK;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user