1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <math.h>
8 #include <zephyr/console/console.h>
9 #include <zephyr/sys/byteorder.h>
10 #include <zephyr/bluetooth/bluetooth.h>
11 #include <zephyr/bluetooth/cs.h>
12 #include <zephyr/bluetooth/att.h>
13 #include <zephyr/bluetooth/gatt.h>
14 #include "distance_estimation.h"
15 #include "common.h"
16 #include "cs_test_params.h"
17 
18 static K_SEM_DEFINE(sem_results_available, 0, 1);
19 static K_SEM_DEFINE(sem_test_complete, 0, 1);
20 static K_SEM_DEFINE(sem_connected, 0, 1);
21 static K_SEM_DEFINE(sem_disconnected, 0, 1);
22 static K_SEM_DEFINE(sem_data_received, 0, 1);
23 
24 static ssize_t on_attr_write_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
25 				const void *buf, uint16_t len, uint16_t offset, uint8_t flags);
26 static struct bt_conn *connection;
27 static uint8_t n_ap;
28 static uint8_t latest_num_steps_reported;
29 static uint16_t latest_step_data_len;
30 static uint8_t latest_local_steps[STEP_DATA_BUF_LEN];
31 static uint8_t latest_peer_steps[STEP_DATA_BUF_LEN];
32 
33 static struct bt_gatt_attr gatt_attributes[] = {
34 	BT_GATT_PRIMARY_SERVICE(&step_data_svc_uuid),
35 	BT_GATT_CHARACTERISTIC(&step_data_char_uuid.uuid, BT_GATT_CHRC_WRITE,
36 			       BT_GATT_PERM_WRITE | BT_GATT_PERM_READ, NULL, on_attr_write_cb,
37 			       NULL),
38 };
39 static struct bt_gatt_service step_data_gatt_service = BT_GATT_SERVICE(gatt_attributes);
40 static const char sample_str[] = "CS Test Sample";
41 
on_attr_write_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)42 static ssize_t on_attr_write_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
43 				const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
44 {
45 	if (flags & BT_GATT_WRITE_FLAG_PREPARE) {
46 		return 0;
47 	}
48 
49 	if (offset) {
50 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
51 	}
52 
53 	if (len != sizeof(latest_local_steps)) {
54 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
55 	}
56 
57 	if (flags & BT_GATT_WRITE_FLAG_EXECUTE) {
58 		uint8_t *data = (uint8_t *)buf;
59 
60 		memcpy(latest_peer_steps, &data[offset], len);
61 		k_sem_give(&sem_data_received);
62 	}
63 
64 	return len;
65 }
66 
subevent_result_cb(struct bt_conn_le_cs_subevent_result * result)67 static void subevent_result_cb(struct bt_conn_le_cs_subevent_result *result)
68 {
69 	latest_num_steps_reported = result->header.num_steps_reported;
70 	n_ap = result->header.num_antenna_paths;
71 
72 	if (result->step_data_buf) {
73 		if (result->step_data_buf->len <= STEP_DATA_BUF_LEN) {
74 			memcpy(latest_local_steps, result->step_data_buf->data,
75 			       result->step_data_buf->len);
76 			latest_step_data_len = result->step_data_buf->len;
77 		} else {
78 			printk("Not enough memory to store step data. (%d > %d)\n",
79 			       result->step_data_buf->len, STEP_DATA_BUF_LEN);
80 			latest_num_steps_reported = 0;
81 		}
82 	}
83 
84 	if (result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_COMPLETE ||
85 	    result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_ABORTED) {
86 		k_sem_give(&sem_results_available);
87 	}
88 }
89 
end_cb(void)90 static void end_cb(void)
91 {
92 	k_sem_give(&sem_test_complete);
93 }
94 
mtu_exchange_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_exchange_params * params)95 static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
96 			    struct bt_gatt_exchange_params *params)
97 {
98 	printk("MTU exchange %s (%u)\n", err == 0U ? "success" : "failed", bt_gatt_get_mtu(conn));
99 }
100 
connected_cb(struct bt_conn * conn,uint8_t err)101 static void connected_cb(struct bt_conn *conn, uint8_t err)
102 {
103 	char addr[BT_ADDR_LE_STR_LEN];
104 
105 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
106 	printk("Connected to %s (err 0x%02X)\n", addr, err);
107 
108 	__ASSERT(connection == conn, "Unexpected connected callback");
109 
110 	if (err) {
111 		bt_conn_unref(conn);
112 		connection = NULL;
113 	}
114 
115 	static struct bt_gatt_exchange_params mtu_exchange_params = {.func = mtu_exchange_cb};
116 
117 	err = bt_gatt_exchange_mtu(connection, &mtu_exchange_params);
118 	if (err) {
119 		printk("%s: MTU exchange failed (err %d)\n", __func__, err);
120 	}
121 
122 	k_sem_give(&sem_connected);
123 }
124 
disconnected_cb(struct bt_conn * conn,uint8_t reason)125 static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
126 {
127 	printk("Disconnected (reason 0x%02X)\n", reason);
128 
129 	bt_conn_unref(conn);
130 	connection = NULL;
131 
132 	k_sem_give(&sem_disconnected);
133 }
134 
data_cb(struct bt_data * data,void * user_data)135 static bool data_cb(struct bt_data *data, void *user_data)
136 {
137 	char *name = user_data;
138 	uint8_t len;
139 
140 	switch (data->type) {
141 	case BT_DATA_NAME_SHORTENED:
142 	case BT_DATA_NAME_COMPLETE:
143 		len = MIN(data->data_len, NAME_LEN - 1);
144 		memcpy(name, data->data, len);
145 		name[len] = '\0';
146 		return false;
147 	default:
148 		return true;
149 	}
150 }
151 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)152 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
153 			 struct net_buf_simple *ad)
154 {
155 	char addr_str[BT_ADDR_LE_STR_LEN];
156 	char name[NAME_LEN] = {};
157 	int err;
158 
159 	if (connection) {
160 		return;
161 	}
162 
163 	/* We're only interested in connectable events */
164 	if (type != BT_GAP_ADV_TYPE_ADV_IND && type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
165 		return;
166 	}
167 
168 	bt_data_parse(ad, data_cb, name);
169 
170 	if (strcmp(name, sample_str)) {
171 		return;
172 	}
173 
174 	if (bt_le_scan_stop()) {
175 		return;
176 	}
177 
178 	printk("Found device with name %s, connecting...\n", name);
179 
180 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,
181 				&connection);
182 	if (err) {
183 		printk("Create conn to %s failed (%u)\n", addr_str, err);
184 	}
185 }
186 
187 BT_CONN_CB_DEFINE(conn_cb) = {
188 	.connected = connected_cb,
189 	.disconnected = disconnected_cb,
190 };
191 
main(void)192 int main(void)
193 {
194 	int err;
195 	struct bt_le_cs_test_param test_params;
196 
197 	printk("Starting Channel Sounding Demo\n");
198 
199 	/* Initialize the Bluetooth Subsystem */
200 	err = bt_enable(NULL);
201 	if (err) {
202 		printk("Bluetooth init failed (err %d)\n", err);
203 		return 0;
204 	}
205 
206 	struct bt_le_cs_test_cb cs_test_cb = {
207 		.le_cs_test_subevent_data_available = subevent_result_cb,
208 		.le_cs_test_end_complete = end_cb,
209 	};
210 
211 	err = bt_le_cs_test_cb_register(cs_test_cb);
212 	if (err) {
213 		printk("Failed to register callbacks (err %d)\n", err);
214 		return 0;
215 	}
216 
217 	err = bt_gatt_service_register(&step_data_gatt_service);
218 	if (err) {
219 		printk("bt_gatt_service_register() returned err %d\n", err);
220 		return 0;
221 	}
222 
223 	while (true) {
224 		while (true) {
225 			k_sleep(K_SECONDS(2));
226 
227 			test_params = test_params_get(BT_CONN_LE_CS_ROLE_INITIATOR);
228 
229 			err = bt_le_cs_start_test(&test_params);
230 			if (err) {
231 				printk("Failed to start CS test (err %d)\n", err);
232 				return 0;
233 			}
234 
235 			k_sem_take(&sem_results_available, K_SECONDS(5));
236 
237 			err = bt_le_cs_stop_test();
238 			if (err) {
239 				printk("Failed to stop CS test (err %d)\n", err);
240 				return 0;
241 			}
242 
243 			k_sem_take(&sem_test_complete, K_FOREVER);
244 
245 			if (latest_num_steps_reported > NUM_MODE_0_STEPS) {
246 				break;
247 			}
248 		}
249 
250 		err = bt_le_scan_start(BT_LE_SCAN_ACTIVE_CONTINUOUS, device_found);
251 		if (err) {
252 			printk("Scanning failed to start (err %d)\n", err);
253 			return 0;
254 		}
255 
256 		k_sem_take(&sem_connected, K_FOREVER);
257 
258 		k_sem_take(&sem_data_received, K_FOREVER);
259 
260 		estimate_distance(
261 			latest_local_steps, latest_step_data_len, latest_peer_steps,
262 			latest_step_data_len -
263 				NUM_MODE_0_STEPS *
264 					(sizeof(struct bt_hci_le_cs_step_data_mode_0_initiator) -
265 					 sizeof(struct bt_hci_le_cs_step_data_mode_0_reflector)),
266 			n_ap, BT_CONN_LE_CS_ROLE_INITIATOR);
267 
268 		bt_conn_disconnect(connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
269 
270 		k_sem_take(&sem_disconnected, K_FOREVER);
271 
272 		printk("Re-running CS test...\n");
273 	}
274 
275 	return 0;
276 }
277