Skip to content

Commit c71a559

Browse files
nordic-krchnashif
authored andcommitted
shell: Extend shell as a log backend
Initial logger backend support added to shell. Signed-off-by: Krzysztof Chruscinski <[email protected]>
1 parent 989fef9 commit c71a559

File tree

6 files changed

+378
-4
lines changed

6 files changed

+378
-4
lines changed

include/shell/shell.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <shell/shell_types.h>
1212
#include <shell/shell_history.h>
1313
#include <shell/shell_fprintf.h>
14-
#include <logging/log_backend.h>
14+
#include <shell/shell_log_backend.h>
1515
#include <logging/log_instance.h>
1616
#include <logging/log.h>
1717
#include <misc/util.h>
@@ -266,6 +266,19 @@ struct shell_transport {
266266
void *ctx;
267267
};
268268

269+
/** @brief Shell statistics structure. */
270+
struct shell_stats {
271+
u32_t log_lost_cnt; /*!< Lost log counter.*/
272+
};
273+
274+
#if CONFIG_SHELL_STATS
275+
#define SHELL_STATS_DEFINE(_name) static struct shell_stats _name##_stats
276+
#define SHELL_STATS_PTR(_name) (&(_name##_stats))
277+
#else
278+
#define SHELL_STATS_DEFINE(_name)
279+
#define SHELL_STATS_PTR(_name) NULL
280+
#endif /* CONFIG_SHELL_STATS */
281+
269282
/*
270283
* @internal @brief Flags for internal shell usage.
271284
*/
@@ -292,6 +305,7 @@ union shell_internal {
292305
enum shell_signal {
293306
SHELL_SIGNAL_RXRDY,
294307
SHELL_SIGNAL_TXDONE,
308+
SHELL_SIGNAL_LOG_MSG,
295309
SHELL_SIGNAL_KILL,
296310
SHELL_SIGNALS
297311
};
@@ -344,6 +358,10 @@ struct shell {
344358

345359
const struct shell_fprintf *fprintf_ctx;
346360

361+
struct shell_stats *stats;
362+
363+
const struct shell_log_backend *log_backend;
364+
347365
LOG_INSTANCE_PTR_DECLARE(log);
348366

349367
/*!< New line character, only allowed values: \\n and \\r.*/
@@ -368,11 +386,14 @@ struct shell {
368386
static const struct shell _name; \
369387
static struct shell_ctx UTIL_CAT(_name, _ctx); \
370388
static u8_t _name##_out_buffer[CONFIG_SHELL_PRINTF_BUFF_SIZE]; \
389+
SHELL_LOG_BACKEND_DEFINE(_name, _name##_out_buffer, \
390+
CONFIG_SHELL_PRINTF_BUFF_SIZE); \
371391
SHELL_HISTORY_DEFINE(_name, 128, 8);/*todo*/ \
372392
SHELL_FPRINTF_DEFINE(_name## _fprintf, &_name, _name##_out_buffer, \
373393
CONFIG_SHELL_PRINTF_BUFF_SIZE, \
374394
true, shell_print_stream); \
375395
LOG_INSTANCE_REGISTER(shell, _name, CONFIG_SHELL_LOG_LEVEL); \
396+
SHELL_STATS_DEFINE(_name); \
376397
static K_THREAD_STACK_DEFINE(_name##_stack, CONFIG_SHELL_STACK_SIZE);\
377398
static struct k_thread _name##_thread; \
378399
static const struct shell _name = { \
@@ -381,6 +402,8 @@ struct shell {
381402
.ctx = &UTIL_CAT(_name, _ctx), \
382403
.history = SHELL_HISTORY_PTR(_name), \
383404
.fprintf_ctx = &_name##_fprintf, \
405+
.stats = SHELL_STATS_PTR(_name), \
406+
.log_backend = SHELL_LOG_BACKEND_PTR(_name), \
384407
LOG_INSTANCE_PTR_INIT(log, shell, _name) \
385408
.newline_char = newline_ch, \
386409
.thread = &_name##_thread, \

include/shell/shell_log_backend.h

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright (c) 2018 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef SHELL_LOG_BACKEND_H__
8+
#define SHELL_LOG_BACKEND_H__
9+
10+
#include <zephyr.h>
11+
#include <logging/log_backend.h>
12+
#include <logging/log_output.h>
13+
#include <atomic.h>
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
extern const struct log_backend_api log_backend_shell_api;
19+
20+
/** @brief Shell log backend states. */
21+
enum shell_log_backend_state {
22+
SHELL_LOG_BACKEND_UNINIT,
23+
SHELL_LOG_BACKEND_ENABLED,
24+
SHELL_LOG_BACKEND_DISABLED,
25+
SHELL_LOG_BACKEND_PANIC,
26+
};
27+
28+
/** @brief Shell log backend control block (RW data). */
29+
struct shell_log_backend_control_block {
30+
atomic_t cnt;
31+
enum shell_log_backend_state state;
32+
};
33+
34+
/** @brief Shell log backend instance structure (RO data). */
35+
struct shell_log_backend {
36+
const struct log_backend *backend;
37+
struct k_fifo *fifo;
38+
const struct log_output *log_output;
39+
struct shell_log_backend_control_block *control_block;
40+
};
41+
42+
/** @brief Prototype of function outputing processed data. */
43+
int shell_log_backend_output_func(u8_t *data, size_t length, void *ctx);
44+
45+
/** @def SHELL_LOG_BACKEND_DEFINE
46+
* @brief Macro for creating instance of shell log backend.
47+
*
48+
* @param _name Shell name.
49+
* @param _buf Output buffer.
50+
* @param _size Output buffer size.
51+
*/
52+
/** @def SHELL_LOG_BACKEND_PTR
53+
* @brief Macro for retrieving pointer to the instance of shell log backend.
54+
*
55+
* @param _name Shell name.
56+
*/
57+
#if CONFIG_LOG
58+
#define SHELL_LOG_BACKEND_DEFINE(_name, _buf, _size) \
59+
LOG_BACKEND_DEFINE(_name##_backend, log_backend_shell_api); \
60+
K_FIFO_DEFINE(_name##_fifo); \
61+
LOG_OUTPUT_DEFINE(_name##_log_output, shell_log_backend_output_func, \
62+
_buf, _size); \
63+
static struct shell_log_backend_control_block _name##_control_block; \
64+
static const struct shell_log_backend _name##_log_backend = { \
65+
.backend = &_name##_backend, \
66+
.fifo = &_name##_fifo, \
67+
.log_output = &_name##_log_output, \
68+
.control_block = &_name##_control_block \
69+
}
70+
71+
#define SHELL_LOG_BACKEND_PTR(_name) (&_name##_log_backend)
72+
#else /* CONFIG_LOG */
73+
#define SHELL_LOG_BACKEND_DEFINE(_name, _buf, _size) /* empty */
74+
#define SHELL_LOG_BACKEND_PTR(_name) NULL
75+
#endif /* CONFIG_LOG */
76+
77+
/** @brief Enable shell log backend.
78+
*
79+
* @param backend Shell log backend instance.
80+
* @param ctx Pointer to shell instance.
81+
* @param init_log_level Initial log level set to all logging sources.
82+
*/
83+
void shell_log_backend_enable(const struct shell_log_backend *backend,
84+
void *ctx, u32_t init_log_level);
85+
86+
/** @brief Disable shell log backend.
87+
*
88+
* @param backend Shell log backend instance.
89+
*/
90+
void shell_log_backend_disable(const struct shell_log_backend *backend);
91+
92+
/** @brief Trigger processing of one log entry.
93+
*
94+
* @param backend Shell log backend instance.
95+
*
96+
* @return True if message was processed, false if FIFO was empty
97+
*/
98+
bool shell_log_backend_process(const struct shell_log_backend *backend);
99+
100+
#ifdef __cplusplus
101+
}
102+
#endif
103+
104+
#endif /* SHELL_LOG_BACKEND_H__ */

subsys/shell/CMakeLists.txt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,17 @@ zephyr_sources_ifdef(
1919
shell_uart.c
2020
)
2121

22+
zephyr_sources_ifdef(
23+
CONFIG_SHELL_CMDS
24+
shell_cmds.c
25+
)
26+
2227
zephyr_sources_ifdef(
2328
CONFIG_SHELL_HISTORY
2429
shell_history.c
2530
)
2631

2732
zephyr_sources_ifdef(
28-
CONFIG_SHELL_CMDS
29-
shell_cmds.c
33+
CONFIG_LOG
34+
shell_log_backend.c
3035
)

subsys/shell/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,17 @@ config SHELL_HISTORY_BUFFER
135135

136136
endif #SHELL_HISTORY
137137

138+
config SHELL_MAX_LOG_MSG_BUFFERED
139+
int "Maximal number of log messages in FIFO"
140+
default 8
141+
help
142+
When amount of buffered log messages exceeds this threshold oldest
143+
messages are discarded.
144+
145+
config SHELL_STATS
146+
bool "Enable shell statistics"
147+
default y
148+
138149
config SHELL_CMDS
139150
bool "Enable built-in commands"
140151
default y

subsys/shell/shell.c

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,44 @@ static void shell_transport_evt_handler(enum shell_transport_evt evt_type,
10331033
k_poll_signal(signal, 0);
10341034
}
10351035

1036+
static void shell_current_command_erase(const struct shell *shell)
1037+
{
1038+
shell_multiline_data_calc(&shell->ctx->vt100_ctx.cons,
1039+
shell->ctx->cmd_buff_pos,
1040+
shell->ctx->cmd_buff_len);
1041+
shell_op_cursor_horiz_move(shell, -shell->ctx->vt100_ctx.cons.cur_x);
1042+
shell_op_cursor_vert_move(shell, shell->ctx->vt100_ctx.cons.cur_y - 1);
1043+
1044+
clear_eos(shell);
1045+
}
1046+
1047+
static void shell_current_command_print(const struct shell *shell)
1048+
{
1049+
shell_fprintf(shell, SHELL_INFO, "%s", shell->name);
1050+
1051+
if (flag_echo_is_set(shell)) {
1052+
shell_fprintf(shell, SHELL_NORMAL, "%s", shell->ctx->cmd_buff);
1053+
shell_op_cursor_position_synchronize(shell);
1054+
}
1055+
}
1056+
1057+
static void shell_log_process(const struct shell *shell)
1058+
{
1059+
bool processed;
1060+
int signaled;
1061+
int result;
1062+
1063+
do {
1064+
shell_current_command_erase(shell);
1065+
processed = shell_log_backend_process(shell->log_backend);
1066+
shell_current_command_print(shell);
1067+
1068+
k_poll_signal_check(&shell->ctx->signals[SHELL_SIGNAL_RXRDY],
1069+
&signaled, &result);
1070+
1071+
} while (processed && !signaled);
1072+
}
1073+
10361074
static int shell_instance_init(const struct shell *shell, const void *p_config,
10371075
bool use_colors)
10381076
{
@@ -1057,6 +1095,10 @@ static int shell_instance_init(const struct shell *shell, const void *p_config,
10571095
shell->ctx->internal.flags.mode_delete = 1;
10581096
}
10591097

1098+
if (IS_ENABLED(CONFIG_SHELL_STATS)) {
1099+
shell->stats->log_lost_cnt = 0;
1100+
}
1101+
10601102
shell->ctx->internal.flags.tx_rdy = 1;
10611103
shell->ctx->internal.flags.echo = CONFIG_SHELL_ECHO_STATUS;
10621104
shell->ctx->state = SHELL_STATE_INITIALIZED;
@@ -1106,13 +1148,23 @@ void shell_thread(void *shell_handle, void *dummy1, void *dummy2)
11061148
(void)shell_instance_uninit(shell);
11071149

11081150
k_thread_abort(k_current_get());
1109-
} else {
1151+
}
1152+
1153+
k_poll_signal_check(&shell->ctx->signals[SHELL_SIGNAL_LOG_MSG],
1154+
&signaled, &result);
1155+
1156+
if (!signaled) {
11101157
/* Other signals handled together.*/
11111158
k_poll_signal_reset(
11121159
&shell->ctx->signals[SHELL_SIGNAL_RXRDY]);
11131160
k_poll_signal_reset(
11141161
&shell->ctx->signals[SHELL_SIGNAL_TXDONE]);
11151162
shell_process(shell);
1163+
} else if (IS_ENABLED(CONFIG_LOG)) {
1164+
k_poll_signal_reset(
1165+
&shell->ctx->signals[SHELL_SIGNAL_LOG_MSG]);
1166+
/* process log msg */
1167+
shell_log_process(shell);
11161168
}
11171169
}
11181170
}
@@ -1128,6 +1180,13 @@ int shell_init(const struct shell *shell, const void *transport_config,
11281180
return err;
11291181
}
11301182

1183+
if (log_backend) {
1184+
if (IS_ENABLED(CONFIG_LOG)) {
1185+
shell_log_backend_enable(shell->log_backend,
1186+
(void *)shell, init_log_level);
1187+
}
1188+
}
1189+
11311190
(void)k_thread_create(shell->thread,
11321191
shell->stack, CONFIG_SHELL_STACK_SIZE,
11331192
shell_thread, (void *)shell, NULL, NULL,
@@ -1146,6 +1205,11 @@ static int shell_instance_uninit(const struct shell *shell)
11461205
return -EBUSY;
11471206
}
11481207

1208+
if (IS_ENABLED(CONFIG_LOG)) {
1209+
/* todo purge log queue */
1210+
shell_log_backend_disable(shell->log_backend);
1211+
}
1212+
11491213
err = shell->iface->api->uninit(shell->iface);
11501214
if (err != 0) {
11511215
return err;

0 commit comments

Comments
 (0)