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_CONN;
125
126 err = bt_le_adv_start(¶m, NULL, 0, NULL, 0);
127 __ASSERT(err == 0, "Advertising failed to start (err %d)\n", err);
128 }
129
disconnect(struct bt_conn * conn)130 void disconnect(struct bt_conn *conn)
131 {
132 int err;
133
134 err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
135 __ASSERT(!err, "Failed to initate disconnection (err %d)", err);
136
137 printk("Waiting for disconnection...\n");
138 WAIT_FOR_FLAG_UNSET(flag_is_connected);
139 }
140
get_conn(void)141 struct bt_conn *get_conn(void)
142 {
143 return default_conn;
144 }
145
146 DEFINE_FLAG(flag_pairing_complete);
147
pairing_failed(struct bt_conn * conn,enum bt_security_err reason)148 static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
149 {
150 FAIL("Pairing failed (unexpected): reason %u", reason);
151 }
152
pairing_complete(struct bt_conn * conn,bool bonded)153 static void pairing_complete(struct bt_conn *conn, bool bonded)
154 {
155 __ASSERT(bonded, "Bonding failed\n");
156
157 printk("Paired\n");
158 SET_FLAG(flag_pairing_complete);
159 }
160
161 static struct bt_conn_auth_info_cb bt_conn_auth_info_cb = {
162 .pairing_failed = pairing_failed,
163 .pairing_complete = pairing_complete,
164 };
165
set_security(struct bt_conn * conn,bt_security_t sec)166 void set_security(struct bt_conn *conn, bt_security_t sec)
167 {
168 int err;
169
170 UNSET_FLAG(flag_encrypted);
171
172 err = bt_conn_set_security(conn, sec);
173 __ASSERT(!err, "Err bt_conn_set_security %d", err);
174
175 WAIT_FOR_FLAG(flag_encrypted);
176 }
177
wait_secured(void)178 void wait_secured(void)
179 {
180 UNSET_FLAG(flag_encrypted);
181 WAIT_FOR_FLAG(flag_encrypted);
182 }
183
bond(struct bt_conn * conn)184 void bond(struct bt_conn *conn)
185 {
186 UNSET_FLAG(flag_pairing_complete);
187
188 int err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb);
189
190 __ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n");
191
192 set_security(conn, BT_SECURITY_L2);
193
194 WAIT_FOR_FLAG(flag_pairing_complete);
195 }
196
wait_bonded(void)197 void wait_bonded(void)
198 {
199 UNSET_FLAG(flag_encrypted);
200 UNSET_FLAG(flag_pairing_complete);
201
202 int err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb);
203
204 __ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n");
205
206 WAIT_FOR_FLAG(flag_encrypted);
207 WAIT_FOR_FLAG(flag_pairing_complete);
208 }
209
connect_as_central(void)210 struct bt_conn *connect_as_central(void)
211 {
212 struct bt_conn *conn;
213
214 scan_connect_to_first_result();
215 wait_connected();
216 conn = get_conn();
217
218 return conn;
219 }
220
connect_as_peripheral(void)221 struct bt_conn *connect_as_peripheral(void)
222 {
223 struct bt_conn *conn;
224
225 advertise_connectable();
226 wait_connected();
227 conn = get_conn();
228
229 return conn;
230 }
231