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 <logging/log_msg.h>
10 #include <logging/log_msg2.h>
11 #include <stdarg.h>
12 #include <sys/__assert.h>
13 #include <sys/util.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /**
20  * @brief Logger backend interface
21  * @defgroup log_backend Logger backend interface
22  * @ingroup logger
23  * @{
24  */
25 
26 /* Forward declaration of the log_backend type. */
27 struct log_backend;
28 
29 /**
30  * @brief Logger backend API.
31  */
32 struct log_backend_api {
33 	void (*process)(const struct log_backend *const backend,
34 			union log_msg2_generic *msg);
35 
36 	void (*put)(const struct log_backend *const backend,
37 		    struct log_msg *msg);
38 	void (*put_sync_string)(const struct log_backend *const backend,
39 			 struct log_msg_ids src_level, uint32_t timestamp,
40 			 const char *fmt, va_list ap);
41 	void (*put_sync_hexdump)(const struct log_backend *const backend,
42 			 struct log_msg_ids src_level, uint32_t timestamp,
43 			 const char *metadata, const uint8_t *data, uint32_t len);
44 
45 	void (*dropped)(const struct log_backend *const backend, uint32_t cnt);
46 	void (*panic)(const struct log_backend *const backend);
47 	void (*init)(const struct log_backend *const backend);
48 };
49 
50 /**
51  * @brief Logger backend control block.
52  */
53 struct log_backend_control_block {
54 	void *ctx;
55 	uint8_t id;
56 	bool active;
57 };
58 
59 /**
60  * @brief Logger backend structure.
61  */
62 struct log_backend {
63 	const struct log_backend_api *api;
64 	struct log_backend_control_block *cb;
65 	const char *name;
66 	bool autostart;
67 };
68 
69 extern const struct log_backend __log_backends_start[];
70 extern const struct log_backend __log_backends_end[];
71 
72 /**
73  * @brief Macro for creating a logger backend instance.
74  *
75  * @param _name		Name of the backend instance.
76  * @param _api		Logger backend API.
77  * @param _autostart	If true backend is initialized and activated together
78  *			with the logger subsystem.
79  * @param ...		Optional context.
80  */
81 #define LOG_BACKEND_DEFINE(_name, _api, _autostart, ...)		       \
82 	static struct log_backend_control_block UTIL_CAT(backend_cb_, _name) = \
83 	{								       \
84 		COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__),	       \
85 				(), (.ctx = __VA_ARGS__,))		       \
86 		.id = 0,						       \
87 		.active = false,					       \
88 	};								       \
89 	static const STRUCT_SECTION_ITERABLE(log_backend, _name) =	       \
90 	{								       \
91 		.api = &_api,						       \
92 		.cb = &UTIL_CAT(backend_cb_, _name),			       \
93 		.name = STRINGIFY(_name),				       \
94 		.autostart = _autostart					       \
95 	}
96 
97 
98 /**
99  * @brief Put message with log entry to the backend.
100  *
101  * @param[in] backend  Pointer to the backend instance.
102  * @param[in] msg      Pointer to message with log entry.
103  */
log_backend_put(const struct log_backend * const backend,struct log_msg * msg)104 static inline void log_backend_put(const struct log_backend *const backend,
105 				   struct log_msg *msg)
106 {
107 	__ASSERT_NO_MSG(backend != NULL);
108 	__ASSERT_NO_MSG(msg != NULL);
109 	backend->api->put(backend, msg);
110 }
111 
log_backend_msg2_process(const struct log_backend * const backend,union log_msg2_generic * msg)112 static inline void log_backend_msg2_process(
113 					const struct log_backend *const backend,
114 					union log_msg2_generic *msg)
115 {
116 	__ASSERT_NO_MSG(backend != NULL);
117 	__ASSERT_NO_MSG(msg != NULL);
118 	backend->api->process(backend, msg);
119 }
120 
121 
122 /**
123  * @brief Synchronously process log message.
124  *
125  * @param[in] backend   Pointer to the backend instance.
126  * @param[in] src_level Message details.
127  * @param[in] timestamp Timestamp.
128  * @param[in] fmt       Log string.
129  * @param[in] ap        Log string arguments.
130  */
log_backend_put_sync_string(const struct log_backend * const backend,struct log_msg_ids src_level,uint32_t timestamp,const char * fmt,va_list ap)131 static inline void log_backend_put_sync_string(
132 					const struct log_backend *const backend,
133 					struct log_msg_ids src_level,
134 					uint32_t timestamp, const char *fmt,
135 					va_list ap)
136 {
137 	__ASSERT_NO_MSG(backend != NULL);
138 
139 	if (backend->api->put_sync_string) {
140 		backend->api->put_sync_string(backend, src_level,
141 					      timestamp, fmt, ap);
142 	}
143 }
144 
145 /**
146  * @brief Synchronously process log hexdump_message.
147  *
148  * @param[in] backend   Pointer to the backend instance.
149  * @param[in] src_level Message details.
150  * @param[in] timestamp Timestamp.
151  * @param[in] metadata  Raw string associated with the data.
152  * @param[in] data      Data.
153  * @param[in] len       Data length.
154  */
log_backend_put_sync_hexdump(const struct log_backend * const backend,struct log_msg_ids src_level,uint32_t timestamp,const char * metadata,const uint8_t * data,uint32_t len)155 static inline void log_backend_put_sync_hexdump(
156 					const struct log_backend *const backend,
157 					struct log_msg_ids src_level,
158 					uint32_t timestamp, const char *metadata,
159 					const uint8_t *data, uint32_t len)
160 {
161 	__ASSERT_NO_MSG(backend != NULL);
162 
163 	if (backend->api->put_sync_hexdump) {
164 		backend->api->put_sync_hexdump(backend, src_level, timestamp,
165 					       metadata, data, len);
166 	}
167 }
168 
169 /**
170  * @brief Notify backend about dropped log messages.
171  *
172  * Function is optional.
173  *
174  * @param[in] backend  Pointer to the backend instance.
175  * @param[in] cnt      Number of dropped logs since last notification.
176  */
log_backend_dropped(const struct log_backend * const backend,uint32_t cnt)177 static inline void log_backend_dropped(const struct log_backend *const backend,
178 				       uint32_t cnt)
179 {
180 	__ASSERT_NO_MSG(backend != NULL);
181 
182 	if (backend->api->dropped != NULL) {
183 		backend->api->dropped(backend, cnt);
184 	}
185 }
186 
187 /**
188  * @brief Reconfigure backend to panic mode.
189  *
190  * @param[in] backend  Pointer to the backend instance.
191  */
log_backend_panic(const struct log_backend * const backend)192 static inline void log_backend_panic(const struct log_backend *const backend)
193 {
194 	__ASSERT_NO_MSG(backend != NULL);
195 	backend->api->panic(backend);
196 }
197 
198 /**
199  * @brief Set backend id.
200  *
201  * @note It is used internally by the logger.
202  *
203  * @param backend  Pointer to the backend instance.
204  * @param id       ID.
205  */
log_backend_id_set(const struct log_backend * const backend,uint8_t id)206 static inline void log_backend_id_set(const struct log_backend *const backend,
207 				      uint8_t id)
208 {
209 	__ASSERT_NO_MSG(backend != NULL);
210 	backend->cb->id = id;
211 }
212 
213 /**
214  * @brief Get backend id.
215  *
216  * @note It is used internally by the logger.
217  *
218  * @param[in] backend  Pointer to the backend instance.
219  * @return    Id.
220  */
log_backend_id_get(const struct log_backend * const backend)221 static inline uint8_t log_backend_id_get(const struct log_backend *const backend)
222 {
223 	__ASSERT_NO_MSG(backend != NULL);
224 	return backend->cb->id;
225 }
226 
227 /**
228  * @brief Get backend.
229  *
230  * @param[in] idx  Pointer to the backend instance.
231  *
232  * @return    Pointer to the backend instance.
233  */
log_backend_get(uint32_t idx)234 static inline const struct log_backend *log_backend_get(uint32_t idx)
235 {
236 	return &__log_backends_start[idx];
237 }
238 
239 /**
240  * @brief Get number of backends.
241  *
242  * @return Number of backends.
243  */
log_backend_count_get(void)244 static inline int log_backend_count_get(void)
245 {
246 	return __log_backends_end - __log_backends_start;
247 }
248 
249 /**
250  * @brief Activate backend.
251  *
252  * @param[in] backend  Pointer to the backend instance.
253  * @param[in] ctx      User context.
254  */
log_backend_activate(const struct log_backend * const backend,void * ctx)255 static inline void log_backend_activate(const struct log_backend *const backend,
256 					void *ctx)
257 {
258 	__ASSERT_NO_MSG(backend != NULL);
259 	backend->cb->ctx = ctx;
260 	backend->cb->active = true;
261 }
262 
263 /**
264  * @brief Deactivate backend.
265  *
266  * @param[in] backend  Pointer to the backend instance.
267  */
log_backend_deactivate(const struct log_backend * const backend)268 static inline void log_backend_deactivate(
269 				const struct log_backend *const backend)
270 {
271 	__ASSERT_NO_MSG(backend != NULL);
272 	backend->cb->active = false;
273 }
274 
275 /**
276  * @brief Check state of the backend.
277  *
278  * @param[in] backend  Pointer to the backend instance.
279  *
280  * @return True if backend is active, false otherwise.
281  */
log_backend_is_active(const struct log_backend * const backend)282 static inline bool log_backend_is_active(
283 				const struct log_backend *const backend)
284 {
285 	__ASSERT_NO_MSG(backend != NULL);
286 	return backend->cb->active;
287 }
288 
289 /**
290  * @}
291  */
292 
293 #ifdef __cplusplus
294 }
295 #endif
296 
297 #endif /* ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_H_ */
298