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