console: shell: Support multiple modules
Ability to use Zephyr shell by multiple modules simultaneously, each module for its own usage. Old shell implementation enabled the user to call only one module commands, not all of the modules simultaneously. Change-Id: I0ef8fa2fd190b7490c44fe91d1016363258302c9 Signed-off-by: Yael Avramovich <yael.avramovich@intel.com> Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
a6463a93c1
commit
d5db35204a
27 changed files with 618 additions and 70 deletions
|
@ -13,3 +13,4 @@ microkernel applications and nanokernel applications.
|
|||
common_kernel_clocks.rst
|
||||
common_atomic.rst
|
||||
common_float.rst
|
||||
common_shell.rst
|
129
doc/kernel/common/common_shell.rst
Normal file
129
doc/kernel/common/common_shell.rst
Normal file
|
@ -0,0 +1,129 @@
|
|||
.. _shell:
|
||||
|
||||
Zephyr OS Shell
|
||||
###############
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
Zephyr OS Shell enables multiple Zephyr OS modules to use and expose their
|
||||
shell interface simultaneously.
|
||||
|
||||
Each module can support shell functionality dynamically by its Kconfig file,
|
||||
which enables or disables the shell usage for the module.
|
||||
|
||||
Using shell commands
|
||||
********************
|
||||
|
||||
Use one of the following formats:
|
||||
|
||||
Specific module's commands
|
||||
==========================
|
||||
`MODULE_NAME COMMAND`
|
||||
One of the available modules is “KERNEL”, for the Kernel module.
|
||||
More information can be found in :c:macro:`SHELL_REGISTER`.
|
||||
|
||||
Help commands
|
||||
=============
|
||||
`help`
|
||||
Prints the available modules.
|
||||
`help MODULE_NAME`
|
||||
Prints the names of the available commands for the module.
|
||||
`help MODULE_NAME COMMAND`
|
||||
Prints help for the module's command (the help should show function
|
||||
goal and required parameters).
|
||||
|
||||
Select module commands
|
||||
======================
|
||||
`set_module MODULE_NAME`
|
||||
Use this command when using the shell only for one module.
|
||||
After entering this command, you will not need to enter module
|
||||
name in further commands.
|
||||
If the selected module has set a default shell prompt during its
|
||||
initialization, the prompt will be changed to that one.
|
||||
Otherwise, the prompt will be changed to the selected module’s name to
|
||||
reflect the current module in use.
|
||||
`set_module`
|
||||
Clears selected module. Restores prompt as well.
|
||||
|
||||
Shell configuration
|
||||
*******************
|
||||
There are two levels of configuration: Infrastructure level and Module level.
|
||||
|
||||
Infrastructure level
|
||||
====================
|
||||
The default value for ENABLE_SHELL flag should be considered per product.
|
||||
This flag enables shell services.
|
||||
If it is enabled, kernel shell commands are also available for use.
|
||||
See the :option:`CONFIG_ENABLE_SHELL` Kconfig options for more information.
|
||||
|
||||
Module level
|
||||
============
|
||||
Each module using shell service should add a unique flag in its Kconfig file.
|
||||
|
||||
Example:
|
||||
CONFIG_SAMPLE_MODULE_USE_SHELL=y
|
||||
|
||||
In the module’s code, the shell usage depends on this config parameter.
|
||||
This module-specific flag should also depend on ENABLE_SHELL flag.
|
||||
|
||||
Therefore, there is one global flag, in addition to a unique flag per each
|
||||
module.
|
||||
The default value for ENABLE_SHELL flag should be considered per product.
|
||||
|
||||
Configuration steps to add shell functionality to a module
|
||||
==========================================================
|
||||
#. Check that ENABLE_SHELL is set to yes.
|
||||
#. Add the module unique flag to its Kconfig file.
|
||||
|
||||
|
||||
Writing a shell module
|
||||
**********************
|
||||
In order to support shell in your module, the application must do the following:
|
||||
|
||||
#. Module configuration flag:
|
||||
Declare a new flag in your module Kconfig file.
|
||||
It should depend on `ENABLE_SHELL` flag.
|
||||
|
||||
#. Module registration to shell:
|
||||
Add your shell identifier and register its callback functions in the
|
||||
shell database using :c:macro:`SHELL_REGISTER`.
|
||||
|
||||
#. Optional:
|
||||
:c:func:`shell_register_default_module`
|
||||
|
||||
:c:func:`shell_register_prompt_handler`
|
||||
|
||||
Usage:
|
||||
In case of a sample applications as well as test environment,
|
||||
user can choose to set a default module in code level.
|
||||
In this case, the function shell_register_default_module should
|
||||
be called after calling SHELL_REGISTER in application level.
|
||||
If the function shell_register_prompt_handler was called
|
||||
as well, the prompt will be changed to that one.
|
||||
Otherwise, the prompt will be changed to the selected module’s
|
||||
name, in order to reflect the current module in use.
|
||||
|
||||
Note:
|
||||
Even if a default module was set in code level, it can be
|
||||
overwritten by “set_module” shell command.
|
||||
|
||||
When to use shell_register_default_module:
|
||||
|
||||
* Use this command in case of using the shell only for one module.
|
||||
After entering this command, no need to enter module name in further
|
||||
commands.
|
||||
|
||||
* Use this function for shell backward compatibility.
|
||||
|
||||
More details on those optional functions can be found
|
||||
in :ref:`shell_api_functions`.
|
||||
|
||||
|
||||
.. _shell_api_functions:
|
||||
|
||||
Shell Api Functions
|
||||
*******************
|
||||
.. doxygengroup:: _shell_api_functions
|
||||
:project: Zephyr
|
||||
:content-only:
|
|
@ -13,4 +13,4 @@ to applications.
|
|||
bluetooth/bluetooth.rst
|
||||
usb/usb.rst
|
||||
sensor
|
||||
power_management.rst
|
||||
power_management.rst
|
|
@ -1,3 +1,4 @@
|
|||
obj-$(CONFIG_ENABLE_SHELL) += shells/
|
||||
obj-$(CONFIG_CONSOLE_HANDLER_SHELL) += console_handler_shell.o
|
||||
obj-$(CONFIG_UART_CONSOLE) += uart_console.o
|
||||
obj-$(CONFIG_RAM_CONSOLE) += ram_console.o
|
||||
|
|
|
@ -30,12 +30,21 @@
|
|||
|
||||
#include <misc/shell.h>
|
||||
|
||||
/* maximum number of command parameters */
|
||||
#define ARGC_MAX 10
|
||||
#define COMMAND_MAX_LEN 50
|
||||
#define MODULE_NAME_MAX_LEN 20
|
||||
/* additional chars are " >" (include '\0' )*/
|
||||
#define PROMPT_SUFFIX 3
|
||||
#define PROMPT_MAX_LEN (MODULE_NAME_MAX_LEN + PROMPT_SUFFIX)
|
||||
|
||||
static const struct shell_cmd *commands;
|
||||
/* command table is located in the dedicated memory segment (.shell_) */
|
||||
extern struct shell_module __shell_cmd_start[];
|
||||
extern struct shell_module __shell_cmd_end[];
|
||||
#define NUM_OF_SHELL_ENTITIES (__shell_cmd_end - __shell_cmd_start)
|
||||
|
||||
static const char *prompt;
|
||||
static char default_module_prompt[PROMPT_MAX_LEN];
|
||||
static int default_module = -1;
|
||||
|
||||
#define STACKSIZE CONFIG_CONSOLE_HANDLER_SHELL_STACKSIZE
|
||||
static char __stack stack[STACKSIZE];
|
||||
|
@ -58,6 +67,8 @@ static const char *get_prompt(void)
|
|||
if (str) {
|
||||
return str;
|
||||
}
|
||||
} else if (default_module != -1) {
|
||||
return default_module_prompt;
|
||||
}
|
||||
|
||||
return prompt;
|
||||
|
@ -115,60 +126,194 @@ static size_t line2argv(char *str, char *argv[], size_t size)
|
|||
return argc;
|
||||
}
|
||||
|
||||
static int show_cmd_help(int argc, char *argv[])
|
||||
static int get_destination_module(const char *module_str)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!argv[0] || argv[0][0] == '\0') {
|
||||
goto done;
|
||||
for (i = 0; i < NUM_OF_SHELL_ENTITIES; i++) {
|
||||
if (!strncmp(module_str,
|
||||
__shell_cmd_start[i].module_name,
|
||||
MODULE_NAME_MAX_LEN)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; commands[i].cmd_name; i++) {
|
||||
if (!strcmp(argv[0], commands[i].cmd_name)) {
|
||||
printk("%s %s\n", commands[i].cmd_name,
|
||||
commands[i].help ? commands[i].help : "");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* For a specific command: argv[0] = module name, argv[1] = command name
|
||||
* If a default module was selected: argv[0] = command name
|
||||
*/
|
||||
static const char *get_command_and_module(char *argv[], int *module)
|
||||
{
|
||||
*module = -1;
|
||||
|
||||
if (!argv[0]) {
|
||||
printk("Unrecognized command\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (default_module == -1) {
|
||||
if (!argv[1] || argv[1][0] == '\0') {
|
||||
printk("Unrecognized command: %s\n", argv[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*module = get_destination_module(argv[0]);
|
||||
if (*module == -1) {
|
||||
printk("Illegal module %s\n", argv[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return argv[1];
|
||||
}
|
||||
|
||||
*module = default_module;
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
static int show_cmd_help(char *argv[])
|
||||
{
|
||||
const char *command = NULL;
|
||||
int module = -1;
|
||||
const struct shell_module *shell_module;
|
||||
int i;
|
||||
|
||||
command = get_command_and_module(argv, &module);
|
||||
if ((module == -1) || (command == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
shell_module = &__shell_cmd_start[module];
|
||||
for (i = 0; shell_module->commands[i].cmd_name; i++) {
|
||||
if (!strcmp(command, shell_module->commands[i].cmd_name)) {
|
||||
printk("%s %s\n",
|
||||
shell_module->commands[i].cmd_name,
|
||||
shell_module->commands[i].help ?
|
||||
shell_module->commands[i].help : "");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
printk("Unrecognized command: %s\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_help(int argc, char *argv[])
|
||||
static void print_module_commands(const int module)
|
||||
{
|
||||
const struct shell_module *shell_module = &__shell_cmd_start[module];
|
||||
int i;
|
||||
|
||||
if (argc > 1) {
|
||||
return show_cmd_help(--argc, &argv[1]);
|
||||
}
|
||||
|
||||
printk("Available commands:\n");
|
||||
printk("help\n");
|
||||
|
||||
for (i = 0; commands[i].cmd_name; i++) {
|
||||
printk("%s\n", commands[i].cmd_name);
|
||||
for (i = 0; shell_module->commands[i].cmd_name; i++) {
|
||||
printk("%s\n", shell_module->commands[i].cmd_name);
|
||||
}
|
||||
}
|
||||
|
||||
static int show_help(int argc, char *argv[])
|
||||
{
|
||||
int module;
|
||||
|
||||
/* help per command */
|
||||
if ((argc > 2) || ((default_module != -1) && (argc == 2))) {
|
||||
return show_cmd_help(&argv[1]);
|
||||
}
|
||||
|
||||
/* help per module */
|
||||
if ((argc == 2) || ((default_module != -1) && (argc == 1))) {
|
||||
if (default_module == -1) {
|
||||
module = get_destination_module(argv[1]);
|
||||
if (module == -1) {
|
||||
printk("Illegal module %s\n", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
module = default_module;
|
||||
}
|
||||
|
||||
print_module_commands(module);
|
||||
} else { /* help for all entities */
|
||||
printk("Available modules:\n");
|
||||
for (module = 0; module < NUM_OF_SHELL_ENTITIES; module++) {
|
||||
printk("%s\n", __shell_cmd_start[module].module_name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static shell_cmd_function_t get_cb(const char *string)
|
||||
static int set_default_module(const char *name)
|
||||
{
|
||||
int module;
|
||||
|
||||
if (strlen(name) > MODULE_NAME_MAX_LEN) {
|
||||
printk("Module name %s is too long, default is not changed\n",
|
||||
name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
module = get_destination_module(name);
|
||||
|
||||
if (module == -1) {
|
||||
printk("Illegal module %s, default is not changed\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
default_module = module;
|
||||
|
||||
strncpy(default_module_prompt, name, MODULE_NAME_MAX_LEN);
|
||||
strcat(default_module_prompt, "> ");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_module(int argc, char *argv[])
|
||||
{
|
||||
if (argc == 1) {
|
||||
default_module = -1;
|
||||
} else {
|
||||
set_default_module(argv[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static shell_cmd_function_t get_cb(int argc, char *argv[])
|
||||
{
|
||||
const char *first_string = argv[0];
|
||||
int module = -1;
|
||||
const struct shell_module *shell_module;
|
||||
const char *command;
|
||||
int i;
|
||||
|
||||
if (!string || string[0] == '\0') {
|
||||
if (!first_string || first_string[0] == '\0') {
|
||||
printk("Illegal parameter\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!strcmp(string, "help")) {
|
||||
if (!strcmp(first_string, "help")) {
|
||||
return show_help;
|
||||
}
|
||||
|
||||
for (i = 0; commands[i].cmd_name; i++) {
|
||||
if (!strcmp(string, commands[i].cmd_name)) {
|
||||
return commands[i].cb;
|
||||
if (!strcmp(first_string, "set_module")) {
|
||||
return set_module;
|
||||
}
|
||||
|
||||
if ((argc == 1) && (default_module == -1)) {
|
||||
printk("Missing parameter\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
command = get_command_and_module(argv, &module);
|
||||
if ((module == -1) || (command == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shell_module = &__shell_cmd_start[module];
|
||||
for (i = 0; shell_module->commands[i].cmd_name; i++) {
|
||||
if (!strcmp(command, shell_module->commands[i].cmd_name)) {
|
||||
return shell_module->commands[i].cb;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,7 +339,7 @@ static void shell(int arg1, int arg2)
|
|||
continue;
|
||||
}
|
||||
|
||||
cb = get_cb(argv[0]);
|
||||
cb = get_cb(argc, argv);
|
||||
if (!cb) {
|
||||
if (app_cmd_handler != NULL) {
|
||||
cb = app_cmd_handler;
|
||||
|
@ -208,28 +353,107 @@ static void shell(int arg1, int arg2)
|
|||
|
||||
/* Execute callback with arguments */
|
||||
if (cb(argc, argv) < 0) {
|
||||
show_cmd_help(argc, argv);
|
||||
show_cmd_help(argv);
|
||||
}
|
||||
|
||||
nano_fiber_fifo_put(&avail_queue, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static int get_command_to_complete(char *str, char *command_prefix)
|
||||
{
|
||||
char dest_str[MODULE_NAME_MAX_LEN];
|
||||
int dest = -1;
|
||||
char *start;
|
||||
|
||||
/* remove ' ' at the beginning of the line */
|
||||
while (*str && *str == ' ') {
|
||||
str++;
|
||||
}
|
||||
|
||||
if (!*str) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
start = str;
|
||||
|
||||
if (default_module != -1) {
|
||||
dest = default_module;
|
||||
/* caller function already checks str len and put '\0' */
|
||||
strncpy(command_prefix, str, COMMAND_MAX_LEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* In case of a default module: only one parameter is possible.
|
||||
* Otherwise, only two parameters are possibles.
|
||||
*/
|
||||
str = strchr(str, ' ');
|
||||
if (default_module != -1) {
|
||||
return (str == NULL) ? dest : -1;
|
||||
}
|
||||
|
||||
if (str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((str - start + 1) >= MODULE_NAME_MAX_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(dest_str, start, (str - start + 1));
|
||||
dest_str[str - start] = '\0';
|
||||
dest = get_destination_module(dest_str);
|
||||
if (dest == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
str++;
|
||||
|
||||
/* caller func has already checked str len and put '\0' at the end */
|
||||
strncpy(command_prefix, str, COMMAND_MAX_LEN);
|
||||
str = strchr(str, ' ');
|
||||
|
||||
/* only two parameters are possibles in case of no default module */
|
||||
return (str == NULL) ? dest : -1;
|
||||
}
|
||||
|
||||
static uint8_t completion(char *line, uint8_t len)
|
||||
{
|
||||
const char *first_match = NULL;
|
||||
int common_chars = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; commands[i].cmd_name; i++) {
|
||||
int i, dest, command_len, num_to_copy;
|
||||
const struct shell_module *module;
|
||||
char command_prefix[COMMAND_MAX_LEN];
|
||||
|
||||
if (len >= (MODULE_NAME_MAX_LEN + COMMAND_MAX_LEN - 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* line to completion is not ended by '\0' as the line that gets from
|
||||
* nano_fiber_fifo_get function
|
||||
*/
|
||||
line[len] = '\0';
|
||||
dest = get_command_to_complete(line, command_prefix);
|
||||
if (dest == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
command_len = strlen(command_prefix);
|
||||
|
||||
module = &__shell_cmd_start[dest];
|
||||
|
||||
for (i = 0; module->commands[i].cmd_name; i++) {
|
||||
int j;
|
||||
|
||||
if (strncmp(line, commands[i].cmd_name, len)) {
|
||||
if (strncmp(command_prefix,
|
||||
module->commands[i].cmd_name, command_len)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first_match) {
|
||||
first_match = commands[i].cmd_name;
|
||||
first_match = module->commands[i].cmd_name;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -241,14 +465,14 @@ static uint8_t completion(char *line, uint8_t len)
|
|||
|
||||
/* cut common part of matching names */
|
||||
for (j = 0; j < common_chars; j++) {
|
||||
if (first_match[j] != commands[i].cmd_name[j]) {
|
||||
if (first_match[j] != module->commands[i].cmd_name[j]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
common_chars = j;
|
||||
|
||||
printk("%s\n", commands[i].cmd_name);
|
||||
printk("%s\n", module->commands[i].cmd_name);
|
||||
}
|
||||
|
||||
/* no match, do nothing */
|
||||
|
@ -259,41 +483,36 @@ static uint8_t completion(char *line, uint8_t len)
|
|||
if (common_chars >= 0) {
|
||||
/* multiple match, restore prompt */
|
||||
printk("%s", get_prompt());
|
||||
|
||||
/* add common part after prompt */
|
||||
for (i = 0; i < common_chars; i++) {
|
||||
printk("%c", first_match[i]);
|
||||
line[i] = first_match[i];
|
||||
}
|
||||
printk("%s", line);
|
||||
} else {
|
||||
common_chars = strlen(first_match);
|
||||
|
||||
/* full command name with trailing spaces, do nothing */
|
||||
if (len > common_chars) {
|
||||
/* full command name with trailing spaces, do nothing*/
|
||||
if (command_len > common_chars) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* complete matched command name */
|
||||
for (i = len; i < common_chars; i++) {
|
||||
printk("%c", first_match[i]);
|
||||
line[i] = first_match[i];
|
||||
}
|
||||
num_to_copy = common_chars - command_len;
|
||||
|
||||
if ((num_to_copy > 0) && ((len + num_to_copy) < COMMAND_MAX_LEN)) {
|
||||
printk("%s", &first_match[command_len]);
|
||||
strncpy(&line[len], &first_match[command_len], num_to_copy);
|
||||
|
||||
/* for convenience add space after command */
|
||||
printk(" ");
|
||||
line[common_chars++] = ' ';
|
||||
line[len+num_to_copy] = ' ';
|
||||
return (num_to_copy + 1);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return common_chars - len;
|
||||
}
|
||||
|
||||
void shell_init(const char *str, const struct shell_cmd *cmds)
|
||||
void shell_init(const char *str)
|
||||
{
|
||||
nano_fifo_init(&cmds_queue);
|
||||
nano_fifo_init(&avail_queue);
|
||||
|
||||
commands = cmds;
|
||||
|
||||
line_queue_init();
|
||||
|
||||
prompt = str ? str : "";
|
||||
|
@ -306,7 +525,8 @@ void shell_init(const char *str, const struct shell_cmd *cmds)
|
|||
|
||||
/** @brief Optionally register an app default cmd handler.
|
||||
*
|
||||
* @param handler To be called if no cmd found in cmds registered with shell_init.
|
||||
* @param handler To be called if no cmd found in cmds registered with
|
||||
* shell_init.
|
||||
*/
|
||||
void shell_register_app_cmd_handler(shell_cmd_function_t handler)
|
||||
{
|
||||
|
@ -317,3 +537,13 @@ void shell_register_prompt_handler(shell_prompt_function_t handler)
|
|||
{
|
||||
app_prompt_handler = handler;
|
||||
}
|
||||
|
||||
void shell_register_default_module(const char *name)
|
||||
{
|
||||
int result = set_default_module(name);
|
||||
|
||||
if (result != -1) {
|
||||
printk("\n%s", default_module_prompt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1
drivers/console/shells/Makefile
Normal file
1
drivers/console/shells/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_ENABLE_SHELL) += shell_service.o
|
65
drivers/console/shells/shell_service.c
Normal file
65
drivers/console/shells/shell_service.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Shell framework services
|
||||
*
|
||||
* This module initiates shell.
|
||||
* Includes also adding basic framework commands to shell commands.
|
||||
*/
|
||||
|
||||
#ifndef _SHELLSERVICE_H
|
||||
#define _SHELLSERVICE_H
|
||||
|
||||
#include <misc/printk.h>
|
||||
#include <misc/shell.h>
|
||||
#include <init.h>
|
||||
|
||||
#define SHELL_KERNEL "kernel"
|
||||
#define SHELL_PROMPT "shell> "
|
||||
|
||||
static int shell_cmd_version(int argc, char *argv[])
|
||||
{
|
||||
uint32_t version = sys_kernel_version_get();
|
||||
|
||||
printk("Zephyr version %d.%d.%d\n",
|
||||
SYS_KERNEL_VER_MAJOR(version),
|
||||
SYS_KERNEL_VER_MINOR(version),
|
||||
SYS_KERNEL_VER_PATCHLEVEL(version));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct shell_cmd kernel_commands[] = {
|
||||
{ "version", shell_cmd_version, "show kernel version" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
int shell_run(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
shell_init(SHELL_PROMPT);
|
||||
SHELL_REGISTER(SHELL_KERNEL, kernel_commands);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SYS_INIT(shell_run, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
||||
|
||||
#endif /* SHELLSERVICE_H */
|
|
@ -97,6 +97,17 @@
|
|||
#define DEVICE_INIT_UNDEFINED_SECTION() \
|
||||
KEEP(*(SORT(.init_[_A-Z0-9]*))) \
|
||||
|
||||
/*
|
||||
* link in shell initialization objects for all modules that use shell and
|
||||
* their shell commands are automatically initialized by the kernel.
|
||||
*/
|
||||
|
||||
#define SHELL_INIT_SECTIONS() \
|
||||
__shell_cmd_start = .; \
|
||||
KEEP(*(".shell_*")); \
|
||||
__shell_cmd_end = .;
|
||||
|
||||
|
||||
#ifdef CONFIG_X86 /* LINKER FILES: defines used by linker script */
|
||||
/* Should be moved to linker-common-defs.h */
|
||||
#if defined(CONFIG_XIP)
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
}
|
||||
ASSERT(SIZEOF(initlevel_error) == 0, "Undefined initialization levels used.")
|
||||
|
||||
SECTION_DATA_PROLOGUE(initshell, (OPTIONAL),)
|
||||
{
|
||||
SHELL_INIT_SECTIONS()
|
||||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||
|
||||
SECTION_DATA_PROLOGUE(_k_task_list, (OPTIONAL),)
|
||||
{
|
||||
_k_task_list_start = .;
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
struct device;
|
||||
|
||||
/** @brief Callback called when command is entered.
|
||||
*
|
||||
* @param argc Number of parameters passed.
|
||||
|
@ -35,17 +38,56 @@ struct shell_cmd {
|
|||
const char *help;
|
||||
};
|
||||
|
||||
|
||||
struct shell_module {
|
||||
const char *module_name;
|
||||
const struct shell_cmd *commands;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Kernel Shell Api
|
||||
* @defgroup _shell_api_functions Shell Api Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def SHELL_REGISTER
|
||||
*
|
||||
* @brief Create shell_module object and set it up for boot time initialization.
|
||||
*
|
||||
* @details This macro defines a shell_module object that is automatically
|
||||
* configured by the kernel during system initialization.
|
||||
*
|
||||
* @param shell_name Module name to be entered in shell console.
|
||||
*
|
||||
* @param shell_commands Array of commands to register.
|
||||
* Shell array entries must be packed to calculate array size correctly.
|
||||
*/
|
||||
#ifdef CONFIG_ENABLE_SHELL
|
||||
#define SHELL_REGISTER(shell_name, shell_commands) \
|
||||
\
|
||||
static struct shell_module (__shell_shell_name) __used \
|
||||
__attribute__((__section__(".shell_"))) = { \
|
||||
.module_name = shell_name, \
|
||||
.commands = shell_commands \
|
||||
}
|
||||
|
||||
#else
|
||||
#define SHELL_REGISTER(shell_name, shell_commands)
|
||||
#endif
|
||||
|
||||
/** @brief Initialize shell with optional prompt, NULL in case no prompt is
|
||||
* needed.
|
||||
*
|
||||
* @param prompt Prompt to be printed on serial console.
|
||||
* @param cmds Commands to register
|
||||
*/
|
||||
void shell_init(const char *prompt, const struct shell_cmd *cmds);
|
||||
void shell_init(const char *prompt);
|
||||
|
||||
/** @brief Optionally register an app default cmd handler.
|
||||
*
|
||||
* @param handler To be called if no cmd found in cmds registered with shell_init.
|
||||
* @param handler To be called if no cmd found in cmds registered with
|
||||
* shell_init.
|
||||
*/
|
||||
void shell_register_app_cmd_handler(shell_cmd_function_t handler);
|
||||
|
||||
|
@ -61,6 +103,25 @@ typedef const char *(*shell_prompt_function_t)(void);
|
|||
*/
|
||||
void shell_register_prompt_handler(shell_prompt_function_t handler);
|
||||
|
||||
/** @brief Optionally register a default module, to eliminate typing it in
|
||||
* shell console or for backwards compatibility.
|
||||
*
|
||||
* @param name Module name.
|
||||
*/
|
||||
void shell_register_default_module(const char *name);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#ifdef CONFIG_ENABLE_SHELL
|
||||
int shell_run(struct device *dev);
|
||||
#else
|
||||
static inline int shell_run(struct device *dev) { return 0; }
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -242,6 +242,14 @@ config OMIT_FRAME_POINTER
|
|||
trace. Recommended only for production builds which do not need to be
|
||||
debugged.
|
||||
|
||||
config ENABLE_SHELL
|
||||
bool
|
||||
prompt "Shell support"
|
||||
default n
|
||||
help
|
||||
Enabling shell services. If it is enabled, kernel shell commands are
|
||||
also available for use.
|
||||
|
||||
source "misc/debug/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_MINIMAL_LIBC_EXTENDED=y
|
||||
#
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_MINIMAL_LIBC_EXTENDED=y
|
||||
#
|
||||
|
|
|
@ -438,6 +438,7 @@ static void zperf_init(void)
|
|||
zperf_session_init();
|
||||
}
|
||||
|
||||
#define MY_SHELL_MODULE "zperf"
|
||||
struct shell_cmd commands[] = {
|
||||
{ CMD_STR_SETIP, shell_cmd_setip },
|
||||
{ CMD_STR_CONNECTAP, shell_cmd_connectap },
|
||||
|
@ -461,7 +462,8 @@ void main(void)
|
|||
{
|
||||
#endif
|
||||
shell_cmd_version(0, NULL);
|
||||
shell_init("zperf> ", commands);
|
||||
SHELL_REGISTER(MY_SHELL_MODULE, commands);
|
||||
shell_register_default_module(MY_SHELL_MODULE);
|
||||
net_init();
|
||||
zperf_init();
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_PRINTK=y
|
||||
|
|
|
@ -19,6 +19,13 @@
|
|||
#include <misc/shell.h>
|
||||
#define DEVICE_NAME "test shell"
|
||||
|
||||
/*
|
||||
* Since we don't have kConfig in application level, we have the define here as
|
||||
* an example to what is needed to be in the relevant module kConfig file
|
||||
*/
|
||||
#define CONFIG_SAMPLE_MODULE_USE_SHELL
|
||||
|
||||
|
||||
static int shell_cmd_ping(int argc, char *argv[])
|
||||
{
|
||||
printk("pong\n");
|
||||
|
@ -26,6 +33,13 @@ static int shell_cmd_ping(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int shell_cmd_params(int argc, char *argv[])
|
||||
{
|
||||
printk("argc = %d, argv[0] = %s\n", argc, argv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shell_cmd_uptime(int argc, char *argv[])
|
||||
{
|
||||
printk("uptime: %u ms\n", k_uptime_get_32());
|
||||
|
@ -41,20 +55,24 @@ static int shell_cmd_cycles(int argc, char *argv[])
|
|||
}
|
||||
|
||||
|
||||
const struct shell_cmd commands[] = {
|
||||
#ifdef CONFIG_SAMPLE_MODULE_USE_SHELL
|
||||
|
||||
#define MY_SHELL_MODULE "sample_module"
|
||||
|
||||
static struct shell_cmd commands[] = {
|
||||
{ "ping", shell_cmd_ping },
|
||||
{ "uptime", shell_cmd_uptime },
|
||||
{ "cycles", shell_cmd_cycles },
|
||||
{ "params", shell_cmd_params, "print argc" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void main(void)
|
||||
{
|
||||
uint32_t version = sys_kernel_version_get();
|
||||
|
||||
printk("Zephyr version %d.%d.%d\n",
|
||||
SYS_KERNEL_VER_MAJOR(version),
|
||||
SYS_KERNEL_VER_MINOR(version),
|
||||
SYS_KERNEL_VER_PATCHLEVEL(version));
|
||||
shell_init("shell> ", commands);
|
||||
#ifdef CONFIG_SAMPLE_MODULE_USE_SHELL
|
||||
SHELL_REGISTER(MY_SHELL_MODULE, commands);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -165,6 +165,8 @@ int shell_cmd_prof(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define MY_SHELL_ENTITY "profiler"
|
||||
|
||||
struct shell_cmd prof_commands[] = {
|
||||
PROF_CMD,
|
||||
{ NULL, NULL}
|
||||
|
@ -225,7 +227,8 @@ void prof_init(void)
|
|||
|
||||
#ifdef PROFILER_SHELL
|
||||
#ifndef PROFILER_NO_SHELL_REGISTER
|
||||
shell_init("shell> ", prof_commands);
|
||||
SHELL_REGISTER(MY_SHELL_ENTITY, prof_commands);
|
||||
shell_register_default_module(MY_SHELL_ENTITY);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_MINIMAL_LIBC_EXTENDED=y
|
||||
CONFIG_TASK_MONITOR=y
|
||||
CONFIG_TASK_MONITOR_MASK=6
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_MINIMAL_LIBC_EXTENDED=y
|
||||
CONFIG_TASK_MONITOR=y
|
||||
CONFIG_TASK_MONITOR_MASK=6
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_MINIMAL_LIBC_EXTENDED=y
|
||||
CONFIG_RING_BUFFER=y
|
||||
CONFIG_KERNEL_EVENT_LOGGER=y
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_MINIMAL_LIBC_EXTENDED=y
|
||||
CONFIG_RING_BUFFER=y
|
||||
CONFIG_KERNEL_EVENT_LOGGER=y
|
||||
|
|
|
@ -460,7 +460,7 @@ class SizeCalculator:
|
|||
alloc_sections = ["bss", "noinit"]
|
||||
rw_sections = ["datas", "initlevel", "_k_mem_map_ptr", "_k_pipe_ptr",
|
||||
"_k_task_ptr", "_k_task_list", "_k_event_list",
|
||||
"_k_memory_pool", "exceptions"]
|
||||
"_k_memory_pool", "exceptions", "initshell"]
|
||||
# These get copied into RAM only on non-XIP
|
||||
ro_sections = ["text", "ctors", "init_array", "reset",
|
||||
"rodata", "devconfig"]
|
||||
|
|
|
@ -13,5 +13,7 @@ CONFIG_BLUETOOTH_GATT_CLIENT=y
|
|||
CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL=y
|
||||
CONFIG_BLUETOOTH_TINYCRYPT_ECC=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_BLUETOOTH_BREDR_NAME="test shell"
|
||||
CONFIG_BLUETOOTH_ATT_REQ_COUNT=5
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ CONFIG_BLUETOOTH_LE=y
|
|||
CONFIG_BLUETOOTH_BREDR=y
|
||||
CONFIG_BLUETOOTH_RFCOMM=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_BLUETOOTH_DEBUG_LOG=y
|
||||
CONFIG_BLUETOOTH_CENTRAL=y
|
||||
CONFIG_BLUETOOTH_PERIPHERAL=y
|
||||
|
@ -14,5 +16,4 @@ CONFIG_BLUETOOTH_ATT_PREPARE_COUNT=2
|
|||
CONFIG_BLUETOOTH_GATT_CLIENT=y
|
||||
CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL=y
|
||||
CONFIG_BLUETOOTH_TINYCRYPT_ECC=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_BLUETOOTH_BREDR_NAME="test shell"
|
||||
|
|
|
@ -5,5 +5,6 @@ CONFIG_BLUETOOTH_STACK_NBLE=y
|
|||
CONFIG_NBLE=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_CONSOLE_HANDLER_SHELL=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
CONFIG_BLUETOOTH_DEBUG_LOG=y
|
||||
CONFIG_BLUETOOTH_ATT_PREPARE_COUNT=2
|
||||
|
|
|
@ -15,3 +15,4 @@ CONFIG_CONSOLE_HANDLER_SHELL=y
|
|||
CONFIG_GPIO=y
|
||||
CONFIG_BLUETOOTH_WAIT_NOP=y
|
||||
CONFIG_BLUETOOTH_NRF51_PM=y
|
||||
CONFIG_ENABLE_SHELL=y
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define DATA_MTU (23 * CREDITS)
|
||||
#define DATA_BREDR_MTU 48
|
||||
|
||||
#define MY_SHELL_MODULE "btshell"
|
||||
static struct bt_conn *default_conn;
|
||||
static bt_addr_le_t id_addr;
|
||||
|
||||
|
@ -2227,9 +2228,9 @@ void main(void)
|
|||
printk("Type \"help\" for supported commands.\n");
|
||||
printk("Before any Bluetooth commands you must run \"init\".\n");
|
||||
|
||||
shell_init("btshell> ", commands);
|
||||
|
||||
SHELL_REGISTER(MY_SHELL_MODULE, commands);
|
||||
shell_register_prompt_handler(current_prompt);
|
||||
shell_register_default_module(MY_SHELL_MODULE);
|
||||
|
||||
while (1) {
|
||||
task_sleep(sys_clock_ticks_per_sec);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue