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 
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)\n", addr, 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 
main(void)113 int main(void)
114 {
115 	struct bt_le_per_adv_sync_transfer_param past_param;
116 	int err;
117 
118 	printk("Starting Peripheral Periodic Advertising Synchronization Transfer (PAST) Demo\n");
119 
120 	/* Initialize the Bluetooth Subsystem */
121 	err = bt_enable(NULL);
122 	if (err) {
123 		printk("Bluetooth init failed (err %d)\n", err);
124 		return 0;
125 	}
126 
127 	printk("Connection callbacks register...");
128 	bt_conn_cb_register(&conn_callbacks);
129 	printk("Success\n");
130 
131 	printk("Periodic Advertising callbacks register...");
132 	bt_le_per_adv_sync_cb_register(&sync_callbacks);
133 	printk("Success.\n");
134 
135 	printk("Subscribing to periodic advertising sync transfers\n");
136 	past_param.skip = 1;
137 	past_param.timeout = 1000; /* 10 seconds */
138 	err = bt_le_per_adv_sync_transfer_subscribe(NULL /* any peer */,
139 						    &past_param);
140 	if (err) {
141 		printk("PAST subscribe failed (err %d)\n", err);
142 		return 0;
143 	}
144 
145 	err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, NULL, 0, NULL, 0);
146 	if (err) {
147 		printk("Advertising failed to start (err %d)\n", err);
148 		return 0;
149 	}
150 
151 	do {
152 		printk("Waiting for periodic sync...\n");
153 		err = k_sem_take(&sem_per_sync, K_FOREVER);
154 		if (err) {
155 			printk("failed (err %d)\n", err);
156 			return 0;
157 		}
158 		printk("Periodic sync established.\n");
159 
160 		printk("Waiting for periodic sync lost...\n");
161 		err = k_sem_take(&sem_per_sync_lost, K_FOREVER);
162 		if (err) {
163 			printk("failed (err %d)\n", err);
164 			return 0;
165 		}
166 		printk("Periodic sync lost.\n");
167 	} while (true);
168 	return 0;
169 }
170