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>
293 lines
8.4 KiB
C
293 lines
8.4 KiB
C
/*
|
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#ifndef ZEPHYR_INCLUDE_LOGGING_LOG_LINK_H_
|
|
#define ZEPHYR_INCLUDE_LOGGING_LOG_LINK_H_
|
|
|
|
#include <zephyr/types.h>
|
|
#include <zephyr/sys/__assert.h>
|
|
#include <zephyr/logging/log_msg.h>
|
|
#include <zephyr/logging/log_internal.h>
|
|
#include <zephyr/sys/iterable_sections.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @brief Log link API
|
|
* @defgroup log_link Log link API
|
|
* @ingroup logger
|
|
* @{
|
|
*/
|
|
|
|
struct log_link;
|
|
|
|
typedef void (*log_link_callback_t)(const struct log_link *link,
|
|
union log_msg_generic *msg);
|
|
|
|
typedef void (*log_link_dropped_cb_t)(const struct log_link *link,
|
|
uint32_t dropped);
|
|
|
|
struct log_link_config {
|
|
log_link_callback_t msg_cb;
|
|
log_link_dropped_cb_t dropped_cb;
|
|
};
|
|
|
|
struct log_link_api {
|
|
int (*initiate)(const struct log_link *link, struct log_link_config *config);
|
|
int (*activate)(const struct log_link *link);
|
|
int (*get_domain_name)(const struct log_link *link, uint32_t domain_id,
|
|
char *buf, size_t *length);
|
|
int (*get_source_name)(const struct log_link *link, uint32_t domain_id,
|
|
uint16_t source_id, char *buf, size_t *length);
|
|
int (*get_levels)(const struct log_link *link, uint32_t domain_id,
|
|
uint16_t source_id, uint8_t *level,
|
|
uint8_t *runtime_level);
|
|
int (*set_runtime_level)(const struct log_link *link, uint32_t domain_id,
|
|
uint16_t source_id, uint8_t level);
|
|
};
|
|
|
|
struct log_link_ctrl_blk {
|
|
uint32_t domain_cnt;
|
|
uint16_t source_cnt[1 + COND_CODE_1(CONFIG_LOG_MULTIDOMAIN,
|
|
(CONFIG_LOG_REMOTE_DOMAIN_MAX_COUNT),
|
|
(0))];
|
|
uint32_t domain_offset;
|
|
uint32_t *filters;
|
|
};
|
|
|
|
struct log_link {
|
|
const struct log_link_api *api;
|
|
const char *name;
|
|
struct log_link_ctrl_blk *ctrl_blk;
|
|
void *ctx;
|
|
struct mpsc_pbuf_buffer *mpsc_pbuf;
|
|
const struct mpsc_pbuf_buffer_config *mpsc_pbuf_config;
|
|
};
|
|
|
|
/** @brief Create instance of a log link.
|
|
*
|
|
* Link can have dedicated buffer for messages if @p _buf_len is positive. In
|
|
* that case messages will be processed in an order since logging core will
|
|
* attempt to fetch message from all available buffers (default and links) and
|
|
* process the one with the earliest timestamp. If strict ordering is not needed
|
|
* then dedicated buffer may be omitted (@p _buf_len set to 0). That results in
|
|
* better memory utilization but unordered messages passed to backends.
|
|
*
|
|
* @param _name Instance name.
|
|
* @param _api API list. See @ref log_link_api.
|
|
* @param _buf_wlen Size (in words) of dedicated buffer for messages from this buffer.
|
|
* If 0 default buffer is used.
|
|
* @param _ctx Context (void *) associated with the link.
|
|
*/
|
|
#define LOG_LINK_DEF(_name, _api, _buf_wlen, _ctx) \
|
|
static uint32_t __aligned(Z_LOG_MSG_ALIGNMENT) _name##_buf32[_buf_wlen]; \
|
|
static const struct mpsc_pbuf_buffer_config _name##_mpsc_pbuf_config = { \
|
|
.buf = (uint32_t *)_name##_buf32, \
|
|
.size = _buf_wlen, \
|
|
.notify_drop = z_log_notify_drop, \
|
|
.get_wlen = log_msg_generic_get_wlen, \
|
|
.flags = IS_ENABLED(CONFIG_LOG_MODE_OVERFLOW) ? \
|
|
MPSC_PBUF_MODE_OVERWRITE : 0 \
|
|
}; \
|
|
COND_CODE_0(_buf_wlen, (), (static STRUCT_SECTION_ITERABLE(log_msg_ptr, \
|
|
_name##_log_msg_ptr);)) \
|
|
static STRUCT_SECTION_ITERABLE_ALTERNATE(log_mpsc_pbuf, \
|
|
mpsc_pbuf_buffer, \
|
|
_name##_log_mpsc_pbuf); \
|
|
static struct log_link_ctrl_blk _name##_ctrl_blk; \
|
|
static const STRUCT_SECTION_ITERABLE(log_link, _name) = \
|
|
{ \
|
|
.api = &_api, \
|
|
.name = STRINGIFY(_name), \
|
|
.ctrl_blk = &_name##_ctrl_blk, \
|
|
.ctx = _ctx, \
|
|
.mpsc_pbuf = _buf_wlen ? &_name##_log_mpsc_pbuf : NULL, \
|
|
.mpsc_pbuf_config = _buf_wlen ? &_name##_mpsc_pbuf_config : NULL \
|
|
}
|
|
|
|
/** @brief Initiate log link.
|
|
*
|
|
* Function initiates the link. Since initialization procedure may be time
|
|
* consuming, function returns before link is ready to not block logging
|
|
* initialization. @ref log_link_activate is called to complete link initialization.
|
|
*
|
|
* @param link Log link instance.
|
|
* @param config Configuration.
|
|
*
|
|
* @return 0 on success or error code.
|
|
*/
|
|
static inline int log_link_initiate(const struct log_link *link,
|
|
struct log_link_config *config)
|
|
{
|
|
__ASSERT_NO_MSG(link);
|
|
|
|
return link->api->initiate(link, config);
|
|
}
|
|
|
|
/** @brief Activate log link.
|
|
*
|
|
* Function checks if link is initilized and completes initialization process.
|
|
* When successfully returns, link is ready with domain and sources count fetched
|
|
* and timestamp details updated.
|
|
*
|
|
* @param link Log link instance.
|
|
*
|
|
* @retval 0 When successfully activated.
|
|
* @retval -EINPROGRESS Activation in progress.
|
|
*/
|
|
static inline int log_link_activate(const struct log_link *link)
|
|
{
|
|
__ASSERT_NO_MSG(link);
|
|
|
|
return link->api->activate(link);
|
|
}
|
|
|
|
/** @brief Check if link is activated.
|
|
*
|
|
* @param link Log link instance.
|
|
*
|
|
* @retval 0 When successfully activated.
|
|
* @retval -EINPROGRESS Activation in progress.
|
|
*/
|
|
static inline int log_link_is_active(const struct log_link *link)
|
|
{
|
|
return link->ctrl_blk->domain_offset > 0 ? 0 : -EINPROGRESS;
|
|
}
|
|
|
|
/** @brief Get number of domains in the link.
|
|
*
|
|
* @param[in] link Log link instance.
|
|
*
|
|
* @return Number of domains.
|
|
*/
|
|
static inline uint8_t log_link_domains_count(const struct log_link *link)
|
|
{
|
|
__ASSERT_NO_MSG(link);
|
|
|
|
return link->ctrl_blk->domain_cnt;
|
|
}
|
|
|
|
/** @brief Get number of sources in the domain.
|
|
*
|
|
* @param[in] link Log link instance.
|
|
* @param[in] domain_id Relative domain ID.
|
|
*
|
|
* @return Source count.
|
|
*/
|
|
static inline uint16_t log_link_sources_count(const struct log_link *link,
|
|
uint32_t domain_id)
|
|
{
|
|
__ASSERT_NO_MSG(link);
|
|
|
|
return link->ctrl_blk->source_cnt[domain_id];
|
|
}
|
|
|
|
/** @brief Get domain name.
|
|
*
|
|
* @param[in] link Log link instance.
|
|
* @param[in] domain_id Relative domain ID.
|
|
* @param[out] buf Output buffer filled with domain name. If NULL
|
|
* then name length is returned.
|
|
* @param[in,out] length Buffer size. Name is trimmed if it does not fit
|
|
* in the buffer and field is set to actual name
|
|
* length.
|
|
*
|
|
* @return 0 on success or error code.
|
|
*/
|
|
static inline int log_link_get_domain_name(const struct log_link *link,
|
|
uint32_t domain_id, char *buf,
|
|
size_t *length)
|
|
{
|
|
__ASSERT_NO_MSG(link);
|
|
|
|
return link->api->get_domain_name(link, domain_id, buf, length);
|
|
}
|
|
|
|
/** @brief Get source name.
|
|
*
|
|
* @param[in] link Log link instance.
|
|
* @param[in] domain_id Relative domain ID.
|
|
* @param[in] source_id Source ID.
|
|
* @param[out] buf Output buffer filled with source name.
|
|
* @param[in,out] length Buffer size. Name is trimmed if it does not fit
|
|
* in the buffer and field is set to actual name
|
|
* length.
|
|
*
|
|
* @return 0 on success or error code.
|
|
*/
|
|
static inline int log_link_get_source_name(const struct log_link *link,
|
|
uint32_t domain_id, uint16_t source_id,
|
|
char *buf, size_t *length)
|
|
{
|
|
__ASSERT_NO_MSG(link);
|
|
__ASSERT_NO_MSG(buf);
|
|
|
|
return link->api->get_source_name(link, domain_id, source_id,
|
|
buf, length);
|
|
}
|
|
|
|
/** @brief Get level settings of the given source.
|
|
*
|
|
* @param[in] link Log link instance.
|
|
* @param[in] domain_id Relative domain ID.
|
|
* @param[in] source_id Source ID.
|
|
* @param[out] level Location to store requested compile time level.
|
|
* @param[out] runtime_level Location to store requested runtime time level.
|
|
*
|
|
* @return 0 on success or error code.
|
|
*/
|
|
static inline int log_link_get_levels(const struct log_link *link,
|
|
uint32_t domain_id, uint16_t source_id,
|
|
uint8_t *level, uint8_t *runtime_level)
|
|
{
|
|
__ASSERT_NO_MSG(link);
|
|
|
|
return link->api->get_levels(link, domain_id, source_id,
|
|
level, runtime_level);
|
|
}
|
|
|
|
/** @brief Set runtime level of the given source.
|
|
*
|
|
* @param[in] link Log link instance.
|
|
* @param[in] domain_id Relative domain ID.
|
|
* @param[in] source_id Source ID.
|
|
* @param[out] level Requested level.
|
|
*
|
|
* @return 0 on success or error code.
|
|
*/
|
|
static inline int log_link_set_runtime_level(const struct log_link *link,
|
|
uint32_t domain_id, uint16_t source_id,
|
|
uint8_t level)
|
|
{
|
|
__ASSERT_NO_MSG(link);
|
|
__ASSERT_NO_MSG(level);
|
|
|
|
return link->api->set_runtime_level(link, domain_id, source_id, level);
|
|
}
|
|
|
|
/**
|
|
* @brief Enqueue external log message.
|
|
*
|
|
* Add log message to processing queue. Log message is created outside local
|
|
* core. For example it maybe coming from external domain.
|
|
*
|
|
* @param link Log link instance.
|
|
* @param data Message from remote domain.
|
|
* @param len Length in bytes.
|
|
*/
|
|
void z_log_msg_enqueue(const struct log_link *link, const void *data, size_t len);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* ZEPHYR_INCLUDE_LOGGING_LOG_LINK_H_ */
|