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