2018-08-09 09:56:10 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
2019-06-25 18:25:32 +02:00
|
|
|
#include <sys/atomic.h>
|
2018-08-09 09:56:10 +02:00
|
|
|
#include <shell/shell.h>
|
2021-05-18 16:40:15 +02:00
|
|
|
#if defined(CONFIG_SHELL_BACKEND_DUMMY)
|
2018-10-02 14:47:20 +02:00
|
|
|
#include <shell/shell_dummy.h>
|
2021-05-18 16:40:15 +02:00
|
|
|
#endif
|
2018-12-06 14:16:09 +01:00
|
|
|
#include "shell_ops.h"
|
2018-11-26 17:09:56 +01:00
|
|
|
#include "shell_help.h"
|
2018-08-09 09:56:10 +02:00
|
|
|
#include "shell_utils.h"
|
|
|
|
#include "shell_vt100.h"
|
2018-12-06 14:16:09 +01:00
|
|
|
#include "shell_wildcard.h"
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
/* 2 == 1 char for cmd + 1 char for '\0' */
|
|
|
|
#if (CONFIG_SHELL_CMD_BUFF_SIZE < 2)
|
|
|
|
#error too small CONFIG_SHELL_CMD_BUFF_SIZE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (CONFIG_SHELL_PRINTF_BUFF_SIZE < 1)
|
|
|
|
#error too small SHELL_PRINTF_BUFF_SIZE
|
|
|
|
#endif
|
|
|
|
|
2019-02-08 14:51:21 +01:00
|
|
|
#define SHELL_MSG_CMD_NOT_FOUND ": command not found"
|
2020-08-03 15:12:17 +02:00
|
|
|
#define SHELL_MSG_BACKEND_NOT_ACTIVE \
|
|
|
|
"WARNING: A print request was detected on not active shell backend.\n"
|
2020-09-11 09:54:12 +02:00
|
|
|
#define SHELL_MSG_TOO_MANY_ARGS "Too many arguments in the command.\n"
|
2018-08-09 09:56:10 +02:00
|
|
|
#define SHELL_INIT_OPTION_PRINTER (NULL)
|
|
|
|
|
|
|
|
static inline void receive_state_change(const struct shell *shell,
|
|
|
|
enum shell_receive_state state)
|
|
|
|
{
|
|
|
|
shell->ctx->receive_state = state;
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
static void cmd_buffer_clear(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
shell->ctx->cmd_buff[0] = '\0'; /* clear command buffer */
|
|
|
|
shell->ctx->cmd_buff_pos = 0;
|
|
|
|
shell->ctx->cmd_buff_len = 0;
|
|
|
|
}
|
|
|
|
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
static void shell_internal_help_print(const struct shell *shell)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HELP)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-06 11:45:42 +01:00
|
|
|
z_shell_help_cmd_print(shell, &shell->ctx->active_cmd);
|
|
|
|
z_shell_help_subcmd_print(shell, &shell->ctx->active_cmd,
|
|
|
|
"Subcommands:\n");
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
}
|
|
|
|
|
2018-11-26 17:09:56 +01:00
|
|
|
/**
|
|
|
|
* @brief Prints error message on wrong argument count.
|
|
|
|
* Optionally, printing help on wrong argument count.
|
2018-08-09 09:56:10 +02:00
|
|
|
*
|
2018-11-26 17:09:56 +01:00
|
|
|
* @param[in] shell Pointer to the shell instance.
|
|
|
|
* @param[in] arg_cnt_ok Flag indicating valid number of arguments.
|
2018-08-09 09:56:10 +02:00
|
|
|
*
|
2018-11-26 17:09:56 +01:00
|
|
|
* @return 0 if check passed
|
|
|
|
* @return -EINVAL if wrong argument count
|
2018-08-09 09:56:10 +02:00
|
|
|
*/
|
2018-12-13 10:26:49 +01:00
|
|
|
static int cmd_precheck(const struct shell *shell,
|
|
|
|
bool arg_cnt_ok)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2018-11-26 17:09:56 +01:00
|
|
|
if (!arg_cnt_ok) {
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_ERROR,
|
|
|
|
"%s: wrong parameter count\n",
|
|
|
|
shell->ctx->active_cmd.syntax);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2018-11-26 17:09:56 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_HELP_ON_WRONG_ARGUMENT_COUNT)) {
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
shell_internal_help_print(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2018-11-26 17:09:56 +01:00
|
|
|
return -EINVAL;
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2018-11-26 17:09:56 +01:00
|
|
|
return 0;
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-08-18 12:14:42 +02:00
|
|
|
static inline void state_set(const struct shell *shell, enum shell_state state)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
shell->ctx->state = state;
|
|
|
|
|
2021-06-09 10:53:53 +02:00
|
|
|
if (state == SHELL_STATE_ACTIVE && !shell->ctx->bypass) {
|
2018-12-13 10:26:49 +01:00
|
|
|
cmd_buffer_clear(shell);
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_print_noinit_get(shell)) {
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_WARNING, "%s",
|
|
|
|
SHELL_MSG_BACKEND_NOT_ACTIVE);
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_print_noinit_set(shell, false);
|
2020-08-03 15:12:17 +02:00
|
|
|
}
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_print_prompt_and_cmd(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-18 12:14:42 +02:00
|
|
|
static inline enum shell_state state_get(const struct shell *shell)
|
|
|
|
{
|
|
|
|
return shell->ctx->state;
|
|
|
|
}
|
|
|
|
|
2020-11-18 12:17:34 +01:00
|
|
|
static inline const struct shell_static_entry *
|
|
|
|
selected_cmd_get(const struct shell *shell)
|
|
|
|
{
|
2021-06-11 16:19:03 +02:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_CMDS_SELECT)
|
|
|
|
|| (CONFIG_SHELL_CMD_ROOT[0] != 0)) {
|
|
|
|
return shell->ctx->selected_cmd;
|
2020-11-18 12:17:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
static void tab_item_print(const struct shell *shell, const char *option,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t longest_option)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
static const char *tab = " ";
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t columns;
|
|
|
|
uint16_t diff;
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
/* Function initialization has been requested. */
|
|
|
|
if (option == NULL) {
|
|
|
|
shell->ctx->vt100_ctx.printed_cmd = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
longest_option += z_shell_strlen(tab);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
columns = (shell->ctx->vt100_ctx.cons.terminal_wid
|
2020-12-07 16:10:11 +01:00
|
|
|
- z_shell_strlen(tab)) / longest_option;
|
|
|
|
diff = longest_option - z_shell_strlen(option);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2019-03-27 02:57:45 +01:00
|
|
|
if (shell->ctx->vt100_ctx.printed_cmd++ % columns == 0U) {
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_OPTION, "\n%s%s", tab, option);
|
2018-08-09 09:56:10 +02:00
|
|
|
} else {
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_OPTION, "%s", option);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_horiz_move(shell, diff);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2018-08-09 10:38:15 +02:00
|
|
|
static void history_init(const struct shell *shell)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-07 10:25:28 +01:00
|
|
|
z_shell_history_init(shell->history);
|
2018-08-09 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void history_purge(const struct shell *shell)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-07 10:25:28 +01:00
|
|
|
z_shell_history_purge(shell->history);
|
2018-08-09 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void history_mode_exit(const struct shell *shell)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_history_exit_set(shell, false);
|
2020-12-07 10:25:28 +01:00
|
|
|
z_shell_history_mode_exit(shell->history);
|
2018-08-09 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static void history_put(const struct shell *shell, uint8_t *line, size_t length)
|
2018-08-09 10:38:15 +02:00
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-07 10:25:28 +01:00
|
|
|
z_shell_history_put(shell->history, line, length);
|
2018-08-09 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void history_handle(const struct shell *shell, bool up)
|
|
|
|
{
|
|
|
|
bool history_mode;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t len;
|
2018-08-09 10:38:15 +02:00
|
|
|
|
|
|
|
/*optional feature */
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-23 19:17:28 +02:00
|
|
|
/* Checking if history process has been stopped */
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_history_exit_get(shell)) {
|
|
|
|
z_flag_history_exit_set(shell, false);
|
2020-12-07 10:25:28 +01:00
|
|
|
z_shell_history_mode_exit(shell->history);
|
2018-10-23 19:17:28 +02:00
|
|
|
}
|
|
|
|
|
2018-08-09 10:38:15 +02:00
|
|
|
/* Backup command if history is entered */
|
2020-12-07 10:25:28 +01:00
|
|
|
if (!z_shell_history_active(shell->history)) {
|
2018-08-09 10:38:15 +02:00
|
|
|
if (up) {
|
2020-12-07 16:10:11 +01:00
|
|
|
uint16_t cmd_len = z_shell_strlen(shell->ctx->cmd_buff);
|
2018-08-09 10:38:15 +02:00
|
|
|
|
|
|
|
if (cmd_len) {
|
|
|
|
strcpy(shell->ctx->temp_buff,
|
|
|
|
shell->ctx->cmd_buff);
|
|
|
|
} else {
|
|
|
|
shell->ctx->temp_buff[0] = '\0';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Pressing 'down' not in history mode has no effect. */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start by checking if history is not empty. */
|
2020-12-07 10:25:28 +01:00
|
|
|
history_mode = z_shell_history_get(shell->history, up,
|
|
|
|
shell->ctx->cmd_buff, &len);
|
2018-08-09 10:38:15 +02:00
|
|
|
|
|
|
|
/* On exiting history mode print backed up command. */
|
|
|
|
if (!history_mode) {
|
|
|
|
strcpy(shell->ctx->cmd_buff, shell->ctx->temp_buff);
|
2020-12-07 16:10:11 +01:00
|
|
|
len = z_shell_strlen(shell->ctx->cmd_buff);
|
2018-08-09 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_home_move(shell);
|
|
|
|
z_clear_eos(shell);
|
|
|
|
z_shell_print_cmd(shell);
|
2018-10-23 19:17:28 +02:00
|
|
|
shell->ctx->cmd_buff_pos = len;
|
|
|
|
shell->ctx->cmd_buff_len = len;
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cond_next_line(shell);
|
2018-08-09 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline uint16_t completion_space_get(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t space = (CONFIG_SHELL_CMD_BUFF_SIZE - 1) -
|
2018-08-09 09:56:10 +02:00
|
|
|
shell->ctx->cmd_buff_len;
|
|
|
|
return space;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prepare arguments and return number of space available for completion. */
|
2018-12-13 10:26:49 +01:00
|
|
|
static bool tab_prepare(const struct shell *shell,
|
|
|
|
const struct shell_static_entry **cmd,
|
2020-04-14 09:01:57 +02:00
|
|
|
const char ***argv, size_t *argc,
|
2018-12-13 10:26:49 +01:00
|
|
|
size_t *complete_arg_idx,
|
|
|
|
struct shell_static_entry *d_entry)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t compl_space = completion_space_get(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
size_t search_argc;
|
|
|
|
|
2019-03-27 02:57:45 +01:00
|
|
|
if (compl_space == 0U) {
|
2018-08-09 09:56:10 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy command from its beginning to cursor position. */
|
|
|
|
memcpy(shell->ctx->temp_buff, shell->ctx->cmd_buff,
|
|
|
|
shell->ctx->cmd_buff_pos);
|
|
|
|
shell->ctx->temp_buff[shell->ctx->cmd_buff_pos] = '\0';
|
|
|
|
|
|
|
|
/* Create argument list. */
|
2020-12-07 16:10:11 +01:00
|
|
|
(void)z_shell_make_argv(argc, *argv, shell->ctx->temp_buff,
|
|
|
|
CONFIG_SHELL_ARGC_MAX);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-09-18 10:38:31 +02:00
|
|
|
if (*argc > CONFIG_SHELL_ARGC_MAX) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* terminate arguments with NULL */
|
|
|
|
(*argv)[*argc] = NULL;
|
|
|
|
|
2021-06-11 16:19:03 +02:00
|
|
|
if ((IS_ENABLED(CONFIG_SHELL_CMDS_SELECT) || (CONFIG_SHELL_CMD_ROOT[0] != 0))
|
|
|
|
&& (*argc > 0) &&
|
2020-07-29 11:46:33 +02:00
|
|
|
(strcmp("select", (*argv)[0]) == 0) &&
|
2020-12-07 16:10:11 +01:00
|
|
|
!z_shell_in_select_mode(shell)) {
|
2019-05-16 11:02:53 +02:00
|
|
|
*argv = *argv + 1;
|
|
|
|
*argc = *argc - 1;
|
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
/* If last command is not completed (followed by space) it is treated
|
|
|
|
* as uncompleted one.
|
|
|
|
*/
|
|
|
|
int space = isspace((int)shell->ctx->cmd_buff[
|
|
|
|
shell->ctx->cmd_buff_pos - 1]);
|
|
|
|
|
|
|
|
/* root command completion */
|
|
|
|
if ((*argc == 0) || ((space == 0) && (*argc == 1))) {
|
2020-12-07 12:32:18 +01:00
|
|
|
*complete_arg_idx = Z_SHELL_CMD_ROOT_LVL;
|
2020-11-18 12:17:34 +01:00
|
|
|
*cmd = selected_cmd_get(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
search_argc = space ? *argc : *argc - 1;
|
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
*cmd = z_shell_get_last_command(selected_cmd_get(shell), search_argc,
|
|
|
|
*argv, complete_arg_idx, d_entry,
|
|
|
|
false);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2019-05-16 11:02:53 +02:00
|
|
|
/* if search_argc == 0 (empty command line) shell_get_last_command will
|
|
|
|
* return NULL tab is allowed, otherwise not.
|
2018-08-09 09:56:10 +02:00
|
|
|
*/
|
|
|
|
if ((*cmd == NULL) && (search_argc != 0)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool is_completion_candidate(const char *candidate,
|
|
|
|
const char *str, size_t len)
|
|
|
|
{
|
|
|
|
return (strncmp(candidate, str, len) == 0) ? true : false;
|
|
|
|
}
|
|
|
|
|
2019-05-16 11:02:53 +02:00
|
|
|
static void find_completion_candidates(const struct shell *shell,
|
|
|
|
const struct shell_static_entry *cmd,
|
2018-08-09 09:56:10 +02:00
|
|
|
const char *incompl_cmd,
|
|
|
|
size_t *first_idx, size_t *cnt,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t *longest)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
const struct shell_static_entry *candidate;
|
2020-04-08 15:42:06 +02:00
|
|
|
struct shell_static_entry dloc;
|
2020-11-18 14:24:57 +01:00
|
|
|
size_t incompl_cmd_len;
|
2018-08-09 09:56:10 +02:00
|
|
|
size_t idx = 0;
|
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
incompl_cmd_len = z_shell_strlen(incompl_cmd);
|
2018-11-29 20:23:03 +01:00
|
|
|
*longest = 0U;
|
2018-08-09 09:56:10 +02:00
|
|
|
*cnt = 0;
|
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
while ((candidate = z_shell_cmd_get(cmd, idx, &dloc)) != NULL) {
|
2019-02-04 11:38:43 +01:00
|
|
|
bool is_candidate;
|
|
|
|
is_candidate = is_completion_candidate(candidate->syntax,
|
|
|
|
incompl_cmd, incompl_cmd_len);
|
2020-07-23 13:14:44 +02:00
|
|
|
if (is_candidate) {
|
2020-04-08 15:42:06 +02:00
|
|
|
*longest = Z_MAX(strlen(candidate->syntax), *longest);
|
|
|
|
if (*cnt == 0) {
|
2018-08-09 09:56:10 +02:00
|
|
|
*first_idx = idx;
|
|
|
|
}
|
2020-04-08 15:42:06 +02:00
|
|
|
(*cnt)++;
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
2020-04-08 15:42:06 +02:00
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void autocomplete(const struct shell *shell,
|
|
|
|
const struct shell_static_entry *cmd,
|
|
|
|
const char *arg,
|
|
|
|
size_t subcmd_idx)
|
|
|
|
{
|
|
|
|
const struct shell_static_entry *match;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t cmd_len;
|
2020-12-07 16:10:11 +01:00
|
|
|
uint16_t arg_len = z_shell_strlen(arg);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
/* shell->ctx->active_cmd can be safely used outside of command context
|
|
|
|
* to save stack
|
|
|
|
*/
|
2020-12-07 16:10:11 +01:00
|
|
|
match = z_shell_cmd_get(cmd, subcmd_idx, &shell->ctx->active_cmd);
|
2020-04-08 15:42:06 +02:00
|
|
|
__ASSERT_NO_MSG(match != NULL);
|
2020-12-07 16:10:11 +01:00
|
|
|
cmd_len = z_shell_strlen(match->syntax);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-11-18 14:24:57 +01:00
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_TAB_AUTOCOMPLETION)) {
|
|
|
|
/* Add a space if the Tab button is pressed when command is
|
|
|
|
* complete.
|
|
|
|
*/
|
|
|
|
if (cmd_len == arg_len) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_char_insert(shell, ' ');
|
2020-11-18 14:24:57 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
/* no exact match found */
|
|
|
|
if (cmd_len != arg_len) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_completion_insert(shell,
|
|
|
|
match->syntax + arg_len,
|
|
|
|
cmd_len - arg_len);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Next character in the buffer is not 'space'. */
|
|
|
|
if (!isspace((int) shell->ctx->cmd_buff[
|
|
|
|
shell->ctx->cmd_buff_pos])) {
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_insert_mode_get(shell)) {
|
|
|
|
z_flag_insert_mode_set(shell, false);
|
|
|
|
z_shell_op_char_insert(shell, ' ');
|
|
|
|
z_flag_insert_mode_set(shell, true);
|
2018-08-09 09:56:10 +02:00
|
|
|
} else {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_char_insert(shell, ' ');
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* case:
|
|
|
|
* | | -> cursor
|
|
|
|
* cons_name $: valid_cmd valid_sub_cmd| |argument <tab>
|
|
|
|
*/
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, 1);
|
2018-08-09 09:56:10 +02:00
|
|
|
/* result:
|
|
|
|
* cons_name $: valid_cmd valid_sub_cmd |a|rgument
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
static size_t str_common(const char *s1, const char *s2, size_t n)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
size_t common = 0;
|
|
|
|
|
|
|
|
while ((n > 0) && (*s1 == *s2) && (*s1 != '\0')) {
|
|
|
|
s1++;
|
|
|
|
s2++;
|
|
|
|
n--;
|
|
|
|
common++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return common;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tab_options_print(const struct shell *shell,
|
|
|
|
const struct shell_static_entry *cmd,
|
2018-09-26 15:43:15 +02:00
|
|
|
const char *str, size_t first, size_t cnt,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t longest)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
const struct shell_static_entry *match;
|
2020-12-07 16:10:11 +01:00
|
|
|
size_t str_len = z_shell_strlen(str);
|
2018-08-09 09:56:10 +02:00
|
|
|
size_t idx = first;
|
|
|
|
|
|
|
|
/* Printing all matching commands (options). */
|
|
|
|
tab_item_print(shell, SHELL_INIT_OPTION_PRINTER, longest);
|
|
|
|
|
2018-12-18 10:00:01 +01:00
|
|
|
while (cnt) {
|
2018-08-09 09:56:10 +02:00
|
|
|
/* shell->ctx->active_cmd can be safely used outside of command
|
|
|
|
* context to save stack
|
|
|
|
*/
|
2020-12-07 16:10:11 +01:00
|
|
|
match = z_shell_cmd_get(cmd, idx, &shell->ctx->active_cmd);
|
2020-04-08 15:42:06 +02:00
|
|
|
__ASSERT_NO_MSG(match != NULL);
|
2018-09-26 15:43:15 +02:00
|
|
|
idx++;
|
2020-07-23 13:14:44 +02:00
|
|
|
if (str && match->syntax &&
|
|
|
|
!is_completion_candidate(match->syntax, str, str_len)) {
|
2018-09-26 15:43:15 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
tab_item_print(shell, match->syntax, longest);
|
2018-12-18 10:00:01 +01:00
|
|
|
cnt--;
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_cursor_next_line_move(shell);
|
|
|
|
z_shell_print_prompt_and_cmd(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static uint16_t common_beginning_find(const struct shell *shell,
|
2019-05-16 11:02:53 +02:00
|
|
|
const struct shell_static_entry *cmd,
|
2018-08-09 09:56:10 +02:00
|
|
|
const char **str,
|
2020-05-27 18:26:57 +02:00
|
|
|
size_t first, size_t cnt, uint16_t arg_len)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
struct shell_static_entry dynamic_entry;
|
|
|
|
const struct shell_static_entry *match;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t common = UINT16_MAX;
|
2018-12-04 12:21:15 +01:00
|
|
|
size_t idx = first + 1;
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2018-12-06 14:16:09 +01:00
|
|
|
__ASSERT_NO_MSG(cnt > 1);
|
2018-11-26 17:09:56 +01:00
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
match = z_shell_cmd_get(cmd, first, &dynamic_entry);
|
2020-04-08 15:42:06 +02:00
|
|
|
__ASSERT_NO_MSG(match);
|
2019-10-17 12:16:54 +02:00
|
|
|
strncpy(shell->ctx->temp_buff, match->syntax,
|
2019-11-21 12:51:53 +01:00
|
|
|
sizeof(shell->ctx->temp_buff) - 1);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
*str = match->syntax;
|
|
|
|
|
2018-12-04 12:21:15 +01:00
|
|
|
while (cnt > 1) {
|
2018-08-09 09:56:10 +02:00
|
|
|
struct shell_static_entry dynamic_entry2;
|
|
|
|
const struct shell_static_entry *match2;
|
|
|
|
int curr_common;
|
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
match2 = z_shell_cmd_get(cmd, idx++, &dynamic_entry2);
|
2018-12-04 12:21:15 +01:00
|
|
|
if (match2 == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2019-10-17 12:16:54 +02:00
|
|
|
curr_common = str_common(shell->ctx->temp_buff, match2->syntax,
|
2018-12-13 10:26:49 +01:00
|
|
|
UINT16_MAX);
|
2018-12-04 12:21:15 +01:00
|
|
|
if ((arg_len == 0U) || (curr_common >= arg_len)) {
|
|
|
|
--cnt;
|
|
|
|
common = (curr_common < common) ? curr_common : common;
|
|
|
|
}
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return common;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void partial_autocomplete(const struct shell *shell,
|
|
|
|
const struct shell_static_entry *cmd,
|
|
|
|
const char *arg,
|
|
|
|
size_t first, size_t cnt)
|
|
|
|
{
|
|
|
|
const char *completion;
|
2020-12-07 16:10:11 +01:00
|
|
|
uint16_t arg_len = z_shell_strlen(arg);
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t common = common_beginning_find(shell, cmd, &completion, first,
|
2019-05-16 11:02:53 +02:00
|
|
|
cnt, arg_len);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-11-18 14:24:57 +01:00
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_TAB_AUTOCOMPLETION)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
if (common) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_completion_insert(shell, &completion[arg_len],
|
|
|
|
common - arg_len);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-14 09:01:57 +02:00
|
|
|
static int exec_cmd(const struct shell *shell, size_t argc, const char **argv,
|
2019-02-07 11:07:07 +01:00
|
|
|
const struct shell_static_entry *help_entry)
|
2018-12-13 10:26:49 +01:00
|
|
|
{
|
|
|
|
int ret_val = 0;
|
|
|
|
|
|
|
|
if (shell->ctx->active_cmd.handler == NULL) {
|
2019-02-07 11:07:07 +01:00
|
|
|
if ((help_entry != NULL) && IS_ENABLED(CONFIG_SHELL_HELP)) {
|
|
|
|
if (help_entry->help == NULL) {
|
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
if (help_entry->help != shell->ctx->active_cmd.help) {
|
|
|
|
shell->ctx->active_cmd = *help_entry;
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
shell_internal_help_print(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
return SHELL_CMD_HELP_PRINTED;
|
|
|
|
} else {
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_ERROR,
|
|
|
|
SHELL_MSG_SPECIFY_SUBCOMMAND);
|
2018-12-13 10:26:49 +01:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-12 14:09:19 +01:00
|
|
|
if (shell->ctx->active_cmd.args.mandatory) {
|
2020-05-27 18:26:57 +02:00
|
|
|
uint32_t mand = shell->ctx->active_cmd.args.mandatory;
|
|
|
|
uint8_t opt8 = shell->ctx->active_cmd.args.optional;
|
|
|
|
uint32_t opt = (opt8 == SHELL_OPT_ARG_CHECK_SKIP) ?
|
2020-04-14 09:01:57 +02:00
|
|
|
UINT16_MAX : opt8;
|
2019-02-12 14:09:19 +01:00
|
|
|
bool in_range = (argc >= mand) && (argc <= (mand + opt));
|
|
|
|
|
|
|
|
/* Check if argc is within allowed range */
|
|
|
|
ret_val = cmd_precheck(shell, in_range);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret_val) {
|
2021-01-15 14:04:21 +01:00
|
|
|
#if CONFIG_SHELL_GETOPT
|
|
|
|
z_shell_getopt_init(&shell->ctx->getopt_state);
|
|
|
|
#endif
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_cmd_ctx_set(shell, true);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
/* Unlock thread mutex in case command would like to borrow
|
|
|
|
* shell context to other thread to avoid mutex deadlock.
|
|
|
|
*/
|
|
|
|
k_mutex_unlock(&shell->ctx->wr_mtx);
|
2020-04-14 09:01:57 +02:00
|
|
|
ret_val = shell->ctx->active_cmd.handler(shell, argc,
|
|
|
|
(char **)argv);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
/* Bring back mutex to shell thread. */
|
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_cmd_ctx_set(shell, false);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
|
2020-04-14 09:01:57 +02:00
|
|
|
static void active_cmd_prepare(const struct shell_static_entry *entry,
|
|
|
|
struct shell_static_entry *active_cmd,
|
|
|
|
struct shell_static_entry *help_entry,
|
|
|
|
size_t *lvl, size_t *handler_lvl,
|
|
|
|
size_t *args_left)
|
|
|
|
{
|
|
|
|
if (entry->handler) {
|
|
|
|
*handler_lvl = *lvl;
|
|
|
|
*active_cmd = *entry;
|
|
|
|
if ((entry->subcmd == NULL)
|
|
|
|
&& entry->args.optional == SHELL_OPT_ARG_RAW) {
|
|
|
|
*args_left = entry->args.mandatory - 1;
|
|
|
|
*lvl = *lvl + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (entry->help) {
|
|
|
|
*help_entry = *entry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool wildcard_check_report(const struct shell *shell, bool found,
|
|
|
|
const struct shell_static_entry *entry)
|
|
|
|
{
|
|
|
|
/* An error occurred, fnmatch argument cannot be followed by argument
|
|
|
|
* with a handler to avoid multiple function calls.
|
|
|
|
*/
|
|
|
|
if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && found && entry->handler) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_end_move(shell);
|
|
|
|
z_shell_op_cond_next_line(shell);
|
2020-04-14 09:01:57 +02:00
|
|
|
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_ERROR,
|
2020-04-14 09:01:57 +02:00
|
|
|
"Error: requested multiple function executions\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
/* Function is analyzing the command buffer to find matching commands. Next, it
|
|
|
|
* invokes the last recognized command which has a handler and passes the rest
|
|
|
|
* of command buffer as arguments.
|
2020-04-14 09:01:57 +02:00
|
|
|
*
|
|
|
|
* By default command buffer is parsed and spaces are treated by arguments
|
|
|
|
* separators. Complex arguments are provided in quotation marks with quotation
|
|
|
|
* marks escaped within the argument. Argument parser is removing quotation
|
|
|
|
* marks at argument boundary as well as escape characters within the argument.
|
|
|
|
* However, it is possible to indicate that command shall treat remaining part
|
|
|
|
* of command buffer as the last argument without parsing. This can be used for
|
|
|
|
* commands which expects whole command buffer to be passed directly to
|
|
|
|
* the command handler without any preprocessing.
|
|
|
|
* Because of that feature, command buffer is processed argument by argument and
|
|
|
|
* decision on further processing is based on currently processed command.
|
2018-12-13 10:26:49 +01:00
|
|
|
*/
|
|
|
|
static int execute(const struct shell *shell)
|
|
|
|
{
|
2020-04-08 15:42:06 +02:00
|
|
|
struct shell_static_entry dloc; /* Memory for dynamic commands. */
|
2020-04-14 09:01:57 +02:00
|
|
|
const char *argv[CONFIG_SHELL_ARGC_MAX + 1]; /* +1 reserved for NULL */
|
2020-11-18 12:17:34 +01:00
|
|
|
const struct shell_static_entry *parent = selected_cmd_get(shell);
|
2020-04-08 15:42:06 +02:00
|
|
|
const struct shell_static_entry *entry = NULL;
|
2018-12-13 10:26:49 +01:00
|
|
|
struct shell_static_entry help_entry;
|
2020-04-14 09:01:57 +02:00
|
|
|
size_t cmd_lvl = 0;
|
2018-12-13 10:26:49 +01:00
|
|
|
size_t cmd_with_handler_lvl = 0;
|
|
|
|
bool wildcard_found = false;
|
2020-04-14 09:01:57 +02:00
|
|
|
size_t argc = 0, args_left = SIZE_MAX;
|
2018-12-13 10:26:49 +01:00
|
|
|
char quote;
|
2020-04-14 09:01:57 +02:00
|
|
|
const char **argvp;
|
|
|
|
char *cmd_buf = shell->ctx->cmd_buff;
|
|
|
|
bool has_last_handler = false;
|
2018-12-13 10:26:49 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_end_move(shell);
|
|
|
|
if (!z_shell_cursor_in_empty_line(shell)) {
|
|
|
|
z_cursor_next_line_move(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&shell->ctx->active_cmd, 0, sizeof(shell->ctx->active_cmd));
|
|
|
|
|
2020-11-18 11:57:53 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
2020-12-07 16:10:11 +01:00
|
|
|
z_shell_cmd_trim(shell);
|
2020-11-18 11:57:53 +01:00
|
|
|
history_put(shell, shell->ctx->cmd_buff,
|
|
|
|
shell->ctx->cmd_buff_len);
|
|
|
|
}
|
2018-12-13 10:26:49 +01:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_SHELL_WILDCARD)) {
|
2020-12-06 11:47:36 +01:00
|
|
|
z_shell_wildcard_prepare(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
2020-04-14 09:01:57 +02:00
|
|
|
/* Parent present means we are in select mode. */
|
|
|
|
if (parent != NULL) {
|
|
|
|
argv[0] = parent->syntax;
|
|
|
|
argv[1] = cmd_buf;
|
|
|
|
argvp = &argv[1];
|
|
|
|
active_cmd_prepare(parent, &shell->ctx->active_cmd, &help_entry,
|
|
|
|
&cmd_lvl, &cmd_with_handler_lvl, &args_left);
|
|
|
|
cmd_lvl++;
|
|
|
|
} else {
|
|
|
|
help_entry.help = NULL;
|
|
|
|
argvp = &argv[0];
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Below loop is analyzing subcommands of found root command. */
|
2020-09-11 09:54:12 +02:00
|
|
|
while ((argc != 1) && (cmd_lvl < CONFIG_SHELL_ARGC_MAX)
|
2020-04-14 09:01:57 +02:00
|
|
|
&& args_left > 0) {
|
2020-12-07 16:10:11 +01:00
|
|
|
quote = z_shell_make_argv(&argc, argvp, cmd_buf, 2);
|
2020-04-14 09:01:57 +02:00
|
|
|
cmd_buf = (char *)argvp[1];
|
|
|
|
|
|
|
|
if (argc == 0) {
|
|
|
|
return -ENOEXEC;
|
|
|
|
} else if ((argc == 1) && (quote != 0)) {
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_ERROR,
|
|
|
|
"not terminated: %c\n", quote);
|
2020-04-14 09:01:57 +02:00
|
|
|
return -ENOEXEC;
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
2019-02-08 14:51:21 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_HELP) && (cmd_lvl > 0) &&
|
2021-01-14 12:31:07 +01:00
|
|
|
z_shell_help_request(argvp[0])) {
|
2018-12-13 10:26:49 +01:00
|
|
|
/* Command called with help option so it makes no sense
|
|
|
|
* to search deeper commands.
|
|
|
|
*/
|
|
|
|
if (help_entry.help) {
|
|
|
|
shell->ctx->active_cmd = help_entry;
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
shell_internal_help_print(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
return SHELL_CMD_HELP_PRINTED;
|
|
|
|
}
|
|
|
|
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_ERROR,
|
|
|
|
SHELL_MSG_SPECIFY_SUBCOMMAND);
|
2018-12-13 10:26:49 +01:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:51:21 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && (cmd_lvl > 0)) {
|
2018-12-13 10:26:49 +01:00
|
|
|
enum shell_wildcard_status status;
|
|
|
|
|
2020-12-06 11:47:36 +01:00
|
|
|
status = z_shell_wildcard_process(shell, entry,
|
|
|
|
argvp[0]);
|
2018-12-13 10:26:49 +01:00
|
|
|
/* Wildcard character found but there is no matching
|
|
|
|
* command.
|
|
|
|
*/
|
|
|
|
if (status == SHELL_WILDCARD_CMD_NO_MATCH_FOUND) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wildcard character was not found function can process
|
|
|
|
* argument.
|
|
|
|
*/
|
|
|
|
if (status != SHELL_WILDCARD_NOT_FOUND) {
|
|
|
|
++cmd_lvl;
|
|
|
|
wildcard_found = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-14 09:01:57 +02:00
|
|
|
if (has_last_handler == false) {
|
2020-12-07 16:10:11 +01:00
|
|
|
entry = z_shell_find_cmd(parent, argvp[0], &dloc);
|
2020-04-14 09:01:57 +02:00
|
|
|
}
|
2018-12-13 10:26:49 +01:00
|
|
|
|
2020-04-14 09:01:57 +02:00
|
|
|
argvp++;
|
|
|
|
args_left--;
|
|
|
|
if (entry) {
|
|
|
|
if (wildcard_check_report(shell, wildcard_found, entry)
|
|
|
|
== false) {
|
2019-02-08 14:51:21 +01:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
2018-12-13 10:26:49 +01:00
|
|
|
|
2020-04-14 09:01:57 +02:00
|
|
|
active_cmd_prepare(entry, &shell->ctx->active_cmd,
|
|
|
|
&help_entry, &cmd_lvl,
|
|
|
|
&cmd_with_handler_lvl, &args_left);
|
|
|
|
parent = entry;
|
|
|
|
} else {
|
2020-05-23 18:42:57 +02:00
|
|
|
if (cmd_lvl == 0 &&
|
2020-12-07 16:10:11 +01:00
|
|
|
(!z_shell_in_select_mode(shell) ||
|
2020-05-23 18:42:57 +02:00
|
|
|
shell->ctx->selected_cmd->handler == NULL)) {
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_ERROR,
|
|
|
|
"%s%s\n", argv[0],
|
|
|
|
SHELL_MSG_CMD_NOT_FOUND);
|
2020-05-23 18:42:57 +02:00
|
|
|
}
|
|
|
|
|
2020-04-14 09:01:57 +02:00
|
|
|
/* last handler found - no need to search commands in
|
|
|
|
* the next iteration.
|
|
|
|
*/
|
|
|
|
has_last_handler = true;
|
|
|
|
}
|
2018-12-13 10:26:49 +01:00
|
|
|
|
2020-04-14 09:01:57 +02:00
|
|
|
if (args_left || (argc == 2)) {
|
2018-12-13 10:26:49 +01:00
|
|
|
cmd_lvl++;
|
|
|
|
}
|
2020-04-14 09:01:57 +02:00
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
2020-09-18 10:38:31 +02:00
|
|
|
if ((cmd_lvl >= CONFIG_SHELL_ARGC_MAX) && (argc == 2)) {
|
2020-09-11 09:54:12 +02:00
|
|
|
/* argc == 2 indicates that when command string was parsed
|
|
|
|
* there was more characters remaining. It means that number of
|
|
|
|
* arguments exceeds the limit.
|
|
|
|
*/
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_ERROR, "%s\n",
|
|
|
|
SHELL_MSG_TOO_MANY_ARGS);
|
2020-09-11 09:54:12 +02:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:51:21 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && wildcard_found) {
|
2020-12-06 11:47:36 +01:00
|
|
|
z_shell_wildcard_finalize(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
/* cmd_buffer has been overwritten by function finalize function
|
|
|
|
* with all expanded commands. Hence shell_make_argv needs to
|
|
|
|
* be called again.
|
|
|
|
*/
|
2020-12-07 16:10:11 +01:00
|
|
|
(void)z_shell_make_argv(&cmd_lvl,
|
|
|
|
&argv[selected_cmd_get(shell) ? 1 : 0],
|
|
|
|
shell->ctx->cmd_buff,
|
|
|
|
CONFIG_SHELL_ARGC_MAX);
|
2020-04-14 09:01:57 +02:00
|
|
|
|
2020-11-18 12:17:34 +01:00
|
|
|
if (selected_cmd_get(shell)) {
|
2020-04-14 09:01:57 +02:00
|
|
|
/* Apart from what is in the command buffer, there is
|
|
|
|
* a selected command.
|
|
|
|
*/
|
|
|
|
cmd_lvl++;
|
|
|
|
}
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
2020-09-11 09:54:12 +02:00
|
|
|
/* terminate arguments with NULL */
|
|
|
|
argv[cmd_lvl] = NULL;
|
2018-12-13 10:26:49 +01:00
|
|
|
/* Executing the deepest found handler. */
|
2020-04-14 09:01:57 +02:00
|
|
|
return exec_cmd(shell, cmd_lvl - cmd_with_handler_lvl,
|
2019-02-07 11:07:07 +01:00
|
|
|
&argv[cmd_with_handler_lvl], &help_entry);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tab_handle(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-09-18 10:38:31 +02:00
|
|
|
const char *__argv[CONFIG_SHELL_ARGC_MAX + 1];
|
2018-08-09 09:56:10 +02:00
|
|
|
/* d_entry - placeholder for dynamic command */
|
|
|
|
struct shell_static_entry d_entry;
|
|
|
|
const struct shell_static_entry *cmd;
|
2020-04-14 09:01:57 +02:00
|
|
|
const char **argv = __argv;
|
2018-12-06 14:16:09 +01:00
|
|
|
size_t first = 0;
|
2018-08-09 09:56:10 +02:00
|
|
|
size_t arg_idx;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t longest;
|
2018-08-09 09:56:10 +02:00
|
|
|
size_t argc;
|
|
|
|
size_t cnt;
|
|
|
|
|
2019-05-16 11:02:53 +02:00
|
|
|
bool tab_possible = tab_prepare(shell, &cmd, &argv, &argc, &arg_idx,
|
|
|
|
&d_entry);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
if (tab_possible == false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-16 11:02:53 +02:00
|
|
|
find_completion_candidates(shell, cmd, argv[arg_idx], &first, &cnt,
|
|
|
|
&longest);
|
2020-09-18 10:38:31 +02:00
|
|
|
|
2018-12-06 14:16:09 +01:00
|
|
|
if (cnt == 1) {
|
2018-08-09 09:56:10 +02:00
|
|
|
/* Autocompletion.*/
|
|
|
|
autocomplete(shell, cmd, argv[arg_idx], first);
|
2018-12-06 14:16:09 +01:00
|
|
|
} else if (cnt > 1) {
|
2018-09-26 15:43:15 +02:00
|
|
|
tab_options_print(shell, cmd, argv[arg_idx], first, cnt,
|
|
|
|
longest);
|
2018-08-09 09:56:10 +02:00
|
|
|
partial_autocomplete(shell, cmd, argv[arg_idx], first, cnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-11 15:08:55 +01:00
|
|
|
static void alt_metakeys_handle(const struct shell *shell, char data)
|
|
|
|
{
|
|
|
|
/* Optional feature */
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_METAKEYS)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (data == SHELL_VT100_ASCII_ALT_B) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_word_move(shell, -1);
|
2019-01-11 15:08:55 +01:00
|
|
|
} else if (data == SHELL_VT100_ASCII_ALT_F) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_word_move(shell, 1);
|
2019-05-16 11:02:53 +02:00
|
|
|
} else if (data == SHELL_VT100_ASCII_ALT_R &&
|
|
|
|
IS_ENABLED(CONFIG_SHELL_CMDS_SELECT)) {
|
2020-11-18 12:17:34 +01:00
|
|
|
if (selected_cmd_get(shell) != NULL) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_cmd_line_erase(shell);
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_WARNING,
|
2019-05-16 11:02:53 +02:00
|
|
|
"Restored default root commands\n");
|
2021-06-11 16:19:03 +02:00
|
|
|
if (CONFIG_SHELL_CMD_ROOT[0]) {
|
|
|
|
shell->ctx->selected_cmd = root_cmd_find(CONFIG_SHELL_CMD_ROOT);
|
|
|
|
} else {
|
|
|
|
shell->ctx->selected_cmd = NULL;
|
|
|
|
}
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_print_prompt_and_cmd(shell);
|
2019-05-16 11:02:53 +02:00
|
|
|
}
|
2019-01-11 15:08:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctrl_metakeys_handle(const struct shell *shell, char data)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
/* Optional feature */
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_METAKEYS)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (data) {
|
|
|
|
case SHELL_VT100_ASCII_CTRL_A: /* CTRL + A */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_home_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
2019-01-11 15:08:55 +01:00
|
|
|
case SHELL_VT100_ASCII_CTRL_B: /* CTRL + B */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_left_arrow(shell);
|
2019-01-11 15:08:55 +01:00
|
|
|
break;
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
case SHELL_VT100_ASCII_CTRL_C: /* CTRL + C */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_end_move(shell);
|
|
|
|
if (!z_shell_cursor_in_empty_line(shell)) {
|
|
|
|
z_cursor_next_line_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_history_exit_set(shell, true);
|
2018-12-13 10:26:49 +01:00
|
|
|
state_set(shell, SHELL_STATE_ACTIVE);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
2019-01-11 15:08:55 +01:00
|
|
|
case SHELL_VT100_ASCII_CTRL_D: /* CTRL + D */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_char_delete(shell);
|
2019-01-11 15:08:55 +01:00
|
|
|
break;
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
case SHELL_VT100_ASCII_CTRL_E: /* CTRL + E */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_end_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
2019-01-11 15:08:55 +01:00
|
|
|
case SHELL_VT100_ASCII_CTRL_F: /* CTRL + F */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_right_arrow(shell);
|
2019-01-11 15:08:55 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_CTRL_K: /* CTRL + K */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_delete_from_cursor(shell);
|
2019-01-11 15:08:55 +01:00
|
|
|
break;
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
case SHELL_VT100_ASCII_CTRL_L: /* CTRL + L */
|
2020-12-07 13:22:35 +01:00
|
|
|
Z_SHELL_VT100_CMD(shell, SHELL_VT100_CURSORHOME);
|
|
|
|
Z_SHELL_VT100_CMD(shell, SHELL_VT100_CLEARSCREEN);
|
|
|
|
z_shell_print_prompt_and_cmd(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
2019-06-22 13:52:48 +02:00
|
|
|
case SHELL_VT100_ASCII_CTRL_N: /* CTRL + N */
|
|
|
|
history_handle(shell, false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_CTRL_P: /* CTRL + P */
|
|
|
|
history_handle(shell, true);
|
|
|
|
break;
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
case SHELL_VT100_ASCII_CTRL_U: /* CTRL + U */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_home_move(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
cmd_buffer_clear(shell);
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_history_exit_set(shell, true);
|
|
|
|
z_clear_eos(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_CTRL_W: /* CTRL + W */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_word_remove(shell);
|
|
|
|
z_flag_history_exit_set(shell, true);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-29 09:08:20 +01:00
|
|
|
/* Functions returns true if new line character shall be processed */
|
2020-05-27 18:26:57 +02:00
|
|
|
static bool process_nl(const struct shell *shell, uint8_t data)
|
2018-11-29 09:08:20 +01:00
|
|
|
{
|
|
|
|
if ((data != '\r') && (data != '\n')) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_last_nl_set(shell, 0);
|
2018-11-29 09:08:20 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
if ((z_flag_last_nl_get(shell) == 0U) ||
|
|
|
|
(data == z_flag_last_nl_get(shell))) {
|
|
|
|
z_flag_last_nl_set(shell, data);
|
2018-11-29 09:08:20 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SHELL_ASCII_MAX_CHAR (127u)
|
|
|
|
static inline int ascii_filter(const char data)
|
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
return (uint8_t) data > SHELL_ASCII_MAX_CHAR ? -EINVAL : 0;
|
2018-11-29 09:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
static void state_collect(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
size_t count = 0;
|
|
|
|
char data;
|
|
|
|
|
|
|
|
while (true) {
|
2021-06-09 10:53:53 +02:00
|
|
|
shell_bypass_cb_t bypass = shell->ctx->bypass;
|
|
|
|
|
|
|
|
if (bypass) {
|
|
|
|
uint8_t buf[16];
|
|
|
|
|
|
|
|
(void)shell->iface->api->read(shell->iface, buf,
|
|
|
|
sizeof(buf), &count);
|
|
|
|
if (count) {
|
|
|
|
bypass(shell, buf, count);
|
|
|
|
/* Check if bypass mode ended. */
|
|
|
|
if (!(volatile shell_bypass_cb_t *)shell->ctx->bypass) {
|
|
|
|
state_set(shell, SHELL_STATE_ACTIVE);
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
(void)shell->iface->api->read(shell->iface, &data,
|
|
|
|
sizeof(data), &count);
|
|
|
|
if (count == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ascii_filter(data) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (shell->ctx->receive_state) {
|
|
|
|
case SHELL_RECEIVE_DEFAULT:
|
2018-11-29 09:08:20 +01:00
|
|
|
if (process_nl(shell, data)) {
|
2020-04-14 09:01:57 +02:00
|
|
|
if (!shell->ctx->cmd_buff_len) {
|
2018-08-09 10:38:15 +02:00
|
|
|
history_mode_exit(shell);
|
2020-12-07 13:22:35 +01:00
|
|
|
z_cursor_next_line_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
} else {
|
|
|
|
/* Command execution */
|
2019-01-25 09:48:09 +01:00
|
|
|
(void)execute(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
2018-11-29 09:08:20 +01:00
|
|
|
/* Function responsible for printing prompt
|
|
|
|
* on received NL.
|
|
|
|
*/
|
2019-01-25 09:48:09 +01:00
|
|
|
state_set(shell, SHELL_STATE_ACTIVE);
|
2019-04-05 22:52:50 +02:00
|
|
|
continue;
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
2018-11-29 09:08:20 +01:00
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
switch (data) {
|
|
|
|
case SHELL_VT100_ASCII_ESC: /* ESCAPE */
|
|
|
|
receive_state_change(shell, SHELL_RECEIVE_ESC);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\0':
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\t': /* TAB */
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_echo_get(shell) &&
|
2020-11-18 14:24:57 +01:00
|
|
|
IS_ENABLED(CONFIG_SHELL_TAB)) {
|
2018-10-23 19:17:28 +02:00
|
|
|
/* If the Tab key is pressed, "history
|
|
|
|
* mode" must be terminated because
|
|
|
|
* tab and history handlers are sharing
|
|
|
|
* the same array: temp_buff.
|
|
|
|
*/
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_history_exit_set(shell, true);
|
2018-12-13 10:26:49 +01:00
|
|
|
tab_handle(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_BSPACE: /* BACKSPACE */
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_echo_get(shell)) {
|
|
|
|
z_flag_history_exit_set(shell, true);
|
|
|
|
z_shell_op_char_backspace(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_DEL: /* DELETE */
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_echo_get(shell)) {
|
|
|
|
z_flag_history_exit_set(shell, true);
|
|
|
|
if (z_flag_mode_delete_get(shell)) {
|
|
|
|
z_shell_op_char_backspace(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
} else {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_char_delete(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (isprint((int) data)) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_history_exit_set(shell, true);
|
|
|
|
z_shell_op_char_insert(shell, data);
|
|
|
|
} else if (z_flag_echo_get(shell)) {
|
2019-01-11 15:08:55 +01:00
|
|
|
ctrl_metakeys_handle(shell, data);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_RECEIVE_ESC:
|
|
|
|
if (data == '[') {
|
|
|
|
receive_state_change(shell,
|
|
|
|
SHELL_RECEIVE_ESC_SEQ);
|
2019-01-27 13:09:39 +01:00
|
|
|
break;
|
2020-12-07 13:22:35 +01:00
|
|
|
} else if (z_flag_echo_get(shell)) {
|
2019-01-11 15:08:55 +01:00
|
|
|
alt_metakeys_handle(shell, data);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
2019-01-27 13:09:39 +01:00
|
|
|
receive_state_change(shell, SHELL_RECEIVE_DEFAULT);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_RECEIVE_ESC_SEQ:
|
|
|
|
receive_state_change(shell, SHELL_RECEIVE_DEFAULT);
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
if (!z_flag_echo_get(shell)) {
|
2019-04-05 22:52:50 +02:00
|
|
|
continue;
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (data) {
|
2018-08-09 10:38:15 +02:00
|
|
|
case 'A': /* UP arrow */
|
|
|
|
history_handle(shell, true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B': /* DOWN arrow */
|
|
|
|
history_handle(shell, false);
|
|
|
|
break;
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
case 'C': /* RIGHT arrow */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_right_arrow(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'D': /* LEFT arrow */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_left_arrow(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case '4': /* END Button in ESC[n~ mode */
|
|
|
|
receive_state_change(shell,
|
|
|
|
SHELL_RECEIVE_TILDE_EXP);
|
2020-08-21 22:45:52 +02:00
|
|
|
__fallthrough;
|
2018-08-09 09:56:10 +02:00
|
|
|
case 'F': /* END Button in VT100 mode */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_end_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case '1': /* HOME Button in ESC[n~ mode */
|
|
|
|
receive_state_change(shell,
|
|
|
|
SHELL_RECEIVE_TILDE_EXP);
|
2020-08-21 22:45:52 +02:00
|
|
|
__fallthrough;
|
2018-08-09 09:56:10 +02:00
|
|
|
case 'H': /* HOME Button in VT100 mode */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_home_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case '2': /* INSERT Button in ESC[n~ mode */
|
|
|
|
receive_state_change(shell,
|
|
|
|
SHELL_RECEIVE_TILDE_EXP);
|
2020-08-21 22:45:52 +02:00
|
|
|
__fallthrough;
|
2018-12-13 10:26:49 +01:00
|
|
|
case 'L': {/* INSERT Button in VT100 mode */
|
2020-12-07 13:22:35 +01:00
|
|
|
bool status = z_flag_insert_mode_get(shell);
|
|
|
|
z_flag_insert_mode_set(shell, !status);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
case '3':/* DELETE Button in ESC[n~ mode */
|
|
|
|
receive_state_change(shell,
|
|
|
|
SHELL_RECEIVE_TILDE_EXP);
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_echo_get(shell)) {
|
|
|
|
z_shell_op_char_delete(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_RECEIVE_TILDE_EXP:
|
|
|
|
receive_state_change(shell, SHELL_RECEIVE_DEFAULT);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
receive_state_change(shell, SHELL_RECEIVE_DEFAULT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-12-05 13:25:43 +01:00
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
z_transport_buffer_flush(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
static void transport_evt_handler(enum shell_transport_evt evt_type, void *ctx)
|
2018-11-06 14:34:11 +01:00
|
|
|
{
|
2018-12-13 10:26:49 +01:00
|
|
|
struct shell *shell = (struct shell *)ctx;
|
2018-08-09 09:56:10 +02:00
|
|
|
struct k_poll_signal *signal;
|
|
|
|
|
|
|
|
signal = (evt_type == SHELL_TRANSPORT_EVT_RX_RDY) ?
|
|
|
|
&shell->ctx->signals[SHELL_SIGNAL_RXRDY] :
|
|
|
|
&shell->ctx->signals[SHELL_SIGNAL_TXDONE];
|
2018-11-02 20:35:30 +01:00
|
|
|
k_poll_signal_raise(signal, 0);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2018-08-09 11:40:02 +02:00
|
|
|
static void shell_log_process(const struct shell *shell)
|
|
|
|
{
|
2019-01-04 14:13:41 +01:00
|
|
|
bool processed = false;
|
2018-12-05 13:25:43 +01:00
|
|
|
int signaled = 0;
|
2018-08-09 11:40:02 +02:00
|
|
|
int result;
|
|
|
|
|
|
|
|
do {
|
2019-01-04 14:13:41 +01:00
|
|
|
if (!IS_ENABLED(CONFIG_LOG_IMMEDIATE)) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_cmd_line_erase(shell);
|
2018-12-05 13:25:43 +01:00
|
|
|
|
2020-12-07 10:58:08 +01:00
|
|
|
processed = z_shell_log_backend_process(
|
|
|
|
shell->log_backend);
|
2019-01-04 14:13:41 +01:00
|
|
|
}
|
2018-08-09 11:40:02 +02:00
|
|
|
|
2019-01-25 09:48:09 +01:00
|
|
|
struct k_poll_signal *signal =
|
|
|
|
&shell->ctx->signals[SHELL_SIGNAL_RXRDY];
|
2018-12-05 13:25:43 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_print_prompt_and_cmd(shell);
|
2018-10-30 08:14:16 +01:00
|
|
|
|
2019-01-25 09:48:09 +01:00
|
|
|
/* Arbitrary delay added to ensure that prompt is
|
|
|
|
* readable and can be used to enter further commands.
|
|
|
|
*/
|
|
|
|
if (shell->ctx->cmd_buff_len) {
|
|
|
|
k_sleep(K_MSEC(15));
|
2018-12-05 13:25:43 +01:00
|
|
|
}
|
2018-08-09 11:40:02 +02:00
|
|
|
|
2019-01-25 09:48:09 +01:00
|
|
|
k_poll_signal_check(signal, &signaled, &result);
|
|
|
|
|
2018-08-09 11:40:02 +02:00
|
|
|
} while (processed && !signaled);
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
static int instance_init(const struct shell *shell, const void *p_config,
|
|
|
|
bool use_colors)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2018-12-06 14:16:09 +01:00
|
|
|
__ASSERT_NO_MSG((shell->shell_flag == SHELL_FLAG_CRLF_DEFAULT) ||
|
2018-10-05 10:49:08 +02:00
|
|
|
(shell->shell_flag == SHELL_FLAG_OLF_CRLF));
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2018-12-05 13:25:43 +01:00
|
|
|
memset(shell->ctx, 0, sizeof(*shell->ctx));
|
2019-02-08 15:37:40 +01:00
|
|
|
shell->ctx->prompt = shell->default_prompt;
|
2021-06-11 16:19:03 +02:00
|
|
|
if (CONFIG_SHELL_CMD_ROOT[0]) {
|
|
|
|
shell->ctx->selected_cmd = root_cmd_find(CONFIG_SHELL_CMD_ROOT);
|
|
|
|
}
|
2018-12-05 13:25:43 +01:00
|
|
|
|
2018-08-09 10:38:15 +02:00
|
|
|
history_init(shell);
|
|
|
|
|
2018-12-05 13:25:43 +01:00
|
|
|
k_mutex_init(&shell->ctx->wr_mtx);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2019-05-13 11:06:49 +02:00
|
|
|
for (int i = 0; i < SHELL_SIGNALS; i++) {
|
|
|
|
k_poll_signal_init(&shell->ctx->signals[i]);
|
|
|
|
k_poll_event_init(&shell->ctx->events[i],
|
|
|
|
K_POLL_TYPE_SIGNAL,
|
|
|
|
K_POLL_MODE_NOTIFY_ONLY,
|
|
|
|
&shell->ctx->signals[i]);
|
|
|
|
}
|
|
|
|
|
2018-08-09 11:40:02 +02:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_STATS)) {
|
|
|
|
shell->stats->log_lost_cnt = 0;
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_tx_rdy_set(shell, true);
|
|
|
|
z_flag_echo_set(shell, IS_ENABLED(CONFIG_SHELL_ECHO_STATUS));
|
2021-03-04 20:28:05 +01:00
|
|
|
z_flag_obscure_set(shell, IS_ENABLED(CONFIG_SHELL_START_OBSCURED));
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_mode_delete_set(shell,
|
2018-12-13 10:26:49 +01:00
|
|
|
IS_ENABLED(CONFIG_SHELL_BACKSPACE_MODE_DELETE));
|
2020-05-13 07:49:57 +02:00
|
|
|
shell->ctx->vt100_ctx.cons.terminal_wid =
|
|
|
|
CONFIG_SHELL_DEFAULT_TERMINAL_WIDTH;
|
|
|
|
shell->ctx->vt100_ctx.cons.terminal_hei =
|
|
|
|
CONFIG_SHELL_DEFAULT_TERMINAL_HEIGHT;
|
2020-12-07 16:10:11 +01:00
|
|
|
shell->ctx->vt100_ctx.cons.name_len = z_shell_strlen(shell->ctx->prompt);
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_use_colors_set(shell, IS_ENABLED(CONFIG_SHELL_VT100_COLORS));
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-08-03 12:47:06 +02:00
|
|
|
int ret = shell->iface->api->init(shell->iface, p_config,
|
|
|
|
transport_evt_handler,
|
|
|
|
(void *)shell);
|
|
|
|
if (ret == 0) {
|
2020-08-18 12:14:42 +02:00
|
|
|
state_set(shell, SHELL_STATE_INITIALIZED);
|
2020-08-03 12:47:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
static int instance_uninit(const struct shell *shell)
|
|
|
|
{
|
|
|
|
__ASSERT_NO_MSG(shell);
|
2019-02-08 15:37:40 +01:00
|
|
|
__ASSERT_NO_MSG(shell->ctx && shell->iface);
|
2018-12-13 10:26:49 +01:00
|
|
|
|
|
|
|
int err;
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_processing_get(shell)) {
|
2018-12-13 10:26:49 +01:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2019-09-23 02:19:19 +02:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) {
|
2018-12-13 10:26:49 +01:00
|
|
|
/* todo purge log queue */
|
2020-12-07 10:58:08 +01:00
|
|
|
z_shell_log_backend_disable(shell->log_backend);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
err = shell->iface->api->uninit(shell->iface);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
history_purge(shell);
|
2020-08-18 12:14:42 +02:00
|
|
|
state_set(shell, SHELL_STATE_UNINITIALIZED);
|
2018-12-13 10:26:49 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2018-12-05 13:25:43 +01:00
|
|
|
typedef void (*shell_signal_handler_t)(const struct shell *shell);
|
|
|
|
|
|
|
|
static void shell_signal_handle(const struct shell *shell,
|
|
|
|
enum shell_signal sig_idx,
|
|
|
|
shell_signal_handler_t handler)
|
|
|
|
{
|
|
|
|
struct k_poll_signal *signal = &shell->ctx->signals[sig_idx];
|
|
|
|
int set;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
k_poll_signal_check(signal, &set, &res);
|
|
|
|
|
|
|
|
if (set) {
|
|
|
|
k_poll_signal_reset(signal);
|
|
|
|
handler(shell);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kill_handler(const struct shell *shell)
|
|
|
|
{
|
2021-03-18 11:05:01 +01:00
|
|
|
int err = instance_uninit(shell);
|
|
|
|
|
|
|
|
if (shell->ctx->uninit_cb) {
|
|
|
|
shell->ctx->uninit_cb(shell, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
shell->ctx->tid = NULL;
|
2018-12-05 13:25:43 +01:00
|
|
|
k_thread_abort(k_current_get());
|
|
|
|
}
|
|
|
|
|
2018-10-30 08:14:16 +01:00
|
|
|
void shell_thread(void *shell_handle, void *arg_log_backend,
|
|
|
|
void *arg_log_level)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2019-05-21 21:48:45 +02:00
|
|
|
struct shell *shell = shell_handle;
|
2018-10-30 08:14:16 +01:00
|
|
|
bool log_backend = (bool)arg_log_backend;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint32_t log_level = POINTER_TO_UINT(arg_log_level);
|
2018-08-09 09:56:10 +02:00
|
|
|
int err;
|
|
|
|
|
2019-01-04 14:13:41 +01:00
|
|
|
err = shell->iface->api->enable(shell->iface, false);
|
2018-08-09 09:56:10 +02:00
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-11 16:19:03 +02:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND) && log_backend
|
|
|
|
&& !IS_ENABLED(CONFIG_SHELL_START_OBSCURED)) {
|
2020-12-07 10:58:08 +01:00
|
|
|
z_shell_log_backend_enable(shell->log_backend, (void *)shell,
|
|
|
|
log_level);
|
2018-10-30 08:14:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-04 14:13:41 +01:00
|
|
|
/* Enable shell and print prompt. */
|
|
|
|
err = shell_start(shell);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
while (true) {
|
2019-01-29 11:41:08 +01:00
|
|
|
/* waiting for all signals except SHELL_SIGNAL_TXDONE */
|
2019-01-29 11:40:08 +01:00
|
|
|
err = k_poll(shell->ctx->events, SHELL_SIGNAL_TXDONE,
|
|
|
|
K_FOREVER);
|
|
|
|
|
2018-12-06 14:16:09 +01:00
|
|
|
if (err != 0) {
|
2020-08-05 10:59:12 +02:00
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_ERROR,
|
|
|
|
"Shell thread error: %d", err);
|
2020-08-05 10:59:12 +02:00
|
|
|
k_mutex_unlock(&shell->ctx->wr_mtx);
|
2018-12-06 14:16:09 +01:00
|
|
|
return;
|
|
|
|
}
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-04-05 18:43:25 +02:00
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
|
|
|
|
2019-01-29 11:40:08 +01:00
|
|
|
if (shell->iface->api->update) {
|
|
|
|
shell->iface->api->update(shell->iface);
|
|
|
|
}
|
|
|
|
|
2018-12-05 13:25:43 +01:00
|
|
|
shell_signal_handle(shell, SHELL_SIGNAL_KILL, kill_handler);
|
|
|
|
shell_signal_handle(shell, SHELL_SIGNAL_RXRDY, shell_process);
|
2019-09-23 02:19:19 +02:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) {
|
2018-12-05 13:25:43 +01:00
|
|
|
shell_signal_handle(shell, SHELL_SIGNAL_LOG_MSG,
|
|
|
|
shell_log_process);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
2019-01-29 11:40:08 +01:00
|
|
|
|
|
|
|
k_mutex_unlock(&shell->ctx->wr_mtx);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int shell_init(const struct shell *shell, const void *transport_config,
|
2020-05-27 18:26:57 +02:00
|
|
|
bool use_colors, bool log_backend, uint32_t init_log_level)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2018-09-25 08:57:32 +02:00
|
|
|
__ASSERT_NO_MSG(shell);
|
2019-02-08 15:37:40 +01:00
|
|
|
__ASSERT_NO_MSG(shell->ctx && shell->iface && shell->default_prompt);
|
2018-12-06 14:16:09 +01:00
|
|
|
|
2021-03-18 11:05:01 +01:00
|
|
|
if (shell->ctx->tid) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
int err = instance_init(shell, transport_config, use_colors);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-03-03 09:31:05 +01:00
|
|
|
k_tid_t tid = k_thread_create(shell->thread,
|
2018-08-09 09:56:10 +02:00
|
|
|
shell->stack, CONFIG_SHELL_STACK_SIZE,
|
2018-10-30 08:14:16 +01:00
|
|
|
shell_thread, (void *)shell, (void *)log_backend,
|
2019-05-21 21:48:45 +02:00
|
|
|
UINT_TO_POINTER(init_log_level),
|
2018-12-05 07:44:24 +01:00
|
|
|
K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2018-12-05 13:25:43 +01:00
|
|
|
shell->ctx->tid = tid;
|
2018-11-19 13:24:25 +01:00
|
|
|
k_thread_name_set(tid, shell->thread_name);
|
2018-10-30 08:14:16 +01:00
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-18 11:05:01 +01:00
|
|
|
void shell_uninit(const struct shell *shell, shell_uninit_cb_t cb)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2018-12-06 14:16:09 +01:00
|
|
|
__ASSERT_NO_MSG(shell);
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
if (IS_ENABLED(CONFIG_MULTITHREADING)) {
|
2018-12-06 09:09:31 +01:00
|
|
|
struct k_poll_signal *signal =
|
|
|
|
&shell->ctx->signals[SHELL_SIGNAL_KILL];
|
|
|
|
|
2021-03-18 11:05:01 +01:00
|
|
|
shell->ctx->uninit_cb = cb;
|
2018-08-09 09:56:10 +02:00
|
|
|
/* signal kill message */
|
2018-12-06 09:09:31 +01:00
|
|
|
(void)k_poll_signal_raise(signal, 0);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2021-03-18 11:05:01 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int err = instance_uninit(shell);
|
|
|
|
|
|
|
|
if (cb) {
|
|
|
|
cb(shell, err);
|
2018-08-09 09:56:10 +02:00
|
|
|
} else {
|
2021-03-18 11:05:01 +01:00
|
|
|
__ASSERT_NO_MSG(0);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int shell_start(const struct shell *shell)
|
|
|
|
{
|
2018-09-25 08:57:32 +02:00
|
|
|
__ASSERT_NO_MSG(shell);
|
2019-02-08 15:37:40 +01:00
|
|
|
__ASSERT_NO_MSG(shell->ctx && shell->iface && shell->default_prompt);
|
2018-12-06 14:16:09 +01:00
|
|
|
|
2020-08-18 12:14:42 +02:00
|
|
|
if (state_get(shell) != SHELL_STATE_INITIALIZED) {
|
2018-08-09 09:56:10 +02:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2020-08-05 10:59:12 +02:00
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
|
|
|
|
2018-11-09 12:19:31 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_vt100_color_set(shell, SHELL_NORMAL);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "\n\n");
|
2018-12-13 10:26:49 +01:00
|
|
|
state_set(shell, SHELL_STATE_ACTIVE);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-08-05 10:59:12 +02:00
|
|
|
k_mutex_unlock(&shell->ctx->wr_mtx);
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int shell_stop(const struct shell *shell)
|
|
|
|
{
|
2018-09-25 08:57:32 +02:00
|
|
|
__ASSERT_NO_MSG(shell);
|
2018-12-06 14:16:09 +01:00
|
|
|
__ASSERT_NO_MSG(shell->ctx);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-08-18 12:14:42 +02:00
|
|
|
enum shell_state state = state_get(shell);
|
|
|
|
|
|
|
|
if ((state == SHELL_STATE_INITIALIZED) ||
|
|
|
|
(state == SHELL_STATE_UNINITIALIZED)) {
|
2018-08-09 09:56:10 +02:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
state_set(shell, SHELL_STATE_INITIALIZED);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void shell_process(const struct shell *shell)
|
|
|
|
{
|
2018-09-25 08:57:32 +02:00
|
|
|
__ASSERT_NO_MSG(shell);
|
2018-12-06 14:16:09 +01:00
|
|
|
__ASSERT_NO_MSG(shell->ctx);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2021-03-11 00:56:32 +01:00
|
|
|
/* atomically set the processing flag */
|
|
|
|
z_flag_processing_set(shell, true);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
switch (shell->ctx->state) {
|
|
|
|
case SHELL_STATE_UNINITIALIZED:
|
|
|
|
case SHELL_STATE_INITIALIZED:
|
|
|
|
/* Console initialized but not started. */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_STATE_ACTIVE:
|
2018-12-13 10:26:49 +01:00
|
|
|
state_collect(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-03-11 00:56:32 +01:00
|
|
|
/* atomically clear the processing flag */
|
|
|
|
z_flag_processing_set(shell, false);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
/* This function mustn't be used from shell context to avoid deadlock.
|
|
|
|
* However it can be used in shell command handlers.
|
|
|
|
*/
|
2020-04-30 23:25:04 +02:00
|
|
|
void shell_vfprintf(const struct shell *shell, enum shell_vt100_color color,
|
|
|
|
const char *fmt, va_list args)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2018-09-25 08:57:32 +02:00
|
|
|
__ASSERT_NO_MSG(shell);
|
2018-12-05 13:25:43 +01:00
|
|
|
__ASSERT(!k_is_in_isr(), "Thread context required.");
|
2021-02-19 02:02:51 +01:00
|
|
|
__ASSERT_NO_MSG(shell->ctx);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
__ASSERT_NO_MSG((shell->ctx->internal.flags.cmd_ctx == 1) ||
|
|
|
|
(k_current_get() != shell->ctx->tid));
|
2018-12-06 14:16:09 +01:00
|
|
|
__ASSERT_NO_MSG(shell->fprintf_ctx);
|
2019-01-29 11:40:08 +01:00
|
|
|
__ASSERT_NO_MSG(fmt);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-08-03 12:47:06 +02:00
|
|
|
/* Sending a message to a non-active shell leads to a dead lock. */
|
2020-08-18 12:14:42 +02:00
|
|
|
if (state_get(shell) != SHELL_STATE_ACTIVE) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_print_noinit_set(shell, true);
|
2020-08-03 12:47:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
2021-06-09 10:53:53 +02:00
|
|
|
if (!z_flag_cmd_ctx_get(shell) && !shell->ctx->bypass) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_cmd_line_erase(shell);
|
2018-12-05 13:25:43 +01:00
|
|
|
}
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_vfprintf(shell, color, fmt, args);
|
2021-06-09 10:53:53 +02:00
|
|
|
if (!z_flag_cmd_ctx_get(shell) && !shell->ctx->bypass) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_print_prompt_and_cmd(shell);
|
2019-01-29 11:40:08 +01:00
|
|
|
}
|
2020-12-07 16:10:11 +01:00
|
|
|
z_transport_buffer_flush(shell);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
k_mutex_unlock(&shell->ctx->wr_mtx);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-04-30 23:25:04 +02:00
|
|
|
/* This function mustn't be used from shell context to avoid deadlock.
|
|
|
|
* However it can be used in shell command handlers.
|
|
|
|
*/
|
|
|
|
void shell_fprintf(const struct shell *shell, enum shell_vt100_color color,
|
|
|
|
const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
shell_vfprintf(shell, color, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2020-05-06 22:56:18 +02:00
|
|
|
void shell_hexdump_line(const struct shell *shell, unsigned int offset,
|
|
|
|
const uint8_t *data, size_t len)
|
2019-03-19 17:24:34 +01:00
|
|
|
{
|
2020-05-05 15:53:21 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL, "%08X: ", offset);
|
|
|
|
|
2020-05-06 22:56:18 +02:00
|
|
|
for (i = 0; i < SHELL_HEXDUMP_BYTES_IN_LINE; i++) {
|
2020-05-05 15:53:21 +02:00
|
|
|
if (i > 0 && !(i % 8)) {
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL, " ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < len) {
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL, "%02x ",
|
|
|
|
data[i] & 0xFF);
|
|
|
|
} else {
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL, " ");
|
|
|
|
}
|
|
|
|
}
|
2019-03-19 17:24:34 +01:00
|
|
|
|
2020-05-05 15:53:21 +02:00
|
|
|
shell_fprintf(shell, SHELL_NORMAL, "|");
|
|
|
|
|
2020-05-06 22:56:18 +02:00
|
|
|
for (i = 0; i < SHELL_HEXDUMP_BYTES_IN_LINE; i++) {
|
2020-05-05 15:53:21 +02:00
|
|
|
if (i > 0 && !(i % 8)) {
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL, " ");
|
2019-03-19 17:24:34 +01:00
|
|
|
}
|
|
|
|
|
2020-05-05 15:53:21 +02:00
|
|
|
if (i < len) {
|
|
|
|
char c = data[i];
|
2019-03-19 17:24:34 +01:00
|
|
|
|
2020-05-05 15:53:21 +02:00
|
|
|
shell_fprintf(shell, SHELL_NORMAL, "%c",
|
|
|
|
isprint((int)c) ? c : '.');
|
|
|
|
} else {
|
|
|
|
shell_fprintf(shell, SHELL_NORMAL, " ");
|
2019-03-19 17:24:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 15:53:21 +02:00
|
|
|
shell_print(shell, "|");
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
void shell_hexdump(const struct shell *shell, const uint8_t *data, size_t len)
|
2020-05-05 15:53:21 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
const uint8_t *p = data;
|
2020-05-05 15:53:21 +02:00
|
|
|
size_t line_len;
|
|
|
|
|
|
|
|
while (len) {
|
2020-05-06 22:56:18 +02:00
|
|
|
line_len = MIN(len, SHELL_HEXDUMP_BYTES_IN_LINE);
|
2020-05-05 15:53:21 +02:00
|
|
|
|
|
|
|
shell_hexdump_line(shell, p - data, p, line_len);
|
|
|
|
|
|
|
|
len -= line_len;
|
|
|
|
p += line_len;
|
2019-03-19 17:24:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 15:37:40 +01:00
|
|
|
int shell_prompt_change(const struct shell *shell, const char *prompt)
|
2018-09-21 16:41:22 +02:00
|
|
|
{
|
2018-09-25 08:57:32 +02:00
|
|
|
__ASSERT_NO_MSG(shell);
|
2018-12-06 14:16:09 +01:00
|
|
|
|
2019-02-08 15:37:40 +01:00
|
|
|
if (prompt == NULL) {
|
|
|
|
return -EINVAL;
|
2018-09-21 16:41:22 +02:00
|
|
|
}
|
2019-02-08 15:37:40 +01:00
|
|
|
shell->ctx->prompt = prompt;
|
2020-12-07 16:10:11 +01:00
|
|
|
shell->ctx->vt100_ctx.cons.name_len = z_shell_strlen(prompt);
|
2019-02-08 15:37:40 +01:00
|
|
|
|
|
|
|
return 0;
|
2018-09-21 16:41:22 +02:00
|
|
|
}
|
|
|
|
|
2018-12-05 11:45:06 +01:00
|
|
|
void shell_help(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
|
|
|
shell_internal_help_print(shell);
|
|
|
|
k_mutex_unlock(&shell->ctx->wr_mtx);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
2018-10-02 09:37:19 +02:00
|
|
|
|
|
|
|
int shell_execute_cmd(const struct shell *shell, const char *cmd)
|
|
|
|
{
|
2020-12-07 16:10:11 +01:00
|
|
|
uint16_t cmd_len = z_shell_strlen(cmd);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
int ret_val;
|
2018-10-02 09:37:19 +02:00
|
|
|
|
2018-10-02 14:47:20 +02:00
|
|
|
if (cmd == NULL) {
|
2018-10-02 09:37:19 +02:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd_len > (CONFIG_SHELL_CMD_BUFF_SIZE - 1)) {
|
2018-11-19 23:49:20 +01:00
|
|
|
return -ENOMEM;
|
2018-10-02 09:37:19 +02:00
|
|
|
}
|
|
|
|
|
2018-10-02 14:47:20 +02:00
|
|
|
if (shell == NULL) {
|
2019-07-24 16:18:41 +02:00
|
|
|
#if defined(CONFIG_SHELL_BACKEND_DUMMY)
|
2018-10-02 14:47:20 +02:00
|
|
|
shell = shell_backend_dummy_get_ptr();
|
|
|
|
#else
|
|
|
|
return -EINVAL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
__ASSERT(shell->ctx->internal.flags.cmd_ctx == 0,
|
|
|
|
"Function cannot be called"
|
|
|
|
" from command context");
|
|
|
|
|
2018-10-02 09:37:19 +02:00
|
|
|
strcpy(shell->ctx->cmd_buff, cmd);
|
|
|
|
shell->ctx->cmd_buff_len = cmd_len;
|
2018-10-02 14:47:20 +02:00
|
|
|
shell->ctx->cmd_buff_pos = cmd_len;
|
2018-10-02 09:37:19 +02:00
|
|
|
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
|
|
|
ret_val = execute(shell);
|
|
|
|
k_mutex_unlock(&shell->ctx->wr_mtx);
|
|
|
|
|
|
|
|
return ret_val;
|
2018-10-02 09:37:19 +02:00
|
|
|
}
|
2020-11-17 12:23:54 +01:00
|
|
|
|
2021-03-11 00:56:32 +01:00
|
|
|
int shell_insert_mode_set(const struct shell *shell, bool val)
|
2021-03-04 20:28:05 +01:00
|
|
|
{
|
|
|
|
if (shell == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-03-11 00:56:32 +01:00
|
|
|
return (int)z_flag_insert_mode_set(shell, val);
|
|
|
|
}
|
2021-03-04 20:28:05 +01:00
|
|
|
|
2021-03-11 00:56:32 +01:00
|
|
|
int shell_use_colors_set(const struct shell *shell, bool val)
|
|
|
|
{
|
|
|
|
if (shell == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int)z_flag_use_colors_set(shell, val);
|
2021-03-04 20:28:05 +01:00
|
|
|
}
|
|
|
|
|
2021-03-11 00:56:32 +01:00
|
|
|
int shell_echo_set(const struct shell *shell, bool val)
|
2021-03-04 20:28:05 +01:00
|
|
|
{
|
|
|
|
if (shell == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-03-11 00:56:32 +01:00
|
|
|
return (int)z_flag_echo_set(shell, val);
|
|
|
|
}
|
2021-03-04 20:28:05 +01:00
|
|
|
|
2021-03-11 00:56:32 +01:00
|
|
|
int shell_obscure_set(const struct shell *shell, bool val)
|
|
|
|
{
|
|
|
|
if (shell == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int)z_flag_obscure_set(shell, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
int shell_mode_delete_set(const struct shell *shell, bool val)
|
|
|
|
{
|
|
|
|
if (shell == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int)z_flag_mode_delete_set(shell, val);
|
2021-03-04 20:28:05 +01:00
|
|
|
}
|
|
|
|
|
2021-06-09 10:53:53 +02:00
|
|
|
void shell_set_bypass(const struct shell *sh, shell_bypass_cb_t bypass)
|
|
|
|
{
|
|
|
|
sh->ctx->bypass = bypass;
|
|
|
|
}
|
|
|
|
|
2020-11-17 12:23:54 +01:00
|
|
|
static int cmd_help(const struct shell *shell, size_t argc, char **argv)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(argc);
|
|
|
|
ARG_UNUSED(argv);
|
|
|
|
|
|
|
|
#if defined(CONFIG_SHELL_TAB)
|
|
|
|
shell_print(shell, "Please press the <Tab> button to see all available "
|
|
|
|
"commands.");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_SHELL_TAB_AUTOCOMPLETION)
|
|
|
|
shell_print(shell,
|
|
|
|
"You can also use the <Tab> button to prompt or auto-complete"
|
|
|
|
" all commands or its subcommands.");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_SHELL_HELP)
|
|
|
|
shell_print(shell,
|
|
|
|
"You can try to call commands with <-h> or <--help> parameter"
|
|
|
|
" for more information.");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_SHELL_METAKEYS)
|
|
|
|
shell_print(shell,
|
|
|
|
"\nShell supports following meta-keys:\n"
|
|
|
|
" Ctrl + (a key from: abcdefklnpuw)\n"
|
|
|
|
" Alt + (a key from: bf)\n"
|
|
|
|
"Please refer to shell documentation for more details.");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_SHELL_HELP)) {
|
|
|
|
/* For NULL argument function will print all root commands */
|
2020-12-06 11:45:42 +01:00
|
|
|
z_shell_help_subcmd_print(shell, NULL,
|
|
|
|
"\nAvailable commands:\n");
|
2020-11-17 12:23:54 +01:00
|
|
|
} else {
|
|
|
|
const struct shell_static_entry *entry;
|
|
|
|
size_t idx = 0;
|
|
|
|
|
|
|
|
shell_print(shell, "\nAvailable commands:");
|
2020-12-07 16:10:11 +01:00
|
|
|
while ((entry = z_shell_cmd_get(NULL, idx++, NULL)) != NULL) {
|
2020-11-17 12:23:54 +01:00
|
|
|
shell_print(shell, " %s", entry->syntax);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SHELL_CMD_ARG_REGISTER(help, NULL, "Prints the help message.", cmd_help, 1, 0);
|