/* * Copyright (c) 2018 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include "shell_ops.h" #include int shell_log_backend_output_func(u8_t *data, size_t length, void *ctx) { shell_print_stream(ctx, data, length); return length; } void shell_log_backend_enable(const struct shell_log_backend *backend, void *ctx, u32_t init_log_level) { log_backend_enable(backend->backend, ctx, init_log_level); log_output_ctx_set(backend->log_output, ctx); backend->control_block->cnt = 0; backend->control_block->state = SHELL_LOG_BACKEND_ENABLED; } static struct log_msg *msg_from_fifo(const struct shell_log_backend *backend) { struct shell_log_backend_msg msg; int err; err = k_msgq_get(backend->msgq, &msg, K_NO_WAIT); return (err == 0) ? msg.msg : NULL; } static void fifo_flush(const struct shell_log_backend *backend) { struct log_msg *msg; /* Flush log messages. */ while ((msg = msg_from_fifo(backend)) != NULL) { log_msg_put(msg); } } static void flush_expired_messages(const struct shell *shell) { int err; struct shell_log_backend_msg msg; struct k_msgq *msgq = shell->log_backend->msgq; u32_t timeout = shell->log_backend->timeout; u32_t now = k_uptime_get_32(); while (1) { err = k_msgq_peek(msgq, &msg); if (err == 0 && ((now - msg.timestamp) > timeout)) { (void)k_msgq_get(msgq, &msg, K_NO_WAIT); log_msg_put(msg.msg); if (IS_ENABLED(CONFIG_SHELL_STATS)) { shell->stats->log_lost_cnt++; } } else { break; } } } static void msg_to_fifo(const struct shell *shell, struct log_msg *msg) { int err; struct shell_log_backend_msg t_msg = { .msg = msg, .timestamp = k_uptime_get_32() }; err = k_msgq_put(shell->log_backend->msgq, &t_msg, shell->log_backend->timeout); switch (err) { case 0: break; case -EAGAIN: case -ENOMSG: { flush_expired_messages(shell); err = k_msgq_put(shell->log_backend->msgq, &msg, K_NO_WAIT); if (err) { /* Unexpected case as we just freed one element and * there is no other context that puts into the msgq. */ __ASSERT_NO_MSG(0); } break; } default: /* Other errors are not expected. */ __ASSERT_NO_MSG(0); break; } } void shell_log_backend_disable(const struct shell_log_backend *backend) { fifo_flush(backend); log_backend_disable(backend->backend); backend->control_block->state = SHELL_LOG_BACKEND_DISABLED; } static void msg_process(const struct log_output *log_output, struct log_msg *msg) { u32_t flags = LOG_OUTPUT_FLAG_LEVEL | LOG_OUTPUT_FLAG_TIMESTAMP | LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP; if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) { flags |= LOG_OUTPUT_FLAG_COLORS; } log_output_msg_process(log_output, msg, flags); log_msg_put(msg); } bool shell_log_backend_process(const struct shell_log_backend *backend) { const struct shell *shell = (const struct shell *)backend->backend->cb->ctx; struct log_msg *msg = msg_from_fifo(backend); if (!msg) { return false; } msg_process(shell->log_backend->log_output, msg); return true; } static void put(const struct log_backend *const backend, struct log_msg *msg) { const struct shell *shell = (const struct shell *)backend->cb->ctx; struct k_poll_signal *signal; log_msg_get(msg); switch (shell->log_backend->control_block->state) { case SHELL_LOG_BACKEND_ENABLED: msg_to_fifo(shell, msg); if (IS_ENABLED(CONFIG_MULTITHREADING)) { signal = &shell->ctx->signals[SHELL_SIGNAL_LOG_MSG]; k_poll_signal_raise(signal, 0); } break; case SHELL_LOG_BACKEND_PANIC: msg_process(shell->log_backend->log_output, msg); break; case SHELL_LOG_BACKEND_DISABLED: /* fall through */ /* no break */ default: /* Discard message. */ log_msg_put(msg); } } static void panic(const struct log_backend *const backend) { const struct shell *shell = (const struct shell *)backend->cb->ctx; int err; err = shell->iface->api->enable(shell->iface, true); if (err == 0) { shell->log_backend->control_block->state = SHELL_LOG_BACKEND_PANIC; /* Move to the start of next line. */ shell_multiline_data_calc(&shell->ctx->vt100_ctx.cons, shell->ctx->cmd_buff_pos, shell->ctx->cmd_buff_len); shell_op_cursor_vert_move(shell, -1); shell_op_cursor_horiz_move(shell, -shell->ctx->vt100_ctx.cons.cur_x); while (shell_log_backend_process(shell->log_backend)) { /* empty */ } } else { shell_log_backend_disable(shell->log_backend); } } const struct log_backend_api log_backend_shell_api = { .put = put, .panic = panic };