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>
12 #include <zephyr/sys/iterable_sections.h>
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17
18 /**
19 * @brief Zbus API
20 * @defgroup zbus_apis Zbus APIs
21 * @ingroup os_services
22 * @{
23 */
24
25 /**
26 * @brief Type used to represent a channel mutable data.
27 *
28 * Every channel has a zbus_channel_data structure associated.
29 */
30 struct zbus_channel_data {
31 /** Static channel observer list start index. Considering the ITERABLE SECTIONS allocation
32 * order.
33 */
34 int16_t observers_start_idx;
35
36 /** Static channel observer list end index. Considering the ITERABLE SECTIONS allocation
37 * order.
38 */
39 int16_t observers_end_idx;
40
41 /** Access control semaphore. Points to the semaphore used to avoid race conditions
42 * for accessing the channel.
43 */
44 struct k_sem sem;
45
46 #if defined(CONFIG_ZBUS_PRIORITY_BOOST)
47 /** Highest observer priority. Indicates the priority that the VDED will use to boost the
48 * notification process avoiding preemptions.
49 */
50 int highest_observer_priority;
51 #endif /* CONFIG_ZBUS_PRIORITY_BOOST */
52
53 #if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__)
54 /** Channel observer list. Represents the channel's observers list, it can be empty
55 * or have listeners and subscribers mixed in any sequence. It can be changed in runtime.
56 */
57 sys_slist_t observers;
58 #endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */
59
60 #if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION) || defined(__DOXYGEN__)
61 /** Net buf pool for message subscribers. It can be either the global or a separated one.
62 */
63 struct net_buf_pool *msg_subscriber_pool;
64 #endif /* ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION */
65
66 #if defined(CONFIG_ZBUS_CHANNEL_PUBLISH_STATS) || defined(__DOXYGEN__)
67 /** Kernel timestamp of the last publish action on this channel */
68 k_ticks_t publish_timestamp;
69 /** Number of times data has been published to this channel */
70 uint32_t publish_count;
71 #endif /* CONFIG_ZBUS_CHANNEL_PUBLISH_STATS */
72 };
73
74 /**
75 * @brief Type used to represent a channel.
76 *
77 * Every channel has a zbus_channel structure associated used to control the channel
78 * access and usage.
79 */
80 struct zbus_channel {
81 #if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__)
82 /** Channel name. */
83 const char *name;
84 #endif
85 #if defined(CONFIG_ZBUS_CHANNEL_ID) || defined(__DOXYGEN__)
86 /** Unique numeric channel identifier. */
87 uint32_t id;
88 #endif
89 /** Message reference. Represents the message's reference that points to the actual
90 * shared memory region.
91 */
92 void *message;
93
94 /** Message size. Represents the channel's message size. */
95 size_t message_size;
96
97 /** User data available to extend zbus features. The channel must be claimed before
98 * using this field.
99 */
100 void *user_data;
101
102 /** Message validator. Stores the reference to the function to check the message
103 * validity before actually performing the publishing. No invalid messages can be
104 * published. Every message is valid when this field is empty.
105 */
106 bool (*validator)(const void *msg, size_t msg_size);
107
108 /** Mutable channel data struct. */
109 struct zbus_channel_data *data;
110 };
111
112 /**
113 * @brief Type used to represent an observer type.
114 *
115 * A observer can be a listener or a subscriber.
116 */
117 enum __packed zbus_observer_type {
118 ZBUS_OBSERVER_LISTENER_TYPE,
119 ZBUS_OBSERVER_SUBSCRIBER_TYPE,
120 ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE,
121 };
122
123 struct zbus_observer_data {
124 /** Enabled flag. Indicates if observer is receiving notification. */
125 bool enabled;
126
127 #if defined(CONFIG_ZBUS_PRIORITY_BOOST)
128 /** Subscriber attached thread priority. */
129 int priority;
130 #endif /* CONFIG_ZBUS_PRIORITY_BOOST */
131 };
132
133 /**
134 * @brief Type used to represent an observer.
135 *
136 * Every observer has an representation structure containing the relevant information.
137 * An observer is a code portion interested in some channel. The observer can be notified
138 * synchronously or asynchronously and it is called listener and subscriber respectively.
139 * The observer can be enabled or disabled during runtime by change the enabled boolean
140 * field of the structure. The listeners have a callback function that is executed by the
141 * bus with the index of the changed channel as argument when the notification is sent.
142 * The subscribers have a message queue where the bus enqueues the index of the changed
143 * channel when a notification is sent.
144 *
145 * @see zbus_obs_set_enable function to properly change the observer's enabled field.
146 *
147 */
148 struct zbus_observer {
149 #if defined(CONFIG_ZBUS_OBSERVER_NAME) || defined(__DOXYGEN__)
150 /** Observer name. */
151 const char *name;
152 #endif
153 /** Type indication. */
154 enum zbus_observer_type type;
155
156 /** Mutable observer data struct. */
157 struct zbus_observer_data *data;
158
159 union {
160 /** Observer message queue. It turns the observer into a subscriber. */
161 struct k_msgq *queue;
162
163 /** Observer callback function. It turns the observer into a listener. */
164 void (*callback)(const struct zbus_channel *chan);
165
166 #if defined(CONFIG_ZBUS_MSG_SUBSCRIBER) || defined(__DOXYGEN__)
167 /** Observer message FIFO. It turns the observer into a message subscriber. It only
168 * exists if the @kconfig{CONFIG_ZBUS_MSG_SUBSCRIBER} is enabled.
169 */
170 struct k_fifo *message_fifo;
171 #endif /* CONFIG_ZBUS_MSG_SUBSCRIBER */
172 };
173 };
174
175 /** @cond INTERNAL_HIDDEN */
176 struct zbus_channel_observation_mask {
177 bool enabled;
178 };
179
180 struct zbus_channel_observation {
181 const struct zbus_channel *chan;
182 const struct zbus_observer *obs;
183 };
184
185 #ifdef __cplusplus
186 #define _ZBUS_CPP_EXTERN extern
187 #else
188 #define _ZBUS_CPP_EXTERN
189 #endif /* __cplusplus */
190
191 #define ZBUS_MIN_THREAD_PRIORITY (CONFIG_NUM_PREEMPT_PRIORITIES - 1)
192
193 #if defined(CONFIG_ZBUS_ASSERT_MOCK)
194 #define _ZBUS_ASSERT(_cond, _fmt, ...) \
195 do { \
196 if (!(_cond)) { \
197 printk("ZBUS ASSERT: "); \
198 printk(_fmt, ##__VA_ARGS__); \
199 printk("\n"); \
200 return -EFAULT; \
201 } \
202 } while (0)
203 #else
204 #define _ZBUS_ASSERT(_cond, _fmt, ...) __ASSERT(_cond, _fmt, ##__VA_ARGS__)
205 #endif
206
207 #if defined(CONFIG_ZBUS_CHANNEL_NAME)
208 #define ZBUS_CHANNEL_NAME_INIT(_name) .name = #_name,
209 #define _ZBUS_CHAN_NAME(_chan) (_chan)->name
210 #else
211 #define ZBUS_CHANNEL_NAME_INIT(_name)
212 #define _ZBUS_CHAN_NAME(_chan) ""
213 #endif
214
215 #if defined(CONFIG_ZBUS_OBSERVER_NAME)
216 #define ZBUS_OBSERVER_NAME_INIT(_name) .name = #_name,
217 #define _ZBUS_OBS_NAME(_obs) (_obs)->name
218 #else
219 #define ZBUS_OBSERVER_NAME_INIT(_name)
220 #define _ZBUS_OBS_NAME(_obs) ""
221 #endif
222
223 #if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS)
224 #define ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_slist_name) static sys_slist_t _slist_name
225 #define ZBUS_RUNTIME_OBSERVERS_LIST_INIT(_slist_name) .runtime_observers = &_slist_name,
226 #else
227 #define ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_slist_name)
228 #define ZBUS_RUNTIME_OBSERVERS_LIST_INIT(_slist_name) /* No runtime observers */
229 #endif
230
231 #define _ZBUS_OBS_EXTERN(_name) extern const struct zbus_observer _name
232
233 #define _ZBUS_CHAN_EXTERN(_name) extern const struct zbus_channel _name
234
235 #define ZBUS_REF(_value) &(_value)
236
237 #define FOR_EACH_FIXED_ARG_NONEMPTY_TERM(F, sep, fixed_arg, ...) \
238 COND_CODE_0(/* are there zero non-empty arguments ? */ \
239 NUM_VA_ARGS_LESS_1( \
240 LIST_DROP_EMPTY(__VA_ARGS__, _)), /* if so, expand to nothing */ \
241 (), /* otherwise, expand to: */ \
242 (FOR_EACH_IDX_FIXED_ARG( \
243 F, sep, fixed_arg, \
244 LIST_DROP_EMPTY(__VA_ARGS__)) /* plus a final terminator */ \
245 __DEBRACKET sep))
246
247 #define _ZBUS_OBSERVATION_PREFIX(_idx) \
248 GET_ARG_N(_idx, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, \
249 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, \
250 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, \
251 58, 59, 60, 61, 62, 63)
252
253 #define _ZBUS_CHAN_OBSERVATION(_idx, _obs, _chan) \
254 const STRUCT_SECTION_ITERABLE( \
255 zbus_channel_observation, \
256 _CONCAT(_chan, _ZBUS_OBSERVATION_PREFIX(UTIL_INC(_idx)))) = {.chan = &_chan, \
257 .obs = &_obs}; \
258 STRUCT_SECTION_ITERABLE(zbus_channel_observation_mask, \
259 _CONCAT(_CONCAT(_chan, _ZBUS_OBSERVATION_PREFIX(UTIL_INC(_idx))), \
260 _mask)) = {.enabled = false};
261
262 #if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__)
263 #define _ZBUS_RUNTIME_OBSERVERS(_name) .observers = &(_CONCAT(_observers_, _name)),
264 #define _ZBUS_RUNTIME_OBSERVERS_DECL(_name) static sys_slist_t _CONCAT(_observers_, _name);
265 #else
266 #define _ZBUS_RUNTIME_OBSERVERS(_name)
267 #define _ZBUS_RUNTIME_OBSERVERS_DECL(_name)
268 #endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */
269
270 #define _ZBUS_MESSAGE_NAME(_name) _CONCAT(_zbus_message_, _name)
271
272 /* clang-format off */
273 #define _ZBUS_CHAN_DEFINE(_name, _id, _type, _validator, _user_data) \
274 static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \
275 .observers_start_idx = -1, \
276 .observers_end_idx = -1, \
277 .sem = Z_SEM_INITIALIZER(_CONCAT(_zbus_chan_data_, _name).sem, 1, 1), \
278 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, \
279 (.highest_observer_priority = ZBUS_MIN_THREAD_PRIORITY,)) \
280 IF_ENABLED(CONFIG_ZBUS_RUNTIME_OBSERVERS, \
281 (.observers = SYS_SLIST_STATIC_INIT( \
282 &_CONCAT(_zbus_chan_data_, _name).observers),)) \
283 }; \
284 static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \
285 _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \
286 ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \
287 IF_ENABLED(CONFIG_ZBUS_CHANNEL_ID, (.id = _id,)) \
288 .message = &_ZBUS_MESSAGE_NAME(_name), \
289 .message_size = sizeof(_type), \
290 .user_data = _user_data, \
291 .validator = _validator, \
292 .data = &_CONCAT(_zbus_chan_data_, _name), \
293 IF_ENABLED(ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION, \
294 (.msg_subscriber_pool = &_zbus_msg_subscribers_pool,)) \
295 }
296 /* clang-format on */
297
298 /** @endcond */
299
300 /* clang-format off */
301
302 /**
303 * @brief Add a static channel observation.
304 *
305 * This macro initializes a channel observation by receiving the
306 * channel and the observer.
307 *
308 * @param _chan Channel instance.
309 * @param _obs Observer instance.
310 * @param _masked Observation state.
311 * @param _prio Observer notification sequence priority.
312 */
313 #define ZBUS_CHAN_ADD_OBS_WITH_MASK(_chan, _obs, _masked, _prio) \
314 const STRUCT_SECTION_ITERABLE(zbus_channel_observation, \
315 _CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs))) = { \
316 .chan = &_chan, \
317 .obs = &_obs, \
318 }; \
319 STRUCT_SECTION_ITERABLE(zbus_channel_observation_mask, \
320 _CONCAT(_CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs)), \
321 _mask)) = {.enabled = _masked}
322 /* clang-format on */
323
324 /**
325 * @brief Add a static channel observation.
326 *
327 * This macro initializes a channel observation by receiving the
328 * channel and the observer.
329 *
330 * @param _chan Channel instance.
331 * @param _obs Observer instance.
332 * @param _prio Observer notification sequence priority.
333 */
334 #define ZBUS_CHAN_ADD_OBS(_chan, _obs, _prio) ZBUS_CHAN_ADD_OBS_WITH_MASK(_chan, _obs, false, _prio)
335
336 /**
337 * @def ZBUS_OBS_DECLARE
338 * This macro list the observers to be used in a file. Internally, it declares the observers with
339 * the extern statement. Note it is only necessary when the observers are declared outside the file.
340 */
341 #define ZBUS_OBS_DECLARE(...) FOR_EACH_NONEMPTY_TERM(_ZBUS_OBS_EXTERN, (;), __VA_ARGS__)
342
343 /**
344 * @def ZBUS_CHAN_DECLARE
345 * This macro list the channels to be used in a file. Internally, it declares the channels with the
346 * extern statement. Note it is only necessary when the channels are declared outside the file.
347 */
348 #define ZBUS_CHAN_DECLARE(...) FOR_EACH(_ZBUS_CHAN_EXTERN, (;), __VA_ARGS__)
349
350 /**
351 * @def ZBUS_OBSERVERS_EMPTY
352 * This macro indicates the channel has no observers.
353 */
354 #define ZBUS_OBSERVERS_EMPTY
355
356 /**
357 * @def ZBUS_OBSERVERS
358 * This macro indicates the channel has listed observers. Note the sequence of observer notification
359 * will follow the same as listed.
360 */
361 #define ZBUS_OBSERVERS(...) __VA_ARGS__
362
363 /**
364 * @def ZBUS_CHAN_ID_INVALID
365 * This macro indicates the channel does not have a unique ID.
366 */
367 #define ZBUS_CHAN_ID_INVALID UINT32_MAX
368
369 /**
370 * @brief Zbus channel definition.
371 *
372 * This macro defines a channel.
373 *
374 * @param _name The channel's name.
375 * @param _type The Message type. It must be a struct or union.
376 * @param _validator The validator function.
377 * @param _user_data A pointer to the user data.
378 *
379 * @see struct zbus_channel
380 * @param _observers The observers list. The sequence indicates the priority of the observer. The
381 * first the highest priority.
382 * @param _init_val The message initialization.
383 */
384 #define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \
385 static _type _ZBUS_MESSAGE_NAME(_name) = _init_val; \
386 _ZBUS_CHAN_DEFINE(_name, ZBUS_CHAN_ID_INVALID, _type, _validator, _user_data); \
387 /* Extern declaration of observers */ \
388 ZBUS_OBS_DECLARE(_observers); \
389 /* Create all channel observations from observers list */ \
390 FOR_EACH_FIXED_ARG_NONEMPTY_TERM(_ZBUS_CHAN_OBSERVATION, (;), _name, _observers)
391
392 /**
393 * @brief Zbus channel definition with numeric identifier.
394 *
395 * This macro defines a channel.
396 *
397 * @param _name The channel's name.
398 * @param _id The channel's unique numeric identifier.
399 * @param _type The Message type. It must be a struct or union.
400 * @param _validator The validator function.
401 * @param _user_data A pointer to the user data.
402 *
403 * @see struct zbus_channel
404 * @param _observers The observers list. The sequence indicates the priority of the observer. The
405 * first the highest priority.
406 * @param _init_val The message initialization.
407 */
408 #define ZBUS_CHAN_DEFINE_WITH_ID(_name, _id, _type, _validator, _user_data, _observers, _init_val) \
409 static _type _ZBUS_MESSAGE_NAME(_name) = _init_val; \
410 _ZBUS_CHAN_DEFINE(_name, _id, _type, _validator, _user_data); \
411 /* Extern declaration of observers */ \
412 ZBUS_OBS_DECLARE(_observers); \
413 /* Create all channel observations from observers list */ \
414 FOR_EACH_FIXED_ARG_NONEMPTY_TERM(_ZBUS_CHAN_OBSERVATION, (;), _name, _observers)
415
416 /**
417 * @brief Initialize a message.
418 *
419 * This macro initializes a message by passing the values to initialize the message struct
420 * or union.
421 *
422 * @param[in] _val Variadic with the initial values. ``ZBUS_INIT(0)`` means ``{0}``, as
423 * ZBUS_INIT(.a=10, .b=30) means ``{.a=10, .b=30}``.
424 */
425 #define ZBUS_MSG_INIT(_val, ...) {_val, ##__VA_ARGS__}
426
427 /* clang-format off */
428
429 /**
430 * @brief Define and initialize a subscriber.
431 *
432 * This macro defines an observer of subscriber type. It defines a message queue where the
433 * subscriber will receive the notification asynchronously, and initialize the ``struct
434 * zbus_observer`` defining the subscriber.
435 *
436 * @param[in] _name The subscriber's name.
437 * @param[in] _queue_size The notification queue's size.
438 * @param[in] _enable The subscriber initial enable state.
439 */
440 #define ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, _enable) \
441 K_MSGQ_DEFINE(_zbus_observer_queue_##_name, \
442 sizeof(struct zbus_channel *), \
443 _queue_size, sizeof(struct zbus_channel *) \
444 ); \
445 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
446 .enabled = _enable, \
447 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
448 .priority = ZBUS_MIN_THREAD_PRIORITY, \
449 )) \
450 }; \
451 _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
452 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
453 .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, \
454 .data = &_CONCAT(_zbus_obs_data_, _name), \
455 .queue = &_zbus_observer_queue_##_name, \
456 }
457 /* clang-format on */
458
459 /**
460 * @brief Define and initialize a subscriber.
461 *
462 * This macro defines an observer of subscriber type. It defines a message queue where the
463 * subscriber will receive the notification asynchronously, and initialize the ``struct
464 * zbus_observer`` defining the subscriber. The subscribers are defined in the enabled
465 * state with this macro.
466 *
467 * @param[in] _name The subscriber's name.
468 * @param[in] _queue_size The notification queue's size.
469 */
470 #define ZBUS_SUBSCRIBER_DEFINE(_name, _queue_size) \
471 ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, true)
472
473 /* clang-format off */
474
475 /**
476 * @brief Define and initialize a listener.
477 *
478 * This macro defines an observer of listener type. This macro establishes the callback where the
479 * listener will be notified synchronously, and initialize the ``struct zbus_observer`` defining the
480 * listener.
481 *
482 * @param[in] _name The listener's name.
483 * @param[in] _cb The callback function.
484 * @param[in] _enable The listener initial enable state.
485 */
486 #define ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, _enable) \
487 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
488 .enabled = _enable, \
489 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
490 .priority = ZBUS_MIN_THREAD_PRIORITY, \
491 )) \
492 }; \
493 _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
494 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
495 .type = ZBUS_OBSERVER_LISTENER_TYPE, \
496 .data = &_CONCAT(_zbus_obs_data_, _name), \
497 .callback = (_cb) \
498 }
499 /* clang-format on */
500
501 /**
502 * @brief Define and initialize a listener.
503 *
504 * This macro defines an observer of listener type. This macro establishes the callback where the
505 * listener will be notified synchronously and initialize the ``struct zbus_observer`` defining the
506 * listener. The listeners are defined in the enabled state with this macro.
507 *
508 * @param[in] _name The listener's name.
509 * @param[in] _cb The callback function.
510 */
511 #define ZBUS_LISTENER_DEFINE(_name, _cb) ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, true)
512
513 /* clang-format off */
514
515 /**
516 * @brief Define and initialize a message subscriber.
517 *
518 * This macro defines an observer of @ref ZBUS_OBSERVER_SUBSCRIBER_TYPE type. It defines a FIFO
519 * where the subscriber will receive the message asynchronously and initialize the @ref
520 * zbus_observer defining the subscriber.
521 *
522 * @param[in] _name The subscriber's name.
523 * @param[in] _enable The subscriber's initial state.
524 */
525 #define ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _enable) \
526 static K_FIFO_DEFINE(_zbus_observer_fifo_##_name); \
527 static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \
528 .enabled = _enable, \
529 IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \
530 .priority = ZBUS_MIN_THREAD_PRIORITY, \
531 )) \
532 }; \
533 _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \
534 ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
535 .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, \
536 .data = &_CONCAT(_zbus_obs_data_, _name), \
537 .message_fifo = &_zbus_observer_fifo_##_name, \
538 }
539 /* clang-format on */
540
541 /**
542 * @brief Define and initialize an enabled message subscriber.
543 *
544 * This macro defines an observer of message subscriber type. It defines a FIFO where the
545 * subscriber will receive the message asynchronously and initialize the @ref
546 * zbus_observer defining the subscriber. The message subscribers are defined in the enabled state
547 * with this macro.
548
549 *
550 * @param[in] _name The subscriber's name.
551 */
552 #define ZBUS_MSG_SUBSCRIBER_DEFINE(_name) ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, true)
553 /**
554 *
555 * @brief Publish to a channel
556 *
557 * This routine publishes a message to a channel.
558 *
559 * @param chan The channel's reference.
560 * @param msg Reference to the message where the publish function copies the channel's
561 * message data from.
562 * @param timeout Waiting period to publish the channel,
563 * or one of the special values K_NO_WAIT and K_FOREVER.
564 *
565 * @retval 0 Channel published.
566 * @retval -ENOMSG The message is invalid based on the validator function or some of the
567 * observers could not receive the notification.
568 * @retval -EBUSY The channel is busy.
569 * @retval -EAGAIN Waiting period timed out.
570 * @retval -EFAULT A parameter is incorrect, the notification could not be sent to one or more
571 * observer, or the function context is invalid (inside an ISR). The function only returns this
572 * value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
573 */
574 int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t timeout);
575
576 /**
577 * @brief Read a channel
578 *
579 * This routine reads a message from a channel.
580 *
581 * @param[in] chan The channel's reference.
582 * @param[out] msg Reference to the message where the read function copies the channel's
583 * message data to.
584 * @param[in] timeout Waiting period to read the channel,
585 * or one of the special values K_NO_WAIT and K_FOREVER.
586 *
587 * @retval 0 Channel read.
588 * @retval -EBUSY The channel is busy.
589 * @retval -EAGAIN Waiting period timed out.
590 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
591 * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
592 */
593 int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeout);
594
595 /**
596 * @brief Claim a channel
597 *
598 * This routine claims a channel. During the claiming period the channel is blocked for publishing,
599 * reading, notifying or claiming again. Finishing is the only available action.
600 *
601 * @warning After calling this routine, the channel cannot be used by other
602 * thread until the zbus_chan_finish routine is performed.
603 *
604 * @warning This routine should only be called once before a zbus_chan_finish.
605 *
606 * @param[in] chan The channel's reference.
607 * @param[in] timeout Waiting period to claim the channel,
608 * or one of the special values K_NO_WAIT and K_FOREVER.
609 *
610 * @retval 0 Channel claimed.
611 * @retval -EBUSY The channel is busy.
612 * @retval -EAGAIN Waiting period timed out.
613 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
614 * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
615 */
616 int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout);
617
618 /**
619 * @brief Finish a channel claim.
620 *
621 * This routine finishes a channel claim. After calling this routine with success, the channel will
622 * be able to be used by other thread.
623 *
624 * @warning This routine must only be used after a zbus_chan_claim.
625 *
626 * @param chan The channel's reference.
627 *
628 * @retval 0 Channel finished.
629 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
630 * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
631 */
632 int zbus_chan_finish(const struct zbus_channel *chan);
633
634 /**
635 * @brief Force a channel notification.
636 *
637 * This routine forces the event dispatcher to notify the channel's observers even if the message
638 * has no changes. Note this function could be useful after claiming/finishing actions.
639 *
640 * @param chan The channel's reference.
641 * @param timeout Waiting period to notify the channel,
642 * or one of the special values K_NO_WAIT and K_FOREVER.
643 *
644 * @retval 0 Channel notified.
645 * @retval -EBUSY The channel's semaphore returned without waiting.
646 * @retval -EAGAIN Timeout to take the channel's semaphore.
647 * @retval -ENOMEM There is not more buffer on the messgage buffers pool.
648 * @retval -EFAULT A parameter is incorrect, the notification could not be sent to one or more
649 * observer, or the function context is invalid (inside an ISR). The function only returns this
650 * value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
651 */
652 int zbus_chan_notify(const struct zbus_channel *chan, k_timeout_t timeout);
653
654 #if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__)
655
656 /**
657 * @brief Get the channel's name.
658 *
659 * This routine returns the channel's name reference.
660 *
661 * @param chan The channel's reference.
662 *
663 * @return Channel's name reference.
664 */
zbus_chan_name(const struct zbus_channel * chan)665 static inline const char *zbus_chan_name(const struct zbus_channel *chan)
666 {
667 __ASSERT(chan != NULL, "chan is required");
668
669 return chan->name;
670 }
671
672 #endif
673
674 #if defined(CONFIG_ZBUS_CHANNEL_ID) || defined(__DOXYGEN__)
675
676 /**
677 * @brief Retrieve a zbus channel from its numeric identifier
678 *
679 * @param channel_id Unique channel ID from @ref ZBUS_CHAN_DEFINE_WITH_ID
680 *
681 * @retval NULL If channel with ID @a channel_id does not exist.
682 * @retval chan Channel pointer with ID @a channel_id otherwise.
683 */
684 const struct zbus_channel *zbus_chan_from_id(uint32_t channel_id);
685
686 #endif
687
688 /**
689 * @brief Get the reference for a channel message directly.
690 *
691 * This routine returns the reference of a channel message.
692 *
693 * @warning This function must only be used directly for already locked channels. This
694 * can be done inside a listener for the receiving channel or after claim a channel.
695 *
696 * @param chan The channel's reference.
697 *
698 * @return Channel's message reference.
699 */
zbus_chan_msg(const struct zbus_channel * chan)700 static inline void *zbus_chan_msg(const struct zbus_channel *chan)
701 {
702 __ASSERT(chan != NULL, "chan is required");
703
704 return chan->message;
705 }
706
707 /**
708 * @brief Get a constant reference for a channel message directly.
709 *
710 * This routine returns a constant reference of a channel message. This should be used
711 * inside listeners to access the message directly. In this way zbus prevents the listener of
712 * changing the notifying channel's message during the notification process.
713 *
714 * @warning This function must only be used directly for already locked channels. This
715 * can be done inside a listener for the receiving channel or after claim a channel.
716 *
717 * @param chan The channel's constant reference.
718 *
719 * @return A constant channel's message reference.
720 */
zbus_chan_const_msg(const struct zbus_channel * chan)721 static inline const void *zbus_chan_const_msg(const struct zbus_channel *chan)
722 {
723 __ASSERT(chan != NULL, "chan is required");
724
725 return chan->message;
726 }
727
728 /**
729 * @brief Get the channel's message size.
730 *
731 * This routine returns the channel's message size.
732 *
733 * @param chan The channel's reference.
734 *
735 * @return Channel's message size.
736 */
zbus_chan_msg_size(const struct zbus_channel * chan)737 static inline uint16_t zbus_chan_msg_size(const struct zbus_channel *chan)
738 {
739 __ASSERT(chan != NULL, "chan is required");
740
741 return chan->message_size;
742 }
743
744 /**
745 * @brief Get the channel's user data.
746 *
747 * This routine returns the channel's user data.
748 *
749 * @param chan The channel's reference.
750 *
751 * @return Channel's user data.
752 */
zbus_chan_user_data(const struct zbus_channel * chan)753 static inline void *zbus_chan_user_data(const struct zbus_channel *chan)
754 {
755 __ASSERT(chan != NULL, "chan is required");
756
757 return chan->user_data;
758 }
759
760 #if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION) || defined(__DOXYGEN__)
761
762 /**
763 * @brief Set the channel's msg subscriber `net_buf` pool.
764 *
765 * @param chan The channel's reference.
766 * @param pool The reference to the `net_buf` memory pool.
767 */
zbus_chan_set_msg_sub_pool(const struct zbus_channel * chan,struct net_buf_pool * pool)768 static inline void zbus_chan_set_msg_sub_pool(const struct zbus_channel *chan,
769 struct net_buf_pool *pool)
770 {
771 __ASSERT(chan != NULL, "chan is required");
772 __ASSERT(pool != NULL, "pool is required");
773
774 chan->data->msg_subscriber_pool = pool;
775 }
776
777 #endif /* ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_ISOLATION */
778
779 #if defined(CONFIG_ZBUS_CHANNEL_PUBLISH_STATS) || defined(__DOXYGEN__)
780
781 /**
782 * @brief Update the publishing statistics for a channel
783 *
784 * This function updates the publishing statistics for the @ref zbus_chan_claim ->
785 * @ref zbus_chan_finish workflow, which cannot automatically determine whether
786 * new data has been published or not.
787 *
788 * @warning This function must only be used directly for already locked channels.
789 *
790 * @param chan The channel's reference.
791 */
zbus_chan_pub_stats_update(const struct zbus_channel * chan)792 static inline void zbus_chan_pub_stats_update(const struct zbus_channel *chan)
793 {
794 __ASSERT(chan != NULL, "chan is required");
795
796 chan->data->publish_timestamp = k_uptime_ticks();
797 chan->data->publish_count += 1;
798 }
799
800 /**
801 * @brief Get the time a channel was last published to.
802 *
803 * @note Will return 0 if channel has not yet been published to.
804 *
805 * @param chan The channel's reference.
806 *
807 * @return The kernel timestamp of the last publishing action.
808 */
zbus_chan_pub_stats_last_time(const struct zbus_channel * chan)809 static inline k_ticks_t zbus_chan_pub_stats_last_time(const struct zbus_channel *chan)
810 {
811 __ASSERT(chan != NULL, "chan is required");
812
813 return chan->data->publish_timestamp;
814 }
815
816 /**
817 * @brief Get the number of times a channel has been published to.
818 *
819 * @note Will return 0 if channel has not yet been published to.
820 *
821 * @param chan The channel's reference.
822 *
823 * @return The number of times a channel has been published to.
824 */
zbus_chan_pub_stats_count(const struct zbus_channel * chan)825 static inline uint32_t zbus_chan_pub_stats_count(const struct zbus_channel *chan)
826 {
827 __ASSERT(chan != NULL, "chan is required");
828
829 return chan->data->publish_count;
830 }
831
832 /**
833 * @brief Get the average period between publishes to a channel.
834 *
835 * @note Will return 0 if channel has not yet been published to.
836 *
837 * @param chan The channel's reference.
838 *
839 * @return Average duration in milliseconds between publishes.
840 */
zbus_chan_pub_stats_avg_period(const struct zbus_channel * chan)841 static inline uint32_t zbus_chan_pub_stats_avg_period(const struct zbus_channel *chan)
842 {
843 __ASSERT(chan != NULL, "chan is required");
844
845 /* Not yet published, period = 0ms */
846 if (chan->data->publish_count == 0) {
847 return 0;
848 }
849 /* Average period across application runtime */
850 return k_uptime_get() / chan->data->publish_count;
851 }
852
853 #else
854
zbus_chan_pub_stats_update(const struct zbus_channel * chan)855 static inline void zbus_chan_pub_stats_update(const struct zbus_channel *chan)
856 {
857 (void)chan;
858 }
859
860 #endif /* CONFIG_ZBUS_CHANNEL_PUBLISH_STATS */
861
862 #if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__)
863
864 /**
865 * @brief Add an observer to a channel.
866 *
867 * This routine adds an observer to the channel.
868 *
869 * @param chan The channel's reference.
870 * @param obs The observer's reference to be added.
871 * @param timeout Waiting period to add an observer,
872 * or one of the special values K_NO_WAIT and K_FOREVER.
873 *
874 * @retval 0 Observer added to the channel.
875 * @retval -EALREADY The observer is already present in the channel's runtime observers list.
876 * @retval -ENOMEM Returned without waiting.
877 * @retval -EAGAIN Waiting period timed out.
878 * @retval -EINVAL Some parameter is invalid.
879 */
880 int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observer *obs,
881 k_timeout_t timeout);
882
883 /**
884 * @brief Remove an observer from a channel.
885 *
886 * This routine removes an observer to the channel.
887 *
888 * @param chan The channel's reference.
889 * @param obs The observer's reference to be removed.
890 * @param timeout Waiting period to remove an observer,
891 * or one of the special values K_NO_WAIT and K_FOREVER.
892 *
893 * @retval 0 Observer removed to the channel.
894 * @retval -EINVAL Invalid data supplied.
895 * @retval -EBUSY Returned without waiting.
896 * @retval -EAGAIN Waiting period timed out.
897 * @retval -ENODATA no observer found in channel's runtime observer list.
898 * @retval -ENOMEM Returned without waiting.
899 */
900 int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer *obs,
901 k_timeout_t timeout);
902
903 /** @cond INTERNAL_HIDDEN */
904
905 struct zbus_observer_node {
906 sys_snode_t node;
907 const struct zbus_observer *obs;
908 };
909
910 /** @endcond */
911
912 #endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */
913
914 /**
915 * @brief Change the observer state.
916 *
917 * This routine changes the observer state. A channel when disabled will not receive
918 * notifications from the event dispatcher.
919 *
920 * @param[in] obs The observer's reference.
921 * @param[in] enabled State to be. When false the observer stops to receive notifications.
922 *
923 * @retval 0 Observer set enable.
924 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
925 * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
926 */
927 int zbus_obs_set_enable(const struct zbus_observer *obs, bool enabled);
928
929 /**
930 * @brief Get the observer state.
931 *
932 * This routine retrieves the observer state.
933 *
934 * @param[in] obs The observer's reference.
935 * @param[out] enable The boolean output's reference.
936 *
937 * @return Observer state.
938 */
zbus_obs_is_enabled(const struct zbus_observer * obs,bool * enable)939 static inline int zbus_obs_is_enabled(const struct zbus_observer *obs, bool *enable)
940 {
941 _ZBUS_ASSERT(obs != NULL, "obs is required");
942 _ZBUS_ASSERT(enable != NULL, "enable is required");
943
944 *enable = obs->data->enabled;
945
946 return 0;
947 }
948
949 /**
950 * @brief Mask notifications from a channel to an observer.
951 *
952 * The observer can mask notifications from a specific observing channel by calling this function.
953 *
954 * @param obs The observer's reference to be added.
955 * @param chan The channel's reference.
956 * @param masked The mask state. When the mask is true, the observer will not receive notifications
957 * from the channel.
958 *
959 * @retval 0 Channel notifications masked to the observer.
960 * @retval -ESRCH No observation found for the related pair chan/obs.
961 * @retval -EINVAL Some parameter is invalid.
962 */
963 int zbus_obs_set_chan_notification_mask(const struct zbus_observer *obs,
964 const struct zbus_channel *chan, bool masked);
965
966 /**
967 * @brief Get the notifications masking state from a channel to an observer.
968 *
969 * @param obs The observer's reference to be added.
970 * @param chan The channel's reference.
971 * @param[out] masked The mask state. When the mask is true, the observer will not receive
972 * notifications from the channel.
973 *
974 * @retval 0 Retrieved the masked state.
975 * @retval -ESRCH No observation found for the related pair chan/obs.
976 * @retval -EINVAL Some parameter is invalid.
977 */
978 int zbus_obs_is_chan_notification_masked(const struct zbus_observer *obs,
979 const struct zbus_channel *chan, bool *masked);
980
981 #if defined(CONFIG_ZBUS_OBSERVER_NAME) || defined(__DOXYGEN__)
982
983 /**
984 * @brief Get the observer's name.
985 *
986 * This routine returns the observer's name reference.
987 *
988 * @param obs The observer's reference.
989 *
990 * @return The observer's name reference.
991 */
zbus_obs_name(const struct zbus_observer * obs)992 static inline const char *zbus_obs_name(const struct zbus_observer *obs)
993 {
994 __ASSERT(obs != NULL, "obs is required");
995
996 return obs->name;
997 }
998
999 #endif
1000
1001 #if defined(CONFIG_ZBUS_PRIORITY_BOOST) || defined(__DOXYGEN__)
1002
1003 /**
1004 * @brief Set the observer thread priority by attaching it to a thread.
1005 *
1006 * @param[in] obs The observer's reference.
1007 *
1008 * @retval 0 Observer detached from the thread.
1009 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
1010 * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
1011 */
1012 int zbus_obs_attach_to_thread(const struct zbus_observer *obs);
1013
1014 /**
1015 * @brief Clear the observer thread priority by detaching it from a thread.
1016 *
1017 * @param[in] obs The observer's reference.
1018 *
1019 * @retval 0 Observer detached from the thread.
1020 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
1021 * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
1022 */
1023 int zbus_obs_detach_from_thread(const struct zbus_observer *obs);
1024
1025 #endif /* CONFIG_ZBUS_PRIORITY_BOOST */
1026
1027 /**
1028 * @brief Wait for a channel notification.
1029 *
1030 * This routine makes the subscriber to wait a notification. The notification comes as a channel
1031 * reference.
1032 *
1033 * @param[in] sub The subscriber's reference.
1034 * @param[out] chan The notification channel's reference.
1035 * @param[in] timeout Waiting period for a notification arrival,
1036 * or one of the special values K_NO_WAIT and K_FOREVER.
1037 *
1038 * @retval 0 Notification received.
1039 * @retval -ENOMSG Returned without waiting.
1040 * @retval -EAGAIN Waiting period timed out.
1041 * @retval -EINVAL The observer is not a subscriber.
1042 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
1043 * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
1044 */
1045 int zbus_sub_wait(const struct zbus_observer *sub, const struct zbus_channel **chan,
1046 k_timeout_t timeout);
1047
1048 #if defined(CONFIG_ZBUS_MSG_SUBSCRIBER) || defined(__DOXYGEN__)
1049
1050 /**
1051 * @brief Wait for a channel message.
1052 *
1053 * This routine makes the subscriber wait for the new message in case of channel publication.
1054 *
1055 * @param[in] sub The subscriber's reference.
1056 * @param[out] chan The notification channel's reference.
1057 * @param[out] msg A reference to a copy of the published message.
1058 * @param[in] timeout Waiting period for a notification arrival,
1059 * or one of the special values, K_NO_WAIT and K_FOREVER.
1060 *
1061 * @retval 0 Message received.
1062 * @retval -EINVAL The observer is not a subscriber.
1063 * @retval -ENOMSG Could not retrieve the net_buf from the subscriber FIFO.
1064 * @retval -EILSEQ Received an invalid channel reference.
1065 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
1066 * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled.
1067 */
1068 int zbus_sub_wait_msg(const struct zbus_observer *sub, const struct zbus_channel **chan, void *msg,
1069 k_timeout_t timeout);
1070
1071 #endif /* CONFIG_ZBUS_MSG_SUBSCRIBER */
1072
1073 /**
1074 *
1075 * @brief Iterate over channels.
1076 *
1077 * Enables the developer to iterate over the channels giving to this function an
1078 * iterator_func which is called for each channel. If the iterator_func returns false all
1079 * the iteration stops.
1080 *
1081 * @param[in] iterator_func The function that will be execute on each iteration.
1082 *
1083 * @retval true Iterator executed for all channels.
1084 * @retval false Iterator could not be executed. Some iterate returned false.
1085 */
1086 bool zbus_iterate_over_channels(bool (*iterator_func)(const struct zbus_channel *chan));
1087 /**
1088 *
1089 * @brief Iterate over channels with user data.
1090 *
1091 * Enables the developer to iterate over the channels giving to this function an
1092 * iterator_func which is called for each channel. If the iterator_func returns false all
1093 * the iteration stops.
1094 *
1095 * @param[in] iterator_func The function that will be execute on each iteration.
1096 * @param[in] user_data The user data that can be passed in the function.
1097 *
1098 * @retval true Iterator executed for all channels.
1099 * @retval false Iterator could not be executed. Some iterate returned false.
1100 */
1101 bool zbus_iterate_over_channels_with_user_data(
1102 bool (*iterator_func)(const struct zbus_channel *chan, void *user_data), void *user_data);
1103
1104 /**
1105 *
1106 * @brief Iterate over observers.
1107 *
1108 * Enables the developer to iterate over the observers giving to this function an
1109 * iterator_func which is called for each observer. If the iterator_func returns false all
1110 * the iteration stops.
1111 *
1112 * @param[in] iterator_func The function that will be execute on each iteration.
1113 *
1114 * @retval true Iterator executed for all channels.
1115 * @retval false Iterator could not be executed. Some iterate returned false.
1116 */
1117 bool zbus_iterate_over_observers(bool (*iterator_func)(const struct zbus_observer *obs));
1118 /**
1119 *
1120 * @brief Iterate over observers with user data.
1121 *
1122 * Enables the developer to iterate over the observers giving to this function an
1123 * iterator_func which is called for each observer. If the iterator_func returns false all
1124 * the iteration stops.
1125 *
1126 * @param[in] iterator_func The function that will be execute on each iteration.
1127 * @param[in] user_data The user data that can be passed in the function.
1128 *
1129 * @retval true Iterator executed for all channels.
1130 * @retval false Iterator could not be executed. Some iterate returned false.
1131 */
1132 bool zbus_iterate_over_observers_with_user_data(
1133 bool (*iterator_func)(const struct zbus_observer *obs, void *user_data), void *user_data);
1134
1135 /**
1136 * @}
1137 */
1138
1139 #ifdef __cplusplus
1140 }
1141 #endif
1142
1143 #endif /* ZEPHYR_INCLUDE_ZBUS_H_ */
1144