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