1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/devicetree.h>
9 #include <zephyr/bluetooth/bluetooth.h>
10 #include <zephyr/bluetooth/conn.h>
11 #include <zephyr/bluetooth/hci.h>
12 
13 static struct bt_conn *default_conn;
14 
15 static K_SEM_DEFINE(sem_per_sync, 0, 1);
16 static K_SEM_DEFINE(sem_per_sync_lost, 0, 1);
17 
sync_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)18 static void sync_cb(struct bt_le_per_adv_sync *sync,
19 		    struct bt_le_per_adv_sync_synced_info *info)
20 {
21 	char le_addr[BT_ADDR_LE_STR_LEN];
22 	char past_peer_addr[BT_ADDR_LE_STR_LEN];
23 
24 	if (!info->conn) {
25 		printk("Sync not from PAST\n");
26 		return;
27 	}
28 
29 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
30 
31 	bt_addr_le_to_str(bt_conn_get_dst(info->conn), past_peer_addr,
32 			  sizeof(past_peer_addr));
33 
34 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, Interval 0x%04x (%u ms). PAST peer %s\n",
35 	       bt_le_per_adv_sync_get_index(sync), le_addr, info->interval,
36 	       info->interval * 5 / 4, past_peer_addr);
37 
38 	k_sem_give(&sem_per_sync);
39 }
40 
term_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)41 static void term_cb(struct bt_le_per_adv_sync *sync,
42 		    const struct bt_le_per_adv_sync_term_info *info)
43 {
44 	char le_addr[BT_ADDR_LE_STR_LEN];
45 
46 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
47 
48 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
49 	       bt_le_per_adv_sync_get_index(sync), le_addr);
50 
51 	k_sem_give(&sem_per_sync_lost);
52 }
53 
recv_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_recv_info * info,struct net_buf_simple * buf)54 static void recv_cb(struct bt_le_per_adv_sync *sync,
55 		    const struct bt_le_per_adv_sync_recv_info *info,
56 		    struct net_buf_simple *buf)
57 {
58 	char le_addr[BT_ADDR_LE_STR_LEN];
59 	char data_str[129];
60 
61 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
62 	bin2hex(buf->data, buf->len, data_str, sizeof(data_str));
63 
64 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s, tx_power %i, RSSI %i, CTE %u, data length %u, "
65 	       "data: %s\n", bt_le_per_adv_sync_get_index(sync), le_addr,
66 	       info->tx_power, info->rssi, info->cte_type, buf->len, data_str);
67 }
68 
69 static struct bt_le_per_adv_sync_cb sync_callbacks = {
70 	.synced = sync_cb,
71 	.term = term_cb,
72 	.recv = recv_cb
73 };
74 
connected(struct bt_conn * conn,uint8_t err)75 static void connected(struct bt_conn *conn, uint8_t err)
76 {
77 	char addr[BT_ADDR_LE_STR_LEN];
78 
79 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
80 
81 	if (default_conn == NULL) {
82 		default_conn = bt_conn_ref(conn);
83 	}
84 
85 	if (conn != default_conn) {
86 		return;
87 	}
88 
89 	printk("Connected: %s\n", addr);
90 }
91 
disconnected(struct bt_conn * conn,uint8_t reason)92 static void disconnected(struct bt_conn *conn, uint8_t reason)
93 {
94 	char addr[BT_ADDR_LE_STR_LEN];
95 
96 	if (conn != default_conn) {
97 		return;
98 	}
99 
100 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
101 
102 	printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
103 
104 	bt_conn_unref(default_conn);
105 	default_conn = NULL;
106 }
107 
108 static struct bt_conn_cb conn_callbacks = {
109 	.connected = connected,
110 	.disconnected = disconnected,
111 };
112 
113 static const struct bt_data sd[] = {
114 	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
115 };
116 
main(void)117 int main(void)
118 {
119 	struct bt_le_per_adv_sync_transfer_param past_param;
120 	int err;
121 
122 	printk("Starting Peripheral Periodic Advertising Synchronization Transfer (PAST) Demo\n");
123 
124 	/* Initialize the Bluetooth Subsystem */
125 	err = bt_enable(NULL);
126 	if (err) {
127 		printk("Bluetooth init failed (err %d)\n", err);
128 		return 0;
129 	}
130 
131 	printk("Connection callbacks register...");
132 	bt_conn_cb_register(&conn_callbacks);
133 	printk("Success\n");
134 
135 	printk("Periodic Advertising callbacks register...");
136 	bt_le_per_adv_sync_cb_register(&sync_callbacks);
137 	printk("Success.\n");
138 
139 	printk("Subscribing to periodic advertising sync transfers\n");
140 	past_param.skip = 1;
141 	past_param.timeout = 1000; /* 10 seconds */
142 	err = bt_le_per_adv_sync_transfer_subscribe(NULL /* any peer */,
143 						    &past_param);
144 	if (err) {
145 		printk("PAST subscribe failed (err %d)\n", err);
146 		return 0;
147 	}
148 
149 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, NULL, 0, sd, ARRAY_SIZE(sd));
150 	if (err) {
151 		printk("Advertising failed to start (err %d)\n", err);
152 		return 0;
153 	}
154 
155 	do {
156 		printk("Waiting for periodic sync...\n");
157 		err = k_sem_take(&sem_per_sync, K_FOREVER);
158 		if (err) {
159 			printk("failed (err %d)\n", err);
160 			return 0;
161 		}
162 		printk("Periodic sync established.\n");
163 
164 		printk("Waiting for periodic sync lost...\n");
165 		err = k_sem_take(&sem_per_sync_lost, K_FOREVER);
166 		if (err) {
167 			printk("failed (err %d)\n", err);
168 			return 0;
169 		}
170 		printk("Periodic sync lost.\n");
171 	} while (true);
172 	return 0;
173 }
174