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>
|
2018-12-06 14:16:09 +01:00
|
|
|
#include <atomic.h>
|
2018-08-09 09:56:10 +02:00
|
|
|
#include <shell/shell.h>
|
2018-10-02 14:47:20 +02:00
|
|
|
#include <shell/shell_dummy.h>
|
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"
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
shell_help_cmd_print(shell);
|
|
|
|
shell_help_subcmd_print(shell);
|
|
|
|
}
|
|
|
|
|
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) {
|
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_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
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
static void state_set(const struct shell *shell, enum shell_state state)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
shell->ctx->state = state;
|
|
|
|
|
|
|
|
if (state == SHELL_STATE_ACTIVE) {
|
2018-12-13 10:26:49 +01:00
|
|
|
cmd_buffer_clear(shell);
|
2019-02-01 14:15:44 +01:00
|
|
|
shell_print_prompt_and_cmd(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tab_item_print(const struct shell *shell, const char *option,
|
|
|
|
u16_t longest_option)
|
|
|
|
{
|
|
|
|
static const char *tab = " ";
|
|
|
|
u16_t columns;
|
|
|
|
u16_t diff;
|
|
|
|
|
|
|
|
/* Function initialization has been requested. */
|
|
|
|
if (option == NULL) {
|
|
|
|
shell->ctx->vt100_ctx.printed_cmd = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
longest_option += shell_strlen(tab);
|
|
|
|
|
|
|
|
columns = (shell->ctx->vt100_ctx.cons.terminal_wid
|
|
|
|
- shell_strlen(tab)) / longest_option;
|
|
|
|
diff = longest_option - shell_strlen(option);
|
|
|
|
|
|
|
|
if (shell->ctx->vt100_ctx.printed_cmd++ % columns == 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
|
|
|
shell_internal_fprintf(shell, SHELL_OPTION, "\n%s%s", tab,
|
|
|
|
option);
|
2018-08-09 09:56:10 +02:00
|
|
|
} else {
|
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_fprintf(shell, SHELL_OPTION, "%s", option);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
shell_op_cursor_horiz_move(shell, diff);
|
|
|
|
}
|
|
|
|
|
2018-08-09 10:38:15 +02:00
|
|
|
static void history_init(const struct shell *shell)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
shell_history_init(shell->history);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void history_purge(const struct shell *shell)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
shell_history_purge(shell->history);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void history_mode_exit(const struct shell *shell)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
flag_history_exit_set(shell, false);
|
2018-08-09 10:38:15 +02:00
|
|
|
shell_history_mode_exit(shell->history);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void history_put(const struct shell *shell, u8_t *line, size_t length)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
shell_history_put(shell->history, line, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void history_handle(const struct shell *shell, bool up)
|
|
|
|
{
|
|
|
|
bool history_mode;
|
2018-12-03 22:04:38 +01:00
|
|
|
u16_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 */
|
2018-12-13 10:26:49 +01:00
|
|
|
if (flag_history_exit_get(shell)) {
|
|
|
|
flag_history_exit_set(shell, false);
|
2018-10-23 19:17:28 +02:00
|
|
|
shell_history_mode_exit(shell->history);
|
|
|
|
}
|
|
|
|
|
2018-08-09 10:38:15 +02:00
|
|
|
/* Backup command if history is entered */
|
|
|
|
if (!shell_history_active(shell->history)) {
|
|
|
|
if (up) {
|
|
|
|
u16_t cmd_len = shell_strlen(shell->ctx->cmd_buff);
|
|
|
|
|
|
|
|
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. */
|
2018-10-23 19:17:28 +02:00
|
|
|
history_mode = shell_history_get(shell->history, up,
|
2018-08-09 10:38:15 +02:00
|
|
|
shell->ctx->cmd_buff, &len);
|
|
|
|
|
|
|
|
/* On exiting history mode print backed up command. */
|
|
|
|
if (!history_mode) {
|
|
|
|
strcpy(shell->ctx->cmd_buff, shell->ctx->temp_buff);
|
|
|
|
len = shell_strlen(shell->ctx->cmd_buff);
|
|
|
|
}
|
|
|
|
|
2018-10-23 19:17:28 +02:00
|
|
|
shell_op_cursor_home_move(shell);
|
|
|
|
clear_eos(shell);
|
2019-02-01 14:15:44 +01:00
|
|
|
shell_print_cmd(shell);
|
2018-10-23 19:17:28 +02:00
|
|
|
shell->ctx->cmd_buff_pos = len;
|
|
|
|
shell->ctx->cmd_buff_len = len;
|
|
|
|
shell_op_cond_next_line(shell);
|
2018-08-09 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
static const struct shell_static_entry *find_cmd(
|
|
|
|
const struct shell_cmd_entry *cmd,
|
|
|
|
size_t lvl,
|
|
|
|
char *cmd_str,
|
|
|
|
struct shell_static_entry *d_entry)
|
|
|
|
{
|
|
|
|
const struct shell_static_entry *entry = NULL;
|
|
|
|
size_t idx = 0;
|
|
|
|
|
|
|
|
do {
|
2018-11-26 17:09:56 +01:00
|
|
|
shell_cmd_get(cmd, lvl, idx++, &entry, d_entry);
|
2018-08-09 09:56:10 +02:00
|
|
|
if (entry && (strcmp(cmd_str, entry->syntax) == 0)) {
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
} while (entry);
|
|
|
|
|
2018-12-06 14:16:09 +01:00
|
|
|
return NULL;
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @brief Function for getting last valid command in list of arguments. */
|
|
|
|
static const struct shell_static_entry *get_last_command(
|
|
|
|
const struct shell *shell,
|
|
|
|
size_t argc,
|
|
|
|
char *argv[],
|
|
|
|
size_t *match_arg,
|
|
|
|
struct shell_static_entry *d_entry)
|
|
|
|
{
|
|
|
|
const struct shell_static_entry *prev_entry = NULL;
|
|
|
|
const struct shell_cmd_entry *prev_cmd = NULL;
|
|
|
|
const struct shell_static_entry *entry = NULL;
|
|
|
|
*match_arg = SHELL_CMD_ROOT_LVL;
|
|
|
|
|
|
|
|
while (*match_arg < argc) {
|
2018-08-09 11:57:31 +02:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_SHELL_WILDCARD)) {
|
|
|
|
/* ignore wildcard argument */
|
|
|
|
if (shell_wildcard_character_exist(argv[*match_arg])) {
|
|
|
|
(*match_arg)++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
entry = find_cmd(prev_cmd, *match_arg, argv[*match_arg],
|
|
|
|
d_entry);
|
|
|
|
if (entry) {
|
|
|
|
prev_cmd = entry->subcmd;
|
|
|
|
prev_entry = entry;
|
|
|
|
(*match_arg)++;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u16_t completion_space_get(const struct shell *shell)
|
|
|
|
{
|
|
|
|
u16_t space = (CONFIG_SHELL_CMD_BUFF_SIZE - 1) -
|
|
|
|
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,
|
|
|
|
char **argv, size_t *argc,
|
|
|
|
size_t *complete_arg_idx,
|
|
|
|
struct shell_static_entry *d_entry)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
u16_t compl_space = completion_space_get(shell);
|
|
|
|
size_t search_argc;
|
|
|
|
|
|
|
|
if (compl_space == 0) {
|
|
|
|
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. */
|
|
|
|
(void)shell_make_argv(argc, argv, shell->ctx->temp_buff,
|
|
|
|
CONFIG_SHELL_ARGC_MAX);
|
|
|
|
|
|
|
|
/* 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))) {
|
|
|
|
*complete_arg_idx = SHELL_CMD_ROOT_LVL;
|
|
|
|
*cmd = NULL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
search_argc = space ? *argc : *argc - 1;
|
|
|
|
|
|
|
|
*cmd = get_last_command(shell, search_argc, argv, complete_arg_idx,
|
|
|
|
d_entry);
|
|
|
|
|
|
|
|
/* if search_argc == 0 (empty command line) get_last_command will return
|
|
|
|
* NULL tab is allowed, otherwise not.
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void find_completion_candidates(const struct shell_static_entry *cmd,
|
|
|
|
const char *incompl_cmd,
|
|
|
|
size_t *first_idx, size_t *cnt,
|
|
|
|
u16_t *longest)
|
|
|
|
{
|
|
|
|
size_t incompl_cmd_len = shell_strlen(incompl_cmd);
|
|
|
|
const struct shell_static_entry *candidate;
|
|
|
|
struct shell_static_entry dynamic_entry;
|
|
|
|
bool found = false;
|
|
|
|
size_t idx = 0;
|
|
|
|
|
2018-11-29 20:23:03 +01:00
|
|
|
*longest = 0U;
|
2018-08-09 09:56:10 +02:00
|
|
|
*cnt = 0;
|
|
|
|
|
|
|
|
while (true) {
|
2018-11-26 17:09:56 +01:00
|
|
|
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
|
|
|
idx, &candidate, &dynamic_entry);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
if (!candidate) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_completion_candidate(candidate->syntax, incompl_cmd,
|
|
|
|
incompl_cmd_len)) {
|
|
|
|
size_t slen = strlen(candidate->syntax);
|
|
|
|
|
|
|
|
*longest = (slen > *longest) ? slen : *longest;
|
|
|
|
(*cnt)++;
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
*first_idx = idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
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;
|
2018-12-03 22:04:38 +01:00
|
|
|
u16_t cmd_len;
|
|
|
|
u16_t arg_len = 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
|
|
|
|
*/
|
2018-11-26 17:09:56 +01:00
|
|
|
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
|
|
|
subcmd_idx, &match, &shell->ctx->active_cmd);
|
2018-08-09 09:56:10 +02:00
|
|
|
cmd_len = shell_strlen(match->syntax);
|
|
|
|
|
|
|
|
/* no exact match found */
|
|
|
|
if (cmd_len != arg_len) {
|
|
|
|
shell_op_completion_insert(shell,
|
|
|
|
match->syntax + arg_len,
|
|
|
|
cmd_len - arg_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next character in the buffer is not 'space'. */
|
|
|
|
if (!isspace((int) shell->ctx->cmd_buff[
|
|
|
|
shell->ctx->cmd_buff_pos])) {
|
2018-12-13 10:26:49 +01:00
|
|
|
if (flag_insert_mode_get(shell)) {
|
|
|
|
flag_insert_mode_set(shell, false);
|
2018-08-09 09:56:10 +02:00
|
|
|
shell_op_char_insert(shell, ' ');
|
2018-12-13 10:26:49 +01:00
|
|
|
flag_insert_mode_set(shell, true);
|
2018-08-09 09:56:10 +02:00
|
|
|
} else {
|
|
|
|
shell_op_char_insert(shell, ' ');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* case:
|
|
|
|
* | | -> cursor
|
|
|
|
* cons_name $: valid_cmd valid_sub_cmd| |argument <tab>
|
|
|
|
*/
|
|
|
|
shell_op_cursor_move(shell, 1);
|
|
|
|
/* 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,
|
|
|
|
u16_t longest)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
const struct shell_static_entry *match;
|
2018-12-06 14:16:09 +01:00
|
|
|
size_t str_len = 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
|
|
|
|
*/
|
2018-11-26 17:09:56 +01:00
|
|
|
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
|
|
|
idx, &match, &shell->ctx->active_cmd);
|
2018-09-26 15:43:15 +02:00
|
|
|
idx++;
|
|
|
|
|
|
|
|
if (str && match->syntax &&
|
|
|
|
!is_completion_candidate(match->syntax, str, str_len)) {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-12-06 14:16:09 +01:00
|
|
|
cursor_next_line_move(shell);
|
2019-02-01 14:15:44 +01:00
|
|
|
shell_print_prompt_and_cmd(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static u16_t common_beginning_find(const struct shell_static_entry *cmd,
|
|
|
|
const char **str,
|
2018-12-06 19:36:11 +01:00
|
|
|
size_t first, size_t cnt, u16_t arg_len)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
struct shell_static_entry dynamic_entry;
|
|
|
|
const struct shell_static_entry *match;
|
|
|
|
u16_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
|
|
|
|
|
|
|
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
|
|
|
first, &match, &dynamic_entry);
|
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;
|
|
|
|
|
2018-11-26 17:09:56 +01:00
|
|
|
shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0,
|
|
|
|
idx++, &match2, &dynamic_entry2);
|
2018-12-04 12:21:15 +01:00
|
|
|
|
|
|
|
if (match2 == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
curr_common = str_common(match->syntax, match2->syntax,
|
|
|
|
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;
|
2018-12-03 22:04:38 +01:00
|
|
|
u16_t arg_len = shell_strlen(arg);
|
|
|
|
u16_t common = common_beginning_find(cmd, &completion,
|
|
|
|
first, cnt, arg_len);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
if (common) {
|
|
|
|
shell_op_completion_insert(shell, &completion[arg_len],
|
|
|
|
common - arg_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
static int exec_cmd(const struct shell *shell, size_t argc, 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 {
|
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_fprintf(shell, SHELL_ERROR,
|
|
|
|
SHELL_MSG_SPECIFY_SUBCOMMAND);
|
2018-12-13 10:26:49 +01:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shell->ctx->active_cmd.args) {
|
|
|
|
const struct shell_static_args *args;
|
|
|
|
|
|
|
|
args = shell->ctx->active_cmd.args;
|
|
|
|
|
|
|
|
if (args->optional > 0) {
|
|
|
|
/* Check if argc is within allowed range */
|
|
|
|
ret_val = cmd_precheck(shell,
|
|
|
|
((argc >= args->mandatory)
|
|
|
|
&&
|
|
|
|
(argc <= args->mandatory +
|
|
|
|
args->optional)));
|
|
|
|
} else {
|
|
|
|
/* Perform exact match if there are no optional args */
|
|
|
|
ret_val = cmd_precheck(shell,
|
|
|
|
(args->mandatory == argc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret_val) {
|
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);
|
|
|
|
flag_cmd_ctx_set(shell, 1);
|
2018-12-13 10:26:49 +01:00
|
|
|
ret_val = shell->ctx->active_cmd.handler(shell, argc, 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
|
|
|
flag_cmd_ctx_set(shell, 0);
|
|
|
|
/* Bring back mutex to shell thread. */
|
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
static int execute(const struct shell *shell)
|
|
|
|
{
|
|
|
|
struct shell_static_entry d_entry; /* Memory for dynamic commands. */
|
|
|
|
char *argv[CONFIG_SHELL_ARGC_MAX + 1]; /* +1 reserved for NULL */
|
|
|
|
const struct shell_static_entry *p_static_entry = NULL;
|
|
|
|
const struct shell_cmd_entry *p_cmd = NULL;
|
|
|
|
struct shell_static_entry help_entry;
|
|
|
|
size_t cmd_lvl = SHELL_CMD_ROOT_LVL;
|
|
|
|
size_t cmd_with_handler_lvl = 0;
|
|
|
|
bool wildcard_found = false;
|
2019-02-08 14:51:21 +01:00
|
|
|
size_t cmd_idx = 0;
|
2018-12-13 10:26:49 +01:00
|
|
|
size_t argc;
|
|
|
|
char quote;
|
|
|
|
|
|
|
|
shell_op_cursor_end_move(shell);
|
|
|
|
if (!shell_cursor_in_empty_line(shell)) {
|
|
|
|
cursor_next_line_move(shell);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&shell->ctx->active_cmd, 0, sizeof(shell->ctx->active_cmd));
|
|
|
|
|
|
|
|
shell_cmd_trim(shell);
|
|
|
|
|
|
|
|
history_put(shell, shell->ctx->cmd_buff,
|
|
|
|
shell->ctx->cmd_buff_len);
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_SHELL_WILDCARD)) {
|
|
|
|
shell_wildcard_prepare(shell);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create argument list */
|
|
|
|
quote = shell_make_argv(&argc, &argv[0], shell->ctx->cmd_buff,
|
|
|
|
CONFIG_SHELL_ARGC_MAX);
|
|
|
|
|
|
|
|
if (!argc) {
|
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quote != 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
|
|
|
shell_internal_fprintf(shell, SHELL_ERROR,
|
|
|
|
"not terminated: %c\n",
|
|
|
|
quote);
|
2018-12-13 10:26:49 +01:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Below loop is analyzing subcommands of found root command. */
|
|
|
|
while (true) {
|
|
|
|
if (cmd_lvl >= argc) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:51:21 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_HELP) && (cmd_lvl > 0) &&
|
2018-12-13 15:14:18 +01:00
|
|
|
(!strcmp(argv[cmd_lvl], "-h") ||
|
|
|
|
!strcmp(argv[cmd_lvl], "--help"))) {
|
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;
|
|
|
|
}
|
|
|
|
|
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_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;
|
|
|
|
|
|
|
|
status = shell_wildcard_process(shell, p_cmd,
|
|
|
|
argv[cmd_lvl]);
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
shell_cmd_get(p_cmd, cmd_lvl, cmd_idx++, &p_static_entry,
|
|
|
|
&d_entry);
|
|
|
|
|
|
|
|
if ((cmd_idx == 0) || (p_static_entry == NULL)) {
|
2019-02-08 14:51:21 +01:00
|
|
|
if (cmd_lvl == 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
|
|
|
shell_internal_fprintf(shell, SHELL_ERROR,
|
|
|
|
"%s%s\n", argv[0],
|
|
|
|
SHELL_MSG_CMD_NOT_FOUND);
|
2019-02-08 14:51:21 +01:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
2018-12-13 10:26:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(argv[cmd_lvl], p_static_entry->syntax) == 0) {
|
|
|
|
/* checking if command has a handler */
|
|
|
|
if (p_static_entry->handler != NULL) {
|
2019-02-08 14:51:21 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_WILDCARD) &&
|
|
|
|
(wildcard_found)) {
|
|
|
|
shell_op_cursor_end_move(shell);
|
|
|
|
shell_op_cond_next_line(shell);
|
|
|
|
|
|
|
|
/* An error occurred, fnmatch argument
|
|
|
|
* cannot be followed by argument with
|
|
|
|
* a handler to avoid multiple function
|
|
|
|
* calls.
|
|
|
|
*/
|
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_fprintf(shell,
|
|
|
|
SHELL_ERROR,
|
2019-02-08 14:51:21 +01:00
|
|
|
"Error: requested multiple"
|
|
|
|
" function executions\n");
|
|
|
|
|
|
|
|
return -ENOEXEC;
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
shell->ctx->active_cmd = *p_static_entry;
|
|
|
|
cmd_with_handler_lvl = cmd_lvl;
|
|
|
|
}
|
|
|
|
/* checking if function has a help handler */
|
|
|
|
if (p_static_entry->help != NULL) {
|
|
|
|
help_entry = *p_static_entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd_lvl++;
|
|
|
|
cmd_idx = 0;
|
|
|
|
p_cmd = p_static_entry->subcmd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:51:21 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && wildcard_found) {
|
2018-12-13 10:26:49 +01:00
|
|
|
shell_wildcard_finalize(shell);
|
|
|
|
/* cmd_buffer has been overwritten by function finalize function
|
|
|
|
* with all expanded commands. Hence shell_make_argv needs to
|
|
|
|
* be called again.
|
|
|
|
*/
|
|
|
|
(void)shell_make_argv(&argc, &argv[0],
|
|
|
|
shell->ctx->cmd_buff,
|
|
|
|
CONFIG_SHELL_ARGC_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Executing the deepest found handler. */
|
|
|
|
return exec_cmd(shell, argc - 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
|
|
|
{
|
|
|
|
/* +1 reserved for NULL in function shell_make_argv */
|
|
|
|
char *argv[CONFIG_SHELL_ARGC_MAX + 1];
|
|
|
|
/* d_entry - placeholder for dynamic command */
|
|
|
|
struct shell_static_entry d_entry;
|
|
|
|
const struct shell_static_entry *cmd;
|
2018-12-06 14:16:09 +01:00
|
|
|
size_t first = 0;
|
2018-08-09 09:56:10 +02:00
|
|
|
size_t arg_idx;
|
|
|
|
u16_t longest;
|
|
|
|
size_t argc;
|
|
|
|
size_t cnt;
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
bool tab_possible = tab_prepare(shell, &cmd, argv, &argc,
|
2018-08-09 09:56:10 +02:00
|
|
|
&arg_idx, &d_entry);
|
|
|
|
|
|
|
|
if (tab_possible == false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
find_completion_candidates(cmd, argv[arg_idx], &first, &cnt, &longest);
|
|
|
|
|
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) {
|
|
|
|
shell_op_cursor_word_move(shell, -1);
|
|
|
|
} else if (data == SHELL_VT100_ASCII_ALT_F) {
|
|
|
|
shell_op_cursor_word_move(shell, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
|
|
|
shell_op_cursor_home_move(shell);
|
|
|
|
break;
|
|
|
|
|
2019-01-11 15:08:55 +01:00
|
|
|
case SHELL_VT100_ASCII_CTRL_B: /* CTRL + B */
|
|
|
|
shell_op_left_arrow(shell);
|
|
|
|
break;
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
case SHELL_VT100_ASCII_CTRL_C: /* CTRL + C */
|
|
|
|
shell_op_cursor_end_move(shell);
|
|
|
|
if (!shell_cursor_in_empty_line(shell)) {
|
|
|
|
cursor_next_line_move(shell);
|
|
|
|
}
|
2018-12-13 10:26:49 +01:00
|
|
|
flag_history_exit_set(shell, true);
|
|
|
|
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 */
|
|
|
|
shell_op_char_delete(shell);
|
|
|
|
break;
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
case SHELL_VT100_ASCII_CTRL_E: /* CTRL + E */
|
|
|
|
shell_op_cursor_end_move(shell);
|
|
|
|
break;
|
|
|
|
|
2019-01-11 15:08:55 +01:00
|
|
|
case SHELL_VT100_ASCII_CTRL_F: /* CTRL + F */
|
|
|
|
shell_op_right_arrow(shell);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_CTRL_K: /* CTRL + K */
|
|
|
|
shell_op_delete_from_cursor(shell);
|
|
|
|
break;
|
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
case SHELL_VT100_ASCII_CTRL_L: /* CTRL + L */
|
|
|
|
SHELL_VT100_CMD(shell, SHELL_VT100_CURSORHOME);
|
|
|
|
SHELL_VT100_CMD(shell, SHELL_VT100_CLEARSCREEN);
|
2019-02-01 14:15:44 +01:00
|
|
|
shell_print_prompt_and_cmd(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_CTRL_U: /* CTRL + U */
|
|
|
|
shell_op_cursor_home_move(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
cmd_buffer_clear(shell);
|
|
|
|
flag_history_exit_set(shell, true);
|
2018-08-09 09:56:10 +02:00
|
|
|
clear_eos(shell);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_CTRL_W: /* CTRL + W */
|
|
|
|
shell_op_word_remove(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
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 */
|
|
|
|
static bool process_nl(const struct shell *shell, u8_t data)
|
|
|
|
{
|
|
|
|
if ((data != '\r') && (data != '\n')) {
|
2018-12-13 10:26:49 +01:00
|
|
|
flag_last_nl_set(shell, 0);
|
2018-11-29 09:08:20 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
if ((flag_last_nl_get(shell) == 0) ||
|
|
|
|
(data == flag_last_nl_get(shell))) {
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
return (u8_t) data > SHELL_ASCII_MAX_CHAR ? -EINVAL : 0;
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
(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)) {
|
2018-08-09 09:56:10 +02:00
|
|
|
if (!shell->ctx->cmd_buff_len) {
|
2018-08-09 10:38:15 +02:00
|
|
|
history_mode_exit(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
cursor_next_line_move(shell);
|
|
|
|
} 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);
|
2018-08-09 09:56:10 +02:00
|
|
|
return;
|
|
|
|
}
|
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 */
|
2018-12-13 10:26:49 +01:00
|
|
|
if (flag_echo_get(shell)) {
|
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.
|
|
|
|
*/
|
2018-12-13 10:26:49 +01:00
|
|
|
flag_history_exit_set(shell, true);
|
|
|
|
tab_handle(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_BSPACE: /* BACKSPACE */
|
2018-12-13 10:26:49 +01:00
|
|
|
if (flag_echo_get(shell)) {
|
|
|
|
flag_history_exit_set(shell, true);
|
2018-08-09 09:56:10 +02:00
|
|
|
shell_op_char_backspace(shell);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHELL_VT100_ASCII_DEL: /* DELETE */
|
2018-12-13 10:26:49 +01:00
|
|
|
if (flag_echo_get(shell)) {
|
|
|
|
flag_history_exit_set(shell, true);
|
|
|
|
if (flag_mode_delete_get(shell)) {
|
2018-08-09 09:56:10 +02:00
|
|
|
shell_op_char_backspace(shell);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
shell_op_char_delete(shell);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (isprint((int) data)) {
|
2018-12-13 10:26:49 +01:00
|
|
|
flag_history_exit_set(shell, true);
|
2018-08-09 09:56:10 +02:00
|
|
|
shell_op_char_insert(shell, data);
|
2019-01-27 13:09:39 +01:00
|
|
|
} else if (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;
|
|
|
|
} else if (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);
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
if (!flag_echo_get(shell)) {
|
2018-08-09 09:56:10 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
|
|
|
shell_op_right_arrow(shell);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'D': /* LEFT arrow */
|
|
|
|
shell_op_left_arrow(shell);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '4': /* END Button in ESC[n~ mode */
|
|
|
|
receive_state_change(shell,
|
|
|
|
SHELL_RECEIVE_TILDE_EXP);
|
|
|
|
/* fall through */
|
|
|
|
/* no break */
|
|
|
|
case 'F': /* END Button in VT100 mode */
|
|
|
|
shell_op_cursor_end_move(shell);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '1': /* HOME Button in ESC[n~ mode */
|
|
|
|
receive_state_change(shell,
|
|
|
|
SHELL_RECEIVE_TILDE_EXP);
|
|
|
|
/* fall through */
|
|
|
|
/* no break */
|
|
|
|
case 'H': /* HOME Button in VT100 mode */
|
|
|
|
shell_op_cursor_home_move(shell);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '2': /* INSERT Button in ESC[n~ mode */
|
|
|
|
receive_state_change(shell,
|
|
|
|
SHELL_RECEIVE_TILDE_EXP);
|
|
|
|
/* fall through */
|
|
|
|
/* no break */
|
2018-12-13 10:26:49 +01:00
|
|
|
case 'L': {/* INSERT Button in VT100 mode */
|
|
|
|
bool status = flag_insert_mode_get(shell);
|
|
|
|
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);
|
2018-12-13 10:26:49 +01:00
|
|
|
if (flag_echo_get(shell)) {
|
2018-08-09 09:56:10 +02:00
|
|
|
shell_op_char_delete(shell);
|
|
|
|
}
|
|
|
|
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
|
|
|
|
|
|
|
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)) {
|
|
|
|
shell_cmd_line_erase(shell);
|
2018-12-05 13:25:43 +01:00
|
|
|
|
2019-01-04 14:13:41 +01:00
|
|
|
processed = shell_log_backend_process(shell->log_backend);
|
|
|
|
}
|
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
|
|
|
|
2019-02-01 14:15:44 +01:00
|
|
|
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-06 14:16:09 +01:00
|
|
|
int err = shell->iface->api->init(shell->iface, p_config,
|
2018-12-13 10:26:49 +01:00
|
|
|
transport_evt_handler,
|
2018-12-06 14:16:09 +01:00
|
|
|
(void *) shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
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;
|
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
|
|
|
|
2018-08-09 11:40:02 +02:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_STATS)) {
|
|
|
|
shell->stats->log_lost_cnt = 0;
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
flag_tx_rdy_set(shell, true);
|
|
|
|
flag_echo_set(shell, CONFIG_SHELL_ECHO_STATUS);
|
|
|
|
flag_mode_delete_set(shell,
|
|
|
|
IS_ENABLED(CONFIG_SHELL_BACKSPACE_MODE_DELETE));
|
2018-08-09 09:56:10 +02:00
|
|
|
shell->ctx->state = SHELL_STATE_INITIALIZED;
|
|
|
|
shell->ctx->vt100_ctx.cons.terminal_wid = SHELL_DEFAULT_TERMINAL_WIDTH;
|
|
|
|
shell->ctx->vt100_ctx.cons.terminal_hei = SHELL_DEFAULT_TERMINAL_HEIGHT;
|
2019-02-08 15:37:40 +01:00
|
|
|
shell->ctx->vt100_ctx.cons.name_len = shell_strlen(shell->ctx->prompt);
|
2018-12-13 10:26:49 +01:00
|
|
|
flag_use_colors_set(shell, IS_ENABLED(CONFIG_SHELL_VT100_COLORS));
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (flag_processing_get(shell)) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_LOG)) {
|
|
|
|
/* todo purge log queue */
|
|
|
|
shell_log_backend_disable(shell->log_backend);
|
|
|
|
}
|
|
|
|
|
|
|
|
err = shell->iface->api->uninit(shell->iface);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
history_purge(shell);
|
|
|
|
|
|
|
|
shell->ctx->state = SHELL_STATE_UNINITIALIZED;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
(void)instance_uninit(shell);
|
|
|
|
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
|
|
|
{
|
|
|
|
struct shell *shell = (struct shell *)shell_handle;
|
2018-10-30 08:14:16 +01:00
|
|
|
bool log_backend = (bool)arg_log_backend;
|
|
|
|
u32_t log_level = (u32_t)arg_log_level;
|
2018-08-09 09:56:10 +02:00
|
|
|
int err;
|
|
|
|
|
2018-12-06 14:16:09 +01:00
|
|
|
for (int i = 0; i < SHELL_SIGNALS; i++) {
|
2018-08-09 09:56:10 +02:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-10-30 08:14:16 +01:00
|
|
|
if (log_backend && IS_ENABLED(CONFIG_LOG)) {
|
|
|
|
shell_log_backend_enable(shell->log_backend, (void *)shell,
|
|
|
|
log_level);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2018-12-06 14:16:09 +01:00
|
|
|
if (err != 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
|
|
|
shell_internal_fprintf(shell, SHELL_ERROR,
|
|
|
|
"Shell thread error: %d", err);
|
2018-12-06 14:16:09 +01:00
|
|
|
return;
|
|
|
|
}
|
2018-08-09 09:56:10 +02:00
|
|
|
|
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);
|
|
|
|
if (IS_ENABLED(CONFIG_LOG)) {
|
|
|
|
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,
|
|
|
|
bool use_colors, bool log_backend, u32_t init_log_level)
|
|
|
|
{
|
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
|
|
|
|
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,
|
|
|
|
(void *)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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int shell_uninit(const struct shell *shell)
|
|
|
|
{
|
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];
|
|
|
|
|
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
|
|
|
|
|
|
|
return 0;
|
|
|
|
} else {
|
2018-12-13 10:26:49 +01:00
|
|
|
return instance_uninit(shell);
|
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
|
|
|
|
2018-08-09 09:56:10 +02:00
|
|
|
if (shell->ctx->state != SHELL_STATE_INITIALIZED) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2018-11-09 12:19:31 +01:00
|
|
|
if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) {
|
2018-12-13 10:26:49 +01:00
|
|
|
shell_vt100_color_set(shell, SHELL_NORMAL);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2018-12-13 09:58:17 +01:00
|
|
|
shell_raw_fprintf(shell->fprintf_ctx, "\n\n");
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2018-12-13 10:26:49 +01:00
|
|
|
state_set(shell, SHELL_STATE_ACTIVE);
|
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
|
|
|
|
|
|
|
if ((shell->ctx->state == SHELL_STATE_INITIALIZED) ||
|
|
|
|
(shell->ctx->state == SHELL_STATE_UNINITIALIZED)) {
|
|
|
|
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
|
|
|
|
|
|
|
union shell_internal internal;
|
|
|
|
|
|
|
|
internal.value = 0;
|
|
|
|
internal.flags.processing = 1;
|
|
|
|
|
|
|
|
(void)atomic_or((atomic_t *)&shell->ctx->internal.value,
|
|
|
|
internal.value);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal.value = 0xFFFFFFFF;
|
|
|
|
internal.flags.processing = 0;
|
|
|
|
(void)atomic_and((atomic_t *)&shell->ctx->internal.value,
|
|
|
|
internal.value);
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
*/
|
2018-08-09 09:56:10 +02:00
|
|
|
void shell_fprintf(const struct shell *shell, enum shell_vt100_color color,
|
2019-01-29 11:40:08 +01:00
|
|
|
const char *fmt, ...)
|
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.");
|
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->ctx);
|
|
|
|
__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
|
|
|
|
|
|
|
va_list args = { 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
|
|
|
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
|
|
|
|
if (!flag_cmd_ctx_get(shell)) {
|
2019-01-29 11:40:08 +01:00
|
|
|
shell_cmd_line_erase(shell);
|
2018-12-05 13:25:43 +01:00
|
|
|
}
|
|
|
|
|
2019-01-29 11:40:08 +01:00
|
|
|
va_start(args, fmt);
|
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_vfprintf(shell, color, fmt, args);
|
2018-08-09 09:56:10 +02:00
|
|
|
va_end(args);
|
2018-12-05 13:25:43 +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
|
|
|
if (!flag_cmd_ctx_get(shell)) {
|
2019-02-01 14:15:44 +01:00
|
|
|
shell_print_prompt_and_cmd(shell);
|
2019-01-29 11:40:08 +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
|
|
|
transport_buffer_flush(shell);
|
|
|
|
k_mutex_unlock(&shell->ctx->wr_mtx);
|
2018-08-09 09:56:10 +02: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;
|
2019-02-11 14:45:43 +01:00
|
|
|
shell->ctx->vt100_ctx.cons.name_len = 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)
|
|
|
|
{
|
|
|
|
u16_t cmd_len = 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) {
|
|
|
|
#if CONFIG_SHELL_BACKEND_DUMMY
|
|
|
|
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
|
|
|
}
|