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