From 61acee411794a78c760afe07a8ae4ffc9b44fe7b Mon Sep 17 00:00:00 2001 From: Serge Bazanski <q3k@q3k.org> Date: Tue, 11 Jul 2023 20:56:00 +0200 Subject: [PATCH] st3m: add usb stack (unused) This implements a st3m-specific USB stack. It's effectively what espressif provides with their esp_tinyusb component, but allows for dynamic reconfiguration of the USB device. --- components/st3m/CMakeLists.txt | 9 ++ components/st3m/st3m_usb.c | 139 ++++++++++++++++++++ components/st3m/st3m_usb.h | 125 ++++++++++++++++++ components/st3m/st3m_usb_cdc.c | 76 +++++++++++ components/st3m/st3m_usb_descriptors.c | 170 +++++++++++++++++++++++++ components/st3m/st3m_usb_msc.c | 122 ++++++++++++++++++ components/st3m/tusb_config.h | 31 +++++ 7 files changed, 672 insertions(+) create mode 100644 components/st3m/st3m_usb.c create mode 100644 components/st3m/st3m_usb.h create mode 100644 components/st3m/st3m_usb_cdc.c create mode 100644 components/st3m/st3m_usb_descriptors.c create mode 100644 components/st3m/st3m_usb_msc.c create mode 100644 components/st3m/tusb_config.h diff --git a/components/st3m/CMakeLists.txt b/components/st3m/CMakeLists.txt index 0dfdc6969d..1b71759191 100644 --- a/components/st3m/CMakeLists.txt +++ b/components/st3m/CMakeLists.txt @@ -9,6 +9,10 @@ idf_component_register( st3m_leds.c st3m_colors.c st3m_io.c + st3m_usb_cdc.c + st3m_usb_descriptors.c + st3m_usb_msc.c + st3m_usb.c INCLUDE_DIRS . REQUIRES @@ -16,4 +20,9 @@ idf_component_register( bl00mbox ctx fatfs + tinyusb + usb ) + +idf_component_get_property(tusb_lib tinyusb COMPONENT_LIB) +target_include_directories(${tusb_lib} PRIVATE .) \ No newline at end of file diff --git a/components/st3m/st3m_usb.c b/components/st3m/st3m_usb.c new file mode 100644 index 0000000000..04c13e5c7b --- /dev/null +++ b/components/st3m/st3m_usb.c @@ -0,0 +1,139 @@ +#include "st3m_usb.h" + +static const char *TAG = "st3m-usb"; + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +#include "esp_log.h" +#include "esp_mac.h" +#include "esp_private/usb_phy.h" +#include "tusb.h" + +static SemaphoreHandle_t _mu = NULL; +static st3m_usb_mode_kind_t _mode = st3m_usb_mode_kind_disabled; +static usb_phy_handle_t phy_hdl; +static bool _connected = false; + +static void _usb_task(void *_arg) { + (void)_arg; + while (true) { + tud_task_ext(10, false); + + xSemaphoreTake(_mu, portMAX_DELAY); + st3m_usb_mode_kind_t mode = _mode; + xSemaphoreGive(_mu); + + if (mode == st3m_usb_mode_kind_app) { + st3m_usb_cdc_txpoll(); + } + } +} + +// Generate USB serial from on-board chip ID / MAC. +static void _generate_serial(void) { + uint8_t mac[6]; + memset(mac, 0, 6); + // Ignore error. Worst case we get zeroes. + esp_read_mac(mac, ESP_MAC_WIFI_STA); + + char serial[13]; + snprintf(serial, 13, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + st3m_usb_descriptors_set_serial(serial); +} + +void st3m_usb_init(void) { + assert(_mu == NULL); + _mu = xSemaphoreCreateMutex(); + assert(_mu != NULL); + + _generate_serial(); + st3m_usb_cdc_init(); + usb_phy_config_t phy_conf = { + .controller = USB_PHY_CTRL_OTG, + .otg_mode = USB_OTG_MODE_DEVICE, + .target = USB_PHY_TARGET_INT, + }; + // TODO(q3k): set self-powered based on battery state? + ESP_ERROR_CHECK(usb_new_phy(&phy_conf, &phy_hdl)); + + if (!tusb_init()) { + ESP_LOGE(TAG, "TInyUSB init failed"); + assert(false); + } + + xTaskCreate(_usb_task, "usb", 4096, NULL, 5, NULL); + ESP_LOGI(TAG, "USB stack started"); +} + +void st3m_usb_mode_switch(st3m_usb_mode_t *mode) { + xSemaphoreTake(_mu, portMAX_DELAY); + + bool running = false; + switch (_mode) { + case st3m_usb_mode_kind_app: + case st3m_usb_mode_kind_disk: + running = true; + default: + } + + bool should_run = false; + switch (mode->kind) { + case st3m_usb_mode_kind_app: + case st3m_usb_mode_kind_disk: + should_run = true; + default: + } + + if (running) { + ESP_LOGI(TAG, "stopping and disconnecting"); + usb_phy_action(phy_hdl, USB_PHY_ACTION_HOST_FORCE_DISCONN); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + + st3m_usb_descriptors_switch(mode); + if (mode->kind == st3m_usb_mode_kind_disk) { + assert(mode->disk != NULL); + st3m_usb_msc_set_conf(mode->disk); + } + if (mode->kind == st3m_usb_mode_kind_app) { + assert(mode->app != NULL); + st3m_usb_cdc_set_conf(mode->app); + } + + if (should_run) { + ESP_LOGI(TAG, "reconnecting and starting"); + usb_phy_action(phy_hdl, USB_PHY_ACTION_HOST_ALLOW_CONN); + } + + _mode = mode->kind; + _connected = false; + xSemaphoreGive(_mu); +} + +bool st3m_usb_connected(void) { + xSemaphoreTake(_mu, portMAX_DELAY); + bool res = _connected; + xSemaphoreGive(_mu); + return res; +} + +void tud_mount_cb(void) { + ESP_LOGI(TAG, "USB attached"); + xSemaphoreTake(_mu, portMAX_DELAY); + _connected = true; + xSemaphoreGive(_mu); +} + +void tud_suspend_cb(bool remote_wakeup_en) { + ESP_LOGI(TAG, "USB detached"); + + xSemaphoreTake(_mu, portMAX_DELAY); + st3m_usb_mode_kind_t mode = _mode; + _connected = false; + xSemaphoreGive(_mu); + if (mode == st3m_usb_mode_kind_app) { + st3m_usb_cdc_detached(); + } +} \ No newline at end of file diff --git a/components/st3m/st3m_usb.h b/components/st3m/st3m_usb.h new file mode 100644 index 0000000000..a13f7e41e3 --- /dev/null +++ b/components/st3m/st3m_usb.h @@ -0,0 +1,125 @@ +#pragma once + +// USB support for st3m, via the USB-OTG peripheral (not USB UART/JTAG!). +// +// USB is a complex beast. Attempting to make user-friendly wrappers that are +// also general-purpose is a waste of time. +// +// What we do instead is provide a limited feature set for USB. A device is in +// one of either three modes, and these modes can be switch at runtime: +// 1. Disabled, +// 2. Application, or +// 3. Disk. +// +// Disabled mode makes the device appear as if it was just a passive charging +// device. It does not appear on any host device if plugged in. This is the +// default mode until the stack fully initializes. Then, the device switches +// to application mode. +// +// Application mode is where the device spends most of its time. If plugged in, +// it will enumerate as a `flow3r` and expose a CDC-ACM (serial) endpoint which +// hosts the Micropython console. In the future more USB endpoints will appear +// here: USB MIDI, for example. +// +// Device mode can be requested by software. If the device is plugged into a +// host, it will enumerate as a USB mass storage device that can be written and +// read from. +// +// Note that this codebase does not implement any of the logic behind any +// endpoint (like CDC-ACM or MSC). Instead it just provides a callback-base +// interface that is activated by switching to a mode configuration which +// collects these callbacks. Higher level layers implement the rest of the +// stack, like USB console for Micropython or flash/SD card mounting. +// +// The current API design assumes there is only one kind of each endpoint in +// each mode, and thus things are a bit simplistic. This might change in the +// future. + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> + +typedef enum { + // Device should not enumerate. + st3m_usb_mode_kind_disabled = 0, + // Device should appear as a 'flow3er' with a CDC-ACM (serial) endpoint. + st3m_usb_mode_kind_app = 1, + // Device should appear as a 'flower (disk mode)' with a MSC (mass storage) + // endpoint. + st3m_usb_mode_kind_disk = 2, +} st3m_usb_mode_kind_t; + +// Description of the device in disk mode. +typedef struct { + // Number of blocks. + size_t block_size; + // Size of each block (usually 512 bytes). + size_t block_count; + // Product ID, padded with zeroes. + uint8_t product_id[16]; + + // Optional. Called whenever the host asks if the device is ready. Defaults to always ready. + bool (*fn_ready)(uint8_t lun); + // Optional. Called whenever the hosts executes a scsi start/stop. Defaults to 'yeah sure' stub. + bool (*fn_start_stop)(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); + // Required. Called when the host wishes to read from an LBA/offset. Address + // = lba*block_size+offset. Must return however many bytes were actually + // read. + int32_t (*fn_read10)(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); + // Optional. Called when the host wishes to write to an LBA/offset. Defaults + // to ignoring writes. + int32_t (*fn_write10)(uint8_t lun, uint32_t lba, uint32_t offset, const void* buffer, uint32_t bufsize); +} st3m_usb_msc_conf_t; + +// Description of the device in application mode. +typedef struct { + // Required. Called whenever the host wrote some bytes. All bytes must be + // processed. + void (*fn_rx)(uint8_t *buffer, size_t bufsize); + // Required. Called whenever the host requests bytes to read. Must return + // how many bytes are actually available to transmit to the host. + size_t (*fn_txpoll)(uint8_t *buffer, size_t bufsize); + // Optional. Called whenever the host has detached from the device. + size_t (*fn_detach)(void); +} st3m_usb_app_conf_t; + +// Main configuration structure, passed by pointer to st3m_usb_mode_switch. +// Describes a requested configuration mode of the USB subsystem. +typedef struct { + st3m_usb_mode_kind_t kind; + + // Only valid if kind == disk. + st3m_usb_msc_conf_t *disk; + // Only valid if kind == app. + st3m_usb_app_conf_t *app; +} st3m_usb_mode_t; + + +// Immediately switch to a given mode, blocking until that mode is active. A +// mode being active does not indicate that the device is connected to a host. +void st3m_usb_mode_switch(st3m_usb_mode_t *target); + +// Initialize the subsystem. Must be called, bad things will happen otherwise. +void st3m_usb_init(); + +// Return true if the badge is connected to a host. +bool st3m_usb_connected(void); + +// Private. +void st3m_usb_descriptors_switch(st3m_usb_mode_t *mode); +void st3m_usb_msc_set_conf(st3m_usb_msc_conf_t *conf); +void st3m_usb_cdc_set_conf(st3m_usb_app_conf_t *conf); +void st3m_usb_descriptors_set_serial(const char *serial); +void st3m_usb_cdc_init(void); +void st3m_usb_cdc_txpoll(void); +void st3m_usb_cdc_detached(void); + +typedef enum { + st3m_usb_interface_disk_msc, + st3m_usb_interface_disk_total, +} st3m_usb_interface_disk_t; + +typedef enum { + st3m_usb_interface_app_cdc, + st3m_usb_interface_app_total, +} st3m_usb_interface_app_t; diff --git a/components/st3m/st3m_usb_cdc.c b/components/st3m/st3m_usb_cdc.c new file mode 100644 index 0000000000..6773d0a67b --- /dev/null +++ b/components/st3m/st3m_usb_cdc.c @@ -0,0 +1,76 @@ +#include "st3m_usb.h" + +#include "tusb.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +#include "esp_log.h" + +static const char *TAG = "st3m-usb-cdc"; + +static st3m_usb_app_conf_t _conf = { 0 }; +static SemaphoreHandle_t _write_mu; + +void st3m_usb_cdc_init(void) { + _write_mu = xSemaphoreCreateMutex(); +} + +void st3m_usb_cdc_set_conf(st3m_usb_app_conf_t *conf) { + assert(conf->fn_rx != NULL); + assert(conf->fn_txpoll != NULL); + memcpy(&_conf, conf, sizeof(_conf)); +} + +static st3m_usb_app_conf_t *_get_conf(void) { + assert(_conf.fn_rx != NULL); + assert(_conf.fn_txpoll != NULL); + return &_conf; +} + +#define CDC_RX_BUFSIZE 64 +// TinyUSB callback: when host sent data over OUT endpoint. +void tud_cdc_rx_cb(uint8_t itf) { + st3m_usb_app_conf_t *conf = _get_conf(); + + uint8_t buf[CDC_RX_BUFSIZE]; + while (tud_cdc_n_available(itf)) { + int read_res = tud_cdc_n_read(itf, buf, CDC_RX_BUFSIZE); + conf->fn_rx(buf, read_res); + } +} + +#define CDC_TX_BUFSIZE 64 +void st3m_usb_cdc_txpoll(void) { + st3m_usb_app_conf_t *conf = _get_conf(); + if (conf->fn_txpoll == NULL) { + return; + } + + for (;;) { + uint32_t space = tud_cdc_n_write_available(st3m_usb_interface_app_cdc); + if (space == 0) { + return; + } + + uint8_t buf[CDC_TX_BUFSIZE]; + if (space > CDC_TX_BUFSIZE) { + space = CDC_TX_BUFSIZE; + } + + size_t to_write = conf->fn_txpoll(buf, space); + if (to_write == 0) { + return; + } + tud_cdc_n_write(st3m_usb_interface_app_cdc, buf, to_write); + tud_cdc_n_write_flush(st3m_usb_interface_app_cdc); + } +} + +void st3m_usb_cdc_detached(void) { + st3m_usb_app_conf_t *conf = _get_conf(); + if (conf->fn_detach == NULL) { + return; + } + conf->fn_detach(); +} \ No newline at end of file diff --git a/components/st3m/st3m_usb_descriptors.c b/components/st3m/st3m_usb_descriptors.c new file mode 100644 index 0000000000..983405f071 --- /dev/null +++ b/components/st3m/st3m_usb_descriptors.c @@ -0,0 +1,170 @@ +#include "st3m_usb.h" + +#include "tusb.h" +#include "esp_log.h" + +static const char *TAG = "st3m-usb-descs"; + +static const char * const _manufacturer = "flow3r.garden"; +static const char * const _product_app = "flow3r"; +static const char * const _product_disk = "flow3r (disk mode)"; +static const char * const _cdc_repl = "MicroPython REPL"; +static char _serial[32+1] = {0}; + +typedef struct { + const tusb_desc_device_t dev; + const uint8_t *cfg; + size_t num_str; + const char *str[16]; +} st3m_usb_descriptor_set_t; + +static const uint32_t st3m_usb_configdesc_len_app = TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN; + +#define EPNUM_CDC_0_NOTIF 0x81 +#define EPNUM_CDC_0_OUT 0x02 +#define EPNUM_CDC_0_IN 0x82 + +static uint8_t _cfg_desc_app[] = { + TUD_CONFIG_DESCRIPTOR(1, st3m_usb_interface_app_total, 0, st3m_usb_configdesc_len_app, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_CDC_DESCRIPTOR(st3m_usb_interface_app_cdc, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64), +}; + +static st3m_usb_descriptor_set_t _descset_app = { + .dev = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = 0x303a, + .idProduct = 0x4042, + + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01, + }, + .cfg = _cfg_desc_app, + .num_str = 5, + .str = { + (char[]){0x09, 0x04}, // EN + _manufacturer, + _product_app, + _serial, + _cdc_repl, + }, +}; + +static const uint32_t st3m_usb_configdesc_len_disk = TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN; + + // Use separate endpoint numbers otherwise TinyUSB seems to get very confused... + #define EPNUM_1_MSC_OUT 0x03 + #define EPNUM_1_MSC_IN 0x83 + +static uint8_t _cfg_desc_disk[] = { + TUD_CONFIG_DESCRIPTOR(1, st3m_usb_interface_disk_total, 0, st3m_usb_configdesc_len_disk, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_MSC_DESCRIPTOR(st3m_usb_interface_disk_msc, 0, EPNUM_1_MSC_OUT, EPNUM_1_MSC_IN, 64), +}; + +static st3m_usb_descriptor_set_t _descset_disk = { + .dev = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = 0x303a, + .idProduct = 0x4023, + + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01, + }, + .cfg = _cfg_desc_disk, + .num_str = 4, + .str = { + (char[]){0x09, 0x04}, // EN + _manufacturer, + _product_disk, + _serial, + }, +}; + +static st3m_usb_descriptor_set_t *_descset_current = &_descset_app; + +uint8_t const *tud_descriptor_device_cb(void) { + return (uint8_t const *)&_descset_current->dev; +} + +uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { + return _descset_current->cfg; +} + +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 + uint8_t chr_count; + static uint16_t _desc_str[64]; + + const char **descs = _descset_current->str; + + if (index == 0) { + memcpy(&_desc_str[1], descs[0], 2); + chr_count = 1; + } else { + if (index >= _descset_current->num_str) { + ESP_LOGW(TAG, "String index (%u) is out of bounds, check your string descriptor", index); + return NULL; + } + + if (descs[index] == NULL) { + ESP_LOGW(TAG, "String index (%u) points to NULL, check your string descriptor", index); + return NULL; + } + + const char *str = descs[index]; + chr_count = strnlen(str, 63); // 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; +} + +void st3m_usb_descriptors_switch(st3m_usb_mode_t *mode) { + switch (mode->kind) { + case st3m_usb_mode_kind_app: + _descset_current = &_descset_app; + break; + case st3m_usb_mode_kind_disk: + _descset_current = &_descset_disk; + break; + default: + } +} + +void st3m_usb_descriptors_set_serial(const char *serial) { + memset(_serial, 0, 33); + strncpy(_serial, serial, 32); +} \ No newline at end of file diff --git a/components/st3m/st3m_usb_msc.c b/components/st3m/st3m_usb_msc.c new file mode 100644 index 0000000000..3d84e6d73b --- /dev/null +++ b/components/st3m/st3m_usb_msc.c @@ -0,0 +1,122 @@ +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include "st3m_usb.h" + +#include "tusb.h" +#include "esp_log.h" + +static const char *TAG = "st3m-usb-msc"; + +static st3m_usb_msc_conf_t _conf = { 0 }; + +void st3m_usb_msc_set_conf(st3m_usb_msc_conf_t *conf) { + assert(conf->block_count != 0); + assert(conf->block_size != 0); + assert(conf->fn_read10 != NULL); + memcpy(&_conf, conf, sizeof(_conf)); +} + +static st3m_usb_msc_conf_t *_get_conf(void) { + assert(_conf.block_count != 0); + assert(_conf.block_size != 0); + assert(_conf.fn_read10 != NULL); + return &_conf; +} + +// TinyUSB callback. +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) +{ + (void) lun; + + st3m_usb_msc_conf_t *conf = _get_conf(); + + const char vid[] = "flow3r"; + const char rev[] = "1.0"; + + memcpy(vendor_id , vid, strlen(vid)); + memcpy(product_id , conf->product_id, 16); + memcpy(product_rev, rev, strlen(rev)); +} + +// TinyUSB callback. +bool tud_msc_test_unit_ready_cb(uint8_t lun) +{ + (void) lun; + st3m_usb_msc_conf_t *conf = _get_conf(); + if (conf->fn_ready != NULL) { + return conf->fn_ready(lun); + } + return true; +} + +// TinyUSB callback. +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) { + (void) lun; + st3m_usb_msc_conf_t *conf = _get_conf(); + *block_count = conf->block_count; + *block_size = conf->block_size; +} + +// TinyUSB callback. +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { + st3m_usb_msc_conf_t *conf = _get_conf(); + if (conf->fn_start_stop != NULL) { + return conf->fn_start_stop(lun, power_condition, start, load_eject); + } + return true; +} + +// TinyUSB callback. +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { + st3m_usb_msc_conf_t *conf = _get_conf(); + return conf->fn_read10(lun, lba, offset, buffer, bufsize); +} + +// TinyUSB callback. +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { + st3m_usb_msc_conf_t *conf = _get_conf(); + if (conf->fn_write10 != NULL) { + return conf->fn_write10(lun, lba, offset, buffer, bufsize); + } + + if (lba >= conf->block_count) { + return -1; + } + return (int32_t) bufsize; +} + +// TinyUSB callback. +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) { + void const* response = NULL; + int32_t resplen = 0; + + // most scsi handled is input + bool in_xfer = true; + + switch (scsi_cmd[0]) { + default: + // Set Sense = Invalid Command Operation + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // negative means error -> tinyusb could stall and/or response with failed status + resplen = -1; + break; + } + + // return resplen must not larger than bufsize + if ( resplen > bufsize ) { + resplen = bufsize; + } + + if ( response && (resplen > 0) ) { + if(in_xfer) { + memcpy(buffer, response, (size_t) resplen); + } else { + // SCSI output + } + } + + return resplen; +} \ No newline at end of file diff --git a/components/st3m/tusb_config.h b/components/st3m/tusb_config.h new file mode 100644 index 0000000000..c4fc055a1a --- /dev/null +++ b/components/st3m/tusb_config.h @@ -0,0 +1,31 @@ +#pragma once + +#include "tusb_option.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED +#define CFG_TUSB_OS OPT_OS_FREERTOS +#define CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) +#define CFG_TUSB_DEBUG 0 + +int st3m_uart0_debug(const char *fmt, ...); +#define CFG_TUSB_DEBUG_PRINTF st3m_uart0_debug + +#define CFG_TUD_ENDPOINT0_SIZE 64 + +#define CFG_TUD_CDC 1 +#define CFG_TUD_CDC_RX_BUFSIZE 64 +#define CFG_TUD_CDC_TX_BUFSIZE 64 + +#define CFG_TUD_MSC 1 +#define CFG_TUD_MSC_EP_BUFSIZE 512 + + +#ifdef __cplusplus +} +#endif + -- GitLab