Zephyr Project API 3.7.0
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
zbus.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Rodrigo Peixoto <rodrigopex@gmail.com>
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6#ifndef ZEPHYR_INCLUDE_ZBUS_H_
7#define ZEPHYR_INCLUDE_ZBUS_H_
8
9#include <string.h>
10
11#include <zephyr/kernel.h>
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
35
40
44 struct k_sem sem;
45
46#if defined(CONFIG_ZBUS_PRIORITY_BOOST)
50 int highest_observer_priority;
51#endif /* CONFIG_ZBUS_PRIORITY_BOOST */
52
53#if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__)
58#endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */
59
60#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION) || defined(__DOXYGEN__)
64#endif /* ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION */
65};
66
74#if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__)
76 const char *const name;
77#endif
81 void *const message;
82
84 const size_t message_size;
85
89 void *const user_data;
90
95 bool (*const validator)(const void *msg, size_t msg_size);
96
98 struct zbus_channel_data *const data;
99};
100
111
115
116#if defined(CONFIG_ZBUS_PRIORITY_BOOST)
118 int priority;
119#endif /* CONFIG_ZBUS_PRIORITY_BOOST */
120};
121
138#if defined(CONFIG_ZBUS_OBSERVER_NAME) || defined(__DOXYGEN__)
140 const char *const name;
141#endif
144
147
148 union {
150 struct k_msgq *const queue;
151
153 void (*const callback)(const struct zbus_channel *chan);
154
155#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER) || defined(__DOXYGEN__)
159 struct k_fifo *const message_fifo;
160#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER */
161 };
162};
163
165struct zbus_channel_observation_mask {
166 bool enabled;
167};
168
169struct zbus_channel_observation {
170 const struct zbus_channel *const chan;
171 const struct zbus_observer *const obs;
172};
173
174#ifdef __cplusplus
175#define _ZBUS_CPP_EXTERN extern
176#else
177#define _ZBUS_CPP_EXTERN
178#endif /* __cplusplus */
179
180#define ZBUS_MIN_THREAD_PRIORITY (CONFIG_NUM_PREEMPT_PRIORITIES - 1)
181
182#if defined(CONFIG_ZBUS_ASSERT_MOCK)
183#define _ZBUS_ASSERT(_cond, _fmt, ...) \
184 do { \
185 if (!(_cond)) { \
186 printk("ZBUS ASSERT: "); \
187 printk(_fmt, ##__VA_ARGS__); \
188 printk("\n"); \
189 return -EFAULT; \
190 } \
191 } while (0)
192#else
193#define _ZBUS_ASSERT(_cond, _fmt, ...) __ASSERT(_cond, _fmt, ##__VA_ARGS__)
194#endif
195
196#if defined(CONFIG_ZBUS_CHANNEL_NAME)
197#define ZBUS_CHANNEL_NAME_INIT(_name) .name = #_name,
198#define _ZBUS_CHAN_NAME(_chan) (_chan)->name
199#else
200#define ZBUS_CHANNEL_NAME_INIT(_name)
201#define _ZBUS_CHAN_NAME(_chan) ""
202#endif
203
204#if defined(CONFIG_ZBUS_OBSERVER_NAME)
205#define ZBUS_OBSERVER_NAME_INIT(_name) .name = #_name,
206#define _ZBUS_OBS_NAME(_obs) (_obs)->name
207#else
208#define ZBUS_OBSERVER_NAME_INIT(_name)
209#define _ZBUS_OBS_NAME(_obs) ""
210#endif
211
212#if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS)
213#define ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_slist_name) static sys_slist_t _slist_name
214#define ZBUS_RUNTIME_OBSERVERS_LIST_INIT(_slist_name) .runtime_observers = &_slist_name,
215#else
216#define ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_slist_name)
217#define ZBUS_RUNTIME_OBSERVERS_LIST_INIT(_slist_name) /* No runtime observers */
218#endif
219
220#define _ZBUS_OBS_EXTERN(_name) extern struct zbus_observer _name
221
222#define _ZBUS_CHAN_EXTERN(_name) extern const struct zbus_channel _name
223
224#define ZBUS_REF(_value) &(_value)
225
226#define FOR_EACH_FIXED_ARG_NONEMPTY_TERM(F, sep, fixed_arg, ...) \
227 COND_CODE_0(/* are there zero non-empty arguments ? */ \
228 NUM_VA_ARGS_LESS_1( \
229 LIST_DROP_EMPTY(__VA_ARGS__, _)), /* if so, expand to nothing */ \
230 (), /* otherwise, expand to: */ \
231 (FOR_EACH_IDX_FIXED_ARG( \
232 F, sep, fixed_arg, \
233 LIST_DROP_EMPTY(__VA_ARGS__)) /* plus a final terminator */ \
234 __DEBRACKET sep))
235
236#define _ZBUS_OBSERVATION_PREFIX(_idx) \
237 GET_ARG_N(_idx, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, \
238 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, \
239 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, \
240 58, 59, 60, 61, 62, 63)
241
242#define _ZBUS_CHAN_OBSERVATION(_idx, _obs, _chan) \
243 const STRUCT_SECTION_ITERABLE( \
244 zbus_channel_observation, \
245 _CONCAT(_chan, _ZBUS_OBSERVATION_PREFIX(UTIL_INC(_idx)))) = {.chan = &_chan, \
246 .obs = &_obs}; \
247 STRUCT_SECTION_ITERABLE(zbus_channel_observation_mask, \
248 _CONCAT(_CONCAT(_chan, _ZBUS_OBSERVATION_PREFIX(UTIL_INC(_idx))), \
249 _mask)) = {.enabled = false};
250
251#if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__)
252#define _ZBUS_RUNTIME_OBSERVERS(_name) .observers = &(_CONCAT(_observers_, _name)),
253#define _ZBUS_RUNTIME_OBSERVERS_DECL(_name) static sys_slist_t _CONCAT(_observers_, _name);
254#else
255#define _ZBUS_RUNTIME_OBSERVERS(_name)
256#define _ZBUS_RUNTIME_OBSERVERS_DECL(_name)
257#endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */
258
261/* clang-format off */
273#define ZBUS_CHAN_ADD_OBS_WITH_MASK(_chan, _obs, _masked, _prio) \
274 const STRUCT_SECTION_ITERABLE(zbus_channel_observation, \
275 _CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs))) = { \
276 .chan = &_chan, \
277 .obs = &_obs, \
278 }; \
279 STRUCT_SECTION_ITERABLE(zbus_channel_observation_mask, \
280 _CONCAT(_CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs)), \
281 _mask)) = {.enabled = _masked}
282/* clang-format on */
283
294#define ZBUS_CHAN_ADD_OBS(_chan, _obs, _prio) ZBUS_CHAN_ADD_OBS_WITH_MASK(_chan, _obs, false, _prio)
295
301#define ZBUS_OBS_DECLARE(...) FOR_EACH_NONEMPTY_TERM(_ZBUS_OBS_EXTERN, (;), __VA_ARGS__)
302
308#define ZBUS_CHAN_DECLARE(...) FOR_EACH(_ZBUS_CHAN_EXTERN, (;), __VA_ARGS__)
309
314#define ZBUS_OBSERVERS_EMPTY
315
321#define ZBUS_OBSERVERS(...) __VA_ARGS__
322
323/* clang-format off */
339#define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \
340 static _type _CONCAT(_zbus_message_, _name) = _init_val; \
341 static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \
342 .observers_start_idx = -1, \
343 .observers_end_idx = -1, \
344 .sem = Z_SEM_INITIALIZER(_CONCAT(_zbus_chan_data_, _name).sem, 1, 1), \
345 IF_ENABLED(CONFIG_ZBUS_RUNTIME_OBSERVERS, ( \
346 .observers = SYS_SLIST_STATIC_INIT( \
347 &_CONCAT(_zbus_chan_data_, _name).observers), \
348 )) \
349 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
350 .highest_observer_priority = ZBUS_MIN_THREAD_PRIORITY, \
351 )) \
352 }; \
353 static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \
354 _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \
355 ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \
356 .message = &_CONCAT(_zbus_message_, _name), \
357 .message_size = sizeof(_type), \
358 .user_data = _user_data, \
359 .validator = _validator, \
360 .data = &_CONCAT(_zbus_chan_data_, _name), \
361 IF_ENABLED(ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION, ( \
362 .msg_subscriber_pool = &_zbus_msg_subscribers_pool, \
363 )) \
364 }; \
365 /* Extern declaration of observers */ \
366 ZBUS_OBS_DECLARE(_observers); \
367 /* Create all channel observations from observers list */ \
368 FOR_EACH_FIXED_ARG_NONEMPTY_TERM(_ZBUS_CHAN_OBSERVATION, (;), _name, _observers)
369/* clang-format on */
370
380#define ZBUS_MSG_INIT(_val, ...) \
381 { \
382 _val, ##__VA_ARGS__ \
383 }
384
385/* clang-format off */
397#define ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, _enable) \
398 K_MSGQ_DEFINE(_zbus_observer_queue_##_name, \
399 sizeof(const struct zbus_channel *), \
400 _queue_size, sizeof(const struct zbus_channel *) \
401 ); \
402 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
403 .enabled = _enable, \
404 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
405 .priority = ZBUS_MIN_THREAD_PRIORITY, \
406 )) \
407 }; \
408 STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
409 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
410 .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, \
411 .data = &_CONCAT(_zbus_obs_data_, _name), \
412 .queue = &_zbus_observer_queue_##_name, \
413 }
414/* clang-format on */
415
427#define ZBUS_SUBSCRIBER_DEFINE(_name, _queue_size) \
428 ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, true)
429
430/* clang-format off */
442#define ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, _enable) \
443 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
444 .enabled = _enable, \
445 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
446 .priority = ZBUS_MIN_THREAD_PRIORITY, \
447 )) \
448 }; \
449 STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
450 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
451 .type = ZBUS_OBSERVER_LISTENER_TYPE, \
452 .data = &_CONCAT(_zbus_obs_data_, _name), \
453 .callback = (_cb) \
454 }
455/* clang-format on */
456
467#define ZBUS_LISTENER_DEFINE(_name, _cb) ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, true)
468
469/* clang-format off */
480#define ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _enable) \
481 static K_FIFO_DEFINE(_zbus_observer_fifo_##_name); \
482 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
483 .enabled = _enable, \
484 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
485 .priority = ZBUS_MIN_THREAD_PRIORITY, \
486 )) \
487 }; \
488 STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
489 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
490 .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, \
491 .data = &_CONCAT(_zbus_obs_data_, _name), \
492 .message_fifo = &_zbus_observer_fifo_##_name, \
493 }
494/* clang-format on */
495
507#define ZBUS_MSG_SUBSCRIBER_DEFINE(_name) ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, true)
529int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t timeout);
530
548int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeout);
549
572
587int zbus_chan_finish(const struct zbus_channel *chan);
588
608
609#if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__)
610
620static inline const char *zbus_chan_name(const struct zbus_channel *chan)
621{
622 __ASSERT(chan != NULL, "chan is required");
623
624 return chan->name;
625}
626
627#endif
628
641static inline void *zbus_chan_msg(const struct zbus_channel *chan)
642{
643 __ASSERT(chan != NULL, "chan is required");
644
645 return chan->message;
646}
647
662static inline const void *zbus_chan_const_msg(const struct zbus_channel *chan)
663{
664 __ASSERT(chan != NULL, "chan is required");
665
666 return chan->message;
667}
668
678static inline uint16_t zbus_chan_msg_size(const struct zbus_channel *chan)
679{
680 __ASSERT(chan != NULL, "chan is required");
681
682 return chan->message_size;
683}
684
694static inline void *zbus_chan_user_data(const struct zbus_channel *chan)
695{
696 __ASSERT(chan != NULL, "chan is required");
697
698 return chan->user_data;
699}
700
701#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION) || defined(__DOXYGEN__)
702
709static inline void zbus_chan_set_msg_sub_pool(const struct zbus_channel *chan,
710 struct net_buf_pool *pool)
711{
712 __ASSERT(chan != NULL, "chan is required");
713 __ASSERT(pool != NULL, "pool is required");
714
715 chan->data->msg_subscriber_pool = pool;
716}
717
718#endif /* ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION */
719
720#if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__)
721
738int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observer *obs,
740
758int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer *obs,
760
763struct zbus_observer_node {
764 sys_snode_t node;
765 const struct zbus_observer *obs;
766};
767
770#endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */
771
785int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled);
786
797static inline int zbus_obs_is_enabled(struct zbus_observer *obs, bool *enable)
798{
799 _ZBUS_ASSERT(obs != NULL, "obs is required");
800 _ZBUS_ASSERT(enable != NULL, "enable is required");
801
802 *enable = obs->data->enabled;
803
804 return 0;
805}
806
822 const struct zbus_channel *chan, bool masked);
823
837 const struct zbus_channel *chan, bool *masked);
838
839#if defined(CONFIG_ZBUS_OBSERVER_NAME) || defined(__DOXYGEN__)
840
850static inline const char *zbus_obs_name(const struct zbus_observer *obs)
851{
852 __ASSERT(obs != NULL, "obs is required");
853
854 return obs->name;
855}
856
857#endif
858
859#if defined(CONFIG_ZBUS_PRIORITY_BOOST) || defined(__DOXYGEN__)
860
871
882
883#endif /* CONFIG_ZBUS_PRIORITY_BOOST */
884
903int zbus_sub_wait(const struct zbus_observer *sub, const struct zbus_channel **chan,
905
906#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER) || defined(__DOXYGEN__)
907
926int zbus_sub_wait_msg(const struct zbus_observer *sub, const struct zbus_channel **chan, void *msg,
928
929#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER */
930
944bool zbus_iterate_over_channels(bool (*iterator_func)(const struct zbus_channel *chan));
960 bool (*iterator_func)(const struct zbus_channel *chan, void *user_data), void *user_data);
961
975bool zbus_iterate_over_observers(bool (*iterator_func)(const struct zbus_observer *obs));
991 bool (*iterator_func)(const struct zbus_observer *obs, void *user_data), void *user_data);
992
997#ifdef __cplusplus
998}
999#endif
1000
1001#endif /* ZEPHYR_INCLUDE_ZBUS_H_ */
ZTEST_BMEM int timeout
Definition main.c:31
struct _slist sys_slist_t
Single-linked list structure.
Definition slist.h:49
struct _snode sys_snode_t
Single-linked list node structure.
Definition slist.h:39
int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout)
Claim a channel.
static const char * zbus_chan_name(const struct zbus_channel *chan)
Get the channel's name.
Definition zbus.h:620
bool zbus_iterate_over_observers_with_user_data(bool(*iterator_func)(const struct zbus_observer *obs, void *user_data), void *user_data)
Iterate over observers with user data.
bool zbus_iterate_over_observers(bool(*iterator_func)(const struct zbus_observer *obs))
Iterate over observers.
static void zbus_chan_set_msg_sub_pool(const struct zbus_channel *chan, struct net_buf_pool *pool)
Set the channel's msg subscriber net_buf pool.
Definition zbus.h:709
int zbus_obs_is_chan_notification_masked(const struct zbus_observer *obs, const struct zbus_channel *chan, bool *masked)
Get the notifications masking state from a channel to an observer.
int zbus_obs_detach_from_thread(const struct zbus_observer *obs)
Clear the observer thread priority by detaching it from a thread.
static const char * zbus_obs_name(const struct zbus_observer *obs)
Get the observer's name.
Definition zbus.h:850
int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled)
Change the observer state.
bool zbus_iterate_over_channels(bool(*iterator_func)(const struct zbus_channel *chan))
Iterate over channels.
int zbus_chan_notify(const struct zbus_channel *chan, k_timeout_t timeout)
Force a channel notification.
int zbus_chan_finish(const struct zbus_channel *chan)
Finish a channel claim.
int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeout)
Read a channel.
int zbus_sub_wait(const struct zbus_observer *sub, const struct zbus_channel **chan, k_timeout_t timeout)
Wait for a channel notification.
zbus_observer_type
Type used to represent an observer type.
Definition zbus.h:106
static uint16_t zbus_chan_msg_size(const struct zbus_channel *chan)
Get the channel's message size.
Definition zbus.h:678
int zbus_obs_set_chan_notification_mask(const struct zbus_observer *obs, const struct zbus_channel *chan, bool masked)
Mask notifications from a channel to an observer.
static int zbus_obs_is_enabled(struct zbus_observer *obs, bool *enable)
Get the observer state.
Definition zbus.h:797
static void * zbus_chan_msg(const struct zbus_channel *chan)
Get the reference for a channel message directly.
Definition zbus.h:641
bool zbus_iterate_over_channels_with_user_data(bool(*iterator_func)(const struct zbus_channel *chan, void *user_data), void *user_data)
Iterate over channels with user data.
int zbus_obs_attach_to_thread(const struct zbus_observer *obs)
Set the observer thread priority by attaching it to a thread.
static void * zbus_chan_user_data(const struct zbus_channel *chan)
Get the channel's user data.
Definition zbus.h:694
int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observer *obs, k_timeout_t timeout)
Add an observer to a channel.
int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t timeout)
Publish to a channel.
int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer *obs, k_timeout_t timeout)
Remove an observer from a channel.
int zbus_sub_wait_msg(const struct zbus_observer *sub, const struct zbus_channel **chan, void *msg, k_timeout_t timeout)
Wait for a channel message.
static const void * zbus_chan_const_msg(const struct zbus_channel *chan)
Get a constant reference for a channel message directly.
Definition zbus.h:662
@ ZBUS_OBSERVER_LISTENER_TYPE
Definition zbus.h:107
@ ZBUS_OBSERVER_SUBSCRIBER_TYPE
Definition zbus.h:108
@ ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE
Definition zbus.h:109
Public kernel APIs.
#define bool
Definition stdbool.h:13
__UINT16_TYPE__ uint16_t
Definition stdint.h:89
__INT16_TYPE__ int16_t
Definition stdint.h:73
Definition kernel.h:2391
Message Queue Structure.
Definition kernel.h:4426
Kernel timeout type.
Definition sys_clock.h:65
Network buffer pool representation.
Definition buf.h:1076
Type used to represent a channel mutable data.
Definition zbus.h:30
struct net_buf_pool * msg_subscriber_pool
Net buf pool for message subscribers.
Definition zbus.h:63
int16_t observers_end_idx
Static channel observer list end index.
Definition zbus.h:39
int16_t observers_start_idx
Static channel observer list start index.
Definition zbus.h:34
struct k_sem sem
Access control semaphore.
Definition zbus.h:44
sys_slist_t observers
Channel observer list.
Definition zbus.h:57
Type used to represent a channel.
Definition zbus.h:73
bool(*const validator)(const void *msg, size_t msg_size)
Message validator.
Definition zbus.h:95
struct zbus_channel_data *const data
Mutable channel data struct.
Definition zbus.h:98
const size_t message_size
Message size.
Definition zbus.h:84
void *const message
Message reference.
Definition zbus.h:81
const char *const name
Channel name.
Definition zbus.h:76
void *const user_data
User data available to extend zbus features.
Definition zbus.h:89
Definition zbus.h:112
bool enabled
Enabled flag.
Definition zbus.h:114
Type used to represent an observer.
Definition zbus.h:137
enum zbus_observer_type type
Type indication.
Definition zbus.h:143
struct zbus_observer_data *const data
Mutable observer data struct.
Definition zbus.h:146
struct k_msgq *const queue
Observer message queue.
Definition zbus.h:150
struct k_fifo *const message_fifo
Observer message FIFO.
Definition zbus.h:159
const char *const name
Observer name.
Definition zbus.h:140
static void msg(uint64_t c64)
Definition main.c:17
static const intptr_t user_data[5]
Definition main.c:588