1 /*
2  * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #pragma once
7 
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11 
12 #include <stddef.h>
13 #include "sdkconfig.h"
14 #include "esp_err.h"
15 
16 // Forward declaration. Definition in linenoise/linenoise.h.
17 typedef struct linenoiseCompletions linenoiseCompletions;
18 
19 /**
20  * @brief Parameters for console initialization
21  */
22 typedef struct {
23     size_t max_cmdline_length;  //!< length of command line buffer, in bytes
24     size_t max_cmdline_args;    //!< maximum number of command line arguments to parse
25     int hint_color;             //!< ASCII color code of hint text
26     int hint_bold;              //!< Set to 1 to print hint text in bold
27 } esp_console_config_t;
28 
29 /**
30  * @brief Default console configuration value
31  *
32  */
33 #define ESP_CONSOLE_CONFIG_DEFAULT() \
34     {                                \
35         .max_cmdline_length = 256,   \
36         .max_cmdline_args = 32,      \
37         .hint_color = 39,            \
38         .hint_bold = 0               \
39     }
40 
41 /**
42  * @brief Parameters for console REPL (Read Eval Print Loop)
43  *
44  */
45 typedef struct {
46     uint32_t max_history_len;      //!< maximum length for the history
47     const char *history_save_path; //!< file path used to save history commands, set to NULL won't save to file system
48     uint32_t task_stack_size;      //!< repl task stack size
49     uint32_t task_priority;        //!< repl task priority
50     const char *prompt;            //!< prompt (NULL represents default: "esp> ")
51     size_t max_cmdline_length;     //!< maximum length of a command line. If 0, default value will be used
52 } esp_console_repl_config_t;
53 
54 /**
55  * @brief Default console repl configuration value
56  *
57  */
58 #define ESP_CONSOLE_REPL_CONFIG_DEFAULT() \
59 {                                         \
60         .max_history_len = 32,            \
61         .history_save_path = NULL,        \
62         .task_stack_size = 4096,          \
63         .task_priority = 2,               \
64         .prompt = NULL,                   \
65         .max_cmdline_length = 0,          \
66 }
67 
68 /**
69  * @brief Parameters for console device: UART
70  *
71  */
72 typedef struct {
73     int channel;     //!< UART channel number (count from zero)
74     int baud_rate;   //!< Comunication baud rate
75     int tx_gpio_num; //!< GPIO number for TX path, -1 means using default one
76     int rx_gpio_num; //!< GPIO number for RX path, -1 means using default one
77 } esp_console_dev_uart_config_t;
78 
79 #ifdef CONFIG_ESP_CONSOLE_UART_CUSTOM
80 #define ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT()       \
81 {                                                   \
82     .channel = CONFIG_ESP_CONSOLE_UART_NUM,         \
83     .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,  \
84     .tx_gpio_num = CONFIG_ESP_CONSOLE_UART_TX_GPIO, \
85     .rx_gpio_num = CONFIG_ESP_CONSOLE_UART_RX_GPIO, \
86 }
87 #else
88 #define ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT()      \
89 {                                                  \
90     .channel = CONFIG_ESP_CONSOLE_UART_NUM,        \
91     .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE, \
92     .tx_gpio_num = -1,                             \
93     .rx_gpio_num = -1,                             \
94 }
95 #endif
96 
97 /**
98  * @brief Parameters for console device: USB CDC
99  *
100  * @note It's an empty structure for now, reserved for future
101  *
102  */
103 typedef struct {
104 
105 } esp_console_dev_usb_cdc_config_t;
106 
107 #define ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT() \
108 {                                            \
109 }
110 
111 #if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
112 /**
113  * @brief Parameters for console device: USB-SERIAL-JTAG
114  *
115  * @note It's an empty structure for now, reserved for future
116  *
117  */
118 typedef struct {
119 
120 } esp_console_dev_usb_serial_jtag_config_t;
121 
122 #define ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT() {}
123 
124 #endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
125 
126 /**
127  * @brief initialize console module
128  * @param config console configuration
129  * @note  Call this once before using other console module features
130  * @return
131  *      - ESP_OK on success
132  *      - ESP_ERR_NO_MEM if out of memory
133  *      - ESP_ERR_INVALID_STATE if already initialized
134  *      - ESP_ERR_INVALID_ARG if the configuration is invalid
135  */
136 esp_err_t esp_console_init(const esp_console_config_t *config);
137 
138 /**
139  * @brief de-initialize console module
140  * @note  Call this once when done using console module functions
141  * @return
142  *      - ESP_OK on success
143  *      - ESP_ERR_INVALID_STATE if not initialized yet
144  */
145 esp_err_t esp_console_deinit(void);
146 
147 /**
148  * @brief Console command main function
149  * @param argc number of arguments
150  * @param argv array with argc entries, each pointing to a zero-terminated string argument
151  * @return console command return code, 0 indicates "success"
152  */
153 typedef int (*esp_console_cmd_func_t)(int argc, char **argv);
154 
155 /**
156  * @brief Console command description
157  */
158 typedef struct {
159     /**
160      * Command name. Must not be NULL, must not contain spaces.
161      * The pointer must be valid until the call to esp_console_deinit.
162      */
163     const char *command;
164     /**
165      * Help text for the command, shown by help command.
166      * If set, the pointer must be valid until the call to esp_console_deinit.
167      * If not set, the command will not be listed in 'help' output.
168      */
169     const char *help;
170     /**
171      * Hint text, usually lists possible arguments.
172      * If set to NULL, and 'argtable' field is non-NULL, hint will be generated
173      * automatically
174      */
175     const char *hint;
176     /**
177      * Pointer to a function which implements the command.
178      */
179     esp_console_cmd_func_t func;
180     /**
181      * Array or structure of pointers to arg_xxx structures, may be NULL.
182      * Used to generate hint text if 'hint' is set to NULL.
183      * Array/structure which this field points to must end with an arg_end.
184      * Only used for the duration of esp_console_cmd_register call.
185      */
186     void *argtable;
187 } esp_console_cmd_t;
188 
189 /**
190  * @brief Register console command
191  * @param cmd pointer to the command description; can point to a temporary value
192  * @return
193  *      - ESP_OK on success
194  *      - ESP_ERR_NO_MEM if out of memory
195  *      - ESP_ERR_INVALID_ARG if command description includes invalid arguments
196  */
197 esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd);
198 
199 /**
200  * @brief Run command line
201  * @param cmdline command line (command name followed by a number of arguments)
202  * @param[out] cmd_ret return code from the command (set if command was run)
203  * @return
204  *      - ESP_OK, if command was run
205  *      - ESP_ERR_INVALID_ARG, if the command line is empty, or only contained
206  *        whitespace
207  *      - ESP_ERR_NOT_FOUND, if command with given name wasn't registered
208  *      - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called
209  */
210 esp_err_t esp_console_run(const char *cmdline, int *cmd_ret);
211 
212 /**
213  * @brief Split command line into arguments in place
214  * @verbatim
215  * - This function finds whitespace-separated arguments in the given input line.
216  *
217  *     'abc def 1 20 .3' -> [ 'abc', 'def', '1', '20', '.3' ]
218  *
219  * - Argument which include spaces may be surrounded with quotes. In this case
220  *   spaces are preserved and quotes are stripped.
221  *
222  *     'abc "123 456" def' -> [ 'abc', '123 456', 'def' ]
223  *
224  * - Escape sequences may be used to produce backslash, double quote, and space:
225  *
226  *     'a\ b\\c\"' -> [ 'a b\c"' ]
227  * @endverbatim
228  * @note Pointers to at most argv_size - 1 arguments are returned in argv array.
229  *       The pointer after the last one (i.e. argv[argc]) is set to NULL.
230  *
231  * @param line pointer to buffer to parse; it is modified in place
232  * @param argv array where the pointers to arguments are written
233  * @param argv_size number of elements in argv_array (max. number of arguments)
234  * @return number of arguments found (argc)
235  */
236 size_t esp_console_split_argv(char *line, char **argv, size_t argv_size);
237 
238 /**
239  * @brief Callback which provides command completion for linenoise library
240  *
241  * When using linenoise for line editing, command completion support
242  * can be enabled like this:
243  *
244  *   linenoiseSetCompletionCallback(&esp_console_get_completion);
245  *
246  * @param buf the string typed by the user
247  * @param lc linenoiseCompletions to be filled in
248  */
249 void esp_console_get_completion(const char *buf, linenoiseCompletions *lc);
250 
251 /**
252  * @brief Callback which provides command hints for linenoise library
253  *
254  * When using linenoise for line editing, hints support can be enabled as
255  * follows:
256  *
257  *   linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);
258  *
259  * The extra cast is needed because linenoiseHintsCallback is defined as
260  * returning a char* instead of const char*.
261  *
262  * @param buf line typed by the user
263  * @param[out] color ANSI color code to be used when displaying the hint
264  * @param[out] bold set to 1 if hint has to be displayed in bold
265  * @return string containing the hint text. This string is persistent and should
266  *         not be freed (i.e. linenoiseSetFreeHintsCallback should not be used).
267  */
268 const char *esp_console_get_hint(const char *buf, int *color, int *bold);
269 
270 /**
271  * @brief Register a 'help' command
272  *
273  * Default 'help' command prints the list of registered commands along with
274  * hints and help strings.
275  *
276  * @return
277  *      - ESP_OK on success
278  *      - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called
279  */
280 esp_err_t esp_console_register_help_command(void);
281 
282 /******************************************************************************
283  *              Console REPL
284  ******************************************************************************/
285 
286 /**
287  * @brief Type defined for console REPL
288  *
289  */
290 typedef struct esp_console_repl_s esp_console_repl_t;
291 
292 /**
293  * @brief Console REPL base structure
294  *
295  */
296 struct esp_console_repl_s {
297     /**
298      * @brief Delete console REPL environment
299      * @param[in] repl REPL handle returned from esp_console_new_repl_xxx
300      * @return
301      *      - ESP_OK on success
302      *      - ESP_FAIL on errors
303      */
304     esp_err_t (*del)(esp_console_repl_t *repl);
305 };
306 
307 /**
308  * @brief Establish a console REPL environment over UART driver
309  *
310  * @param[in] dev_config UART device configuration
311  * @param[in] repl_config REPL configuration
312  * @param[out] ret_repl return REPL handle after initialization succeed, return NULL otherwise
313  *
314  * @note This is a all-in-one function to establish the environment needed for REPL, includes:
315  *       - Install the UART driver on the console UART (8n1, 115200, REF_TICK clock source)
316  *       - Configures the stdin/stdout to go through the UART driver
317  *       - Initializes linenoise
318  *       - Spawn new thread to run REPL in the background
319  *
320  * @attention This function is meant to be used in the examples to make the code more compact.
321  *            Applications which use console functionality should be based on
322  *            the underlying linenoise and esp_console functions.
323  *
324  * @return
325  *      - ESP_OK on success
326  *      - ESP_FAIL Parameter error
327  */
328 esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl);
329 
330 /**
331  * @brief Establish a console REPL environment over USB CDC
332  *
333  * @param[in] dev_config USB CDC configuration
334  * @param[in] repl_config REPL configuration
335  * @param[out] ret_repl return REPL handle after initialization succeed, return NULL otherwise
336  *
337  * @note This is a all-in-one function to establish the environment needed for REPL, includes:
338  *       - Initializes linenoise
339  *       - Spawn new thread to run REPL in the background
340  *
341  * @attention This function is meant to be used in the examples to make the code more compact.
342  *            Applications which use console functionality should be based on
343  *            the underlying linenoise and esp_console functions.
344  *
345  * @return
346  *      - ESP_OK on success
347  *      - ESP_FAIL Parameter error
348  */
349 esp_err_t esp_console_new_repl_usb_cdc(const esp_console_dev_usb_cdc_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl);
350 
351 #if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
352 /**
353  * @brief Establish a console REPL (Read-eval-print loop) environment over USB-SERIAL-JTAG
354  *
355  * @param[in] dev_config USB-SERIAL-JTAG configuration
356  * @param[in] repl_config REPL configuration
357  * @param[out] ret_repl return REPL handle after initialization succeed, return NULL otherwise
358  *
359  * @note This is a all-in-one function to establish the environment needed for REPL, includes:
360  *       - Initializes linenoise
361  *       - Spawn new thread to run REPL in the background
362  *
363  * @attention This function is meant to be used in the examples to make the code more compact.
364  *            Applications which use console functionality should be based on
365  *            the underlying linenoise and esp_console functions.
366  *
367  * @return
368  *      - ESP_OK on success
369  *      - ESP_FAIL Parameter error
370  */
371 esp_err_t esp_console_new_repl_usb_serial_jtag(const esp_console_dev_usb_serial_jtag_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl);
372 #endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
373 
374 /**
375  * @brief Start REPL environment
376  * @param[in] repl REPL handle returned from esp_console_new_repl_xxx
377  * @note Once the REPL got started, it won't be stopped until user call repl->del(repl) to destory the REPL environment.
378  * @return
379  *      - ESP_OK on success
380  *      - ESP_ERR_INVALID_STATE, if repl has started already
381  */
382 esp_err_t esp_console_start_repl(esp_console_repl_t *repl);
383 
384 #ifdef __cplusplus
385 }
386 #endif
387