1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2021 Nordic Semiconductor ASA
5 * Copyright (c) 2015-2016 Intel Corporation
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/types.h>
11 #include <stddef.h>
12 #include <errno.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/printk.h>
15
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/hci.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/uuid.h>
20 #include <zephyr/bluetooth/gatt.h>
21 #include <zephyr/sys/byteorder.h>
22
23 #define SCAN_INTERVAL 0x0010 /* 10 ms */
24 #define SCAN_WINDOW 0x0010 /* 10 ms */
25 #define INIT_INTERVAL 0x0010 /* 10 ms */
26 #define INIT_WINDOW 0x0010 /* 10 ms */
27 #define CONN_INTERVAL 0x0320 /* 1000 ms */
28 #define CONN_LATENCY 0
29 #define CONN_TIMEOUT MIN(MAX((CONN_INTERVAL * 125 * \
30 MAX(CONFIG_BT_MAX_CONN, 6) / 1000), 10), 3200)
31
32 static void start_scan(void);
33
34 static struct bt_conn *conn_connecting;
35 static uint8_t conn_count_max;
36 static uint8_t volatile conn_count;
37 static bool volatile is_disconnecting;
38
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)39 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
40 struct net_buf_simple *ad)
41 {
42 struct bt_conn_le_create_param create_param = {
43 .options = BT_CONN_LE_OPT_NONE,
44 .interval = INIT_INTERVAL,
45 .window = INIT_WINDOW,
46 .interval_coded = 0,
47 .window_coded = 0,
48 .timeout = 0,
49 };
50 struct bt_le_conn_param conn_param = {
51 .interval_min = CONN_INTERVAL,
52 .interval_max = CONN_INTERVAL,
53 .latency = CONN_LATENCY,
54 .timeout = CONN_TIMEOUT,
55 };
56 char addr_str[BT_ADDR_LE_STR_LEN];
57 int err;
58
59 if (conn_connecting) {
60 return;
61 }
62
63 /* We're only interested in connectable events */
64 if (type != BT_GAP_ADV_TYPE_ADV_IND &&
65 type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND &&
66 type != BT_GAP_ADV_TYPE_EXT_ADV) {
67 return;
68 }
69
70 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
71 printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
72
73 /* connect only to devices in close proximity */
74 if (rssi < -50) {
75 return;
76 }
77
78 if (bt_le_scan_stop()) {
79 printk("Scanning successfully stopped\n");
80 return;
81 }
82
83 err = bt_conn_le_create(addr, &create_param, &conn_param,
84 &conn_connecting);
85 if (err) {
86 printk("Create conn to %s failed (%d)\n", addr_str, err);
87 start_scan();
88 }
89 }
90
start_scan(void)91 static void start_scan(void)
92 {
93 struct bt_le_scan_param scan_param = {
94 .type = BT_LE_SCAN_TYPE_PASSIVE,
95 .options = BT_LE_SCAN_OPT_NONE,
96 .interval = SCAN_INTERVAL,
97 .window = SCAN_WINDOW,
98 };
99 int err;
100
101 err = bt_le_scan_start(&scan_param, device_found);
102 if (err) {
103 printk("Scanning failed to start (err %d)\n", err);
104 return;
105 }
106
107 printk("Scanning successfully started\n");
108 }
109
110 #if defined(CONFIG_BT_GATT_CLIENT)
mtu_exchange_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_exchange_params * params)111 static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
112 struct bt_gatt_exchange_params *params)
113 {
114 printk("MTU exchange %u %s (%u)\n", bt_conn_index(conn),
115 err == 0U ? "successful" : "failed", bt_gatt_get_mtu(conn));
116 }
117
118 static struct bt_gatt_exchange_params mtu_exchange_params[CONFIG_BT_MAX_CONN];
119
mtu_exchange(struct bt_conn * conn)120 static int mtu_exchange(struct bt_conn *conn)
121 {
122 uint8_t conn_index;
123 int err;
124
125 conn_index = bt_conn_index(conn);
126
127 printk("MTU (%u): %u\n", conn_index, bt_gatt_get_mtu(conn));
128
129 mtu_exchange_params[conn_index].func = mtu_exchange_cb;
130
131 err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params[conn_index]);
132 if (err) {
133 printk("MTU exchange failed (err %d)", err);
134 } else {
135 printk("Exchange pending...");
136 }
137
138 return err;
139 }
140 #endif /* CONFIG_BT_GATT_CLIENT */
141
connected(struct bt_conn * conn,uint8_t reason)142 static void connected(struct bt_conn *conn, uint8_t reason)
143 {
144 char addr[BT_ADDR_LE_STR_LEN];
145
146 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
147
148 if (reason) {
149 printk("Failed to connect to %s (%u)\n", addr, reason);
150
151 bt_conn_unref(conn_connecting);
152 conn_connecting = NULL;
153
154 start_scan();
155 return;
156 }
157
158 conn_connecting = NULL;
159
160 conn_count++;
161 if (conn_count < conn_count_max) {
162 start_scan();
163 }
164
165 printk("Connected (%u): %s\n", conn_count, addr);
166
167 #if defined(CONFIG_BT_SMP)
168 int err = bt_conn_set_security(conn, BT_SECURITY_L2);
169
170 if (err) {
171 printk("Failed to set security (%d).\n", err);
172 }
173 #endif
174
175 #if defined(CONFIG_BT_GATT_CLIENT)
176 mtu_exchange(conn);
177 #endif
178 }
179
disconnected(struct bt_conn * conn,uint8_t reason)180 static void disconnected(struct bt_conn *conn, uint8_t reason)
181 {
182 char addr[BT_ADDR_LE_STR_LEN];
183
184 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
185
186 printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
187
188 bt_conn_unref(conn);
189
190 if ((conn_count == 1U) && (is_disconnecting || (reason == BT_HCI_ERR_CONN_FAIL_TO_ESTAB))) {
191 is_disconnecting = false;
192 start_scan();
193 }
194 conn_count--;
195 }
196
le_param_req(struct bt_conn * conn,struct bt_le_conn_param * param)197 static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
198 {
199 char addr[BT_ADDR_LE_STR_LEN];
200
201 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
202
203 printk("LE conn param req: %s int (0x%04x, 0x%04x) lat %d to %d\n",
204 addr, param->interval_min, param->interval_max, param->latency,
205 param->timeout);
206
207 return true;
208 }
209
le_param_updated(struct bt_conn * conn,uint16_t interval,uint16_t latency,uint16_t timeout)210 static void le_param_updated(struct bt_conn *conn, uint16_t interval,
211 uint16_t latency, uint16_t timeout)
212 {
213 char addr[BT_ADDR_LE_STR_LEN];
214
215 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
216
217 printk("LE conn param updated: %s int 0x%04x lat %d to %d\n",
218 addr, interval, latency, timeout);
219 }
220
221 #if defined(CONFIG_BT_SMP)
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)222 static void security_changed(struct bt_conn *conn, bt_security_t level,
223 enum bt_security_err err)
224 {
225 char addr[BT_ADDR_LE_STR_LEN];
226
227 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
228
229 if (!err) {
230 printk("Security changed: %s level %u\n", addr, level);
231 } else {
232 printk("Security failed: %s level %u err %d %s\n", addr, level,
233 err, bt_security_err_to_str(err));
234 }
235 }
236 #endif
237
238 #if defined(CONFIG_BT_USER_PHY_UPDATE)
le_phy_updated(struct bt_conn * conn,struct bt_conn_le_phy_info * param)239 static void le_phy_updated(struct bt_conn *conn,
240 struct bt_conn_le_phy_info *param)
241 {
242 char addr[BT_ADDR_LE_STR_LEN];
243
244 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
245
246 printk("LE PHY Updated: %s Tx 0x%x, Rx 0x%x\n", addr, param->tx_phy,
247 param->rx_phy);
248 }
249 #endif /* CONFIG_BT_USER_PHY_UPDATE */
250
251 #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
le_data_len_updated(struct bt_conn * conn,struct bt_conn_le_data_len_info * info)252 static void le_data_len_updated(struct bt_conn *conn,
253 struct bt_conn_le_data_len_info *info)
254 {
255 char addr[BT_ADDR_LE_STR_LEN];
256
257 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
258
259 printk("Data length updated: %s max tx %u (%u us) max rx %u (%u us)\n",
260 addr, info->tx_max_len, info->tx_max_time, info->rx_max_len,
261 info->rx_max_time);
262 }
263 #endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
264
265 static struct bt_conn_cb conn_callbacks = {
266 .connected = connected,
267 .disconnected = disconnected,
268 .le_param_req = le_param_req,
269 .le_param_updated = le_param_updated,
270
271 #if defined(CONFIG_BT_SMP)
272 .security_changed = security_changed,
273 #endif
274
275 #if defined(CONFIG_BT_USER_PHY_UPDATE)
276 .le_phy_updated = le_phy_updated,
277 #endif /* CONFIG_BT_USER_PHY_UPDATE */
278
279 #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
280 .le_data_len_updated = le_data_len_updated,
281 #endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
282 };
283
remote_info(struct bt_conn * conn,void * data)284 static void remote_info(struct bt_conn *conn, void *data)
285 {
286 struct bt_conn_remote_info remote_info;
287 char addr[BT_ADDR_LE_STR_LEN];
288 int err;
289
290 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
291
292 printk("Get remote info %s...\n", addr);
293 err = bt_conn_get_remote_info(conn, &remote_info);
294 if (err) {
295 printk("Failed remote info %s.\n", addr);
296 return;
297 }
298 printk("success.\n");
299
300 uint8_t *actual_count = (void *)data;
301
302 (*actual_count)++;
303 }
304
disconnect(struct bt_conn * conn,void * data)305 static void disconnect(struct bt_conn *conn, void *data)
306 {
307 char addr[BT_ADDR_LE_STR_LEN];
308 int err;
309
310 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
311
312 printk("Disconnecting %s...\n", addr);
313 err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
314 if (err) {
315 printk("Failed disconnection %s.\n", addr);
316 return;
317 }
318 printk("success.\n");
319 }
320
init_central(uint8_t max_conn,uint8_t iterations)321 int init_central(uint8_t max_conn, uint8_t iterations)
322 {
323 int err;
324
325 conn_count_max = max_conn;
326
327 err = bt_enable(NULL);
328 if (err) {
329 printk("Bluetooth init failed (err %d)\n", err);
330 return err;
331 }
332
333 printk("Bluetooth initialized\n");
334
335 bt_conn_cb_register(&conn_callbacks);
336
337 start_scan();
338
339 while (true) {
340 while (conn_count < conn_count_max) {
341 k_sleep(K_MSEC(10));
342 }
343
344 is_disconnecting = true;
345
346 /* Let us perform version exchange on all connections to ensure
347 * there is actual communication.
348 */
349 uint8_t actual_count = 0U;
350
351 bt_conn_foreach(BT_CONN_TYPE_LE, remote_info, &actual_count);
352 if (actual_count < conn_count_max) {
353 k_sleep(K_MSEC(10));
354
355 continue;
356 }
357
358 /* Lets wait sufficiently to ensure a stable connection
359 * before starting to disconnect for next iteration.
360 */
361 k_sleep(K_SECONDS(60));
362
363 if (!iterations) {
364 break;
365 }
366 iterations--;
367 printk("Iterations remaining: %u\n", iterations);
368
369 /* Device needing multiple connections is the one
370 * initiating the disconnects.
371 */
372 if (conn_count_max > 1U) {
373 printk("Disconnecting all...\n");
374 bt_conn_foreach(BT_CONN_TYPE_LE, disconnect, NULL);
375 } else {
376 printk("Wait for disconnections...\n");
377 }
378
379 while (is_disconnecting) {
380 k_sleep(K_MSEC(10));
381 }
382 printk("All disconnected.\n");
383 }
384
385 return 0;
386 }
387