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
87 /* Initialization level. */
88 uint8_t level;
89 };
90
91 /**
92 * @brief Logger backend structure.
93 */
94 struct log_backend {
95 const struct log_backend_api *api;
96 struct log_backend_control_block *cb;
97 const char *name;
98 bool autostart;
99 };
100
101 /**
102 * @brief Macro for creating a logger backend instance.
103 *
104 * @param _name Name of the backend instance.
105 * @param _api Logger backend API.
106 * @param _autostart If true backend is initialized and activated together
107 * with the logger subsystem.
108 * @param ... Optional context.
109 */
110 #define LOG_BACKEND_DEFINE(_name, _api, _autostart, ...) \
111 static struct log_backend_control_block UTIL_CAT(backend_cb_, _name) = \
112 { \
113 COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
114 (), (.ctx = __VA_ARGS__,)) \
115 .id = 0, \
116 .active = false, \
117 }; \
118 static const STRUCT_SECTION_ITERABLE(log_backend, _name) = \
119 { \
120 .api = &_api, \
121 .cb = &UTIL_CAT(backend_cb_, _name), \
122 .name = STRINGIFY(_name), \
123 .autostart = _autostart \
124 }
125
126
127 /**
128 * @brief Initialize or initiate the logging backend.
129 *
130 * If backend initialization takes longer time it could block logging thread
131 * if backend is autostarted. That is because all backends are initilized in
132 * the context of the logging thread. In that case, backend shall provide
133 * function for polling for readiness (@ref log_backend_is_ready).
134 *
135 * @param[in] backend Pointer to the backend instance.
136 */
log_backend_init(const struct log_backend * const backend)137 static inline void log_backend_init(const struct log_backend *const backend)
138 {
139 __ASSERT_NO_MSG(backend != NULL);
140 if (backend->api->init) {
141 backend->api->init(backend);
142 }
143 }
144
145 /**
146 * @brief Poll for backend readiness.
147 *
148 * If backend is ready immediately after initialization then backend may not
149 * provide this function.
150 *
151 * @param[in] backend Pointer to the backend instance.
152 *
153 * @retval 0 if backend is ready.
154 * @retval -EBUSY if backend is not yet ready.
155 */
log_backend_is_ready(const struct log_backend * const backend)156 static inline int log_backend_is_ready(const struct log_backend *const backend)
157 {
158 __ASSERT_NO_MSG(backend != NULL);
159 if (backend->api->is_ready != NULL) {
160 return backend->api->is_ready(backend);
161 }
162
163 return 0;
164 }
165
166 /**
167 * @brief Process message.
168 *
169 * Function is used in deferred and immediate mode. On return, message content
170 * is processed by the backend and memory can be freed.
171 *
172 * @param[in] backend Pointer to the backend instance.
173 * @param[in] msg Pointer to message with log entry.
174 */
log_backend_msg_process(const struct log_backend * const backend,union log_msg_generic * msg)175 static inline void log_backend_msg_process(const struct log_backend *const backend,
176 union log_msg_generic *msg)
177 {
178 __ASSERT_NO_MSG(backend != NULL);
179 __ASSERT_NO_MSG(msg != NULL);
180 backend->api->process(backend, msg);
181 }
182
183 /**
184 * @brief Notify backend about dropped log messages.
185 *
186 * Function is optional.
187 *
188 * @param[in] backend Pointer to the backend instance.
189 * @param[in] cnt Number of dropped logs since last notification.
190 */
log_backend_dropped(const struct log_backend * const backend,uint32_t cnt)191 static inline void log_backend_dropped(const struct log_backend *const backend,
192 uint32_t cnt)
193 {
194 __ASSERT_NO_MSG(backend != NULL);
195
196 if (backend->api->dropped != NULL) {
197 backend->api->dropped(backend, cnt);
198 }
199 }
200
201 /**
202 * @brief Reconfigure backend to panic mode.
203 *
204 * @param[in] backend Pointer to the backend instance.
205 */
log_backend_panic(const struct log_backend * const backend)206 static inline void log_backend_panic(const struct log_backend *const backend)
207 {
208 __ASSERT_NO_MSG(backend != NULL);
209 backend->api->panic(backend);
210 }
211
212 /**
213 * @brief Set backend id.
214 *
215 * @note It is used internally by the logger.
216 *
217 * @param backend Pointer to the backend instance.
218 * @param id ID.
219 */
log_backend_id_set(const struct log_backend * const backend,uint8_t id)220 static inline void log_backend_id_set(const struct log_backend *const backend,
221 uint8_t id)
222 {
223 __ASSERT_NO_MSG(backend != NULL);
224 backend->cb->id = id;
225 }
226
227 /**
228 * @brief Get backend id.
229 *
230 * @note It is used internally by the logger.
231 *
232 * @param[in] backend Pointer to the backend instance.
233 * @return Id.
234 */
log_backend_id_get(const struct log_backend * const backend)235 static inline uint8_t log_backend_id_get(const struct log_backend *const backend)
236 {
237 __ASSERT_NO_MSG(backend != NULL);
238 return backend->cb->id;
239 }
240
241 /**
242 * @brief Get backend.
243 *
244 * @param[in] idx Pointer to the backend instance.
245 *
246 * @return Pointer to the backend instance.
247 */
log_backend_get(uint32_t idx)248 static inline const struct log_backend *log_backend_get(uint32_t idx)
249 {
250 const struct log_backend *backend;
251
252 STRUCT_SECTION_GET(log_backend, idx, &backend);
253
254 return backend;
255 }
256
257 /**
258 * @brief Get number of backends.
259 *
260 * @return Number of backends.
261 */
log_backend_count_get(void)262 static inline int log_backend_count_get(void)
263 {
264 int cnt;
265
266 STRUCT_SECTION_COUNT(log_backend, &cnt);
267
268 return cnt;
269 }
270
271 /**
272 * @brief Activate backend.
273 *
274 * @param[in] backend Pointer to the backend instance.
275 * @param[in] ctx User context.
276 */
log_backend_activate(const struct log_backend * const backend,void * ctx)277 static inline void log_backend_activate(const struct log_backend *const backend,
278 void *ctx)
279 {
280 __ASSERT_NO_MSG(backend != NULL);
281 backend->cb->ctx = ctx;
282 backend->cb->active = true;
283 }
284
285 /**
286 * @brief Deactivate backend.
287 *
288 * @param[in] backend Pointer to the backend instance.
289 */
log_backend_deactivate(const struct log_backend * const backend)290 static inline void log_backend_deactivate(
291 const struct log_backend *const backend)
292 {
293 __ASSERT_NO_MSG(backend != NULL);
294 backend->cb->active = false;
295 }
296
297 /**
298 * @brief Check state of the backend.
299 *
300 * @param[in] backend Pointer to the backend instance.
301 *
302 * @return True if backend is active, false otherwise.
303 */
log_backend_is_active(const struct log_backend * const backend)304 static inline bool log_backend_is_active(
305 const struct log_backend *const backend)
306 {
307 __ASSERT_NO_MSG(backend != NULL);
308 return backend->cb->active;
309 }
310
311 /** @brief Set logging format.
312 *
313 * @param backend Pointer to the backend instance.
314 * @param log_type Log format.
315 *
316 * @retval -ENOTSUP If the backend does not support changing format types.
317 * @retval -EINVAL If the input is invalid.
318 * @retval 0 for success.
319 */
log_backend_format_set(const struct log_backend * backend,uint32_t log_type)320 static inline int log_backend_format_set(const struct log_backend *backend, uint32_t log_type)
321 {
322 extern size_t log_format_table_size(void);
323
324 if ((size_t)log_type >= log_format_table_size()) {
325 return -EINVAL;
326 }
327
328 if (log_format_func_t_get(log_type) == NULL) {
329 return -EINVAL;
330 }
331
332 if (backend == NULL) {
333 return -EINVAL;
334 }
335
336 if (backend->api->format_set == NULL) {
337 return -ENOTSUP;
338 }
339
340 return backend->api->format_set(backend, log_type);
341 }
342
343 /**
344 * @brief Notify a backend of an event.
345 *
346 * @param backend Pointer to the backend instance.
347 * @param event Event to be notified.
348 * @param arg Pointer to the argument(s).
349 */
log_backend_notify(const struct log_backend * const backend,enum log_backend_evt event,union log_backend_evt_arg * arg)350 static inline void log_backend_notify(const struct log_backend *const backend,
351 enum log_backend_evt event,
352 union log_backend_evt_arg *arg)
353 {
354 __ASSERT_NO_MSG(backend != NULL);
355
356 if (backend->api->notify) {
357 backend->api->notify(backend, event, arg);
358 }
359 }
360
361 /**
362 * @}
363 */
364
365 #ifdef __cplusplus
366 }
367 #endif
368
369 #endif /* ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_H_ */
370