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