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