1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <string.h>
11 
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/addr.h>
14 #include <zephyr/bluetooth/audio/tbs.h>
15 #include <zephyr/bluetooth/audio/ccp.h>
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/gap.h>
19 #include <zephyr/bluetooth/hci_types.h>
20 #include <zephyr/bluetooth/uuid.h>
21 #include <zephyr/kernel.h>
22 #include <zephyr/logging/log.h>
23 #include <zephyr/net_buf.h>
24 #include <zephyr/sys/byteorder.h>
25 #include <zephyr/sys/util.h>
26 #include <zephyr/sys/util_macro.h>
27 
28 LOG_MODULE_REGISTER(ccp_call_control_client, CONFIG_LOG_DEFAULT_LEVEL);
29 
30 #define SEM_TIMEOUT K_SECONDS(10)
31 
32 static struct bt_conn *peer_conn;
33 /* call_control_client is not static as it is used for testing purposes */
34 struct bt_ccp_call_control_client *call_control_client;
35 static struct bt_ccp_call_control_client_bearers client_bearers;
36 
37 static K_SEM_DEFINE(sem_conn_state_change, 0, 1);
38 static K_SEM_DEFINE(sem_security_updated, 0, 1);
39 static K_SEM_DEFINE(sem_ccp_action_completed, 0, 1);
40 
connected_cb(struct bt_conn * conn,uint8_t err)41 static void connected_cb(struct bt_conn *conn, uint8_t err)
42 {
43 	char addr[BT_ADDR_LE_STR_LEN];
44 
45 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
46 	LOG_INF("Connected: %s", addr);
47 
48 	k_sem_give(&sem_conn_state_change);
49 }
50 
disconnected_cb(struct bt_conn * conn,uint8_t reason)51 static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
52 {
53 	char addr[BT_ADDR_LE_STR_LEN];
54 
55 	if (conn != peer_conn) {
56 		return;
57 	}
58 
59 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
60 	LOG_INF("Disconnected: %s (reason 0x%02x)", addr, reason);
61 
62 	bt_conn_unref(peer_conn);
63 	peer_conn = NULL;
64 	call_control_client = NULL;
65 	memset(&client_bearers, 0, sizeof(client_bearers));
66 	k_sem_give(&sem_conn_state_change);
67 }
68 
security_changed_cb(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)69 static void security_changed_cb(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
70 {
71 	if (err == 0) {
72 		k_sem_give(&sem_security_updated);
73 	} else {
74 		LOG_ERR("Failed to set security level: %s(%u)", bt_security_err_to_str(err), err);
75 	}
76 }
77 
78 BT_CONN_CB_DEFINE(conn_callbacks) = {
79 	.connected = connected_cb,
80 	.disconnected = disconnected_cb,
81 	.security_changed = security_changed_cb,
82 };
83 
check_gtbs_support(struct bt_data * data,void * user_data)84 static bool check_gtbs_support(struct bt_data *data, void *user_data)
85 {
86 	struct net_buf_simple svc_data;
87 	bool *connect = user_data;
88 	const struct bt_uuid *uuid;
89 	uint16_t uuid_val;
90 
91 	if (data->type != BT_DATA_SVC_DATA16) {
92 		return true; /* Continue parsing to next AD data type */
93 	}
94 
95 	if (data->data_len < sizeof(uuid_val)) {
96 		LOG_WRN("AD invalid size %u", data->data_len);
97 		return true; /* Continue parsing to next AD data type */
98 	}
99 
100 	net_buf_simple_init_with_data(&svc_data, (void *)data->data, data->data_len);
101 
102 	/* Pull the 16-bit service data and compare to what we are searching for */
103 	uuid_val = net_buf_simple_pull_le16(&svc_data);
104 	uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(uuid_val));
105 	if (bt_uuid_cmp(uuid, BT_UUID_GTBS) != 0) {
106 		/* We are looking for the GTBS service data */
107 		return true; /* Continue parsing to next AD data type */
108 	}
109 
110 	*connect = true;
111 
112 	return false; /* Stop parsing */
113 }
114 
scan_recv_cb(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)115 static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
116 {
117 	char addr_str[BT_ADDR_LE_STR_LEN];
118 	bool connect = false;
119 
120 	if (peer_conn != NULL) {
121 		/* Already connected */
122 		return;
123 	}
124 
125 	/* CCP mandates that connectbale extended advertising is used by the peripherals so we
126 	 * ignore any scan report this is not that.
127 	 * We also ignore reports with poor RSSI
128 	 */
129 	if (info->adv_type != BT_GAP_ADV_TYPE_EXT_ADV ||
130 	    (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) == 0 ||
131 	    (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) == 0 || info->rssi < -70) {
132 		return;
133 	}
134 
135 	(void)bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str));
136 	LOG_INF("Connectable device found: %s (RSSI %d)", addr_str, info->rssi);
137 
138 	/* Iterate on the advertising data to see if claims GTBS support */
139 	bt_data_parse(ad, check_gtbs_support, &connect);
140 
141 	if (connect) {
142 		int err;
143 
144 		err = bt_le_scan_stop();
145 		if (err != 0) {
146 			LOG_ERR("Scanning failed to stop (err %d)", err);
147 			return;
148 		}
149 
150 		LOG_INF("Connecting to found CCP server");
151 		err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN,
152 					BT_LE_CONN_PARAM_DEFAULT, &peer_conn);
153 		if (err != 0) {
154 			LOG_ERR("Conn create failed: %d", err);
155 		}
156 	}
157 }
158 
scan_and_connect(void)159 static int scan_and_connect(void)
160 {
161 	int err;
162 
163 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
164 	if (err != 0) {
165 		LOG_ERR("Scanning failed to start (err %d)", err);
166 		return err;
167 	}
168 
169 	LOG_INF("Scanning successfully started");
170 
171 	err = k_sem_take(&sem_conn_state_change, K_FOREVER);
172 	if (err != 0) {
173 		LOG_ERR("failed to take sem_connected (err %d)", err);
174 		return err;
175 	}
176 
177 	err = bt_conn_set_security(peer_conn, BT_SECURITY_L2);
178 	if (err != 0) {
179 		LOG_ERR("failed to set security (err %d)", err);
180 		return err;
181 	}
182 
183 	err = k_sem_take(&sem_security_updated, SEM_TIMEOUT);
184 	if (err != 0) {
185 		LOG_ERR("failed to take sem_security_updated (err %d)", err);
186 		return err;
187 	}
188 
189 	LOG_INF("Security successfully updated");
190 
191 	return 0;
192 }
193 
ccp_call_control_client_discover_cb(struct bt_ccp_call_control_client * client,int err,struct bt_ccp_call_control_client_bearers * bearers)194 static void ccp_call_control_client_discover_cb(struct bt_ccp_call_control_client *client, int err,
195 						struct bt_ccp_call_control_client_bearers *bearers)
196 {
197 	if (err != 0) {
198 		LOG_ERR("Discovery failed: %d", err);
199 		return;
200 	}
201 
202 	LOG_INF("Discovery completed with %s%u TBS bearers",
203 		bearers->gtbs_bearer != NULL ? "GTBS and " : "", bearers->tbs_count);
204 
205 	memcpy(&client_bearers, bearers, sizeof(client_bearers));
206 
207 	k_sem_give(&sem_ccp_action_completed);
208 }
209 
210 #if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
ccp_call_control_client_read_bearer_provider_name_cb(struct bt_ccp_call_control_client_bearer * bearer,int err,const char * name)211 static void ccp_call_control_client_read_bearer_provider_name_cb(
212 	struct bt_ccp_call_control_client_bearer *bearer, int err, const char *name)
213 {
214 	if (err != 0) {
215 		LOG_ERR("Failed to read bearer %p provider name: %d\n", (void *)bearer, err);
216 		return;
217 	}
218 
219 	LOG_INF("Bearer %p provider name: %s", (void *)bearer, name);
220 
221 	k_sem_give(&sem_ccp_action_completed);
222 }
223 #endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
224 
reset_ccp_call_control_client(void)225 static int reset_ccp_call_control_client(void)
226 {
227 	int err;
228 
229 	LOG_INF("Resetting");
230 
231 	if (peer_conn != NULL) {
232 		err = bt_conn_disconnect(peer_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
233 		if (err != 0) {
234 			return err;
235 		}
236 
237 		err = k_sem_take(&sem_conn_state_change, K_FOREVER);
238 		if (err != 0) {
239 			LOG_ERR("Failed to take sem_conn_state_change: %d", err);
240 			return err;
241 		}
242 	}
243 
244 	/* If scanning is already stopped it will still return `0` */
245 	err = bt_le_scan_stop();
246 	if (err != 0) {
247 		LOG_ERR("Scanning failed to stop (err %d)", err);
248 		return err;
249 	}
250 
251 	k_sem_reset(&sem_conn_state_change);
252 
253 	return 0;
254 }
255 
discover_services(void)256 static int discover_services(void)
257 {
258 	int err;
259 
260 	LOG_INF("Discovering GTBS and TBS");
261 
262 	err = bt_ccp_call_control_client_discover(peer_conn, &call_control_client);
263 	if (err != 0) {
264 		LOG_ERR("Failed to discover: %d", err);
265 		return err;
266 	}
267 
268 	err = k_sem_take(&sem_ccp_action_completed, SEM_TIMEOUT);
269 	if (err != 0) {
270 		LOG_ERR("Failed to take sem_ccp_action_completed: %d", err);
271 		return err;
272 	}
273 
274 	return 0;
275 }
276 
read_bearer_name(struct bt_ccp_call_control_client_bearer * bearer)277 static int read_bearer_name(struct bt_ccp_call_control_client_bearer *bearer)
278 {
279 	int err;
280 
281 	err = bt_ccp_call_control_client_read_bearer_provider_name(bearer);
282 	if (err != 0) {
283 		return err;
284 	}
285 
286 	err = k_sem_take(&sem_ccp_action_completed, SEM_TIMEOUT);
287 	if (err != 0) {
288 		LOG_ERR("Failed to take sem_ccp_action_completed: %d", err);
289 		return err;
290 	}
291 
292 	return 0;
293 }
294 
read_bearer_names(void)295 static int read_bearer_names(void)
296 {
297 	int err;
298 
299 #if defined(CONFIG_BT_TBS_CLIENT_GTBS)
300 	err = read_bearer_name(client_bearers.gtbs_bearer);
301 	if (err != 0) {
302 		LOG_ERR("Failed to read name for GTBS bearer: %d", err);
303 		return err;
304 	}
305 #endif /* CONFIG_BT_TBS_CLIENT_GTBS */
306 
307 #if defined(CONFIG_BT_TBS_CLIENT_TBS)
308 	for (size_t i = 0; i < client_bearers.tbs_count; i++) {
309 		err = read_bearer_name(client_bearers.tbs_bearers[i]);
310 		if (err != 0) {
311 			LOG_ERR("Failed to read name for bearer[%zu]: %d", i, err);
312 			return err;
313 		}
314 	}
315 #endif /* CONFIG_BT_TBS_CLIENT_TBS */
316 
317 	return 0;
318 }
319 
init_ccp_call_control_client(void)320 static int init_ccp_call_control_client(void)
321 {
322 	static struct bt_ccp_call_control_client_cb ccp_call_control_client_cbs = {
323 		.discover = ccp_call_control_client_discover_cb,
324 #if defined(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)
325 		.bearer_provider_name = ccp_call_control_client_read_bearer_provider_name_cb
326 #endif /* CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME */
327 	};
328 	static struct bt_le_scan_cb scan_cbs = {
329 		.recv = scan_recv_cb,
330 	};
331 	int err;
332 
333 	err = bt_enable(NULL);
334 	if (err != 0) {
335 		LOG_ERR("Bluetooth enable failed (err %d)", err);
336 
337 		return err;
338 	}
339 
340 	LOG_DBG("Bluetooth initialized");
341 	err = bt_le_scan_cb_register(&scan_cbs);
342 	if (err != 0) {
343 		LOG_ERR("Bluetooth enable failed (err %d)", err);
344 
345 		return err;
346 	}
347 
348 	err = bt_ccp_call_control_client_register_cb(&ccp_call_control_client_cbs);
349 	if (err != 0) {
350 		LOG_ERR("Bluetooth enable failed (err %d)", err);
351 
352 		return err;
353 	}
354 
355 	return 0;
356 }
357 
main(void)358 int main(void)
359 {
360 	int err;
361 
362 	err = init_ccp_call_control_client();
363 	if (err != 0) {
364 		return 0;
365 	}
366 
367 	LOG_INF("CCP Call Control Client initialized");
368 
369 	while (true) {
370 		err = reset_ccp_call_control_client();
371 		if (err != 0) {
372 			break;
373 		}
374 
375 		/* Start scanning for CCP servers and connect to the first we find */
376 		err = scan_and_connect();
377 		if (err != 0) {
378 			continue;
379 		}
380 
381 		/* Discover TBS and GTBS on the remove server */
382 		err = discover_services();
383 		if (err != 0) {
384 			continue;
385 		}
386 
387 		if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_BEARER_PROVIDER_NAME)) {
388 			err = read_bearer_names();
389 			if (err != 0) {
390 				continue;
391 			}
392 		}
393 
394 		/* Reset if disconnected */
395 		err = k_sem_take(&sem_conn_state_change, K_FOREVER);
396 		if (err != 0) {
397 			LOG_ERR("Failed to take sem_conn_state_change: err %d", err);
398 			break;
399 		}
400 	}
401 
402 	return 0;
403 }
404