1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/bluetooth.h>
8 #include <zephyr/bluetooth/conn.h>
9 #include <zephyr/bluetooth/gap.h>
10 #include <zephyr/bluetooth/hci.h>
11 
12 #define NUM_RSP_SLOTS	  5
13 #define NUM_SUBEVENTS	  5
14 #define PACKET_SIZE	  5
15 #define SUBEVENT_INTERVAL 0x30
16 
17 static const struct bt_le_per_adv_param per_adv_params = {
18 	.interval_min = 0xFF,
19 	.interval_max = 0xFF,
20 	.options = 0,
21 	.num_subevents = NUM_SUBEVENTS,
22 	.subevent_interval = SUBEVENT_INTERVAL,
23 	.response_slot_delay = 0x5,
24 	.response_slot_spacing = 0x50,
25 	.num_response_slots = NUM_RSP_SLOTS,
26 };
27 
28 static struct bt_le_per_adv_subevent_data_params subevent_data_params[NUM_SUBEVENTS];
29 static struct net_buf_simple bufs[NUM_SUBEVENTS];
30 static uint8_t backing_store[NUM_SUBEVENTS][PACKET_SIZE];
31 
32 BUILD_ASSERT(ARRAY_SIZE(bufs) == ARRAY_SIZE(subevent_data_params));
33 BUILD_ASSERT(ARRAY_SIZE(backing_store) == ARRAY_SIZE(subevent_data_params));
34 
request_cb(struct bt_le_ext_adv * adv,const struct bt_le_per_adv_data_request * request)35 static void request_cb(struct bt_le_ext_adv *adv, const struct bt_le_per_adv_data_request *request)
36 {
37 	int err;
38 	uint8_t to_send;
39 
40 	/* Continuously send the same dummy data and listen to all response slots */
41 
42 	to_send = MIN(request->count, ARRAY_SIZE(subevent_data_params));
43 	for (size_t i = 0; i < to_send; i++) {
44 		subevent_data_params[i].subevent =
45 			(request->start + i) % per_adv_params.num_subevents;
46 		subevent_data_params[i].response_slot_start = 0;
47 		subevent_data_params[i].response_slot_count = NUM_RSP_SLOTS;
48 		subevent_data_params[i].data = &bufs[i];
49 	}
50 
51 	err = bt_le_per_adv_set_subevent_data(adv, to_send, subevent_data_params);
52 	if (err) {
53 		printk("Failed to set subevent data (err %d)\n", err);
54 	}
55 }
56 
get_address(struct bt_data * data,void * user_data)57 static bool get_address(struct bt_data *data, void *user_data)
58 {
59 	bt_addr_le_t *addr = user_data;
60 
61 	if (data->type == BT_DATA_LE_BT_DEVICE_ADDRESS) {
62 		memcpy(addr->a.val, data->data, sizeof(addr->a.val));
63 		addr->type = data->data[sizeof(addr->a)];
64 
65 		return false;
66 	}
67 
68 	return true;
69 }
70 
71 static struct bt_conn *default_conn;
72 
response_cb(struct bt_le_ext_adv * adv,struct bt_le_per_adv_response_info * info,struct net_buf_simple * buf)73 static void response_cb(struct bt_le_ext_adv *adv, struct bt_le_per_adv_response_info *info,
74 			struct net_buf_simple *buf)
75 {
76 	int err;
77 	bt_addr_le_t peer;
78 	char addr_str[BT_ADDR_LE_STR_LEN];
79 	struct bt_conn_le_create_synced_param synced_param;
80 	struct bt_le_conn_param conn_param;
81 
82 	if (!buf) {
83 		return;
84 	}
85 
86 	if (default_conn) {
87 		/* Do not initiate new connections while already connected */
88 		return;
89 	}
90 
91 	bt_addr_le_copy(&peer, &bt_addr_le_none);
92 	bt_data_parse(buf, get_address, &peer);
93 	if (bt_addr_le_eq(&peer, &bt_addr_le_none)) {
94 		/* No address found */
95 		return;
96 	}
97 
98 	bt_addr_le_to_str(&peer, addr_str, sizeof(addr_str));
99 	printk("Connecting to %s in subevent %d\n", addr_str, info->subevent);
100 
101 	synced_param.peer = &peer;
102 	synced_param.subevent = info->subevent;
103 
104 	/* Choose same interval as PAwR advertiser to avoid scheduling conflicts */
105 	conn_param.interval_min = SUBEVENT_INTERVAL;
106 	conn_param.interval_max = SUBEVENT_INTERVAL;
107 
108 	/* Default values */
109 	conn_param.latency = 0;
110 	conn_param.timeout = 400;
111 
112 	err = bt_conn_le_create_synced(adv, &synced_param, &conn_param, &default_conn);
113 	if (err) {
114 		printk("Failed to initiate connection (err %d)", err);
115 	}
116 }
117 
118 static const struct bt_le_ext_adv_cb adv_cb = {
119 	.pawr_data_request = request_cb,
120 	.pawr_response = response_cb,
121 };
122 
connected_cb(struct bt_conn * conn,uint8_t err)123 static void connected_cb(struct bt_conn *conn, uint8_t err)
124 {
125 	printk("Connected (err 0x%02X)\n", err);
126 
127 	__ASSERT(conn == default_conn, "Unexpected connected callback");
128 
129 	if (err) {
130 		bt_conn_unref(default_conn);
131 		default_conn = NULL;
132 	}
133 }
134 
disconnected_cb(struct bt_conn * conn,uint8_t reason)135 static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
136 {
137 	printk("Disconnected, reason 0x%02X %s\n", reason, bt_hci_err_to_str(reason));
138 
139 	__ASSERT(conn == default_conn, "Unexpected disconnected callback");
140 
141 	bt_conn_unref(default_conn);
142 	default_conn = NULL;
143 }
144 
145 BT_CONN_CB_DEFINE(conn_cb) = {
146 	.connected = connected_cb,
147 	.disconnected = disconnected_cb,
148 };
149 
init_bufs(void)150 static void init_bufs(void)
151 {
152 	/* Set up some dummy data to send */
153 	for (size_t i = 0; i < ARRAY_SIZE(backing_store); i++) {
154 		backing_store[i][0] = ARRAY_SIZE(backing_store[i]) - 1;
155 		backing_store[i][1] = BT_DATA_MANUFACTURER_DATA;
156 		backing_store[i][2] = 0x59; /* Nordic */
157 		backing_store[i][3] = 0x00;
158 
159 		net_buf_simple_init_with_data(&bufs[i], &backing_store[i],
160 					      ARRAY_SIZE(backing_store[i]));
161 	}
162 }
163 
164 static const struct bt_data ad[] = {
165 	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
166 };
167 
168 
main(void)169 int main(void)
170 {
171 	int err;
172 	struct bt_le_ext_adv *pawr_adv;
173 
174 	init_bufs();
175 
176 	printk("Starting Periodic Advertising Demo\n");
177 
178 	/* Initialize the Bluetooth Subsystem */
179 	err = bt_enable(NULL);
180 	if (err) {
181 		printk("Bluetooth init failed (err %d)\n", err);
182 		return 0;
183 	}
184 
185 	/* Create a non-connectable advertising set */
186 	err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, &adv_cb, &pawr_adv);
187 	if (err) {
188 		printk("Failed to create advertising set (err %d)\n", err);
189 		return 0;
190 	}
191 
192 	/* Set advertising data to have complete local name set */
193 	err = bt_le_ext_adv_set_data(pawr_adv, ad, ARRAY_SIZE(ad), NULL, 0);
194 	if (err) {
195 		printk("Failed to set advertising data (err %d)\n", err);
196 		return 0;
197 	}
198 
199 	/* Set periodic advertising parameters */
200 	err = bt_le_per_adv_set_param(pawr_adv, &per_adv_params);
201 	if (err) {
202 		printk("Failed to set periodic advertising parameters (err %d)\n", err);
203 		return 0;
204 	}
205 
206 	/* Enable Periodic Advertising */
207 	err = bt_le_per_adv_start(pawr_adv);
208 	if (err) {
209 		printk("Failed to enable periodic advertising (err %d)\n", err);
210 		return 0;
211 	}
212 
213 	printk("Start Periodic Advertising\n");
214 	err = bt_le_ext_adv_start(pawr_adv, BT_LE_EXT_ADV_START_DEFAULT);
215 	if (err) {
216 		printk("Failed to start extended advertising (err %d)\n", err);
217 		return 0;
218 	}
219 
220 	while (true) {
221 		k_sleep(K_SECONDS(1));
222 	}
223 
224 	return 0;
225 }
226