console: simplify examples

1. simplify console examples
2. add "quit" command
3. support console command overwrite
4. add API reference
This commit is contained in:
suda-morris 2020-02-03 18:01:04 +08:00
parent 13623ef430
commit 75cadc2e41
31 changed files with 794 additions and 1288 deletions

View file

@ -1,4 +1,5 @@
idf_component_register(SRCS "commands.c"
"esp_console_repl.c"
"split_argv.c"
"argtable3/argtable3.c"
"linenoise/linenoise.c"

View file

@ -1,4 +1,4 @@
// Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -18,6 +18,7 @@
#include <sys/param.h>
#include "esp_log.h"
#include "esp_console.h"
#include "esp_system.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "sys/queue.h"
@ -56,6 +57,9 @@ static const cmd_item_t *find_command_by_name(const char *name);
esp_err_t esp_console_init(const esp_console_config_t *config)
{
if (!config) {
return ESP_ERR_INVALID_ARG;
}
if (s_tmp_line_buf) {
return ESP_ERR_INVALID_STATE;
}
@ -76,8 +80,10 @@ esp_err_t esp_console_deinit(void)
return ESP_ERR_INVALID_STATE;
}
free(s_tmp_line_buf);
s_tmp_line_buf = NULL;
cmd_item_t *it, *tmp;
SLIST_FOREACH_SAFE(it, &s_cmd_list, next, tmp) {
SLIST_REMOVE(&s_cmd_list, it, cmd_item_, next);
free(it->hint);
free(it);
}
@ -86,18 +92,25 @@ esp_err_t esp_console_deinit(void)
esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd)
{
cmd_item_t *item = (cmd_item_t *) calloc(1, sizeof(*item));
if (item == NULL) {
return ESP_ERR_NO_MEM;
}
if (cmd->command == NULL) {
free(item);
cmd_item_t *item = NULL;
if (!cmd || cmd->command == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (strchr(cmd->command, ' ') != NULL) {
free(item);
return ESP_ERR_INVALID_ARG;
}
item = (cmd_item_t *)find_command_by_name(cmd->command);
if (!item) {
// not registered before
item = calloc(1, sizeof(*item));
if (item == NULL) {
return ESP_ERR_NO_MEM;
}
} else {
// remove from list and free the old hint, because we will alloc new hint for the command
SLIST_REMOVE(&s_cmd_list, item, cmd_item_, next);
free(item->hint);
}
item->command = cmd->command;
item->help = cmd->help;
if (cmd->hint) {
@ -166,8 +179,10 @@ static const cmd_item_t *find_command_by_name(const char *name)
{
const cmd_item_t *cmd = NULL;
cmd_item_t *it;
int len = strlen(name);
SLIST_FOREACH(it, &s_cmd_list, next) {
if (strcmp(name, it->command) == 0) {
if (strlen(it->command) == len &&
strcmp(name, it->command) == 0) {
cmd = it;
break;
}
@ -231,7 +246,6 @@ static int help_command(int argc, char **argv)
return 0;
}
esp_err_t esp_console_register_help_command(void)
{
esp_console_cmd_t command = {

View file

@ -1,4 +1,4 @@
// Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -14,8 +14,7 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#include <stddef.h>
@ -34,34 +33,71 @@ typedef struct {
int hint_bold; //!< Set to 1 to print hint text in bold
} esp_console_config_t;
/**
* @brief Default console configuration value
*
*/
#define ESP_CONSOLE_CONFIG_DEFAULT() \
{ \
.max_cmdline_length = 256, \
.max_cmdline_args = 32, \
.hint_color = 39, \
.hint_bold = 0 \
}
/**
* @brief Parameters for console REPL (Read Eval Print Loop)
*
*/
typedef struct {
uint32_t max_history_len; //!< maximum length for the history
const char *history_save_path; //!< file path used to save history commands, set to NULL won't save to file system
uint32_t task_stack_size; //!< repl task stack size
uint32_t task_priority; //!< repl task priority
const char *prompt; //!< prompt (NULL represents default: "esp> ")
} esp_console_repl_config_t;
/**
* @brief Default console repl configuration value
*
*/
#define ESP_CONSOLE_REPL_CONFIG_DEFAULT() \
{ \
.max_history_len = 32, \
.history_save_path = NULL, \
.task_stack_size = 4096, \
.task_priority = 2, \
.prompt = NULL, \
}
/**
* @brief initialize console module
* Call this once before using other console module features
* @param config console configuration
* @note Call this once before using other console module features
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if out of memory
* - ESP_ERR_INVALID_STATE if already initialized
* - ESP_ERR_INVALID_ARG if the configuration is invalid
*/
esp_err_t esp_console_init(const esp_console_config_t* config);
esp_err_t esp_console_init(const esp_console_config_t *config);
/**
* @brief de-initialize console module
* Call this once when done using console module functions
* @note Call this once when done using console module functions
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if not initialized yet
*/
esp_err_t esp_console_deinit(void);
/**
* @brief Console command main function
* @param argc number of arguments
* @param argv array with argc entries, each pointing to a zero-terminated string argument
* @return console command return code, 0 indicates "success"
*/
typedef int (*esp_console_cmd_func_t)(int argc, char** argv);
typedef int (*esp_console_cmd_func_t)(int argc, char **argv);
/**
* @brief Console command description
@ -71,19 +107,19 @@ typedef struct {
* Command name. Must not be NULL, must not contain spaces.
* The pointer must be valid until the call to esp_console_deinit.
*/
const char* command; //!< command name
const char *command;
/**
* Help text for the command, shown by help command.
* If set, the pointer must be valid until the call to esp_console_deinit.
* If not set, the command will not be listed in 'help' output.
*/
const char* help;
const char *help;
/**
* Hint text, usually lists possible arguments.
* If set to NULL, and 'argtable' field is non-NULL, hint will be generated
* automatically
*/
const char* hint;
const char *hint;
/**
* Pointer to a function which implements the command.
*/
@ -94,7 +130,7 @@ typedef struct {
* Array/structure which this field points to must end with an arg_end.
* Only used for the duration of esp_console_cmd_register call.
*/
void* argtable;
void *argtable;
} esp_console_cmd_t;
/**
@ -103,6 +139,7 @@ typedef struct {
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if out of memory
* - ESP_ERR_INVALID_ARG if command description includes invalid arguments
*/
esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd);
@ -117,11 +154,11 @@ esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd);
* - ESP_ERR_NOT_FOUND, if command with given name wasn't registered
* - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called
*/
esp_err_t esp_console_run(const char* cmdline, int* cmd_ret);
esp_err_t esp_console_run(const char *cmdline, int *cmd_ret);
/**
* @brief Split command line into arguments in place
*
* @verbatim
* - This function finds whitespace-separated arguments in the given input line.
*
* 'abc def 1 20 .3' -> [ 'abc', 'def', '1', '20', '.3' ]
@ -134,8 +171,8 @@ esp_err_t esp_console_run(const char* cmdline, int* cmd_ret);
* - Escape sequences may be used to produce backslash, double quote, and space:
*
* 'a\ b\\c\"' -> [ 'a b\c"' ]
*
* Pointers to at most argv_size - 1 arguments are returned in argv array.
* @endverbatim
* @note Pointers to at most argv_size - 1 arguments are returned in argv array.
* The pointer after the last one (i.e. argv[argc]) is set to NULL.
*
* @param line pointer to buffer to parse; it is modified in place
@ -179,14 +216,58 @@ const char *esp_console_get_hint(const char *buf, int *color, int *bold);
/**
* @brief Register a 'help' command
*
* Default 'help' command prints the list of registered commands along with
* hints and help strings.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called
*/
esp_err_t esp_console_register_help_command(void);
/******************************************************************************
* Console REPL
******************************************************************************/
/**
* @brief Initialize console REPL environment
*
* @note This is a all-in-one function to establish the environment needed for REPL, includes:
* - Install the UART driver on the console UART (8n1, 115200, REF_TICK clock source)
* - Configures the stdin/stdout to go through the UART driver
* - 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_repl_init(const esp_console_repl_config_t *config);
/**
* @brief Start REPL task
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE, if repl has started already
*/
esp_err_t esp_console_repl_start(void);
/**
* @brief Register a 'quit' command
*
* Default 'quit' command will destory resources and exit REPL environment.
*
* @return
* - ESP_OK on success
* - others on failed
*/
esp_err_t esp_console_register_quit_command(void);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,284 @@
// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD
//
// 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.
#include <stdint.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "linenoise/linenoise.h"
static const char *TAG = "console.repl";
#define CONSOLE_PROMPT_LEN_MAX (32)
typedef enum {
CONSOLE_REPL_STATE_DEINIT,
CONSOLE_REPL_STATE_INIT,
CONSOLE_REPL_STATE_START,
} repl_state_t;
static repl_state_t s_repl_state = CONSOLE_REPL_STATE_DEINIT;
/**
* @brief Prompt to be printed before each line.
*
*/
static char s_prompt[CONSOLE_PROMPT_LEN_MAX];
/**
* @brief path to save history commands in file system
*
*/
static const char *s_history_save_path = NULL;
/**
* @brief REPL task handle
*
*/
static TaskHandle_t s_repl_task_hdl = NULL;
static void esp_console_repl_thread(void *param)
{
// waiting for task notify
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
while (s_repl_state == CONSOLE_REPL_STATE_START) {
char *line = linenoise(s_prompt);
if (line == NULL) {
ESP_LOGD(TAG, "empty line");
/* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
/* Save command history to filesystem */
if (s_history_save_path) {
linenoiseHistorySave(s_history_save_path);
}
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret));
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
ESP_LOGD(TAG, "The End");
vTaskDelete(NULL);
}
esp_err_t esp_console_repl_init(const esp_console_repl_config_t *config)
{
esp_err_t ret = ESP_OK;
if (!config) {
ret = ESP_ERR_INVALID_ARG;
goto _exit;
}
// check if already initialized
if (s_repl_state != CONSOLE_REPL_STATE_DEINIT) {
ESP_LOGE(TAG, "already initialized");
ret = ESP_ERR_INVALID_STATE;
goto _exit;
}
/* Drain stdout before reconfiguring it */
fflush(stdout);
fsync(fileno(stdout));
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
* correct while APB frequency is changing in light sleep mode.
*/
const uart_config_t uart_config = {
.baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.source_clk = UART_SCLK_REF_TICK,
};
/* Install UART driver for interrupt-driven reads and writes */
ret = uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0);
if (ret != ESP_OK) {
goto _exit;
}
uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config);
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = ESP_CONSOLE_CONFIG_DEFAULT();
#if CONFIG_LOG_COLORS
console_config.hint_color = atoi(LOG_COLOR_CYAN);
#endif
ret = esp_console_init(&console_config);
if (ret != ESP_OK) {
goto _console_del;
}
ret = esp_console_register_help_command();
if (ret != ESP_OK) {
goto _console_del;
}
ret = esp_console_register_quit_command();
if (ret != ESP_OK) {
goto _console_del;
}
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within single line */
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
if (config->history_save_path) {
s_history_save_path = config->history_save_path;
/* Load command history from filesystem */
linenoiseHistoryLoad(s_history_save_path);
}
/* Set command history size */
if (linenoiseHistorySetMaxLen(config->max_history_len) != 1) {
ESP_LOGE(TAG, "set max history length to %d failed", config->max_history_len);
ret = ESP_FAIL;
goto _console_del;
}
/* set command line prompt */
const char *prompt_temp = "esp>";
if (config->prompt) {
prompt_temp = config->prompt;
}
snprintf(s_prompt, CONSOLE_PROMPT_LEN_MAX - 1, LOG_COLOR_I "%s " LOG_RESET_COLOR, prompt_temp);
printf("\r\n"
"Type 'help' to get the list of commands.\r\n"
"Use UP/DOWN arrows to navigate through command history.\r\n"
"Press TAB when typing command name to auto-complete.\r\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) {
/* zero indicates success */
printf("\r\n"
"Your terminal application does not support escape sequences.\n\n"
"Line editing and history features are disabled.\n\n"
"On Windows, try using Putty instead.\r\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the s_prompt.
*/
snprintf(s_prompt, CONSOLE_PROMPT_LEN_MAX - 1, "%s ", prompt_temp);
#endif //CONFIG_LOG_COLORS
}
/* spawn a single thread to run REPL */
if (xTaskCreate(esp_console_repl_thread, "console_repl", config->task_stack_size,
NULL, config->task_priority, &s_repl_task_hdl) != pdTRUE) {
ret = ESP_FAIL;
goto _console_del;
}
s_repl_state = CONSOLE_REPL_STATE_INIT;
return ret;
_console_del:
esp_console_deinit();
esp_vfs_dev_uart_use_nonblocking(CONFIG_ESP_CONSOLE_UART_NUM);
uart_driver_delete(CONFIG_ESP_CONSOLE_UART_NUM);
s_repl_state = CONSOLE_REPL_STATE_DEINIT;
_exit:
return ret;
}
esp_err_t esp_console_repl_deinit(void)
{
esp_err_t ret = ESP_OK;
// check if already de-initialized
if (s_repl_state == CONSOLE_REPL_STATE_DEINIT) {
ESP_LOGE(TAG, "not initialized yet");
ret = ESP_ERR_INVALID_STATE;
goto _exit;
}
s_repl_state = CONSOLE_REPL_STATE_DEINIT;
esp_console_deinit();
esp_vfs_dev_uart_use_nonblocking(CONFIG_ESP_CONSOLE_UART_NUM);
uart_driver_delete(CONFIG_ESP_CONSOLE_UART_NUM);
s_repl_task_hdl = NULL;
s_history_save_path = NULL;
_exit:
return ret;
}
esp_err_t esp_console_repl_start(void)
{
esp_err_t ret = ESP_OK;
// check if already initialized
if (s_repl_state != CONSOLE_REPL_STATE_INIT) {
ret = ESP_ERR_INVALID_STATE;
goto _exit;
}
s_repl_state = CONSOLE_REPL_STATE_START;
xTaskNotifyGive(s_repl_task_hdl);
_exit:
return ret;
}
/* handle 'quit' command */
static int do_cmd_quit(int argc, char **argv)
{
printf("ByeBye\r\n");
esp_console_repl_deinit();
return 0;
}
esp_err_t esp_console_register_quit_command(void)
{
esp_console_cmd_t command = {
.command = "quit",
.help = "Quit REPL environment",
.func = &do_cmd_quit
};
return esp_console_cmd_register(&command);
}

View file

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS .
INCLUDE_DIRS .
PRIV_REQUIRES unity test_utils console)

View file

@ -0,0 +1,7 @@
#
#Component Makefile
#
COMPONENT_SRCDIRS := .
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View file

@ -0,0 +1,40 @@
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "unity.h"
#include "test_utils.h"
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static int do_hello_cmd(int argc, char **argv)
{
printf("Hello World\n");
return 0;
}
TEST_CASE("esp console init/deinit test", "[console]")
{
esp_console_config_t console_config = ESP_CONSOLE_CONFIG_DEFAULT();
TEST_ESP_OK(esp_console_init(&console_config));
const esp_console_cmd_t cmd = {
.command = "hello",
.help = "Print Hello World",
.hint = NULL,
.func = do_hello_cmd,
};
TEST_ESP_OK(esp_console_cmd_register(&cmd));
// re-register the same command, just for test
TEST_ESP_OK(esp_console_cmd_register(&cmd));
TEST_ESP_OK(esp_console_deinit());
}
// Enter "quit" to exit REPL environment
TEST_CASE("esp console repl test", "[console][ignore]")
{
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
TEST_ESP_OK(esp_console_repl_init(&repl_config));
TEST_ESP_OK(esp_console_repl_start());
vTaskDelay(pdMS_TO_TICKS(2000));
}

View file

@ -210,7 +210,9 @@ INPUT = \
##
## System - API Reference
##
## Memory Allocation #
## ESP Console
$(IDF_PATH)/components/console/esp_console.h \
## Memory Allocation
$(IDF_PATH)/components/heap/include/esp_heap_caps.h \
$(IDF_PATH)/components/heap/include/esp_heap_trace.h \
$(IDF_PATH)/components/heap/include/esp_heap_caps_init.h \

View file

@ -10,7 +10,6 @@ API Guides
Bootloader <bootloader>
Build System <build-system>
:esp32: Build System (Legacy GNU Make) <build-system-legacy>
Console Component <console>
Deep Sleep Wake Stubs <deep-sleep-stub>
Error Handling <error-handling>
:esp32: ESP-BLE-MESH <esp-ble-mesh/ble-mesh-index>

View file

@ -6,17 +6,22 @@ ESP-IDF provides ``console`` component, which includes building blocks needed to
- Line editing, provided by `linenoise`_ library. This includes handling of backspace and arrow keys, scrolling through command history, command auto-completion, and argument hints.
- Splitting of command line into arguments.
- Argument parsing, provided by `argtable3`_ library. This library includes APIs useful for parsing GNU style command line arguments.
- Argument parsing, provided by `argtable3`_ library. This library includes APIs used for parsing GNU style command line arguments.
- Functions for registration and dispatching of commands.
- Functions to establish a basic REPL (Read-Evaluate-Print-Loop) environment.
These facilities can be used together or independently. For example, it is possible to use line editing and command registration features, but use ``getopt`` or custom code for argument parsing, instead of `argtable3`_. Likewise, it is possible to use simpler means of command input (such as ``fgets``) together with the rest of the means for command splitting and argument parsing.
.. note::
These facilities can be used together or independently. For example, it is possible to use line editing and command registration features, but use ``getopt`` or custom code for argument parsing, instead of `argtable3`_. Likewise, it is possible to use simpler means of command input (such as ``fgets``) together with the rest of the means for command splitting and argument parsing.
Line editing
------------
Line editing feature lets users compose commands by typing them, erasing symbols using 'backspace' key, navigating within the command using left/right keys, navigating to previously typed commands using up/down keys, and performing autocompletion using 'tab' key.
.. note:: This feature relies on ANSI escape sequence support in the terminal application. As such, serial monitors which display raw UART data can not be used together with the line editing library. If you see ``[6n`` or similar escape sequence when running get_started/console example instead of a command prompt (``[{IDF_TARGET_PATH_NAME}]>``), it means that the serial monitor does not support escape sequences. Programs which are known to work are GNU screen, minicom, and idf_monitor.py (which can be invoked using ``idf.py monitor`` from project directory).
.. note::
This feature relies on ANSI escape sequence support in the terminal application. As such, serial monitors which display raw UART data can not be used together with the line editing library. If you see ``[6n`` or similar escape sequence when running :example:`system/console` example instead of a command prompt (e.g. ``esp> ``), it means that the serial monitor does not support escape sequences. Programs which are known to work are GNU screen, minicom, and idf_monitor.py (which can be invoked using ``idf.py monitor`` from project directory).
Here is an overview of functions provided by `linenoise`_ library.
@ -25,62 +30,62 @@ Configuration
Linenoise library does not need explicit initialization. However, some configuration defaults may need to be changed before invoking the main line editing function.
``linenoiseClearScreen``
:cpp:func:`linenoiseClearScreen`
Clear terminal screen using an escape sequence and position the cursor at the top left corner.
``linenoiseSetMultiLine``
:cpp:func:`linenoiseSetMultiLine`
Switch between single line and multi line editing modes. In single line mode, if the length of the command exceeds the width of the terminal, the command text is scrolled within the line to show the end of the text. In this case the beginning of the text is hidden. Single line needs less data to be sent to refresh screen on each key press, so exhibits less glitching compared to the multi line mode. On the flip side, editing commands and copying command text from terminal in single line mode is harder. Default is single line mode.
Main loop
^^^^^^^^^
``linenoise``
In most cases, console applications have some form of read/eval loop. ``linenoise`` is the single function which handles user's key presses and returns completed line once 'enter' key is pressed. As such, it handles the 'read' part of the loop.
:cpp:func:`linenoise`
In most cases, console applications have some form of read/eval loop. :cpp:func:`linenoise` is the single function which handles user's key presses and returns completed line once 'enter' key is pressed. As such, it handles the 'read' part of the loop.
``linenoiseFree``
This function must be called to release the command line buffer obtained from ``linenoise`` function.
:cpp:func:`linenoiseFree`
This function must be called to release the command line buffer obtained from :cpp:func:`linenoise` function.
Hints and completions
^^^^^^^^^^^^^^^^^^^^^
``linenoiseSetCompletionCallback``
When user presses 'tab' key, linenoise library invokes completion callback. The callback should inspect the contents of the command typed so far and provide a list of possible completions using calls to ``linenoiseAddCompletion`` function. ``linenoiseSetCompletionCallback`` function should be called to register this completion callback, if completion feature is desired.
:cpp:func:`linenoiseSetCompletionCallback`
When user presses 'tab' key, linenoise library invokes completion callback. The callback should inspect the contents of the command typed so far and provide a list of possible completions using calls to :cpp:func:`linenoiseAddCompletion` function. :cpp:func:`linenoiseSetCompletionCallback` function should be called to register this completion callback, if completion feature is desired.
``console`` component provides a ready made function to provide completions for registered commands, ``esp_console_get_completion`` (see below).
``console`` component provides a ready made function to provide completions for registered commands, :cpp:func:`esp_console_get_completion` (see below).
``linenoiseAddCompletion``
:cpp:func:`linenoiseAddCompletion`
Function to be called by completion callback to inform the library about possible completions of the currently typed command.
``linenoiseSetHintsCallback``
:cpp:func:`linenoiseSetHintsCallback`
Whenever user input changes, linenoise invokes hints callback. This callback can inspect the command line typed so far, and provide a string with hints (which can include list of command arguments, for example). The library then displays the hint text on the same line where editing happens, possibly with a different color.
``linenoiseSetFreeHintsCallback``
If hint string returned by hints callback is dynamically allocated or needs to be otherwise recycled, the function which performs such cleanup should be registered via ``linenoiseSetFreeHintsCallback``.
:cpp:func:`linenoiseSetFreeHintsCallback`
If hint string returned by hints callback is dynamically allocated or needs to be otherwise recycled, the function which performs such cleanup should be registered via :cpp:func:`linenoiseSetFreeHintsCallback`.
History
^^^^^^^
``linenoiseHistorySetMaxLen``
:cpp:func:`linenoiseHistorySetMaxLen`
This function sets the number of most recently typed commands to be kept in memory. Users can navigate the history using up/down arrows.
``linenoiseHistoryAdd``
:cpp:func:`linenoiseHistoryAdd`
Linenoise does not automatically add commands to history. Instead, applications need to call this function to add command strings to the history.
``linenoiseHistorySave``
:cpp:func:`linenoiseHistorySave`
Function saves command history from RAM to a text file, for example on an SD card or on a filesystem in flash memory.
``linenoiseHistoryLoad``
Counterpart to ``linenoiseHistorySave``, loads history from a file.
:cpp:func:`linenoiseHistoryLoad`
Counterpart to :cpp:func:`linenoiseHistorySave`, loads history from a file.
``linenoiseHistoryFree``
:cpp:func:`linenoiseHistoryFree`
Releases memory used to store command history. Call this function when done working with linenoise library.
Splitting of command line into arguments
----------------------------------------
``console`` component provides ``esp_console_split_argv`` function to split command line string into arguments. The function returns the number of arguments found (``argc``) and fills an array of pointers which can be passed as ``argv`` argument to any function which accepts arguments in ``argc, argv`` format.
``console`` component provides :cpp:func:`esp_console_split_argv` function to split command line string into arguments. The function returns the number of arguments found (``argc``) and fills an array of pointers which can be passed as ``argv`` argument to any function which accepts arguments in ``argc, argv`` format.
The command line is split into arguments according to the following rules:
@ -112,7 +117,7 @@ Command registration and dispatching
``console`` component includes utility functions which handle registration of commands, matching commands typed by the user to registered ones, and calling these commands with the arguments given on the command line.
Application first initializes command registration module using a call to ``esp_console_init``, and calls ``esp_console_cmd_register`` function to register command handlers.
Application first initializes command registration module using a call to :cpp:func:`esp_console_init`, and calls :cpp:func:`esp_console_cmd_register` function to register command handlers.
For each command, application provides the following information (in the form of ``esp_console_cmd_t`` structure):
@ -123,22 +128,35 @@ For each command, application provides the following information (in the form of
A few other functions are provided by the command registration module:
``esp_console_run``
This function takes the command line string, splits it into argc/argv argument list using ``esp_console_split_argv``, looks up the command in the list of registered components, and if it is found, executes its handler.
:cpp:func:`esp_console_run`
This function takes the command line string, splits it into argc/argv argument list using :cpp:func:`esp_console_split_argv`, looks up the command in the list of registered components, and if it is found, executes its handler.
``esp_console_register_help_command``
:cpp:func:`esp_console_register_help_command`
Adds ``help`` command to the list of registered commands. This command prints the list of all the registered commands, along with their arguments and help texts.
``esp_console_get_completion``
Callback function to be used with ``linenoiseSetCompletionCallback`` from linenoise library. Provides completions to linenoise based on the list of registered commands.
:cpp:func:`esp_console_get_completion`
Callback function to be used with :cpp:func:`linenoiseSetCompletionCallback` from linenoise library. Provides completions to linenoise based on the list of registered commands.
``esp_console_get_hint``
Callback function to be used with ``linenoiseSetHintsCallback`` from linenoise library. Provides argument hints for registered commands to linenoise.
:cpp:func:`esp_console_get_hint`
Callback function to be used with :cpp:func:`linenoiseSetHintsCallback` from linenoise library. Provides argument hints for registered commands to linenoise.
Example
-------
Initialize console REPL environment
-----------------------------------
Example application illustrating usage of the ``console`` component is available in ``examples/system/console`` directory. This example shows how to initialize UART and VFS functions, set up linenoise library, read and handle commands from UART, and store command history in Flash. See README.md in the example directory for more details.
To establish a basic REPL environment, ``console`` component provides several useful APIs, combining those functions described above.
In a typical application, you only need to call :cpp:func:`esp_console_repl_init` to initialize the REPL environment, including UART driver install, basic console configuration, spawning a thread to do REPL task and register several useful commands (e.g. `help`, `quit`).
After that, you can register your own commands with :cpp:func:`esp_console_cmd_register`. The REPL environment keeps in init state until you call :cpp:func:`esp_console_repl_start`.
Application Example
-------------------
Example application illustrating usage of the ``console`` component is available in :example:`system/console` directory. This example shows how to initialize UART and VFS functions, set up linenoise library, read and handle commands from UART, and store command history in Flash. See README.md in the example directory for more details.
Besides that, ESP-IDF contains several useful examples which based on `console` component and can be treated as "tools" when developing applications. For example, :example:`peripherals/i2c/i2c_tools`, :example:`wifi/iperf`.
API Reference
-------------
.. include-build-file:: inc/esp_console.inc

View file

@ -6,6 +6,7 @@ System API
App image format <app_image_format>
Application Level Tracing <app_trace>
Console Component <console>
eFuse Manager <efuse>
Error Codes and Helper Functions <esp_err>
ESP HTTPS OTA <esp_https_ota>

View file

@ -26,7 +26,6 @@ API 指南
单元测试 <unit-tests>
:esp32: 单元测试 (传统 GNU Make) <unit-tests-legacy>
应用层跟踪 <app_trace>
控制台终端组件 <console>
ROM debug console <romconsole>
:esp32: RF Calibration <RF_calibration>
WiFi Driver <wifi>

View file

@ -8,97 +8,108 @@ ESP-IDF 提供了 ``console`` 组件,它包含了开发基于串口的交互
- 将命令行拆分为参数列表。
- 参数解析,由 `argtable3 <http://www.argtable.org/>`_ 库具体实现,它支持解析 GNU 样式的命令行参数。
- 用于注册和调度命令的函数。
- 帮助创建 REPL (Read-Evaluate-Print-Loop) 环境的函数。
.. note::
这些功能模块可以一起使用也可以独立使用,例如仅使用行编辑和命令注册的功能,然后使用 ``getopt`` 函数或者自定义的函数来实现参数解析,而不是直接使用 `argtable3 <http://www.argtable.org/>`_ 库。同样地,还可以使用更简单的命令输入方法(比如 ``fgets`` 函数)和其他用于命令分割和参数解析的方法。
这些功能模块可以一起使用也可以独立使用,例如仅使用行编辑和命令注册的功能,然后使用 ``getopt`` 函数或者自定义的函数来实现参数解析,而不是直接使用 `argtable3 <http://www.argtable.org/>`_ 库。同样地,还可以使用更简单的命令输入方法(比如 ``fgets`` 函数)和其他用于命令分割和参数解析的方法。
行编辑
------
行编辑功能允许用户通过按键输入来编辑命令,使用退格键删除符号,使用左/右键在命令中移动光标,使用上/下键导航到之前输入的命令使用制表键“Tab”来自动补全命令。
.. note:: 此功能依赖于终端应用程序对 ANSI 转移符的支持,显示原始 UART 数据的串口监视器不能与行编辑库一同使用。如果运行 get_started/console 示例程序的时候观察到的输出结果是 ``[6n`` 或者类似的转义字符而不是命令行提示符 ``[{IDFT_TARGET_PATH_NAME}]>`` 时,就表明当前的串口监视器不支持 ANSI 转移字符。已知可用的串口监视程序有 GNU screenminicom 和 idf_monitor.py可以通过在项目目录下执行 ``idf.py monitor`` 来调用)。
.. note::
此功能依赖于终端应用程序对 ANSI 转移符的支持,显示原始 UART 数据的串口监视器不能与行编辑库一同使用。如果运行 :example:`system/console` 示例程序的时候观察到的输出结果是 ``[6n`` 或者类似的转义字符而不是命令行提示符 ``esp> `` 时,就表明当前的串口监视器不支持 ANSI 转移字符。已知可用的串口监视程序有 GNU screenminicom 和 idf_monitor.py可以通过在项目目录下执行 ``idf.py monitor`` 来调用)。
前往这里可以查看 `linenoise <https://github.com/antirez/linenoise>`_ 库提供的所有函数的描述。
配置
~~~~
^^^^
Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前,可能需要对某些配置的默认值稍作修改。
``linenoiseClearScreen``
:cpp:func:`linenoiseClearScreen`
使用转移字符清除终端屏幕,并将光标定位在左上角。
``linenoiseSetMultiLine``
:cpp:func:`linenoiseSetMultiLine`
在单行和多行编辑模式之间进行切换。单行模式下,如果命令的长度超过终端的宽度,会在行内滚动命令文本以显示文本的结尾,在这种情况下,文本的开头部分会被隐藏。单行模式在每次按下按键时发送给屏幕刷新的数据比较少,与多行模式相比更不容易发生故障。另一方面,在单行模式下编辑命令和复制命令将变得更加困难。默认情况下开启的是单行模式。
主循环
~~~~~~
^^^^^^
``linenoise``
:cpp:func:`linenoise`
在大多数情况下,控制台应用程序都会具有相同的工作形式——在某个循环中不断读取输入的内容,然后解析再处理。 ``linenoise`` 是专门用来获取用户按键输入的函数,当回车键被按下后会便返回完整的一行内容。因此可以用它来完成前面循环中的“读取”任务。
在大多数情况下,控制台应用程序都会具有相同的工作形式——在某个循环中不断读取输入的内容,然后解析再处理。 :cpp:func:`linenoise` 是专门用来获取用户按键输入的函数,当回车键被按下后会便返回完整的一行内容。因此可以用它来完成前面循环中的“读取”任务。
``linenoiseFree``
:cpp:func:`linenoiseFree`
必须调用此函数才能释放从 :cpp:func:`linenoise` 函数获取的命令行缓冲。
必须调用此函数才能释放从 ``linenoise`` 函数获取的命令行缓冲。
提示和补全
~~~~~~~~~~
^^^^^^^^^^
``linenoiseSetCompletionCallback``
:cpp:func:`linenoiseSetCompletionCallback`
当用户按下制表键时, linenoise 会调用 **补全回调函数** ,该回调函数会检查当前已经输入的内容,然后调用 ``linenoiseAddCompletion`` 函数来提供所有可能的补全后的命令列表。启用补全功能,需要事先调用 ``linenoiseSetCompletionCallback`` 函数来注册补全回调函数。
当用户按下制表键时, linenoise 会调用 **补全回调函数** ,该回调函数会检查当前已经输入的内容,然后调用 :cpp:func:`linenoiseAddCompletion` 函数来提供所有可能的补全后的命令列表。启用补全功能,需要事先调用 :cpp:func:`linenoiseSetCompletionCallback` 函数来注册补全回调函数。
``console`` 组件提供了一个现成的函数来为注册的命令提供补全功能 ``esp_console_get_completion`` (见后文)。
``console`` 组件提供了一个现成的函数来为注册的命令提供补全功能 :cpp:func:`esp_console_get_completion` (见下文)。
``linenoiseAddCompletion``
:cpp:func:`linenoiseAddCompletion`
补全回调函数会通过调用此函数来通知 linenoise 库当前键入命令所有可能的补全结果。
``linenoiseSetHintsCallback``
:cpp:func:`linenoiseSetHintsCallback`
每当用户的输入改变时, linenoise 就会调用此回调函数,检查到目前为止输入的命令行内容,然后提供带有提示信息的字符串(例如命令参数列表),然后会在同一行上用不同的颜色显示出该文本。
``linenoiseSetFreeHintsCallback``
:cpp:func:`linenoiseSetFreeHintsCallback`
如果 **提示回调函数** 返回的提示字符串是动态分配的或者需要以其它方式回收,就需要使用 :cpp:func:`linenoiseSetFreeHintsCallback` 注册具体的清理函数。
如果 **提示回调函数** 返回的提示字符串是动态分配的或者需要以其它方式回收,就需要使用 ``linenoiseSetFreeHintsCallback`` 注册具体的清理函数。
历史记录
~~~~~~~~
^^^^^^^^
``linenoiseHistorySetMaxLen``
:cpp:func:`linenoiseHistorySetMaxLen`
该函数设置要保留在内存中的最近输入的命令的数量。用户通过使用向上/向下箭头来导航历史记录。
``linenoiseHistoryAdd``
:cpp:func:`linenoiseHistoryAdd`
Linenoise 不会自动向历史记录中添加命令,应用程序需要调用此函数来将命令字符串添加到历史记录中。
``linenoiseHistorySave``
:cpp:func:`linenoiseHistorySave`
该函数将命令的历史记录从 RAM 中保存为文本文件,例如保存到 SD 卡或者 Flash 的文件系统中。
``linenoiseHistoryLoad``
:cpp:func:`linenoiseHistoryLoad`
``linenoiseHistorySave`` 相对应,从文件中加载历史记录。
``linenoiseHistoryFree``
:cpp:func:`linenoiseHistoryFree`
释放用于存储命令历史记录的内存。当使用完 linenoise 库后需要调用此函数。
将命令行拆分成参数列表
----------------------
``console`` 组件提供 ``esp_console_split_argv`` 函数来将命令行字符串拆分为参数列表。该函数会返回参数的数量(``argc``)和一个指针数组,该指针数组可以作为 ``argv`` 参数传递给任何接受 ``argcargv`` 格式参数的函数。
``console`` 组件提供 :cpp:func:`esp_console_split_argv` 函数来将命令行字符串拆分为参数列表。该函数会返回参数的数量(``argc``)和一个指针数组,该指针数组可以作为 ``argv`` 参数传递给任何接受 ``argcargv`` 格式参数的函数。
根据以下规则来将命令行拆分成参数列表:
- 参数由空格分隔
- 如果参数本身需要使用空格,可以使用 ``\`` (反斜杠)对它们进行转义
- 其它能被识别的转义字符有 ``\\`` (显示反斜杠本身)和 ``\"`` (显示双引号)
- 可以使用双引号来引用参数,引号只可能出现在参数的开头和结尾。参数中的引号必须如上所述进行转移。参数周围的引号会被 ``esp_console_split_argv`` 函数删除
- 可以使用双引号来引用参数,引号只可能出现在参数的开头和结尾。参数中的引号必须如上所述进行转移。参数周围的引号会被 :cpp:func:`esp_console_split_argv` 函数删除
示例:
@ -106,17 +117,19 @@ Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前
- ``abc "123 456" def`` ⟶ [ ``abc``, ``123 456``, ``def`` ]
- ```a\ b\\c\"`` ⟶ [ ``a b\c"`` ]
参数解析
--------
对于参数解析,``console`` 组件使用 `argtable3 <http://www.argtable.org/>`_ 库。有关 `argtable3 <http://www.argtable.org/>`_ 的介绍请查看 `教程 <http://www.argtable.org/tutorial/>`_ 或者 Github 仓库中的 `示例代码 <https://github.com/argtable/argtable3/tree/master/examples>`_
命令的注册与调度
----------------
``console`` 组件包含了一些工具函数,用来注册命令,将用户输入的命令和已经注册的命令进行匹配,使用命令行输入的参数调用命令。
应用程序首先调用 ``esp_console_init`` 来初始化命令注册模块,然后调用 ``esp_console_cmd_register`` 函数注册命令处理程序。
应用程序首先调用 :cpp:func:`esp_console_init` 来初始化命令注册模块,然后调用 :cpp:func:`esp_console_cmd_register` 函数注册命令处理程序。
对于每个命令,应用程序需要提供以下信息(需要以 ``esp_console_cmd_t`` 结构体的形式给出):
@ -127,23 +140,42 @@ Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前
命令注册模块还提供了其它函数:
``esp_console_run``
:cpp:func:`esp_console_run`
该函数接受命令行字符串,使用 ``esp_console_split_argv`` 函数将其拆分为 argc/argv 形式的参数列表,在已经注册的组件列表中查找命令,如果找到,则执行其对应的处理程序。
该函数接受命令行字符串,使用 :cpp:func:`esp_console_split_argv` 函数将其拆分为 argc/argv 形式的参数列表,在已经注册的组件列表中查找命令,如果找到,则执行其对应的处理程序。
``esp_console_register_help_command``
:cpp:func:`esp_console_register_help_command`
``help`` 命令添加到已注册命令列表中,此命令将会以列表的方式打印所有注册的命令及其参数和帮助文本。
``esp_console_get_completion``
:cpp:func:`esp_console_get_completion`
与 linenoise 库中的 ``linenoiseSetCompletionCallback`` 一同使用的回调函数,根据已经注册的命令列表为 linenoise 提供补全功能。
与 linenoise 库中的 :cpp:func:`linenoiseSetCompletionCallback` 一同使用的回调函数,根据已经注册的命令列表为 linenoise 提供补全功能。
``esp_console_get_hint``
:cpp:func:`esp_console_get_hint`
与 linenoise 库中 ``linenoiseSetHintsCallback`` 一同使用的回调函数,为 linenoise 提供已经注册的命令的参数提示功能。
与 linenoise 库中 :cpp:func:`linenoiseSetHintsCallback` 一同使用的回调函数,为 linenoise 提供已经注册的命令的参数提示功能。
示例
----
``examples/system/console`` 目录下提供了 ``console`` 组件的示例应用程序,展示了具体的使用方法。该示例介绍了如何初始化 UART 和 VFS 的功能,设置 linenoise 库,从 UART 中读取命令并加以处理,然后将历史命令存储到 Flash 中。更多信息,请参阅示例代码目录中的 README.md 文件。
初始化 REPL 环境
----------------
``console`` 组建还提供了一些 API 来帮助创建一个基本的 REPL 环境。
在一个典型的 console 应用中,你只需要调用 :cpp:func:`esp_console_repl_init`,它会为你初始化好 REPL 环境,其中包括安装 UART 驱动,基本的 console 配置,创建一个新的线程来执行 REPL 任务,注册一些基本的命令(比如 `help``quit` 命令)。
完了之后你可以使用 :cpp:func:`esp_console_cmd_register` 来注册其它命令。REPL 环境在初始化后需要再调用 :cpp:func:`esp_console_repl_start` 函数才能开始运行。
应用程序示例
------------
:example:`system/console` 目录下提供了 ``console`` 组件的示例应用程序,展示了具体的使用方法。该示例介绍了如何初始化 UART 和 VFS 的功能,设置 linenoise 库,从 UART 中读取命令并加以处理,然后将历史命令存储到 Flash 中。更多信息,请参阅示例代码目录中的 README.md 文件。
此外ESP-IDF 还提供了众多基于 `console` 组件的示例程序,它们可以辅助应用程序的开发。例如,:example:`peripherals/i2c/i2c_tools`:example:`wifi/iperf` 等等。
API 参考
--------
.. include-build-file:: inc/esp_console.inc

View file

@ -15,10 +15,8 @@
#include <stdio.h>
#include <string.h>
#include "esp_system.h"
#include "esp_log.h"
#include "esp_vfs_dev.h"
#include "driver/uart.h"
#include "nvs.h"
#include "nvs_flash.h"
@ -26,8 +24,6 @@
#include "esp_bt_main.h"
#include "esp_console.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "ble_mesh_console_decl.h"
@ -51,54 +47,6 @@ static void initialize_filesystem(void)
}
#endif // CONFIG_STORE_HISTORY
static void initialize_console(void)
{
/* Disable buffering on stdin and stdout */
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0) );
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 20,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK( esp_console_init(&console_config) );
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
#if CONFIG_STORE_HISTORY
/* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_PATH);
#endif
}
esp_err_t bluetooth_init(void)
{
esp_err_t ret;
@ -141,75 +89,19 @@ void app_main(void)
printf("esp32_bluetooth_init failed (ret %d)", res);
}
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
#if CONFIG_STORE_HISTORY
initialize_filesystem();
repl_config.his_save_path = HISTORY_PATH;
#endif
initialize_console();
ESP_ERROR_CHECK(esp_console_repl_init(&repl_config));
/* Register commands */
esp_console_register_help_command();
register_system();
register_bluetooth();
ble_mesh_register_mesh_node();
ble_mesh_register_server();
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
printf("\n"
"This is an example of ESP-IDF console component.\n"
"Type 'help' to get the list of commands.\n"
"Use UP/DOWN arrows to navigate through command history.\n"
"Press TAB when typing command name to auto-complete.\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) { /* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "esp32> ";
#endif //CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char *line = linenoise(prompt);
if (line == NULL) { /* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
#if CONFIG_STORE_HISTORY
/* Save command history to filesystem */
linenoiseHistorySave(HISTORY_PATH);
#endif
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
printf("\nCommand returned non-zero error code: 0x%x\n", ret);
} else if (err != ESP_OK) {
printf("Internal error: 0x%x\n", err);
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
// start console REPL
ESP_ERROR_CHECK(esp_console_repl_start());
}

View file

@ -15,13 +15,9 @@
#include <stdio.h>
#include <string.h>
#include "esp_system.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "driver/uart.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "esp_vfs_fat.h"
#include "nvs.h"
@ -54,54 +50,6 @@ static void initialize_filesystem(void)
}
#endif // CONFIG_STORE_HISTORY
static void initialize_console(void)
{
/* Disable buffering on stdin and stdout */
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0) );
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 20,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK( esp_console_init(&console_config) );
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* a single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
#if CONFIG_STORE_HISTORY
/* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_PATH);
#endif
}
esp_err_t bluetooth_init(void)
{
esp_err_t ret;
@ -144,14 +92,15 @@ void app_main(void)
printf("esp32_bluetooth_init failed (ret %d)", res);
}
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
#if CONFIG_STORE_HISTORY
initialize_filesystem();
repl_config.his_save_path = HISTORY_PATH;
#endif
initialize_console();
// init console REPL environment
ESP_ERROR_CHECK(esp_console_repl_init(&repl_config));
/* Register commands */
esp_console_register_help_command();
register_system();
register_bluetooth();
ble_mesh_register_mesh_node();
@ -166,63 +115,6 @@ void app_main(void)
ble_mesh_register_configuration_client_model();
#endif
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
printf("\n"
"This is an example of an ESP-IDF console component.\n"
"Type 'help' to get the list of commands.\n"
"Use UP/DOWN arrows to navigate through the command history.\n"
"Press TAB when typing a command name to auto-complete.\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) { /* zero indicates OK */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "esp32> ";
#endif //CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char *line = linenoise(prompt);
if (line == NULL) { /* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
#if CONFIG_STORE_HISTORY
/* Save command history to filesystem */
linenoiseHistorySave(HISTORY_PATH);
#endif
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
printf("\nCommand returned non-zero error code: 0x%x\n", ret);
} else if (err != ESP_OK) {
printf("Internal error: 0x%x\n", err);
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
// start console REPL
ESP_ERROR_CHECK(esp_console_repl_start());
}

View file

@ -742,69 +742,17 @@ static esp_err_t ble_mesh_init(void)
#define WIFI_CONNECTED_BIT BIT0
static void initialize_console(void)
{
/* Disable buffering on stdin and stdout */
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0) );
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 32,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK( esp_console_init(&console_config) );
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
}
static void wifi_console_init(void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
initialise_wifi();
initialize_console();
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
// init console REPL environment
ESP_ERROR_CHECK(esp_console_repl_init(&repl_config));
/* Register commands */
esp_console_register_help_command();
register_wifi();
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
printf("\n ==================================================\n");
printf(" | Steps to test WiFi throughput |\n");
printf(" | |\n");
@ -815,50 +763,8 @@ static void wifi_console_init(void)
printf(" | |\n");
printf(" =================================================\n\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) { /* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "esp32> ";
#endif //CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char *line = linenoise(prompt);
if (line == NULL) { /* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x\n", ret);
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
return;
// start console REPL
ESP_ERROR_CHECK(esp_console_repl_start());
}
void app_main(void)

View file

@ -1,20 +0,0 @@
/* Console example — declarations of command registration functions.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "cmd_system.h"
#include "cmd_ethernet.h"
#ifdef __cplusplus
}
#endif

View file

@ -1,4 +1,4 @@
/* Console example
/* Ethernet iperf example
This example code is in the Public Domain (or CC0 licensed, at your option.)
@ -9,18 +9,12 @@
#include <stdio.h>
#include <string.h>
#include "esp_system.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "driver/uart.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "cmd_decl.h"
#include "esp_vfs_fat.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "cmd_system.h"
#include "cmd_ethernet.h"
static const char *TAG = "eth_example";
@ -44,90 +38,20 @@ static void initialize_filesystem(void)
}
#endif // CONFIG_EXAMPLE_STORE_HISTORY
static void initialize_nvs(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
}
static void initialize_console(void)
{
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
* correct while APB frequency is changing in light sleep mode.
*/
const uart_config_t uart_config = {
.baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.source_clk = UART_SCLK_REF_TICK,
};
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0));
ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config));
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 16,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK(esp_console_init(&console_config));
/* Configure linenoise line completion library */
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
#if CONFIG_EXAMPLE_STORE_HISTORY
/* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_PATH);
#endif
}
void app_main(void)
{
initialize_nvs();
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
#if CONFIG_EXAMPLE_STORE_HISTORY
initialize_filesystem();
repl_config.history_save_path = HISTORY_PATH;
#endif
initialize_console();
// initialize console REPL environment
ESP_ERROR_CHECK(esp_console_repl_init(&repl_config));
/* Register commands */
esp_console_register_help_command();
register_system();
register_ethernet();
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
printf("\n =======================================================\n");
printf(" | Steps to Test Ethernet Bandwidth |\n");
printf(" | |\n");
@ -139,53 +63,6 @@ void app_main(void)
printf(" | |\n");
printf(" =======================================================\n\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) {
/* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "esp32> ";
#endif //CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char *line = linenoise(prompt);
if (line == NULL) {
/* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
#if CONFIG_EXAMPLE_STORE_HISTORY
/* Save command history to filesystem */
linenoiseHistorySave(HISTORY_PATH);
#endif
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret));
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
// start console REPL
ESP_ERROR_CHECK(esp_console_repl_start());
}

View file

@ -36,8 +36,6 @@ To run this example, you should have one ESP32 dev board (e.g. ESP32-WROVER Kit)
Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu.
- You can choose whether or not to save command history into flash in `Store command history in flash` option.
- You can set the maximum number of command line arguments under `Maximum number of command line arguments` option.
- You can set the command line buffer length under `Command line buffer length` option.
### Build and Flash
@ -197,9 +195,6 @@ esp32> i2cget -c 0x5b -r 0x02 -l 8
* Reset you I2C device, and then run `i2cdetect` again.
* I cant get the right content when running `i2cdump` command.
* Currently the `i2cdump` only support those who have the same content length of registers inside the I2C device. For example, if a device have three register addresses, and the content length at these address are 1 byte, 2 bytes and 4 bytes. In this case you should not expect this command to dump the register correctly.
* I really input argument correctly, but the command line “discard” the last few arguements from time to time.
* Enlarge the maximum number of arguments in the menuconfig.
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View file

@ -10,7 +10,7 @@ def test_i2ctools_example(env, extra_data):
# Get device under test, flash and start example. "i2ctool" must be defined in EnvConfig
dut = env.get_dut('i2ctools', 'examples/peripherals/i2c/i2c_tools', dut_class=ttfw_idf.ESP32DUT)
dut.start_app()
dut.expect("esp32>", timeout=EXPECT_TIMEOUT)
dut.expect("i2c-tools>", timeout=EXPECT_TIMEOUT)
# Get i2c address
dut.write("i2cdetect")
dut.expect("5b", timeout=EXPECT_TIMEOUT)

View file

@ -7,19 +7,4 @@ menu "Example Configuration"
Linenoise line editing library provides functions to save and load
command history. If this option is enabled, initalizes a FAT filesystem
and uses it to store command history.
config EXAMPLE_MAX_CMD_ARGUMENTS
int "Maximum number of command line arguments"
default 16
range 8 256
help
maximum number of command line arguments to parse
config EXAMPLE_MAX_CMD_LENGTH
int "Command line buffer length"
default 256
range 256 512
help
length of command line buffer, in bytes
endmenu

View file

@ -1,21 +0,0 @@
/* cmd_decl.h
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "cmd_system.h"
#include "cmd_i2ctools.h"
#ifdef __cplusplus
}
#endif

View file

@ -9,18 +9,12 @@
#include <stdio.h>
#include <string.h>
#include "esp_system.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "driver/uart.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "cmd_decl.h"
#include "esp_vfs_fat.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "cmd_system.h"
#include "cmd_i2ctools.h"
static const char *TAG = "i2c-tools";
@ -44,92 +38,22 @@ static void initialize_filesystem(void)
}
#endif // CONFIG_EXAMPLE_STORE_HISTORY
static void initialize_nvs(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
}
static void initialize_console(void)
{
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
* correct while APB frequency is changing in light sleep mode.
*/
const uart_config_t uart_config = {
.baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.source_clk = UART_SCLK_REF_TICK,
};
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0));
ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config));
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = CONFIG_EXAMPLE_MAX_CMD_ARGUMENTS,
.max_cmdline_length = CONFIG_EXAMPLE_MAX_CMD_LENGTH,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK(esp_console_init(&console_config));
/* Configure linenoise line completion library */
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
#if CONFIG_EXAMPLE_STORE_HISTORY
/* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_PATH);
#endif
}
void app_main(void)
{
initialize_nvs();
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
#if CONFIG_EXAMPLE_STORE_HISTORY
initialize_filesystem();
repl_config.history_save_path = HISTORY_PATH;
#endif
repl_config.prompt = "i2c-tools>";
// initialize console REPL environment
ESP_ERROR_CHECK(esp_console_repl_init(&repl_config));
initialize_console();
/* Register commands */
esp_console_register_help_command();
register_i2ctools();
register_system();
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
printf("\n ==============================================================\n");
printf(" | Steps to Use i2c-tools on ESP32 |\n");
printf(" | Steps to Use i2c-tools |\n");
printf(" | |\n");
printf(" | 1. Try 'help', check all supported commands |\n");
printf(" | 2. Try 'i2cconfig' to configure your I2C bus |\n");
@ -140,53 +64,6 @@ void app_main(void)
printf(" | |\n");
printf(" ==============================================================\n\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) {
/* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "esp32> ";
#endif //CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char *line = linenoise(prompt);
if (line == NULL) {
/* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
#if CONFIG_EXAMPLE_STORE_HISTORY
/* Save command history to filesystem */
linenoiseHistorySave(HISTORY_PATH);
#endif
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret));
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
// start console REPL
ESP_ERROR_CHECK(esp_console_repl_start());
}

View file

@ -1,2 +1,2 @@
idf_component_register(SRCS "echo_example_main.c" "cmd_ping.c"
idf_component_register(SRCS "echo_example_main.c"
INCLUDE_DIRS ".")

View file

@ -1,161 +0,0 @@
/* Ping command
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "cmd_ping.h"
#include "argtable3/argtable3.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include "esp_console.h"
#include "ping/ping_sock.h"
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
{
uint8_t ttl;
uint16_t seqno;
uint32_t elapsed_time, recv_len;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
printf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n",
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
}
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
{
uint16_t seqno;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
}
static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
{
ip_addr_t target_addr;
uint32_t transmitted;
uint32_t received;
uint32_t total_time_ms;
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
uint32_t loss = (uint32_t)((1 - ((float)received) / transmitted) * 100);
if (IP_IS_V4(&target_addr)) {
printf("\n--- %s ping statistics ---\n", inet_ntoa(*ip_2_ip4(&target_addr)));
} else {
printf("\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
}
printf("%d packets transmitted, %d received, %d%% packet loss, time %dms\n",
transmitted, received, loss, total_time_ms);
// delete the ping sessions, so that we clean up all resources and can create a new ping session
// we don't have to call delete function in the callback, instead we can call delete function from other tasks
esp_ping_delete_session(hdl);
}
static struct {
struct arg_dbl *timeout;
struct arg_dbl *interval;
struct arg_int *data_size;
struct arg_int *count;
struct arg_int *tos;
struct arg_str *host;
struct arg_end *end;
} ping_args;
static int do_ping_cmd(int argc, char **argv)
{
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
int nerrors = arg_parse(argc, argv, (void **)&ping_args);
if (nerrors != 0) {
arg_print_errors(stderr, ping_args.end, argv[0]);
return 1;
}
if (ping_args.timeout->count > 0) {
config.timeout_ms = (uint32_t)(ping_args.timeout->dval[0] * 1000);
}
if (ping_args.interval->count > 0) {
config.interval_ms = (uint32_t)(ping_args.interval->dval[0] * 1000);
}
if (ping_args.data_size->count > 0) {
config.data_size = (uint32_t)(ping_args.data_size->ival[0]);
}
if (ping_args.count->count > 0) {
config.count = (uint32_t)(ping_args.count->ival[0]);
}
if (ping_args.tos->count > 0) {
config.tos = (uint32_t)(ping_args.tos->ival[0]);
}
// parse IP address
ip_addr_t target_addr;
struct addrinfo hint;
struct addrinfo *res = NULL;
memset(&hint, 0, sizeof(hint));
memset(&target_addr, 0, sizeof(target_addr));
/* convert domain name to IP address */
if (getaddrinfo(ping_args.host->sval[0], NULL, &hint, &res) != 0) {
printf("ping: unknown host %s\n", ping_args.host->sval[0]);
return 1;
}
if (res->ai_family == AF_INET) {
struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
} else {
struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
}
freeaddrinfo(res);
config.target_addr = target_addr;
/* set callback functions */
esp_ping_callbacks_t cbs = {
.on_ping_success = cmd_ping_on_ping_success,
.on_ping_timeout = cmd_ping_on_ping_timeout,
.on_ping_end = cmd_ping_on_ping_end,
.cb_args = NULL
};
esp_ping_handle_t ping;
esp_ping_new_session(&config, &cbs, &ping);
esp_ping_start(ping);
return 0;
}
void register_ping(void)
{
ping_args.timeout = arg_dbl0("W", "timeout", "<t>", "Time to wait for a response, in seconds");
ping_args.interval = arg_dbl0("i", "interval", "<t>", "Wait interval seconds between sending each packet");
ping_args.data_size = arg_int0("s", "size", "<n>", "Specify the number of data bytes to be sent");
ping_args.count = arg_int0("c", "count", "<n>", "Stop after sending count packets");
ping_args.tos = arg_int0("Q", "tos", "<n>", "Set Type of Service related bits in IP datagrams");
ping_args.host = arg_str1(NULL, NULL, "<host>", "Host address");
ping_args.end = arg_end(1);
const esp_console_cmd_t ping_cmd = {
.command = "ping",
.help = "send ICMP ECHO_REQUEST to network hosts",
.hint = NULL,
.func = &do_ping_cmd,
.argtable = &ping_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&ping_cmd));
}

View file

@ -1,24 +0,0 @@
/* Ping command
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Register Ping command
*
*/
void register_ping(void);
#ifdef __cplusplus
}
#endif

View file

@ -10,135 +10,172 @@
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_system.h"
#include "esp_log.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include "esp_console.h"
#include "driver/uart.h"
#include "esp_vfs_dev.h"
#include "esp_event.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "nvs_flash.h"
#include "argtable3/argtable3.h"
#include "protocol_examples_common.h"
#include "cmd_ping.h"
#include "ping/ping_sock.h"
static void initialize_console(void)
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
{
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
uint8_t ttl;
uint16_t seqno;
uint32_t elapsed_time, recv_len;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
printf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n",
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
}
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
{
uint16_t seqno;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
}
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
* correct while APB frequency is changing in light sleep mode.
*/
const uart_config_t uart_config = {
.baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.source_clk = UART_SCLK_REF_TICK,
static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
{
ip_addr_t target_addr;
uint32_t transmitted;
uint32_t received;
uint32_t total_time_ms;
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
uint32_t loss = (uint32_t)((1 - ((float)received) / transmitted) * 100);
if (IP_IS_V4(&target_addr)) {
printf("\n--- %s ping statistics ---\n", inet_ntoa(*ip_2_ip4(&target_addr)));
} else {
printf("\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
}
printf("%d packets transmitted, %d received, %d%% packet loss, time %dms\n",
transmitted, received, loss, total_time_ms);
// delete the ping sessions, so that we clean up all resources and can create a new ping session
// we don't have to call delete function in the callback, instead we can call delete function from other tasks
esp_ping_delete_session(hdl);
}
static struct {
struct arg_dbl *timeout;
struct arg_dbl *interval;
struct arg_int *data_size;
struct arg_int *count;
struct arg_int *tos;
struct arg_str *host;
struct arg_end *end;
} ping_args;;
static int do_ping_cmd(int argc, char **argv)
{
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
int nerrors = arg_parse(argc, argv, (void **)&ping_args);
if (nerrors != 0) {
arg_print_errors(stderr, ping_args.end, argv[0]);
return 1;
}
if (ping_args.timeout->count > 0) {
config.timeout_ms = (uint32_t)(ping_args.timeout->dval[0] * 1000);
}
if (ping_args.interval->count > 0) {
config.interval_ms = (uint32_t)(ping_args.interval->dval[0] * 1000);
}
if (ping_args.data_size->count > 0) {
config.data_size = (uint32_t)(ping_args.data_size->ival[0]);
}
if (ping_args.count->count > 0) {
config.count = (uint32_t)(ping_args.count->ival[0]);
}
if (ping_args.tos->count > 0) {
config.tos = (uint32_t)(ping_args.tos->ival[0]);
}
// parse IP address
ip_addr_t target_addr;
struct addrinfo hint;
struct addrinfo *res = NULL;
memset(&hint, 0, sizeof(hint));
memset(&target_addr, 0, sizeof(target_addr));
/* convert domain name to IP address */
if (getaddrinfo(ping_args.host->sval[0], NULL, &hint, &res) != 0) {
printf("ping: unknown host %s\n", ping_args.host->sval[0]);
return 1;
}
if (res->ai_family == AF_INET) {
struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
} else {
struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
}
freeaddrinfo(res);
config.target_addr = target_addr;
/* set callback functions */
esp_ping_callbacks_t cbs = {
.on_ping_success = cmd_ping_on_ping_success,
.on_ping_timeout = cmd_ping_on_ping_timeout,
.on_ping_end = cmd_ping_on_ping_end,
.cb_args = NULL
};
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0));
ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config));
esp_ping_handle_t ping;
esp_ping_new_session(&config, &cbs, &ping);
esp_ping_start(ping);
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
return 0;
}
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 16,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
static void register_ping(void)
{
ping_args.timeout = arg_dbl0("W", "timeout", "<t>", "Time to wait for a response, in seconds");
ping_args.interval = arg_dbl0("i", "interval", "<t>", "Wait interval seconds between sending each packet");
ping_args.data_size = arg_int0("s", "size", "<n>", "Specify the number of data bytes to be sent");
ping_args.count = arg_int0("c", "count", "<n>", "Stop after sending count packets");
ping_args.tos = arg_int0("Q", "tos", "<n>", "Set Type of Service related bits in IP datagrams");
ping_args.host = arg_str1(NULL, NULL, "<host>", "Host address");
ping_args.end = arg_end(1);
const esp_console_cmd_t ping_cmd = {
.command = "ping",
.help = "send ICMP ECHO_REQUEST to network hosts",
.hint = NULL,
.func = &do_ping_cmd,
.argtable = &ping_args
};
ESP_ERROR_CHECK(esp_console_init(&console_config));
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
ESP_ERROR_CHECK(esp_console_cmd_register(&ping_cmd));
}
void app_main(void)
{
initialize_console();
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* wait for active network connection */
ESP_ERROR_CHECK(example_connect());
/* Register commands */
esp_console_register_help_command();
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
// init console REPL environment
ESP_ERROR_CHECK(esp_console_repl_init(&repl_config));
/* register command `ping` */
register_ping();
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
printf("\n"
"Type 'help' to get the list of commands.\n"
"Use UP/DOWN arrows to navigate through command history.\n"
"Press TAB when typing command name to auto-complete.\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) { /* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "esp32> ";
#endif //CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char *line = linenoise(prompt);
if (line == NULL) { /* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret));
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
// start console REPL
ESP_ERROR_CHECK(esp_console_repl_start());
}

View file

@ -305,7 +305,7 @@ class IperfTestUtility(object):
except subprocess.CalledProcessError:
pass
self.dut.write("restart")
self.dut.expect("esp32>")
self.dut.expect("iperf>")
self.dut.write("scan {}".format(self.ap_ssid))
for _ in range(SCAN_RETRY_COUNT):
try:
@ -431,7 +431,7 @@ class IperfTestUtility(object):
:return: True or False
"""
self.dut.write("restart")
self.dut.expect("esp32>")
self.dut.expect("iperf>")
for _ in range(WAIT_AP_POWER_ON_TIMEOUT // SCAN_TIMEOUT):
try:
self.dut.write("scan {}".format(self.ap_ssid))
@ -477,7 +477,7 @@ def test_wifi_throughput_with_different_configs(env, extra_data):
dut = env.get_dut("iperf", "examples/wifi/iperf", dut_class=ttfw_idf.ESP32DUT,
app_config_name=config_name)
dut.start_app()
dut.expect("esp32>")
dut.expect("iperf>")
# 3. run test for each required att value
test_result[config_name] = {
@ -533,7 +533,7 @@ def test_wifi_throughput_vs_rssi(env, extra_data):
dut = env.get_dut("iperf", "examples/wifi/iperf", dut_class=ttfw_idf.ESP32DUT,
app_config_name=BEST_PERFORMANCE_CONFIG)
dut.start_app()
dut.expect("esp32>")
dut.expect("iperf>")
# 2. run test for each required att value
for ap_info in ap_list:
@ -580,7 +580,7 @@ def test_wifi_throughput_basic(env, extra_data):
dut = env.get_dut("iperf", "examples/wifi/iperf", dut_class=ttfw_idf.ESP32DUT,
app_config_name=BEST_PERFORMANCE_CONFIG)
dut.start_app()
dut.expect("esp32>")
dut.expect("iperf>")
# 2. preparing
test_result = {

View file

@ -1,4 +1,4 @@
/* Iperf Example
/* Wi-Fi iperf Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
@ -9,64 +9,13 @@
#include <errno.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_err.h"
#include "nvs_flash.h"
#include "esp_console.h"
#include "esp_vfs_dev.h"
#include "driver/uart.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "cmd_decl.h"
#define WIFI_CONNECTED_BIT BIT0
static void initialize_console(void)
{
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0) );
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 32,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK( esp_console_init(&console_config) );
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
}
void app_main(void)
{
esp_err_t ret = nvs_flash_init();
@ -77,18 +26,15 @@ void app_main(void)
ESP_ERROR_CHECK( ret );
initialise_wifi();
initialize_console();
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
repl_config.prompt = "iperf>";
// init console REPL
ESP_ERROR_CHECK(esp_console_repl_init(&repl_config));
/* Register commands */
esp_console_register_help_command();
register_system();
register_wifi();
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
printf("\n ==================================================\n");
printf(" | Steps to test WiFi throughput |\n");
printf(" | |\n");
@ -99,46 +45,7 @@ void app_main(void)
printf(" | |\n");
printf(" =================================================\n\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) { /* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "esp32> ";
#endif //CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char *line = linenoise(prompt);
if (line == NULL) { /* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x\n", ret);
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
// start console REPL
ESP_ERROR_CHECK(esp_console_repl_start());
}

View file

@ -1,20 +0,0 @@
/* Iperf example — declarations of command registration functions.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "cmd_system.h"
#include "cmd_sniffer.h"
#ifdef __cplusplus
}
#endif

View file

@ -9,23 +9,22 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sdkconfig.h"
#include "linenoise/linenoise.h"
#include "argtable3/argtable3.h"
#include "esp_netif.h"
#include "esp_console.h"
#include "esp_event.h"
#include "esp_vfs_dev.h"
#include "esp_vfs_fat.h"
#include "esp_wifi.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/sdmmc_host.h"
#include "driver/sdspi_host.h"
#include "nvs_flash.h"
#include "sdmmc_cmd.h"
#include "cmd_decl.h"
#include "sdkconfig.h"
#include "cmd_system.h"
#include "cmd_sniffer.h"
#if CONFIG_SNIFFER_STORE_HISTORY
#define HISTORY_MOUNT_POINT "/data"
@ -72,53 +71,6 @@ static void initialize_wifi(void)
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
}
/* Initialize console component */
static void initialize_console(void)
{
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0));
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 8,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK(esp_console_init(&console_config));
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
#if CONFIG_SNIFFER_STORE_HISTORY
/* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_FILE_PATH);
#endif
}
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
static struct {
struct arg_str *device;
@ -223,17 +175,19 @@ void app_main(void)
{
initialize_nvs();
#if CONFIG_SNIFFER_STORE_HISTORY
initialize_filesystem();
#endif
/* Initialize WiFi */
initialize_wifi();
/* Initialize Console component */
initialize_console();
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
#if CONFIG_SNIFFER_STORE_HISTORY
initialize_filesystem();
repl_config.history_save_path = HISTORY_FILE_PATH;
#endif
repl_config.prompt = "sniffer>";
/* Initialize Console REPL environment */
ESP_ERROR_CHECK(esp_console_repl_init(&repl_config));
/* Register commands */
esp_console_register_help_command();
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
register_mount();
register_unmount();
@ -241,11 +195,6 @@ void app_main(void)
register_sniffer();
register_system();
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
printf("\n =======================================================\n");
printf(" | Steps to sniffer WiFi packets |\n");
printf(" | |\n");
@ -256,51 +205,5 @@ void app_main(void)
printf(" | |\n");
printf(" =======================================================\n\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) {
/* zero indicates success */
printf("\n"
"Your terminal application does not support escape sequences.\n"
"Line editing and history features are disabled.\n"
"On Windows, try using Putty instead.\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "esp32> ";
#endif //CONFIG_LOG_COLORS
}
/* Main loop */
while (true) {
/* Get a line using linenoise.
* The line is returned when ENTER is pressed.
*/
char *line = linenoise(prompt);
if (line == NULL) {
/* Ignore empty lines */
continue;
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
#if CONFIG_SNIFFER_STORE_HISTORY
/* Save command history to filesystem */
linenoiseHistorySave(HISTORY_FILE_PATH);
#endif
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
printf("Unrecognized command\n");
} else if (err == ESP_OK && ret != ESP_OK) {
printf("Command returned non-zero error code: 0x%x\n", ret);
} else if (err != ESP_OK) {
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
ESP_ERROR_CHECK(esp_console_repl_start());
}