1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <math.h>
8 #include <zephyr/sys/byteorder.h>
9 #include <zephyr/bluetooth/bluetooth.h>
10 #include <zephyr/bluetooth/cs.h>
11 #include <zephyr/bluetooth/att.h>
12 #include <zephyr/bluetooth/gatt.h>
13 #include "common.h"
14 
15 #define CS_CONFIG_ID     0
16 #define NUM_MODE_0_STEPS 1
17 
18 static K_SEM_DEFINE(sem_remote_capabilities_obtained, 0, 1);
19 static K_SEM_DEFINE(sem_config_created, 0, 1);
20 static K_SEM_DEFINE(sem_cs_security_enabled, 0, 1);
21 static K_SEM_DEFINE(sem_procedure_done, 0, 1);
22 static K_SEM_DEFINE(sem_connected, 0, 1);
23 static K_SEM_DEFINE(sem_discovered, 0, 1);
24 static K_SEM_DEFINE(sem_written, 0, 1);
25 
26 static uint16_t step_data_attr_handle;
27 static struct bt_conn *connection;
28 static uint8_t latest_local_steps[STEP_DATA_BUF_LEN];
29 
30 static const char sample_str[] = "CS Sample";
31 static const struct bt_data ad[] = {
32 	BT_DATA(BT_DATA_NAME_COMPLETE, "CS Sample", sizeof(sample_str) - 1),
33 };
34 
subevent_result_cb(struct bt_conn * conn,struct bt_conn_le_cs_subevent_result * result)35 static void subevent_result_cb(struct bt_conn *conn, struct bt_conn_le_cs_subevent_result *result)
36 {
37 	if (result->step_data_buf) {
38 		if (result->step_data_buf->len <= STEP_DATA_BUF_LEN) {
39 			memcpy(latest_local_steps, result->step_data_buf->data,
40 			       result->step_data_buf->len);
41 		} else {
42 			printk("Not enough memory to store step data. (%d > %d)\n",
43 			       result->step_data_buf->len, STEP_DATA_BUF_LEN);
44 		}
45 	}
46 
47 	if (result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_COMPLETE) {
48 		k_sem_give(&sem_procedure_done);
49 	}
50 }
51 
mtu_exchange_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_exchange_params * params)52 static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
53 			    struct bt_gatt_exchange_params *params)
54 {
55 	printk("MTU exchange %s (%u)\n", err == 0U ? "success" : "failed", bt_gatt_get_mtu(conn));
56 }
57 
connected_cb(struct bt_conn * conn,uint8_t err)58 static void connected_cb(struct bt_conn *conn, uint8_t err)
59 {
60 	char addr[BT_ADDR_LE_STR_LEN];
61 
62 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
63 	printk("Connected to %s (err 0x%02X)\n", addr, err);
64 
65 	__ASSERT(connection == conn, "Unexpected connected callback");
66 
67 	if (err) {
68 		bt_conn_unref(conn);
69 		connection = NULL;
70 	}
71 
72 	connection = bt_conn_ref(conn);
73 
74 	static struct bt_gatt_exchange_params mtu_exchange_params = {.func = mtu_exchange_cb};
75 
76 	err = bt_gatt_exchange_mtu(connection, &mtu_exchange_params);
77 	if (err) {
78 		printk("%s: MTU exchange failed (err %d)\n", __func__, err);
79 	}
80 
81 	k_sem_give(&sem_connected);
82 }
83 
disconnected_cb(struct bt_conn * conn,uint8_t reason)84 static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
85 {
86 	printk("Disconnected (reason 0x%02X)\n", reason);
87 
88 	bt_conn_unref(conn);
89 	connection = NULL;
90 }
91 
remote_capabilities_cb(struct bt_conn * conn,struct bt_conn_le_cs_capabilities * params)92 static void remote_capabilities_cb(struct bt_conn *conn, struct bt_conn_le_cs_capabilities *params)
93 {
94 	ARG_UNUSED(params);
95 	printk("CS capability exchange completed.\n");
96 	k_sem_give(&sem_remote_capabilities_obtained);
97 }
98 
config_created_cb(struct bt_conn * conn,struct bt_conn_le_cs_config * config)99 static void config_created_cb(struct bt_conn *conn, struct bt_conn_le_cs_config *config)
100 {
101 	printk("CS config creation complete. ID: %d\n", config->id);
102 	k_sem_give(&sem_config_created);
103 }
104 
security_enabled_cb(struct bt_conn * conn)105 static void security_enabled_cb(struct bt_conn *conn)
106 {
107 	printk("CS security enabled.\n");
108 	k_sem_give(&sem_cs_security_enabled);
109 }
110 
procedure_enabled_cb(struct bt_conn * conn,struct bt_conn_le_cs_procedure_enable_complete * params)111 static void procedure_enabled_cb(struct bt_conn *conn,
112 				 struct bt_conn_le_cs_procedure_enable_complete *params)
113 {
114 	if (params->state == 1) {
115 		printk("CS procedures enabled.\n");
116 	} else {
117 		printk("CS procedures disabled.\n");
118 	}
119 }
120 
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)121 static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
122 			     struct bt_gatt_discover_params *params)
123 {
124 	struct bt_gatt_chrc *chrc;
125 	char str[BT_UUID_STR_LEN];
126 
127 	printk("Discovery: attr %p\n", attr);
128 
129 	if (!attr) {
130 		return BT_GATT_ITER_STOP;
131 	}
132 
133 	chrc = (struct bt_gatt_chrc *)attr->user_data;
134 
135 	bt_uuid_to_str(chrc->uuid, str, sizeof(str));
136 	printk("UUID %s\n", str);
137 
138 	if (!bt_uuid_cmp(chrc->uuid, &step_data_char_uuid.uuid)) {
139 		step_data_attr_handle = chrc->value_handle;
140 
141 		printk("Found expected UUID\n");
142 
143 		k_sem_give(&sem_discovered);
144 	}
145 
146 	return BT_GATT_ITER_STOP;
147 }
148 
write_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)149 static void write_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params)
150 {
151 	if (err) {
152 		printk("Write failed (err %d)\n", err);
153 
154 		return;
155 	}
156 
157 	k_sem_give(&sem_written);
158 }
159 
160 BT_CONN_CB_DEFINE(conn_cb) = {
161 	.connected = connected_cb,
162 	.disconnected = disconnected_cb,
163 	.le_cs_remote_capabilities_available = remote_capabilities_cb,
164 	.le_cs_config_created = config_created_cb,
165 	.le_cs_security_enabled = security_enabled_cb,
166 	.le_cs_procedure_enabled = procedure_enabled_cb,
167 	.le_cs_subevent_data_available = subevent_result_cb,
168 };
169 
main(void)170 int main(void)
171 {
172 	int err;
173 	struct bt_gatt_discover_params discover_params;
174 	struct bt_gatt_write_params write_params;
175 
176 	printk("Starting Channel Sounding Demo\n");
177 
178 	/* Initialize the Bluetooth Subsystem */
179 	err = bt_enable(NULL);
180 	if (err) {
181 		printk("Bluetooth init failed (err %d)\n", err);
182 		return 0;
183 	}
184 
185 	err = bt_le_adv_start(BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONN, BT_GAP_ADV_FAST_INT_MIN_1,
186 					      BT_GAP_ADV_FAST_INT_MAX_1, NULL),
187 			      ad, ARRAY_SIZE(ad), NULL, 0);
188 	if (err) {
189 		printk("Advertising failed to start (err %d)\n", err);
190 		return 0;
191 	}
192 
193 	k_sem_take(&sem_connected, K_FOREVER);
194 
195 	const struct bt_le_cs_set_default_settings_param default_settings = {
196 		.enable_initiator_role = false,
197 		.enable_reflector_role = true,
198 		.cs_sync_antenna_selection = BT_LE_CS_ANTENNA_SELECTION_OPT_REPETITIVE,
199 		.max_tx_power = BT_HCI_OP_LE_CS_MAX_MAX_TX_POWER,
200 	};
201 
202 	err = bt_le_cs_set_default_settings(connection, &default_settings);
203 	if (err) {
204 		printk("Failed to configure default CS settings (err %d)\n", err);
205 	}
206 
207 	discover_params.uuid = &step_data_char_uuid.uuid;
208 	discover_params.func = discover_func;
209 	discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
210 	discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
211 	discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
212 
213 	err = bt_gatt_discover(connection, &discover_params);
214 	if (err) {
215 		printk("Discovery failed (err %d)\n", err);
216 		return 0;
217 	}
218 
219 	err = k_sem_take(&sem_discovered, K_SECONDS(10));
220 	if (err) {
221 		printk("Timed out during GATT discovery\n");
222 		return 0;
223 	}
224 
225 	while (true) {
226 		k_sem_take(&sem_procedure_done, K_FOREVER);
227 
228 		write_params.func = write_func;
229 		write_params.handle = step_data_attr_handle;
230 		write_params.length = STEP_DATA_BUF_LEN;
231 		write_params.data = &latest_local_steps[0];
232 		write_params.offset = 0;
233 
234 		err = bt_gatt_write(connection, &write_params);
235 		if (err) {
236 			printk("Write failed (err %d)\n", err);
237 			return 0;
238 		}
239 
240 		err = k_sem_take(&sem_written, K_SECONDS(10));
241 		if (err) {
242 			printk("Timed out during GATT write\n");
243 			return 0;
244 		}
245 	}
246 
247 	return 0;
248 }
249