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