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 <stddef.h>
11 #include <zephyr/sys/printk.h>
12 
13 #include <zephyr/bluetooth/bluetooth.h>
14 #include <zephyr/bluetooth/conn.h>
15 #include <zephyr/bluetooth/hci.h>
16 
17 static struct k_work work_adv_start;
18 static uint8_t conn_count_max;
19 static uint8_t volatile conn_count;
20 static uint8_t id_current;
21 static bool volatile is_disconnecting;
22 
23 static const struct bt_data ad[] = {
24 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
25 };
26 
27 static const struct bt_data sd[] = {
28 	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
29 };
30 
adv_start(struct k_work * work)31 static void adv_start(struct k_work *work)
32 {
33 	struct bt_le_adv_param adv_param = {
34 		.id = BT_ID_DEFAULT,
35 		.sid = 0,
36 		.secondary_max_skip = 0,
37 		.options = BT_LE_ADV_OPT_CONN,
38 		.interval_min = 0x0020, /* 20 ms */
39 		.interval_max = 0x0020, /* 20 ms */
40 		.peer = NULL,
41 	};
42 	size_t id_count = 0xFF;
43 	int err;
44 
45 	bt_id_get(NULL, &id_count);
46 	if (id_current == id_count) {
47 		int id;
48 
49 		id = bt_id_create(NULL, NULL);
50 		if (id < 0) {
51 			printk("Create id failed (%d)\n", id);
52 			if (id_current == 0) {
53 				id_current = conn_count_max;
54 			}
55 			id_current--;
56 		} else {
57 			printk("New id: %d\n", id);
58 		}
59 	}
60 
61 	printk("Using current id: %u\n", id_current);
62 	adv_param.id = id_current;
63 
64 	err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
65 	if (err) {
66 		printk("Advertising failed to start (err %d)\n", err);
67 		return;
68 	}
69 
70 	id_current++;
71 	if (id_current == conn_count_max) {
72 		id_current = 0;
73 	}
74 
75 	printk("Advertising successfully started\n");
76 }
77 
connected(struct bt_conn * conn,uint8_t err)78 static void connected(struct bt_conn *conn, uint8_t err)
79 {
80 	char addr[BT_ADDR_LE_STR_LEN];
81 
82 	if (err) {
83 		printk("Connection failed, err 0x%02x %s\n", err, bt_hci_err_to_str(err));
84 		return;
85 	}
86 
87 	conn_count++;
88 	if (conn_count < conn_count_max) {
89 		k_work_submit(&work_adv_start);
90 	}
91 
92 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
93 
94 	printk("Connected (%u): %s\n", conn_count, addr);
95 }
96 
disconnected(struct bt_conn * conn,uint8_t reason)97 static void disconnected(struct bt_conn *conn, uint8_t reason)
98 {
99 	char addr[BT_ADDR_LE_STR_LEN];
100 
101 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
102 
103 	printk("Disconnected %s, reason %s(0x%02x)\n", addr, bt_hci_err_to_str(reason), reason);
104 
105 	if ((conn_count == 1U) && is_disconnecting) {
106 		is_disconnecting = false;
107 		k_work_submit(&work_adv_start);
108 	}
109 	conn_count--;
110 }
111 
le_param_req(struct bt_conn * conn,struct bt_le_conn_param * param)112 static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
113 {
114 	char addr[BT_ADDR_LE_STR_LEN];
115 
116 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
117 
118 	printk("LE conn  param req: %s int (0x%04x, 0x%04x) lat %d to %d\n",
119 	       addr, param->interval_min, param->interval_max, param->latency,
120 	       param->timeout);
121 
122 	return true;
123 }
124 
le_param_updated(struct bt_conn * conn,uint16_t interval,uint16_t latency,uint16_t timeout)125 static void le_param_updated(struct bt_conn *conn, uint16_t interval,
126 			     uint16_t latency, uint16_t timeout)
127 {
128 	char addr[BT_ADDR_LE_STR_LEN];
129 
130 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
131 
132 	printk("LE conn param updated: %s int 0x%04x lat %d to %d\n",
133 	       addr, interval, latency, timeout);
134 }
135 
136 #if defined(CONFIG_BT_USER_PHY_UPDATE)
le_phy_updated(struct bt_conn * conn,struct bt_conn_le_phy_info * param)137 static void le_phy_updated(struct bt_conn *conn,
138 			   struct bt_conn_le_phy_info *param)
139 {
140 	char addr[BT_ADDR_LE_STR_LEN];
141 
142 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
143 
144 	printk("LE PHY Updated: %s Tx 0x%x, Rx 0x%x\n", addr, param->tx_phy,
145 	       param->rx_phy);
146 }
147 #endif /* CONFIG_BT_USER_PHY_UPDATE */
148 
149 #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
le_data_len_updated(struct bt_conn * conn,struct bt_conn_le_data_len_info * info)150 static void le_data_len_updated(struct bt_conn *conn,
151 				struct bt_conn_le_data_len_info *info)
152 {
153 	char addr[BT_ADDR_LE_STR_LEN];
154 
155 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
156 
157 	printk("Data length updated: %s max tx %u (%u us) max rx %u (%u us)\n",
158 	       addr, info->tx_max_len, info->tx_max_time, info->rx_max_len,
159 	       info->rx_max_time);
160 }
161 #endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
162 
163 #if defined(CONFIG_BT_SMP)
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)164 static void security_changed(struct bt_conn *conn, bt_security_t level,
165 			     enum bt_security_err err)
166 {
167 	char addr[BT_ADDR_LE_STR_LEN];
168 
169 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
170 
171 	if (!err) {
172 		printk("Security changed: %s level %u\n", addr, level);
173 	} else {
174 		printk("Security failed: %s level %u err %s(%d)\n", addr, level,
175 		       bt_security_err_to_str(err), err);
176 	}
177 }
178 
auth_cancel(struct bt_conn * conn)179 static void auth_cancel(struct bt_conn *conn)
180 {
181 	char addr[BT_ADDR_LE_STR_LEN];
182 
183 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
184 
185 	printk("Pairing cancelled: %s\n", addr);
186 }
187 
188 static struct bt_conn_auth_cb auth_callbacks = {
189 	.cancel = auth_cancel,
190 };
191 #endif /* CONFIG_BT_SMP */
192 
193 static struct bt_conn_cb conn_callbacks = {
194 	.connected = connected,
195 	.disconnected = disconnected,
196 	.le_param_req = le_param_req,
197 	.le_param_updated = le_param_updated,
198 
199 #if defined(CONFIG_BT_SMP)
200 	.security_changed = security_changed,
201 #endif /* CONFIG_BT_SMP */
202 
203 #if defined(CONFIG_BT_USER_PHY_UPDATE)
204 	.le_phy_updated = le_phy_updated,
205 #endif /* CONFIG_BT_USER_PHY_UPDATE */
206 
207 #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
208 	.le_data_len_updated = le_data_len_updated,
209 #endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
210 };
211 
212 #if defined(CONFIG_BT_OBSERVER)
213 #define BT_LE_SCAN_PASSIVE_ALLOW_DUPILCATES \
214 		BT_LE_SCAN_PARAM(BT_LE_SCAN_TYPE_PASSIVE, \
215 				 BT_LE_SCAN_OPT_NONE, \
216 				 BT_GAP_SCAN_FAST_INTERVAL, \
217 				 BT_GAP_SCAN_FAST_INTERVAL)
218 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)219 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
220 			 struct net_buf_simple *ad)
221 {
222 	char addr_str[BT_ADDR_LE_STR_LEN];
223 
224 	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
225 	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
226 }
227 #endif /* CONFIG_BT_OBSERVER */
228 
disconnect(struct bt_conn * conn,void * data)229 static void disconnect(struct bt_conn *conn, void *data)
230 {
231 	char addr[BT_ADDR_LE_STR_LEN];
232 	int err;
233 
234 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
235 
236 	printk("Disconnecting %s...\n", addr);
237 	err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
238 	if (err) {
239 		printk("Failed disconnection %s.\n", addr);
240 		return;
241 	}
242 	printk("success.\n");
243 }
244 
init_peripheral(uint8_t max_conn,uint8_t iterations)245 int init_peripheral(uint8_t max_conn, uint8_t iterations)
246 {
247 	size_t id_count;
248 	int err;
249 
250 	conn_count_max = max_conn;
251 
252 	err = bt_enable(NULL);
253 	if (err) {
254 		printk("Bluetooth init failed (err %d)\n", err);
255 		return err;
256 	}
257 
258 	bt_conn_cb_register(&conn_callbacks);
259 
260 #if defined(CONFIG_BT_SMP)
261 	bt_conn_auth_cb_register(&auth_callbacks);
262 #endif /* CONFIG_BT_SMP */
263 
264 	printk("Bluetooth initialized\n");
265 
266 #if defined(CONFIG_BT_OBSERVER)
267 	printk("Start continuous passive scanning...");
268 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE_ALLOW_DUPILCATES,
269 			       device_found);
270 	if (err) {
271 		printk("Scan start failed (%d).\n", err);
272 		return err;
273 	}
274 	printk("success.\n");
275 #endif /* CONFIG_BT_OBSERVER */
276 
277 	k_work_init(&work_adv_start, adv_start);
278 	k_work_submit(&work_adv_start);
279 
280 	/* wait for connection attempts on all identities */
281 	do {
282 		k_sleep(K_MSEC(10));
283 
284 		id_count = 0xFF;
285 		bt_id_get(NULL, &id_count);
286 	} while (id_count != conn_count_max);
287 
288 	/* rotate identities so reconnections are attempted in case of any
289 	 * disconnections
290 	 */
291 	uint8_t prev_count = conn_count;
292 	while (1) {
293 		/* If maximum connections is reached, wait for disconnections
294 		 */
295 		if (conn_count == conn_count_max) {
296 			is_disconnecting = true;
297 
298 			/* Lets wait sufficiently to ensure a stable connection
299 			 * before starting to disconnect for next iteration.
300 			 */
301 			k_sleep(K_SECONDS(60));
302 
303 			if (!iterations) {
304 				break;
305 			}
306 			iterations--;
307 			printk("Iterations remaining: %u\n", iterations);
308 
309 			/* Device needing multiple connections is the one
310 			 * initiating the disconnects.
311 			 */
312 			if (conn_count_max > 1U) {
313 				printk("Disconnecting all...\n");
314 				bt_conn_foreach(BT_CONN_TYPE_LE, disconnect, NULL);
315 			} else {
316 				printk("Wait for disconnections...\n");
317 			}
318 
319 			while (is_disconnecting) {
320 				k_sleep(K_MSEC(10));
321 			}
322 			printk("All disconnected.\n");
323 
324 			continue;
325 		}
326 
327 		/* As long as there is connection count changes, identity
328 		 * rotation in this loop is not needed.
329 		 */
330 		if (prev_count != conn_count) {
331 			prev_count = conn_count;
332 
333 			continue;
334 		} else {
335 			uint16_t wait = 6200U;
336 
337 			/* Maximum duration without connection count change,
338 			 * central waiting before disconnecting all its
339 			 * connections plus few seconds of margin.
340 			 */
341 			while ((prev_count == conn_count) && wait) {
342 				printk("Waiting connections (%u/%u) %u...\n",
343 				       prev_count, conn_count, wait);
344 
345 				wait--;
346 
347 				k_sleep(K_MSEC(10));
348 			}
349 
350 			if (wait) {
351 				continue;
352 			}
353 		}
354 
355 		/* Stopping and restarting advertising to use new identity */
356 		printk("Stop advertising...\n");
357 		err = bt_le_adv_stop();
358 		if (err) {
359 			printk("Failed to stop advertising (%d)\n", err);
360 
361 			return err;
362 		}
363 
364 		k_work_submit(&work_adv_start);
365 	}
366 
367 	return 0;
368 }
369