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