1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "utils.h"
8 #include "gatt_utils.h"
9 #include <zephyr/sys/__assert.h>
10 #include <zephyr/bluetooth/hci.h>
11
12 static struct bt_conn *default_conn;
13
14 DEFINE_FLAG(flag_is_connected);
15 DEFINE_FLAG(flag_test_end);
16
wait_connected(void)17 void wait_connected(void)
18 {
19 UNSET_FLAG(flag_is_connected);
20 WAIT_FOR_FLAG(flag_is_connected);
21 printk("connected\n");
22
23 }
24
wait_disconnected(void)25 void wait_disconnected(void)
26 {
27 SET_FLAG(flag_is_connected);
28 WAIT_FOR_FLAG_UNSET(flag_is_connected);
29 printk("disconnected\n");
30 }
31
disconnected(struct bt_conn * conn,uint8_t reason)32 static void disconnected(struct bt_conn *conn, uint8_t reason)
33 {
34 __ASSERT_NO_MSG(default_conn == conn);
35
36 bt_conn_unref(default_conn);
37 default_conn = NULL;
38
39 UNSET_FLAG(flag_is_connected);
40 gatt_clear_flags();
41 }
42
connected(struct bt_conn * conn,uint8_t err)43 static void connected(struct bt_conn *conn, uint8_t err)
44 {
45 struct bt_conn_info info = { 0 };
46 int ret;
47
48 if (err != 0) {
49 return;
50 }
51
52 ret = bt_conn_get_info(conn, &info);
53 __ASSERT_NO_MSG(ret == 0);
54
55 if (info.role == BT_CONN_ROLE_PERIPHERAL) {
56 __ASSERT_NO_MSG(default_conn == NULL);
57 default_conn = bt_conn_ref(conn);
58 }
59
60 __ASSERT_NO_MSG(default_conn != NULL);
61
62 SET_FLAG(flag_is_connected);
63 }
64
65 DEFINE_FLAG(flag_encrypted);
66
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)67 void security_changed(struct bt_conn *conn, bt_security_t level,
68 enum bt_security_err err)
69 {
70 __ASSERT(err == 0, "Error setting security (err %u)\n", err);
71
72 printk("Encrypted\n");
73 SET_FLAG(flag_encrypted);
74 }
75
76 BT_CONN_CB_DEFINE(conn_callbacks) = {
77 .connected = connected,
78 .disconnected = disconnected,
79 .security_changed = security_changed,
80 };
81
scan_connect_to_first_result_device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)82 static void scan_connect_to_first_result_device_found(const bt_addr_le_t *addr, int8_t rssi,
83 uint8_t type, struct net_buf_simple *ad)
84 {
85 char addr_str[BT_ADDR_LE_STR_LEN];
86 int err;
87
88 /* We're only interested in connectable events */
89 if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
90 FAIL("Unexpected advertisement type.");
91 }
92
93 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
94 printk("Got scan result, connecting.. dst %s, RSSI %d\n",
95 addr_str, rssi);
96
97 err = bt_le_scan_stop();
98 __ASSERT(!err, "Err bt_le_scan_stop %d", err);
99
100 err = bt_conn_le_create(addr,
101 BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,
102 &default_conn);
103 __ASSERT(!err, "Err bt_conn_le_create %d", err);
104 }
105
scan_connect_to_first_result(void)106 void scan_connect_to_first_result(void)
107 {
108 int err;
109
110 printk("start scanner\n");
111 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE,
112 scan_connect_to_first_result_device_found);
113 __ASSERT(!err, "Err bt_le_scan_start %d", err);
114 }
115
advertise_connectable(void)116 void advertise_connectable(void)
117 {
118 printk("start advertiser\n");
119 int err;
120 struct bt_le_adv_param param = {};
121
122 param.interval_min = 0x0020;
123 param.interval_max = 0x4000;
124 param.options |= BT_LE_ADV_OPT_ONE_TIME;
125 param.options |= BT_LE_ADV_OPT_CONNECTABLE;
126
127 err = bt_le_adv_start(¶m, NULL, 0, NULL, 0);
128 __ASSERT(err == 0, "Advertising failed to start (err %d)\n", err);
129 }
130
disconnect(struct bt_conn * conn)131 void disconnect(struct bt_conn *conn)
132 {
133 int err;
134
135 err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
136 __ASSERT(!err, "Failed to initate disconnection (err %d)", err);
137
138 printk("Waiting for disconnection...\n");
139 WAIT_FOR_FLAG_UNSET(flag_is_connected);
140 }
141
get_conn(void)142 struct bt_conn *get_conn(void)
143 {
144 return default_conn;
145 }
146
147 DEFINE_FLAG(flag_pairing_complete);
148
pairing_failed(struct bt_conn * conn,enum bt_security_err reason)149 static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
150 {
151 FAIL("Pairing failed (unexpected): reason %u", reason);
152 }
153
pairing_complete(struct bt_conn * conn,bool bonded)154 static void pairing_complete(struct bt_conn *conn, bool bonded)
155 {
156 __ASSERT(bonded, "Bonding failed\n");
157
158 printk("Paired\n");
159 SET_FLAG(flag_pairing_complete);
160 }
161
162 static struct bt_conn_auth_info_cb bt_conn_auth_info_cb = {
163 .pairing_failed = pairing_failed,
164 .pairing_complete = pairing_complete,
165 };
166
set_security(struct bt_conn * conn,bt_security_t sec)167 void set_security(struct bt_conn *conn, bt_security_t sec)
168 {
169 int err;
170
171 UNSET_FLAG(flag_encrypted);
172
173 err = bt_conn_set_security(conn, sec);
174 __ASSERT(!err, "Err bt_conn_set_security %d", err);
175
176 WAIT_FOR_FLAG(flag_encrypted);
177 }
178
wait_secured(void)179 void wait_secured(void)
180 {
181 UNSET_FLAG(flag_encrypted);
182 WAIT_FOR_FLAG(flag_encrypted);
183 }
184
bond(struct bt_conn * conn)185 void bond(struct bt_conn *conn)
186 {
187 UNSET_FLAG(flag_pairing_complete);
188
189 int err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb);
190
191 __ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n");
192
193 set_security(conn, BT_SECURITY_L2);
194
195 WAIT_FOR_FLAG(flag_pairing_complete);
196 }
197
wait_bonded(void)198 void wait_bonded(void)
199 {
200 UNSET_FLAG(flag_encrypted);
201 UNSET_FLAG(flag_pairing_complete);
202
203 int err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb);
204
205 __ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n");
206
207 WAIT_FOR_FLAG(flag_encrypted);
208 WAIT_FOR_FLAG(flag_pairing_complete);
209 }
210
connect_as_central(void)211 struct bt_conn *connect_as_central(void)
212 {
213 struct bt_conn *conn;
214
215 scan_connect_to_first_result();
216 wait_connected();
217 conn = get_conn();
218
219 return conn;
220 }
221
connect_as_peripheral(void)222 struct bt_conn *connect_as_peripheral(void)
223 {
224 struct bt_conn *conn;
225
226 advertise_connectable();
227 wait_connected();
228 conn = get_conn();
229
230 return conn;
231 }
232