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(&param, 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