subsys: shell: add dummy backend to simplify commands testing

Added dummy backend which can be enabled with Kconfig. By default it is
disabled because it needs the same amount of memory as other phisical
backends. It shall be use only for commands testing purposes.

Improved shell_execute_cmd function, now it clears command context
before new command will be executed.

Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
This commit is contained in:
Jakub Rzeszutko 2018-10-02 14:47:20 +02:00 committed by Anas Nashif
commit c3bc7180b0
8 changed files with 188 additions and 3 deletions

View file

@ -600,7 +600,9 @@ void shell_print_stream(const void *user_ctx, const char *data,
* Note: This by no means makes any of the commands a stable interface, so * Note: This by no means makes any of the commands a stable interface, so
* this function should only be used for debugging/diagnostic. * this function should only be used for debugging/diagnostic.
* *
* @param[in] shell Pointer to the shell instance. * @param[in] shell Pointer to the shell instance. It can be NULL when
* the :option:`CONFIG_SHELL_BACKEND_DUMMY` option is
* enabled.
* @param[in] cmd Command to be executed. * @param[in] cmd Command to be executed.
* *
* @returns Result of the execution * @returns Result of the execution

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef SHELL_DUMMY_H__
#define SHELL_DUMMY_H__
#include <shell/shell.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const struct shell_transport_api shell_dummy_transport_api;
struct shell_dummy {
bool initialized;
};
#define SHELL_DUMMY_DEFINE(_name) \
static struct shell_dummy _name##_shell_dummy; \
struct shell_transport _name = { \
.api = &shell_dummy_transport_api, \
.ctx = (struct shell_dummy *)&_name##_shell_dummy \
}
/**
* @brief This function shall not be used directly. It provides pointer to shell
* dummy backend instance.
*
* Function returns pointer to the shell dummy instance. This instance can be
* next used with shell_execute_cmd function in order to test commands behavior.
*
* @returns Pointer to the shell instance.
*/
const struct shell *shell_backend_dummy_get_ptr(void);
#ifdef __cplusplus
}
#endif
#endif /* SHELL_DUMMY_H__ */

View file

@ -31,6 +31,16 @@ struct shell_uart {
.ctx = (struct shell_uart *)&_name##_shell_uart \ .ctx = (struct shell_uart *)&_name##_shell_uart \
} }
/**
* @brief This function provides pointer to shell uart backend instance.
*
* Function returns pointer to the shell uart instance. This instance can be
* next used with shell_execute_cmd function in order to test commands behavior.
*
* @returns Pointer to the shell instance.
*/
const struct shell *shell_backend_uart_get_ptr(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -21,7 +21,12 @@ zephyr_sources_ifdef(
zephyr_sources_ifdef( zephyr_sources_ifdef(
CONFIG_SHELL_BACKEND_SERIAL CONFIG_SHELL_BACKEND_SERIAL
shell_uart.c shell_uart.c
) )
zephyr_sources_ifdef(
CONFIG_SHELL_BACKEND_DUMMY
shell_dummy.c
)
zephyr_sources_ifdef( zephyr_sources_ifdef(
CONFIG_SHELL_CMDS CONFIG_SHELL_CMDS

View file

@ -21,5 +21,12 @@ config SHELL_BACKEND_SERIAL
help help
Enable serial backends. Enable serial backends.
config SHELL_BACKEND_DUMMY
bool "Enable dummy backend."
select SERIAL
help
Enable dummy backend which can be used to test commands with no need
for physical transport interface.
endif # SHELL_BACKENDS endif # SHELL_BACKENDS

View file

@ -8,6 +8,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <shell/shell.h> #include <shell/shell.h>
#include <shell/shell_dummy.h>
#include "shell_utils.h" #include "shell_utils.h"
#include "shell_ops.h" #include "shell_ops.h"
#include "shell_wildcard.h" #include "shell_wildcard.h"
@ -1748,7 +1749,7 @@ int shell_execute_cmd(const struct shell *shell, const char *cmd)
{ {
u16_t cmd_len = shell_strlen(cmd); u16_t cmd_len = shell_strlen(cmd);
if ((cmd == NULL) || (shell == NULL)) { if (cmd == NULL) {
return -ENOEXEC; return -ENOEXEC;
} }
@ -1756,8 +1757,17 @@ int shell_execute_cmd(const struct shell *shell, const char *cmd)
return -ENOEXEC; return -ENOEXEC;
} }
if (shell == NULL) {
#if CONFIG_SHELL_BACKEND_DUMMY
shell = shell_backend_dummy_get_ptr();
#else
return -EINVAL;
#endif
}
strcpy(shell->ctx->cmd_buff, cmd); strcpy(shell->ctx->cmd_buff, cmd);
shell->ctx->cmd_buff_len = cmd_len; shell->ctx->cmd_buff_len = cmd_len;
shell->ctx->cmd_buff_pos = cmd_len;
return shell_execute(shell); return shell_execute(shell);
} }

102
subsys/shell/shell_dummy.c Normal file
View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <shell/shell_dummy.h>
#include <init.h>
SHELL_DUMMY_DEFINE(shell_transport_dummy);
SHELL_DEFINE(dummy_shell, "~$ ", &shell_transport_dummy, 10,
SHELL_FLAG_OLF_CRLF);
static int init(const struct shell_transport *transport,
const void *config,
shell_transport_handler_t evt_handler,
void *context)
{
struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx;
if (sh_dummy->initialized) {
return -EINVAL;
}
sh_dummy->initialized = true;
return 0;
}
static int uninit(const struct shell_transport *transport)
{
struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx;
if (sh_dummy->initialized == false) {
return -EINVAL;
}
sh_dummy->initialized = false;
return 0;
}
static int enable(const struct shell_transport *transport, bool blocking)
{
struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx;
if (sh_dummy->initialized == false) {
return -EINVAL;
}
return 0;
}
static int write(const struct shell_transport *transport,
const void *data, size_t length, size_t *cnt)
{
struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx;
if (!sh_dummy->initialized) {
*cnt = 0;
return -EINVAL;
}
*cnt = length;
return 0;
}
static int read(const struct shell_transport *transport,
void *data, size_t length, size_t *cnt)
{
struct shell_dummy *sh_dummy = (struct shell_dummy *)transport->ctx;
if (sh_dummy->initialized) {
return -EINVAL;
}
*cnt = 0;
return 0;
}
const struct shell_transport_api shell_dummy_transport_api = {
.init = init,
.uninit = uninit,
.enable = enable,
.write = write,
.read = read
};
static int enable_shell_dummy(struct device *arg)
{
ARG_UNUSED(arg);
shell_init(&dummy_shell, NULL, true, true, LOG_LEVEL_INF);
return 0;
}
SYS_INIT(enable_shell_dummy, POST_KERNEL, 0);
const struct shell *shell_backend_dummy_get_ptr(void)
{
return &dummy_shell;
}

View file

@ -100,3 +100,8 @@ static int enable_shell_uart(struct device *arg)
return 0; return 0;
} }
SYS_INIT(enable_shell_uart, POST_KERNEL, 0); SYS_INIT(enable_shell_uart, POST_KERNEL, 0);
const struct shell *shell_backend_uart_get_ptr(void)
{
return &uart_shell;
}