1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ZEPHYR_INCLUDE_LOGGING_LOG_LINK_H_
7 #define ZEPHYR_INCLUDE_LOGGING_LOG_LINK_H_
8 
9 #include <zephyr/types.h>
10 #include <zephyr/sys/__assert.h>
11 #include <zephyr/logging/log_msg.h>
12 #include <zephyr/logging/log_internal.h>
13 #include <zephyr/sys/iterable_sections.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /**
20  * @brief Log link API
21  * @defgroup log_link Log link API
22  * @ingroup logger
23  * @{
24  */
25 
26 struct log_link;
27 
28 typedef void (*log_link_callback_t)(const struct log_link *link,
29 				    union log_msg_generic *msg);
30 
31 typedef void (*log_link_dropped_cb_t)(const struct log_link *link,
32 				      uint32_t dropped);
33 
34 struct log_link_config {
35 	log_link_callback_t msg_cb;
36 	log_link_dropped_cb_t dropped_cb;
37 };
38 
39 struct log_link_api {
40 	int (*initiate)(const struct log_link *link, struct log_link_config *config);
41 	int (*activate)(const struct log_link *link);
42 	int (*get_domain_name)(const struct log_link *link, uint32_t domain_id,
43 				char *buf, size_t *length);
44 	int (*get_source_name)(const struct log_link *link, uint32_t domain_id,
45 				uint16_t source_id, char *buf, size_t *length);
46 	int (*get_levels)(const struct log_link *link, uint32_t domain_id,
47 				uint16_t source_id, uint8_t *level,
48 				uint8_t *runtime_level);
49 	int (*set_runtime_level)(const struct log_link *link, uint32_t domain_id,
50 				uint16_t source_id, uint8_t level);
51 };
52 
53 struct log_link_ctrl_blk {
54 	uint32_t domain_cnt;
55 	uint16_t source_cnt[1 + COND_CODE_1(CONFIG_LOG_MULTIDOMAIN,
56 					    (CONFIG_LOG_REMOTE_DOMAIN_MAX_COUNT),
57 					    (0))];
58 	uint32_t domain_offset;
59 	uint32_t *filters;
60 };
61 
62 struct log_link {
63 	const struct log_link_api *api;
64 	const char *name;
65 	struct log_link_ctrl_blk *ctrl_blk;
66 	void *ctx;
67 	struct mpsc_pbuf_buffer *mpsc_pbuf;
68 	const struct mpsc_pbuf_buffer_config *mpsc_pbuf_config;
69 };
70 
71 /** @brief Create instance of a log link.
72  *
73  * Link can have dedicated buffer for messages if @p _buf_len is positive. In
74  * that case messages will be processed in an order since logging core will
75  * attempt to fetch message from all available buffers (default and links) and
76  * process the one with the earliest timestamp. If strict ordering is not needed
77  * then dedicated buffer may be omitted (@p _buf_len set to 0). That results in
78  * better memory utilization but unordered messages passed to backends.
79  *
80  * @param _name     Instance name.
81  * @param _api      API list. See @ref log_link_api.
82  * @param _buf_wlen Size (in words) of dedicated buffer for messages from this buffer.
83  *		    If 0 default buffer is used.
84  * @param _ctx      Context (void *) associated with the link.
85  */
86 #define LOG_LINK_DEF(_name, _api, _buf_wlen, _ctx) \
87 	static uint32_t __aligned(Z_LOG_MSG_ALIGNMENT) _name##_buf32[_buf_wlen]; \
88 	static const struct mpsc_pbuf_buffer_config _name##_mpsc_pbuf_config = { \
89 		.buf = (uint32_t *)_name##_buf32, \
90 		.size = _buf_wlen, \
91 		.notify_drop = z_log_notify_drop, \
92 		.get_wlen = log_msg_generic_get_wlen, \
93 		.flags = IS_ENABLED(CONFIG_LOG_MODE_OVERFLOW) ? \
94 			MPSC_PBUF_MODE_OVERWRITE : 0 \
95 	}; \
96 	COND_CODE_0(_buf_wlen, (), (static STRUCT_SECTION_ITERABLE(log_msg_ptr, \
97 								   _name##_log_msg_ptr);)) \
98 	static STRUCT_SECTION_ITERABLE_ALTERNATE(log_mpsc_pbuf, \
99 						 mpsc_pbuf_buffer, \
100 						 _name##_log_mpsc_pbuf); \
101 	static struct log_link_ctrl_blk _name##_ctrl_blk; \
102 	static const STRUCT_SECTION_ITERABLE(log_link, _name) = \
103 	{ \
104 		.api = &_api, \
105 		.name = STRINGIFY(_name), \
106 		.ctrl_blk = &_name##_ctrl_blk, \
107 		.ctx = _ctx, \
108 		.mpsc_pbuf = _buf_wlen ? &_name##_log_mpsc_pbuf : NULL, \
109 		.mpsc_pbuf_config = _buf_wlen ? &_name##_mpsc_pbuf_config : NULL \
110 	}
111 
112 /** @brief Initiate log link.
113  *
114  * Function initiates the link. Since initialization procedure may be time
115  * consuming, function returns before link is ready to not block logging
116  * initialization. @ref log_link_activate is called to complete link initialization.
117  *
118  * @param link		Log link instance.
119  * @param config	Configuration.
120  *
121  * @return 0 on success or error code.
122  */
log_link_initiate(const struct log_link * link,struct log_link_config * config)123 static inline int log_link_initiate(const struct log_link *link,
124 				   struct log_link_config *config)
125 {
126 	__ASSERT_NO_MSG(link);
127 
128 	return link->api->initiate(link, config);
129 }
130 
131 /** @brief Activate log link.
132  *
133  * Function checks if link is initilized and completes initialization process.
134  * When successfully returns, link is ready with domain and sources count fetched
135  * and timestamp details updated.
136  *
137  * @param link		Log link instance.
138  *
139  * @retval 0 When successfully activated.
140  * @retval -EINPROGRESS Activation in progress.
141  */
log_link_activate(const struct log_link * link)142 static inline int log_link_activate(const struct log_link *link)
143 {
144 	__ASSERT_NO_MSG(link);
145 
146 	return link->api->activate(link);
147 }
148 
149 /** @brief Check if link is activated.
150  *
151  * @param link		Log link instance.
152  *
153  * @retval 0 When successfully activated.
154  * @retval -EINPROGRESS Activation in progress.
155  */
log_link_is_active(const struct log_link * link)156 static inline int log_link_is_active(const struct log_link *link)
157 {
158 	return link->ctrl_blk->domain_offset > 0 ? 0 : -EINPROGRESS;
159 }
160 
161 /** @brief Get number of domains in the link.
162  *
163  * @param[in] link	Log link instance.
164  *
165  * @return Number of domains.
166  */
log_link_domains_count(const struct log_link * link)167 static inline uint8_t log_link_domains_count(const struct log_link *link)
168 {
169 	__ASSERT_NO_MSG(link);
170 
171 	return link->ctrl_blk->domain_cnt;
172 }
173 
174 /** @brief Get number of sources in the domain.
175  *
176  * @param[in] link		Log link instance.
177  * @param[in] domain_id		Relative domain ID.
178  *
179  * @return Source count.
180  */
log_link_sources_count(const struct log_link * link,uint32_t domain_id)181 static inline uint16_t log_link_sources_count(const struct log_link *link,
182 					      uint32_t domain_id)
183 {
184 	__ASSERT_NO_MSG(link);
185 
186 	return link->ctrl_blk->source_cnt[domain_id];
187 }
188 
189 /** @brief Get domain name.
190  *
191  * @param[in] link		Log link instance.
192  * @param[in] domain_id		Relative domain ID.
193  * @param[out] buf		Output buffer filled with domain name. If NULL
194  *				then name length is returned.
195  * @param[in,out] length	Buffer size. Name is trimmed if it does not fit
196  *				in the buffer and field is set to actual name
197  *				length.
198  *
199  * @return 0 on success or error code.
200  */
log_link_get_domain_name(const struct log_link * link,uint32_t domain_id,char * buf,size_t * length)201 static inline int log_link_get_domain_name(const struct log_link *link,
202 					   uint32_t domain_id, char *buf,
203 					   size_t *length)
204 {
205 	__ASSERT_NO_MSG(link);
206 
207 	return link->api->get_domain_name(link, domain_id, buf, length);
208 }
209 
210 /** @brief Get source name.
211  *
212  * @param[in] link	Log link instance.
213  * @param[in] domain_id	Relative domain ID.
214  * @param[in] source_id	Source ID.
215  * @param[out] buf	Output buffer filled with source name.
216  * @param[in,out] length	Buffer size. Name is trimmed if it does not fit
217  *				in the buffer and field is set to actual name
218  *				length.
219  *
220  * @return 0 on success or error code.
221  */
log_link_get_source_name(const struct log_link * link,uint32_t domain_id,uint16_t source_id,char * buf,size_t * length)222 static inline int log_link_get_source_name(const struct log_link *link,
223 					   uint32_t domain_id, uint16_t source_id,
224 					   char *buf, size_t *length)
225 {
226 	__ASSERT_NO_MSG(link);
227 	__ASSERT_NO_MSG(buf);
228 
229 	return link->api->get_source_name(link, domain_id, source_id,
230 					buf, length);
231 }
232 
233 /** @brief Get level settings of the given source.
234  *
235  * @param[in] link	Log link instance.
236  * @param[in] domain_id	Relative domain ID.
237  * @param[in] source_id	Source ID.
238  * @param[out] level	Location to store requested compile time level.
239  * @param[out] runtime_level Location to store requested runtime time level.
240  *
241  * @return 0 on success or error code.
242  */
log_link_get_levels(const struct log_link * link,uint32_t domain_id,uint16_t source_id,uint8_t * level,uint8_t * runtime_level)243 static inline int log_link_get_levels(const struct log_link *link,
244 				      uint32_t domain_id, uint16_t source_id,
245 				      uint8_t *level, uint8_t *runtime_level)
246 {
247 	__ASSERT_NO_MSG(link);
248 
249 	return link->api->get_levels(link, domain_id, source_id,
250 				     level, runtime_level);
251 }
252 
253 /** @brief Set runtime level of the given source.
254  *
255  * @param[in] link	Log link instance.
256  * @param[in] domain_id	Relative domain ID.
257  * @param[in] source_id	Source ID.
258  * @param[out] level	Requested level.
259  *
260  * @return 0 on success or error code.
261  */
log_link_set_runtime_level(const struct log_link * link,uint32_t domain_id,uint16_t source_id,uint8_t level)262 static inline int log_link_set_runtime_level(const struct log_link *link,
263 					     uint32_t domain_id, uint16_t source_id,
264 					     uint8_t level)
265 {
266 	__ASSERT_NO_MSG(link);
267 	__ASSERT_NO_MSG(level);
268 
269 	return link->api->set_runtime_level(link, domain_id, source_id, level);
270 }
271 
272 /**
273  * @brief Enqueue external log message.
274  *
275  * Add log message to processing queue. Log message is created outside local
276  * core. For example it maybe coming from external domain.
277  *
278  * @param link Log link instance.
279  * @param data Message from remote domain.
280  * @param len  Length in bytes.
281  */
282 void z_log_msg_enqueue(const struct log_link *link, const void *data, size_t len);
283 
284 /**
285  * @}
286  */
287 
288 #ifdef __cplusplus
289 }
290 #endif
291 
292 #endif /* ZEPHYR_INCLUDE_LOGGING_LOG_LINK_H_ */
293