mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 04:04:31 +02:00
feat(console): Make console deinit optional
This commit is contained in:
@@ -2,6 +2,7 @@ idf_build_get_property(target IDF_TARGET)
|
|||||||
|
|
||||||
set(srcs "commands.c"
|
set(srcs "commands.c"
|
||||||
"esp_console_common.c"
|
"esp_console_common.c"
|
||||||
|
"esp_console_repl_internal.c"
|
||||||
"split_argv.c"
|
"split_argv.c"
|
||||||
"linenoise/linenoise.c")
|
"linenoise/linenoise.c")
|
||||||
|
|
||||||
|
@@ -451,13 +451,23 @@ esp_err_t esp_console_new_repl_usb_serial_jtag(const esp_console_dev_usb_serial_
|
|||||||
/**
|
/**
|
||||||
* @brief Start REPL environment
|
* @brief Start REPL environment
|
||||||
* @param[in] repl REPL handle returned from esp_console_new_repl_xxx
|
* @param[in] repl REPL handle returned from esp_console_new_repl_xxx
|
||||||
* @note Once the REPL gets started, it won't be stopped until the user calls repl->del(repl) to destroy the REPL environment.
|
* @note Once the REPL gets started, it won't be stopped until the user calls esp_console_stop_repl to destroy the REPL environment.
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK on success
|
* - ESP_OK on success
|
||||||
* - ESP_ERR_INVALID_STATE, if repl has started already
|
* - ESP_ERR_INVALID_STATE, if repl has started already
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_console_start_repl(esp_console_repl_t *repl);
|
esp_err_t esp_console_start_repl(esp_console_repl_t *repl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop REPL environment
|
||||||
|
*
|
||||||
|
* @param[in] repl REPL handle returned from esp_console_new_repl_xxx
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - others on failure
|
||||||
|
*/
|
||||||
|
esp_err_t esp_console_stop_repl(esp_console_repl_t *repl);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include <sys/cdefs.h> // __containerof
|
#include <sys/cdefs.h> // __containerof
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
#include "esp_console.h"
|
#include "esp_console.h"
|
||||||
#include "console_private.h"
|
#include "console_private.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
@@ -18,10 +20,6 @@
|
|||||||
|
|
||||||
static const char *TAG = "console.common";
|
static const char *TAG = "console.common";
|
||||||
|
|
||||||
static bool s_init = false;
|
|
||||||
static int s_interrupt_reading_fd = -1;
|
|
||||||
static uint64_t s_interrupt_reading_signal = 1;
|
|
||||||
|
|
||||||
esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com)
|
esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com)
|
||||||
{
|
{
|
||||||
/* set command line prompt */
|
/* set command line prompt */
|
||||||
@@ -68,6 +66,11 @@ _exit:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) esp_err_t esp_console_internal_set_event_fd(esp_console_repl_com_t *repl_com)
|
||||||
|
{
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com)
|
esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
@@ -103,50 +106,36 @@ esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_co
|
|||||||
linenoiseSetCompletionCallback(&esp_console_get_completion);
|
linenoiseSetCompletionCallback(&esp_console_get_completion);
|
||||||
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
|
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
|
||||||
|
|
||||||
/* Tell linenoise what file descriptor to add to the read file descriptor set,
|
#if CONFIG_VFS_SUPPORT_SELECT
|
||||||
* that will be used to signal a read termination */
|
ret = esp_console_internal_set_event_fd(repl_com);
|
||||||
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
|
if (ret != ESP_OK) {
|
||||||
ret = esp_vfs_eventfd_register(&config);
|
|
||||||
if (ret == ESP_OK) {
|
|
||||||
/* first time calling the eventfd register function */
|
|
||||||
s_interrupt_reading_fd = eventfd(0, 0);
|
|
||||||
linenoiseSetInterruptReadingData(s_interrupt_reading_fd, s_interrupt_reading_signal);
|
|
||||||
} else if (ret == ESP_ERR_INVALID_STATE) {
|
|
||||||
/* the evenfd has already been registered*/
|
|
||||||
} else {
|
|
||||||
/* issue with arg, this should not happen */
|
|
||||||
goto _exit;
|
goto _exit;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
repl_com->state_mux = xSemaphoreCreateMutex();
|
|
||||||
if (repl_com->state_mux == NULL) {
|
|
||||||
ESP_LOGE(TAG, "state_mux create error");
|
|
||||||
ret = ESP_ERR_NO_MEM;
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
xSemaphoreGive(repl_com->state_mux);
|
|
||||||
|
|
||||||
s_init = true;
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
_exit:
|
_exit:
|
||||||
s_init = false;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void esp_console_common_deinit(esp_console_repl_com_t *repl_com)
|
__attribute__((weak)) esp_err_t esp_console_common_deinit(esp_console_repl_com_t *repl_com)
|
||||||
{
|
{
|
||||||
|
// set the state to deinit to force the while loop in
|
||||||
|
// esp_console_repl_task to break
|
||||||
|
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
|
||||||
|
|
||||||
/* Unregister the heap function to avoid memory leak, since it is created
|
/* Unregister the heap function to avoid memory leak, since it is created
|
||||||
* every time a console init is called. */
|
* every time a console init is called. */
|
||||||
esp_err_t ret = esp_console_deregister_help_command();
|
esp_err_t ret = esp_console_deregister_help_command();
|
||||||
assert(ret == ESP_OK);
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
/* unregister eventfd to avoid memory leaks, since it is created every time a
|
}
|
||||||
* console init is called */
|
|
||||||
(void)esp_vfs_eventfd_unregister();
|
|
||||||
|
|
||||||
/* free the history to avoid memory leak, since it is created
|
/* free the history to avoid memory leak, since it is created
|
||||||
* every time a console init is called. */
|
* every time a console init is called. */
|
||||||
linenoiseHistoryFree();
|
linenoiseHistoryFree();
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_console_start_repl(esp_console_repl_t *repl)
|
esp_err_t esp_console_start_repl(esp_console_repl_t *repl)
|
||||||
@@ -176,9 +165,10 @@ void esp_console_repl_task(void *args)
|
|||||||
* function is called. */
|
* function is called. */
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
assert(repl_com->state_mux != NULL);
|
if (repl_com->state_mux != NULL) {
|
||||||
BaseType_t ret_val = xSemaphoreTake(repl_com->state_mux, portMAX_DELAY);
|
BaseType_t ret_val = xSemaphoreTake(repl_com->state_mux, portMAX_DELAY);
|
||||||
assert(ret_val == pdTRUE);
|
assert(ret_val == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Change standard input and output of the task if the requested UART is
|
/* Change standard input and output of the task if the requested UART is
|
||||||
* NOT the default one. This block will replace stdin, stdout and stderr.
|
* NOT the default one. This block will replace stdin, stdout and stderr.
|
||||||
@@ -242,17 +232,9 @@ void esp_console_repl_task(void *args)
|
|||||||
linenoiseFree(line);
|
linenoiseFree(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
xSemaphoreGive(repl_com->state_mux);
|
if (repl_com->state_mux != NULL) {
|
||||||
|
xSemaphoreGive(repl_com->state_mux);
|
||||||
|
}
|
||||||
ESP_LOGD(TAG, "The End");
|
ESP_LOGD(TAG, "The End");
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_console_interrupt_reading(void)
|
|
||||||
{
|
|
||||||
if (!s_init) {
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
ssize_t ret = write(s_interrupt_reading_fd, &s_interrupt_reading_signal, sizeof(s_interrupt_reading_signal));
|
|
||||||
assert(ret == sizeof(s_interrupt_reading_signal));
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
#include "console_private.h"
|
#include "console_private.h"
|
||||||
|
|
||||||
#if !CONFIG_ESP_CONSOLE_NONE
|
#if !CONFIG_ESP_CONSOLE_NONE
|
||||||
static const char *TAG = "console.repl";
|
static const char *TAG = "console.repl.chip";
|
||||||
#endif // !CONFIG_ESP_CONSOLE_NONE
|
#endif // !CONFIG_ESP_CONSOLE_NONE
|
||||||
|
|
||||||
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
|
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
|
||||||
@@ -296,27 +296,11 @@ static esp_err_t esp_console_repl_uart_delete(esp_console_repl_t *repl)
|
|||||||
goto _exit;
|
goto _exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the state to deinit to force the while loop in
|
ret = esp_console_common_deinit(&uart_repl->repl_com);
|
||||||
// esp_console_repl_task to break
|
if (ret != ESP_OK) {
|
||||||
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
|
goto _exit;
|
||||||
|
|
||||||
const esp_err_t read_interrupted = esp_console_interrupt_reading();
|
|
||||||
if (read_interrupted != ESP_OK) {
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the task to notify that
|
|
||||||
// esp_console_repl_task returned
|
|
||||||
assert(repl_com->state_mux != NULL);
|
|
||||||
BaseType_t ret_val = xSemaphoreTake(repl_com->state_mux, portMAX_DELAY);
|
|
||||||
assert(ret_val == pdTRUE);
|
|
||||||
|
|
||||||
// delete the semaphore for the repl state
|
|
||||||
vSemaphoreDelete(repl_com->state_mux);
|
|
||||||
repl_com->state_mux = NULL;
|
|
||||||
|
|
||||||
esp_console_common_deinit(&uart_repl->repl_com);
|
|
||||||
|
|
||||||
esp_console_deinit();
|
esp_console_deinit();
|
||||||
uart_vfs_dev_use_nonblocking(uart_repl->uart_channel);
|
uart_vfs_dev_use_nonblocking(uart_repl->uart_channel);
|
||||||
uart_driver_delete(uart_repl->uart_channel);
|
uart_driver_delete(uart_repl->uart_channel);
|
||||||
@@ -339,27 +323,11 @@ static esp_err_t esp_console_repl_usb_cdc_delete(esp_console_repl_t *repl)
|
|||||||
goto _exit;
|
goto _exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the state to deinit to force the while loop in
|
ret = esp_console_common_deinit(&cdc_repl->repl_com);
|
||||||
// esp_console_repl_task to break
|
if (ret != ESP_OK) {
|
||||||
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
|
goto _exit;
|
||||||
|
|
||||||
const esp_err_t read_interrupted = esp_console_interrupt_reading();
|
|
||||||
if (read_interrupted != ESP_OK) {
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the task to notify that
|
|
||||||
// esp_console_repl_task returned
|
|
||||||
assert(repl_com->state_mux != NULL);
|
|
||||||
BaseType_t ret_val = xSemaphoreTake(repl_com->state_mux, portMAX_DELAY);
|
|
||||||
assert(ret_val == pdTRUE);
|
|
||||||
|
|
||||||
// delete the semaphore for the repl state
|
|
||||||
vSemaphoreDelete(repl_com->state_mux);
|
|
||||||
repl_com->state_mux = NULL;
|
|
||||||
|
|
||||||
esp_console_common_deinit(&cdc_repl->repl_com);
|
|
||||||
|
|
||||||
esp_console_deinit();
|
esp_console_deinit();
|
||||||
free(cdc_repl);
|
free(cdc_repl);
|
||||||
_exit:
|
_exit:
|
||||||
@@ -380,27 +348,11 @@ static esp_err_t esp_console_repl_usb_serial_jtag_delete(esp_console_repl_t *rep
|
|||||||
goto _exit;
|
goto _exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the state to deinit to force the while loop in
|
ret = esp_console_common_deinit(&usb_serial_jtag_repl->repl_com);
|
||||||
// esp_console_repl_task to break
|
if (ret != ESP_OK) {
|
||||||
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
|
goto _exit;
|
||||||
|
|
||||||
const esp_err_t read_interrupted = esp_console_interrupt_reading();
|
|
||||||
if (read_interrupted != ESP_OK) {
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the task to notify that
|
|
||||||
// esp_console_repl_task returned
|
|
||||||
assert(repl_com->state_mux != NULL);
|
|
||||||
BaseType_t ret_val = xSemaphoreTake(repl_com->state_mux, portMAX_DELAY);
|
|
||||||
assert(ret_val == pdTRUE);
|
|
||||||
|
|
||||||
// delete the semaphore for the repl state
|
|
||||||
vSemaphoreDelete(repl_com->state_mux);
|
|
||||||
repl_com->state_mux = NULL;
|
|
||||||
|
|
||||||
esp_console_common_deinit(&usb_serial_jtag_repl->repl_com);
|
|
||||||
|
|
||||||
esp_console_deinit();
|
esp_console_deinit();
|
||||||
usb_serial_jtag_vfs_use_nonblocking();
|
usb_serial_jtag_vfs_use_nonblocking();
|
||||||
usb_serial_jtag_driver_uninstall();
|
usb_serial_jtag_driver_uninstall();
|
||||||
|
166
components/console/esp_console_repl_internal.c
Normal file
166
components/console/esp_console_repl_internal.c
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/cdefs.h> // __containerof
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include "esp_console.h"
|
||||||
|
#include "console_private.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "linenoise/linenoise.h"
|
||||||
|
|
||||||
|
#include "esp_vfs_eventfd.h"
|
||||||
|
|
||||||
|
#if CONFIG_VFS_SUPPORT_SELECT
|
||||||
|
|
||||||
|
static const char *TAG = "console.repl.internal";
|
||||||
|
|
||||||
|
static int s_interrupt_reading_fd = -1;
|
||||||
|
static uint64_t s_interrupt_reading_signal = 1;
|
||||||
|
|
||||||
|
static ssize_t read_bytes(int fd, void *buf, size_t max_bytes)
|
||||||
|
{
|
||||||
|
fd_set read_fds;
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
FD_SET(fd, &read_fds);
|
||||||
|
if (s_interrupt_reading_fd != -1) {
|
||||||
|
FD_SET(s_interrupt_reading_fd, &read_fds);
|
||||||
|
}
|
||||||
|
int maxFd = MAX(fd, s_interrupt_reading_fd);
|
||||||
|
/* call select to wait for either a read ready or an except to happen */
|
||||||
|
int nread = select(maxFd + 1, &read_fds, NULL, NULL, NULL);
|
||||||
|
if (nread < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(s_interrupt_reading_fd, &read_fds)) {
|
||||||
|
/* read termination request happened, return */
|
||||||
|
int buf[sizeof(s_interrupt_reading_signal)];
|
||||||
|
nread = read(s_interrupt_reading_fd, buf, sizeof(s_interrupt_reading_signal));
|
||||||
|
if ((nread == sizeof(s_interrupt_reading_signal)) && (buf[0] == s_interrupt_reading_signal)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (FD_ISSET(fd, &read_fds)) {
|
||||||
|
/* a read ready triggered the select to return. call the
|
||||||
|
* read function with the number of bytes max_bytes */
|
||||||
|
nread = read(fd, buf, max_bytes);
|
||||||
|
}
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strong definition of the weak definition of linenoiseSetReadCharacteristics in
|
||||||
|
* linenoise.c. This function set the read to be non blocking and set the read
|
||||||
|
* function used by linenoise to read_bytes. This function is compiled only if
|
||||||
|
* esp_console_stop_repl is used. */
|
||||||
|
void linenoiseSetReadCharacteristics(void)
|
||||||
|
{
|
||||||
|
/* Make sure we are using non blocking reads with
|
||||||
|
* the select */
|
||||||
|
int stdin_fileno = fileno(stdin);
|
||||||
|
int flags = fcntl(stdin_fileno, F_GETFL);
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
(void)fcntl(stdin_fileno, F_SETFL, flags);
|
||||||
|
|
||||||
|
linenoiseSetReadFunction(read_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strong definition of the weak definition of esp_console_internal_set_event_fd
|
||||||
|
* in esp_console_common to allow the use of select with non blocking
|
||||||
|
* read. This function is compiled only if esp_console_stop_repl
|
||||||
|
* is used. */
|
||||||
|
esp_err_t esp_console_internal_set_event_fd(esp_console_repl_com_t *repl_com)
|
||||||
|
{
|
||||||
|
/* Tell linenoise what file descriptor to add to the read file descriptor set,
|
||||||
|
* that will be used to signal a read termination */
|
||||||
|
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
|
||||||
|
esp_err_t ret = esp_vfs_eventfd_register(&config);
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
/* first time calling the eventfd register function */
|
||||||
|
s_interrupt_reading_fd = eventfd(0, 0);
|
||||||
|
} else if (ret == ESP_ERR_INVALID_STATE) {
|
||||||
|
/* the evenfd has already been registered*/
|
||||||
|
} else {
|
||||||
|
/* issue with arg, this should not happen */
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
repl_com->state_mux = xSemaphoreCreateMutex();
|
||||||
|
if (repl_com->state_mux == NULL) {
|
||||||
|
ESP_LOGE(TAG, "state_mux create error");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
xSemaphoreGive(repl_com->state_mux);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strong definition of the weak definition of esp_console_common_deinit
|
||||||
|
* in esp_console_common to allow the use of select with non blocking
|
||||||
|
* read. This function is compiled only if esp_console_stop_repl
|
||||||
|
* is used. */
|
||||||
|
esp_err_t esp_console_common_deinit(esp_console_repl_com_t *repl_com)
|
||||||
|
{
|
||||||
|
// set the state to deinit to force the while loop in
|
||||||
|
// esp_console_repl_task to break
|
||||||
|
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
|
||||||
|
|
||||||
|
if (s_interrupt_reading_fd == -1) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nwrite = write(s_interrupt_reading_fd, &s_interrupt_reading_signal, sizeof(s_interrupt_reading_signal));
|
||||||
|
if (nwrite != sizeof(s_interrupt_reading_signal)) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for the task to notify that
|
||||||
|
// esp_console_repl_task returned
|
||||||
|
assert(repl_com->state_mux != NULL);
|
||||||
|
BaseType_t ret_val = xSemaphoreTake(repl_com->state_mux, portMAX_DELAY);
|
||||||
|
assert(ret_val == pdTRUE);
|
||||||
|
|
||||||
|
// delete the semaphore for the repl state
|
||||||
|
vSemaphoreDelete(repl_com->state_mux);
|
||||||
|
repl_com->state_mux = NULL;
|
||||||
|
|
||||||
|
/* Unregister the heap function to avoid memory leak, since it is created
|
||||||
|
* every time a console init is called. */
|
||||||
|
esp_err_t ret = esp_console_deregister_help_command();
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unregister eventfd to avoid memory leaks, since it is created every time a
|
||||||
|
* console init is called */
|
||||||
|
ret = esp_vfs_eventfd_unregister();
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free the history to avoid memory leak, since it is created
|
||||||
|
* every time a console init is called. */
|
||||||
|
linenoiseHistoryFree();
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||||
|
|
||||||
|
/* DO NOT move this function out of this file. All other definitions in this
|
||||||
|
* file are strong definition of weak functions.
|
||||||
|
*
|
||||||
|
* Those function are used to provide a clean way to exit linenoise
|
||||||
|
* and properly deinitialize the console by using select with non blocking
|
||||||
|
* read instead of blocking read as the default way to read character implemented
|
||||||
|
* in linenoise.
|
||||||
|
*
|
||||||
|
* If the user never calls this function, then the default read process is used and
|
||||||
|
* those functions will be ignored by the linker. */
|
||||||
|
esp_err_t esp_console_stop_repl(esp_console_repl_t *repl)
|
||||||
|
{
|
||||||
|
return repl->del(repl);
|
||||||
|
}
|
@@ -116,14 +116,12 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/fcntl.h>
|
#include <sys/fcntl.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "linenoise.h"
|
#include "linenoise.h"
|
||||||
|
|
||||||
@@ -145,9 +143,6 @@ static int history_len = 0;
|
|||||||
static char **history = NULL;
|
static char **history = NULL;
|
||||||
static bool allow_empty = true;
|
static bool allow_empty = true;
|
||||||
|
|
||||||
static int intr_reading_fd = -1;
|
|
||||||
static uint64_t intr_reading_signal = -1;
|
|
||||||
|
|
||||||
/* The linenoiseState structure represents the state during line editing.
|
/* The linenoiseState structure represents the state during line editing.
|
||||||
* We pass this state to functions implementing specific editing
|
* We pass this state to functions implementing specific editing
|
||||||
* functionalities. */
|
* functionalities. */
|
||||||
@@ -243,35 +238,21 @@ static void flushWrite(void) {
|
|||||||
fsync(fileno(stdout));
|
fsync(fileno(stdout));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int linenoiseReadBytes(int fd, void *buf, size_t max_bytes)
|
static linenoise_read_bytes_fn read_func = NULL;
|
||||||
|
void linenoiseSetReadFunction(linenoise_read_bytes_fn read_fn)
|
||||||
{
|
{
|
||||||
fd_set read_fds;
|
read_func = read_fn;
|
||||||
FD_ZERO(&read_fds);
|
}
|
||||||
FD_SET(fd, &read_fds);
|
|
||||||
if (intr_reading_fd !=-1) {
|
|
||||||
FD_SET(intr_reading_fd, &read_fds);
|
|
||||||
}
|
|
||||||
int maxFd = MAX(fd, intr_reading_fd);
|
|
||||||
/* call select to wait for either a read ready or an except to happen */
|
|
||||||
int nread = select(maxFd + 1, &read_fds, NULL, NULL, NULL);
|
|
||||||
if (nread < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(FD_ISSET(intr_reading_fd, &read_fds)) {
|
__attribute__((weak)) void linenoiseSetReadCharacteristics(void)
|
||||||
/* read termination request happened, return */
|
{
|
||||||
int buf[sizeof(intr_reading_signal)];
|
/* By default linenoise uses blocking reads */
|
||||||
nread = read(intr_reading_fd, buf, sizeof(intr_reading_signal));
|
int stdin_fileno = fileno(stdin);
|
||||||
if ((nread == sizeof(intr_reading_signal)) && (buf[0] == intr_reading_signal)) {
|
int flags = fcntl(stdin_fileno, F_GETFL);
|
||||||
return -1;
|
flags &= ~O_NONBLOCK;
|
||||||
}
|
(void)fcntl(stdin_fileno, F_SETFL, flags);
|
||||||
}
|
|
||||||
else if(FD_ISSET(fd, &read_fds)) {
|
linenoiseSetReadFunction(read);
|
||||||
/* a read ready triggered the select to return. call the
|
|
||||||
* read function with the number of bytes max_bytes */
|
|
||||||
nread = read(fd, buf, max_bytes);
|
|
||||||
}
|
|
||||||
return nread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the ESC [6n escape sequence to query the horizontal cursor position
|
/* Use the ESC [6n escape sequence to query the horizontal cursor position
|
||||||
@@ -308,7 +289,7 @@ static int getCursorPosition(void) {
|
|||||||
/* Keep using unistd's functions. Here, using `read` instead of `fgets`
|
/* Keep using unistd's functions. Here, using `read` instead of `fgets`
|
||||||
* or `fgets` guarantees us that we we can read a byte regardless on
|
* or `fgets` guarantees us that we we can read a byte regardless on
|
||||||
* whether the sender sent end of line character(s) (CR, CRLF, LF). */
|
* whether the sender sent end of line character(s) (CR, CRLF, LF). */
|
||||||
if (linenoiseReadBytes(in_fd, buf + i, 1) != 1 || buf[i] == 'R') {
|
if (read_func(in_fd, buf + i, 1) != 1 || buf[i] == 'R') {
|
||||||
/* If we couldn't read a byte from STDIN or if 'R' was received,
|
/* If we couldn't read a byte from STDIN or if 'R' was received,
|
||||||
* the transmission is finished. */
|
* the transmission is finished. */
|
||||||
break;
|
break;
|
||||||
@@ -448,7 +429,7 @@ static int completeLine(struct linenoiseState *ls) {
|
|||||||
refreshLine(ls);
|
refreshLine(ls);
|
||||||
}
|
}
|
||||||
|
|
||||||
nread = linenoiseReadBytes(in_fd, &c, 1);
|
nread = read_func(in_fd, &c, 1);
|
||||||
if (nread <= 0) {
|
if (nread <= 0) {
|
||||||
freeCompletions(&lc);
|
freeCompletions(&lc);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -491,12 +472,6 @@ void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
|
|||||||
hintsCallback = fn;
|
hintsCallback = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void linenoiseSetInterruptReadingData(int fd, uint64_t data)
|
|
||||||
{
|
|
||||||
intr_reading_fd = fd;
|
|
||||||
intr_reading_signal = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register a function to free the hints returned by the hints callback
|
/* Register a function to free the hints returned by the hints callback
|
||||||
* registered with linenoiseSetHintsCallback(). */
|
* registered with linenoiseSetHintsCallback(). */
|
||||||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
|
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
|
||||||
@@ -942,7 +917,7 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
|
|||||||
* about 40ms (or even more)
|
* about 40ms (or even more)
|
||||||
*/
|
*/
|
||||||
t1 = getMillis();
|
t1 = getMillis();
|
||||||
int nread = linenoiseReadBytes(in_fd, &c, 1);
|
int nread = read_func(in_fd, &c, 1);
|
||||||
if (nread <= 0) {
|
if (nread <= 0) {
|
||||||
return l.len;
|
return l.len;
|
||||||
}
|
}
|
||||||
@@ -1047,14 +1022,14 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
|
|||||||
case ESC: { /* escape sequence */
|
case ESC: { /* escape sequence */
|
||||||
/* ESC [ sequences. */
|
/* ESC [ sequences. */
|
||||||
char seq[3];
|
char seq[3];
|
||||||
int r = linenoiseReadBytes(in_fd, seq, 2);
|
int r = read_func(in_fd, seq, 2);
|
||||||
if (r != 2) {
|
if (r != 2) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (seq[0] == '[') {
|
if (seq[0] == '[') {
|
||||||
if (seq[1] >= '0' && seq[1] <= '9') {
|
if (seq[1] >= '0' && seq[1] <= '9') {
|
||||||
/* Extended escape, read additional byte. */
|
/* Extended escape, read additional byte. */
|
||||||
r = linenoiseReadBytes(in_fd, seq + 2, 1);
|
r = read_func(in_fd, seq + 2, 1);
|
||||||
if (r != 1) {
|
if (r != 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1115,11 +1090,13 @@ void linenoiseAllowEmpty(bool val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int linenoiseProbe(void) {
|
int linenoiseProbe(void) {
|
||||||
/* Switch to non-blocking mode */
|
linenoiseSetReadCharacteristics();
|
||||||
|
|
||||||
|
/* Make sure we are in non blocking mode */
|
||||||
int stdin_fileno = fileno(stdin);
|
int stdin_fileno = fileno(stdin);
|
||||||
int flags = fcntl(stdin_fileno, F_GETFL);
|
int old_flags = fcntl(stdin_fileno, F_GETFL);
|
||||||
flags |= O_NONBLOCK;
|
int new_flags = old_flags | O_NONBLOCK;
|
||||||
int res = fcntl(stdin_fileno, F_SETFL, flags);
|
int res = fcntl(stdin_fileno, F_SETFL, new_flags);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1146,6 +1123,12 @@ int linenoiseProbe(void) {
|
|||||||
read_bytes += cb;
|
read_bytes += cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Switch back to whatever mode we had before the function call */
|
||||||
|
res = fcntl(stdin_fileno, F_SETFL, old_flags);
|
||||||
|
if (res != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (read_bytes < 4) {
|
if (read_bytes < 4) {
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
@@ -1177,7 +1160,7 @@ static int linenoiseDumb(char* buf, size_t buflen, const char* prompt) {
|
|||||||
|
|
||||||
while (count < buflen) {
|
while (count < buflen) {
|
||||||
|
|
||||||
int nread = linenoiseReadBytes(in_fd, &c, 1);
|
int nread = read_func(in_fd, &c, 1);
|
||||||
if (nread < 0) {
|
if (nread < 0) {
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
@@ -43,6 +43,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -58,7 +60,6 @@ typedef void(linenoiseFreeHintsCallback)(void *);
|
|||||||
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
||||||
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
||||||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
||||||
void linenoiseSetInterruptReadingData(int, uint64_t);
|
|
||||||
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||||
|
|
||||||
int linenoiseProbe(void);
|
int linenoiseProbe(void);
|
||||||
@@ -77,6 +78,10 @@ void linenoisePrintKeyCodes(void);
|
|||||||
void linenoiseAllowEmpty(bool);
|
void linenoiseAllowEmpty(bool);
|
||||||
int linenoiseSetMaxLineLen(size_t len);
|
int linenoiseSetMaxLineLen(size_t len);
|
||||||
|
|
||||||
|
typedef ssize_t (*linenoise_read_bytes_fn)(int, void*, size_t);
|
||||||
|
void linenoiseSetReadFunction(linenoise_read_bytes_fn read_fn);
|
||||||
|
void linenoiseSetReadCharacteristics(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -47,9 +47,9 @@ typedef struct {
|
|||||||
void esp_console_repl_task(void *args);
|
void esp_console_repl_task(void *args);
|
||||||
|
|
||||||
esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com);
|
esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com);
|
||||||
void esp_console_common_deinit(esp_console_repl_com_t *repl_com);
|
esp_err_t esp_console_common_deinit(esp_console_repl_com_t *repl_com);
|
||||||
|
esp_err_t esp_console_internal_set_event_fd(esp_console_repl_com_t *repl_com);
|
||||||
esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com);
|
esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com);
|
||||||
esp_err_t esp_console_setup_history(const char *history_path,
|
esp_err_t esp_console_setup_history(const char *history_path,
|
||||||
uint32_t max_history_len,
|
uint32_t max_history_len,
|
||||||
esp_console_repl_com_t *repl_com);
|
esp_console_repl_com_t *repl_com);
|
||||||
esp_err_t esp_console_interrupt_reading(void);
|
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#include "linenoise/linenoise.h"
|
#include "linenoise/linenoise.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: Most of these unit tests DO NOT work standalone. They require pytest to control
|
* NOTE: Most of these unit tests DO NOT work standalone. They require pytest to control
|
||||||
@@ -24,6 +25,8 @@
|
|||||||
* https://docs.espressif.com/projects/esp-idf/en/latest/esp32/contribute/esp-idf-tests-with-pytest.html.
|
* https://docs.espressif.com/projects/esp-idf/en/latest/esp32/contribute/esp-idf-tests-with-pytest.html.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
extern void set_leak_threshold(int threshold);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *in;
|
const char *in;
|
||||||
const char *out;
|
const char *out;
|
||||||
@@ -123,12 +126,17 @@ TEST_CASE("esp console init/deinit with context test", "[console]")
|
|||||||
TEST_ESP_OK(esp_console_deinit());
|
TEST_ESP_OK(esp_console_deinit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool can_terminate = false;
|
||||||
|
static SemaphoreHandle_t s_test_console_mutex = NULL;
|
||||||
|
static StaticSemaphore_t s_test_console_mutex_buf;
|
||||||
|
|
||||||
/* handle 'quit' command */
|
/* handle 'quit' command */
|
||||||
static int do_cmd_quit(int argc, char **argv)
|
static int do_cmd_quit(int argc, char **argv)
|
||||||
{
|
{
|
||||||
printf("ByeBye\r\n");
|
TEST_ASSERT_NOT_NULL(s_test_console_mutex);
|
||||||
TEST_ESP_OK(s_repl->del(s_repl));
|
xSemaphoreTake(s_test_console_mutex, portMAX_DELAY);
|
||||||
linenoiseHistoryFree(); // Free up memory
|
can_terminate = true;
|
||||||
|
xSemaphoreGive(s_test_console_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -144,6 +152,11 @@ static esp_console_cmd_t s_quit_cmd = {
|
|||||||
ran separately in test_console_repl */
|
ran separately in test_console_repl */
|
||||||
TEST_CASE("esp console repl test", "[console][ignore]")
|
TEST_CASE("esp console repl test", "[console][ignore]")
|
||||||
{
|
{
|
||||||
|
set_leak_threshold(400);
|
||||||
|
|
||||||
|
s_test_console_mutex = xSemaphoreCreateMutexStatic(&s_test_console_mutex_buf);
|
||||||
|
TEST_ASSERT_NOT_NULL(s_test_console_mutex);
|
||||||
|
|
||||||
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
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();
|
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
||||||
TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
|
TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
|
||||||
@@ -151,10 +164,29 @@ TEST_CASE("esp console repl test", "[console][ignore]")
|
|||||||
TEST_ESP_OK(esp_console_cmd_register(&s_quit_cmd));
|
TEST_ESP_OK(esp_console_cmd_register(&s_quit_cmd));
|
||||||
|
|
||||||
TEST_ESP_OK(esp_console_start_repl(s_repl));
|
TEST_ESP_OK(esp_console_start_repl(s_repl));
|
||||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
|
||||||
|
bool temp_can_terminate = false;
|
||||||
|
do {
|
||||||
|
xSemaphoreTake(s_test_console_mutex, portMAX_DELAY);
|
||||||
|
temp_can_terminate = can_terminate;
|
||||||
|
xSemaphoreGive(s_test_console_mutex);
|
||||||
|
} while (temp_can_terminate != true);
|
||||||
|
|
||||||
|
/* Wait to make sure the command has finished its execution */
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
|
esp_err_t ret = esp_console_stop_repl(s_repl);
|
||||||
|
TEST_ESP_OK(ret);
|
||||||
|
|
||||||
|
xSemaphoreTake(s_test_console_mutex, portMAX_DELAY);
|
||||||
|
can_terminate = false;
|
||||||
|
xSemaphoreGive(s_test_console_mutex);
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
|
printf("ByeBye\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void set_leak_threshold(int threshold);
|
|
||||||
TEST_CASE("esp console repl deinit", "[console][ignore]")
|
TEST_CASE("esp console repl deinit", "[console][ignore]")
|
||||||
{
|
{
|
||||||
set_leak_threshold(400);
|
set_leak_threshold(400);
|
||||||
@@ -168,14 +200,12 @@ TEST_CASE("esp console repl deinit", "[console][ignore]")
|
|||||||
|
|
||||||
/* wait to make sure the task reaches linenoiseEdit function
|
/* wait to make sure the task reaches linenoiseEdit function
|
||||||
* and gets stuck in the select */
|
* and gets stuck in the select */
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
/* call the delete function, this returns only when the repl task terminated */
|
/* call the delete function, this returns only when the repl task terminated */
|
||||||
const esp_err_t res = s_repl->del(s_repl);
|
const esp_err_t res = esp_console_stop_repl(s_repl);
|
||||||
|
|
||||||
/* wait to make sure the task reaches linenoiseEdit function
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
* and gets stuck in the select */
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
|
||||||
|
|
||||||
/* if this point is reached, the repl environment has been deleted successfully */
|
/* if this point is reached, the repl environment has been deleted successfully */
|
||||||
TEST_ASSERT(res == ESP_OK);
|
TEST_ASSERT(res == ESP_OK);
|
||||||
|
@@ -51,6 +51,14 @@ Linenoise library does not need explicit initialization. However, some configura
|
|||||||
|
|
||||||
Set maximum length of the line for linenoise library. Default length is 4096 bytes. The default value can be updated to optimize RAM memory usage.
|
Set maximum length of the line for linenoise library. Default length is 4096 bytes. The default value can be updated to optimize RAM memory usage.
|
||||||
|
|
||||||
|
- :cpp:func:`linenoiseSetReadFunction`
|
||||||
|
|
||||||
|
Set the read function to be used by linenoise.
|
||||||
|
|
||||||
|
- :cpp:func:`linenoiseSetReadCharacteristics`
|
||||||
|
|
||||||
|
Set the characteristics of the read file descriptor (e.g., blocking or non blocking mode). The function has a weak definition in linenoise.c that can be overridden
|
||||||
|
by providing a strong definition of the function.
|
||||||
|
|
||||||
Main Loop
|
Main Loop
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
@@ -274,7 +274,7 @@ static int console_exit(int argc, char **argv)
|
|||||||
tinyusb_msc_storage_deinit();
|
tinyusb_msc_storage_deinit();
|
||||||
tinyusb_driver_uninstall();
|
tinyusb_driver_uninstall();
|
||||||
printf("Application Exit\n");
|
printf("Application Exit\n");
|
||||||
repl->del(repl);
|
esp_console_stop_repl(repl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -201,24 +201,6 @@ static void register_ping(void)
|
|||||||
|
|
||||||
static esp_console_repl_t *s_repl = NULL;
|
static esp_console_repl_t *s_repl = NULL;
|
||||||
|
|
||||||
/* handle 'quit' command */
|
|
||||||
static int do_cmd_quit(int argc, char **argv)
|
|
||||||
{
|
|
||||||
printf("ByeBye\r\n");
|
|
||||||
s_repl->del(s_repl);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t register_quit(void)
|
|
||||||
{
|
|
||||||
esp_console_cmd_t command = {
|
|
||||||
.command = "quit",
|
|
||||||
.help = "Quit REPL environment",
|
|
||||||
.func = &do_cmd_quit
|
|
||||||
};
|
|
||||||
return esp_console_cmd_register(&command);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
ESP_ERROR_CHECK(nvs_flash_init());
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
@@ -256,8 +238,6 @@ void app_main(void)
|
|||||||
|
|
||||||
/* register command `ping` */
|
/* register command `ping` */
|
||||||
register_ping();
|
register_ping();
|
||||||
/* register command `quit` */
|
|
||||||
register_quit();
|
|
||||||
|
|
||||||
// start console REPL
|
// start console REPL
|
||||||
ESP_ERROR_CHECK(esp_console_start_repl(s_repl));
|
ESP_ERROR_CHECK(esp_console_start_repl(s_repl));
|
||||||
|
Reference in New Issue
Block a user