1 /*
2 * Copyright (c) 2023 Nordic Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Composition Data Page 1 (CDP1) test
7 */
8
9 #include "mesh_test.h"
10
11 #include <stddef.h>
12 #include <string.h>
13 #include <mesh/access.h>
14 #include <mesh/net.h>
15
16 #include <zephyr/logging/log.h>
17 #define LOG_MODULE_NAME test_cdp1
18 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
19
20 #define NODE_ADDR 0x00a1
21 #define WAIT_TIME 60 /* seconds */
22
23 #define TEST_MODEL_ID_1 0x2a2a
24 #define TEST_MODEL_ID_2 0x2b2b
25 #define TEST_MODEL_ID_3 0x2c2c
26 #define TEST_MODEL_ID_4 0x2d2d
27 #define TEST_MODEL_ID_5 0x2e2e
28 #define TEST_MODEL_ID_6 0x2f2f
29 #define TEST_VND_MODEL_ID_1 0x3a3a
30
31 #define TEST_MODEL_DECLARE(number) \
32 static int model_##number##_init(struct bt_mesh_model *model); \
33 static const struct bt_mesh_model_cb test_model_##number##_cb = { \
34 .init = model_##number##_init, \
35 }; \
36 static const struct bt_mesh_model_op model_op_##number[] = { \
37 BT_MESH_MODEL_OP_END, \
38 };
39
40 TEST_MODEL_DECLARE(1);
41 TEST_MODEL_DECLARE(2);
42 TEST_MODEL_DECLARE(3);
43 TEST_MODEL_DECLARE(4);
44 TEST_MODEL_DECLARE(5);
45 TEST_MODEL_DECLARE(6);
46 TEST_MODEL_DECLARE(vnd1);
47
48 static uint8_t app_key[16] = {0xaa};
49 static uint8_t net_key[16] = {0xcc};
50
51 static const struct bt_mesh_test_cfg node_1_cfg = {
52 .addr = NODE_ADDR,
53 .dev_key = {0xaa},
54 };
55
56 static struct bt_mesh_prov prov;
57 static struct bt_mesh_cfg_cli cfg_cli;
58
59 static struct bt_mesh_model models_1[] = {
60 BT_MESH_MODEL_CFG_SRV,
61 BT_MESH_MODEL_CFG_CLI(&cfg_cli),
62 BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_op_1, NULL, NULL, &test_model_1_cb),
63 BT_MESH_MODEL_CB(TEST_MODEL_ID_2, model_op_2, NULL, NULL, &test_model_2_cb),
64 BT_MESH_MODEL_CB(TEST_MODEL_ID_3, model_op_3, NULL, NULL, &test_model_3_cb),
65 };
66
67 static struct bt_mesh_model models_2[] = {
68 BT_MESH_MODEL_CB(TEST_MODEL_ID_4, model_op_4, NULL, NULL, &test_model_4_cb),
69 };
70
71 static struct bt_mesh_model models_3[] = {
72 BT_MESH_MODEL_CB(TEST_MODEL_ID_5, model_op_5, NULL, NULL, &test_model_5_cb),
73 };
74
75 static struct bt_mesh_model models_4[] = {
76 BT_MESH_MODEL_CB(TEST_MODEL_ID_6, model_op_6, NULL, NULL, &test_model_6_cb),
77 };
78
79 static struct bt_mesh_model models_vnd1[] = {
80 BT_MESH_MODEL_VND_CB(TEST_VND_COMPANY_ID, TEST_VND_MODEL_ID_1, model_op_vnd1, NULL, NULL,
81 &test_model_vnd1_cb),
82 };
83
84 static struct bt_mesh_elem elems[] = {
85 BT_MESH_ELEM(0, models_1, models_vnd1),
86 BT_MESH_ELEM(1, models_2, BT_MESH_MODEL_NONE),
87 BT_MESH_ELEM(2, models_3, BT_MESH_MODEL_NONE),
88 BT_MESH_ELEM(3, models_3, BT_MESH_MODEL_NONE),
89 BT_MESH_ELEM(4, models_4, BT_MESH_MODEL_NONE),
90 };
91
92 static const struct bt_mesh_comp comp = {
93 .cid = TEST_VND_COMPANY_ID,
94 .vid = 0xdead,
95 .pid = 0xface,
96 .elem = elems,
97 .elem_count = ARRAY_SIZE(elems),
98 };
99
100 /* The extensions and correspondence between models are as follows:
101 * Within elements:
102 * E0: M2 extends M1. VND1 extends M2. M3 and VND1 corresponds.
103 *
104 * Between elements:
105 * M3 on E0 extends M4 on E1.
106 * M2 on E0 and M4 on E1 corresponds.
107 * M6 on E4 extends M1 on E0
108 */
model_1_init(struct bt_mesh_model * model)109 static int model_1_init(struct bt_mesh_model *model)
110 {
111 return 0;
112 }
113
model_2_init(struct bt_mesh_model * model)114 static int model_2_init(struct bt_mesh_model *model)
115 {
116 ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1)));
117 return 0;
118 }
119
model_3_init(struct bt_mesh_model * model)120 static int model_3_init(struct bt_mesh_model *model)
121 {
122 return 0;
123 }
124
model_4_init(struct bt_mesh_model * model)125 static int model_4_init(struct bt_mesh_model *model)
126 {
127 ASSERT_OK(bt_mesh_model_extend(bt_mesh_model_find(&elems[0], TEST_MODEL_ID_3), model));
128 ASSERT_OK(bt_mesh_model_correspond(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_2)));
129 return 0;
130 }
131
model_5_init(struct bt_mesh_model * model)132 static int model_5_init(struct bt_mesh_model *model)
133 {
134 return 0;
135 }
136
model_6_init(struct bt_mesh_model * model)137 static int model_6_init(struct bt_mesh_model *model)
138 {
139 ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1)));
140 return 0;
141 }
142
model_vnd1_init(struct bt_mesh_model * model)143 static int model_vnd1_init(struct bt_mesh_model *model)
144 {
145 ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1)));
146 ASSERT_OK(bt_mesh_model_correspond(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_3)));
147 return 0;
148 }
149
150 /* Hardcoded version of the CDP1 fields.
151 * Extensions are named extending-model_base-model.
152 */
153
154 static struct bt_mesh_comp_p1_ext_item test_p1_ext_mod2_mod1 = {.type = SHORT,
155 .short_item = {
156 .elem_offset = 0,
157 .mod_item_idx = 2,
158 }};
159
160 static struct bt_mesh_comp_p1_ext_item test_p1_ext_vnd1_mod1 = {.type = SHORT,
161 .short_item = {
162 .elem_offset = 0,
163 .mod_item_idx = 2,
164 }};
165
166 static struct bt_mesh_comp_p1_ext_item test_p1_ext_mod3_mod4 = {.type = SHORT,
167 .short_item = {
168 .elem_offset = 7,
169 .mod_item_idx = 0,
170 }};
171
172 static struct bt_mesh_comp_p1_ext_item test_p1_ext_mod6_mod1 = {.type = LONG,
173 .long_item = {
174 .elem_offset = 4,
175 .mod_item_idx = 2,
176 }};
177
178 static const struct bt_mesh_comp_p1_model_item test_p1_cfg_srv_mod = {
179 .cor_present = 0,
180 .format = 0,
181 .ext_item_cnt = 0,
182 };
183
184 static const struct bt_mesh_comp_p1_model_item test_p1_cfg_cli_mod = {
185 .cor_present = 0,
186 .format = 0,
187 .ext_item_cnt = 0,
188 };
189
190 static const struct bt_mesh_comp_p1_model_item test_p1_mod1 = {
191 .cor_present = 0,
192 .format = 0,
193 .ext_item_cnt = 0,
194 };
195
196 static const struct bt_mesh_comp_p1_model_item test_p1_mod2 = {
197 .cor_present = 1,
198 .format = 0,
199 .ext_item_cnt = 1,
200 .cor_id = 0,
201 };
202
203 static const struct bt_mesh_comp_p1_model_item test_p1_mod3 = {
204 .cor_present = 1,
205 .format = 0,
206 .ext_item_cnt = 1,
207 .cor_id = 0,
208 };
209
210 static const struct bt_mesh_comp_p1_model_item test_p1_mod4 = {
211 .cor_present = 1,
212 .format = 0,
213 .ext_item_cnt = 0,
214 .cor_id = 0,
215 };
216
217 static const struct bt_mesh_comp_p1_model_item test_p1_mod5 = {
218 .cor_present = 0,
219 .format = 0,
220 .ext_item_cnt = 0,
221 };
222
223 static const struct bt_mesh_comp_p1_model_item test_p1_mod6 = {
224 .cor_present = 0,
225 .format = 1,
226 .ext_item_cnt = 1,
227 };
228
229 static const struct bt_mesh_comp_p1_model_item test_p1_vnd1 = {
230 .cor_present = 1,
231 .format = 0,
232 .ext_item_cnt = 1,
233 .cor_id = 0,
234 };
235
236 static const struct bt_mesh_comp_p1_model_item test_p1_elem0_models[] = {
237 test_p1_cfg_srv_mod, test_p1_cfg_cli_mod, test_p1_mod1,
238 test_p1_mod2, test_p1_mod3, test_p1_vnd1,
239 };
240
241 static const struct bt_mesh_comp_p1_model_item test_p1_elem1_models[] = {
242 test_p1_mod4,
243 };
244
245 static const struct bt_mesh_comp_p1_model_item test_p1_elem2_models[] = {
246 test_p1_mod5,
247 };
248
249 static const struct bt_mesh_comp_p1_model_item test_p1_elem3_models[] = {
250 test_p1_mod5,
251 };
252
253 static const struct bt_mesh_comp_p1_model_item test_p1_elem4_models[] = {
254 test_p1_mod6,
255 };
256
257 static const struct bt_mesh_comp_p1_model_item *test_p1_elem_models[] = {
258 test_p1_elem0_models, test_p1_elem1_models, test_p1_elem2_models,
259 test_p1_elem3_models, test_p1_elem4_models,
260 };
261
262 static const struct bt_mesh_comp_p1_elem test_p1_elem0 = {
263 .nsig = 5,
264 .nvnd = 1,
265 };
266
267 static const struct bt_mesh_comp_p1_elem test_p1_elem1 = {
268 .nsig = 1,
269 .nvnd = 0,
270 };
271
272 static const struct bt_mesh_comp_p1_elem test_p1_elem2 = {
273 .nsig = 1,
274 .nvnd = 0,
275 };
276
277 static const struct bt_mesh_comp_p1_elem test_p1_elem3 = {
278 .nsig = 1,
279 .nvnd = 0,
280 };
281
282 static const struct bt_mesh_comp_p1_elem test_p1_elem4 = {
283 .nsig = 1,
284 .nvnd = 0,
285 };
286
287 static struct bt_mesh_comp_p1_elem test_p1_elems[] = {
288 test_p1_elem0, test_p1_elem1, test_p1_elem2, test_p1_elem3, test_p1_elem4,
289 };
290
provision_and_configure(struct bt_mesh_test_cfg cfg)291 static void provision_and_configure(struct bt_mesh_test_cfg cfg)
292 {
293 int err;
294 uint8_t status;
295
296 err = bt_mesh_provision(net_key, 0, 0, 0, cfg.addr, cfg.dev_key);
297 if (err) {
298 FAIL("Provisioning failed (err %d)", err);
299 }
300
301 err = bt_mesh_cfg_cli_app_key_add(0, cfg.addr, 0, 0, app_key, &status);
302 if (err || status) {
303 FAIL("AppKey add failed (err %d, status %u)", err, status);
304 }
305 }
306
verify_model_item(struct bt_mesh_comp_p1_model_item * mod_item,int elem_idx,int mod_idx,int offset)307 static void verify_model_item(struct bt_mesh_comp_p1_model_item *mod_item, int elem_idx,
308 int mod_idx, int offset)
309 {
310 ASSERT_EQUAL(test_p1_elem_models[elem_idx][mod_idx + offset].cor_present,
311 mod_item->cor_present);
312 ASSERT_EQUAL(test_p1_elem_models[elem_idx][mod_idx + offset].format, mod_item->format);
313 ASSERT_EQUAL(test_p1_elem_models[elem_idx][mod_idx + offset].ext_item_cnt,
314 mod_item->ext_item_cnt);
315 if (mod_item->cor_present) {
316 ASSERT_EQUAL(test_p1_elem_models[elem_idx][mod_idx + offset].cor_id,
317 mod_item->cor_id);
318 }
319 }
320
verify_ext_item(struct bt_mesh_comp_p1_ext_item * ext_item,int elem_idx,int mod_idx,int offset)321 static void verify_ext_item(struct bt_mesh_comp_p1_ext_item *ext_item, int elem_idx, int mod_idx,
322 int offset)
323 {
324 struct bt_mesh_comp_p1_ext_item *test_p1_ext_item;
325
326 switch (elem_idx * 100 + (mod_idx + offset)) {
327 case 3: /* elem_idx=0, mod_idx=3, offset = 0 */
328 test_p1_ext_item = &test_p1_ext_mod2_mod1;
329 break;
330 case 4: /* elem_idx=0, mod_idx=4, offset = 0 */
331 test_p1_ext_item = &test_p1_ext_mod3_mod4;
332 break;
333 case 5: /* elem_idx=0, mod_idx=0, offset = 5 */
334 test_p1_ext_item = &test_p1_ext_vnd1_mod1;
335 break;
336 case 400: /* elem_idx=4, mod_idx=0, offset = 0 */
337 test_p1_ext_item = &test_p1_ext_mod6_mod1;
338 break;
339 default:
340 FAIL("Unexpected call to %s (elem %d, mod %d, offset %d)", __func__, elem_idx,
341 mod_idx, offset);
342 }
343
344 ASSERT_EQUAL(test_p1_ext_item->type, ext_item->type);
345 if (ext_item->type == SHORT) {
346 ASSERT_EQUAL(test_p1_ext_item->short_item.elem_offset,
347 ext_item->short_item.elem_offset);
348 ASSERT_EQUAL(test_p1_ext_item->short_item.mod_item_idx,
349 ext_item->short_item.mod_item_idx);
350 } else {
351 ASSERT_EQUAL(test_p1_ext_item->long_item.elem_offset,
352 ext_item->long_item.elem_offset);
353 ASSERT_EQUAL(test_p1_ext_item->long_item.mod_item_idx,
354 ext_item->long_item.mod_item_idx);
355 }
356 }
357
verify_cdp1(struct bt_mesh_comp_p1_elem * p1_elem,struct bt_mesh_comp_p1_model_item * mod_item,struct bt_mesh_comp_p1_ext_item * ext_item,struct net_buf_simple * p1_dev_comp)358 static void verify_cdp1(struct bt_mesh_comp_p1_elem *p1_elem,
359 struct bt_mesh_comp_p1_model_item *mod_item,
360 struct bt_mesh_comp_p1_ext_item *ext_item,
361 struct net_buf_simple *p1_dev_comp)
362 {
363 int elem_idx = 0;
364
365 while (bt_mesh_comp_p1_elem_pull(p1_dev_comp, p1_elem)) {
366 ASSERT_EQUAL(test_p1_elems[elem_idx].nsig, p1_elem->nsig);
367 ASSERT_EQUAL(test_p1_elems[elem_idx].nvnd, p1_elem->nvnd);
368
369 for (int mod_idx = 0; mod_idx < p1_elem->nsig; mod_idx++) {
370 if (bt_mesh_comp_p1_item_pull(p1_elem, mod_item)) {
371 verify_model_item(mod_item, elem_idx, mod_idx, 0);
372 }
373
374 for (int ext_mod_idx = 0; ext_mod_idx < mod_item->ext_item_cnt;
375 ext_mod_idx++) {
376 bt_mesh_comp_p1_pull_ext_item(mod_item, ext_item);
377 verify_ext_item(ext_item, elem_idx, mod_idx, 0);
378 }
379 }
380
381 for (int mod_idx = 0; mod_idx < p1_elem->nvnd; mod_idx++) {
382 if (bt_mesh_comp_p1_item_pull(p1_elem, mod_item)) {
383 verify_model_item(mod_item, elem_idx, mod_idx, p1_elem->nsig);
384 }
385
386 for (int ext_mod_idx = 0; ext_mod_idx < mod_item->ext_item_cnt;
387 ext_mod_idx++) {
388 bt_mesh_comp_p1_pull_ext_item(mod_item, ext_item);
389 verify_ext_item(ext_item, elem_idx, mod_idx, p1_elem->nsig);
390 }
391 }
392 elem_idx++;
393 }
394 }
395
test_node_data_comparison(void)396 static void test_node_data_comparison(void)
397 {
398 bt_mesh_test_cfg_set(NULL, WAIT_TIME);
399 bt_mesh_device_setup(&prov, &comp);
400 provision_and_configure(node_1_cfg);
401
402 NET_BUF_SIMPLE_DEFINE(p1_dev_comp, 500);
403 uint8_t page_rsp;
404
405 ASSERT_OK(bt_mesh_cfg_cli_comp_data_get(0, node_1_cfg.addr, 1, &page_rsp, &p1_dev_comp));
406 ASSERT_EQUAL(1, page_rsp);
407
408 NET_BUF_SIMPLE_DEFINE(p1_buf, 500);
409 NET_BUF_SIMPLE_DEFINE(p1_item_buf, 500);
410 struct bt_mesh_comp_p1_elem p1_elem = {._buf = &p1_buf};
411 struct bt_mesh_comp_p1_model_item mod_item = {._buf = &p1_item_buf};
412 struct bt_mesh_comp_p1_ext_item ext_item = {0};
413
414 verify_cdp1(&p1_elem, &mod_item, &ext_item, &p1_dev_comp);
415
416 PASS();
417 }
418
419 #define TEST_CASE(role, name, description) \
420 { \
421 .test_id = "cdp1_" #role "_" #name, .test_descr = description, \
422 .test_tick_f = bt_mesh_test_timeout, .test_main_f = test_##role##_##name, \
423 }
424
425 static const struct bst_test_instance test_cdp1[] = {
426 TEST_CASE(node, data_comparison, "Compare encoded and decoded CDP1 data."),
427
428 BSTEST_END_MARKER};
429
test_cdp1_install(struct bst_test_list * tests)430 struct bst_test_list *test_cdp1_install(struct bst_test_list *tests)
431 {
432 tests = bst_add_tests(tests, test_cdp1);
433 return tests;
434 }
435