Line data Source code
1 0 : /*
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 1 : 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 1 : union log_backend_evt_arg {
56 : /** @brief Unspecified argument(s). */
57 1 : void *raw;
58 : };
59 :
60 : /**
61 : * @brief Logger backend API.
62 : */
63 1 : struct log_backend_api {
64 0 : void (*process)(const struct log_backend *const backend,
65 : union log_msg_generic *msg);
66 :
67 0 : void (*dropped)(const struct log_backend *const backend, uint32_t cnt);
68 0 : void (*panic)(const struct log_backend *const backend);
69 0 : void (*init)(const struct log_backend *const backend);
70 0 : int (*is_ready)(const struct log_backend *const backend);
71 0 : int (*format_set)(const struct log_backend *const backend,
72 : uint32_t log_type);
73 :
74 0 : 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 1 : struct log_backend_control_block {
83 0 : void *ctx;
84 0 : uint8_t id;
85 0 : bool active;
86 0 : bool initialized;
87 :
88 : /* Initialization level. */
89 0 : uint8_t level;
90 : };
91 :
92 : /**
93 : * @brief Logger backend structure.
94 : */
95 1 : struct log_backend {
96 0 : const struct log_backend_api *api;
97 0 : struct log_backend_control_block *cb;
98 0 : const char *name;
99 0 : 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 1 : #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 : */
138 1 : 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 : */
158 1 : 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 : */
177 1 : 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 : */
193 1 : 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 : */
208 1 : 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 : */
222 1 : 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 : */
237 1 : 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 : */
250 1 : 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 : */
264 1 : 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 : */
279 1 : 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 : */
292 1 : 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 : */
306 1 : 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 : */
322 1 : 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 : */
352 1 : 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_ */
|