diff --git a/components/console/esp_console.h b/components/console/esp_console.h index 98201cdbc4..29aab8b4fb 100644 --- a/components/console/esp_console.h +++ b/components/console/esp_console.h @@ -100,6 +100,20 @@ typedef struct { } #endif +/** + * @brief Parameters for console device: USB CDC + * + * @note It's an empty structure for now, reserved for future + * + */ +typedef struct { + +} esp_console_dev_usb_cdc_config_t; + +#define ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT() \ +{ \ +} + /** * @brief initialize console module * @param config console configuration @@ -304,6 +318,27 @@ struct esp_console_repl_s { */ esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl); +/** + * @brief Establish a console REPL environment over USB CDC + * + * @param[in] dev_config USB CDC configuration + * @param[in] repl_config REPL configuration + * @param[out] ret_repl return REPL handle after initialization succeed, return NULL otherwise + * + * @note This is a all-in-one function to establish the environment needed for REPL, includes: + * - Initializes linenoise + * - Spawn new thread to run REPL in the background + * + * @attention This function is meant to be used in the examples to make the code more compact. + * Applications which use console functionality should be based on + * the underlying linenoise and esp_console functions. + * + * @return + * - ESP_OK on success + * - ESP_FAIL Parameter error + */ +esp_err_t esp_console_new_repl_usb_cdc(const esp_console_dev_usb_cdc_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl); + /** * @brief Start REPL environment * @param[in] repl REPL handle returned from esp_console_new_repl_xxx diff --git a/components/console/esp_console_repl.c b/components/console/esp_console_repl.c index dd006c3b81..080096b47a 100644 --- a/components/console/esp_console_repl.c +++ b/components/console/esp_console_repl.c @@ -14,18 +14,20 @@ #include #include +#include #include #include "sdkconfig.h" #include "esp_err.h" #include "esp_log.h" #include "esp_console.h" #include "esp_vfs_dev.h" +#include "esp_vfs_cdcacm.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/uart.h" #include "linenoise/linenoise.h" -static const char *TAG = "console.repl.uart"; +static const char *TAG = "console.repl"; #define CONSOLE_PROMPT_MAX_LEN (32) @@ -48,12 +50,81 @@ typedef struct { int uart_channel; // uart channel number } esp_console_repl_uart_t; +typedef struct { + esp_console_repl_com_t repl_com; // base class +} esp_console_repl_usb_cdc_t; + static void esp_console_repl_task(void *args); static esp_err_t esp_console_repl_uart_delete(esp_console_repl_t *repl); +static esp_err_t esp_console_repl_usb_cdc_delete(esp_console_repl_t *repl); static esp_err_t esp_console_common_init(esp_console_repl_com_t *repl_com); static esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com); static esp_err_t esp_console_setup_history(const char *history_path, uint32_t max_history_len, esp_console_repl_com_t *repl_com); +esp_err_t esp_console_new_repl_usb_cdc(const esp_console_dev_usb_cdc_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl) +{ + esp_err_t ret = ESP_OK; + esp_console_repl_usb_cdc_t *cdc_repl = NULL; + if (!repl_config | !dev_config | !ret_repl) { + ret = ESP_ERR_INVALID_ARG; + goto _exit; + } + // allocate memory for console REPL context + cdc_repl = calloc(1, sizeof(esp_console_repl_usb_cdc_t)); + if (!cdc_repl) { + ret = ESP_ERR_NO_MEM; + goto _exit; + } + + /* Disable buffering on stdin */ + setvbuf(stdin, NULL, _IONBF, 0); + + /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ + esp_vfs_dev_cdcacm_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + /* Move the caret to the beginning of the next line on '\n' */ + esp_vfs_dev_cdcacm_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); + + /* Enable non-blocking mode on stdin and stdout */ + fcntl(fileno(stdout), F_SETFL, 0); + fcntl(fileno(stdin), F_SETFL, 0); + + // initialize console, common part + ret = esp_console_common_init(&cdc_repl->repl_com); + if (ret != ESP_OK) { + goto _exit; + } + + // setup history + ret = esp_console_setup_history(repl_config->history_save_path, repl_config->max_history_len, &cdc_repl->repl_com); + if (ret != ESP_OK) { + goto _exit; + } + + // setup prompt + esp_console_setup_prompt(repl_config->prompt, &cdc_repl->repl_com); + + /* spawn a single thread to run REPL */ + if (xTaskCreate(esp_console_repl_task, "console_repl", repl_config->task_stack_size, + &cdc_repl->repl_com, repl_config->task_priority, &cdc_repl->repl_com.task_hdl) != pdTRUE) { + ret = ESP_FAIL; + goto _exit; + } + + cdc_repl->repl_com.state = CONSOLE_REPL_STATE_INIT; + cdc_repl->repl_com.repl_core.del = esp_console_repl_usb_cdc_delete; + *ret_repl = &cdc_repl->repl_com.repl_core; + return ESP_OK; +_exit: + if (cdc_repl) { + esp_console_deinit(); + free(cdc_repl); + } + if (ret_repl) { + *ret_repl = NULL; + } + return ret; +} + esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl) { esp_err_t ret = ESP_OK; @@ -266,6 +337,24 @@ _exit: return ret; } +static esp_err_t esp_console_repl_usb_cdc_delete(esp_console_repl_t *repl) +{ + esp_err_t ret = ESP_OK; + esp_console_repl_com_t *repl_com = __containerof(repl, esp_console_repl_com_t, repl_core); + esp_console_repl_usb_cdc_t *cdc_repl = __containerof(repl_com, esp_console_repl_usb_cdc_t, repl_com); + // check if already de-initialized + if (repl_com->state == CONSOLE_REPL_STATE_DEINIT) { + ESP_LOGE(TAG, "already de-initialized"); + ret = ESP_ERR_INVALID_STATE; + goto _exit; + } + repl_com->state = CONSOLE_REPL_STATE_DEINIT; + esp_console_deinit(); + free(cdc_repl); +_exit: + return ret; +} + static void esp_console_repl_task(void *args) { esp_console_repl_com_t *repl_com = (esp_console_repl_com_t *)args; diff --git a/components/esp_system/system_api.c b/components/esp_system/system_api.c index 33541c6072..66f30f9704 100644 --- a/components/esp_system/system_api.c +++ b/components/esp_system/system_api.c @@ -15,7 +15,7 @@ #endif -#define SHUTDOWN_HANDLERS_NO 2 +#define SHUTDOWN_HANDLERS_NO 3 static shutdown_handler_t shutdown_handlers[SHUTDOWN_HANDLERS_NO]; esp_err_t esp_register_shutdown_handler(shutdown_handler_t handler) diff --git a/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c b/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c index 23cad5a874..c29231b24e 100644 --- a/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c +++ b/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c @@ -42,14 +42,21 @@ void app_main(void) { esp_console_repl_t *repl = NULL; esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); - esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + #if CONFIG_EXAMPLE_STORE_HISTORY initialize_filesystem(); repl_config.history_save_path = HISTORY_PATH; #endif repl_config.prompt = "i2c-tools>"; - // init console REPL environment + + // install console REPL environment +#if CONFIG_ESP_CONSOLE_UART + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); +#elif CONFIG_ESP_CONSOLE_USB_CDC + esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &repl)); +#endif register_i2ctools(); register_system(); diff --git a/examples/protocols/icmp_echo/main/echo_example_main.c b/examples/protocols/icmp_echo/main/echo_example_main.c index 04c88defc8..86e3884c17 100644 --- a/examples/protocols/icmp_echo/main/echo_example_main.c +++ b/examples/protocols/icmp_echo/main/echo_example_main.c @@ -197,9 +197,14 @@ void app_main(void) ESP_ERROR_CHECK(example_connect()); esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + // install console REPL environment +#if CONFIG_ESP_CONSOLE_UART esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); - // init console REPL environment ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); +#elif CONFIG_ESP_CONSOLE_USB_CDC + esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &s_repl)); +#endif /* register command `ping` */ register_ping(); diff --git a/examples/wifi/iperf/main/iperf_example_main.c b/examples/wifi/iperf/main/iperf_example_main.c index 6d60a9e4cf..30f0980fc2 100644 --- a/examples/wifi/iperf/main/iperf_example_main.c +++ b/examples/wifi/iperf/main/iperf_example_main.c @@ -29,10 +29,17 @@ void app_main(void) esp_console_repl_t *repl = NULL; esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); - esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); repl_config.prompt = "iperf>"; + // init console REPL environment +#if CONFIG_ESP_CONSOLE_UART + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); +#elif CONFIG_ESP_CONSOLE_USB_CDC + esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &repl)); +#endif + /* Register commands */ register_system(); register_wifi(); diff --git a/examples/wifi/simple_sniffer/main/simple_sniffer_example_main.c b/examples/wifi/simple_sniffer/main/simple_sniffer_example_main.c index fe95e2e34f..4117bcfa96 100644 --- a/examples/wifi/simple_sniffer/main/simple_sniffer_example_main.c +++ b/examples/wifi/simple_sniffer/main/simple_sniffer_example_main.c @@ -181,14 +181,20 @@ void app_main(void) initialize_wifi(); esp_console_repl_t *repl = NULL; esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); - esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); #if CONFIG_SNIFFER_STORE_HISTORY initialize_filesystem(); repl_config.history_save_path = HISTORY_FILE_PATH; #endif repl_config.prompt = "sniffer>"; - // init console REPL environment + + // install console REPL environment +#if CONFIG_ESP_CONSOLE_UART + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); +#elif CONFIG_ESP_CONSOLE_USB_CDC + esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &repl)); +#endif /* Register commands */ #if CONFIG_SNIFFER_PCAP_DESTINATION_SD