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