1 /* main.c - Application main entry point */
2 
3 /*
4  * Copyright 2024 NXP
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/types.h>
10 #include <stddef.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <zephyr/sys/printk.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/kernel.h>
16 
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/l2cap.h>
20 #include <zephyr/bluetooth/hci.h>
21 #include <zephyr/bluetooth/classic/rfcomm.h>
22 #include <zephyr/bluetooth/classic/sdp.h>
23 #include <zephyr/bluetooth/classic/hfp_ag.h>
24 #include <zephyr/settings/settings.h>
25 
26 static struct bt_conn *default_conn;
27 struct bt_hfp_ag *hfp_ag;
28 
29 static struct bt_br_discovery_param br_discover;
30 
31 static struct bt_br_discovery_param br_discover;
32 static struct bt_br_discovery_result scan_result[CONFIG_BT_HFP_AG_DISCOVER_RESULT_COUNT];
33 
34 struct k_work discover_work;
35 struct k_work_delayable call_connect_work;
36 struct k_work_delayable call_disconnect_work;
37 
38 struct k_work_delayable call_remote_ringing_work;
39 struct k_work_delayable call_remote_accept_work;
40 
41 NET_BUF_POOL_DEFINE(sdp_discover_pool, 10, BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
42 		    CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
43 
ag_connected(struct bt_hfp_ag * ag)44 static void ag_connected(struct bt_hfp_ag *ag)
45 {
46 	printk("HFP AG connected!\n");
47 	k_work_schedule(&call_connect_work, K_MSEC(CONFIG_BT_HFP_AG_START_CALL_DELAY_TIME));
48 }
49 
ag_disconnected(struct bt_hfp_ag * ag)50 static void ag_disconnected(struct bt_hfp_ag *ag)
51 {
52 	printk("HFP AG disconnected!\n");
53 }
54 
ag_sco_connected(struct bt_hfp_ag * ag,struct bt_conn * sco_conn)55 static void ag_sco_connected(struct bt_hfp_ag *ag, struct bt_conn *sco_conn)
56 {
57 	printk("HFP AG SCO connected!\n");
58 }
59 
ag_sco_disconnected(struct bt_hfp_ag * ag)60 static void ag_sco_disconnected(struct bt_hfp_ag *ag)
61 {
62 	printk("HFP AG SCO disconnected!\n");
63 }
64 
ag_ringing(struct bt_hfp_ag * ag,bool in_band)65 static void ag_ringing(struct bt_hfp_ag *ag, bool in_band)
66 {
67 	printk("Ringing (in bond? %s)\n", in_band ? "Yes" : "No");
68 }
69 
ag_accept(struct bt_hfp_ag * ag)70 static void ag_accept(struct bt_hfp_ag *ag)
71 {
72 	printk("Call Accepted\n");
73 	k_work_schedule(&call_disconnect_work, K_SECONDS(10));
74 }
75 
ag_reject(struct bt_hfp_ag * ag)76 static void ag_reject(struct bt_hfp_ag *ag)
77 {
78 	printk("Call Rejected\n");
79 	k_work_schedule(&call_disconnect_work, K_SECONDS(1));
80 }
81 
ag_terminate(struct bt_hfp_ag * ag)82 static void ag_terminate(struct bt_hfp_ag *ag)
83 {
84 	printk("Call terminated\n");
85 	k_work_schedule(&call_disconnect_work, K_SECONDS(1));
86 }
87 
ag_outgoing(struct bt_hfp_ag * ag,const char * number)88 static void ag_outgoing(struct bt_hfp_ag *ag, const char *number)
89 {
90 	printk("Call outgoing, remote number %s\n", number);
91 	k_work_cancel_delayable(&call_connect_work);
92 	k_work_schedule(&call_remote_ringing_work, K_SECONDS(1));
93 }
94 
ag_incoming(struct bt_hfp_ag * ag,const char * number)95 static void ag_incoming(struct bt_hfp_ag *ag, const char *number)
96 {
97 	printk("Incoming call, remote number %s\n", number);
98 	k_work_cancel_delayable(&call_connect_work);
99 }
100 
101 static struct bt_hfp_ag_cb ag_cb = {
102 	.connected = ag_connected,
103 	.disconnected = ag_disconnected,
104 	.sco_connected = ag_sco_connected,
105 	.sco_disconnected = ag_sco_disconnected,
106 	.outgoing = ag_outgoing,
107 	.incoming = ag_incoming,
108 	.ringing = ag_ringing,
109 	.accept = ag_accept,
110 	.reject = ag_reject,
111 	.terminate = ag_terminate,
112 };
113 
sdp_discover_cb(struct bt_conn * conn,struct bt_sdp_client_result * result,const struct bt_sdp_discover_params * params)114 static uint8_t sdp_discover_cb(struct bt_conn *conn, struct bt_sdp_client_result *result,
115 			       const struct bt_sdp_discover_params *params)
116 {
117 	int err;
118 	uint16_t value;
119 
120 	printk("Discover done\n");
121 
122 	if (result->resp_buf != NULL) {
123 		err = bt_sdp_get_proto_param(result->resp_buf, BT_SDP_PROTO_RFCOMM, &value);
124 
125 		if (err != 0) {
126 			printk("Fail to parser RFCOMM the SDP response!\n");
127 		} else {
128 			printk("The server channel is %d\n", value);
129 			err = bt_hfp_ag_connect(conn, &hfp_ag, value);
130 			if (err != 0) {
131 				printk("Fail to create hfp AG connection (err %d)\n", err);
132 			}
133 		}
134 	}
135 
136 	return BT_SDP_DISCOVER_UUID_STOP;
137 }
138 
139 static struct bt_sdp_discover_params sdp_discover = {
140 	.type = BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR,
141 	.func = sdp_discover_cb,
142 	.pool = &sdp_discover_pool,
143 	.uuid = BT_UUID_DECLARE_16(BT_SDP_HANDSFREE_SVCLASS),
144 };
145 
connected(struct bt_conn * conn,uint8_t err)146 static void connected(struct bt_conn *conn, uint8_t err)
147 {
148 	int res;
149 
150 	if (err) {
151 		if (default_conn != NULL) {
152 			default_conn = NULL;
153 		}
154 		printk("Connection failed, err 0x%02x %s\n", err, bt_hci_err_to_str(err));
155 	} else {
156 		if (default_conn == conn) {
157 			struct bt_conn_info info;
158 
159 			bt_conn_get_info(conn, &info);
160 			if (info.type != BT_CONN_TYPE_BR) {
161 				return;
162 			}
163 
164 			/*
165 			 * Do an SDP Query on Successful ACL connection complete with the
166 			 * required device
167 			 */
168 			res = bt_sdp_discover(default_conn, &sdp_discover);
169 			if (res) {
170 				printk("SDP discovery failed (err %d)\r\n", res);
171 			} else {
172 				printk("SDP discovery started\r\n");
173 			}
174 			printk("Connected\n");
175 		}
176 	}
177 }
178 
disconnected(struct bt_conn * conn,uint8_t reason)179 static void disconnected(struct bt_conn *conn, uint8_t reason)
180 {
181 	printk("Disconnected, reason 0x%02x %s\n", reason, bt_hci_err_to_str(reason));
182 
183 	if (default_conn != conn) {
184 		return;
185 	}
186 
187 	if (default_conn) {
188 		default_conn = NULL;
189 	} else {
190 		return;
191 	}
192 }
193 
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)194 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
195 {
196 	char addr[BT_ADDR_LE_STR_LEN];
197 	struct bt_conn_info info;
198 
199 	bt_conn_get_info(conn, &info);
200 
201 	bt_addr_to_str(info.br.dst, addr, sizeof(addr));
202 
203 	printk("Security changed: %s level %u, err %s(%d)\n", addr, level,
204 	       bt_security_err_to_str(err), err);
205 }
206 
207 static struct bt_conn_cb conn_callbacks = {
208 	.connected = connected,
209 	.disconnected = disconnected,
210 	.security_changed = security_changed,
211 };
212 
discovery_recv_cb(const struct bt_br_discovery_result * result)213 static void discovery_recv_cb(const struct bt_br_discovery_result *result)
214 {
215 	(void)result;
216 }
217 
discovery_timeout_cb(const struct bt_br_discovery_result * results,size_t count)218 static void discovery_timeout_cb(const struct bt_br_discovery_result *results, size_t count)
219 {
220 	char addr[BT_ADDR_LE_STR_LEN];
221 	const uint8_t *eir;
222 	bool cod_hf = false;
223 	static uint8_t temp[240];
224 	size_t len = sizeof(results->eir);
225 	uint8_t major_device;
226 	uint8_t minor_device;
227 	size_t i;
228 
229 	for (i = 0; i < count; i++) {
230 		bt_addr_to_str(&results[i].addr, addr, sizeof(addr));
231 		printk("Device[%d]: %s, rssi %d, cod 0x%X%X%X", i, addr, results[i].rssi,
232 		       results[i].cod[0], results[i].cod[1], results[i].cod[2]);
233 
234 		major_device = (uint8_t)BT_COD_MAJOR_DEVICE_CLASS(results[i].cod);
235 		minor_device = (uint8_t)BT_COD_MINOR_DEVICE_CLASS(results[i].cod);
236 
237 		if ((major_device & BT_COD_MAJOR_AUDIO_VIDEO) &&
238 		    (minor_device & BT_COD_MAJOR_AUDIO_VIDEO_MINOR_HANDS_FREE)) {
239 			cod_hf = true;
240 		}
241 
242 		eir = results[i].eir;
243 
244 		while ((eir[0] > 2) && (len > eir[0])) {
245 			switch (eir[1]) {
246 			case BT_DATA_NAME_SHORTENED:
247 			case BT_DATA_NAME_COMPLETE:
248 				memcpy(temp, &eir[2], eir[0] - 1);
249 				temp[eir[0] - 1] = '\0'; /* Set end flag */
250 				printk(", name %s", temp);
251 				break;
252 			}
253 			len = len - eir[0] - 1;
254 			eir = eir + eir[0] + 1;
255 		}
256 		printk("\n");
257 
258 		if (cod_hf) {
259 			break;
260 		}
261 	}
262 
263 	if (!cod_hf) {
264 		(void)k_work_submit(&discover_work);
265 	} else {
266 		(void)k_work_cancel(&discover_work);
267 		default_conn = bt_conn_create_br(&results[i].addr, BT_BR_CONN_PARAM_DEFAULT);
268 
269 		if (default_conn == NULL) {
270 			printk("Fail to create the connecton\n");
271 		} else {
272 			bt_conn_unref(default_conn);
273 		}
274 	}
275 }
276 
discover_work_handler(struct k_work * work)277 static void discover_work_handler(struct k_work *work)
278 {
279 	int err;
280 
281 	br_discover.length = 10;
282 	br_discover.limited = false;
283 
284 	err = bt_br_discovery_start(&br_discover, scan_result,
285 				    CONFIG_BT_HFP_AG_DISCOVER_RESULT_COUNT);
286 	if (err) {
287 		printk("Fail to start discovery (err %d)\n", err);
288 		return;
289 	}
290 }
291 
call_connect_work_handler(struct k_work * work)292 static void call_connect_work_handler(struct k_work *work)
293 {
294 #if CONFIG_BT_HFP_AG_CALL_OUTGOING
295 	int err;
296 
297 	printk("Dialing\n");
298 
299 	err = bt_hfp_ag_outgoing(hfp_ag, "test_hf");
300 
301 	if (err != 0) {
302 		printk("Fail to dial a call (err %d)\n", err);
303 	}
304 #else
305 	int err = bt_hfp_ag_remote_incoming(hfp_ag, "test_hf");
306 
307 	if (err != 0) {
308 		printk("Fail to set remote incoming call (err %d)\n", err);
309 	}
310 #endif /* CONFIG_BT_HFP_AG_CALL_OUTGOING */
311 }
312 
call_disconnect_work_handler(struct k_work * work)313 static void call_disconnect_work_handler(struct k_work *work)
314 {
315 	int err;
316 
317 	if (default_conn != NULL) {
318 		err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
319 
320 		if (err != 0) {
321 			printk("Fail to disconnect acl connection (err %d)\n", err);
322 		}
323 	}
324 }
325 
call_remote_ringing_work_handler(struct k_work * work)326 static void call_remote_ringing_work_handler(struct k_work *work)
327 {
328 	int err;
329 
330 	printk("Remote starts ringing\n");
331 
332 	err = bt_hfp_ag_remote_ringing(hfp_ag);
333 
334 	if (err != 0) {
335 		printk("Fail to notify hfp unit that the remote starts ringing (err %d)\n", err);
336 	} else {
337 		k_work_schedule(&call_remote_accept_work, K_SECONDS(1));
338 	}
339 }
340 
call_remote_accept_work_handler(struct k_work * work)341 static void call_remote_accept_work_handler(struct k_work *work)
342 {
343 	int err;
344 
345 	printk("Remote accepts the call\n");
346 
347 	err = bt_hfp_ag_remote_accept(hfp_ag);
348 
349 	if (err != 0) {
350 		printk("Fail to notify hfp unit that the remote accepts call (err %d)\n", err);
351 	}
352 }
353 
354 static struct bt_br_discovery_cb discovery_cb = {
355 	.recv = discovery_recv_cb,
356 	.timeout = discovery_timeout_cb,
357 };
358 
bt_ready(int err)359 static void bt_ready(int err)
360 {
361 	if (err) {
362 		printk("Bluetooth init failed (err %d)\n", err);
363 		return;
364 	}
365 
366 	if (IS_ENABLED(CONFIG_SETTINGS)) {
367 		settings_load();
368 	}
369 
370 	printk("Bluetooth initialized\n");
371 
372 	bt_conn_cb_register(&conn_callbacks);
373 
374 	bt_br_discovery_cb_register(&discovery_cb);
375 
376 	bt_hfp_ag_register(&ag_cb);
377 
378 	k_work_init(&discover_work, discover_work_handler);
379 
380 	(void)k_work_submit(&discover_work);
381 
382 	k_work_init_delayable(&call_connect_work, call_connect_work_handler);
383 	k_work_init_delayable(&call_disconnect_work, call_disconnect_work_handler);
384 
385 	k_work_init_delayable(&call_remote_ringing_work, call_remote_ringing_work_handler);
386 	k_work_init_delayable(&call_remote_accept_work, call_remote_accept_work_handler);
387 }
388 
main(void)389 int main(void)
390 {
391 	int err;
392 
393 	printk("Bluetooth Handsfree AG demo start...\n");
394 
395 	err = bt_enable(bt_ready);
396 	if (err) {
397 		printk("Bluetooth init failed (err %d)\n", err);
398 	}
399 	return 0;
400 }
401