1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/types.h>
8 #include <stddef.h>
9 #include <errno.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/sys/byteorder.h>
13 
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/hci.h>
16 #include <zephyr/bluetooth/direction.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/uuid.h>
19 #include <zephyr/bluetooth/gatt.h>
20 #include <zephyr/bluetooth/hci.h>
21 #include <zephyr/bluetooth/hci_vs.h>
22 
23 /* Latency set to zero, to enforce PDU exchange every connection event */
24 #define CONN_LATENCY 0U
25 /* Arbitrary selected timeout value */
26 #define CONN_TIMEOUT 400U
27 /* Interval used to run CTE request procedure periodically.
28  * Value is a number of connection events.
29  */
30 #define CTE_REQ_INTERVAL (CONN_LATENCY + 10U)
31 /* Length of CTE in unit of 8 us */
32 #define CTE_LEN (0x14U)
33 
34 #define DF_FEAT_ENABLED BIT64(BT_LE_FEAT_BIT_CONN_CTE_RESP)
35 
36 static struct bt_conn *default_conn;
37 static const struct bt_le_conn_param conn_params = BT_LE_CONN_PARAM_INIT(
38 	BT_GAP_INIT_CONN_INT_MIN, BT_GAP_INIT_CONN_INT_MAX, CONN_LATENCY, CONN_TIMEOUT);
39 
40 #if defined(CONFIG_BT_DF_CTE_RX_AOA)
41 static const uint8_t ant_patterns[] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA };
42 #endif /* CONFIG_BT_DF_CTE_RX_AOA */
43 
44 static void start_scan(void);
45 
cte_type2str(uint8_t type)46 static const char *cte_type2str(uint8_t type)
47 {
48 	switch (type) {
49 	case BT_DF_CTE_TYPE_AOA:
50 		return "AOA";
51 	case BT_DF_CTE_TYPE_AOD_1US:
52 		return "AOD 1 [us]";
53 	case BT_DF_CTE_TYPE_AOD_2US:
54 		return "AOD 2 [us]";
55 	default:
56 		return "Unknown";
57 	}
58 }
59 
sample_type2str(enum bt_df_iq_sample type)60 static const char *sample_type2str(enum bt_df_iq_sample type)
61 {
62 	switch (type) {
63 	case BT_DF_IQ_SAMPLE_8_BITS_INT:
64 		return "8 bits int";
65 	case BT_DF_IQ_SAMPLE_16_BITS_INT:
66 		return "16 bits int";
67 	default:
68 		return "Unknown";
69 	}
70 }
71 
packet_status2str(uint8_t status)72 static const char *packet_status2str(uint8_t status)
73 {
74 	switch (status) {
75 	case BT_DF_CTE_CRC_OK:
76 		return "CRC OK";
77 	case BT_DF_CTE_CRC_ERR_CTE_BASED_TIME:
78 		return "CRC not OK, CTE Info OK";
79 	case BT_DF_CTE_CRC_ERR_CTE_BASED_OTHER:
80 		return "CRC not OK, Sampled other way";
81 	case BT_DF_CTE_INSUFFICIENT_RESOURCES:
82 		return "No resources";
83 	default:
84 		return "Unknown";
85 	}
86 }
87 
eir_found(struct bt_data * data,void * user_data)88 static bool eir_found(struct bt_data *data, void *user_data)
89 {
90 	bt_addr_le_t *addr = user_data;
91 	uint64_t u64 = 0U;
92 	int err;
93 
94 	printk("[AD]: %u data_len %u\n", data->type, data->data_len);
95 
96 	switch (data->type) {
97 	case BT_DATA_LE_SUPPORTED_FEATURES:
98 		if (data->data_len > sizeof(u64)) {
99 			return true;
100 		}
101 
102 		(void)memcpy(&u64, data->data, data->data_len);
103 
104 		u64 = sys_le64_to_cpu(u64);
105 
106 		if (!(u64 & DF_FEAT_ENABLED)) {
107 			return true;
108 		}
109 
110 		err = bt_le_scan_stop();
111 		if (err) {
112 			printk("Stop LE scan failed (err %d)\n", err);
113 			return true;
114 		}
115 
116 		err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, &conn_params, &default_conn);
117 		if (err) {
118 			printk("Create conn failed (err %d)\n", err);
119 			start_scan();
120 		}
121 		return false;
122 	}
123 
124 	return true;
125 }
126 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)127 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
128 			 struct net_buf_simple *ad)
129 {
130 	char dev[BT_ADDR_LE_STR_LEN];
131 
132 	bt_addr_le_to_str(addr, dev, sizeof(dev));
133 	printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n", dev, type, ad->len, rssi);
134 
135 	/* We're only interested in connectable events */
136 	if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
137 		bt_data_parse(ad, eir_found, (void *)addr);
138 	}
139 }
140 
enable_cte_reqest(void)141 static void enable_cte_reqest(void)
142 {
143 	int err;
144 
145 	const struct bt_df_conn_cte_rx_param cte_rx_params = {
146 #if defined(CONFIG_BT_DF_CTE_RX_AOA)
147 		.cte_types = BT_DF_CTE_TYPE_ALL,
148 		.slot_durations = 0x2,
149 		.num_ant_ids = ARRAY_SIZE(ant_patterns),
150 		.ant_ids = ant_patterns,
151 #else
152 		.cte_types = BT_DF_CTE_TYPE_AOD_1US | BT_DF_CTE_TYPE_AOD_2US,
153 #endif /* CONFIG_BT_DF_CTE_RX_AOA */
154 	};
155 
156 	const struct bt_df_conn_cte_req_params cte_req_params = {
157 		.interval = CTE_REQ_INTERVAL,
158 		.cte_length = CTE_LEN,
159 #if defined(CONFIG_BT_DF_CTE_RX_AOA)
160 		.cte_type = BT_DF_CTE_TYPE_AOA,
161 #else
162 		.cte_type = BT_DF_CTE_TYPE_AOD_2US,
163 #endif /* CONFIG_BT_DF_CTE_RX_AOA */
164 	};
165 
166 	printk("Enable receiving of CTE...\n");
167 	err = bt_df_conn_cte_rx_enable(default_conn, &cte_rx_params);
168 	if (err) {
169 		printk("failed (err %d)\n", err);
170 		return;
171 	}
172 	printk("success. CTE receive enabled.\n");
173 
174 	printk("Request CTE from peer device...\n");
175 	err = bt_df_conn_cte_req_enable(default_conn, &cte_req_params);
176 	if (err) {
177 		printk("failed (err %d)\n", err);
178 		return;
179 	}
180 	printk("success. CTE request enabled.\n");
181 }
182 
start_scan(void)183 static void start_scan(void)
184 {
185 	int err;
186 
187 	/* Use active scanning and disable duplicate filtering to handle any
188 	 * devices that might update their advertising data at runtime.
189 	 */
190 	struct bt_le_scan_param scan_param = {
191 		.type = BT_LE_SCAN_TYPE_ACTIVE,
192 		.options = BT_LE_SCAN_OPT_NONE,
193 		.interval = BT_GAP_SCAN_FAST_INTERVAL,
194 		.window = BT_GAP_SCAN_FAST_WINDOW,
195 	};
196 
197 	err = bt_le_scan_start(&scan_param, device_found);
198 	if (err) {
199 		printk("Scanning failed to start (err %d)\n", err);
200 		return;
201 	}
202 
203 	printk("Scanning successfully started\n");
204 }
205 
connected(struct bt_conn * conn,uint8_t conn_err)206 static void connected(struct bt_conn *conn, uint8_t conn_err)
207 {
208 	char addr[BT_ADDR_LE_STR_LEN];
209 
210 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
211 
212 	if (conn_err) {
213 		printk("Failed to connect to %s (%u)\n", addr, conn_err);
214 
215 		bt_conn_unref(default_conn);
216 		default_conn = NULL;
217 
218 		start_scan();
219 		return;
220 	}
221 
222 	printk("Connected: %s\n", addr);
223 
224 	if (conn == default_conn) {
225 		enable_cte_reqest();
226 	}
227 }
228 
disconnected(struct bt_conn * conn,uint8_t reason)229 static void disconnected(struct bt_conn *conn, uint8_t reason)
230 {
231 	char addr[BT_ADDR_LE_STR_LEN];
232 
233 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
234 
235 	printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
236 
237 	if (default_conn != conn) {
238 		return;
239 	}
240 
241 	bt_conn_unref(default_conn);
242 	default_conn = NULL;
243 
244 	start_scan();
245 }
246 
cte_recv_cb(struct bt_conn * conn,struct bt_df_conn_iq_samples_report const * report)247 static void cte_recv_cb(struct bt_conn *conn, struct bt_df_conn_iq_samples_report const *report)
248 {
249 	char addr[BT_ADDR_LE_STR_LEN];
250 
251 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
252 
253 	if (report->err == BT_DF_IQ_REPORT_ERR_SUCCESS) {
254 		printk("CTE[%s]: samples type: %s, samples count %d, cte type %s, slot durations: "
255 			"%u [us], packet status %s, RSSI %i\n", addr,
256 			sample_type2str(report->sample_type), report->sample_count,
257 			cte_type2str(report->cte_type), report->slot_durations,
258 			packet_status2str(report->packet_status), report->rssi);
259 
260 		if (IS_ENABLED(CONFIG_DF_CENTRAL_APP_IQ_REPORT_PRINT_IQ_SAMPLES)) {
261 			for (uint8_t idx = 0; idx < report->sample_count; idx++) {
262 				if (report->sample_type == BT_DF_IQ_SAMPLE_8_BITS_INT) {
263 					printk(" IQ[%d]: %d, %d\n", idx, report->sample[idx].i,
264 					       report->sample[idx].q);
265 				} else if (IS_ENABLED(
266 					CONFIG_BT_DF_VS_CONN_IQ_REPORT_16_BITS_IQ_SAMPLES)) {
267 					printk(" IQ[%" PRIu8 "]: %d, %d\n", idx,
268 					       report->sample16[idx].i, report->sample16[idx].q);
269 				} else {
270 					printk("Unhandled vendor specific IQ samples type\n");
271 					break;
272 				}
273 			}
274 		}
275 	} else {
276 		printk("CTE[%s]: request failed, err %u\n", addr, report->err);
277 	}
278 }
279 
280 BT_CONN_CB_DEFINE(conn_callbacks) = {
281 	.connected = connected,
282 	.disconnected = disconnected,
283 	.cte_report_cb = cte_recv_cb,
284 };
285 
main(void)286 int main(void)
287 {
288 	int err;
289 
290 	err = bt_enable(NULL);
291 	if (err) {
292 		printk("Bluetooth init failed (err %d)\n", err);
293 		return 0;
294 	}
295 
296 	printk("Bluetooth initialized\n");
297 
298 	start_scan();
299 	return 0;
300 }
301