1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/printk.h>
9 
10 #include <zephyr/bluetooth/bluetooth.h>
11 #include <zephyr/bluetooth/conn.h>
12 #include <zephyr/bluetooth/gatt.h>
13 #include <zephyr/bluetooth/hci.h>
14 
15 /* Count down number of metrics intervals before performing a PHY update */
16 #define PHY_UPDATE_COUNTDOWN 3U
17 static uint32_t phy_update_countdown;
18 static uint8_t phy_param_idx;
19 
phy_update_iterate(struct bt_conn * conn)20 static void phy_update_iterate(struct bt_conn *conn)
21 {
22 	const struct bt_conn_le_phy_param phy_param[] = {
23 		/* List of 1M Tx with Rx on other PHYs */
24 		{
25 			.options = BT_CONN_LE_PHY_OPT_NONE,
26 			.pref_tx_phy = BT_GAP_LE_PHY_1M,
27 			.pref_rx_phy = BT_GAP_LE_PHY_1M,
28 		}, {
29 			.options = BT_CONN_LE_PHY_OPT_NONE,
30 			.pref_tx_phy = BT_GAP_LE_PHY_1M,
31 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
32 		}, {
33 			.options = BT_CONN_LE_PHY_OPT_NONE,
34 			.pref_tx_phy = BT_GAP_LE_PHY_1M,
35 			.pref_rx_phy = BT_GAP_LE_PHY_CODED,
36 		},
37 
38 		/* List of 2M Tx with Rx on other PHYs */
39 		{
40 			.options = BT_CONN_LE_PHY_OPT_NONE,
41 			.pref_tx_phy = BT_GAP_LE_PHY_2M,
42 			.pref_rx_phy = BT_GAP_LE_PHY_1M,
43 		}, {
44 			.options = BT_CONN_LE_PHY_OPT_NONE,
45 			.pref_tx_phy = BT_GAP_LE_PHY_2M,
46 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
47 		}, {
48 			.options = BT_CONN_LE_PHY_OPT_NONE,
49 			.pref_tx_phy = BT_GAP_LE_PHY_2M,
50 			.pref_rx_phy = BT_GAP_LE_PHY_CODED,
51 		},
52 
53 		/* List of Coded PHY S8 Tx with Rx on other PHYs */
54 		{
55 			.options = BT_CONN_LE_PHY_OPT_CODED_S8,
56 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
57 			.pref_rx_phy = BT_GAP_LE_PHY_1M,
58 		}, {
59 			.options = BT_CONN_LE_PHY_OPT_CODED_S8,
60 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
61 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
62 		}, {
63 			.options = BT_CONN_LE_PHY_OPT_CODED_S8,
64 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
65 			.pref_rx_phy = BT_GAP_LE_PHY_CODED,
66 		},
67 
68 		/* List of Coded PHY S2 Tx with Rx on other PHYs */
69 		{
70 			.options = BT_CONN_LE_PHY_OPT_CODED_S2,
71 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
72 			.pref_rx_phy = BT_GAP_LE_PHY_1M,
73 		}, {
74 			.options = BT_CONN_LE_PHY_OPT_CODED_S2,
75 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
76 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
77 		}, {
78 			.options = BT_CONN_LE_PHY_OPT_CODED_S2,
79 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
80 			.pref_rx_phy = BT_GAP_LE_PHY_CODED,
81 		},
82 
83 		/* Finally stop at 2M Tx with Rx on 2M */
84 		{
85 			.options = BT_CONN_LE_PHY_OPT_NONE,
86 			.pref_tx_phy = BT_GAP_LE_PHY_2M,
87 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
88 		},
89 	};
90 	int err;
91 
92 	if (phy_update_countdown--) {
93 		return;
94 	}
95 
96 	phy_update_countdown = PHY_UPDATE_COUNTDOWN;
97 
98 	phy_param_idx++;
99 	if (phy_param_idx >= ARRAY_SIZE(phy_param)) {
100 		/* No more PHY updates, stay at the last index */
101 		phy_param_idx = ARRAY_SIZE(phy_param);
102 		return;
103 	}
104 
105 	struct bt_conn_info conn_info;
106 
107 	err = bt_conn_get_info(conn, &conn_info);
108 	if (err) {
109 		printk("Failed to get connection info (%d).\n", err);
110 		return;
111 	}
112 
113 	struct bt_conn_le_phy_param conn_phy_param;
114 
115 	if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
116 		conn_phy_param.options = phy_param[phy_param_idx].options;
117 		conn_phy_param.pref_tx_phy = phy_param[phy_param_idx].pref_tx_phy;
118 		conn_phy_param.pref_rx_phy = phy_param[phy_param_idx].pref_rx_phy;
119 	} else {
120 		conn_phy_param.options = phy_param[phy_param_idx].options;
121 		conn_phy_param.pref_tx_phy = phy_param[phy_param_idx].pref_rx_phy;
122 		conn_phy_param.pref_rx_phy = phy_param[phy_param_idx].pref_tx_phy;
123 	}
124 
125 	printk("%s: PHY Update requested %u %u (%u)\n", __func__,
126 	       conn_phy_param.pref_tx_phy,
127 	       conn_phy_param.pref_rx_phy,
128 	       conn_phy_param.options);
129 
130 	err = bt_conn_le_phy_update(conn, &conn_phy_param);
131 	if (err) {
132 		printk("Failed to update PHY (%d).\n", err);
133 		return;
134 	}
135 }
136 
137 /* Interval between storing the measured write rate */
138 #define METRICS_INTERVAL 1U /* seconds */
139 
140 static struct bt_gatt_exchange_params mtu_exchange_params;
141 static uint32_t write_count;
142 static uint32_t write_len;
143 static uint32_t write_rate;
144 
145 /* Globals, reused by central_gatt_write and peripheral_gatt_write samples */
146 struct bt_conn *conn_connected;
147 uint32_t last_write_rate;
148 void (*start_scan_func)(void);
149 
write_cmd_cb(struct bt_conn * conn,void * user_data)150 static void write_cmd_cb(struct bt_conn *conn, void *user_data)
151 {
152 	static uint32_t cycle_stamp;
153 	uint64_t delta;
154 
155 	delta = k_cycle_get_32() - cycle_stamp;
156 	delta = k_cyc_to_ns_floor64(delta);
157 
158 	if (delta == 0) {
159 		/* Skip division by zero */
160 		return;
161 	}
162 
163 	/* if last data rx-ed was greater than 1 second in the past,
164 	 * reset the metrics.
165 	 */
166 	if (delta > (METRICS_INTERVAL * NSEC_PER_SEC)) {
167 		printk("%s: count= %u, len= %u, rate= %u bps.\n", __func__,
168 		       write_count, write_len, write_rate);
169 
170 		last_write_rate = write_rate;
171 
172 		write_count = 0U;
173 		write_len = 0U;
174 		write_rate = 0U;
175 		cycle_stamp = k_cycle_get_32();
176 
177 		if (IS_ENABLED(CONFIG_BT_USER_PHY_UPDATE)) {
178 			phy_update_iterate(conn);
179 		}
180 
181 	} else {
182 		uint16_t len;
183 
184 		write_count++;
185 
186 		/* Extract the 16-bit data length stored in user_data */
187 		len = (uint32_t)user_data & 0xFFFF;
188 
189 		write_len += len;
190 		write_rate = ((uint64_t)write_len << 3) * (METRICS_INTERVAL * NSEC_PER_SEC) /
191 			     delta;
192 	}
193 }
194 
mtu_exchange_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_exchange_params * params)195 static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
196 			    struct bt_gatt_exchange_params *params)
197 {
198 	printk("%s: MTU exchange %s (%u)\n", __func__,
199 	       err == 0U ? "successful" : "failed",
200 	       bt_gatt_get_mtu(conn));
201 }
202 
mtu_exchange(struct bt_conn * conn)203 static int mtu_exchange(struct bt_conn *conn)
204 {
205 	int err;
206 
207 	printk("%s: Current MTU = %u\n", __func__, bt_gatt_get_mtu(conn));
208 
209 	mtu_exchange_params.func = mtu_exchange_cb;
210 
211 	printk("%s: Exchange MTU...\n", __func__);
212 	err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params);
213 	if (err) {
214 		printk("%s: MTU exchange failed (err %d)", __func__, err);
215 	}
216 
217 	return err;
218 }
219 
connected(struct bt_conn * conn,uint8_t conn_err)220 static void connected(struct bt_conn *conn, uint8_t conn_err)
221 {
222 	struct bt_conn_info conn_info;
223 	char addr[BT_ADDR_LE_STR_LEN];
224 	int err;
225 
226 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
227 
228 	if (conn_err) {
229 		printk("%s: Failed to connect to %s (%u)\n", __func__, addr,
230 		       conn_err);
231 		return;
232 	}
233 
234 	err = bt_conn_get_info(conn, &conn_info);
235 	if (err) {
236 		printk("Failed to get connection info (%d).\n", err);
237 		return;
238 	}
239 
240 	printk("%s: %s role %u\n", __func__, addr, conn_info.role);
241 
242 	conn_connected = bt_conn_ref(conn);
243 
244 	(void)mtu_exchange(conn);
245 
246 #if defined(CONFIG_BT_SMP)
247 	if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
248 		err = bt_conn_set_security(conn, BT_SECURITY_L2);
249 		if (err) {
250 			printk("Failed to set security (%d).\n", err);
251 		}
252 	}
253 #endif
254 
255 	if (IS_ENABLED(CONFIG_BT_USER_PHY_UPDATE)) {
256 		phy_update_countdown = PHY_UPDATE_COUNTDOWN;
257 		phy_param_idx = 0U;
258 	}
259 }
260 
disconnected(struct bt_conn * conn,uint8_t reason)261 static void disconnected(struct bt_conn *conn, uint8_t reason)
262 {
263 	struct bt_conn_info conn_info;
264 	char addr[BT_ADDR_LE_STR_LEN];
265 	int err;
266 
267 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
268 
269 	err = bt_conn_get_info(conn, &conn_info);
270 	if (err) {
271 		printk("Failed to get connection info (%d).\n", err);
272 		return;
273 	}
274 
275 	printk("%s: %s role %u, reason %u %s\n", __func__, addr, conn_info.role,
276 	       reason, bt_hci_err_to_str(reason));
277 
278 	conn_connected = NULL;
279 
280 	bt_conn_unref(conn);
281 
282 	if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
283 		start_scan_func();
284 	}
285 }
286 
le_param_req(struct bt_conn * conn,struct bt_le_conn_param * param)287 static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
288 {
289 	printk("%s: int (0x%04x, 0x%04x) lat %u to %u\n", __func__,
290 	       param->interval_min, param->interval_max, param->latency,
291 	       param->timeout);
292 
293 	return true;
294 }
295 
le_param_updated(struct bt_conn * conn,uint16_t interval,uint16_t latency,uint16_t timeout)296 static void le_param_updated(struct bt_conn *conn, uint16_t interval,
297 			     uint16_t latency, uint16_t timeout)
298 {
299 	printk("%s: int 0x%04x lat %u to %u\n", __func__, interval,
300 	       latency, timeout);
301 }
302 
303 #if defined(CONFIG_BT_SMP)
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)304 static void security_changed(struct bt_conn *conn, bt_security_t level,
305 			     enum bt_security_err err)
306 {
307 	printk("%s: to level %u, err %s(%u)\n", __func__, level, bt_security_err_to_str(err), err);
308 }
309 #endif
310 
311 #if defined(CONFIG_BT_USER_PHY_UPDATE)
le_phy_updated(struct bt_conn * conn,struct bt_conn_le_phy_info * param)312 static void le_phy_updated(struct bt_conn *conn,
313 			   struct bt_conn_le_phy_info *param)
314 {
315 	char addr[BT_ADDR_LE_STR_LEN];
316 
317 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
318 
319 	printk("LE PHY Updated: %s Tx 0x%x, Rx 0x%x\n", addr, param->tx_phy,
320 	       param->rx_phy);
321 }
322 #endif /* CONFIG_BT_USER_PHY_UPDATE */
323 
324 #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
le_data_len_updated(struct bt_conn * conn,struct bt_conn_le_data_len_info * info)325 static void le_data_len_updated(struct bt_conn *conn,
326 				struct bt_conn_le_data_len_info *info)
327 {
328 	char addr[BT_ADDR_LE_STR_LEN];
329 
330 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
331 
332 	printk("Data length updated: %s max tx %u (%u us) max rx %u (%u us)\n",
333 	       addr, info->tx_max_len, info->tx_max_time, info->rx_max_len,
334 	       info->rx_max_time);
335 }
336 #endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
337 
338 BT_CONN_CB_DEFINE(conn_callbacks) = {
339 	.connected = connected,
340 	.disconnected = disconnected,
341 	.le_param_req = le_param_req,
342 	.le_param_updated = le_param_updated,
343 
344 #if defined(CONFIG_BT_SMP)
345 	.security_changed = security_changed,
346 #endif
347 
348 #if defined(CONFIG_BT_USER_PHY_UPDATE)
349 	.le_phy_updated = le_phy_updated,
350 #endif /* CONFIG_BT_USER_PHY_UPDATE */
351 
352 #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
353 	.le_data_len_updated = le_data_len_updated,
354 #endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
355 };
356 
write_cmd(struct bt_conn * conn)357 int write_cmd(struct bt_conn *conn)
358 {
359 	static uint8_t data[BT_ATT_MAX_ATTRIBUTE_LEN] = {0, };
360 	static uint16_t data_len;
361 	uint16_t data_len_max;
362 	int err;
363 
364 	data_len_max = bt_gatt_get_mtu(conn) - 3;
365 	if (data_len_max > BT_ATT_MAX_ATTRIBUTE_LEN) {
366 		data_len_max = BT_ATT_MAX_ATTRIBUTE_LEN;
367 	}
368 
369 #if TEST_FRAGMENTATION_WITH_VARIABLE_LENGTH_DATA
370 	/* Use incremental length data for every write command */
371 	/* TODO: Include test case in BabbleSim tests */
372 	static bool decrement;
373 
374 	if (decrement) {
375 		data_len--;
376 		if (data_len <= 1) {
377 			data_len = 1;
378 			decrement = false;
379 		}
380 	} else {
381 		data_len++;
382 		if (data_len >= data_len_max) {
383 			data_len = data_len_max;
384 			decrement = true;
385 		}
386 	}
387 #else
388 	/* Use fixed length data for every write command */
389 	data_len = data_len_max;
390 #endif
391 
392 	/* Pass the 16-bit data length value (instead of reference) in
393 	 * user_data so that unique value is pass for each write callback.
394 	 * Using handle 0x0001, we do not care if it is writable, we just want
395 	 * to transmit the data across.
396 	 */
397 	err = bt_gatt_write_without_response_cb(conn, 0x0001, data, data_len,
398 						false, write_cmd_cb,
399 						(void *)((uint32_t)data_len));
400 	if (err) {
401 		printk("%s: Write cmd failed (%d).\n", __func__, err);
402 	}
403 
404 	return err;
405 }
406