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