1 /*
2  * Copyright (c) 2021-2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 
9 #include <zephyr/bluetooth/gap.h>
10 #include <zephyr/device.h>
11 #include <zephyr/devicetree.h>
12 #include <zephyr/bluetooth/bluetooth.h>
13 #include <zephyr/bluetooth/conn.h>
14 #include <zephyr/bluetooth/hci.h>
15 #include <zephyr/sys/util.h>
16 
17 #define NAME_LEN            30
18 
19 static bool per_adv_found;
20 static bt_addr_le_t per_addr;
21 static uint8_t per_sid;
22 static struct bt_conn *default_conn;
23 static uint16_t per_adv_sync_timeout;
24 
25 static K_SEM_DEFINE(sem_conn, 0, 1);
26 static K_SEM_DEFINE(sem_conn_lost, 0, 1);
27 static K_SEM_DEFINE(sem_per_adv, 0, 1);
28 static K_SEM_DEFINE(sem_per_sync, 0, 1);
29 
data_cb(struct bt_data * data,void * user_data)30 static bool data_cb(struct bt_data *data, void *user_data)
31 {
32 	char *name = user_data;
33 	uint8_t len;
34 
35 	switch (data->type) {
36 	case BT_DATA_NAME_SHORTENED:
37 	case BT_DATA_NAME_COMPLETE:
38 		len = MIN(data->data_len, NAME_LEN - 1);
39 		memcpy(name, data->data, len);
40 		name[len] = '\0';
41 		return false;
42 	default:
43 		return true;
44 	}
45 }
46 
phy2str(uint8_t phy)47 static const char *phy2str(uint8_t phy)
48 {
49 	switch (phy) {
50 	case 0: return "No packets";
51 	case BT_GAP_LE_PHY_1M: return "LE 1M";
52 	case BT_GAP_LE_PHY_2M: return "LE 2M";
53 	case BT_GAP_LE_PHY_CODED: return "LE Coded";
54 	default: return "Unknown";
55 	}
56 }
57 
scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)58 static void scan_recv(const struct bt_le_scan_recv_info *info,
59 		      struct net_buf_simple *buf)
60 {
61 	char le_addr[BT_ADDR_LE_STR_LEN];
62 	char name[NAME_LEN];
63 	int err;
64 
65 	/* only parse devices in close proximity */
66 	if (info->rssi < -70) {
67 		return;
68 	}
69 
70 	(void)memset(name, 0, sizeof(name));
71 
72 	bt_data_parse(buf, data_cb, name);
73 
74 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
75 
76 	printk("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i, name: %s "
77 	       "C:%u S:%u D:%u SR:%u E:%u Prim: %s, Secn: %s, "
78 	       "Interval: 0x%04x (%u ms), SID: %u\n",
79 	       le_addr, info->adv_type, info->tx_power, info->rssi, name,
80 	       (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
81 	       (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
82 	       (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
83 	       (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
84 	       (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0,
85 	       phy2str(info->primary_phy), phy2str(info->secondary_phy),
86 	       info->interval, info->interval * 5 / 4, info->sid);
87 
88 	/* If connectable, connect */
89 	if (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) {
90 		if (default_conn) {
91 			return;
92 		}
93 
94 		printk("Connecting to %s\n", le_addr);
95 
96 		err = bt_le_scan_stop();
97 		if (err != 0) {
98 			printk("Stop LE scan failed (err %d)\n", err);
99 			return;
100 		}
101 
102 		err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN,
103 					BT_LE_CONN_PARAM_DEFAULT,
104 					&default_conn);
105 		if (err != 0) {
106 			printk("Failed to connect (err %d)\n", err);
107 			return;
108 		}
109 	} else {
110 		/* If info->interval it is a periodic advertiser, mark for sync */
111 		if (!per_adv_found && info->interval) {
112 			uint32_t interval_us;
113 			uint32_t timeout;
114 
115 			per_adv_found = true;
116 
117 			/* Add retries and convert to unit in 10's of ms */
118 			interval_us = BT_GAP_PER_ADV_INTERVAL_TO_US(info->interval);
119 
120 			timeout = BT_GAP_US_TO_PER_ADV_SYNC_TIMEOUT(interval_us);
121 
122 			/* 10 attempts */
123 			timeout *= 10;
124 
125 			/* Enforce restraints */
126 			per_adv_sync_timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT,
127 						     BT_GAP_PER_ADV_MAX_TIMEOUT);
128 
129 			per_sid = info->sid;
130 			bt_addr_le_copy(&per_addr, info->addr);
131 
132 			k_sem_give(&sem_per_adv);
133 		}
134 	}
135 }
136 
137 static struct bt_le_scan_cb scan_callbacks = {
138 	.recv = scan_recv,
139 };
140 
connected(struct bt_conn * conn,uint8_t err)141 static void connected(struct bt_conn *conn, uint8_t err)
142 {
143 	char addr[BT_ADDR_LE_STR_LEN];
144 	int bt_err;
145 
146 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
147 
148 	if (err != 0) {
149 		printk("Failed to connect to %s %u %s\n", addr, err, bt_hci_err_to_str(err));
150 
151 		bt_conn_unref(default_conn);
152 		default_conn = NULL;
153 
154 
155 		bt_err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
156 		if (bt_err) {
157 			printk("Failed to start scan (err %d)\n", bt_err);
158 			return;
159 		}
160 
161 		return;
162 	}
163 
164 	if (conn != default_conn) {
165 		return;
166 	}
167 
168 	printk("Connected: %s\n", addr);
169 
170 	k_sem_give(&sem_conn);
171 }
172 
disconnected(struct bt_conn * conn,uint8_t reason)173 static void disconnected(struct bt_conn *conn, uint8_t reason)
174 {
175 	char addr[BT_ADDR_LE_STR_LEN];
176 	int err;
177 
178 	if (conn != default_conn) {
179 		return;
180 	}
181 
182 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
183 
184 	printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
185 
186 	bt_conn_unref(default_conn);
187 	default_conn = NULL;
188 
189 	k_sem_give(&sem_conn_lost);
190 
191 	err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
192 	if (err != 0) {
193 		printk("Failed to start scan (err %d)\n", err);
194 		return;
195 	}
196 }
197 
198 static struct bt_conn_cb conn_callbacks = {
199 	.connected = connected,
200 	.disconnected = disconnected,
201 };
202 
sync_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)203 static void sync_cb(struct bt_le_per_adv_sync *sync,
204 		    struct bt_le_per_adv_sync_synced_info *info)
205 {
206 	char le_addr[BT_ADDR_LE_STR_LEN];
207 
208 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
209 
210 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, "
211 	       "Interval 0x%04x (%u ms), PHY %s\n",
212 	       bt_le_per_adv_sync_get_index(sync), le_addr,
213 	       info->interval, info->interval * 5 / 4, phy2str(info->phy));
214 
215 	k_sem_give(&sem_per_sync);
216 }
217 
term_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)218 static void term_cb(struct bt_le_per_adv_sync *sync,
219 		    const struct bt_le_per_adv_sync_term_info *info)
220 {
221 	char le_addr[BT_ADDR_LE_STR_LEN];
222 
223 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
224 
225 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
226 	       bt_le_per_adv_sync_get_index(sync), le_addr);
227 }
228 
recv_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_recv_info * info,struct net_buf_simple * buf)229 static void recv_cb(struct bt_le_per_adv_sync *sync,
230 		    const struct bt_le_per_adv_sync_recv_info *info,
231 		    struct net_buf_simple *buf)
232 {
233 	char le_addr[BT_ADDR_LE_STR_LEN];
234 	char data_str[129];
235 
236 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
237 	bin2hex(buf->data, buf->len, data_str, sizeof(data_str));
238 
239 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s, tx_power %i, "
240 	       "RSSI %i, CTE %u, data length %u, data: %s\n",
241 	       bt_le_per_adv_sync_get_index(sync), le_addr, info->tx_power,
242 	       info->rssi, info->cte_type, buf->len, data_str);
243 }
244 
245 static struct bt_le_per_adv_sync_cb sync_callbacks = {
246 	.synced = sync_cb,
247 	.term = term_cb,
248 	.recv = recv_cb
249 };
250 
main(void)251 int main(void)
252 {
253 	struct bt_le_per_adv_sync_param sync_create_param;
254 	struct bt_le_per_adv_sync *sync;
255 	int err;
256 	char le_addr[BT_ADDR_LE_STR_LEN];
257 
258 	printk("Starting Central Periodic Advertising Synchronization Transfer (PAST) Demo\n");
259 
260 	/* Initialize the Bluetooth Subsystem */
261 	err = bt_enable(NULL);
262 	if (err != 0) {
263 		printk("failed to enable BT (err %d)\n", err);
264 		return 0;
265 	}
266 
267 	printk("Connection callbacks register\n");
268 	bt_conn_cb_register(&conn_callbacks);
269 
270 	printk("Scan callbacks register\n");
271 	bt_le_scan_cb_register(&scan_callbacks);
272 
273 	printk("Periodic Advertising callbacks register\n");
274 	bt_le_per_adv_sync_cb_register(&sync_callbacks);
275 
276 	printk("Start scanning...");
277 	err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
278 	if (err != 0) {
279 		printk("failed (err %d)\n", err);
280 		return 0;
281 	}
282 	printk("success.\n");
283 
284 	do {
285 		printk("Waiting for connection...\n");
286 		err = k_sem_take(&sem_conn, K_FOREVER);
287 		if (err != 0) {
288 			printk("Could not take sem_conn (err %d)\n", err);
289 			return 0;
290 		}
291 		printk("Connected.\n");
292 
293 		printk("Start scanning for PA...\n");
294 		per_adv_found = false;
295 		err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
296 		if (err != 0) {
297 			printk("failed (err %d)\n", err);
298 			return 0;
299 		}
300 		printk("Scan started.\n");
301 
302 		printk("Waiting for periodic advertising...\n");
303 		err = k_sem_take(&sem_per_adv, K_FOREVER);
304 		if (err != 0) {
305 			printk("Could not take sem_per_adv (err %d)\n", err);
306 			return 0;
307 		}
308 		printk("Found periodic advertising.\n");
309 
310 		bt_addr_le_to_str(&per_addr, le_addr, sizeof(le_addr));
311 		printk("Creating Periodic Advertising Sync to %s...\n", le_addr);
312 		bt_addr_le_copy(&sync_create_param.addr, &per_addr);
313 		sync_create_param.options = 0;
314 		sync_create_param.sid = per_sid;
315 		sync_create_param.skip = 0;
316 		sync_create_param.timeout = per_adv_sync_timeout;
317 		err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
318 		if (err != 0) {
319 			printk("failed (err %d)\n", err);
320 			return 0;
321 		}
322 		printk("success.\n");
323 
324 		printk("Waiting for periodic sync...\n");
325 		err = k_sem_take(&sem_per_sync, K_FOREVER);
326 		if (err != 0) {
327 			printk("failed (err %d)\n", err);
328 			return 0;
329 		}
330 		printk("Periodic sync established.\n");
331 
332 		printk("Transferring sync\n");
333 		err = bt_le_per_adv_sync_transfer(sync, default_conn, 0);
334 		if (err != 0) {
335 			printk("Could not transfer sync (err %d)\n", err);
336 			return 0;
337 		}
338 
339 		printk("Waiting for connection lost...\n");
340 		err = k_sem_take(&sem_conn_lost, K_FOREVER);
341 		if (err != 0) {
342 			printk("Could not take sem_conn_lost (err %d)\n", err);
343 			return 0;
344 		}
345 		printk("Connection lost.\n");
346 	} while (true);
347 }
348