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