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