From 8d6d872388ec2a6d0f562350d3ee28d7c855a0a5 Mon Sep 17 00:00:00 2001 From: Al Semjonovs Date: Tue, 9 Apr 2024 14:41:20 -0600 Subject: [PATCH 1/2] shell: Allow extension of shell APIs Similar to logging module, allow application specific extension of shell fprintf APIs at a macro level. Signed-off-by: Al Semjonovs --- include/zephyr/shell/shell.h | 12 +++++++++--- subsys/shell/Kconfig | 8 ++++++++ subsys/shell/shell.c | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/zephyr/shell/shell.h b/include/zephyr/shell/shell.h index 91dd73a2d9b59..a19418fa52857 100644 --- a/include/zephyr/shell/shell.h +++ b/include/zephyr/shell/shell.h @@ -1008,9 +1008,10 @@ int shell_stop(const struct shell *sh); * @param[in] fmt Format string. * @param[in] ... List of parameters to print. */ -void __printf_like(3, 4) shell_fprintf(const struct shell *sh, - enum shell_vt100_color color, - const char *fmt, ...); +void __printf_like(3, 4) shell_fprintf_impl(const struct shell *sh, enum shell_vt100_color color, + const char *fmt, ...); + +#define shell_fprintf(sh, color, fmt, ...) shell_fprintf_impl(sh, color, fmt, ##__VA_ARGS__) /** * @brief vprintf-like function which sends formatted data stream to the shell. @@ -1277,4 +1278,9 @@ int shell_get_return_value(const struct shell *sh); } #endif +#ifdef CONFIG_SHELL_CUSTOM_HEADER +/* This include must always be at the end of shell.h */ +#include +#endif + #endif /* SHELL_H__ */ diff --git a/subsys/shell/Kconfig b/subsys/shell/Kconfig index 5921a56bb4960..c990783995981 100644 --- a/subsys/shell/Kconfig +++ b/subsys/shell/Kconfig @@ -297,6 +297,14 @@ config SHELL_CMDS_RETURN_VALUE This option enables the retval command. It is used to retrieve the return value from the most recently executed command. +config SHELL_CUSTOM_HEADER + bool "Include Custom Shell Header" + help + When enabled, a custom application provided header, named + "zephyr_custom_shell.h", is included at the end of shell.h. This enables + extension of the shell APIs at the macro level. Please use cautiously! + The internal shell API may change in future releases. + source "subsys/shell/modules/Kconfig" endif # SHELL diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index 1bd8de70d029c..29f9d856d5fcf 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -1548,7 +1548,7 @@ void shell_vfprintf(const struct shell *sh, enum shell_vt100_color color, /* This function mustn't be used from shell context to avoid deadlock. * However it can be used in shell command handlers. */ -void shell_fprintf(const struct shell *sh, enum shell_vt100_color color, +void shell_fprintf_impl(const struct shell *sh, enum shell_vt100_color color, const char *fmt, ...) { va_list args; From c7bef6f2f75bc56f14fa153a3ab41e9068a74815 Mon Sep 17 00:00:00 2001 From: Al Semjonovs Date: Fri, 12 Apr 2024 09:17:45 -0600 Subject: [PATCH 2/2] shell: Add test for custom shell macros Verify customized shell macro APIs Signed-off-by: Al Semjonovs --- .../shell/shell_custom_header/CMakeLists.txt | 10 ++++ .../subsys/shell/shell_custom_header/prj.conf | 11 ++++ .../shell/shell_custom_header/src/main.c | 56 +++++++++++++++++++ .../src/zephyr_custom_shell.h | 17 ++++++ .../shell/shell_custom_header/testcase.yaml | 9 +++ 5 files changed, 103 insertions(+) create mode 100644 tests/subsys/shell/shell_custom_header/CMakeLists.txt create mode 100644 tests/subsys/shell/shell_custom_header/prj.conf create mode 100644 tests/subsys/shell/shell_custom_header/src/main.c create mode 100644 tests/subsys/shell/shell_custom_header/src/zephyr_custom_shell.h create mode 100644 tests/subsys/shell/shell_custom_header/testcase.yaml diff --git a/tests/subsys/shell/shell_custom_header/CMakeLists.txt b/tests/subsys/shell/shell_custom_header/CMakeLists.txt new file mode 100644 index 0000000000000..1993b96acef5f --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(shell_custom_header) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +zephyr_include_directories(src) diff --git a/tests/subsys/shell/shell_custom_header/prj.conf b/tests/subsys/shell/shell_custom_header/prj.conf new file mode 100644 index 0000000000000..602d869aa1c5c --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/prj.conf @@ -0,0 +1,11 @@ +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=n +CONFIG_SHELL_BACKEND_DUMMY=y +CONFIG_SHELL_CMDS_SELECT=y +CONFIG_SHELL_CMD_BUFF_SIZE=90 +CONFIG_SHELL_PRINTF_BUFF_SIZE=15 +CONFIG_SHELL_METAKEYS=n +CONFIG_SHELL_CUSTOM_HEADER=y +CONFIG_LOG=n +CONFIG_ZTEST=y +CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/subsys/shell/shell_custom_header/src/main.c b/tests/subsys/shell/shell_custom_header/src/main.c new file mode 100644 index 0000000000000..81fd71dd06bb3 --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/src/main.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 Google, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Custom header shell test suite + * + */ + +#include +#include + +#include +#include + +static void *shell_setup(void) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + + /* Wait for the initialization of the shell dummy backend. */ + WAIT_FOR(shell_ready(sh), 20000, k_msleep(1)); + zassert_true(shell_ready(sh), "timed out waiting for dummy shell backend"); + + return NULL; +} + +ZTEST_SUITE(sh, NULL, shell_setup, NULL, NULL, NULL); + +ZTEST(sh, test_shell_fprintf) +{ + static const char expect[] = "[CUSTOM_PREFIX]testing 1 2 3"; + const struct shell *sh; + const char *buf; + size_t size; + + sh = shell_backend_dummy_get_ptr(); + zassert_not_null(sh, "Failed to get shell"); + + /* Clear the output buffer */ + shell_backend_dummy_clear_output(sh); + + shell_fprintf(sh, SHELL_VT100_COLOR_DEFAULT, "testing %d %s %c", + 1, "2", '3'); + buf = shell_backend_dummy_get_output(sh, &size); + zassert_true(size >= sizeof(expect), "Expected size > %u, got %d", + sizeof(expect), size); + + /* + * There are prompts and various ANSI characters in the output, so just + * check that the string is in there somewhere. + */ + zassert_true(strstr(buf, expect), + "Expected string to contain '%s', got '%s'", expect, buf); +} diff --git a/tests/subsys/shell/shell_custom_header/src/zephyr_custom_shell.h b/tests/subsys/shell/shell_custom_header/src/zephyr_custom_shell.h new file mode 100644 index 0000000000000..a2eedd2a0a0ef --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/src/zephyr_custom_shell.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Google, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ZEPHYR_CUSTOM_SHELL_H +#define __ZEPHYR_CUSTOM_SHELL_H + +#define CUSTOM_SHELL_PREFIX "[CUSTOM_PREFIX]" + +#undef shell_fprintf + +#define shell_fprintf(sh, color, fmt, ...) \ + shell_fprintf_impl(sh, color, CUSTOM_SHELL_PREFIX fmt, ##__VA_ARGS__) + +#endif /* __ZEPHYR_CUSTOM_SHELL_H */ diff --git a/tests/subsys/shell/shell_custom_header/testcase.yaml b/tests/subsys/shell/shell_custom_header/testcase.yaml new file mode 100644 index 0000000000000..5e85e3aabd865 --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/testcase.yaml @@ -0,0 +1,9 @@ +common: + integration_platforms: + - native_sim + +tests: + shell.shell_custom_header: + tags: + - shell_custom_header + - shell