1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_H_
7 #define ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_H_
8 
9 #include <zephyr/logging/log_msg.h>
10 #include <stdarg.h>
11 #include <zephyr/sys/__assert.h>
12 #include <zephyr/sys/util.h>
13 #include <zephyr/logging/log_output.h>
14 #include <zephyr/sys/iterable_sections.h>
15 
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
19 
20 /**
21  * @brief Logger backend interface
22  * @defgroup log_backend Logger backend interface
23  * @ingroup logger
24  * @{
25  */
26 
27 /* Forward declaration of the log_backend type. */
28 struct log_backend;
29 
30 
31 /**
32  * @brief Backend events
33  */
34 enum log_backend_evt {
35 	/**
36 	 * @brief Event when process thread finishes processing.
37 	 *
38 	 * This event is emitted when the process thread finishes
39 	 * processing pending log messages.
40 	 *
41 	 * @note This is not emitted when there are no pending
42 	 *       log messages being processed.
43 	 *
44 	 * @note Deferred mode only.
45 	 */
46 	LOG_BACKEND_EVT_PROCESS_THREAD_DONE,
47 
48 	/** @brief Maximum number of backend events */
49 	LOG_BACKEND_EVT_MAX,
50 };
51 
52 /**
53  * @brief Argument(s) for backend events.
54  */
55 union log_backend_evt_arg {
56 	/** @brief Unspecified argument(s). */
57 	void *raw;
58 };
59 
60 /**
61  * @brief Logger backend API.
62  */
63 struct log_backend_api {
64 	void (*process)(const struct log_backend *const backend,
65 			union log_msg_generic *msg);
66 
67 	void (*dropped)(const struct log_backend *const backend, uint32_t cnt);
68 	void (*panic)(const struct log_backend *const backend);
69 	void (*init)(const struct log_backend *const backend);
70 	int (*is_ready)(const struct log_backend *const backend);
71 	int (*format_set)(const struct log_backend *const backend,
72 				uint32_t log_type);
73 
74 	void (*notify)(const struct log_backend *const backend,
75 		       enum log_backend_evt event,
76 		       union log_backend_evt_arg *arg);
77 };
78 
79 /**
80  * @brief Logger backend control block.
81  */
82 struct log_backend_control_block {
83 	void *ctx;
84 	uint8_t id;
85 	bool active;
86 	bool initialized;
87 
88 	/* Initialization level. */
89 	uint8_t level;
90 };
91 
92 /**
93  * @brief Logger backend structure.
94  */
95 struct log_backend {
96 	const struct log_backend_api *api;
97 	struct log_backend_control_block *cb;
98 	const char *name;
99 	bool autostart;
100 };
101 
102 /**
103  * @brief Macro for creating a logger backend instance.
104  *
105  * @param _name		Name of the backend instance.
106  * @param _api		Logger backend API.
107  * @param _autostart	If true backend is initialized and activated together
108  *			with the logger subsystem.
109  * @param ...		Optional context.
110  */
111 #define LOG_BACKEND_DEFINE(_name, _api, _autostart, ...)		       \
112 	static struct log_backend_control_block UTIL_CAT(backend_cb_, _name) = \
113 	{								       \
114 		COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__),	       \
115 				(), (.ctx = __VA_ARGS__,))		       \
116 		.id = 0,						       \
117 		.active = false,					       \
118 	};								       \
119 	static const STRUCT_SECTION_ITERABLE(log_backend, _name) =	       \
120 	{								       \
121 		.api = &_api,						       \
122 		.cb = &UTIL_CAT(backend_cb_, _name),			       \
123 		.name = STRINGIFY(_name),				       \
124 		.autostart = _autostart					       \
125 	}
126 
127 
128 /**
129  * @brief Initialize or initiate the logging backend.
130  *
131  * If backend initialization takes longer time it could block logging thread
132  * if backend is autostarted. That is because all backends are initialized in
133  * the context of the logging thread. In that case, backend shall provide
134  * function for polling for readiness (@ref log_backend_is_ready).
135  *
136  * @param[in] backend  Pointer to the backend instance.
137  */
log_backend_init(const struct log_backend * const backend)138 static inline void log_backend_init(const struct log_backend *const backend)
139 {
140 	__ASSERT_NO_MSG(backend != NULL);
141 	if (backend->api->init) {
142 		backend->api->init(backend);
143 	}
144 	backend->cb->initialized = true;
145 }
146 
147 /**
148  * @brief Poll for backend readiness.
149  *
150  * If backend is ready immediately after initialization then backend may not
151  * provide this function.
152  *
153  * @param[in] backend  Pointer to the backend instance.
154  *
155  * @retval 0 if backend is ready.
156  * @retval -EBUSY if backend is not yet ready.
157  */
log_backend_is_ready(const struct log_backend * const backend)158 static inline int log_backend_is_ready(const struct log_backend *const backend)
159 {
160 	__ASSERT_NO_MSG(backend != NULL);
161 	if (backend->api->is_ready != NULL) {
162 		return backend->api->is_ready(backend);
163 	}
164 
165 	return 0;
166 }
167 
168 /**
169  * @brief Process message.
170  *
171  * Function is used in deferred and immediate mode. On return, message content
172  * is processed by the backend and memory can be freed.
173  *
174  * @param[in] backend  Pointer to the backend instance.
175  * @param[in] msg      Pointer to message with log entry.
176  */
log_backend_msg_process(const struct log_backend * const backend,union log_msg_generic * msg)177 static inline void log_backend_msg_process(const struct log_backend *const backend,
178 					   union log_msg_generic *msg)
179 {
180 	__ASSERT_NO_MSG(backend != NULL);
181 	__ASSERT_NO_MSG(msg != NULL);
182 	backend->api->process(backend, msg);
183 }
184 
185 /**
186  * @brief Notify backend about dropped log messages.
187  *
188  * Function is optional.
189  *
190  * @param[in] backend  Pointer to the backend instance.
191  * @param[in] cnt      Number of dropped logs since last notification.
192  */
log_backend_dropped(const struct log_backend * const backend,uint32_t cnt)193 static inline void log_backend_dropped(const struct log_backend *const backend,
194 				       uint32_t cnt)
195 {
196 	__ASSERT_NO_MSG(backend != NULL);
197 
198 	if (backend->api->dropped != NULL) {
199 		backend->api->dropped(backend, cnt);
200 	}
201 }
202 
203 /**
204  * @brief Reconfigure backend to panic mode.
205  *
206  * @param[in] backend  Pointer to the backend instance.
207  */
log_backend_panic(const struct log_backend * const backend)208 static inline void log_backend_panic(const struct log_backend *const backend)
209 {
210 	__ASSERT_NO_MSG(backend != NULL);
211 	backend->api->panic(backend);
212 }
213 
214 /**
215  * @brief Set backend id.
216  *
217  * @note It is used internally by the logger.
218  *
219  * @param backend  Pointer to the backend instance.
220  * @param id       ID.
221  */
log_backend_id_set(const struct log_backend * const backend,uint8_t id)222 static inline void log_backend_id_set(const struct log_backend *const backend,
223 				      uint8_t id)
224 {
225 	__ASSERT_NO_MSG(backend != NULL);
226 	backend->cb->id = id;
227 }
228 
229 /**
230  * @brief Get backend id.
231  *
232  * @note It is used internally by the logger.
233  *
234  * @param[in] backend  Pointer to the backend instance.
235  * @return    Id.
236  */
log_backend_id_get(const struct log_backend * const backend)237 static inline uint8_t log_backend_id_get(const struct log_backend *const backend)
238 {
239 	__ASSERT_NO_MSG(backend != NULL);
240 	return backend->cb->id;
241 }
242 
243 /**
244  * @brief Get backend.
245  *
246  * @param[in] idx  Pointer to the backend instance.
247  *
248  * @return    Pointer to the backend instance.
249  */
log_backend_get(uint32_t idx)250 static inline const struct log_backend *log_backend_get(uint32_t idx)
251 {
252 	const struct log_backend *backend;
253 
254 	STRUCT_SECTION_GET(log_backend, idx, &backend);
255 
256 	return backend;
257 }
258 
259 /**
260  * @brief Get number of backends.
261  *
262  * @return Number of backends.
263  */
log_backend_count_get(void)264 static inline int log_backend_count_get(void)
265 {
266 	int cnt;
267 
268 	STRUCT_SECTION_COUNT(log_backend, &cnt);
269 
270 	return cnt;
271 }
272 
273 /**
274  * @brief Activate backend.
275  *
276  * @param[in] backend  Pointer to the backend instance.
277  * @param[in] ctx      User context.
278  */
log_backend_activate(const struct log_backend * const backend,void * ctx)279 static inline void log_backend_activate(const struct log_backend *const backend,
280 					void *ctx)
281 {
282 	__ASSERT_NO_MSG(backend != NULL);
283 	backend->cb->ctx = ctx;
284 	backend->cb->active = true;
285 }
286 
287 /**
288  * @brief Deactivate backend.
289  *
290  * @param[in] backend  Pointer to the backend instance.
291  */
log_backend_deactivate(const struct log_backend * const backend)292 static inline void log_backend_deactivate(
293 				const struct log_backend *const backend)
294 {
295 	__ASSERT_NO_MSG(backend != NULL);
296 	backend->cb->active = false;
297 }
298 
299 /**
300  * @brief Check state of the backend.
301  *
302  * @param[in] backend  Pointer to the backend instance.
303  *
304  * @return True if backend is active, false otherwise.
305  */
log_backend_is_active(const struct log_backend * const backend)306 static inline bool log_backend_is_active(
307 				const struct log_backend *const backend)
308 {
309 	__ASSERT_NO_MSG(backend != NULL);
310 	return backend->cb->active;
311 }
312 
313 /** @brief Set logging format.
314  *
315  * @param backend Pointer to the backend instance.
316  * @param log_type Log format.
317  *
318  * @retval -ENOTSUP If the backend does not support changing format types.
319  * @retval -EINVAL If the input is invalid.
320  * @retval 0 for success.
321  */
log_backend_format_set(const struct log_backend * backend,uint32_t log_type)322 static inline int log_backend_format_set(const struct log_backend *backend, uint32_t log_type)
323 {
324 	extern size_t log_format_table_size(void);
325 
326 	if ((size_t)log_type >= log_format_table_size()) {
327 		return -EINVAL;
328 	}
329 
330 	if (log_format_func_t_get(log_type) == NULL) {
331 		return -EINVAL;
332 	}
333 
334 	if (backend == NULL) {
335 		return -EINVAL;
336 	}
337 
338 	if (backend->api->format_set == NULL) {
339 		return -ENOTSUP;
340 	}
341 
342 	return backend->api->format_set(backend, log_type);
343 }
344 
345 /**
346  * @brief Notify a backend of an event.
347  *
348  * @param backend Pointer to the backend instance.
349  * @param event Event to be notified.
350  * @param arg Pointer to the argument(s).
351  */
log_backend_notify(const struct log_backend * const backend,enum log_backend_evt event,union log_backend_evt_arg * arg)352 static inline void log_backend_notify(const struct log_backend *const backend,
353 				      enum log_backend_evt event,
354 				      union log_backend_evt_arg *arg)
355 {
356 	__ASSERT_NO_MSG(backend != NULL);
357 
358 	if (backend->api->notify) {
359 		backend->api->notify(backend, event, arg);
360 	}
361 }
362 
363 /**
364  * @}
365  */
366 
367 #ifdef __cplusplus
368 }
369 #endif
370 
371 #endif /* ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_H_ */
372