1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #ifndef ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_
7 #define ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_
8
9 #include <sys/atomic.h>
10 #include <sys/util.h>
11 #include <string.h>
12 #include <logging/log_msg2.h>
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17
18 /**
19 * @brief Log message API
20 * @defgroup log_msg Log message API
21 * @ingroup logger
22 * @{
23 */
24
25 /** @brief Log argument type.
26 *
27 * Should preferably be equivalent to a native word size.
28 */
29 typedef unsigned long log_arg_t;
30
31 /** @brief Maximum number of arguments in the standard log entry.
32 *
33 * It is limited by 4 bit nargs field in the log message.
34 */
35 #define LOG_MAX_NARGS 15
36
37 /** @brief Number of arguments in the log entry which fits in one chunk.*/
38 #ifdef CONFIG_64BIT
39 #define LOG_MSG_NARGS_SINGLE_CHUNK 4U
40 #else
41 #define LOG_MSG_NARGS_SINGLE_CHUNK 3U
42 #endif
43
44 /** @brief Number of arguments in the head of extended standard log message..*/
45 #define LOG_MSG_NARGS_HEAD_CHUNK \
46 (LOG_MSG_NARGS_SINGLE_CHUNK - (sizeof(void *)/sizeof(log_arg_t)))
47
48 /** @brief Maximal amount of bytes in the hexdump entry which fits in one chunk.
49 */
50 #define LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK \
51 (LOG_MSG_NARGS_SINGLE_CHUNK * sizeof(log_arg_t))
52
53 /** @brief Number of bytes in the first chunk of hexdump message if message
54 * consists of more than one chunk.
55 */
56 #define LOG_MSG_HEXDUMP_BYTES_HEAD_CHUNK \
57 (LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK - sizeof(void *))
58
59 /** @brief Number of bytes that can be stored in chunks following head chunk
60 * in hexdump log message.
61 */
62 #define HEXDUMP_BYTES_CONT_MSG \
63 (sizeof(struct log_msg) - sizeof(void *))
64
65 #define ARGS_CONT_MSG (HEXDUMP_BYTES_CONT_MSG / sizeof(log_arg_t))
66
67 /** @brief Flag indicating standard log message. */
68 #define LOG_MSG_TYPE_STD 0U
69
70 /** @brief Flag indicating hexdump log message. */
71 #define LOG_MSG_TYPE_HEXDUMP 1
72
73 /** @brief Common part of log message header. */
74 #define COMMON_PARAM_HDR() \
75 uint16_t type : 1; \
76 uint16_t ext : 1
77
78 /** @brief Number of bits used for storing length of hexdump log message. */
79 #define LOG_MSG_HEXDUMP_LENGTH_BITS 14
80
81 /** @brief Maximum length of log hexdump message. */
82 #define LOG_MSG_HEXDUMP_MAX_LENGTH (BIT(LOG_MSG_HEXDUMP_LENGTH_BITS) - 1)
83
84 /** @brief Part of log message header identifying source and level. */
85 struct log_msg_ids {
86 uint16_t level : 3; /*!< Severity. */
87 uint16_t domain_id : 3; /*!< Originating domain. */
88 uint16_t source_id : 10; /*!< Source ID. */
89 };
90
91 /** Part of log message header common to standard and hexdump log message. */
92 struct log_msg_generic_hdr {
93 COMMON_PARAM_HDR();
94 uint16_t reserved : 14;
95 };
96
97 /** Part of log message header specific to standard log message. */
98 struct log_msg_std_hdr {
99 COMMON_PARAM_HDR();
100 uint16_t reserved : 10;
101 uint16_t nargs : 4;
102 };
103
104 /** Part of log message header specific to hexdump log message. */
105 struct log_msg_hexdump_hdr {
106 COMMON_PARAM_HDR();
107 uint16_t length : LOG_MSG_HEXDUMP_LENGTH_BITS;
108 };
109
110 /** Log message header structure */
111 struct log_msg_hdr {
112 atomic_t ref_cnt; /*!< Reference counter for tracking message users. */
113 union log_msg_hdr_params {
114 struct log_msg_generic_hdr generic;
115 struct log_msg_std_hdr std;
116 struct log_msg_hexdump_hdr hexdump;
117 uint16_t raw;
118 } params;
119 struct log_msg_ids ids; /*!< Identification part of the message.*/
120 uint32_t timestamp; /*!< Timestamp. */
121 };
122
123 /** @brief Data part of log message. */
124 union log_msg_head_data {
125 log_arg_t args[LOG_MSG_NARGS_SINGLE_CHUNK];
126 uint8_t bytes[LOG_MSG_HEXDUMP_BYTES_SINGLE_CHUNK];
127 };
128
129 /** @brief Data part of extended log message. */
130 struct log_msg_ext_head_data {
131 struct log_msg_cont *next;
132 union log_msg_ext_head_data_data {
133 log_arg_t args[LOG_MSG_NARGS_HEAD_CHUNK];
134 uint8_t bytes[LOG_MSG_HEXDUMP_BYTES_HEAD_CHUNK];
135 } data;
136 };
137
138 /** @brief Log message structure. */
139 struct log_msg {
140 struct log_msg *next; /*!< Used by logger core list.*/
141 struct log_msg_hdr hdr; /*!< Message header. */
142 const char *str;
143 union log_msg_data {
144 union log_msg_head_data single;
145 struct log_msg_ext_head_data ext;
146 } payload; /*!< Message data. */
147 };
148
149 /** @brief Chunks following message head when message is extended. */
150 struct log_msg_cont {
151 struct log_msg_cont *next; /*!< Pointer to the next chunk. */
152 union log_msg_cont_data {
153 log_arg_t args[ARGS_CONT_MSG];
154 uint8_t bytes[HEXDUMP_BYTES_CONT_MSG];
155 } payload;
156 };
157
158 /** @brief Log message */
159 union log_msg_chunk {
160 struct log_msg head;
161 struct log_msg_cont cont;
162 };
163
164 /** @brief Function for initialization of the log message pool. */
165 void log_msg_pool_init(void);
166
167 /** @brief Function for indicating that message is in use.
168 *
169 * @details Message can be used (read) by multiple users. Internal reference
170 * counter is atomically increased. See @ref log_msg_put.
171 *
172 * @param msg Message.
173 */
174 void log_msg_get(struct log_msg *msg);
175
176 /** @brief Function for indicating that message is no longer in use.
177 *
178 * @details Internal reference counter is atomically decreased. If reference
179 * counter equals 0 message is freed.
180 *
181 * @param msg Message.
182 */
183 void log_msg_put(struct log_msg *msg);
184
185 /** @brief Get domain ID of the message.
186 *
187 * @param msg Message
188 *
189 * @return Domain ID.
190 */
log_msg_domain_id_get(struct log_msg * msg)191 static inline uint32_t log_msg_domain_id_get(struct log_msg *msg)
192 {
193 return msg->hdr.ids.domain_id;
194 }
195
196 /** @brief Get source ID (module or instance) of the message.
197 *
198 * @param msg Message
199 *
200 * @return Source ID.
201 */
log_msg_source_id_get(struct log_msg * msg)202 static inline uint32_t log_msg_source_id_get(struct log_msg *msg)
203 {
204 return msg->hdr.ids.source_id;
205 }
206
207 /** @brief Get severity level of the message.
208 *
209 * @param msg Message
210 *
211 * @return Severity message.
212 */
log_msg_level_get(struct log_msg * msg)213 static inline uint32_t log_msg_level_get(struct log_msg *msg)
214 {
215 return msg->hdr.ids.level;
216 }
217
218 /** @brief Get timestamp of the message.
219 *
220 * @param msg Message
221 *
222 * @return Timestamp value.
223 */
log_msg_timestamp_get(struct log_msg * msg)224 static inline uint32_t log_msg_timestamp_get(struct log_msg *msg)
225 {
226 return msg->hdr.timestamp;
227 }
228
229 /** @brief Check if message is of standard type.
230 *
231 * @param msg Message
232 *
233 * @retval true Standard message.
234 * @retval false Hexdump message.
235 */
log_msg_is_std(struct log_msg * msg)236 static inline bool log_msg_is_std(struct log_msg *msg)
237 {
238 return (msg->hdr.params.generic.type == LOG_MSG_TYPE_STD);
239 }
240
241 /** @brief Returns number of arguments in standard log message.
242 *
243 * @param msg Standard log message.
244 *
245 * @return Number of arguments.
246 */
247 uint32_t log_msg_nargs_get(struct log_msg *msg);
248
249 /** @brief Gets argument from standard log message.
250 *
251 * @param msg Standard log message.
252 * @param arg_idx Argument index.
253 *
254 * @return Argument value or 0 if arg_idx exceeds number of arguments in the
255 * message.
256 */
257 log_arg_t log_msg_arg_get(struct log_msg *msg, uint32_t arg_idx);
258
259
260 /** @brief Gets pointer to the unformatted string from standard log message.
261 *
262 * @param msg Standard log message.
263 *
264 * @return Pointer to the string.
265 */
266 const char *log_msg_str_get(struct log_msg *msg);
267
268 /** @brief Allocates chunks for hexdump message and copies the data.
269 *
270 * @details Function resets header and sets following fields:
271 * - message type
272 * - length
273 *
274 * @note Allocation and partial filling is combined for performance reasons.
275 *
276 * @param str String.
277 * @param data Data.
278 * @param length Data length.
279 *
280 * @return Pointer to allocated head of the message or NULL
281 */
282 struct log_msg *log_msg_hexdump_create(const char *str,
283 const uint8_t *data,
284 uint32_t length);
285
286 /** @brief Put data into hexdump log message.
287 *
288 * @param[in] msg Message.
289 * @param[in] data Data to be copied.
290 * @param[in, out] length Input: requested amount. Output: actual amount.
291 * @param[in] offset Offset.
292 */
293 void log_msg_hexdump_data_put(struct log_msg *msg,
294 uint8_t *data,
295 size_t *length,
296 size_t offset);
297
298 /** @brief Get data from hexdump log message.
299 *
300 * @param[in] msg Message.
301 * @param[in] data Buffer for data.
302 * @param[in, out] length Input: requested amount. Output: actual amount.
303 * @param[in] offset Offset.
304 */
305 void log_msg_hexdump_data_get(struct log_msg *msg,
306 uint8_t *data,
307 size_t *length,
308 size_t offset);
309
310 union log_msg_chunk *log_msg_no_space_handle(void);
311
312 /** @brief Allocate single chunk from the pool.
313 *
314 * @return Pointer to the allocated chunk or NULL if failed to allocate.
315 */
316 union log_msg_chunk *log_msg_chunk_alloc(void);
317
318 /** @brief Allocate chunk for standard log message.
319 *
320 * @return Allocated chunk of NULL.
321 */
z_log_msg_std_alloc(void)322 static inline struct log_msg *z_log_msg_std_alloc(void)
323 {
324 struct log_msg *msg = (struct log_msg *)log_msg_chunk_alloc();
325
326 if (msg != NULL) {
327 /* all fields reset to 0, reference counter to 1 */
328 msg->hdr.ref_cnt = 1;
329 msg->hdr.params.raw = 0U;
330 msg->hdr.params.std.type = LOG_MSG_TYPE_STD;
331
332 if (IS_ENABLED(CONFIG_USERSPACE)) {
333 /* it may be used in msg_free() function. */
334 msg->hdr.ids.level = 0;
335 msg->hdr.ids.domain_id = 0;
336 msg->hdr.ids.source_id = 0;
337 }
338 }
339
340 return msg;
341 }
342
343 /** @brief Create standard log message with no arguments.
344 *
345 * @details Function resets header and sets following fields:
346 * - message type
347 * - string pointer
348 *
349 * @return Pointer to allocated head of the message or NULL.
350 */
log_msg_create_0(const char * str)351 static inline struct log_msg *log_msg_create_0(const char *str)
352 {
353 struct log_msg *msg = z_log_msg_std_alloc();
354
355 if (msg != NULL) {
356 msg->str = str;
357 }
358
359 return msg;
360 }
361
362 /** @brief Create standard log message with one argument.
363 *
364 * @details Function resets header and sets following fields:
365 * - message type
366 * - string pointer
367 * - number of arguments
368 * - argument
369 *
370 * @param str String.
371 * @param arg1 Argument.
372 *
373 * @return Pointer to allocated head of the message or NULL.
374 */
log_msg_create_1(const char * str,log_arg_t arg1)375 static inline struct log_msg *log_msg_create_1(const char *str,
376 log_arg_t arg1)
377 {
378 struct log_msg *msg = z_log_msg_std_alloc();
379
380 if (msg != NULL) {
381 msg->str = str;
382 msg->hdr.params.std.nargs = 1U;
383 msg->payload.single.args[0] = arg1;
384 }
385
386 return msg;
387 }
388
389 /** @brief Create standard log message with two arguments.
390 *
391 * @details Function resets header and sets following fields:
392 * - message type
393 * - string pointer
394 * - number of arguments
395 * - arguments
396 *
397 * @param str String.
398 * @param arg1 Argument 1.
399 * @param arg2 Argument 2.
400 *
401 * @return Pointer to allocated head of the message or NULL.
402 */
log_msg_create_2(const char * str,log_arg_t arg1,log_arg_t arg2)403 static inline struct log_msg *log_msg_create_2(const char *str,
404 log_arg_t arg1,
405 log_arg_t arg2)
406 {
407 struct log_msg *msg = z_log_msg_std_alloc();
408
409 if (msg != NULL) {
410 msg->str = str;
411 msg->hdr.params.std.nargs = 2U;
412 msg->payload.single.args[0] = arg1;
413 msg->payload.single.args[1] = arg2;
414 }
415
416 return msg;
417 }
418
419 /** @brief Create standard log message with three arguments.
420 *
421 * @details Function resets header and sets following fields:
422 * - message type
423 * - string pointer
424 * - number of arguments
425 * - arguments
426 *
427 * @param str String.
428 * @param arg1 Argument 1.
429 * @param arg2 Argument 2.
430 * @param arg3 Argument 3.
431 *
432 * @return Pointer to allocated head of the message or NULL.
433 */
log_msg_create_3(const char * str,log_arg_t arg1,log_arg_t arg2,log_arg_t arg3)434 static inline struct log_msg *log_msg_create_3(const char *str,
435 log_arg_t arg1,
436 log_arg_t arg2,
437 log_arg_t arg3)
438 {
439 struct log_msg *msg = z_log_msg_std_alloc();
440
441 if (msg != NULL) {
442 msg->str = str;
443 msg->hdr.params.std.nargs = 3U;
444 msg->payload.single.args[0] = arg1;
445 msg->payload.single.args[1] = arg2;
446 msg->payload.single.args[2] = arg3;
447 }
448
449 return msg;
450 }
451
452 /** @brief Create standard log message with variable number of arguments.
453 *
454 * @details Function resets header and sets following fields:
455 * - message type
456 * - string pointer
457 * - number of arguments
458 * - arguments
459 *
460 * @param str String.
461 * @param args Array with arguments.
462 * @param nargs Number of arguments.
463 *
464 * @return Pointer to allocated head of the message or NULL.
465 */
466 struct log_msg *log_msg_create_n(const char *str,
467 log_arg_t *args,
468 uint32_t nargs);
469
470 /**
471 * @brief Get number of free blocks from the log mem pool
472 */
473 uint32_t log_msg_mem_get_free(void);
474
475 /**
476 * @brief Get number of used blocks from the log mem pool
477 */
478 uint32_t log_msg_mem_get_used(void);
479
480 /**
481 * @brief Get max used blocks from the log mem pool
482 */
483 uint32_t log_msg_mem_get_max_used(void);
484
485
486 /**
487 * @}
488 */
489
490 #ifdef __cplusplus
491 }
492 #endif
493
494 #endif /* ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_ */
495