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 static struct bt_gatt_exchange_params mtu_exchange_params;
16 static uint32_t write_count;
17 static uint32_t write_len;
18 static uint32_t write_rate;
19 struct bt_conn *conn_connected;
20 uint32_t last_write_rate;
21 void (*start_scan_func)(void);
22 
write_cmd_cb(struct bt_conn * conn,void * user_data)23 static void write_cmd_cb(struct bt_conn *conn, void *user_data)
24 {
25 	static uint32_t cycle_stamp;
26 	uint64_t delta;
27 
28 	delta = k_cycle_get_32() - cycle_stamp;
29 	delta = k_cyc_to_ns_floor64(delta);
30 
31 	if (delta == 0) {
32 		/* Skip division by zero */
33 		return;
34 	}
35 
36 	/* if last data rx-ed was greater than 1 second in the past,
37 	 * reset the metrics.
38 	 */
39 	if (delta > (1U * NSEC_PER_SEC)) {
40 		printk("%s: count= %u, len= %u, rate= %u bps.\n", __func__,
41 		       write_count, write_len, write_rate);
42 
43 		last_write_rate = write_rate;
44 
45 		write_count = 0U;
46 		write_len = 0U;
47 		write_rate = 0U;
48 		cycle_stamp = k_cycle_get_32();
49 	} else {
50 		uint16_t len;
51 
52 		write_count++;
53 
54 		/* Extract the 16-bit data length stored in user_data */
55 		len = (uint32_t)user_data & 0xFFFF;
56 
57 		write_len += len;
58 		write_rate = ((uint64_t)write_len << 3) * (1U * NSEC_PER_SEC) /
59 			     delta;
60 	}
61 }
62 
mtu_exchange_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_exchange_params * params)63 static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
64 			    struct bt_gatt_exchange_params *params)
65 {
66 	printk("%s: MTU exchange %s (%u)\n", __func__,
67 	       err == 0U ? "successful" : "failed",
68 	       bt_gatt_get_mtu(conn));
69 }
70 
mtu_exchange(struct bt_conn * conn)71 static int mtu_exchange(struct bt_conn *conn)
72 {
73 	int err;
74 
75 	printk("%s: Current MTU = %u\n", __func__, bt_gatt_get_mtu(conn));
76 
77 	mtu_exchange_params.func = mtu_exchange_cb;
78 
79 	printk("%s: Exchange MTU...\n", __func__);
80 	err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params);
81 	if (err) {
82 		printk("%s: MTU exchange failed (err %d)", __func__, err);
83 	}
84 
85 	return err;
86 }
87 
connected(struct bt_conn * conn,uint8_t conn_err)88 static void connected(struct bt_conn *conn, uint8_t conn_err)
89 {
90 	struct bt_conn_info conn_info;
91 	char addr[BT_ADDR_LE_STR_LEN];
92 	int err;
93 
94 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
95 
96 	if (conn_err) {
97 		printk("%s: Failed to connect to %s (%u)\n", __func__, addr,
98 		       conn_err);
99 		return;
100 	}
101 
102 	err = bt_conn_get_info(conn, &conn_info);
103 	if (err) {
104 		printk("Failed to get connection info (%d).\n", err);
105 		return;
106 	}
107 
108 	printk("%s: %s role %u\n", __func__, addr, conn_info.role);
109 
110 	conn_connected = bt_conn_ref(conn);
111 
112 	(void)mtu_exchange(conn);
113 
114 #if defined(CONFIG_BT_SMP)
115 	if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
116 		err = bt_conn_set_security(conn, BT_SECURITY_L2);
117 		if (err) {
118 			printk("Failed to set security (%d).\n", err);
119 		}
120 	}
121 #endif
122 }
123 
disconnected(struct bt_conn * conn,uint8_t reason)124 static void disconnected(struct bt_conn *conn, uint8_t reason)
125 {
126 	struct bt_conn_info conn_info;
127 	char addr[BT_ADDR_LE_STR_LEN];
128 	int err;
129 
130 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
131 
132 	err = bt_conn_get_info(conn, &conn_info);
133 	if (err) {
134 		printk("Failed to get connection info (%d).\n", err);
135 		return;
136 	}
137 
138 	printk("%s: %s role %u, reason %u %s\n", __func__, addr, conn_info.role,
139 	       reason, bt_hci_err_to_str(reason));
140 
141 	conn_connected = NULL;
142 
143 	bt_conn_unref(conn);
144 
145 	if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
146 		start_scan_func();
147 	}
148 }
149 
le_param_req(struct bt_conn * conn,struct bt_le_conn_param * param)150 static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
151 {
152 	printk("%s: int (0x%04x, 0x%04x) lat %u to %u\n", __func__,
153 	       param->interval_min, param->interval_max, param->latency,
154 	       param->timeout);
155 
156 	return true;
157 }
158 
le_param_updated(struct bt_conn * conn,uint16_t interval,uint16_t latency,uint16_t timeout)159 static void le_param_updated(struct bt_conn *conn, uint16_t interval,
160 			     uint16_t latency, uint16_t timeout)
161 {
162 	printk("%s: int 0x%04x lat %u to %u\n", __func__, interval,
163 	       latency, timeout);
164 }
165 
166 #if defined(CONFIG_BT_SMP)
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)167 static void security_changed(struct bt_conn *conn, bt_security_t level,
168 			     enum bt_security_err err)
169 {
170 	printk("%s: to level %u, err %s(%u)\n", __func__, level, bt_security_err_to_str(err), err);
171 }
172 #endif
173 
174 BT_CONN_CB_DEFINE(conn_callbacks) = {
175 	.connected = connected,
176 	.disconnected = disconnected,
177 	.le_param_req = le_param_req,
178 	.le_param_updated = le_param_updated,
179 #if defined(CONFIG_BT_SMP)
180 	.security_changed = security_changed,
181 #endif
182 };
183 
write_cmd(struct bt_conn * conn)184 int write_cmd(struct bt_conn *conn)
185 {
186 	static uint8_t data[BT_ATT_MAX_ATTRIBUTE_LEN] = {0, };
187 	static uint16_t data_len;
188 	uint16_t data_len_max;
189 	int err;
190 
191 	data_len_max = bt_gatt_get_mtu(conn) - 3;
192 	if (data_len_max > BT_ATT_MAX_ATTRIBUTE_LEN) {
193 		data_len_max = BT_ATT_MAX_ATTRIBUTE_LEN;
194 	}
195 
196 #if TEST_FRAGMENTATION_WITH_VARIABLE_LENGTH_DATA
197 	/* Use incremental length data for every write command */
198 	/* TODO: Include test case in BabbleSim tests */
199 	static bool decrement;
200 
201 	if (decrement) {
202 		data_len--;
203 		if (data_len <= 1) {
204 			data_len = 1;
205 			decrement = false;
206 		}
207 	} else {
208 		data_len++;
209 		if (data_len >= data_len_max) {
210 			data_len = data_len_max;
211 			decrement = true;
212 		}
213 	}
214 #else
215 	/* Use fixed length data for every write command */
216 	data_len = data_len_max;
217 #endif
218 
219 	/* Pass the 16-bit data length value (instead of reference) in
220 	 * user_data so that unique value is pass for each write callback.
221 	 * Using handle 0x0001, we do not care if it is writable, we just want
222 	 * to transmit the data across.
223 	 */
224 	err = bt_gatt_write_without_response_cb(conn, 0x0001, data, data_len,
225 						false, write_cmd_cb,
226 						(void *)((uint32_t)data_len));
227 	if (err) {
228 		printk("%s: Write cmd failed (%d).\n", __func__, err);
229 	}
230 
231 	return err;
232 }
233