1 /*
2  * Copyright (c) 2022 Rodrigo Peixoto <rodrigopex@gmail.com>
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <stdint.h>
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/logging/log.h>
10 #include <zephyr/zbus/zbus.h>
11 LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL);
12 
13 struct version_msg {
14 	uint8_t major;
15 	uint8_t minor;
16 	uint16_t build;
17 };
18 
19 struct acc_msg {
20 	int x;
21 	int y;
22 	int z;
23 };
24 
25 ZBUS_CHAN_DEFINE(version_chan,       /* Name */
26 		 struct version_msg, /* Message type */
27 
28 		 NULL,                 /* Validator */
29 		 NULL,                 /* User data */
30 		 ZBUS_OBSERVERS_EMPTY, /* observers */
31 		 ZBUS_MSG_INIT(.major = 0, .minor = 1,
32 			       .build = 2) /* Initial value major 0, minor 1, build 2 */
33 );
34 
35 ZBUS_CHAN_DEFINE(acc_data_chan,  /* Name */
36 		 struct acc_msg, /* Message type */
37 
38 		 NULL,                                 /* Validator */
39 		 NULL,                                 /* User data */
40 		 ZBUS_OBSERVERS(foo_lis, bar_sub),     /* observers */
41 		 ZBUS_MSG_INIT(.x = 0, .y = 0, .z = 0) /* Initial value */
42 );
43 
simple_chan_validator(const void * msg,size_t msg_size)44 static bool simple_chan_validator(const void *msg, size_t msg_size)
45 {
46 	ARG_UNUSED(msg_size);
47 
48 	const int *simple = msg;
49 
50 	if ((*simple >= 0) && (*simple < 10)) {
51 		return true;
52 	}
53 
54 	return false;
55 }
56 
57 ZBUS_CHAN_DEFINE(simple_chan, /* Name */
58 		 int,         /* Message type */
59 
60 		 simple_chan_validator, /* Validator */
61 		 NULL,                  /* User data */
62 		 ZBUS_OBSERVERS_EMPTY,  /* observers */
63 		 0                      /* Initial value is 0 */
64 );
65 
listener_callback_example(const struct zbus_channel * chan)66 static void listener_callback_example(const struct zbus_channel *chan)
67 {
68 	const struct acc_msg *acc = zbus_chan_const_msg(chan);
69 
70 	LOG_INF("From listener -> Acc x=%d, y=%d, z=%d", acc->x, acc->y, acc->z);
71 }
72 
73 ZBUS_LISTENER_DEFINE(foo_lis, listener_callback_example);
74 
75 ZBUS_SUBSCRIBER_DEFINE(bar_sub, 4);
76 
subscriber_task(void)77 static void subscriber_task(void)
78 {
79 	const struct zbus_channel *chan;
80 
81 	while (!zbus_sub_wait(&bar_sub, &chan, K_FOREVER)) {
82 		struct acc_msg acc;
83 
84 		if (&acc_data_chan == chan) {
85 			zbus_chan_read(&acc_data_chan, &acc, K_MSEC(500));
86 
87 			LOG_INF("From subscriber -> Acc x=%d, y=%d, z=%d", acc.x, acc.y, acc.z);
88 		}
89 	}
90 }
91 
92 K_THREAD_DEFINE(subscriber_task_id, CONFIG_MAIN_STACK_SIZE, subscriber_task, NULL, NULL, NULL, 3, 0,
93 		0);
94 
print_channel_data_iterator(const struct zbus_channel * chan,void * user_data)95 static bool print_channel_data_iterator(const struct zbus_channel *chan, void *user_data)
96 {
97 	int *count = user_data;
98 
99 	LOG_INF("%d - Channel %s:", *count, zbus_chan_name(chan));
100 	LOG_INF("      Message size: %d", zbus_chan_msg_size(chan));
101 	LOG_INF("      Observers:");
102 
103 	++(*count);
104 
105 	struct zbus_channel_observation *observation;
106 
107 	for (int16_t i = chan->data->observers_start_idx, limit = chan->data->observers_end_idx;
108 	     i < limit; ++i) {
109 		STRUCT_SECTION_GET(zbus_channel_observation, i, &observation);
110 
111 		__ASSERT(observation != NULL, "observation must be not NULL");
112 
113 		LOG_INF("      - %s", observation->obs->name);
114 	}
115 
116 	struct zbus_observer_node *obs_nd, *tmp;
117 
118 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&chan->data->observers, obs_nd, tmp, node) {
119 		LOG_INF("      - %s", obs_nd->obs->name);
120 	}
121 
122 	return true;
123 }
124 
print_observer_data_iterator(const struct zbus_observer * obs,void * user_data)125 static bool print_observer_data_iterator(const struct zbus_observer *obs, void *user_data)
126 {
127 	int *count = user_data;
128 
129 	LOG_INF("%d - %s %s", *count,
130 		obs->type == ZBUS_OBSERVER_LISTENER_TYPE ? "Listener" : "Subscriber",
131 		zbus_obs_name(obs));
132 
133 	++(*count);
134 
135 	return true;
136 }
137 
main(void)138 int main(void)
139 {
140 	int err, value;
141 	struct acc_msg acc1 = {.x = 1, .y = 1, .z = 1};
142 	const struct version_msg *v = zbus_chan_const_msg(&version_chan);
143 
144 	LOG_INF("Sensor sample started raw reading, version %u.%u-%u!", v->major, v->minor,
145 		v->build);
146 
147 	int count = 0;
148 
149 	LOG_INF("Channel list:");
150 	zbus_iterate_over_channels_with_user_data(print_channel_data_iterator, &count);
151 
152 	count = 0;
153 
154 	LOG_INF("Observers list:");
155 	zbus_iterate_over_observers_with_user_data(print_observer_data_iterator, &count);
156 	zbus_chan_pub(&acc_data_chan, &acc1, K_SECONDS(1));
157 
158 	k_msleep(1000);
159 
160 	acc1.x = 2;
161 	acc1.y = 2;
162 	acc1.z = 2;
163 	zbus_chan_pub(&acc_data_chan, &(acc1), K_SECONDS(1));
164 
165 	value = 5;
166 	err = zbus_chan_pub(&simple_chan, &value, K_MSEC(200));
167 
168 	if (err == 0) {
169 		LOG_INF("Pub a valid value to a channel with validator successfully.");
170 	}
171 
172 	value = 15;
173 	err = zbus_chan_pub(&simple_chan, &value, K_MSEC(200));
174 
175 	if (err == -ENOMSG) {
176 		LOG_INF("Pub an invalid value to a channel with validator successfully.");
177 	}
178 	return 0;
179 }
180