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