1 /** @file
2 * @brief Bluetooth Call Control Profile (CCP) Call Controller role.
3 *
4 * Copyright (c) 2020 Nordic Semiconductor ASA
5 * Copyright (c) 2022 Codecoup
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/sys/util.h>
13
14 #include <zephyr/bluetooth/conn.h>
15 #include <zephyr/bluetooth/audio/tbs.h>
16
17 enum {
18 CCP_FLAG_PROFILE_CONNECTED,
19 CCP_FLAG_GTBS_DISCOVER,
20 CCP_FLAG_CCID_READ,
21 CCP_FLAG_STATUS_FLAGS_READ,
22 CCP_FLAG_CALL_STATE_READ,
23
24 CCP_FLAG_NUM,
25 };
26
27 static ATOMIC_DEFINE(flags, CCP_FLAG_NUM)[CONFIG_BT_MAX_CONN];
28
process_profile_connection(struct bt_conn * conn)29 static int process_profile_connection(struct bt_conn *conn)
30 {
31 atomic_t *flags_for_conn = flags[bt_conn_index(conn)];
32 int err = 0;
33
34 if (!atomic_test_and_set_bit(flags_for_conn, CCP_FLAG_GTBS_DISCOVER)) {
35 err = bt_tbs_client_discover(conn);
36 if (err != 0) {
37 printk("bt_tbs_client_discover (err %d)\n", err);
38 }
39 } else if (!atomic_test_and_set_bit(flags_for_conn, CCP_FLAG_CCID_READ)) {
40 err = bt_tbs_client_read_ccid(conn, BT_TBS_GTBS_INDEX);
41 if (err != 0) {
42 printk("bt_tbs_client_read_ccid (err %d)\n", err);
43 }
44 } else if (!atomic_test_and_set_bit(flags_for_conn, CCP_FLAG_STATUS_FLAGS_READ)) {
45 err = bt_tbs_client_read_status_flags(conn, BT_TBS_GTBS_INDEX);
46 if (err != 0) {
47 printk("bt_tbs_client_read_status_flags (err %d)\n", err);
48 }
49 } else if (!atomic_test_and_set_bit(flags_for_conn, CCP_FLAG_CALL_STATE_READ)) {
50 err = bt_tbs_client_read_call_state(conn, BT_TBS_GTBS_INDEX);
51 if (err != 0) {
52 printk("bt_tbs_client_read_call_state (err %d)\n", err);
53 }
54 } else if (!atomic_test_and_set_bit(flags_for_conn, CCP_FLAG_PROFILE_CONNECTED)) {
55 printk("CCP Profile connected\n");
56 }
57
58 return err;
59 }
60
connected(struct bt_conn * conn,uint8_t err)61 static void connected(struct bt_conn *conn, uint8_t err)
62 {
63 if (err) {
64 printk("Connection failed (err %d)\n", err);
65 return;
66 }
67
68 atomic_set(flags[bt_conn_index(conn)], 0);
69
70 if (process_profile_connection(conn) != 0) {
71 printk("Profile connection failed");
72 }
73 }
74
75 BT_CONN_CB_DEFINE(conn_callbacks) = {
76 .connected = connected,
77 };
78
discover_cb(struct bt_conn * conn,int err,uint8_t tbs_count,bool gtbs_found)79 static void discover_cb(struct bt_conn *conn, int err, uint8_t tbs_count, bool gtbs_found)
80 {
81 if (!gtbs_found) {
82 printk("Failed to discover GTBS\n");
83 return;
84 }
85
86 if (err) {
87 printk("%s (err %d)\n", __func__, err);
88 return;
89 }
90
91 if (!atomic_test_bit(flags[bt_conn_index(conn)], CCP_FLAG_PROFILE_CONNECTED)) {
92 process_profile_connection(conn);
93 }
94 }
95
ccid_cb(struct bt_conn * conn,int err,uint8_t inst_index,uint32_t value)96 static void ccid_cb(struct bt_conn *conn, int err, uint8_t inst_index, uint32_t value)
97 {
98 if (inst_index != BT_TBS_GTBS_INDEX) {
99 printk("Unexpected %s for instance %u\n", __func__, inst_index);
100 return;
101 }
102
103 if (err) {
104 printk("%s (err %d)\n", __func__, err);
105 return;
106 }
107
108 if (!atomic_test_bit(flags[bt_conn_index(conn)], CCP_FLAG_PROFILE_CONNECTED)) {
109 process_profile_connection(conn);
110 }
111 }
112
status_flags_cb(struct bt_conn * conn,int err,uint8_t inst_index,uint32_t value)113 static void status_flags_cb(struct bt_conn *conn, int err, uint8_t inst_index, uint32_t value)
114 {
115 if (inst_index != BT_TBS_GTBS_INDEX) {
116 printk("Unexpected %s for instance %u\n", __func__, inst_index);
117 return;
118 }
119
120 if (err) {
121 printk("%s (err %d)\n", __func__, err);
122 return;
123 }
124
125 if (!atomic_test_bit(flags[bt_conn_index(conn)], CCP_FLAG_PROFILE_CONNECTED)) {
126 process_profile_connection(conn);
127 }
128 }
129
call_state_cb(struct bt_conn * conn,int err,uint8_t inst_index,uint8_t call_count,const struct bt_tbs_client_call_state * call_states)130 static void call_state_cb(struct bt_conn *conn, int err, uint8_t inst_index, uint8_t call_count,
131 const struct bt_tbs_client_call_state *call_states)
132 {
133 if (inst_index != BT_TBS_GTBS_INDEX) {
134 printk("Unexpected %s for instance %u\n", __func__, inst_index);
135 return;
136 }
137
138 if (err) {
139 printk("%s (err %d)\n", __func__, err);
140 return;
141 }
142
143 if (!atomic_test_bit(flags[bt_conn_index(conn)], CCP_FLAG_PROFILE_CONNECTED)) {
144 process_profile_connection(conn);
145 }
146 }
147
148 struct bt_tbs_client_cb tbs_client_cb = {
149 .discover = discover_cb,
150 .ccid = ccid_cb,
151 .status_flags = status_flags_cb,
152 .call_state = call_state_cb,
153 };
154
ccp_call_ctrl_init(void)155 int ccp_call_ctrl_init(void)
156 {
157 bt_tbs_client_register_cb(&tbs_client_cb);
158
159 return 0;
160 }
161