/* * 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 #include #include #include #include #include #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 initialized 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_ */