1 /*
2 * Copyright (c) 2022 Codecoup
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <string.h>
10
11 #include <zephyr/autoconf.h>
12 #include <zephyr/bluetooth/audio/has.h>
13 #include <zephyr/bluetooth/att.h>
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/conn.h>
16 #include <zephyr/bluetooth/gatt.h>
17 #include <zephyr/bluetooth/hci_types.h>
18 #include <zephyr/bluetooth/uuid.h>
19 #include <zephyr/logging/log.h>
20 #include <zephyr/logging/log_core.h>
21 #include <zephyr/sys/util_macro.h>
22
23 #include "../../subsys/bluetooth/audio/has_internal.h"
24
25 #include "bstests.h"
26 #include "common.h"
27
28 LOG_MODULE_REGISTER(has_client_test, LOG_LEVEL_DBG);
29
30 extern enum bst_result_t bst_result;
31
32 extern const char *test_preset_name_1;
33 extern const char *test_preset_name_5;
34 extern const uint8_t test_preset_index_1;
35 extern const uint8_t test_preset_index_3;
36 extern const uint8_t test_preset_index_5;
37 extern const enum bt_has_properties test_preset_properties;
38
39 CREATE_FLAG(g_service_discovered);
40 CREATE_FLAG(g_preset_switched);
41 CREATE_FLAG(g_preset_1_found);
42 CREATE_FLAG(g_preset_3_found);
43 CREATE_FLAG(g_preset_5_found);
44
45 static struct bt_has *g_has;
46 static uint8_t g_active_index;
47
discover_cb(struct bt_conn * conn,int err,struct bt_has * has,enum bt_has_hearing_aid_type type,enum bt_has_capabilities caps)48 static void discover_cb(struct bt_conn *conn, int err, struct bt_has *has,
49 enum bt_has_hearing_aid_type type, enum bt_has_capabilities caps)
50 {
51 if (err) {
52 FAIL("Failed to discover HAS (err %d)\n", err);
53 return;
54 }
55
56 LOG_DBG("HAS discovered type %d caps %d", type, caps);
57
58 g_has = has;
59 SET_FLAG(g_service_discovered);
60 }
61
preset_switch_cb(struct bt_has * has,int err,uint8_t index)62 static void preset_switch_cb(struct bt_has *has, int err, uint8_t index)
63 {
64 if (err != 0) {
65 return;
66 }
67
68 LOG_DBG("Active preset index %d", index);
69
70 SET_FLAG(g_preset_switched);
71 g_active_index = index;
72 }
73
check_preset_record(const struct bt_has_preset_record * record,enum bt_has_properties expected_properties,const char * expected_name)74 static void check_preset_record(const struct bt_has_preset_record *record,
75 enum bt_has_properties expected_properties,
76 const char *expected_name)
77 {
78 if (record->properties != expected_properties || strcmp(record->name, expected_name)) {
79 FAIL("mismatch 0x%02x %s vs 0x%02x %s expected\n",
80 record->properties, record->name, expected_properties, expected_name);
81 }
82 }
83
preset_read_rsp_cb(struct bt_has * has,int err,const struct bt_has_preset_record * record,bool is_last)84 static void preset_read_rsp_cb(struct bt_has *has, int err,
85 const struct bt_has_preset_record *record, bool is_last)
86 {
87 if (err) {
88 FAIL("%s: err %d\n", __func__, err);
89 return;
90 }
91
92 if (record->index == test_preset_index_1) {
93 SET_FLAG(g_preset_1_found);
94
95 check_preset_record(record, test_preset_properties, test_preset_name_1);
96 } else if (record->index == test_preset_index_5) {
97 SET_FLAG(g_preset_5_found);
98
99 check_preset_record(record, test_preset_properties, test_preset_name_5);
100 } else {
101 FAIL("unexpected index 0x%02x", record->index);
102 }
103 }
104
preset_update_cb(struct bt_has * has,uint8_t index_prev,const struct bt_has_preset_record * record,bool is_last)105 static void preset_update_cb(struct bt_has *has, uint8_t index_prev,
106 const struct bt_has_preset_record *record, bool is_last)
107 {
108 if (record->index == test_preset_index_1) {
109 SET_FLAG(g_preset_1_found);
110 } else if (record->index == test_preset_index_3) {
111 SET_FLAG(g_preset_3_found);
112 } else if (record->index == test_preset_index_5) {
113 SET_FLAG(g_preset_5_found);
114 }
115 }
116
117 static const struct bt_has_client_cb has_cb = {
118 .discover = discover_cb,
119 .preset_switch = preset_switch_cb,
120 .preset_read_rsp = preset_read_rsp_cb,
121 .preset_update = preset_update_cb,
122 };
123
test_preset_switch(uint8_t index)124 static bool test_preset_switch(uint8_t index)
125 {
126 int err;
127
128 UNSET_FLAG(g_preset_switched);
129
130 err = bt_has_client_preset_set(g_has, index, false);
131 if (err < 0) {
132 LOG_DBG("%s (err %d)", __func__, err);
133 return false;
134 }
135
136 WAIT_FOR_COND(g_preset_switched);
137
138 return g_active_index == index;
139 }
140
test_preset_next(uint8_t active_index_expected)141 static bool test_preset_next(uint8_t active_index_expected)
142 {
143 int err;
144
145 UNSET_FLAG(g_preset_switched);
146
147 err = bt_has_client_preset_next(g_has, false);
148 if (err < 0) {
149 LOG_DBG("%s (err %d)", __func__, err);
150 return false;
151 }
152
153 WAIT_FOR_COND(g_preset_switched);
154
155 return g_active_index == active_index_expected;
156 }
157
test_preset_prev(uint8_t active_index_expected)158 static bool test_preset_prev(uint8_t active_index_expected)
159 {
160 int err;
161
162 UNSET_FLAG(g_preset_switched);
163
164 err = bt_has_client_preset_prev(g_has, false);
165 if (err < 0) {
166 LOG_DBG("%s (err %d)", __func__, err);
167 return false;
168 }
169
170 WAIT_FOR_COND(g_preset_switched);
171
172 return g_active_index == active_index_expected;
173 }
174
discover_has(void)175 static void discover_has(void)
176 {
177 int err;
178
179 g_service_discovered = false;
180
181 err = bt_has_client_discover(default_conn);
182 if (err < 0) {
183 FAIL("Failed to discover HAS (err %d)\n", err);
184 return;
185 }
186
187 WAIT_FOR_COND(g_service_discovered);
188 }
189
test_main(void)190 static void test_main(void)
191 {
192 int err;
193
194 err = bt_enable(NULL);
195 if (err < 0) {
196 FAIL("Bluetooth discover failed (err %d)\n", err);
197 return;
198 }
199
200 LOG_DBG("Bluetooth initialized");
201
202 err = bt_has_client_cb_register(&has_cb);
203 if (err < 0) {
204 FAIL("Failed to register callbacks (err %d)\n", err);
205 return;
206 }
207
208 bt_le_scan_cb_register(&common_scan_cb);
209
210 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
211 if (err < 0) {
212 FAIL("Scanning failed to start (err %d)\n", err);
213 return;
214 }
215
216 LOG_DBG("Scanning successfully started");
217
218 WAIT_FOR_FLAG(flag_connected);
219
220 discover_has();
221 WAIT_FOR_COND(g_preset_switched);
222
223 err = bt_has_client_presets_read(g_has, BT_HAS_PRESET_INDEX_FIRST, 255);
224 if (err < 0) {
225 FAIL("Failed to read presets (err %d)\n", err);
226 return;
227 }
228
229 WAIT_FOR_COND(g_preset_1_found);
230 WAIT_FOR_COND(g_preset_5_found);
231
232 if (!test_preset_switch(test_preset_index_1)) {
233 FAIL("Failed to switch preset %d\n", test_preset_index_1);
234 return;
235 }
236
237 if (!test_preset_switch(test_preset_index_5)) {
238 FAIL("Failed to switch preset %d\n", test_preset_index_5);
239 return;
240 }
241
242 if (!test_preset_next(test_preset_index_1)) {
243 FAIL("Failed to set next preset %d\n", test_preset_index_1);
244 return;
245 }
246
247 if (!test_preset_next(test_preset_index_5)) {
248 FAIL("Failed to set next preset %d\n", test_preset_index_5);
249 return;
250 }
251
252 if (!test_preset_next(test_preset_index_1)) {
253 FAIL("Failed to set next preset %d\n", test_preset_index_1);
254 return;
255 }
256
257 if (!test_preset_prev(test_preset_index_5)) {
258 FAIL("Failed to set previous preset %d\n", test_preset_index_5);
259 return;
260 }
261
262 if (!test_preset_prev(test_preset_index_1)) {
263 FAIL("Failed to set previous preset %d\n", test_preset_index_1);
264 return;
265 }
266
267 if (!test_preset_prev(test_preset_index_5)) {
268 FAIL("Failed to set previous preset %d\n", test_preset_index_5);
269 return;
270 }
271
272 PASS("HAS main PASS\n");
273 }
274
275 #define FEATURES_SUB_NTF BIT(0)
276 #define ACTIVE_INDEX_SUB_NTF BIT(1)
277 #define PRESET_CHANGED_SUB_NTF BIT(2)
278 #define SUB_NTF_ALL (FEATURES_SUB_NTF | ACTIVE_INDEX_SUB_NTF | PRESET_CHANGED_SUB_NTF)
279
280 CREATE_FLAG(flag_features_discovered);
281 CREATE_FLAG(flag_active_preset_index_discovered);
282 CREATE_FLAG(flag_control_point_discovered);
283 CREATE_FLAG(flag_all_notifications_received);
284
285 enum preset_state {
286 STATE_UNKNOWN,
287 STATE_AVAILABLE,
288 STATE_UNAVAILABLE,
289 STATE_DELETED,
290 };
291
292 static enum preset_state preset_state_1;
293 static enum preset_state preset_state_3;
294 static enum preset_state preset_state_5;
295
296 static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
297 static struct bt_gatt_discover_params discover_params;
298 static struct bt_gatt_subscribe_params features_sub;
299 static struct bt_gatt_subscribe_params active_preset_index_sub;
300 static struct bt_gatt_subscribe_params control_point_sub;
301 static uint8_t notify_received_mask;
302
preset_availability_changed(uint8_t index,bool available)303 static void preset_availability_changed(uint8_t index, bool available)
304 {
305 enum preset_state state = available ? STATE_AVAILABLE : STATE_UNAVAILABLE;
306
307 if (index == test_preset_index_1) {
308 preset_state_1 = state;
309 } else if (index == test_preset_index_3) {
310 preset_state_3 = state;
311 } else if (index == test_preset_index_5) {
312 preset_state_5 = state;
313 } else {
314 FAIL("invalid preset index 0x%02x", index);
315 }
316 }
317
notify_handler(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)318 static uint8_t notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
319 const void *data, uint16_t length)
320 {
321 LOG_DBG("conn %p params %p data %p length %u", (void *)conn, params, data, length);
322
323 if (params == &features_sub) {
324 if (data == NULL) {
325 LOG_DBG("features_sub [UNSUBSCRIBED]");
326 return BT_GATT_ITER_STOP;
327 }
328
329 LOG_DBG("Received features_sub notification");
330 notify_received_mask |= FEATURES_SUB_NTF;
331 } else if (params == &active_preset_index_sub) {
332 if (data == NULL) {
333 LOG_DBG("active_preset_index_sub_sub [UNSUBSCRIBED]");
334 return BT_GATT_ITER_STOP;
335 }
336
337 LOG_DBG("Received active_preset_index_sub_sub notification");
338 notify_received_mask |= ACTIVE_INDEX_SUB_NTF;
339 } else if (params == &control_point_sub) {
340 const struct bt_has_cp_hdr *hdr;
341
342 if (data == NULL) {
343 LOG_DBG("control_point_sub [UNSUBSCRIBED]");
344 return BT_GATT_ITER_STOP;
345 }
346
347 if (length < sizeof(*hdr)) {
348 FAIL("malformed bt_has_cp_hdr");
349 return BT_GATT_ITER_STOP;
350 }
351
352 hdr = data;
353
354 if (hdr->opcode == BT_HAS_OP_PRESET_CHANGED) {
355 const struct bt_has_cp_preset_changed *pc;
356
357 if (length < (sizeof(*hdr) + sizeof(*pc))) {
358 FAIL("malformed bt_has_cp_preset_changed");
359 return BT_GATT_ITER_STOP;
360 }
361
362 pc = (const void *)hdr->data;
363
364 switch (pc->change_id) {
365 case BT_HAS_CHANGE_ID_GENERIC_UPDATE: {
366 const struct bt_has_cp_generic_update *gu;
367 bool is_available;
368
369 if (length < (sizeof(*hdr) + sizeof(*pc) + sizeof(*gu))) {
370 FAIL("malformed bt_has_cp_generic_update");
371 return BT_GATT_ITER_STOP;
372 }
373
374 gu = (const void *)pc->additional_params;
375
376 LOG_DBG("Received generic update index 0x%02x props 0x%02x",
377 gu->index, gu->properties);
378
379 is_available = (gu->properties & BT_HAS_PROP_AVAILABLE) != 0;
380
381 preset_availability_changed(gu->index, is_available);
382 break;
383 }
384 default:
385 LOG_DBG("Unexpected Change ID 0x%02x", pc->change_id);
386 return BT_GATT_ITER_STOP;
387 }
388
389 if (pc->is_last) {
390 notify_received_mask |= PRESET_CHANGED_SUB_NTF;
391 }
392 } else {
393 LOG_DBG("Unexpected opcode 0x%02x", hdr->opcode);
394 return BT_GATT_ITER_STOP;
395 }
396 }
397
398 LOG_DBG("pacs_instance.notify_received_mask is %d", notify_received_mask);
399
400 if (notify_received_mask == SUB_NTF_ALL) {
401 SET_FLAG(flag_all_notifications_received);
402 notify_received_mask = 0;
403 }
404
405 return BT_GATT_ITER_CONTINUE;
406 }
407
subscribe_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_subscribe_params * params)408 static void subscribe_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_subscribe_params *params)
409 {
410 if (err != BT_ATT_ERR_SUCCESS) {
411 return;
412 }
413
414 LOG_DBG("[SUBSCRIBED]");
415
416 if (params == &features_sub) {
417 SET_FLAG(flag_features_discovered);
418 return;
419 }
420
421 if (params == &control_point_sub) {
422 SET_FLAG(flag_control_point_discovered);
423 return;
424 }
425
426 if (params == &active_preset_index_sub) {
427 SET_FLAG(flag_active_preset_index_discovered);
428 return;
429 }
430 }
431
discover_features_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)432 static uint8_t discover_features_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
433 struct bt_gatt_discover_params *params)
434 {
435 struct bt_gatt_subscribe_params *subscribe_params;
436 int err;
437
438 if (!attr) {
439 LOG_DBG("Discover complete");
440 (void)memset(params, 0, sizeof(*params));
441 return BT_GATT_ITER_STOP;
442 }
443
444 if (!bt_uuid_cmp(params->uuid, BT_UUID_HAS_HEARING_AID_FEATURES)) {
445 LOG_DBG("HAS Hearing Aid Features handle at %d", attr->handle);
446 memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
447 discover_params.uuid = &uuid.uuid;
448 discover_params.start_handle = attr->handle + 2;
449 discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
450 subscribe_params = &features_sub;
451 subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
452
453 err = bt_gatt_discover(conn, &discover_params);
454 if (err) {
455 LOG_DBG("Discover failed (err %d)", err);
456 }
457 } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
458 LOG_DBG("CCC handle at %d", attr->handle);
459 subscribe_params = &features_sub;
460 subscribe_params->notify = notify_handler;
461 subscribe_params->value = BT_GATT_CCC_NOTIFY;
462 subscribe_params->ccc_handle = attr->handle;
463 subscribe_params->subscribe = subscribe_cb;
464
465 err = bt_gatt_subscribe(conn, subscribe_params);
466 if (err && err != -EALREADY) {
467 LOG_DBG("Subscribe failed (err %d)", err);
468 }
469 } else {
470 LOG_DBG("Unknown handle at %d", attr->handle);
471 return BT_GATT_ITER_CONTINUE;
472 }
473
474 return BT_GATT_ITER_STOP;
475 }
476
discover_and_subscribe_features(void)477 static void discover_and_subscribe_features(void)
478 {
479 int err = 0;
480
481 LOG_DBG("%s", __func__);
482
483 memcpy(&uuid, BT_UUID_HAS_HEARING_AID_FEATURES, sizeof(uuid));
484 discover_params.uuid = &uuid.uuid;
485 discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
486 discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
487 discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
488 discover_params.func = discover_features_cb;
489
490 err = bt_gatt_discover(default_conn, &discover_params);
491 if (err != 0) {
492 FAIL("Service Discovery failed (err %d)\n", err);
493 return;
494 }
495 }
496
discover_active_preset_index_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)497 static uint8_t discover_active_preset_index_cb(struct bt_conn *conn,
498 const struct bt_gatt_attr *attr,
499 struct bt_gatt_discover_params *params)
500 {
501 struct bt_gatt_subscribe_params *subscribe_params;
502 int err;
503
504 if (!attr) {
505 LOG_DBG("Discover complete");
506 (void)memset(params, 0, sizeof(*params));
507 return BT_GATT_ITER_STOP;
508 }
509
510 if (!bt_uuid_cmp(params->uuid, BT_UUID_HAS_ACTIVE_PRESET_INDEX)) {
511 LOG_DBG("HAS Hearing Aid Features handle at %d", attr->handle);
512 memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
513 discover_params.uuid = &uuid.uuid;
514 discover_params.start_handle = attr->handle + 2;
515 discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
516 subscribe_params = &active_preset_index_sub;
517 subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
518
519 err = bt_gatt_discover(conn, &discover_params);
520 if (err) {
521 LOG_DBG("Discover failed (err %d)", err);
522 }
523 } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
524 LOG_DBG("CCC handle at %d", attr->handle);
525 subscribe_params = &active_preset_index_sub;
526 subscribe_params->notify = notify_handler;
527 subscribe_params->value = BT_GATT_CCC_NOTIFY;
528 subscribe_params->ccc_handle = attr->handle;
529 subscribe_params->subscribe = subscribe_cb;
530
531 err = bt_gatt_subscribe(conn, subscribe_params);
532 if (err && err != -EALREADY) {
533 LOG_DBG("Subscribe failed (err %d)", err);
534 }
535 } else {
536 LOG_DBG("Unknown handle at %d", attr->handle);
537 return BT_GATT_ITER_CONTINUE;
538 }
539
540 return BT_GATT_ITER_STOP;
541 }
542
discover_and_subscribe_active_preset_index(void)543 static void discover_and_subscribe_active_preset_index(void)
544 {
545 int err = 0;
546
547 LOG_DBG("%s", __func__);
548
549 memcpy(&uuid, BT_UUID_HAS_ACTIVE_PRESET_INDEX, sizeof(uuid));
550 discover_params.uuid = &uuid.uuid;
551 discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
552 discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
553 discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
554 discover_params.func = discover_active_preset_index_cb;
555
556 err = bt_gatt_discover(default_conn, &discover_params);
557 if (err != 0) {
558 FAIL("Service Discovery failed (err %d)\n", err);
559 return;
560 }
561 }
562
discover_control_point_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)563 static uint8_t discover_control_point_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
564 struct bt_gatt_discover_params *params)
565 {
566 struct bt_gatt_subscribe_params *subscribe_params;
567 int err;
568
569 if (!attr) {
570 LOG_DBG("Discover complete");
571 (void)memset(params, 0, sizeof(*params));
572 return BT_GATT_ITER_STOP;
573 }
574
575 if (!bt_uuid_cmp(params->uuid, BT_UUID_HAS_PRESET_CONTROL_POINT)) {
576 LOG_DBG("HAS Control Point handle at %d", attr->handle);
577 memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
578 discover_params.uuid = &uuid.uuid;
579 discover_params.start_handle = attr->handle + 2;
580 discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
581 subscribe_params = &control_point_sub;
582 subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
583
584 err = bt_gatt_discover(conn, &discover_params);
585 if (err) {
586 LOG_DBG("Discover failed (err %d)", err);
587 }
588 } else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
589 LOG_DBG("CCC handle at %d", attr->handle);
590 subscribe_params = &control_point_sub;
591 subscribe_params->notify = notify_handler;
592 subscribe_params->value = BT_GATT_CCC_INDICATE;
593 subscribe_params->ccc_handle = attr->handle;
594 subscribe_params->subscribe = subscribe_cb;
595
596 err = bt_gatt_subscribe(conn, subscribe_params);
597 if (err && err != -EALREADY) {
598 LOG_DBG("Subscribe failed (err %d)", err);
599 }
600 } else {
601 LOG_DBG("Unknown handle at %d", attr->handle);
602 return BT_GATT_ITER_CONTINUE;
603 }
604
605 return BT_GATT_ITER_STOP;
606 }
607
discover_and_subscribe_control_point(void)608 static void discover_and_subscribe_control_point(void)
609 {
610 int err = 0;
611
612 LOG_DBG("%s", __func__);
613
614 memcpy(&uuid, BT_UUID_HAS_PRESET_CONTROL_POINT, sizeof(uuid));
615 discover_params.uuid = &uuid.uuid;
616 discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
617 discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
618 discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
619 discover_params.func = discover_control_point_cb;
620
621 err = bt_gatt_discover(default_conn, &discover_params);
622 if (err != 0) {
623 FAIL("Control Point failed (err %d)\n", err);
624 return;
625 }
626 }
627
test_gatt_client(void)628 static void test_gatt_client(void)
629 {
630 int err;
631
632 err = bt_enable(NULL);
633 if (err < 0) {
634 FAIL("Bluetooth discover failed (err %d)\n", err);
635 return;
636 }
637
638 LOG_DBG("Bluetooth initialized");
639
640 bt_le_scan_cb_register(&common_scan_cb);
641
642 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
643 if (err < 0) {
644 FAIL("Scanning failed to start (err %d)\n", err);
645 return;
646 }
647
648 LOG_DBG("Scanning successfully started");
649
650 WAIT_FOR_FLAG(flag_connected);
651
652 err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
653 if (err) {
654 FAIL("Failed to set security level %d (err %d)", BT_SECURITY_L2, err);
655 return;
656 }
657
658 WAIT_FOR_COND(security_level == BT_SECURITY_L2);
659
660 discover_and_subscribe_features();
661 WAIT_FOR_FLAG(flag_features_discovered);
662
663 discover_and_subscribe_active_preset_index();
664 WAIT_FOR_FLAG(flag_active_preset_index_discovered);
665
666 discover_and_subscribe_control_point();
667 WAIT_FOR_FLAG(flag_control_point_discovered);
668
669 bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
670 WAIT_FOR_UNSET_FLAG(flag_connected);
671
672 notify_received_mask = 0;
673 UNSET_FLAG(flag_all_notifications_received);
674
675 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
676 if (err < 0) {
677 FAIL("Scanning failed to start (err %d)\n", err);
678 return;
679 }
680
681 LOG_DBG("Scanning successfully started");
682
683 WAIT_FOR_FLAG(flag_connected);
684
685 err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
686 if (err) {
687 FAIL("Failed to set security level %d (err %d)\n", BT_SECURITY_L2, err);
688 return;
689 }
690
691 WAIT_FOR_FLAG(flag_all_notifications_received);
692
693 PASS("HAS main PASS\n");
694 }
695
696 static const struct bst_test_instance test_has[] = {
697 {
698 .test_id = "has_client",
699 .test_pre_init_f = test_init,
700 .test_tick_f = test_tick,
701 .test_main_f = test_main,
702 },
703 {
704 .test_id = "has_client_offline_behavior",
705 .test_descr = "Test receiving notifications after reconnection",
706 .test_pre_init_f = test_init,
707 .test_tick_f = test_tick,
708 .test_main_f = test_gatt_client,
709 },
710 BSTEST_END_MARKER
711 };
712
test_has_client_install(struct bst_test_list * tests)713 struct bst_test_list *test_has_client_install(struct bst_test_list *tests)
714 {
715 if (IS_ENABLED(CONFIG_BT_HAS_CLIENT)) {
716 return bst_add_tests(tests, test_has);
717 } else {
718 return tests;
719 }
720 }
721