1 /* btp_tmap.c - Bluetooth TMAP Tester */
2 
3 /*
4  * Copyright (c) 2024 Codecoup
5  * Copyright (c) 2025 Nordic Semiconductor ASA
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 #include <zephyr/autoconf.h>
10 #include <zephyr/bluetooth/audio/tmap.h>
11 #include "btp/btp.h"
12 
13 #include <zephyr/logging/log.h>
14 #include <zephyr/sys/util_macro.h>
15 LOG_MODULE_REGISTER(bttester_tmap, CONFIG_BTTESTER_LOG_LEVEL);
16 
read_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)17 static uint8_t read_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp,
18 				       uint16_t *rsp_len)
19 {
20 	struct btp_tmap_read_supported_commands_rp *rp = rsp;
21 
22 	tester_set_bit(rp->data, BTP_TMAP_READ_SUPPORTED_COMMANDS);
23 	tester_set_bit(rp->data, BTP_TMAP_DISCOVER);
24 
25 	*rsp_len = sizeof(*rp) + 1;
26 
27 	return BTP_STATUS_SUCCESS;
28 }
29 
tmap_discover_cb(enum bt_tmap_role role,struct bt_conn * conn,int err)30 static void tmap_discover_cb(enum bt_tmap_role role, struct bt_conn *conn, int err)
31 {
32 	struct btp_tmap_discovery_complete_ev ev;
33 
34 	if (err) {
35 		LOG_ERR("Discovery failed (%d)", err);
36 	}
37 
38 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
39 	ev.status = err;
40 	ev.role = role;
41 
42 	tester_event(BTP_SERVICE_ID_TMAP, BT_TMAP_EV_DISCOVERY_COMPLETE, &ev, sizeof(ev));
43 }
44 
45 static const struct bt_tmap_cb tmap_cb = {
46 	.discovery_complete = tmap_discover_cb,
47 };
48 
tmap_discover(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)49 static uint8_t tmap_discover(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
50 {
51 	const struct btp_tmap_discover_cmd *cp = cmd;
52 	struct bt_conn *conn;
53 	int err;
54 
55 	conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
56 	if (!conn) {
57 		LOG_ERR("Unknown connection");
58 		return BTP_STATUS_FAILED;
59 	}
60 
61 	err = bt_tmap_discover(conn, &tmap_cb);
62 	if (err != 0) {
63 		LOG_ERR("Failed to discover remote TMAP: %d", err);
64 	}
65 
66 	bt_conn_unref(conn);
67 
68 	return BTP_STATUS_VAL(err);
69 }
70 
71 static const struct btp_handler tmap_handlers[] = {
72 	{
73 		.opcode = BTP_TMAP_READ_SUPPORTED_COMMANDS,
74 		.index = BTP_INDEX_NONE,
75 		.expect_len = 0,
76 		.func = read_supported_commands,
77 	},
78 	{
79 		.opcode = BTP_TMAP_DISCOVER,
80 		.expect_len = sizeof(struct btp_tmap_discover_cmd),
81 		.func = tmap_discover,
82 	},
83 };
84 
tester_init_tmap(void)85 uint8_t tester_init_tmap(void)
86 {
87 	const enum bt_tmap_role role =
88 		(IS_ENABLED(CONFIG_BT_TMAP_CG_SUPPORTED) ? BT_TMAP_ROLE_CG : 0U) |
89 		(IS_ENABLED(CONFIG_BT_TMAP_CT_SUPPORTED) ? BT_TMAP_ROLE_CT : 0U) |
90 		(IS_ENABLED(CONFIG_BT_TMAP_UMS_SUPPORTED) ? BT_TMAP_ROLE_UMS : 0U) |
91 		(IS_ENABLED(CONFIG_BT_TMAP_UMR_SUPPORTED) ? BT_TMAP_ROLE_UMR : 0U) |
92 		(IS_ENABLED(CONFIG_BT_TMAP_BMS_SUPPORTED) ? BT_TMAP_ROLE_BMS : 0U) |
93 		(IS_ENABLED(CONFIG_BT_TMAP_BMR_SUPPORTED) ? BT_TMAP_ROLE_BMR : 0U);
94 	int err;
95 
96 	err = bt_tmap_register(role);
97 
98 	if (err != 0) {
99 		LOG_ERR("Failed to register TMAP (err %d)", err);
100 		return BTP_STATUS_FAILED;
101 	}
102 
103 	tester_register_command_handlers(BTP_SERVICE_ID_TMAP, tmap_handlers,
104 					 ARRAY_SIZE(tmap_handlers));
105 
106 	return BTP_STATUS_SUCCESS;
107 }
108 
tester_unregister_tmap(void)109 uint8_t tester_unregister_tmap(void)
110 {
111 	return BTP_STATUS_SUCCESS;
112 }
113