1 /* Copyright (c) 2023 Nordic Semiconductor ASA
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 
5 #include <stddef.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <testlib/scan.h>
9 #include <zephyr/bluetooth/addr.h>
10 #include <zephyr/bluetooth/bluetooth.h>
11 #include <zephyr/bluetooth/gap.h>
12 #include <zephyr/bluetooth/gatt.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log_core.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/net_buf.h>
17 #include <zephyr/sys/__assert.h>
18 #include <zephyr/sys/util.h>
19 
20 LOG_MODULE_REGISTER(bt_testlib_scan, LOG_LEVEL_INF);
21 
22 struct bt_scan_find_name_closure {
23 	const char *wanted_name;
24 	bt_addr_le_t *result;
25 	struct k_condvar done;
26 };
27 
28 /* Context pool (with capacity of one). */
29 static K_SEM_DEFINE(g_ctx_free, 1, 1);
30 static K_MUTEX_DEFINE(g_ctx_lock);
31 static struct bt_scan_find_name_closure *g_ctx;
32 
bt_scan_find_name_cb_data_cb(struct bt_data * data,void * user_data)33 static bool bt_scan_find_name_cb_data_cb(struct bt_data *data, void *user_data)
34 {
35 	const char **wanted = user_data;
36 
37 	if (data->type == BT_DATA_NAME_COMPLETE) {
38 		if (data->data_len == strlen(*wanted) &&
39 		    !memcmp(*wanted, data->data, data->data_len)) {
40 			*wanted = NULL;
41 			/* Stop bt_data_parse. */
42 			return false;
43 		}
44 	}
45 
46 	/* Continue with next ad data. */
47 	return true;
48 }
49 
bt_scan_find_name_cb(const bt_addr_le_t * addr,int8_t rssi,uint8_t adv_type,struct net_buf_simple * buf)50 static void bt_scan_find_name_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type,
51 				 struct net_buf_simple *buf)
52 {
53 	const char *wanted;
54 
55 	k_mutex_lock(&g_ctx_lock, K_FOREVER);
56 
57 	__ASSERT_NO_MSG(g_ctx);
58 	__ASSERT_NO_MSG(g_ctx->wanted_name);
59 
60 	wanted = g_ctx->wanted_name;
61 
62 	bt_data_parse(buf, bt_scan_find_name_cb_data_cb, &wanted);
63 
64 	if (!wanted) {
65 		(void)bt_le_scan_stop();
66 		*g_ctx->result = *addr;
67 		k_condvar_signal(&g_ctx->done);
68 	}
69 
70 	k_mutex_unlock(&g_ctx_lock);
71 }
72 
bt_testlib_scan_find_name(bt_addr_le_t * result,const char * name)73 int bt_testlib_scan_find_name(bt_addr_le_t *result, const char *name)
74 {
75 	int api_err;
76 	struct bt_scan_find_name_closure ctx = {
77 		.wanted_name = name,
78 		.result = result,
79 	};
80 
81 	k_condvar_init(&ctx.done);
82 
83 	k_sem_take(&g_ctx_free, K_FOREVER);
84 	k_mutex_lock(&g_ctx_lock, K_FOREVER);
85 	g_ctx = &ctx;
86 
87 	api_err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, bt_scan_find_name_cb);
88 	if (!api_err) {
89 		k_condvar_wait(&ctx.done, &g_ctx_lock, K_FOREVER);
90 	}
91 
92 	g_ctx = NULL;
93 	k_mutex_unlock(&g_ctx_lock);
94 	k_sem_give(&g_ctx_free);
95 
96 	if (!api_err) {
97 		char str[BT_ADDR_LE_STR_LEN];
98 		(void)bt_addr_le_to_str(result, str, ARRAY_SIZE(str));
99 		LOG_INF("Scan match: %s", str);
100 	} else {
101 		LOG_ERR("Scan error: %d", api_err);
102 	}
103 
104 	return api_err;
105 }
106