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