Zephyr API Documentation  3.6.99
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 <[email protected]>
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
68#if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__)
70 const char *const name;
71#endif
75 void *const message;
76
78 const size_t message_size;
79
83 void *const user_data;
84
89 bool (*const validator)(const void *msg, size_t msg_size);
90
92 struct zbus_channel_data *const data;
93};
94
100enum __packed zbus_observer_type {
104};
105
109
110#if defined(CONFIG_ZBUS_PRIORITY_BOOST)
112 int priority;
113#endif /* CONFIG_ZBUS_PRIORITY_BOOST */
114};
115
132#if defined(CONFIG_ZBUS_OBSERVER_NAME) || defined(__DOXYGEN__)
134 const char *const name;
135#endif
138
141
142 union {
144 struct k_msgq *const queue;
145
147 void (*const callback)(const struct zbus_channel *chan);
148
149#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER) || defined(__DOXYGEN__)
153 struct k_fifo *const message_fifo;
154#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER */
155 };
156};
157
159struct zbus_channel_observation_mask {
160 bool enabled;
161};
162
163struct zbus_channel_observation {
164 const struct zbus_channel *const chan;
165 const struct zbus_observer *const obs;
166};
167
168#ifdef __cplusplus
169#define _ZBUS_CPP_EXTERN extern
170#else
171#define _ZBUS_CPP_EXTERN
172#endif /* __cplusplus */
173
174#define ZBUS_MIN_THREAD_PRIORITY (CONFIG_NUM_PREEMPT_PRIORITIES - 1)
175
176#if defined(CONFIG_ZBUS_ASSERT_MOCK)
177#define _ZBUS_ASSERT(_cond, _fmt, ...) \
178 do { \
179 if (!(_cond)) { \
180 printk("ZBUS ASSERT: "); \
181 printk(_fmt, ##__VA_ARGS__); \
182 printk("\n"); \
183 return -EFAULT; \
184 } \
185 } while (0)
186#else
187#define _ZBUS_ASSERT(_cond, _fmt, ...) __ASSERT(_cond, _fmt, ##__VA_ARGS__)
188#endif
189
190#if defined(CONFIG_ZBUS_CHANNEL_NAME)
191#define ZBUS_CHANNEL_NAME_INIT(_name) .name = #_name,
192#define _ZBUS_CHAN_NAME(_chan) (_chan)->name
193#else
194#define ZBUS_CHANNEL_NAME_INIT(_name)
195#define _ZBUS_CHAN_NAME(_chan) ""
196#endif
197
198#if defined(CONFIG_ZBUS_OBSERVER_NAME)
199#define ZBUS_OBSERVER_NAME_INIT(_name) .name = #_name,
200#define _ZBUS_OBS_NAME(_obs) (_obs)->name
201#else
202#define ZBUS_OBSERVER_NAME_INIT(_name)
203#define _ZBUS_OBS_NAME(_obs) ""
204#endif
205
206#if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS)
207#define ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_slist_name) static sys_slist_t _slist_name
208#define ZBUS_RUNTIME_OBSERVERS_LIST_INIT(_slist_name) .runtime_observers = &_slist_name,
209#else
210#define ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_slist_name)
211#define ZBUS_RUNTIME_OBSERVERS_LIST_INIT(_slist_name) /* No runtime observers */
212#endif
213
214#define _ZBUS_OBS_EXTERN(_name) extern struct zbus_observer _name
215
216#define _ZBUS_CHAN_EXTERN(_name) extern const struct zbus_channel _name
217
218#define ZBUS_REF(_value) &(_value)
219
220#define FOR_EACH_FIXED_ARG_NONEMPTY_TERM(F, sep, fixed_arg, ...) \
221 COND_CODE_0(/* are there zero non-empty arguments ? */ \
222 NUM_VA_ARGS_LESS_1( \
223 LIST_DROP_EMPTY(__VA_ARGS__, _)), /* if so, expand to nothing */ \
224 (), /* otherwise, expand to: */ \
225 (FOR_EACH_IDX_FIXED_ARG( \
226 F, sep, fixed_arg, \
227 LIST_DROP_EMPTY(__VA_ARGS__)) /* plus a final terminator */ \
228 __DEBRACKET sep))
229
230#define _ZBUS_OBSERVATION_PREFIX(_idx) \
231 GET_ARG_N(_idx, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, \
232 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, \
233 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, \
234 58, 59, 60, 61, 62, 63)
235
236#define _ZBUS_CHAN_OBSERVATION(_idx, _obs, _chan) \
237 const STRUCT_SECTION_ITERABLE( \
238 zbus_channel_observation, \
239 _CONCAT(_chan, _ZBUS_OBSERVATION_PREFIX(UTIL_INC(_idx)))) = {.chan = &_chan, \
240 .obs = &_obs}; \
241 STRUCT_SECTION_ITERABLE(zbus_channel_observation_mask, \
242 _CONCAT(_CONCAT(_chan, _ZBUS_OBSERVATION_PREFIX(UTIL_INC(_idx))), \
243 _mask)) = {.enabled = false};
244
245#if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__)
246#define _ZBUS_RUNTIME_OBSERVERS(_name) .observers = &(_CONCAT(_observers_, _name)),
247#define _ZBUS_RUNTIME_OBSERVERS_DECL(_name) static sys_slist_t _CONCAT(_observers_, _name);
248#else
249#define _ZBUS_RUNTIME_OBSERVERS(_name)
250#define _ZBUS_RUNTIME_OBSERVERS_DECL(_name)
251#endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */
252
255/* clang-format off */
267#define ZBUS_CHAN_ADD_OBS_WITH_MASK(_chan, _obs, _masked, _prio) \
268 const STRUCT_SECTION_ITERABLE(zbus_channel_observation, \
269 _CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs))) = { \
270 .chan = &_chan, \
271 .obs = &_obs, \
272 }; \
273 STRUCT_SECTION_ITERABLE(zbus_channel_observation_mask, \
274 _CONCAT(_CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs)), \
275 _mask)) = {.enabled = _masked}
276/* clang-format on */
277
288#define ZBUS_CHAN_ADD_OBS(_chan, _obs, _prio) ZBUS_CHAN_ADD_OBS_WITH_MASK(_chan, _obs, false, _prio)
289
295#define ZBUS_OBS_DECLARE(...) FOR_EACH_NONEMPTY_TERM(_ZBUS_OBS_EXTERN, (;), __VA_ARGS__)
296
302#define ZBUS_CHAN_DECLARE(...) FOR_EACH(_ZBUS_CHAN_EXTERN, (;), __VA_ARGS__)
303
308#define ZBUS_OBSERVERS_EMPTY
309
315#define ZBUS_OBSERVERS(...) __VA_ARGS__
316
317/* clang-format off */
333#define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \
334 static _type _CONCAT(_zbus_message_, _name) = _init_val; \
335 static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \
336 .observers_start_idx = -1, \
337 .observers_end_idx = -1, \
338 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
339 .highest_observer_priority = ZBUS_MIN_THREAD_PRIORITY, \
340 )) \
341 }; \
342 static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \
343 _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \
344 ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \
345 .message = &_CONCAT(_zbus_message_, _name), \
346 .message_size = sizeof(_type), \
347 .user_data = _user_data, \
348 .validator = _validator, \
349 .data = &_CONCAT(_zbus_chan_data_, _name), \
350 }; \
351 /* Extern declaration of observers */ \
352 ZBUS_OBS_DECLARE(_observers); \
353 /* Create all channel observations from observers list */ \
354 FOR_EACH_FIXED_ARG_NONEMPTY_TERM(_ZBUS_CHAN_OBSERVATION, (;), _name, _observers)
355/* clang-format on */
356
366#define ZBUS_MSG_INIT(_val, ...) \
367 { \
368 _val, ##__VA_ARGS__ \
369 }
370
371/* clang-format off */
383#define ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, _enable) \
384 K_MSGQ_DEFINE(_zbus_observer_queue_##_name, \
385 sizeof(const struct zbus_channel *), \
386 _queue_size, sizeof(const struct zbus_channel *) \
387 ); \
388 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
389 .enabled = _enable, \
390 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
391 .priority = ZBUS_MIN_THREAD_PRIORITY, \
392 )) \
393 }; \
394 STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
395 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
396 .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, \
397 .data = &_CONCAT(_zbus_obs_data_, _name), \
398 .queue = &_zbus_observer_queue_##_name, \
399 }
400/* clang-format on */
401
413#define ZBUS_SUBSCRIBER_DEFINE(_name, _queue_size) \
414 ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, true)
415
416/* clang-format off */
428#define ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, _enable) \
429 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
430 .enabled = _enable, \
431 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
432 .priority = ZBUS_MIN_THREAD_PRIORITY, \
433 )) \
434 }; \
435 STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
436 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
437 .type = ZBUS_OBSERVER_LISTENER_TYPE, \
438 .data = &_CONCAT(_zbus_obs_data_, _name), \
439 .callback = (_cb) \
440 }
441/* clang-format on */
442
453#define ZBUS_LISTENER_DEFINE(_name, _cb) ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, true)
454
455/* clang-format off */
466#define ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _enable) \
467 static K_FIFO_DEFINE(_zbus_observer_fifo_##_name); \
468 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
469 .enabled = _enable, \
470 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
471 .priority = ZBUS_MIN_THREAD_PRIORITY, \
472 )) \
473 }; \
474 STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
475 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
476 .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, \
477 .data = &_CONCAT(_zbus_obs_data_, _name), \
478 .message_fifo = &_zbus_observer_fifo_##_name, \
479 }
480/* clang-format on */
481
493#define ZBUS_MSG_SUBSCRIBER_DEFINE(_name) ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, true)
515int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t timeout);
516
534int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeout);
535
557int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout);
558
573int zbus_chan_finish(const struct zbus_channel *chan);
574
593int zbus_chan_notify(const struct zbus_channel *chan, k_timeout_t timeout);
594
595#if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__)
596
606static inline const char *zbus_chan_name(const struct zbus_channel *chan)
607{
608 __ASSERT(chan != NULL, "chan is required");
609
610 return chan->name;
611}
612
613#endif
614
627static inline void *zbus_chan_msg(const struct zbus_channel *chan)
628{
629 __ASSERT(chan != NULL, "chan is required");
630
631 return chan->message;
632}
633
648static inline const void *zbus_chan_const_msg(const struct zbus_channel *chan)
649{
650 __ASSERT(chan != NULL, "chan is required");
651
652 return chan->message;
653}
654
664static inline uint16_t zbus_chan_msg_size(const struct zbus_channel *chan)
665{
666 __ASSERT(chan != NULL, "chan is required");
667
668 return chan->message_size;
669}
670
680static inline void *zbus_chan_user_data(const struct zbus_channel *chan)
681{
682 __ASSERT(chan != NULL, "chan is required");
683
684 return chan->user_data;
685}
686
687#if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__)
688
705int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observer *obs,
706 k_timeout_t timeout);
707
725int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer *obs,
726 k_timeout_t timeout);
727
730struct zbus_observer_node {
731 sys_snode_t node;
732 const struct zbus_observer *obs;
733};
734
737#endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */
738
752int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled);
753
764static inline int zbus_obs_is_enabled(struct zbus_observer *obs, bool *enable)
765{
766 _ZBUS_ASSERT(obs != NULL, "obs is required");
767 _ZBUS_ASSERT(enable != NULL, "enable is required");
768
769 *enable = obs->data->enabled;
770
771 return 0;
772}
773
789 const struct zbus_channel *chan, bool masked);
790
804 const struct zbus_channel *chan, bool *masked);
805
806#if defined(CONFIG_ZBUS_OBSERVER_NAME) || defined(__DOXYGEN__)
807
817static inline const char *zbus_obs_name(const struct zbus_observer *obs)
818{
819 __ASSERT(obs != NULL, "obs is required");
820
821 return obs->name;
822}
823
824#endif
825
826#if defined(CONFIG_ZBUS_PRIORITY_BOOST) || defined(__DOXYGEN__)
827
838
849
850#endif /* CONFIG_ZBUS_PRIORITY_BOOST */
851
870int zbus_sub_wait(const struct zbus_observer *sub, const struct zbus_channel **chan,
871 k_timeout_t timeout);
872
873#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER) || defined(__DOXYGEN__)
874
893int zbus_sub_wait_msg(const struct zbus_observer *sub, const struct zbus_channel **chan, void *msg,
894 k_timeout_t timeout);
895
896#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER */
897
911bool zbus_iterate_over_channels(bool (*iterator_func)(const struct zbus_channel *chan));
927 bool (*iterator_func)(const struct zbus_channel *chan, void *user_data), void *user_data);
928
942bool zbus_iterate_over_observers(bool (*iterator_func)(const struct zbus_observer *obs));
958 bool (*iterator_func)(const struct zbus_observer *obs, void *user_data), void *user_data);
959
964#ifdef __cplusplus
965}
966#endif
967
968#endif /* ZEPHYR_INCLUDE_ZBUS_H_ */
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:606
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.
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:817
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:100
static uint16_t zbus_chan_msg_size(const struct zbus_channel *chan)
Get the channel's message size.
Definition: zbus.h:664
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:764
static void * zbus_chan_msg(const struct zbus_channel *chan)
Get the reference for a channel message directly.
Definition: zbus.h:627
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:680
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:648
@ ZBUS_OBSERVER_LISTENER_TYPE
Definition: zbus.h:101
@ ZBUS_OBSERVER_SUBSCRIBER_TYPE
Definition: zbus.h:102
@ ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE
Definition: zbus.h:103
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:2388
Message Queue Structure.
Definition: kernel.h:4421
Kernel timeout type.
Definition: sys_clock.h:65
Type used to represent a channel mutable data.
Definition: zbus.h:30
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:67
bool(*const validator)(const void *msg, size_t msg_size)
Message validator.
Definition: zbus.h:89
struct zbus_channel_data *const data
Mutable channel data struct.
Definition: zbus.h:92
const size_t message_size
Message size.
Definition: zbus.h:78
void *const message
Message reference.
Definition: zbus.h:75
const char *const name
Channel name.
Definition: zbus.h:70
void *const user_data
User data available to extend zbus features.
Definition: zbus.h:83
Definition: zbus.h:106
bool enabled
Enabled flag.
Definition: zbus.h:108
Type used to represent an observer.
Definition: zbus.h:131
enum zbus_observer_type type
Type indication.
Definition: zbus.h:137
struct zbus_observer_data *const data
Mutable observer data struct.
Definition: zbus.h:140
struct k_msgq *const queue
Observer message queue.
Definition: zbus.h:144
struct k_fifo *const message_fifo
Observer message FIFO.
Definition: zbus.h:153
const char *const name
Observer name.
Definition: zbus.h:134