dacb3dbfeb
Until now iterable sections APIs have been part of the toolchain (common) headers. They are not strictly related to a toolchain, they just rely on linker providing support for sections. Most files relied on indirect includes to access the API, now, it is included as needed. Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
370 lines
8.5 KiB
C
370 lines
8.5 KiB
C
/*
|
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#ifndef ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_H_
|
|
#define ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_H_
|
|
|
|
#include <zephyr/logging/log_msg.h>
|
|
#include <stdarg.h>
|
|
#include <zephyr/sys/__assert.h>
|
|
#include <zephyr/sys/util.h>
|
|
#include <zephyr/logging/log_output.h>
|
|
#include <zephyr/sys/iterable_sections.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @brief Logger backend interface
|
|
* @defgroup log_backend Logger backend interface
|
|
* @ingroup logger
|
|
* @{
|
|
*/
|
|
|
|
/* Forward declaration of the log_backend type. */
|
|
struct log_backend;
|
|
|
|
|
|
/**
|
|
* @brief Backend events
|
|
*/
|
|
enum log_backend_evt {
|
|
/**
|
|
* @brief Event when process thread finishes processing.
|
|
*
|
|
* This event is emitted when the process thread finishes
|
|
* processing pending log messages.
|
|
*
|
|
* @note This is not emitted when there are no pending
|
|
* log messages being processed.
|
|
*
|
|
* @note Deferred mode only.
|
|
*/
|
|
LOG_BACKEND_EVT_PROCESS_THREAD_DONE,
|
|
|
|
/** @brief Maximum number of backend events */
|
|
LOG_BACKEND_EVT_MAX,
|
|
};
|
|
|
|
/**
|
|
* @brief Argument(s) for backend events.
|
|
*/
|
|
union log_backend_evt_arg {
|
|
/** @brief Unspecified argument(s). */
|
|
void *raw;
|
|
};
|
|
|
|
/**
|
|
* @brief Logger backend API.
|
|
*/
|
|
struct log_backend_api {
|
|
void (*process)(const struct log_backend *const backend,
|
|
union log_msg_generic *msg);
|
|
|
|
void (*dropped)(const struct log_backend *const backend, uint32_t cnt);
|
|
void (*panic)(const struct log_backend *const backend);
|
|
void (*init)(const struct log_backend *const backend);
|
|
int (*is_ready)(const struct log_backend *const backend);
|
|
int (*format_set)(const struct log_backend *const backend,
|
|
uint32_t log_type);
|
|
|
|
void (*notify)(const struct log_backend *const backend,
|
|
enum log_backend_evt event,
|
|
union log_backend_evt_arg *arg);
|
|
};
|
|
|
|
/**
|
|
* @brief Logger backend control block.
|
|
*/
|
|
struct log_backend_control_block {
|
|
void *ctx;
|
|
uint8_t id;
|
|
bool active;
|
|
|
|
/* Initialization level. */
|
|
uint8_t level;
|
|
};
|
|
|
|
/**
|
|
* @brief Logger backend structure.
|
|
*/
|
|
struct log_backend {
|
|
const struct log_backend_api *api;
|
|
struct log_backend_control_block *cb;
|
|
const char *name;
|
|
bool autostart;
|
|
};
|
|
|
|
/**
|
|
* @brief Macro for creating a logger backend instance.
|
|
*
|
|
* @param _name Name of the backend instance.
|
|
* @param _api Logger backend API.
|
|
* @param _autostart If true backend is initialized and activated together
|
|
* with the logger subsystem.
|
|
* @param ... Optional context.
|
|
*/
|
|
#define LOG_BACKEND_DEFINE(_name, _api, _autostart, ...) \
|
|
static struct log_backend_control_block UTIL_CAT(backend_cb_, _name) = \
|
|
{ \
|
|
COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
|
|
(), (.ctx = __VA_ARGS__,)) \
|
|
.id = 0, \
|
|
.active = false, \
|
|
}; \
|
|
static const STRUCT_SECTION_ITERABLE(log_backend, _name) = \
|
|
{ \
|
|
.api = &_api, \
|
|
.cb = &UTIL_CAT(backend_cb_, _name), \
|
|
.name = STRINGIFY(_name), \
|
|
.autostart = _autostart \
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Initialize or initiate the logging backend.
|
|
*
|
|
* If backend initialization takes longer time it could block logging thread
|
|
* if backend is autostarted. That is because all backends are initilized in
|
|
* the context of the logging thread. In that case, backend shall provide
|
|
* function for polling for readiness (@ref log_backend_is_ready).
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
*/
|
|
static inline void log_backend_init(const struct log_backend *const backend)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
if (backend->api->init) {
|
|
backend->api->init(backend);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Poll for backend readiness.
|
|
*
|
|
* If backend is ready immediately after initialization then backend may not
|
|
* provide this function.
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
*
|
|
* @retval 0 if backend is ready.
|
|
* @retval -EBUSY if backend is not yet ready.
|
|
*/
|
|
static inline int log_backend_is_ready(const struct log_backend *const backend)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
if (backend->api->is_ready != NULL) {
|
|
return backend->api->is_ready(backend);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Process message.
|
|
*
|
|
* Function is used in deferred and immediate mode. On return, message content
|
|
* is processed by the backend and memory can be freed.
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
* @param[in] msg Pointer to message with log entry.
|
|
*/
|
|
static inline void log_backend_msg_process(const struct log_backend *const backend,
|
|
union log_msg_generic *msg)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
__ASSERT_NO_MSG(msg != NULL);
|
|
backend->api->process(backend, msg);
|
|
}
|
|
|
|
/**
|
|
* @brief Notify backend about dropped log messages.
|
|
*
|
|
* Function is optional.
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
* @param[in] cnt Number of dropped logs since last notification.
|
|
*/
|
|
static inline void log_backend_dropped(const struct log_backend *const backend,
|
|
uint32_t cnt)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
|
|
if (backend->api->dropped != NULL) {
|
|
backend->api->dropped(backend, cnt);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Reconfigure backend to panic mode.
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
*/
|
|
static inline void log_backend_panic(const struct log_backend *const backend)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
backend->api->panic(backend);
|
|
}
|
|
|
|
/**
|
|
* @brief Set backend id.
|
|
*
|
|
* @note It is used internally by the logger.
|
|
*
|
|
* @param backend Pointer to the backend instance.
|
|
* @param id ID.
|
|
*/
|
|
static inline void log_backend_id_set(const struct log_backend *const backend,
|
|
uint8_t id)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
backend->cb->id = id;
|
|
}
|
|
|
|
/**
|
|
* @brief Get backend id.
|
|
*
|
|
* @note It is used internally by the logger.
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
* @return Id.
|
|
*/
|
|
static inline uint8_t log_backend_id_get(const struct log_backend *const backend)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
return backend->cb->id;
|
|
}
|
|
|
|
/**
|
|
* @brief Get backend.
|
|
*
|
|
* @param[in] idx Pointer to the backend instance.
|
|
*
|
|
* @return Pointer to the backend instance.
|
|
*/
|
|
static inline const struct log_backend *log_backend_get(uint32_t idx)
|
|
{
|
|
const struct log_backend *backend;
|
|
|
|
STRUCT_SECTION_GET(log_backend, idx, &backend);
|
|
|
|
return backend;
|
|
}
|
|
|
|
/**
|
|
* @brief Get number of backends.
|
|
*
|
|
* @return Number of backends.
|
|
*/
|
|
static inline int log_backend_count_get(void)
|
|
{
|
|
int cnt;
|
|
|
|
STRUCT_SECTION_COUNT(log_backend, &cnt);
|
|
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* @brief Activate backend.
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
* @param[in] ctx User context.
|
|
*/
|
|
static inline void log_backend_activate(const struct log_backend *const backend,
|
|
void *ctx)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
backend->cb->ctx = ctx;
|
|
backend->cb->active = true;
|
|
}
|
|
|
|
/**
|
|
* @brief Deactivate backend.
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
*/
|
|
static inline void log_backend_deactivate(
|
|
const struct log_backend *const backend)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
backend->cb->active = false;
|
|
}
|
|
|
|
/**
|
|
* @brief Check state of the backend.
|
|
*
|
|
* @param[in] backend Pointer to the backend instance.
|
|
*
|
|
* @return True if backend is active, false otherwise.
|
|
*/
|
|
static inline bool log_backend_is_active(
|
|
const struct log_backend *const backend)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
return backend->cb->active;
|
|
}
|
|
|
|
/** @brief Set logging format.
|
|
*
|
|
* @param backend Pointer to the backend instance.
|
|
* @param log_type Log format.
|
|
*
|
|
* @retval -ENOTSUP If the backend does not support changing format types.
|
|
* @retval -EINVAL If the input is invalid.
|
|
* @retval 0 for success.
|
|
*/
|
|
static inline int log_backend_format_set(const struct log_backend *backend, uint32_t log_type)
|
|
{
|
|
extern size_t log_format_table_size(void);
|
|
|
|
if ((size_t)log_type >= log_format_table_size()) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (log_format_func_t_get(log_type) == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (backend == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (backend->api->format_set == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return backend->api->format_set(backend, log_type);
|
|
}
|
|
|
|
/**
|
|
* @brief Notify a backend of an event.
|
|
*
|
|
* @param backend Pointer to the backend instance.
|
|
* @param event Event to be notified.
|
|
* @param arg Pointer to the argument(s).
|
|
*/
|
|
static inline void log_backend_notify(const struct log_backend *const backend,
|
|
enum log_backend_evt event,
|
|
union log_backend_evt_arg *arg)
|
|
{
|
|
__ASSERT_NO_MSG(backend != NULL);
|
|
|
|
if (backend->api->notify) {
|
|
backend->api->notify(backend, event, arg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_H_ */
|