Zephyr Project API  3.3.0
A Scalable Open Source RTOS
log_msg.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021 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
11#include <zephyr/sys/cbprintf.h>
12#include <zephyr/sys/atomic.h>
13#include <zephyr/sys/util.h>
14#include <string.h>
15#include <zephyr/toolchain.h>
16
17#ifdef __GNUC__
18#ifndef alloca
19#define alloca __builtin_alloca
20#endif
21#else
22#include <alloca.h>
23#endif
24
25#ifdef __cplusplus
26extern "C" {
27#endif
28
29#define LOG_MSG2_DEBUG 0
30#define LOG_MSG2_DBG(...) IF_ENABLED(LOG_MSG2_DEBUG, (printk(__VA_ARGS__)))
31
32#ifdef CONFIG_LOG_TIMESTAMP_64BIT
34#else
36#endif
37
45#define Z_LOG_MSG2_LOG 0
46
47#define LOG_MSG2_GENERIC_HDR \
48 MPSC_PBUF_HDR;\
49 uint32_t type:1
50
58};
59
63 void *raw;
64};
65
68/* Attempting to keep best alignment. When address is 64 bit and timestamp 32
69 * swap the order to have 16 byte header instead of 24 byte.
70 */
71#if (INTPTR_MAX > INT32_MAX) && !CONFIG_LOG_TIMESTAMP_64BIT
73 const void *source;
74#else
75 const void *source;
77#endif
78};
79
80/* Messages are aligned to alignment required by cbprintf package. */
81#define Z_LOG_MSG2_ALIGNMENT CBPRINTF_PACKAGE_ALIGNMENT
82
83#define Z_LOG_MSG2_PADDING \
84 ((sizeof(struct log_msg_hdr) % Z_LOG_MSG2_ALIGNMENT) > 0 ? \
85 (Z_LOG_MSG2_ALIGNMENT - (sizeof(struct log_msg_hdr) % Z_LOG_MSG2_ALIGNMENT)) : \
86 0)
87
88struct log_msg {
90 /* Adding padding to ensure that cbprintf package that follows is
91 * properly aligned.
92 */
93 uint8_t padding[Z_LOG_MSG2_PADDING];
95};
96
100BUILD_ASSERT(sizeof(struct log_msg) % Z_LOG_MSG2_ALIGNMENT == 0,
101 "Log msg size must aligned");
109};
110
114 struct log_msg log;
115};
116
121enum z_log_msg_mode {
122 /* Runtime mode is least efficient but supports all cases thus it is
123 * treated as a fallback method when others cannot be used.
124 */
125 Z_LOG_MSG2_MODE_RUNTIME,
126 /* Mode creates statically a string package on stack and calls a
127 * function for creating a message. It takes code size than
128 * Z_LOG_MSG2_MODE_ZERO_COPY but is a bit slower.
129 */
130 Z_LOG_MSG2_MODE_FROM_STACK,
131
132 /* Mode calculates size of the message and allocates it and writes
133 * directly to the message space. It is the fastest method but requires
134 * more code size.
135 */
136 Z_LOG_MSG2_MODE_ZERO_COPY,
137};
138
139#define Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, _plen, _dlen) \
140{ \
141 .valid = 0, \
142 .busy = 0, \
143 .type = Z_LOG_MSG2_LOG, \
144 .domain = _domain_id, \
145 .level = _level, \
146 .package_len = _plen, \
147 .data_len = _dlen, \
148 .reserved = 0, \
149}
150
151#define Z_LOG_MSG2_CBPRINTF_FLAGS(_cstr_cnt) \
152 (CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(_cstr_cnt) | \
153 (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? \
154 CBPRINTF_PACKAGE_ADD_STRING_IDXS : 0))
155
156#ifdef CONFIG_LOG_USE_VLA
157#define Z_LOG_MSG2_ON_STACK_ALLOC(ptr, len) \
158 long long _ll_buf[ceiling_fraction(len, sizeof(long long))]; \
159 long double _ld_buf[ceiling_fraction(len, sizeof(long double))]; \
160 ptr = (sizeof(long double) == Z_LOG_MSG2_ALIGNMENT) ? \
161 (struct log_msg *)_ld_buf : (struct log_msg *)_ll_buf; \
162 if (IS_ENABLED(CONFIG_LOG_TEST_CLEAR_MESSAGE_SPACE)) { \
163 /* During test fill with 0's to simplify message comparison */ \
164 memset(ptr, 0, len); \
165 }
166#else /* Z_LOG_MSG2_USE_VLA */
167/* When VLA cannot be used we need to trick compiler a bit and create multiple
168 * fixed size arrays and take the smallest one that will fit the message.
169 * Compiler will remove unused arrays and stack usage will be kept similar
170 * to vla case, rounded to the size of the used buffer.
171 */
172#define Z_LOG_MSG2_ON_STACK_ALLOC(ptr, len) \
173 long long _ll_buf32[32 / sizeof(long long)]; \
174 long long _ll_buf48[48 / sizeof(long long)]; \
175 long long _ll_buf64[64 / sizeof(long long)]; \
176 long long _ll_buf128[128 / sizeof(long long)]; \
177 long long _ll_buf256[256 / sizeof(long long)]; \
178 long double _ld_buf32[32 / sizeof(long double)]; \
179 long double _ld_buf48[48 / sizeof(long double)]; \
180 long double _ld_buf64[64 / sizeof(long double)]; \
181 long double _ld_buf128[128 / sizeof(long double)]; \
182 long double _ld_buf256[256 / sizeof(long double)]; \
183 if (sizeof(long double) == Z_LOG_MSG2_ALIGNMENT) { \
184 ptr = (len > 128) ? (struct log_msg *)_ld_buf256 : \
185 ((len > 64) ? (struct log_msg *)_ld_buf128 : \
186 ((len > 48) ? (struct log_msg *)_ld_buf64 : \
187 ((len > 32) ? (struct log_msg *)_ld_buf48 : \
188 (struct log_msg *)_ld_buf32)));\
189 } else { \
190 ptr = (len > 128) ? (struct log_msg *)_ll_buf256 : \
191 ((len > 64) ? (struct log_msg *)_ll_buf128 : \
192 ((len > 48) ? (struct log_msg *)_ll_buf64 : \
193 ((len > 32) ? (struct log_msg *)_ll_buf48 : \
194 (struct log_msg *)_ll_buf32)));\
195 } \
196 if (IS_ENABLED(CONFIG_LOG_TEST_CLEAR_MESSAGE_SPACE)) { \
197 /* During test fill with 0's to simplify message comparison */ \
198 memset(ptr, 0, len); \
199 }
200#endif /* Z_LOG_MSG2_USE_VLA */
201
202#define Z_LOG_MSG2_ALIGN_OFFSET \
203 offsetof(struct log_msg, data)
204
205#define Z_LOG_MSG2_LEN(pkg_len, data_len) \
206 (offsetof(struct log_msg, data) + pkg_len + (data_len))
207
208#define Z_LOG_MSG2_ALIGNED_WLEN(pkg_len, data_len) \
209 ceiling_fraction(ROUND_UP(Z_LOG_MSG2_LEN(pkg_len, data_len), \
210 Z_LOG_MSG2_ALIGNMENT), \
211 sizeof(uint32_t))
212
213/*
214 * With Zephyr SDK 0.14.2, aarch64-zephyr-elf-gcc (10.3.0) fails to ensure $sp
215 * is below the active memory during message construction. As a result,
216 * interrupts happening in the middle of that process can end up smashing active
217 * data and causing a logging fault. Work around this by inserting a compiler
218 * barrier after the allocation and before any use to make sure GCC moves the
219 * stack pointer soon enough
220 */
221
222#define Z_LOG_ARM64_VLA_PROTECT() compiler_barrier()
223
224#define Z_LOG_MSG2_STACK_CREATE(_cstr_cnt, _domain_id, _source, _level, _data, _dlen, ...) \
225do { \
226 int _plen; \
227 uint32_t flags = Z_LOG_MSG2_CBPRINTF_FLAGS(_cstr_cnt) | \
228 CBPRINTF_PACKAGE_ADD_RW_STR_POS; \
229 if (GET_ARG_N(1, __VA_ARGS__) == NULL) { \
230 _plen = 0; \
231 } else { \
232 CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG2_ALIGN_OFFSET, flags, \
233 __VA_ARGS__); \
234 } \
235 struct log_msg *_msg; \
236 Z_LOG_MSG2_ON_STACK_ALLOC(_msg, Z_LOG_MSG2_LEN(_plen, 0)); \
237 Z_LOG_ARM64_VLA_PROTECT(); \
238 if (_plen != 0) { \
239 CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, \
240 _plen, Z_LOG_MSG2_ALIGN_OFFSET, flags, \
241 __VA_ARGS__);\
242 } \
243 struct log_msg_desc _desc = \
244 Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, \
245 (uint32_t)_plen, _dlen); \
246 LOG_MSG2_DBG("creating message on stack: package len: %d, data len: %d\n", \
247 _plen, (int)(_dlen)); \
248 z_log_msg_static_create((void *)_source, _desc, _msg->data, _data); \
249} while (false)
250
251#ifdef CONFIG_LOG_SPEED
252#define Z_LOG_MSG2_SIMPLE_CREATE(_cstr_cnt, _domain_id, _source, _level, ...) do { \
253 int _plen; \
254 CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG2_ALIGN_OFFSET, \
255 Z_LOG_MSG2_CBPRINTF_FLAGS(_cstr_cnt), \
256 __VA_ARGS__); \
257 size_t _msg_wlen = Z_LOG_MSG2_ALIGNED_WLEN(_plen, 0); \
258 struct log_msg *_msg = z_log_msg_alloc(_msg_wlen); \
259 struct log_msg_desc _desc = \
260 Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, (uint32_t)_plen, 0); \
261 LOG_MSG2_DBG("creating message zero copy: package len: %d, msg: %p\n", \
262 _plen, _msg); \
263 if (_msg) { \
264 CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, _plen, \
265 Z_LOG_MSG2_ALIGN_OFFSET, \
266 Z_LOG_MSG2_CBPRINTF_FLAGS(_cstr_cnt), \
267 __VA_ARGS__); \
268 } \
269 z_log_msg_finalize(_msg, (void *)_source, _desc, NULL); \
270} while (false)
271#else
272/* Alternative empty macro created to speed up compilation when LOG_SPEED is
273 * disabled (default).
274 */
275#define Z_LOG_MSG2_SIMPLE_CREATE(...)
276#endif
277
278/* Macro handles case when local variable with log message string is created. It
279 * replaces original string literal with that variable.
280 */
281#define Z_LOG_FMT_ARGS_2(_name, ...) \
282 COND_CODE_1(CONFIG_LOG_FMT_SECTION, \
283 (COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \
284 (_name), (_name, GET_ARGS_LESS_N(1, __VA_ARGS__)))), \
285 (__VA_ARGS__))
286
296#define Z_LOG_FMT_ARGS(_name, ...) \
297 COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
298 (NULL), \
299 (Z_LOG_FMT_ARGS_2(_name, ##__VA_ARGS__)))
300
301#if defined(CONFIG_LOG_USE_TAGGED_ARGUMENTS)
302
303#define Z_LOG_FMT_TAGGED_ARGS_2(_name, ...) \
304 COND_CODE_1(CONFIG_LOG_FMT_SECTION, \
305 (_name, Z_CBPRINTF_TAGGED_ARGS(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \
306 GET_ARGS_LESS_N(1, __VA_ARGS__))), \
307 (GET_ARG_N(1, __VA_ARGS__), \
308 Z_CBPRINTF_TAGGED_ARGS(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \
309 GET_ARGS_LESS_N(1, __VA_ARGS__))))
310
321#define Z_LOG_FMT_TAGGED_ARGS(_name, ...) \
322 COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
323 (Z_CBPRINTF_TAGGED_ARGS(0)), \
324 (Z_LOG_FMT_TAGGED_ARGS_2(_name, ##__VA_ARGS__)))
325
326#define Z_LOG_FMT_RUNTIME_ARGS(...) \
327 Z_LOG_FMT_TAGGED_ARGS(__VA_ARGS__)
328
329#else
330
331#define Z_LOG_FMT_RUNTIME_ARGS(...) \
332 Z_LOG_FMT_ARGS(__VA_ARGS__)
333
334#endif /* CONFIG_LOG_USE_TAGGED_ARGUMENTS */
335
336/* Macro handles case when there is no string provided, in that case variable
337 * is not created.
338 */
339#define Z_LOG_MSG2_STR_VAR_IN_SECTION(_name, ...) \
340 COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
341 (/* No args provided, no variable */), \
342 (static const char _name[] \
343 __attribute__((__section__(".log_strings"))) = \
344 GET_ARG_N(1, __VA_ARGS__);))
345
353#define Z_LOG_MSG2_STR_VAR(_name, ...) \
354 IF_ENABLED(CONFIG_LOG_FMT_SECTION, \
355 (Z_LOG_MSG2_STR_VAR_IN_SECTION(_name, ##__VA_ARGS__)))
356
396#if defined(CONFIG_LOG_ALWAYS_RUNTIME) || \
397 (!defined(CONFIG_LOG) && \
398 (!TOOLCHAIN_HAS_PRAGMA_DIAG || !TOOLCHAIN_HAS_C_AUTO_TYPE))
399#define Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
400 _level, _data, _dlen, ...) \
401do {\
402 Z_LOG_MSG2_STR_VAR(_fmt, ##__VA_ARGS__) \
403 z_log_msg_runtime_create(_domain_id, (void *)_source, \
404 _level, (uint8_t *)_data, _dlen,\
405 Z_LOG_MSG2_CBPRINTF_FLAGS(_cstr_cnt) | \
406 (IS_ENABLED(CONFIG_LOG_USE_TAGGED_ARGUMENTS) ? \
407 CBPRINTF_PACKAGE_ARGS_ARE_TAGGED : 0), \
408 Z_LOG_FMT_RUNTIME_ARGS(_fmt, ##__VA_ARGS__));\
409 _mode = Z_LOG_MSG2_MODE_RUNTIME; \
410} while (false)
411#else /* CONFIG_LOG_ALWAYS_RUNTIME */
412#define Z_LOG_MSG2_CREATE3(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
413 _level, _data, _dlen, ...) \
414do { \
415 Z_LOG_MSG2_STR_VAR(_fmt, ##__VA_ARGS__); \
416 bool has_rw_str = CBPRINTF_MUST_RUNTIME_PACKAGE( \
417 Z_LOG_MSG2_CBPRINTF_FLAGS(_cstr_cnt), \
418 __VA_ARGS__); \
419 if (IS_ENABLED(CONFIG_LOG_SPEED) && _try_0cpy && ((_dlen) == 0) && !has_rw_str) {\
420 LOG_MSG2_DBG("create zero-copy message\n");\
421 Z_LOG_MSG2_SIMPLE_CREATE(_cstr_cnt, _domain_id, _source, \
422 _level, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \
423 _mode = Z_LOG_MSG2_MODE_ZERO_COPY; \
424 } else { \
425 LOG_MSG2_DBG("create on stack message\n");\
426 Z_LOG_MSG2_STACK_CREATE(_cstr_cnt, _domain_id, _source, _level, _data, \
427 _dlen, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \
428 _mode = Z_LOG_MSG2_MODE_FROM_STACK; \
429 } \
430 (void)_mode; \
431} while (false)
432
433#if defined(__cplusplus)
434#define Z_AUTO_TYPE auto
435#else
436#define Z_AUTO_TYPE __auto_type
437#endif
438
439/* Macro for getting name of a local variable with the exception of the first argument
440 * which is a formatted string in log message.
441 */
442#define Z_LOG_LOCAL_ARG_NAME(idx, arg) COND_CODE_0(idx, (arg), (_v##idx))
443
444/* Create local variable from input variable (expect for the first (fmt) argument). */
445#define Z_LOG_LOCAL_ARG_CREATE(idx, arg) \
446 COND_CODE_0(idx, (), (Z_AUTO_TYPE Z_LOG_LOCAL_ARG_NAME(idx, arg) = (arg) + 0))
447
448/* First level of processing creates stack variables to be passed for further processing.
449 * This is done to prevent multiple evaluations of input arguments (in case argument
450 * evaluation has side effects, e.g. it is a non-pure function call).
451 */
452#define Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source, \
453 _level, _data, _dlen, ...) \
454do { \
455 _Pragma("GCC diagnostic push") \
456 _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") \
457 FOR_EACH_IDX(Z_LOG_LOCAL_ARG_CREATE, (;), __VA_ARGS__); \
458 _Pragma("GCC diagnostic pop") \
459 Z_LOG_MSG2_CREATE3(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
460 _level, _data, _dlen, \
461 FOR_EACH_IDX(Z_LOG_LOCAL_ARG_NAME, (,), __VA_ARGS__)); \
462} while (false)
463#endif /* CONFIG_LOG_ALWAYS_RUNTIME ||
464 * (!LOG && (!TOOLCHAIN_HAS_PRAGMA_DIAG || !TOOLCHAIN_HAS_C_AUTO_TYPE))
465 */
466
467
468#define Z_LOG_MSG2_CREATE(_try_0cpy, _mode, _domain_id, _source,\
469 _level, _data, _dlen, ...) \
470 Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, UTIL_CAT(Z_LOG_FUNC_PREFIX_, _level), \
471 _domain_id, _source, _level, _data, _dlen, \
472 Z_LOG_STR(_level, __VA_ARGS__))
473
480struct log_msg *z_log_msg_alloc(uint32_t wlen);
481
495void z_log_msg_finalize(struct log_msg *msg, const void *source,
496 const struct log_msg_desc desc, const void *data);
497
508__syscall void z_log_msg_static_create(const void *source,
509 const struct log_msg_desc desc,
510 uint8_t *package, const void *data);
511
533__syscall void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source,
534 uint8_t level, const void *data,
535 size_t dlen, uint32_t package_flags,
536 const char *fmt,
537 va_list ap);
538
560static inline void z_log_msg_runtime_create(uint8_t domain_id,
561 const void *source,
562 uint8_t level, const void *data,
563 size_t dlen, uint32_t package_flags,
564 const char *fmt, ...)
565{
566 va_list ap;
567
568 va_start(ap, fmt);
569 z_log_msg_runtime_vcreate(domain_id, source, level,
570 data, dlen, package_flags, fmt, ap);
571 va_end(ap);
572}
573
574static inline bool z_log_item_is_msg(const union log_msg_generic *msg)
575{
576 return msg->generic.type == Z_LOG_MSG2_LOG;
577}
578
585static inline uint32_t log_msg_get_total_wlen(const struct log_msg_desc desc)
586{
587 return Z_LOG_MSG2_ALIGNED_WLEN(desc.package_len, desc.data_len);
588}
589
597{
598 const union log_msg_generic *generic_msg = (const union log_msg_generic *)item;
599
600 if (z_log_item_is_msg(generic_msg)) {
601 const struct log_msg *msg = (const struct log_msg *)generic_msg;
602
603 return log_msg_get_total_wlen(msg->hdr.desc);
604 }
605
606 return 0;
607}
608
615static inline uint8_t log_msg_get_domain(struct log_msg *msg)
616{
617 return msg->hdr.desc.domain;
618}
619
626static inline uint8_t log_msg_get_level(struct log_msg *msg)
627{
628 return msg->hdr.desc.level;
629}
630
637static inline const void *log_msg_get_source(struct log_msg *msg)
638{
639 return msg->hdr.source;
640}
641
649{
650 return msg->hdr.timestamp;
651}
652
661static inline uint8_t *log_msg_get_data(struct log_msg *msg, size_t *len)
662{
663 *len = msg->hdr.desc.data_len;
664
665 return msg->data + msg->hdr.desc.package_len;
666}
667
676static inline uint8_t *log_msg_get_package(struct log_msg *msg, size_t *len)
677{
678 *len = msg->hdr.desc.package_len;
679
680 return msg->data;
681}
682
687#include <syscalls/log_msg.h>
688
689#ifdef __cplusplus
690}
691#endif
692
693#endif /* ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_ */
static const void * log_msg_get_source(struct log_msg *msg)
Get message source data.
Definition: log_msg.h:637
#define LOG_MSG2_GENERIC_HDR
Definition: log_msg.h:47
static uint8_t log_msg_get_level(struct log_msg *msg)
Get log message level.
Definition: log_msg.h:626
static uint8_t log_msg_get_domain(struct log_msg *msg)
Get log message domain ID.
Definition: log_msg.h:615
static uint32_t log_msg_generic_get_wlen(const union mpsc_pbuf_generic *item)
Get length of the log item.
Definition: log_msg.h:596
static uint32_t log_msg_get_total_wlen(const struct log_msg_desc desc)
Get total length (in 32 bit words) of a log message.
Definition: log_msg.h:585
static uint8_t * log_msg_get_package(struct log_msg *msg, size_t *len)
Get string package.
Definition: log_msg.h:676
static log_timestamp_t log_msg_get_timestamp(struct log_msg *msg)
Get timestamp.
Definition: log_msg.h:648
static uint8_t * log_msg_get_data(struct log_msg *msg, size_t *len)
Get data buffer.
Definition: log_msg.h:661
uint32_t log_timestamp_t
Definition: log_msg.h:35
__UINT32_TYPE__ uint32_t
Definition: stdint.h:90
__UINT64_TYPE__ uint64_t
Definition: stdint.h:91
__UINT8_TYPE__ uint8_t
Definition: stdint.h:88
Definition: log_msg.h:51
uint32_t domain
Definition: log_msg.h:53
uint32_t package_len
Definition: log_msg.h:55
uint32_t level
Definition: log_msg.h:54
uint32_t reserved
Definition: log_msg.h:57
uint32_t data_len
Definition: log_msg.h:56
Definition: log_msg.h:107
Definition: log_msg.h:66
struct log_msg_desc desc
Definition: log_msg.h:67
log_timestamp_t timestamp
Definition: log_msg.h:76
const void * source
Definition: log_msg.h:75
Definition: log_msg.h:88
uint8_t data[]
Definition: log_msg.h:94
uint8_t padding[((sizeof(struct log_msg_hdr) % CBPRINTF_PACKAGE_ALIGNMENT) > 0 ?(CBPRINTF_PACKAGE_ALIGNMENT -(sizeof(struct log_msg_hdr) % CBPRINTF_PACKAGE_ALIGNMENT)) :0)]
Definition: log_msg.h:93
struct log_msg_hdr hdr
Definition: log_msg.h:89
Constant data associated with the source of log messages.
Definition: log_instance.h:16
Dynamic data associated with the source of log messages.
Definition: log_instance.h:29
static fdata_t data[2]
Definition: test_fifo_contexts.c:15
static void msg(uint64_t c64)
Definition: main.c:17
Macros to abstract toolchain specific capabilities.
Definition: log_msg.h:111
union mpsc_pbuf_generic buf
Definition: log_msg.h:112
struct log_msg log
Definition: log_msg.h:114
struct log_msg_generic_hdr generic
Definition: log_msg.h:113
Definition: log_msg.h:60
const struct log_source_const_data * fixed
Definition: log_msg.h:61
struct log_source_dynamic_data * dynamic
Definition: log_msg.h:62
void * raw
Definition: log_msg.h:63
Generic packet header.
Definition: mpsc_packet.h:49
Misc utilities.