1 /*
2  * Copyright (c) 2022 Rodrigo Peixoto <rodrigopex@gmail.com>
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/kernel.h>
7 #include <zephyr/logging/log.h>
8 #include <zephyr/zbus/zbus.h>
9 #include <zephyr/ztest.h>
10 LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL);
11 
12 struct sensor_data_msg {
13 	int a;
14 	int b;
15 };
16 
17 ZBUS_CHAN_DEFINE(chan1,			 /* Name */
18 		 struct sensor_data_msg, /* Message type */
19 
20 		 NULL,		       /* Validator */
21 		 NULL,		       /* User data */
22 		 ZBUS_OBSERVERS_EMPTY, /* observers */
23 		 ZBUS_MSG_INIT(0)      /* Initial value major 0, minor 1, build 1023 */
24 );
25 
26 ZBUS_CHAN_DEFINE(chan2,			 /* Name */
27 		 struct sensor_data_msg, /* Message type */
28 
29 		 NULL,		       /* Validator */
30 		 NULL,		       /* User data */
31 		 ZBUS_OBSERVERS(lis2), /* observers */
32 		 ZBUS_MSG_INIT(0)      /* Initial value major 0, minor 1, build 1023 */
33 );
34 
35 ZBUS_CHAN_DEFINE(chan3,			 /* Name */
36 		 struct sensor_data_msg, /* Message type */
37 
38 		 NULL,		       /* Validator */
39 		 NULL,		       /* User data */
40 		 ZBUS_OBSERVERS_EMPTY, /* observers */
41 		 ZBUS_MSG_INIT(0)      /* Initial value major 0, minor 1, build 1023 */
42 );
43 
44 ZBUS_SUBSCRIBER_DEFINE(sub1, 1);
45 ZBUS_SUBSCRIBER_DEFINE(sub2, 1);
46 
47 static int count_callback1;
callback1(const struct zbus_channel * chan)48 static void callback1(const struct zbus_channel *chan)
49 {
50 	++count_callback1;
51 }
52 
53 ZBUS_LISTENER_DEFINE(lis1, callback1);
54 
55 static int count_callback2;
callback2(const struct zbus_channel * chan)56 static void callback2(const struct zbus_channel *chan)
57 {
58 	++count_callback2;
59 }
60 
61 ZBUS_LISTENER_DEFINE(lis2, callback2);
62 ZBUS_LISTENER_DEFINE(lis3, callback2);
63 ZBUS_LISTENER_DEFINE(lis4, callback2);
64 ZBUS_LISTENER_DEFINE(lis5, callback2);
65 ZBUS_LISTENER_DEFINE(lis6, callback2);
66 ZBUS_LISTENER_DEFINE(lis7, callback2);
67 
ZTEST(basic,test_specification_based__zbus_obs_add_rm_obs)68 ZTEST(basic, test_specification_based__zbus_obs_add_rm_obs)
69 {
70 	count_callback1 = 0;
71 	struct sensor_data_msg sd = {.a = 10, .b = 100};
72 
73 	/* Tyring to add same static observer as one dynamic */
74 	zassert_equal(-EEXIST, zbus_chan_add_obs(&chan2, &lis2, K_MSEC(200)), NULL);
75 
76 	zassert_equal(0, zbus_chan_pub(&chan1, &sd, K_MSEC(500)), NULL);
77 	zassert_equal(count_callback1, 0, "The counter could not be more than zero, no obs");
78 
79 	zassert_equal(0, zbus_chan_add_obs(&chan1, &lis1, K_MSEC(200)), NULL);
80 	zassert_equal(-EALREADY, zbus_chan_add_obs(&chan1, &lis1, K_MSEC(200)),
81 		      "It cannot be added twice");
82 
83 	zassert_equal(0, zbus_chan_pub(&chan1, &sd, K_MSEC(500)), NULL);
84 	zassert_equal(count_callback1, 1, "The counter could not be more than zero, no obs, %d",
85 		      count_callback1);
86 
87 	zassert_equal(0, zbus_chan_rm_obs(&chan1, &lis1, K_MSEC(200)), "It must remove the obs");
88 
89 	zassert_equal(-ENODATA, zbus_chan_rm_obs(&chan1, &lis1, K_MSEC(200)),
90 		      "It cannot be removed twice");
91 
92 	zassert_equal(0, zbus_chan_pub(&chan1, &sd, K_MSEC(500)), NULL);
93 	zassert_equal(count_callback1, 1, "The counter could not be more than zero, no obs, %d",
94 		      count_callback1);
95 
96 	count_callback2 = 0;
97 
98 	zassert_equal(0, zbus_chan_pub(&chan2, &sd, K_MSEC(500)), NULL);
99 	zassert_equal(count_callback2, 1, "The counter could not be more than zero, no obs");
100 
101 	zassert_equal(0, zbus_chan_add_obs(&chan2, &lis3, K_MSEC(200)), NULL);
102 
103 	zassert_equal(-EALREADY, zbus_chan_add_obs(&chan2, &lis3, K_MSEC(200)),
104 		      "It cannot be added twice");
105 
106 	zassert_equal(0, zbus_chan_pub(&chan2, &sd, K_MSEC(500)), NULL);
107 	zassert_equal(count_callback2, 3, "The counter could not be more than zero, no obs, %d",
108 		      count_callback2);
109 	count_callback2 = 0;
110 	zassert_equal(0, zbus_chan_add_obs(&chan2, &sub1, K_MSEC(200)), NULL);
111 	zassert_equal(0, zbus_chan_add_obs(&chan2, &sub2, K_MSEC(200)), NULL);
112 	zassert_equal(0, zbus_chan_add_obs(&chan2, &lis4, K_MSEC(200)), "It must add the obs");
113 	zassert_equal(0, zbus_chan_add_obs(&chan2, &lis5, K_MSEC(200)), "It must add the obs");
114 	zassert_equal(0, zbus_chan_add_obs(&chan2, &lis6, K_MSEC(200)), "It must add the obs");
115 
116 	/* Make the heap full */
117 	void *mem;
118 
119 	do {
120 		mem = k_malloc(1);
121 	} while (mem != NULL);
122 
123 	/* With the heap full it will not be possible to add another obs */
124 	zassert_equal(-ENOMEM, zbus_chan_add_obs(&chan2, &lis7, K_MSEC(200)), NULL);
125 	zassert_equal(0, zbus_chan_pub(&chan2, &sd, K_MSEC(500)), NULL);
126 	zassert_equal(count_callback2, 5, NULL);
127 
128 	/* To cause an error to sub1 and sub2. They have the queue full in this point */
129 	/* ENOMSG must be the result */
130 	zassert_equal(-ENOMSG, zbus_chan_pub(&chan2, &sd, K_MSEC(500)), NULL);
131 	zassert_equal(count_callback2, 10, NULL);
132 
133 	zassert_equal(0, zbus_chan_rm_obs(&chan2, &sub1, K_MSEC(200)), NULL);
134 	zassert_equal(0, zbus_chan_rm_obs(&chan2, &sub2, K_MSEC(200)), NULL);
135 }
136 
137 struct aux2_wq_data {
138 	struct k_work work;
139 };
140 
141 static struct aux2_wq_data wq_handler;
142 
wq_dh_cb(struct k_work * item)143 static void wq_dh_cb(struct k_work *item)
144 {
145 	zassert_equal(-EAGAIN, zbus_chan_add_obs(&chan2, &sub1, K_MSEC(200)), NULL);
146 	zassert_equal(-EAGAIN, zbus_chan_rm_obs(&chan2, &sub2, K_MSEC(200)), NULL);
147 }
148 
ZTEST(basic,test_specification_based__zbus_obs_add_rm_obs_busy)149 ZTEST(basic, test_specification_based__zbus_obs_add_rm_obs_busy)
150 {
151 	zassert_equal(0, zbus_chan_claim(&chan2, K_NO_WAIT), NULL);
152 
153 	k_work_init(&wq_handler.work, wq_dh_cb);
154 	k_work_submit(&wq_handler.work);
155 	k_msleep(1000);
156 
157 	zassert_equal(0, zbus_chan_finish(&chan2), NULL);
158 }
159 
160 ZBUS_CHAN_DEFINE(chan4,                  /* Name */
161 		 struct sensor_data_msg, /* Message type */
162 
163 		 NULL,                                 /* Validator */
164 		 NULL,                                 /* User data */
165 		 ZBUS_OBSERVERS(prio_lis6, prio_lis5), /* observers */
166 		 ZBUS_MSG_INIT(0) /* Initial value major 0, minor 1, build 1023 */
167 );
168 
169 static int execution_sequence_idx;
170 static uint8_t execution_sequence[6] = {0};
171 
172 #define CALLBACK_DEF(_lis, _idx)                                                                   \
173 	static void _CONCAT(prio_cb, _idx)(const struct zbus_channel *chan)                        \
174 	{                                                                                          \
175 		execution_sequence[execution_sequence_idx] = _idx;                                 \
176 		++execution_sequence_idx;                                                          \
177 	}                                                                                          \
178 	ZBUS_LISTENER_DEFINE(_lis, _CONCAT(prio_cb, _idx))
179 
180 CALLBACK_DEF(prio_lis1, 1);
181 CALLBACK_DEF(prio_lis2, 2);
182 CALLBACK_DEF(prio_lis3, 3);
183 CALLBACK_DEF(prio_lis4, 4);
184 CALLBACK_DEF(prio_lis5, 5);
185 CALLBACK_DEF(prio_lis6, 6);
186 
187 ZBUS_CHAN_ADD_OBS(chan4, prio_lis3, 3);
188 ZBUS_CHAN_ADD_OBS(chan4, prio_lis4, 2);
189 
190 /* Checking the ZBUS_CHAN_ADD_OBS. The execution sequence must be: 6, 5, 4, 3, 2, 1. */
191 
ZTEST(basic,test_specification_based__zbus_obs_priority)192 ZTEST(basic, test_specification_based__zbus_obs_priority)
193 {
194 	struct sensor_data_msg sd = {.a = 70, .b = 116};
195 
196 	execution_sequence_idx = 0;
197 
198 	zassert_equal(0, zbus_chan_add_obs(&chan4, &prio_lis2, K_MSEC(200)), NULL);
199 	zassert_equal(0, zbus_chan_add_obs(&chan4, &prio_lis1, K_MSEC(200)), NULL);
200 
201 	zassert_equal(0, zbus_chan_pub(&chan4, &sd, K_MSEC(500)), NULL);
202 
203 	zassert_equal(execution_sequence[0], 6, NULL);
204 	zassert_equal(execution_sequence[1], 5, NULL);
205 	zassert_equal(execution_sequence[2], 4, NULL);
206 	zassert_equal(execution_sequence[3], 3, NULL);
207 	zassert_equal(execution_sequence[4], 2, NULL);
208 	zassert_equal(execution_sequence[5], 1, NULL);
209 }
210 
211 ZTEST_SUITE(basic, NULL, NULL, NULL, NULL, NULL);
212