|
|
|
|
@ -0,0 +1,416 @@
|
|
|
|
|
/*
|
|
|
|
|
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* DESCRIPTION:
|
|
|
|
|
* This example contains code to make ESP32 based device recognizable by
|
|
|
|
|
* USB-hosts as a USB Mass Storage Device. It either allows the embedded
|
|
|
|
|
* application i.e. example to access the partition or Host PC accesses the
|
|
|
|
|
* partition over USB MSC. They can't be allowed to access the partition at the
|
|
|
|
|
* same time. For different scenarios and behaviour, Refer to README of this
|
|
|
|
|
* example.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <dirent.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
#include "driver/gpio.h"
|
|
|
|
|
#include "esp_check.h"
|
|
|
|
|
#include "esp_console.h"
|
|
|
|
|
#include "esp_partition.h"
|
|
|
|
|
#include "sdkconfig.h"
|
|
|
|
|
#include "tinyusb.h"
|
|
|
|
|
#include "tinyusb_default_config.h"
|
|
|
|
|
#include "tinyusb_msc.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We warn if a secondary serial console is enabled. A secondary serial console
|
|
|
|
|
* is always output-only and hence not very useful for interactive console
|
|
|
|
|
* applications. If you encounter this warning, consider disabling the secondary
|
|
|
|
|
* serial console in menuconfig unless you know what you are doing.
|
|
|
|
|
*/
|
|
|
|
|
#if SOC_USB_SERIAL_JTAG_SUPPORTED
|
|
|
|
|
#if !CONFIG_ESP_CONSOLE_SECONDARY_NONE
|
|
|
|
|
#warning \
|
|
|
|
|
"A secondary serial console is not useful when using the console component. Please disable it in menuconfig."
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static const char* TAG = "msc";
|
|
|
|
|
static esp_console_repl_t* repl = NULL;
|
|
|
|
|
|
|
|
|
|
/* Storage global variables */
|
|
|
|
|
tinyusb_msc_storage_handle_t storage_hdl = NULL;
|
|
|
|
|
tinyusb_msc_mount_point_t mp;
|
|
|
|
|
|
|
|
|
|
static SemaphoreHandle_t _wait_console_smp = NULL;
|
|
|
|
|
|
|
|
|
|
/* TinyUSB descriptors
|
|
|
|
|
********************************************************************* */
|
|
|
|
|
#define EPNUM_MSC 1
|
|
|
|
|
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN)
|
|
|
|
|
|
|
|
|
|
enum { ITF_NUM_MSC = 0, ITF_NUM_TOTAL };
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
EDPT_CTRL_OUT = 0x00,
|
|
|
|
|
EDPT_CTRL_IN = 0x80,
|
|
|
|
|
|
|
|
|
|
EDPT_MSC_OUT = 0x01,
|
|
|
|
|
EDPT_MSC_IN = 0x81,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static tusb_desc_device_t descriptor_config = {
|
|
|
|
|
.bLength = sizeof(descriptor_config),
|
|
|
|
|
.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};
|
|
|
|
|
|
|
|
|
|
static uint8_t const msc_fs_configuration_desc[] = {
|
|
|
|
|
// Config number, interface count, string index, total length, attribute,
|
|
|
|
|
// power in mA
|
|
|
|
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN,
|
|
|
|
|
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
|
|
|
|
|
|
|
|
|
// Interface number, string index, EP Out & EP In address, EP size
|
|
|
|
|
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 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};
|
|
|
|
|
|
|
|
|
|
static uint8_t const msc_hs_configuration_desc[] = {
|
|
|
|
|
// Config number, interface count, string index, total length, attribute,
|
|
|
|
|
// power in mA
|
|
|
|
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN,
|
|
|
|
|
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
|
|
|
|
|
|
|
|
|
// Interface number, string index, EP Out & EP In address, EP size
|
|
|
|
|
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 512),
|
|
|
|
|
};
|
|
|
|
|
#endif // TUD_OPT_HIGH_SPEED
|
|
|
|
|
|
|
|
|
|
static char const* string_desc_arr[] = {
|
|
|
|
|
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
|
|
|
|
"TinyUSB", // 1: Manufacturer
|
|
|
|
|
"TinyUSB Device", // 2: Product
|
|
|
|
|
"123456", // 3: Serials
|
|
|
|
|
"Example MSC", // 4. MSC
|
|
|
|
|
};
|
|
|
|
|
/*********************************************************************** TinyUSB
|
|
|
|
|
* descriptors*/
|
|
|
|
|
|
|
|
|
|
#define BASE_PATH "/sdcard" // base path to mount the partition
|
|
|
|
|
|
|
|
|
|
#define PROMPT_STR CONFIG_IDF_TARGET
|
|
|
|
|
static int console_unmount(int argc, char** argv);
|
|
|
|
|
static int console_read(int argc, char** argv);
|
|
|
|
|
static int console_write(int argc, char** argv);
|
|
|
|
|
static int console_size(int argc, char** argv);
|
|
|
|
|
static int console_status(int argc, char** argv);
|
|
|
|
|
static int console_exit(int argc, char** argv);
|
|
|
|
|
const esp_console_cmd_t cmds[] = {
|
|
|
|
|
{
|
|
|
|
|
.command = "read",
|
|
|
|
|
.help = "read BASE_PATH/README.MD and print its contents",
|
|
|
|
|
.hint = NULL,
|
|
|
|
|
.func = &console_read,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.command = "write",
|
|
|
|
|
.help = "create file BASE_PATH/README.MD if it does not exist",
|
|
|
|
|
.hint = NULL,
|
|
|
|
|
.func = &console_write,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.command = "size",
|
|
|
|
|
.help = "show storage size and sector size",
|
|
|
|
|
.hint = NULL,
|
|
|
|
|
.func = &console_size,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.command = "expose",
|
|
|
|
|
.help = "Expose Storage to Host",
|
|
|
|
|
.hint = NULL,
|
|
|
|
|
.func = &console_unmount,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.command = "status",
|
|
|
|
|
.help = "Status of storage exposure over USB",
|
|
|
|
|
.hint = NULL,
|
|
|
|
|
.func = &console_status,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.command = "exit",
|
|
|
|
|
.help = "exit from application",
|
|
|
|
|
.hint = NULL,
|
|
|
|
|
.func = &console_exit,
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
// Set mount point to the application and list files in BASE_PATH by filesystem
|
|
|
|
|
// API
|
|
|
|
|
static void mount(void) {
|
|
|
|
|
ESP_LOGI(TAG, "Mount storage...");
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_set_storage_mount_point(
|
|
|
|
|
storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_APP));
|
|
|
|
|
|
|
|
|
|
// List all the files in this directory
|
|
|
|
|
ESP_LOGI(TAG, "\nls command output:");
|
|
|
|
|
struct dirent* d;
|
|
|
|
|
DIR* dh = opendir(BASE_PATH);
|
|
|
|
|
if (!dh) {
|
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
|
// If the directory is not found
|
|
|
|
|
ESP_LOGE(TAG, "Directory doesn't exist %s", BASE_PATH);
|
|
|
|
|
} else {
|
|
|
|
|
// If the directory is not readable then throw error and exit
|
|
|
|
|
ESP_LOGE(TAG, "Unable to read directory %s", BASE_PATH);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// While the next entry is not readable we will print directory files
|
|
|
|
|
while ((d = readdir(dh)) != NULL) {
|
|
|
|
|
printf("%s\n", d->d_name);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// unmount storage
|
|
|
|
|
static int console_unmount(int argc, char** argv) {
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_get_storage_mount_point(storage_hdl, &mp));
|
|
|
|
|
if (mp == TINYUSB_MSC_STORAGE_MOUNT_USB) {
|
|
|
|
|
ESP_LOGE(TAG, "Storage is already exposed");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ESP_LOGI(TAG, "Unmount storage...");
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_set_storage_mount_point(
|
|
|
|
|
storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_USB));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read BASE_PATH/README.MD and print its contents
|
|
|
|
|
static int console_read(int argc, char** argv) {
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_get_storage_mount_point(storage_hdl, &mp));
|
|
|
|
|
if (mp == TINYUSB_MSC_STORAGE_MOUNT_USB) {
|
|
|
|
|
ESP_LOGE(TAG,
|
|
|
|
|
"Storage exposed over USB. Application can't read from storage.");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ESP_LOGD(TAG, "read from storage:");
|
|
|
|
|
const char* filename = BASE_PATH "/README.MD";
|
|
|
|
|
FILE* ptr = fopen(filename, "r");
|
|
|
|
|
if (ptr == NULL) {
|
|
|
|
|
ESP_LOGE(TAG, "Filename not present - %s", filename);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
char buf[1024];
|
|
|
|
|
while (fgets(buf, 1000, ptr) != NULL) {
|
|
|
|
|
printf("%s", buf);
|
|
|
|
|
}
|
|
|
|
|
fclose(ptr);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create file BASE_PATH/README.MD if it does not exist
|
|
|
|
|
static int console_write(int argc, char** argv) {
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_get_storage_mount_point(storage_hdl, &mp));
|
|
|
|
|
if (mp == TINYUSB_MSC_STORAGE_MOUNT_USB) {
|
|
|
|
|
ESP_LOGE(TAG,
|
|
|
|
|
"storage exposed over USB. Application can't write to storage.");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ESP_LOGD(TAG, "write to storage:");
|
|
|
|
|
const char* filename = BASE_PATH "/README.MD";
|
|
|
|
|
FILE* fd = fopen(filename, "r");
|
|
|
|
|
if (!fd) {
|
|
|
|
|
ESP_LOGW(TAG, "README.MD doesn't exist yet, creating");
|
|
|
|
|
fd = fopen(filename, "w");
|
|
|
|
|
fprintf(fd,
|
|
|
|
|
"Mass Storage Devices are one of the most common USB devices. It "
|
|
|
|
|
"use Mass Storage Class (MSC) that allow access to their internal "
|
|
|
|
|
"data storage.\n");
|
|
|
|
|
fprintf(fd,
|
|
|
|
|
"In this example, ESP chip will be recognised by host (PC) as Mass "
|
|
|
|
|
"Storage Device.\n");
|
|
|
|
|
fprintf(fd,
|
|
|
|
|
"Upon connection to USB host (PC), the example application will "
|
|
|
|
|
"initialize the storage module and then the storage will be seen "
|
|
|
|
|
"as removable device on PC.\n");
|
|
|
|
|
fclose(fd);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show storage size and sector size
|
|
|
|
|
static int console_size(int argc, char** argv) {
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_get_storage_mount_point(storage_hdl, &mp));
|
|
|
|
|
if (mp == TINYUSB_MSC_STORAGE_MOUNT_USB) {
|
|
|
|
|
ESP_LOGE(TAG, "storage exposed over USB. Application can't access storage");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t sec_count;
|
|
|
|
|
uint32_t sec_size;
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_get_storage_sector_size(storage_hdl, &sec_size));
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_get_storage_capacity(storage_hdl, &sec_count));
|
|
|
|
|
|
|
|
|
|
// Calculate size in MB or KB
|
|
|
|
|
uint64_t total_bytes = (uint64_t)sec_size * sec_count;
|
|
|
|
|
if (total_bytes >= (1024 * 1024)) {
|
|
|
|
|
uint64_t total_mb = total_bytes / (1024 * 1024);
|
|
|
|
|
printf("Storage Capacity %lluMB\n", total_mb);
|
|
|
|
|
} else {
|
|
|
|
|
uint64_t total_kb = total_bytes / 1024;
|
|
|
|
|
printf("Storage Capacity %lluKB\n", total_kb);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show storage status
|
|
|
|
|
static int console_status(int argc, char** argv) {
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_get_storage_mount_point(storage_hdl, &mp));
|
|
|
|
|
printf("storage exposed over USB: %s\n",
|
|
|
|
|
(mp == TINYUSB_MSC_STORAGE_MOUNT_USB) ? "Yes" : "No");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Exit from application
|
|
|
|
|
static int console_exit(int argc, char** argv) {
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_delete_storage(storage_hdl));
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_driver_uninstall());
|
|
|
|
|
|
|
|
|
|
xSemaphoreGive(_wait_console_smp);
|
|
|
|
|
|
|
|
|
|
printf("Application Exit\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Storage mount changed callback
|
|
|
|
|
*
|
|
|
|
|
* @param handle Storage handle
|
|
|
|
|
* @param event Event information
|
|
|
|
|
* @param arg User argument, provided during callback registration
|
|
|
|
|
*/
|
|
|
|
|
static void storage_mount_changed_cb(tinyusb_msc_storage_handle_t handle,
|
|
|
|
|
tinyusb_msc_event_t* event, void* arg) {
|
|
|
|
|
switch (event->id) {
|
|
|
|
|
case TINYUSB_MSC_EVENT_MOUNT_START:
|
|
|
|
|
// Verify that all the files are closed before unmounting
|
|
|
|
|
break;
|
|
|
|
|
case TINYUSB_MSC_EVENT_MOUNT_COMPLETE:
|
|
|
|
|
ESP_LOGI(
|
|
|
|
|
TAG, "Storage mounted to application: %s",
|
|
|
|
|
(event->mount_point == TINYUSB_MSC_STORAGE_MOUNT_APP) ? "Yes" : "No");
|
|
|
|
|
break;
|
|
|
|
|
case TINYUSB_MSC_EVENT_MOUNT_FAILED:
|
|
|
|
|
case TINYUSB_MSC_EVENT_FORMAT_REQUIRED:
|
|
|
|
|
ESP_LOGE(TAG, "Storage mount failed or format required");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_msc(sdmmc_card_t* card) {
|
|
|
|
|
ESP_LOGI(TAG, "Initializing storage...");
|
|
|
|
|
|
|
|
|
|
_wait_console_smp = xSemaphoreCreateBinary();
|
|
|
|
|
if (_wait_console_smp == NULL) {
|
|
|
|
|
ESP_LOGE(TAG, "Failed to create semaphore");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initial mount point to APP
|
|
|
|
|
tinyusb_msc_storage_config_t storage_cfg = {
|
|
|
|
|
.mount_point = TINYUSB_MSC_STORAGE_MOUNT_USB,
|
|
|
|
|
.fat_fs =
|
|
|
|
|
{
|
|
|
|
|
.base_path = NULL, // Use default base path
|
|
|
|
|
.config.max_files = 5, // Maximum number of files that can be
|
|
|
|
|
// opened simultaneously
|
|
|
|
|
.format_flags = 0, // No special format flags
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
storage_cfg.medium.card = card;
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_new_storage_sdmmc(&storage_cfg, &storage_hdl));
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(
|
|
|
|
|
tinyusb_msc_set_storage_callback(storage_mount_changed_cb, NULL));
|
|
|
|
|
// Re-mount to the APP
|
|
|
|
|
mount();
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "USB MSC initialization");
|
|
|
|
|
|
|
|
|
|
tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();
|
|
|
|
|
|
|
|
|
|
tusb_cfg.descriptor.device = &descriptor_config;
|
|
|
|
|
tusb_cfg.descriptor.full_speed_config = msc_fs_configuration_desc;
|
|
|
|
|
tusb_cfg.descriptor.string = string_desc_arr;
|
|
|
|
|
tusb_cfg.descriptor.string_count =
|
|
|
|
|
sizeof(string_desc_arr) / sizeof(string_desc_arr[0]);
|
|
|
|
|
#if (TUD_OPT_HIGH_SPEED)
|
|
|
|
|
tusb_cfg.descriptor.high_speed_config = msc_hs_configuration_desc;
|
|
|
|
|
tusb_cfg.descriptor.qualifier = &device_qualifier;
|
|
|
|
|
#endif // TUD_OPT_HIGH_SPEED
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "USB MSC initialization DONE");
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(tinyusb_msc_get_storage_mount_point(storage_hdl, &mp));
|
|
|
|
|
if (mp == TINYUSB_MSC_STORAGE_MOUNT_USB) {
|
|
|
|
|
ESP_LOGE(TAG, "storage exposed over USB. Application can't access.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
// Init console based on menuconfig settings
|
|
|
|
|
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
|
|
|
|
/* Prompt to be printed before each line.
|
|
|
|
|
* This can be customized, made dynamic, etc.
|
|
|
|
|
*/
|
|
|
|
|
repl_config.prompt = PROMPT_STR ">";
|
|
|
|
|
repl_config.max_cmdline_length = 64;
|
|
|
|
|
|
|
|
|
|
esp_console_dev_uart_config_t hw_config =
|
|
|
|
|
ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
|
|
|
|
ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl));
|
|
|
|
|
|
|
|
|
|
for (int count = 0; count < sizeof(cmds) / sizeof(esp_console_cmd_t);
|
|
|
|
|
count++) {
|
|
|
|
|
ESP_ERROR_CHECK(esp_console_cmd_register(&cmds[count]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(esp_console_start_repl(repl));
|
|
|
|
|
|
|
|
|
|
xSemaphoreTake(_wait_console_smp, portMAX_DELAY);
|
|
|
|
|
ESP_ERROR_CHECK(esp_console_stop_repl(repl));
|
|
|
|
|
vSemaphoreDelete(_wait_console_smp);
|
|
|
|
|
#endif
|
|
|
|
|
}
|