Lines Matching +full:channel +full:- +full:count

9    https://www.figma.com/community/file/1292866458780627559/zbus-diagram-assets
12 The :dfn:`Zephyr bus - zbus` is a lightweight and flexible software bus enabling a simple way for
13 threads to talk to one another in a many-to-many way.
21 Threads can send messages to one or more observers using zbus. It makes the many-to-many
22 communication possible. The bus implements message-passing and publish/subscribe communication
25 The communication through zbus is channel-based. Threads (or callbacks) use channels to exchange
27 thread publishes a message on a channel, the bus will make the message available to all the
28 published channel's observers. Based on the observer's type, it can access the message directly,
29 receive a copy of it, or even receive only a reference of the published channel.
48 channel, it also propagates the notifications to the observers;
60 including ISRs. The publish and read operations are simple and fast; the procedure is channel
61 locking followed by a memory copy to and from a shared memory region and then a channel unlocking.
70 * Listeners, a callback that the event dispatcher executes every time an observed channel is
72 * Subscriber, a thread-based observer that relies internally on a message queue where the event
73 dispatcher puts a changed channel's reference every time an observed channel is published or
75 message from the channel after receiving the notification;
76 * Message subscribers, a thread-based observer that relies internally on a FIFO where the event
77 dispatcher puts a copy of the message every time an observed channel is published or notified.
79 Channel observation structures define the relationship between a channel and its observers. For
80 every observation, a pair channel/observer. Developers can statically allocate observation using the
96 sending notifications from channel ``C3``. In (d), the event dispatcher will stop sending
100 Suppose a usual sensor-based solution is in the figure below for illustration purposes. When
101 triggered, the timer publishes to the ``Trigger`` channel. As the sensor thread subscribed to the
102 ``Trigger`` channel, it receives the sensor data. Notice the VDED executes the ``Blink`` because it
103 also listens to the ``Trigger`` channel. When the sensor data is ready, the sensor thread publishes
104 it to the ``Sensor data`` channel. The core thread receives the message as a ``Sensor data`` channel
107 buffer information, prepares a package, and publishes that to the ``Payload`` channel. The Lora
108 thread receives that because it is a ``Payload`` channel message subscriber and sends the payload to
110 done`` channel. The VDED executes the ``Blink`` again since it listens to the ``Transmission done``
111 channel.
114 :alt: ZBus sensor-based application
117 ZBus sensor-based application.
128 well-defined behaviors (we call that module) only uses zbus channels and not hardware interfaces, it
132 The last important note is the zbus solution reach. We can count on many ways of using zbus to
135 control the channel in so many different ways claiming the channel, developers can add their
136 metadata information to a channel by using the user-data field, the discretionary use of a validator
138 the solutions that can be done with zbus and make it a good fit as an open-source community tool.
151 * The channel lock is acquired;
152 * The channel receives the new message via direct copy (by a raw :c:func:`memcpy`);
154 subscribers, and pushes the channel's reference to the subscribers' notification message queue in
155 the same sequence they appear on the channel observers' list. The listeners can perform non-copy
157 function) since the channel is still locked;
158 * At last, the publishing function unlocks the channel.
163 ``L1`` and ``L2``; and channel A. Supposing ``L1``, ``L2``, ``MS1``, ``MS2``, and ``S1`` observer
164 channel A.
173 The following code implements channel A. Note the ``struct a_msg`` is illustrative only.
175 .. code-block:: c
187 In the figure below, the letters indicate some action related to the VDED execution. The X-axis
188 represents the time, and the Y-axis represents the priority of threads. Channel A's message,
202 channel A. Thus, the table below describes the activities (represented by a letter) of the VDED
207 .. list-table:: VDED execution steps in detail for priority T1 > MS1 > MS2 > S1.
209 :header-rows: 1
211 * - Actions
212 - Description
213 * - a
214 - T1 starts and, at some point, publishes to channel A.
215 * - b
216 - The publishing (VDED) process starts. The VDED locks the channel A.
217 * - c
218 - The VDED copies the T1 message to the channel A message.
220 * - d, e
221 - The VDED executes L1 and L2 in the respective sequence. Inside the listeners, usually, there
223 reference to channel A's message. It is quick, and no copy is needed here.
225 * - f, g
226 - The VDED copies the message and sends that to MS1 and MS2 sequentially. Notice the threads
229 * - h
230 - The VDED pushes the notification message to the queue of S1. Notice the thread gets ready to
232 it cannot access the channel since it is still locked.
234 * - i
235 - VDED finishes the publishing by unlocking channel A. The MS1 leaves the pending state and
238 * - j
239 - MS1 finishes execution. The MS2 leaves the pending state and starts executing.
241 * - k
242 - MS2 finishes execution. The S1 leaves the pending state and starts executing.
244 * - l, m, n
245 - The S1 leaves the pending state since channel A is not locked. It gets in the CPU again and
246 … starts executing. As it did receive a notification from channel A, it performed a channel read
249 * - o
250 - S1 finishes its workload.
254 channel A. The scenario considers the following priorities: T1 < MS1 < MS2 < S1.
264 .. list-table:: VDED execution steps in detail for priority T1 < MS1 < MS2 < S1.
266 :header-rows: 1
268 * - Actions
269 - Description
270 * - a
271 - T1 starts and, at some point, publishes to channel A.
272 * - b
273 - The publishing (VDED) process starts. The VDED locks the channel A.
274 * - c
275 - The VDED copies the T1 message to the channel A message.
277 * - d, e
278 - The VDED executes L1 and L2 in the respective sequence. Inside the listeners, usually, there
280 reference to channel A's message. It is quick, and no copy is needed here.
282 * - f
283 - The VDED copies the message and sends that to MS1. MS1 preempts T1 and starts working.
286 * - g
287 - The VDED copies the message and sends that to MS2. MS2 preempts T1 and starts working.
290 * - h
291 - The VDED pushes the notification message to the queue of S1.
293 * - i
294 - VDED finishes the publishing by unlocking channel A.
296 * - j, k, l
297 - The S1 leaves the pending state since channel A is not locked. It gets in the CPU again and
298 starts executing. As it did receive a notification from channel A, it performs a channel read
303 ------------------
305 determine a temporary publisher priority. The protocol considers the channel's Highest Observer
306 Priority (HOP); even if the observer is not waiting for a message on the channel, it is considered
318 channel A. The scenario considers the priority boost feature and the following priorities: T1 < MS1
329 consider the observer's priority. The following code illustrates the thread-attaching function.
332 .. code-block:: c
333 :emphasize-lines: 10
358 will be considered on the channel HOP calculation. Masking a specific observation of a channel will
359 affect the channel HOP.
371 * The priority boosting feature can be turned off, and plain semaphores can be used as the channel
373 * The Highest Locker Protocol's major disadvantage, the Inheritance-related Priority Inversion, is
383 high-speed stream of bytes between threads. The :ref:`Pipe <pipes_v2>` kernel object solves this
387 -------------------
394 * Keep the listeners quick-as-possible (deal with them as ISRs). If some processing is needed,
395 consider submitting a work item to a work-queue;
408 at the :zephyr:code-sample:`zbus-msg-subscriber` to see the isolation in action.
411 Subscribers will receive only the reference of the changing channel. A data loss may be perceived
412 if the channel is published twice before the subscriber reads it. The second publication
420 -------------------------
424 #. Observers defined in a channel using the :c:macro:`ZBUS_CHAN_DEFINE` (following the definition
438 message and observers list during the channel definition. A message is a regular C struct; the
442 The following code defines and initializes a regular channel and its dependencies. This channel
445 .. code-block:: c
468 LOG_DBG("From listener -> Acc x=%d, y=%d, z=%d", acc->x, acc->y, acc->z);
489 LOG_DBG("From subscriber -> Acc x=%d, y=%d, z=%d", acc.x, acc.y, acc.z);
507 … LOG_INF("From msg subscriber -> Acc x=%d, y=%d, z=%d", acc.x, acc.y, acc.z);
515 It is possible to add static observers to a channel using the :c:macro:`ZBUS_CHAN_ADD_OBS`. We call
516 that a post-definition static observer. The command enables us to indicate an initialization
518 the post-definition static observers. There is no possibility to overwrite the message delivery
522 It is unnecessary to claim/lock a channel before accessing the message inside the listener since
523 the event dispatcher calls listeners with the notifying channel already locked. Subscribers,
528 Channels can have a *validator function* that enables a channel to accept only valid messages.
530 allows original creators of a channel to exert some authority over other developers/publishers who
531 may want to piggy-back on their channels. The following code defines and initializes a :dfn:`hard
532 channel` and its dependencies. Only valid messages can be published to a :dfn:`hard channel`. It is
533 possible because a *validator function* was passed to the channel's definition. In this example,
534 only messages with ``move`` equal to 0, -1, and 1 are valid. Publish function will discard all other
537 .. code-block:: c
545 bool is_valid = (cm->move == -1) || (cm->move == 0) || (cm->move == 1);
563 .. _publishing to a channel:
565 Publishing to a channel
568 Messages are published to a channel in zbus by calling :c:func:`zbus_chan_pub`. For example, the
569 following code builds on the examples above and publishes to channel ``acc_chan``. The code is
570 trying to publish the message ``acc1`` to channel ``acc_chan``, and it will wait up to one second
574 .. code-block:: c
582 .. _reading from a channel: argument
584 Reading from a channel
587 Messages are read from a channel in zbus by calling :c:func:`zbus_chan_read`. So, for example, the
588 following code tries to read the channel ``acc_chan``, which will wait up to 500 milliseconds to
591 .. code-block:: c
601 :c:func:`zbus_sub_wait` carefully because the channel will always be unavailable during the VDED
607 Notifying a channel
610 It is possible to force zbus to notify a channel's observers by calling :c:func:`zbus_chan_notify`.
612 channel ``acc_chan``. Note this can send events with no message, which does not require any data
613 exchange. See the code example under `Claim and finish a channel`_ where this may become useful.
615 .. code-block:: c
627 words, zbus channel definitions and declarations with the same channel names in different files
628 would point to the same (global) channel. Thus, developers should be careful about existing
630 channel or observer on the same call. The following code builds on the examples above and displays
633 .. code-block:: c
651 .. code-block:: c
655 int *count = user_data;
657 LOG_INF("%d - Channel %s:", *count, zbus_chan_name(chan));
661 ++(*count);
665 for (int16_t i = *chan->observers_start_idx, limit = *chan->observers_end_idx; i < limit;
669 LOG_INF(" - %s", observation->obs->name);
674 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(chan->observers, obs_nd, tmp, node) {
675 LOG_INF(" - %s", obs_nd->obs->name);
683 int *count = user_data;
685 LOG_INF("%d - %s %s", *count, obs->queue ? "Subscriber" : "Listener", zbus_obs_name(obs));
687 ++(*count);
694 int count = 0;
696 LOG_INF("Channel list:");
698 zbus_iterate_over_channels_with_user_data(print_channel_data_iterator, &count);
700 count = 0;
704 zbus_iterate_over_observers_with_user_data(print_observer_data_iterator, &count);
712 .. code-block:: console
714 D: Channel list:
715 D: 0 - Channel acc_chan:
718 D: - my_listener
719 D: - my_subscriber
720 D: 1 - Channel version_chan:
724 D: 0 - Listener my_listener
725 D: 1 - Subscriber my_subscriber
728 .. _Claim and finish a channel:
730 Advanced channel control
737 ------------------------
739 For performance purposes, listeners can access the receiving channel message directly since they
740 already have the channel locked for it. To access the channel's message, the listener should use the
741 :c:func:`zbus_chan_const_msg` because the channel passed as an argument to the listener function is
742 a constant pointer to the channel. The const pointer return type tells developers not to modify the
745 .. code-block:: c
755 LOG_DBG("From listener -> Acc x=%d, y=%d, z=%d", acc->x, acc->y, acc->z);
760 ---------
761 It is possible to pass custom data into the channel's ``user_data`` for various purposes, such as
762 writing channel metadata. That can be achieved by passing a pointer to the channel definition
764 individual for each channel. Also, note that ``user_data`` access is not thread-safe. For
765 thread-safe access to ``user_data``, see the next section.
768 Claim and finish a channel
769 --------------------------
772 :c:func:`zbus_chan_finish`. With these functions, it is possible to access the channel's metadata
773 safely. When a channel is claimed, no actions are available to that channel. After finishing the
774 channel, all the actions are available again.
777 Never change the fields of the channel struct directly. It may cause zbus behavior
784 to the channel. Suppose we would like to count how many times the channels exchange messages. We
788 .. code-block:: c
796 The following code has the exact behavior of the code in :ref:`publishing to a channel`.
798 .. code-block:: c
809 The following code has the exact behavior of the code in :ref:`reading from a channel`.
811 .. code-block:: c
821 -----------------------------
831 .. code-block:: c
837 /* Adding the observer to channel chan1 */
839 /* Removing the observer from channel chan1 */
849 * :zephyr:code-sample:`zbus-hello-world` illustrates the code used above in action;
850 * :zephyr:code-sample:`zbus-work-queue` shows how to define and use different kinds of observers.
853 * :zephyr:code-sample:`zbus-msg-subscriber` illustrates how to use message subscribers;
854 * :zephyr:code-sample:`zbus-dyn-channel` demonstrates how to use dynamically allocated exchanging
856 * :zephyr:code-sample:`zbus-uart-bridge` shows an example of sending the operation of the channel to
858 * :zephyr:code-sample:`zbus-remote-mock` illustrates how to implement an external mock (on the host)
860 * :zephyr:code-sample:`zbus-priority-boost` illustrates zbus priority boost feature with a priority
862 * :zephyr:code-sample:`zbus-runtime-obs-registration` illustrates a way of using the runtime
864 * :zephyr:code-sample:`zbus-confirmed-channel` implements a way of implement confirmed channel only
866 * :zephyr:code-sample:`zbus-benchmark` implements a benchmark with different combinations of inputs.
871 Use zbus to transfer data (messages) between threads in one-to-one, one-to-many, and many-to-many
892 priority used by zbus to organize the channels observations by channel;