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