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.
27 *
28 * Every channel has a zbus_channel structure associated used to control the channel
29 * access and usage.
30 */
31 struct zbus_channel {
32 #if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__)
33 /** Channel name. */
34 const char *const name;
35 #endif
36 /** Message size. Represents the channel's message size. */
37 const uint16_t message_size;
38
39 /** User data available to extend zbus features. The channel must be claimed before
40 * using this field.
41 */
42 void *const user_data;
43
44 /** Message reference. Represents the message's reference that points to the actual
45 * shared memory region.
46 */
47 void *const message;
48
49 /** Message validator. Stores the reference to the function to check the message
50 * validity before actually performing the publishing. No invalid messages can be
51 * published. Every message is valid when this field is empty.
52 */
53 bool (*const validator)(const void *msg, size_t msg_size);
54
55 /** Access control mutex. Points to the mutex used to avoid race conditions
56 * for accessing the channel.
57 */
58 struct k_mutex *mutex;
59 #if (CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE > 0) || defined(__DOXYGEN__)
60 /** Dynamic channel observer list. Represents the channel's observers list, it can be empty
61 * or have listeners and subscribers mixed in any sequence. It can be changed in runtime.
62 */
63 sys_slist_t *runtime_observers;
64 #endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE */
65
66 /** Channel observer list. Represents the channel's observers list, it can be empty or
67 * have listeners and subscribers mixed in any sequence.
68 */
69 const struct zbus_observer *const *observers;
70 };
71
72 /**
73 * @brief Type used to represent an observer.
74 *
75 * Every observer has an representation structure containing the relevant information.
76 * An observer is a code portion interested in some channel. The observer can be notified
77 * synchronously or asynchronously and it is called listener and subscriber respectively.
78 * The observer can be enabled or disabled during runtime by change the enabled boolean
79 * field of the structure. The listeners have a callback function that is executed by the
80 * bus with the index of the changed channel as argument when the notification is sent.
81 * The subscribers have a message queue where the bus enqueues the index of the changed
82 * channel when a notification is sent.
83 *
84 * @see zbus_obs_set_enable function to properly change the observer's enabled field.
85 *
86 */
87 struct zbus_observer {
88 #if defined(CONFIG_ZBUS_OBSERVER_NAME) || defined(__DOXYGEN__)
89 /** Observer name. */
90 const char *const name;
91 #endif
92 /** Enabled flag. Indicates if observer is receiving notification. */
93 bool enabled;
94 /** Observer message queue. It turns the observer into a subscriber. */
95 struct k_msgq *const queue;
96
97 /** Observer callback function. It turns the observer into a listener. */
98 void (*const callback)(const struct zbus_channel *chan);
99 };
100
101 /** @cond INTERNAL_HIDDEN */
102
103 #if defined(CONFIG_ZBUS_ASSERT_MOCK)
104 #define _ZBUS_ASSERT(_cond, _fmt, ...) \
105 do { \
106 if (!(_cond)) { \
107 printk("ZBUS ASSERT: "); \
108 printk(_fmt, ##__VA_ARGS__); \
109 printk("\n"); \
110 return -EFAULT; \
111 } \
112 } while (0)
113 #else
114 #define _ZBUS_ASSERT(_cond, _fmt, ...) __ASSERT(_cond, _fmt, ##__VA_ARGS__)
115 #endif
116
117 #if defined(CONFIG_ZBUS_CHANNEL_NAME)
118 #define ZBUS_CHANNEL_NAME_INIT(_name) .name = #_name,
119 #else
120 #define ZBUS_CHANNEL_NAME_INIT(_name)
121 #endif
122
123 #if defined(CONFIG_ZBUS_OBSERVER_NAME)
124 #define ZBUS_OBSERVER_NAME_INIT(_name) .name = #_name,
125 #define _ZBUS_OBS_NAME(_obs) (_obs)->name
126 #else
127 #define ZBUS_OBSERVER_NAME_INIT(_name)
128 #define _ZBUS_OBS_NAME(_obs) ""
129 #endif
130
131 #if CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE > 0
132 #define ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_slist_name) static sys_slist_t _slist_name
133 #define ZBUS_RUNTIME_OBSERVERS_LIST_INIT(_slist_name) .runtime_observers = &_slist_name,
134 #else
135 #define ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_slist_name)
136 #define ZBUS_RUNTIME_OBSERVERS_LIST_INIT(_slist_name) /* No runtime observers */
137 #endif
138
139 #if defined(CONFIG_ZBUS_STRUCTS_ITERABLE_ACCESS)
140 #define _ZBUS_STRUCT_DECLARE(_type, _name) STRUCT_SECTION_ITERABLE(_type, _name)
141 #else
142 #define _ZBUS_STRUCT_DECLARE(_type, _name) struct _type _name
143 #endif /* CONFIG_ZBUS_STRUCTS_ITERABLE_ACCESS */
144
145 #define _ZBUS_OBS_EXTERN(_name) extern struct zbus_observer _name
146
147 #define _ZBUS_CHAN_EXTERN(_name) extern const struct zbus_channel _name
148
149 #define ZBUS_REF(_value) &(_value)
150
151 k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks);
152 /** @endcond */
153
154 /**
155 * @def ZBUS_OBS_DECLARE
156 * This macro list the observers to be used in a file. Internally, it declares the observers with
157 * the extern statement. Note it is only necessary when the observers are declared outside the file.
158 */
159 #define ZBUS_OBS_DECLARE(...) FOR_EACH(_ZBUS_OBS_EXTERN, (;), __VA_ARGS__)
160
161 /**
162 * @def ZBUS_CHAN_DECLARE
163 * This macro list the channels to be used in a file. Internally, it declares the channels with the
164 * extern statement. Note it is only necessary when the channels are declared outside the file.
165 */
166 #define ZBUS_CHAN_DECLARE(...) FOR_EACH(_ZBUS_CHAN_EXTERN, (;), __VA_ARGS__)
167
168 /**
169 * @def ZBUS_OBSERVERS_EMPTY
170 * This macro indicates the channel has no observers.
171 */
172 #define ZBUS_OBSERVERS_EMPTY
173
174 /**
175 * @def ZBUS_OBSERVERS
176 * This macro indicates the channel has listed observers. Note the sequence of observer notification
177 * will follow the same as listed.
178 */
179 #define ZBUS_OBSERVERS(...) __VA_ARGS__
180
181 /**
182 * @brief Zbus channel definition.
183 *
184 * This macro defines a channel.
185 *
186 * @param _name The channel's name.
187 * @param _type The Message type. It must be a struct or union.
188 * @param _validator The validator function.
189 * @param _user_data A pointer to the user data.
190 *
191 * @see struct zbus_channel
192 * @param _observers The observers list. The sequence indicates the priority of the observer. The
193 * first the highest priority.
194 * @param _init_val The message initialization.
195 */
196 #define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \
197 static _type _CONCAT(_zbus_message_, _name) = _init_val; \
198 static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \
199 ZBUS_RUNTIME_OBSERVERS_LIST_DECL(_CONCAT(_runtime_observers_, _name)); \
200 FOR_EACH_NONEMPTY_TERM(_ZBUS_OBS_EXTERN, (;), _observers) \
201 static const struct zbus_observer *const _CONCAT(_zbus_observers_, _name)[] = { \
202 FOR_EACH_NONEMPTY_TERM(ZBUS_REF, (,), _observers) NULL}; \
203 const _ZBUS_STRUCT_DECLARE(zbus_channel, _name) = { \
204 ZBUS_CHANNEL_NAME_INIT(_name) /* Name */ \
205 .message_size = sizeof(_type), /* Message size */ \
206 .user_data = _user_data, /* User data */ \
207 .message = &_CONCAT(_zbus_message_, _name), /* Reference to the message */\
208 .validator = (_validator), /* Validator function */ \
209 .mutex = &_CONCAT(_zbus_mutex_, _name), /* Channel's Mutex */ \
210 ZBUS_RUNTIME_OBSERVERS_LIST_INIT( \
211 _CONCAT(_runtime_observers_, _name)) /* Runtime observer list */ \
212 .observers = _CONCAT(_zbus_observers_, _name)} /* Static observer list */
213
214 /**
215 * @brief Initialize a message.
216 *
217 * This macro initializes a message by passing the values to initialize the message struct
218 * or union.
219 *
220 * @param[in] _val Variadic with the initial values. ``ZBUS_INIT(0)`` means ``{0}``, as
221 * ZBUS_INIT(.a=10, .b=30) means ``{.a=10, .b=30}``.
222 */
223 #define ZBUS_MSG_INIT(_val, ...) \
224 { \
225 _val, ##__VA_ARGS__ \
226 }
227
228 /**
229 * @brief Define and initialize a subscriber.
230 *
231 * This macro defines an observer of subscriber type. It defines a message queue where the
232 * subscriber will receive the notification asynchronously, and initialize the ``struct
233 * zbus_observer`` defining the subscriber.
234 *
235 * @param[in] _name The subscriber's name.
236 * @param[in] _queue_size The notification queue's size.
237 */
238 #define ZBUS_SUBSCRIBER_DEFINE(_name, _queue_size) \
239 K_MSGQ_DEFINE(_zbus_observer_queue_##_name, sizeof(const struct zbus_channel *), \
240 _queue_size, sizeof(const struct zbus_channel *)); \
241 _ZBUS_STRUCT_DECLARE(zbus_observer, \
242 _name) = {ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
243 .enabled = true, \
244 .queue = &_zbus_observer_queue_##_name, .callback = NULL}
245
246 /**
247 * @brief Define and initialize a listener.
248 *
249 * This macro defines an observer of listener type. This macro establishes the callback where the
250 * listener will be notified synchronously, and initialize the ``struct zbus_observer`` defining the
251 * listener.
252 *
253 * @param[in] _name The listener's name.
254 * @param[in] _cb The callback function.
255 */
256 #define ZBUS_LISTENER_DEFINE(_name, _cb) \
257 _ZBUS_STRUCT_DECLARE(zbus_observer, \
258 _name) = {ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \
259 .enabled = true, \
260 .queue = NULL, .callback = (_cb)}
261
262 /**
263 *
264 * @brief Publish to a channel
265 *
266 * This routine publishes a message to a channel.
267 *
268 * @param chan The channel's reference.
269 * @param msg Reference to the message where the publish function copies the channel's
270 * message data from.
271 * @param timeout Waiting period to publish the channel,
272 * or one of the special values K_NO_WAIT and K_FOREVER.
273 *
274 * @retval 0 Channel published.
275 * @retval -ENOMSG The message is invalid based on the validator function or some of the
276 * observers could not receive the notification.
277 * @retval -EBUSY The channel is busy.
278 * @retval -EAGAIN Waiting period timed out.
279 * @retval -EFAULT A parameter is incorrect, the notification could not be sent to one or more
280 * observer, or the function context is invalid (inside an ISR). The function only returns this
281 * value when the CONFIG_ZBUS_ASSERT_MOCK is enabled.
282 */
283 int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t timeout);
284
285 /**
286 * @brief Read a channel
287 *
288 * This routine reads a message from a channel.
289 *
290 * @param[in] chan The channel's reference.
291 * @param[out] msg Reference to the message where the read function copies the channel's
292 * message data to.
293 * @param[in] timeout Waiting period to read the channel,
294 * or one of the special values K_NO_WAIT and K_FOREVER.
295 *
296 * @retval 0 Channel read.
297 * @retval -EBUSY The channel is busy.
298 * @retval -EAGAIN Waiting period timed out.
299 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
300 * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled.
301 */
302 int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeout);
303
304 /**
305 * @brief Claim a channel
306 *
307 * This routine claims a channel. During the claiming period the channel is blocked for publishing,
308 * reading, notifying or claiming again. Finishing is the only available action.
309 *
310 * @warning After calling this routine, the channel cannot be used by other
311 * thread until the zbus_chan_finish routine is performed.
312 *
313 * @warning This routine should only be called once before a zbus_chan_finish.
314 *
315 * @param[in] chan The channel's reference.
316 * @param[in] timeout Waiting period to claim the channel,
317 * or one of the special values K_NO_WAIT and K_FOREVER.
318 *
319 * @retval 0 Channel claimed.
320 * @retval -EBUSY The channel is busy.
321 * @retval -EAGAIN Waiting period timed out.
322 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
323 * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled.
324 */
325 int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout);
326
327 /**
328 * @brief Finish a channel claim.
329 *
330 * This routine finishes a channel claim. After calling this routine with success, the channel will
331 * be able to be used by other thread.
332 *
333 * @warning This routine must only be used after a zbus_chan_claim.
334 *
335 * @param chan The channel's reference.
336 *
337 * @retval 0 Channel finished.
338 * @retval -EPERM The channel was claimed by other thread.
339 * @retval -EINVAL The channel's mutex is not locked.
340 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
341 * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled.
342 */
343 int zbus_chan_finish(const struct zbus_channel *chan);
344
345 /**
346 * @brief Force a channel notification.
347 *
348 * This routine forces the event dispatcher to notify the channel's observers even if the message
349 * has no changes. Note this function could be useful after claiming/finishing actions.
350 *
351 * @param chan The channel's reference.
352 * @param timeout Waiting period to notify the channel,
353 * or one of the special values K_NO_WAIT and K_FOREVER.
354 *
355 * @retval 0 Channel notified.
356 * @retval -EPERM The current thread does not own the channel.
357 * @retval -EBUSY The channel's mutex returned without waiting.
358 * @retval -EAGAIN Timeout to acquiring the channel's mutex.
359 * @retval -EFAULT A parameter is incorrect, the notification could not be sent to one or more
360 * observer, or the function context is invalid (inside an ISR). The function only returns this
361 * value when the CONFIG_ZBUS_ASSERT_MOCK is enabled.
362 */
363 int zbus_chan_notify(const struct zbus_channel *chan, k_timeout_t timeout);
364
365 #if defined(CONFIG_ZBUS_CHANNEL_NAME) || defined(__DOXYGEN__)
366
367 /**
368 * @brief Get the channel's name.
369 *
370 * This routine returns the channel's name reference.
371 *
372 * @param chan The channel's reference.
373 *
374 * @return Channel's name reference.
375 */
zbus_chan_name(const struct zbus_channel * chan)376 static inline const char *zbus_chan_name(const struct zbus_channel *chan)
377 {
378 __ASSERT(chan != NULL, "chan is required");
379
380 return chan->name;
381 }
382
383 #endif
384
385 /**
386 * @brief Get the reference for a channel message directly.
387 *
388 * This routine returns the reference of a channel message.
389 *
390 * @warning This function must only be used directly for acquired (locked by mutex) channels. This
391 * can be done inside a listener for the receiving channel or after claim a channel.
392 *
393 * @param chan The channel's reference.
394 *
395 * @return Channel's message reference.
396 */
zbus_chan_msg(const struct zbus_channel * chan)397 static inline void *zbus_chan_msg(const struct zbus_channel *chan)
398 {
399 __ASSERT(chan != NULL, "chan is required");
400
401 return chan->message;
402 }
403
404 /**
405 * @brief Get a constant reference for a channel message directly.
406 *
407 * This routine returns a constant reference of a channel message. This should be used
408 * inside listeners to access the message directly. In this way zbus prevents the listener of
409 * changing the notifying channel's message during the notification process.
410 *
411 * @warning This function must only be used directly for acquired (locked by mutex) channels. This
412 * can be done inside a listener for the receiving channel or after claim a channel.
413 *
414 * @param chan The channel's constant reference.
415 *
416 * @return A constant channel's message reference.
417 */
zbus_chan_const_msg(const struct zbus_channel * chan)418 static inline const void *zbus_chan_const_msg(const struct zbus_channel *chan)
419 {
420 __ASSERT(chan != NULL, "chan is required");
421
422 return chan->message;
423 }
424
425 /**
426 * @brief Get the channel's message size.
427 *
428 * This routine returns the channel's message size.
429 *
430 * @param chan The channel's reference.
431 *
432 * @return Channel's message size.
433 */
zbus_chan_msg_size(const struct zbus_channel * chan)434 static inline uint16_t zbus_chan_msg_size(const struct zbus_channel *chan)
435 {
436 __ASSERT(chan != NULL, "chan is required");
437
438 return chan->message_size;
439 }
440
441 /**
442 * @brief Get the channel's user data.
443 *
444 * This routine returns the channel's user data.
445 *
446 * @param chan The channel's reference.
447 *
448 * @return Channel's user data.
449 */
zbus_chan_user_data(const struct zbus_channel * chan)450 static inline void *zbus_chan_user_data(const struct zbus_channel *chan)
451 {
452 __ASSERT(chan != NULL, "chan is required");
453
454 return chan->user_data;
455 }
456
457 #if (CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE > 0) || defined(__DOXYGEN__)
458
459 /**
460 * @brief Add an observer to a channel.
461 *
462 * This routine adds an observer to the channel.
463 *
464 * @param chan The channel's reference.
465 * @param obs The observer's reference to be added.
466 * @param timeout Waiting period to add an observer,
467 * or one of the special values K_NO_WAIT and K_FOREVER.
468 *
469 * @retval 0 Observer added to the channel.
470 * @retval -EALREADY The observer is already present in the channel's runtime observers list.
471 * @retval -ENOMEM Returned without waiting.
472 * @retval -EAGAIN Waiting period timed out.
473 * @retval -EINVAL Some parameter is invalid.
474 */
475 int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observer *obs,
476 k_timeout_t timeout);
477
478 /**
479 * @brief Remove an observer from a channel.
480 *
481 * This routine removes an observer to the channel.
482 *
483 * @param chan The channel's reference.
484 * @param obs The observer's reference to be removed.
485 * @param timeout Waiting period to remove an observer,
486 * or one of the special values K_NO_WAIT and K_FOREVER.
487 *
488 * @retval 0 Observer removed to the channel.
489 * @retval -EINVAL Invalid data supplied.
490 * @retval -EBUSY Returned without waiting.
491 * @retval -EAGAIN Waiting period timed out.
492 * @retval -ENODATA no observer found in channel's runtime observer list.
493 * @retval -ENOMEM Returned without waiting.
494 */
495 int zbus_chan_rm_obs(const struct zbus_channel *chan, const struct zbus_observer *obs,
496 k_timeout_t timeout);
497
498 /**
499 * @brief Get zbus runtime observers pool.
500 *
501 * This routine returns a reference of the runtime observers pool.
502 *
503 * @return Reference of runtime observers pool.
504 */
505 struct k_mem_slab *zbus_runtime_obs_pool(void);
506
507 /** @cond INTERNAL_HIDDEN */
508
509 struct zbus_observer_node {
510 sys_snode_t node;
511 const struct zbus_observer *obs;
512 };
513
514 /** @endcond */
515
516 #endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE */
517
518 /**
519 * @brief Change the observer state.
520 *
521 * This routine changes the observer state. A channel when disabled will not receive
522 * notifications from the event dispatcher.
523 *
524 * @param[in] obs The observer's reference.
525 * @param[in] enabled State to be. When false the observer stops to receive notifications.
526 *
527 * @retval 0 Observer set enable.
528 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
529 * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled.
530 */
zbus_obs_set_enable(struct zbus_observer * obs,bool enabled)531 static inline int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled)
532 {
533 _ZBUS_ASSERT(obs != NULL, "obs is required");
534
535 obs->enabled = enabled;
536
537 return 0;
538 }
539
540 #if defined(CONFIG_ZBUS_OBSERVER_NAME) || defined(__DOXYGEN__)
541
542 /**
543 * @brief Get the observer's name.
544 *
545 * This routine returns the observer's name reference.
546 *
547 * @param obs The observer's reference.
548 *
549 * @return The observer's name reference.
550 */
zbus_obs_name(const struct zbus_observer * obs)551 static inline const char *zbus_obs_name(const struct zbus_observer *obs)
552 {
553 __ASSERT(obs != NULL, "obs is required");
554
555 return obs->name;
556 }
557
558 #endif
559
560 /**
561 * @brief Wait for a channel notification.
562 *
563 * This routine makes the subscriber to wait a notification. The notification comes as a channel
564 * reference.
565 *
566 * @param[in] sub The subscriber's reference.
567 * @param[out] chan The notification channel's reference.
568 * @param[in] timeout Waiting period for a notification arrival,
569 * or one of the special values K_NO_WAIT and K_FOREVER.
570 *
571 * @retval 0 Notification received.
572 * @retval -ENOMSG Returned without waiting.
573 * @retval -EAGAIN Waiting period timed out.
574 * @retval -EINVAL The observer is not a subscriber.
575 * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The
576 * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled.
577 */
578 int zbus_sub_wait(const struct zbus_observer *sub, const struct zbus_channel **chan,
579 k_timeout_t timeout);
580
581 #if defined(CONFIG_ZBUS_STRUCTS_ITERABLE_ACCESS) || defined(__DOXYGEN__)
582 /**
583 *
584 * @brief Iterate over channels.
585 *
586 * Enables the developer to iterate over the channels giving to this function an
587 * iterator_func which is called for each channel. If the iterator_func returns false all
588 * the iteration stops.
589 *
590 * @retval true Iterator executed for all channels.
591 * @retval false Iterator could not be executed. Some iterate returned false.
592 */
593 bool zbus_iterate_over_channels(bool (*iterator_func)(const struct zbus_channel *chan));
594
595 /**
596 *
597 * @brief Iterate over observers.
598 *
599 * Enables the developer to iterate over the observers giving to this function an
600 * iterator_func which is called for each observer. If the iterator_func returns false all
601 * the iteration stops.
602 *
603 * @retval true Iterator executed for all channels.
604 * @retval false Iterator could not be executed. Some iterate returned false.
605 */
606 bool zbus_iterate_over_observers(bool (*iterator_func)(const struct zbus_observer *obs));
607
608 #endif /* CONFIG_ZBUS_STRUCTS_ITERABLE_ACCESS */
609 /**
610 * @}
611 */
612
613 #ifdef __cplusplus
614 }
615 #endif
616
617 #endif /* ZEPHYR_INCLUDE_ZBUS_H_ */
618