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