From bef64c3b777283550b32ad37e747444d91013cca Mon Sep 17 00:00:00 2001 From: Jakub Rzeszutko Date: Mon, 24 Sep 2018 15:18:52 +0200 Subject: [PATCH] doc: subsystems: shell: Add documentation. 1. Remove old shell documentation. 2. Create documentation for new shell module. 3. Fix shell.h comments to be able to generate API documentation. Signed-off-by: Jakub Rzeszutko --- doc/api/api.rst | 1 + doc/api/shell_api.rst | 16 + doc/subsystems/shell.rst | 182 ------- doc/subsystems/shell/images/dynamic_cmd.PNG | Bin 0 -> 15065 bytes doc/subsystems/shell/images/static_cmd.PNG | Bin 0 -> 19109 bytes doc/subsystems/shell/images/wildcard.png | Bin 0 -> 14738 bytes doc/subsystems/shell/shell.rst | 510 ++++++++++++++++++++ doc/subsystems/subsystems.rst | 2 +- include/shell/shell.h | 122 +++-- 9 files changed, 598 insertions(+), 235 deletions(-) create mode 100644 doc/api/shell_api.rst delete mode 100644 doc/subsystems/shell.rst create mode 100644 doc/subsystems/shell/images/dynamic_cmd.PNG create mode 100644 doc/subsystems/shell/images/static_cmd.PNG create mode 100644 doc/subsystems/shell/images/wildcard.png create mode 100644 doc/subsystems/shell/shell.rst diff --git a/doc/api/api.rst b/doc/api/api.rst index 205bda035b4..a16c76582b5 100644 --- a/doc/api/api.rst +++ b/doc/api/api.rst @@ -27,3 +27,4 @@ The Zephyr APIs are used the same way on all SoCs and boards. display_api misc_api logger_api + shell_api diff --git a/doc/api/shell_api.rst b/doc/api/shell_api.rst new file mode 100644 index 00000000000..0c684eb4a82 --- /dev/null +++ b/doc/api/shell_api.rst @@ -0,0 +1,16 @@ + +.. _shell_api: + +Shell system API +################# + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +Shell API +********** + +.. doxygengroup:: shell_api + :project: Zephyr diff --git a/doc/subsystems/shell.rst b/doc/subsystems/shell.rst deleted file mode 100644 index e9f1d0689c5..00000000000 --- a/doc/subsystems/shell.rst +++ /dev/null @@ -1,182 +0,0 @@ -.. _shell: - -Shell -###### - -Overview -******** - -The Shell enables multiple subsystem to use and expose their shell interface -simultaneously. - -Each subsystem can support shell functionality dynamically by its Kconfig file, -which enables or disables the shell usage for the subsystem. - -Using shell commands -******************** - -Use one of the following formats: - -Help commands -============= - -``help`` - Prints the list of 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 describes the available - module commands and required parameters). - - -Specific module's commands -========================== - -A shell interface exposing subsystem features is a shell module, multiple -modules can be available at the same time. - -``MODULE_NAME COMMAND`` - One of the available modules is "KERNEL", for `Kernel module commands`_. - Information about registering a new module and its commands can be - found in :c:macro:`SHELL_REGISTER` documentation. - - -Select module commands -====================== - -``select MODULE_NAME`` - Use this command when using the shell only for one module. After entering this - command, you will not need to enter the 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. - -``select`` - Clears selected module. Restores prompt as well. - - -Kernel module commands -====================== - -When enabled through option :option:`CONFIG_KERNEL_SHELL`, the Kernel -shell module commands display useful kernel-specific information. - -You can issue these Kernel module shell commands by specifying -the module and command:: - - shell> kernel version - -or by first selecting the kernel module, and then issuing the specific -command:: - - shell> select kernel - kernel> version - -Here are the Kernel module shell commands: - -``version`` - Displays the kernel version number - -``uptime`` - Displays the system uptime in milliseconds - -``cycles`` - Displays the current time (in cycles), as measured by the system's hardware clock - -``threads`` - Displays information about the running threads (if - :option:`CONFIG_OBJECT_TRACING` and :option:`CONFIG_THREAD_MONITOR` are - enabled). - -``stacks`` - Displays size and use information about the main, idle, interrupt and system - workqueue call stacks (if :option:`CONFIG_INIT_STACKS` is enabled) - -Other commands -============== - -``noprompt`` - This command will disable the shell prompt. The shell will still be fully - functional, but the prompt will not be printed each time the shell expects a - new command. - -Shell configuration -******************* -There are two levels of configuration: Infrastructure level and Module level. - -Infrastructure level -==================== - -The option :option:`CONFIG_CONSOLE_SHELL` enables the shell subsystem and enable the -default features of the shell subsystem. - -Module/Subsystem level -====================== -Each subsystem using the shell service should add a unique flag in its Kconfig file. - -Example: - -CONFIG_NET_SHELL=y - -In the subsystem's code, the shell usage depends on this config parameter. -This subsystem specific flag should also depend on :option:`CONFIG_CONSOLE_SHELL` flag. - -Configuration steps to add shell functionality to a module -========================================================== - - #. Check that :option:`CONFIG_CONSOLE_SHELL` is set to yes. - #. Add the subsystem unique flag to its Kconfig file. - -Writing a shell module -********************** - -In order to support shell in your subsystem, the application must do the following: - -#. Module configuration flag: Declare a new flag in your subsystem Kconfig file. - It should depend on :option:`CONFIG_CONSOLE_SHELL` flag. - -#. Module registration to shell: Add your shell identifier and register its - callback functions in the shell database using :c:macro:`SHELL_REGISTER`. - -Optionally, you can use one of the following API functions to override default -behavior and settings: - -* :c:func:`shell_register_default_module` - -* :c:func:`shell_register_prompt_handler` - -In case of a sample applications as well as the test environment, you can choose to -set a default module in code level. In this case, the function -:c:func:`shell_register_default_module` should be called after calling SHELL_REGISTER in -application level. If the function -:c:func:`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 - "select" shell command. - -You can use :c:func:`shell_register_default_module` in the following cases: - -* 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 diff --git a/doc/subsystems/shell/images/dynamic_cmd.PNG b/doc/subsystems/shell/images/dynamic_cmd.PNG new file mode 100644 index 0000000000000000000000000000000000000000..09701d07efe066134ecbee7f3cb2f2394e436931 GIT binary patch literal 15065 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 0): Number and syntax must be known during compile + time. Created in the software module. +* Dynamic subcommand (level > 0): Number and syntax does not need to be known + during compile time. Created in the software module. + +Creating commands +================= + +Use the following macros for adding shell commands: + +* :c:macro:`SHELL_CMD_REGISTER` - Create root command. All root commands must + have different name. +* :c:macro:`SHELL_CMD` - Initialize a command. +* :c:macro:`SHELL_CREATE_STATIC_SUBCMD_SET` - Create a static subcommands + array. Static subcommands must be added in alphabetical order to ensure + correct smart completion. +* :c:macro:`SHELL_SUBCMD_SET_END` - shall be placed as last in + :c:macro:`SHELL_CREATE_STATIC_SUBCMD_SET` macro. +* :c:macro:`SHELL_CREATE_DYNAMIC_CMD` - Create a dynamic subcommands array. + Dynamic subcommands must be returned in alphabetical order to ensure correct + smart completion. + +Commands can be created in any file in the system that includes +:file:`include/shell/shell.h`. All created commands are available for all +shell instances. + +Static commands +--------------- + +Example code demonstrating how to create a root command with static +subcommands. + +.. image:: images/static_cmd.PNG + :align: center + :alt: Command tree with static commands. + +.. code-block:: c + + /* Creating subcommands (level 1 command) array for command "demo". + * Subcommands must be added in alphabetical order to ensure correct + * command autocompletion. + */ + SHELL_CREATE_STATIC_SUBCMD_SET(sub_demo) + { + /* Alphabetically sorted. */ + SHELL_CMD(params, NULL, "Print params command.", + cmd_demo_params), + SHELL_CMD(ping, NULL, "Ping command.", cmd_demo_ping), + SHELL_SUBCMD_SET_END /* Array terminated. */ + }; + /* Creating root (level 0) command "demo" */ + SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL); + +Example implementation can be found under following location: +:file:`samples/subsys/shell/shell_module/src/main.c`. + +Dynamic commands +---------------- + +Example code demonstrating how to create a root command with static and dynamic +subcommands. At the beginning dynamic command list is empty. New commands +can be added by typing: + +.. code-block:: none + + dynamic add + +Newly added commands can be prompted or autocompleted with the :kbd:`Tab` key. + +.. image:: images/dynamic_cmd.PNG + :align: center + :alt: Command tree with static and dynamic commands. + +.. code-block:: c + + /* Buffer for 10 dynamic commands */ + static char dynamic_cmd_buffer[10][50]; + + /* commands counter */ + static u8_t dynamic_cmd_cnt; + + /* Function returning command dynamically created + * in dynamic_cmd_buffer. + */ + static void dynamic_cmd_get(size_t idx, + struct shell_static_entry *entry) + { + if (idx < dynamic_cmd_cnt) { + /* m_dynamic_cmd_buffer must be sorted alphabetically + * to ensure correct Shell autocompletion + */ + entry->syntax = dynamic_cmd_buffer[idx]; + entry->handler = NULL; + entry->subcmd = NULL; + entry->help = "Show dynamic command name."; + } else { + /* if there are no more dynamic commands available + * syntax must be set to NULL. + */ + entry->syntax = NULL; + } + } + + SHELL_CREATE_DYNAMIC_CMD(m_sub_dynamic_set, dynamic_cmd_get); + SHELL_CREATE_STATIC_SUBCMD_SET(m_sub_dynamic) + { + SHELL_CMD(add, NULL,"Add new command to dynamic_cmd_buffer and" + " sort them alphabetically.", + cmd_dynamic_add), + SHELL_CMD(execute, &m_sub_dynamic_set, + "Execute a command.", cmd_dynamic_execute), + SHELL_CMD(remove, &m_sub_dynamic_set, + "Remove a command from dynamic_cmd_buffer.", + cmd_dynamic_remove), + SHELL_CMD(show, NULL, + "Show all commands in dynamic_cmd_buffer.", + cmd_dynamic_show), + SHELL_SUBCMD_SET_END + }; + SHELL_CMD_REGISTER(dynamic, &m_sub_dynamic, + "Demonstrate dynamic command usage.", cmd_dynamic); + +Example implementation can be found under following location: +:file:`samples/subsys/shell/shell_module/src/dynamic_cmd.c`. + +Commands execution +================== + +Each command or subcommand may have a handler. The shell executes the handler +that is found deepest in the command tree and further subcommands (without a +handler) are passed as arguments. Characters within parentheses are treated +as one argument. If shell wont find a handler it will display an error message. + +Command handler +---------------- + +Simple command handler implementation: + +.. code-block:: c + + static void cmd_handler(const struct shell *shell, size_t argc, + char **argv) + { + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + shell_fprintf(shell, SHELL_NORMAL, + "Print simple text.\r\n"); + + shell_fprintf(shell, SHELL_WARNING, + "Print warning text.\r\n"); + + shell_fprintf(shell, SHELL_ERROR, + "Print error text.\r\n"); + } + +.. warning:: + Do not use function :cpp:func:`shell_fprintf` outside of the command + handler because this might lead to incorrect text display on the + screen. If any text should be displayed outside of the command context, + then use the :ref:`logger`. + +Command help +------------ + +Every user-defined command, subcommand, or option can have its own help +description. The help for commands and subcommands can be created with +respective macros: :c:macro:`SHELL_CMD_REGISTER` and :c:macro:`SHELL_CMD`. +In addition, you can define options for commands or subcommands using the +macro :c:macro:`SHELL_OPT`. By default, each and every command or subcommand +has these two options implemented: ``-h`` and ``--help``. + +In order to add help functionality to a command or subcommand, you must +implement the help handler by either calling :cpp:func:`shell_cmd_precheck` +or pair of functions :cpp:func:`shell_help_requested` and +:cpp:func:`shell_help_print`. The former is more convenient as it also +checks for valid arguments count. + +.. code-block:: c + + static void cmd_dummy_1(const struct shell *shell, size_t argc, + char **argv) + { + ARG_UNUSED(argv); + + /* Function shell_cmd_precheck will do one of below actions: + * 1. print help if command called with -h or --help + * 2. print error message if argc > 2 + * + * Each of these actions can be deactivated in Kconfig. + */ + if (!shell_cmd_precheck(shell, (argc <= 2), NULL, 0) { + return; + } + + shell_fprintf(shell, SHELL_NORMAL, + "Command called with no -h or --help option." + "\r\n"); + } + + static void cmd_dummy_2(const struct shell *shell, size_t argc, + char **argv) + { + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + if (hell_help_requested(shell) { + shell_help_print(shell, NULL, 0); + return; + } + + shell_fprintf(shell, SHELL_NORMAL, + "Command called with no -h or --help option." + "\r\n"); + } + +Command options +--------------- + +When possible, use subcommands instead of options. Options apply mainly in the +case when an argument with ``-`` or ``--`` is requested. The main benefit of +using subcommands is that they can be prompted or completed with the :kbd:`Tab` +key. In addition, subcommands can have their own handler, which limits the +usage of ``if - else if`` statements combination with the ``strcmp`` function +in command handler. + + +.. code-block:: c + + static void cmd_with_options(const struct shell *shell, size_t argc, + char **argv) + { + /* Dummy options showing options usage */ + static const struct shell_getopt_option opt[] = { + SHELL_OPT( + "--test", + "-t", + "test option help string" + ), + SHELL_OPT( + "--dummy", + "-d", + "dummy option help string" + ) + }; + + /* If command will be called with -h or --help option + * all declared options will be listed in the help message + */ + if (!shell_cmd_precheck(shell, (argc <= 2), opt, + sizeof(opt)/sizeof(opt[1]))) { + return; + } + + /* checking if command was called with test option */ + if (!strcmp(argv[1], "-t") || !strcmp(argv[1], "--test")) { + shell_fprintf(shell, SHELL_NORMAL, "Command called with -t" + " or --test option.\r\n"); + return; + } + + /* checking if command was called with dummy option */ + if (!strcmp(argv[1], "-d") || !strcmp(argv[1], "--dummy")) { + shell_fprintf(shell, SHELL_NORMAL, "Command called with -d" + " or --dummy option.\r\n"); + return; + } + + shell_fprintf(shell, SHELL_WARNING, + "Command called with no valid option.\r\n"); + } + +Parent commands +--------------- + +In the subcommand handler, you can access both the parameters passed to +commands or the parent commands, depending on how you index ``argv``. + +* When indexing ``argv`` with positive numbers, you can access the parameters. +* When indexing ``argv`` with negative numbers, you can access the parent + commands. +* The subcommand to which the handler belongs has the ``argv`` value of 0. + +.. code-block:: c + + static void cmd_handler(const struct shell *shell, size_t argc, + char **argv) + { + ARG_UNUSED(argc); + + /* If it is a subcommand handler parent command syntax + * can be found using argv[-1]. + */ + shell_fprintf(shell, SHELL_NORMAL, + "This command has a parent command: %s\r\n", + argv[-1]); + + /* Print this command syntax */ + shell_fprintf(shell, SHELL_NORMAL, + "This command syntax is: %s\r\n", + argv[0]); + + /* Print first argument */ + shell_fprintf(shell, SHELL_NORMAL, + "This command has an argument: %s\r\n", + argv[1]); + } + +Built-in commands +================= + +* :command:`clear` - Clears the screen. +* :command:`history` - Shows the recently entered commands. +* :command:`resize` - Must be executed when terminal width is different than 80 + characters or after each change of terminal width. It ensures proper + multiline text display and :kbd:`←`, :kbd:`→`, :kbd:`End`, :kbd:`Home` keys + handling. Currently this command works only with UART flow control switched + on. It can be also called with a subcommand: + + * :command:`default` - Shell will send terminal width = 80 to the + terminal and assume successful delivery. + +* :command:`shell` - Root command with useful shell-related subcommands like: + + * :command:`echo` - Toggles shell echo. + * :command:`colors` - Toggles colored syntax. This might be helpful in + case of Bluetooth shell to limit the amount of transferred bytes. + * :command:`stats` - Shows shell statistics. + +Wildcards +********* + +The shell module can handle wildcards. Wildcards are interpreted correctly +when expanded command and its subcommands do not have a handler. For example, +if you want to set logging level to ``err`` for the ``app`` and ``app_test`` +modules you can execute the following command: + +.. code-block:: none + + log enable err a* + +.. image:: images/wildcard.png + :align: center + :alt: Wildcard usage example + +Meta keys +********* + +The shell module supports the following meta keys: + +.. list-table:: Implemented meta keys + :widths: 10 40 + :header-rows: 1 + + * - Meta keys + - Action + * - ctrl + a + - Moves the cursor to the beginning of the line. + * - ctrl + c + - Preserves the last command on the screen and starts a new command in + a new line. + * - ctrl + e + - Moves the cursor to the end of the line. + * - ctrl + l + - Clears the screen and leaves the currently typed command at the top of + the screen. + * - ctrl + u + - Clears the currently typed command. + * - ctrl + w + - Removes the word or part of the word to the left of the cursor. Words + separated by period instead of space are treated as one word. + +Usage +***** + +Use the :c:macro:`SHELL_DEFINE` macro to create an instance of the shell. +Pass the expected newline character to this macro: either ``\r`` or ``\n``, +otherwise the shell will not respond correctly to the :kbd:`Enter` key. + +The following code shows a simple use case of this library: + +.. code-block:: c + + /* Defining shell backend */ + SHELL_UART_DEFINE(shell_transport_uart); + + /* Creating shell instance */ + SHELL_DEFINE(uart_shell, "uart:~$ ", &shell_transport_uart, '\r', 10); + + void main(void) + { + (void)shell_init(&uart_shell, NULL, true, true, LOG_LEVEL_INF); + } + + static void cmd_demo_ping(const struct shell *shell, size_t argc, + char **argv) + { + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + shell_fprintf(shell, SHELL_NORMAL, "pong\r\n"); + } + + static void cmd_demo_params(const struct shell *shell, size_t argc, + char **argv) + { + int cnt; + + shell_fprintf(shell, SHELL_NORMAL, "argc = %d\r\n", argc); + for (cnt = 0; cnt < argc; cnt++) { + shell_fprintf(shell, SHELL_NORMAL, + " argv[%d] = %s\r\n", cnt, argv[cnt]); + } + } + + /* Creating subcommands (level 1 command) array for command "demo". + * Subcommands must be added in alphabetical order + */ + SHELL_CREATE_STATIC_SUBCMD_SET(sub_demo) + { + /* Alphabetically sorted. */ + SHELL_CMD(params, NULL, "Print params command.", + cmd_demo_params), + SHELL_CMD(ping, NULL, "Ping command.", cmd_demo_ping), + SHELL_SUBCMD_SET_END /* Array terminated. */ + }; + /* Creating root (level 0) command "demo" without a handler */ + SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL); + + /* Creating root (level 0) command "version" */ + SHELL_CMD_REGISTER(version, NULL, "Show kernel version", cmd_version); + + +Users may use the :kbd:`Tab` key to complete a command/subcommand or to see the +available subcommands for the currently entered command level. +For example, when the cursor is positioned at the beginning of the command +line and the :kbd:`Tab` key is pressed, the user will see all root (level 0) +commands: + +.. code-block:: none + + clear demo shell history log resize version + + +.. note:: + To view the subcommands that are available for a specific command, you + must first type a :kbd:`space` after this command and then hit + :kbd:`Tab`. + +These commands are registered by various modules, for example: + +* :command:`clear`, :command:`shell`, :command:`history`, and :command:`resize` + are built-in commands which have been registered by + :file:`subsys/shell/shell.c` +* :command:`demo` and :command:`version` have been registered in example code + above by main.c +* :command:`log` has been registered by :file:`subsys/logging/log_cmds.c` + +Then, if a user types a :command:`demo` command and presses the :kbd:`Tab` key, +the shell will only print the subcommands registered for this command: + +.. code-block:: none + + params ping + + diff --git a/doc/subsystems/subsystems.rst b/doc/subsystems/subsystems.rst index 372fdeec983..64a659b48d9 100644 --- a/doc/subsystems/subsystems.rst +++ b/doc/subsystems/subsystems.rst @@ -18,7 +18,7 @@ to applications. networking/networking.rst power_management.rst sensor - shell + shell/shell test/index usb/usb.rst settings/settings.rst diff --git a/include/shell/shell.h b/include/shell/shell.h index 43a7a2dfca4..1abd8270219 100644 --- a/include/shell/shell.h +++ b/include/shell/shell.h @@ -32,18 +32,16 @@ extern "C" { #define SHELL_CMD_ROOT_LVL (0u) -/* - * @defgroup shell Shell - * @ingroup subsys - * - * @brief Module for providing shell. - * +/** + * @brief Shell API + * @defgroup shell_api Shell API + * @ingroup shell * @{ */ struct shell_static_entry; -/* +/** * @brief Shell dynamic command descriptor. * * @details Function shall fill the received shell_static_entry structure @@ -57,12 +55,12 @@ struct shell_static_entry; typedef void (*shell_dynamic_get)(size_t idx, struct shell_static_entry *entry); -/* +/** * @brief Shell command descriptor. */ struct shell_cmd_entry { bool is_dynamic; - union { + union union_cmd_entry { /*!< Pointer to function returning dynamic commands.*/ shell_dynamic_get dynamic_get; @@ -73,7 +71,7 @@ struct shell_cmd_entry { struct shell; -/* +/** * @brief Shell command handler prototype. */ typedef void (*shell_cmd_handler)(const struct shell *shell, @@ -89,8 +87,7 @@ struct shell_static_entry { shell_cmd_handler handler; /*!< Command handler. */ }; -#define SHELL_CMD_NAME(name) UTIL_CAT(shell_cmd_, name) -/* +/** * @brief Macro for defining and adding a root command (level 0). * * @note Each root command shall have unique syntax. @@ -111,7 +108,7 @@ struct shell_static_entry { .u.entry = &UTIL_CAT(shell_, syntax) \ } -/* +/** * @brief Macro for creating a subcommand set. It must be used outside of any * function body. * @@ -125,13 +122,13 @@ struct shell_static_entry { }; \ static const struct shell_static_entry shell_##name[] = -/* +/** * @brief Define ending subcommands set. * */ #define SHELL_SUBCMD_SET_END {NULL} -/* +/** * @brief Macro for creating a dynamic entry. * * @param[in] name Name of the dynamic entry. @@ -143,7 +140,7 @@ struct shell_static_entry { .u.dynamic_get = get \ } -/* +/** * @brief Initializes a shell command. * * @param[in] _syntax Command syntax (for example: history). @@ -158,7 +155,7 @@ struct shell_static_entry { .handler = _handler \ } -/* +/** * @internal @brief Internal shell state in response to data received from the * terminal. */ @@ -170,7 +167,7 @@ enum shell_receive_state { }; -/* +/** * @internal @brief Internal shell state. */ enum shell_state { @@ -181,7 +178,7 @@ enum shell_state { SHELL_STATE_PANIC_MODE_INACTIVE /*!< Panic requested, not supported.*/ }; -/* @brief Shell transport event. */ +/** @brief Shell transport event. */ enum shell_transport_evt { SHELL_TRANSPORT_EVT_RX_RDY, SHELL_TRANSPORT_EVT_TX_RDY @@ -192,11 +189,11 @@ typedef void (*shell_transport_handler_t)(enum shell_transport_evt evt, struct shell_transport; -/* +/** * @brief Unified shell transport interface. */ struct shell_transport_api { - /* + /** * @brief Function for initializing the shell transport interface. * * @param[in] transport Pointer to the transfer instance. @@ -212,7 +209,7 @@ struct shell_transport_api { shell_transport_handler_t evt_handler, void *context); - /* + /** * @brief Function for uninitializing the shell transport interface. * * @param[in] transport Pointer to the transfer instance. @@ -221,7 +218,7 @@ struct shell_transport_api { */ int (*uninit)(const struct shell_transport *transport); - /* + /** * @brief Function for reconfiguring the transport to work in blocking * mode. * @@ -233,7 +230,7 @@ struct shell_transport_api { */ int (*enable)(const struct shell_transport *transport, bool blocking); - /* + /** * @brief Function for writing data to the transport interface. * * @param[in] transport Pointer to the transfer instance. @@ -246,7 +243,7 @@ struct shell_transport_api { int (*write)(const struct shell_transport *transport, const void *data, size_t length, size_t *cnt); - /* + /** * @brief Function for reading data from the transport interface. * * @param[in] p_transport Pointer to the transfer instance. @@ -266,7 +263,9 @@ struct shell_transport { void *ctx; }; -/** @brief Shell statistics structure. */ +/** + * @brief Shell statistics structure. + */ struct shell_stats { u32_t log_lost_cnt; /*!< Lost log counter.*/ }; @@ -279,7 +278,7 @@ struct shell_stats { #define SHELL_STATS_PTR(_name) NULL #endif /* CONFIG_SHELL_STATS */ -/* +/** * @internal @brief Flags for internal shell usage. */ struct shell_flags { @@ -292,9 +291,11 @@ struct shell_flags { u32_t mode_delete :1; /*!< Operation mode of backspace key */ }; -BUILD_ASSERT(sizeof(struct shell_flags) == sizeof(u32_t)); +BUILD_ASSERT_MSG((sizeof(struct shell_flags) == sizeof(u32_t)), + "Structure must fit in 4 bytes"); -/* + +/** * @internal @brief Union for internal shell usage. */ union shell_internal { @@ -310,7 +311,7 @@ enum shell_signal { SHELL_SIGNALS }; -/* +/** * @brief Shell instance context. */ struct shell_ctx { @@ -345,7 +346,7 @@ struct shell_ctx { extern const struct log_backend_api log_backend_shell_api; -/* +/** * @brief Shell instance internals. */ struct shell { @@ -371,7 +372,7 @@ struct shell { k_thread_stack_t *stack; }; -/* +/** * @brief Macro for defining a shell instance. * * @param[in] _name Instance name. @@ -393,7 +394,7 @@ struct shell { SHELL_FPRINTF_DEFINE(_name## _fprintf, &_name, _name##_out_buffer, \ CONFIG_SHELL_PRINTF_BUFF_SIZE, \ true, shell_print_stream); \ - LOG_INSTANCE_REGISTER(shell, _name, CONFIG_SHELL_LOG_LEVEL); \ + LOG_INSTANCE_REGISTER(shell, _name, CONFIG_SHELL_LOG_LEVEL); \ SHELL_STATS_DEFINE(_name); \ static K_THREAD_STACK_DEFINE(_name##_stack, CONFIG_SHELL_STACK_SIZE);\ static struct k_thread _name##_thread; \ @@ -411,7 +412,7 @@ struct shell { .stack = _name##_stack \ } -/* +/** * @brief Function for initializing a transport layer and internal shell state. * * @param[in] shell Pointer to shell instance. @@ -426,7 +427,7 @@ struct shell { int shell_init(const struct shell *shell, const void *transport_config, bool use_colors, bool log_backend, u32_t init_log_level); -/* +/** * @brief Uninitializes the transport layer and the internal shell state. * * @param shell Pointer to shell instance. @@ -435,7 +436,7 @@ int shell_init(const struct shell *shell, const void *transport_config, */ int shell_uninit(const struct shell *shell); -/* +/** * @brief Function for starting shell processing. * * @param shell Pointer to the shell instance. @@ -444,7 +445,7 @@ int shell_uninit(const struct shell *shell); */ int shell_start(const struct shell *shell); -/* +/** * @brief Function for stopping shell processing. * * @param shell Pointer to shell instance. @@ -453,16 +454,32 @@ int shell_start(const struct shell *shell); */ int shell_stop(const struct shell *shell); -/* - * @brief Shell colors for nrf_shell_fprintf function. +/** + * @brief Terminal default text color for nrf_shell_fprintf function. */ #define SHELL_NORMAL SHELL_VT100_COLOR_DEFAULT + +/** + * @brief Green text color for nrf_shell_fprintf function. + */ #define SHELL_INFO SHELL_VT100_COLOR_GREEN + +/** + * @brief Cyan text color for nrf_shell_fprintf function. + */ #define SHELL_OPTION SHELL_VT100_COLOR_CYAN + +/** + * @brief Yellow text color for nrf_shell_fprintf function. + */ #define SHELL_WARNING SHELL_VT100_COLOR_YELLOW + +/** + * @brief Red text color for nrf_shell_fprintf function. + */ #define SHELL_ERROR SHELL_VT100_COLOR_RED -/* +/** * @brief Printf-like function which sends formatted data stream to the shell. * This function shall not be used outside of the shell command context. * @@ -474,7 +491,7 @@ int shell_stop(const struct shell *shell); void shell_fprintf(const struct shell *shell, enum shell_vt100_color color, const char *p_fmt, ...); -/* +/** * @brief Process function, which should be executed when data is ready in the * transport interface. To be used if shell thread is disabled. * @@ -482,7 +499,7 @@ void shell_fprintf(const struct shell *shell, enum shell_vt100_color color, */ void shell_process(const struct shell *shell); -/* +/** * @brief Option descriptor. */ struct shell_getopt_option { @@ -491,7 +508,7 @@ struct shell_getopt_option { const char *optname_help; /*!< Option help string.*/ }; -/* +/** * @brief Option structure initializer. * * @param[in] _optname Option name long. @@ -504,7 +521,7 @@ struct shell_getopt_option { .optname_help = _help, \ } -/* +/** * @brief Informs that a command has been called with -h or --help option. * * @param[in] shell Pointer to the shell instance. @@ -516,7 +533,7 @@ static inline bool shell_help_requested(const struct shell *shell) return shell->ctx->internal.flags.show_help; } -/* +/** * @brief Prints the current command help. * * Function will print a help string with: the currently entered command, its @@ -529,7 +546,7 @@ static inline bool shell_help_requested(const struct shell *shell) void shell_help_print(const struct shell *shell, const struct shell_getopt_option *opt, size_t opt_len); -/* +/** * @brief Change displayed shell prompt. * * @param[in] shell Pointer to the shell instance. @@ -540,10 +557,9 @@ void shell_help_print(const struct shell *shell, */ int shell_prompt_change(const struct shell *shell, char *prompt); -/* - * @brief Prints help if request and prints error message on wrong argument +/** + * @brief Prints help if requested and prints error message on wrong argument * count. - * * Optionally, printing help on wrong argument count can be enabled. * * @param[in] shell Pointer to the shell instance. @@ -554,11 +570,11 @@ int shell_prompt_change(const struct shell *shell, char *prompt); * @return True if check passed, false otherwise or help was requested. */ bool shell_cmd_precheck(const struct shell *shell, - bool arg_cnt_nok, + bool arg_cnt_ok, const struct shell_getopt_option *opt, size_t opt_len); -/* +/** * @internal @brief This function shall not be used directly, it is required by * the fprintf module. * @@ -569,7 +585,9 @@ bool shell_cmd_precheck(const struct shell *shell, void shell_print_stream(const void *user_ctx, const char *data, size_t data_len); -/* @} */ +/** + * @} + */ #ifdef __cplusplus }