1 /** @file
2 * @brief Bluetooth Channel Sounding (CS) shell
3 *
4 */
5
6 /*
7 * Copyright (c) 2024 Nordic Semiconductor ASA
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <stdlib.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/shell/shell.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <zephyr/sys/util.h>
19
20 #include <zephyr/bluetooth/hci.h>
21 #include <zephyr/bluetooth/bluetooth.h>
22 #include <zephyr/bluetooth/conn.h>
23 #include <zephyr/bluetooth/iso.h>
24 #include <zephyr/bluetooth/cs.h>
25 #include <errno.h>
26
27 #include "host/shell/bt.h"
28 #include "host/shell/bt_shell_private.h"
29
check_cs_sync_antenna_selection_input(uint16_t input)30 static int check_cs_sync_antenna_selection_input(uint16_t input)
31 {
32 if (input != BT_LE_CS_ANTENNA_SELECTION_OPT_ONE &&
33 input != BT_LE_CS_ANTENNA_SELECTION_OPT_TWO &&
34 input != BT_LE_CS_ANTENNA_SELECTION_OPT_THREE &&
35 input != BT_LE_CS_ANTENNA_SELECTION_OPT_FOUR &&
36 input != BT_LE_CS_ANTENNA_SELECTION_OPT_REPETITIVE &&
37 input != BT_LE_CS_ANTENNA_SELECTION_OPT_NO_RECOMMENDATION) {
38 return -EINVAL;
39 }
40
41 return 0;
42 }
43
cmd_read_remote_supported_capabilities(const struct shell * sh,size_t argc,char * argv[])44 static int cmd_read_remote_supported_capabilities(const struct shell *sh, size_t argc, char *argv[])
45 {
46 int err = 0;
47
48 if (default_conn == NULL) {
49 shell_error(sh, "Conn handle error, at least one connection is required.");
50 return -ENOEXEC;
51 }
52
53 err = bt_le_cs_read_remote_supported_capabilities(default_conn);
54 if (err) {
55 shell_error(sh, "bt_le_cs_read_remote_supported_capabilities returned error %d",
56 err);
57 return -ENOEXEC;
58 }
59
60 return 0;
61 }
62
cmd_set_default_settings(const struct shell * sh,size_t argc,char * argv[])63 static int cmd_set_default_settings(const struct shell *sh, size_t argc, char *argv[])
64 {
65 int err = 0;
66 struct bt_le_cs_set_default_settings_param params;
67 uint16_t antenna_input;
68 int16_t tx_power_input;
69
70 if (default_conn == NULL) {
71 shell_error(sh, "Conn handle error, at least one connection is required.");
72 return -ENOEXEC;
73 }
74
75 params.enable_initiator_role = shell_strtobool(argv[1], 10, &err);
76 if (err) {
77 shell_help(sh);
78 shell_error(sh, "Could not parse input 1, Enable initiator role");
79 return SHELL_CMD_HELP_PRINTED;
80 }
81
82 params.enable_reflector_role = shell_strtobool(argv[2], 10, &err);
83 if (err) {
84 shell_help(sh);
85 shell_error(sh, "Could not parse input 2, Enable reflector role");
86 return SHELL_CMD_HELP_PRINTED;
87 }
88
89 antenna_input = shell_strtoul(argv[3], 16, &err);
90 if (err) {
91 shell_help(sh);
92 shell_error(sh, "Could not parse input 3, CS_SYNC antenna selection");
93 return SHELL_CMD_HELP_PRINTED;
94 }
95
96 err = check_cs_sync_antenna_selection_input(antenna_input);
97 if (err) {
98 shell_help(sh);
99 shell_error(sh, "CS_SYNC antenna selection input invalid");
100 return SHELL_CMD_HELP_PRINTED;
101 }
102
103 tx_power_input = shell_strtol(argv[4], 10, &err);
104 if (err) {
105 shell_help(sh);
106 shell_error(sh, "Could not parse input 4, Max TX power");
107 return SHELL_CMD_HELP_PRINTED;
108 }
109
110 params.cs_sync_antenna_selection = antenna_input;
111 params.max_tx_power = tx_power_input;
112
113 err = bt_le_cs_set_default_settings(default_conn, ¶ms);
114 if (err) {
115 shell_error(sh, "bt_le_cs_set_default_settings returned error %d", err);
116 return -ENOEXEC;
117 }
118
119 return 0;
120 }
121
cmd_read_remote_fae_table(const struct shell * sh,size_t argc,char * argv[])122 static int cmd_read_remote_fae_table(const struct shell *sh, size_t argc, char *argv[])
123 {
124 int err = 0;
125
126 if (default_conn == NULL) {
127 shell_error(sh, "Conn handle error, at least one connection is required.");
128 return -ENOEXEC;
129 }
130
131 err = bt_le_cs_read_remote_fae_table(default_conn);
132 if (err) {
133 shell_error(sh, "bt_le_cs_read_remote_fae_table returned error %d", err);
134 return -ENOEXEC;
135 }
136
137 return 0;
138 }
139
process_step_data(struct bt_le_cs_subevent_step * step,void * user_data)140 static bool process_step_data(struct bt_le_cs_subevent_step *step, void *user_data)
141 {
142 bt_shell_print("Subevent results contained step data: ");
143 bt_shell_print("- Step mode %d\n"
144 "- Step channel %d\n"
145 "- Step data hexdump:",
146 step->mode,
147 step->channel);
148 bt_shell_hexdump(step->data, step->data_len);
149
150 return true;
151 }
152
cs_test_subevent_data_cb(struct bt_conn_le_cs_subevent_result * result)153 static void cs_test_subevent_data_cb(struct bt_conn_le_cs_subevent_result *result)
154 {
155 bt_shell_print("Received subevent results.");
156 bt_shell_print("Subevent Header:\n"
157 "- Procedure Counter: %d\n"
158 "- Frequency Compensation: 0x%04x\n"
159 "- Reference Power Level: %d\n"
160 "- Procedure Done Status: 0x%02x\n"
161 "- Subevent Done Status: 0x%02x\n"
162 "- Procedure Abort Reason: 0x%02x\n"
163 "- Subevent Abort Reason: 0x%02x\n"
164 "- Number of Antenna Paths: %d\n"
165 "- Number of Steps Reported: %d",
166 result->header.procedure_counter,
167 result->header.frequency_compensation,
168 result->header.reference_power_level,
169 result->header.procedure_done_status,
170 result->header.subevent_done_status,
171 result->header.procedure_abort_reason,
172 result->header.subevent_abort_reason,
173 result->header.num_antenna_paths,
174 result->header.num_steps_reported);
175
176 if (result->step_data_buf) {
177 bt_le_cs_step_data_parse(result->step_data_buf, process_step_data, NULL);
178 }
179 }
180
cs_test_end_complete_cb(void)181 static void cs_test_end_complete_cb(void)
182 {
183 bt_shell_print("CS Test End Complete.");
184 }
185
cmd_cs_test_simple(const struct shell * sh,size_t argc,char * argv[])186 static int cmd_cs_test_simple(const struct shell *sh, size_t argc, char *argv[])
187 {
188 int err = 0;
189 struct bt_le_cs_test_param params;
190
191 params.main_mode = BT_CONN_LE_CS_MAIN_MODE_1;
192 params.sub_mode = BT_CONN_LE_CS_SUB_MODE_UNUSED;
193 params.main_mode_repetition = 0;
194 params.mode_0_steps = 2;
195
196 params.role = shell_strtoul(argv[1], 16, &err);
197
198 if (err) {
199 shell_help(sh);
200 shell_error(sh, "Could not parse input 1, Role selection");
201 return SHELL_CMD_HELP_PRINTED;
202 }
203
204 if (params.role != BT_CONN_LE_CS_ROLE_INITIATOR &&
205 params.role != BT_CONN_LE_CS_ROLE_REFLECTOR) {
206 shell_help(sh);
207 shell_error(sh, "Role selection input invalid");
208 return SHELL_CMD_HELP_PRINTED;
209 }
210
211 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_AA_ONLY;
212 params.cs_sync_phy = BT_CONN_LE_CS_SYNC_1M_PHY;
213 params.cs_sync_antenna_selection = BT_LE_CS_TEST_CS_SYNC_ANTENNA_SELECTION_ONE;
214 params.subevent_len = 3000;
215 params.subevent_interval = 1;
216 params.max_num_subevents = 1;
217 params.transmit_power_level = BT_HCI_OP_LE_CS_TEST_MAXIMIZE_TX_POWER;
218 params.t_ip1_time = 80;
219 params.t_ip2_time = 80;
220 params.t_fcs_time = 120;
221 params.t_pm_time = 20;
222 params.t_sw_time = 0;
223 params.tone_antenna_config_selection = BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_ONE;
224 params.initiator_snr_control = BT_LE_CS_SNR_CONTROL_NOT_USED;
225 params.reflector_snr_control = BT_LE_CS_SNR_CONTROL_NOT_USED;
226 params.drbg_nonce = 0x1234;
227 params.override_config = 0;
228 params.override_config_0.channel_map_repetition = 1;
229 memset(params.override_config_0.not_set.channel_map, 0,
230 sizeof(params.override_config_0.not_set.channel_map));
231 params.override_config_0.not_set.channel_map[1] = 0xFF;
232 params.override_config_0.not_set.channel_map[7] = 0xFF;
233 params.override_config_0.not_set.channel_map[8] = 0xFF;
234 params.override_config_0.not_set.channel_selection_type = BT_CONN_LE_CS_CHSEL_TYPE_3B;
235 params.override_config_0.not_set.ch3c_shape = BT_CONN_LE_CS_CH3C_SHAPE_HAT;
236 params.override_config_0.not_set.ch3c_jump = 0x2;
237
238 struct bt_le_cs_test_cb cs_test_cb = {
239 .le_cs_test_subevent_data_available = cs_test_subevent_data_cb,
240 .le_cs_test_end_complete = cs_test_end_complete_cb,
241 };
242
243 err = bt_le_cs_test_cb_register(cs_test_cb);
244 if (err) {
245 shell_error(sh, "bt_le_cs_test_cb_register returned error %d", err);
246 return -ENOEXEC;
247 }
248
249 err = bt_le_cs_start_test(¶ms);
250 if (err) {
251 shell_error(sh, "bt_le_cs_start_test returned error %d", err);
252 return -ENOEXEC;
253 }
254
255 return 0;
256 }
257
cmd_remove_config(const struct shell * sh,size_t argc,char * argv[])258 static int cmd_remove_config(const struct shell *sh, size_t argc, char *argv[])
259 {
260 int err = 0;
261
262 if (default_conn == NULL) {
263 shell_error(sh, "Conn handle error, at least one connection is required.");
264 return -ENOEXEC;
265 }
266
267 uint8_t config_id = strtoul(argv[1], NULL, 10);
268
269 err = bt_le_cs_remove_config(default_conn, config_id);
270 if (err) {
271 shell_error(sh, "bt_le_cs_remove_config returned error %d", err);
272 return -ENOEXEC;
273 }
274
275 return 0;
276 }
277
cmd_create_config(const struct shell * sh,size_t argc,char * argv[])278 static int cmd_create_config(const struct shell *sh, size_t argc, char *argv[])
279 {
280 int err = 0;
281 enum bt_le_cs_create_config_context context;
282 struct bt_le_cs_create_config_params params;
283
284 if (default_conn == NULL) {
285 shell_error(sh, "Conn handle error, at least one connection is required.");
286 return -ENOEXEC;
287 }
288
289 params.id = strtoul(argv[1], NULL, 10);
290 if (!strcmp(argv[2], "local-only")) {
291 context = BT_LE_CS_CREATE_CONFIG_CONTEXT_LOCAL_ONLY;
292 } else if (!strcmp(argv[2], "local-only")) {
293 context = BT_LE_CS_CREATE_CONFIG_CONTEXT_LOCAL_AND_REMOTE;
294 } else {
295 shell_error(sh, "Invalid context: %s", argv[2]);
296 shell_help(sh);
297 return SHELL_CMD_HELP_PRINTED;
298 }
299
300 if (!strcmp(argv[3], "initiator")) {
301 params.role = BT_CONN_LE_CS_ROLE_INITIATOR;
302 } else if (!strcmp(argv[3], "reflector")) {
303 params.role = BT_CONN_LE_CS_ROLE_REFLECTOR;
304 } else {
305 shell_error(sh, "Invalid role: %s", argv[3]);
306 shell_help(sh);
307 return SHELL_CMD_HELP_PRINTED;
308 }
309
310 /* Set the default values */
311 params.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_2;
312 params.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_1;
313 params.min_main_mode_steps = 0x05;
314 params.max_main_mode_steps = 0x0A;
315 params.main_mode_repetition = 0;
316 params.mode_0_steps = 1;
317 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_AA_ONLY;
318 params.cs_sync_phy = BT_CONN_LE_CS_SYNC_2M_PHY;
319 params.channel_map_repetition = 1;
320 params.channel_selection_type = BT_CONN_LE_CS_CHSEL_TYPE_3B;
321 params.ch3c_shape = BT_CONN_LE_CS_CH3C_SHAPE_HAT;
322 params.ch3c_jump = 2;
323
324 bt_le_cs_set_valid_chmap_bits(params.channel_map);
325
326 for (int j = 4; j < argc; j++) {
327 if (!strcmp(argv[j], "rtt-none")) {
328 params.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_1;
329 params.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_UNUSED;
330 } else if (!strcmp(argv[j], "pbr-none")) {
331 params.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_2;
332 params.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_UNUSED;
333 } else if (!strcmp(argv[j], "both-none")) {
334 params.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_3;
335 params.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_UNUSED;
336 } else if (!strcmp(argv[j], "pbr-rtt")) {
337 params.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_2;
338 params.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_1;
339 } else if (!strcmp(argv[j], "pbr-both")) {
340 params.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_2;
341 params.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_3;
342 } else if (!strcmp(argv[j], "both-pbr")) {
343 params.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_3;
344 params.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_2;
345 } else if (!strcmp(argv[j], "steps")) {
346 if (++j == argc) {
347 shell_help(sh);
348 return SHELL_CMD_HELP_PRINTED;
349 }
350
351 params.min_main_mode_steps = strtoul(argv[j], NULL, 10);
352 if (++j == argc) {
353 shell_help(sh);
354 return SHELL_CMD_HELP_PRINTED;
355 }
356
357 params.max_main_mode_steps = strtoul(argv[j], NULL, 10);
358 if (++j == argc) {
359 shell_help(sh);
360 return SHELL_CMD_HELP_PRINTED;
361 }
362
363 params.mode_0_steps = strtoul(argv[j], NULL, 10);
364 } else if (!strcmp(argv[j], "aa-only")) {
365 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_AA_ONLY;
366 } else if (!strcmp(argv[j], "32b-sound")) {
367 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_32_BIT_SOUNDING;
368 } else if (!strcmp(argv[j], "96b-sound")) {
369 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_96_BIT_SOUNDING;
370 } else if (!strcmp(argv[j], "32b-rand")) {
371 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_32_BIT_RANDOM;
372 } else if (!strcmp(argv[j], "64b-rand")) {
373 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_64_BIT_RANDOM;
374 } else if (!strcmp(argv[j], "96b-rand")) {
375 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_96_BIT_RANDOM;
376 } else if (!strcmp(argv[j], "128b-rand")) {
377 params.rtt_type = BT_CONN_LE_CS_RTT_TYPE_128_BIT_RANDOM;
378 } else if (!strcmp(argv[j], "phy-1m")) {
379 params.cs_sync_phy = BT_CONN_LE_CS_SYNC_1M_PHY;
380 } else if (!strcmp(argv[j], "phy-2m")) {
381 params.cs_sync_phy = BT_CONN_LE_CS_SYNC_2M_PHY;
382 } else if (!strcmp(argv[j], "phy-2m-2b")) {
383 params.cs_sync_phy = BT_CONN_LE_CS_SYNC_2M_2BT_PHY;
384 } else if (!strcmp(argv[j], "chmap-rep")) {
385 if (++j == argc) {
386 shell_help(sh);
387 return SHELL_CMD_HELP_PRINTED;
388 }
389
390 params.channel_map_repetition = strtoul(argv[j], NULL, 10);
391 } else if (!strcmp(argv[j], "hat-shape")) {
392 params.ch3c_shape = BT_CONN_LE_CS_CH3C_SHAPE_HAT;
393 } else if (!strcmp(argv[j], "x-shape")) {
394 params.ch3c_shape = BT_CONN_LE_CS_CH3C_SHAPE_X;
395 } else if (!strcmp(argv[j], "chsel-3b")) {
396 params.channel_selection_type = BT_CONN_LE_CS_CHSEL_TYPE_3B;
397 } else if (!strcmp(argv[j], "chsel-3c")) {
398 params.channel_selection_type = BT_CONN_LE_CS_CHSEL_TYPE_3C;
399 } else if (!strcmp(argv[j], "ch3c-jump")) {
400 if (++j == argc) {
401 shell_help(sh);
402 return SHELL_CMD_HELP_PRINTED;
403 }
404
405 params.ch3c_jump = strtoul(argv[j], NULL, 10);
406 } else if (!strcmp(argv[j], "chmap")) {
407 if (++j == argc) {
408 shell_help(sh);
409 return SHELL_CMD_HELP_PRINTED;
410 }
411
412 if (hex2bin(argv[j], strlen(argv[j]), params.channel_map, 10) == 0) {
413 shell_error(sh, "Invalid channel map");
414 return -ENOEXEC;
415 }
416
417 sys_mem_swap(params.channel_map, 10);
418 } else {
419 shell_help(sh);
420 return SHELL_CMD_HELP_PRINTED;
421 }
422 }
423
424 err = bt_le_cs_create_config(default_conn, ¶ms, context);
425 if (err) {
426 shell_error(sh, "bt_le_cs_create_config returned error %d", err);
427 return -ENOEXEC;
428 }
429
430 return 0;
431 }
432
cmd_cs_stop_test(const struct shell * sh,size_t argc,char * argv[])433 static int cmd_cs_stop_test(const struct shell *sh, size_t argc, char *argv[])
434 {
435 int err = 0;
436
437 err = bt_le_cs_stop_test();
438 if (err) {
439 shell_error(sh, "bt_cs_stop_test returned error %d", err);
440 return -ENOEXEC;
441 }
442
443 return 0;
444 }
445
cmd_read_local_supported_capabilities(const struct shell * sh,size_t argc,char * argv[])446 static int cmd_read_local_supported_capabilities(const struct shell *sh, size_t argc, char *argv[])
447 {
448 int err = 0;
449
450 struct bt_conn_le_cs_capabilities params;
451
452 err = bt_le_cs_read_local_supported_capabilities(¶ms);
453
454 if (err) {
455 shell_error(sh, "bt_le_cs_read_local_supported_capabilities returned error %d",
456 err);
457
458 return -ENOEXEC;
459 }
460
461 shell_print(
462 sh,
463 "Local channel sounding supported capabilities:\n"
464 "- Num CS configurations: %d\n"
465 "- Max consecutive CS procedures: %d\n"
466 "- Num antennas supported: %d\n"
467 "- Max antenna paths supported: %d\n"
468 "- Initiator role supported: %s\n"
469 "- Reflector role supported: %s\n"
470 "- Mode 3 supported: %s\n"
471 "- RTT AA only supported: %s\n"
472 "- RTT AA only is 10ns precise: %s\n"
473 "- RTT AA only N: %d\n"
474 "- RTT sounding supported: %s\n"
475 "- RTT sounding is 10ns precise: %s\n"
476 "- RTT sounding N: %d\n"
477 "- RTT random payload supported: %s\n"
478 "- RTT random payload is 10ns precise: %s\n"
479 "- RTT random payload N: %d\n"
480 "- Phase-based NADM with sounding sequences supported: %s\n"
481 "- Phase-based NADM with random sequences supported: %s\n"
482 "- CS Sync 2M PHY supported: %s\n"
483 "- CS Sync 2M 2BT PHY supported: %s\n"
484 "- CS without transmitter FAE supported: %s\n"
485 "- Channel selection algorithm #3c supported: %s\n"
486 "- Phase-based ranging from RTT sounding sequence supported: %s\n"
487 "- T_IP1 times supported: 0x%04x\n"
488 "- T_IP2 times supported: 0x%04x\n"
489 "- T_FCS times supported: 0x%04x\n"
490 "- T_PM times supported: 0x%04x\n"
491 "- T_SW time supported: %d us\n"
492 "- TX SNR capability: 0x%02x",
493 params.num_config_supported, params.max_consecutive_procedures_supported,
494 params.num_antennas_supported, params.max_antenna_paths_supported,
495 params.initiator_supported ? "Yes" : "No",
496 params.reflector_supported ? "Yes" : "No", params.mode_3_supported ? "Yes" : "No",
497 params.rtt_aa_only_precision == BT_CONN_LE_CS_RTT_AA_ONLY_NOT_SUPP ? "No" : "Yes",
498 params.rtt_aa_only_precision == BT_CONN_LE_CS_RTT_AA_ONLY_10NS ? "Yes" : "No",
499 params.rtt_aa_only_n,
500 params.rtt_sounding_precision == BT_CONN_LE_CS_RTT_SOUNDING_NOT_SUPP ? "No" : "Yes",
501 params.rtt_sounding_precision == BT_CONN_LE_CS_RTT_SOUNDING_10NS ? "Yes" : "No",
502 params.rtt_sounding_n,
503 params.rtt_random_payload_precision == BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_NOT_SUPP
504 ? "No"
505 : "Yes",
506 params.rtt_random_payload_precision == BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS ? "Yes"
507 : "No",
508 params.rtt_random_payload_n,
509 params.phase_based_nadm_sounding_supported ? "Yes" : "No",
510 params.phase_based_nadm_random_supported ? "Yes" : "No",
511 params.cs_sync_2m_phy_supported ? "Yes" : "No",
512 params.cs_sync_2m_2bt_phy_supported ? "Yes" : "No",
513 params.cs_without_fae_supported ? "Yes" : "No",
514 params.chsel_alg_3c_supported ? "Yes" : "No",
515 params.pbr_from_rtt_sounding_seq_supported ? "Yes" : "No",
516 params.t_ip1_times_supported, params.t_ip2_times_supported,
517 params.t_fcs_times_supported, params.t_pm_times_supported, params.t_sw_time,
518 params.tx_snr_capability);
519
520 return 0;
521 }
522
cmd_write_cached_remote_supported_capabilities(const struct shell * sh,size_t argc,char * argv[])523 static int cmd_write_cached_remote_supported_capabilities(const struct shell *sh, size_t argc,
524 char *argv[])
525 {
526 int err = 0;
527
528 if (default_conn == NULL) {
529 shell_error(sh, "Conn handle error, at least one connection is required.");
530 return -ENOEXEC;
531 }
532
533 struct bt_conn_le_cs_capabilities params;
534
535 params.num_config_supported = 1;
536 params.max_consecutive_procedures_supported = 0;
537 params.num_antennas_supported = 1;
538 params.max_antenna_paths_supported = 1;
539 params.initiator_supported = true;
540 params.reflector_supported = true;
541 params.mode_3_supported = true;
542 params.rtt_aa_only_precision = BT_CONN_LE_CS_RTT_AA_ONLY_10NS;
543 params.rtt_sounding_precision = BT_CONN_LE_CS_RTT_SOUNDING_10NS;
544 params.rtt_random_payload_precision = BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS;
545 params.rtt_aa_only_n = 5;
546 params.rtt_sounding_n = 6;
547 params.rtt_random_payload_n = 7;
548 params.phase_based_nadm_sounding_supported = true;
549 params.phase_based_nadm_random_supported = true;
550 params.cs_sync_2m_phy_supported = true;
551 params.cs_sync_2m_2bt_phy_supported = true;
552 params.chsel_alg_3c_supported = true;
553 params.cs_without_fae_supported = true;
554 params.pbr_from_rtt_sounding_seq_supported = false;
555 params.t_ip1_times_supported = BT_HCI_LE_CS_T_IP1_TIME_10US_MASK;
556 params.t_ip2_times_supported = BT_HCI_LE_CS_T_IP2_TIME_10US_MASK;
557 params.t_fcs_times_supported = BT_HCI_LE_CS_T_FCS_TIME_100US_MASK;
558 params.t_sw_time = 0x04;
559 params.tx_snr_capability = BT_HCI_LE_CS_TX_SNR_CAPABILITY_18DB_MASK;
560
561 err = bt_le_cs_write_cached_remote_supported_capabilities(default_conn, ¶ms);
562
563 if (err) {
564 shell_error(sh, "bt_le_cs_set_channel_classification returned error %d", err);
565 return -ENOEXEC;
566 }
567
568 return 0;
569 }
570
cmd_security_enable(const struct shell * sh,size_t argc,char * argv[])571 static int cmd_security_enable(const struct shell *sh, size_t argc, char *argv[])
572 {
573 int err = 0;
574
575 if (default_conn == NULL) {
576 shell_error(sh, "Conn handle error, at least one connection is required.");
577 return -ENOEXEC;
578 }
579
580 err = bt_le_cs_security_enable(default_conn);
581
582 if (err) {
583 shell_error(sh, "bt_le_cs_security_enable returned error %d", err);
584 return -ENOEXEC;
585 }
586
587 return 0;
588 }
589
cmd_set_channel_classification(const struct shell * sh,size_t argc,char * argv[])590 static int cmd_set_channel_classification(const struct shell *sh, size_t argc, char *argv[])
591 {
592 int err = 0;
593
594 if (default_conn == NULL) {
595 shell_error(sh, "Conn handle error, at least one connection is required.");
596 return -ENOEXEC;
597 }
598
599 uint8_t channel_classification[10];
600
601 for (int i = 0; i < 10; i++) {
602 channel_classification[i] = shell_strtoul(argv[1 + i], 16, &err);
603
604 if (err) {
605 shell_help(sh);
606 shell_error(sh, "Could not parse input %d, Channel Classification[%d]", i,
607 i);
608
609 return SHELL_CMD_HELP_PRINTED;
610 }
611 }
612
613 err = bt_le_cs_set_channel_classification(channel_classification);
614
615 if (err) {
616 shell_error(sh, "bt_le_cs_set_channel_classification returned error %d", err);
617 return -ENOEXEC;
618 }
619
620 return 0;
621 }
622
cmd_set_procedure_parameters(const struct shell * sh,size_t argc,char * argv[])623 static int cmd_set_procedure_parameters(const struct shell *sh, size_t argc, char *argv[])
624 {
625 int err = 0;
626
627 if (default_conn == NULL) {
628 shell_error(sh, "Conn handle error, at least one connection is required.");
629 return -ENOEXEC;
630 }
631
632 struct bt_le_cs_set_procedure_parameters_param params;
633
634 params.config_id = 0;
635 params.max_procedure_len = 1000;
636 params.min_procedure_interval = 5;
637 params.max_procedure_interval = 5000;
638 params.max_procedure_count = 1;
639 params.min_subevent_len = 5000;
640 params.max_subevent_len = 4000000;
641 params.tone_antenna_config_selection = BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_ONE;
642 params.phy = 0x01;
643 params.tx_power_delta = 0x80;
644 params.preferred_peer_antenna = 1;
645 params.snr_control_initiator = BT_LE_CS_SNR_CONTROL_18dB;
646 params.snr_control_reflector = BT_LE_CS_SNR_CONTROL_18dB;
647
648 err = bt_le_cs_set_procedure_parameters(default_conn, ¶ms);
649
650 if (err) {
651 shell_error(sh, "bt_le_cs_set_procedure_parameters returned error %d", err);
652 return -ENOEXEC;
653 }
654
655 return 0;
656 }
657
cmd_procedure_enable(const struct shell * sh,size_t argc,char * argv[])658 static int cmd_procedure_enable(const struct shell *sh, size_t argc, char *argv[])
659 {
660 int err = 0;
661
662 if (default_conn == NULL) {
663 shell_error(sh, "Conn handle error, at least one connection is required.");
664 return -ENOEXEC;
665 }
666
667 struct bt_le_cs_procedure_enable_param params;
668
669 params.config_id = shell_strtoul(argv[1], 16, &err);
670
671 if (err) {
672 shell_help(sh);
673 shell_error(sh, "Could not parse input 1, Config ID");
674 return SHELL_CMD_HELP_PRINTED;
675 }
676
677 params.enable = shell_strtoul(argv[2], 16, &err);
678
679 if (err) {
680 shell_help(sh);
681 shell_error(sh, "Could not parse input 2, Enable");
682 return SHELL_CMD_HELP_PRINTED;
683 }
684
685 err = bt_le_cs_procedure_enable(default_conn, ¶ms);
686
687 if (err) {
688 shell_error(sh, "bt_le_cs_procedure_enable returned error %d", err);
689 return -ENOEXEC;
690 }
691
692 return 0;
693 }
694
695 SHELL_STATIC_SUBCMD_SET_CREATE(
696 cs_cmds,
697 SHELL_CMD_ARG(read_remote_supported_capabilities, NULL, "<None>",
698 cmd_read_remote_supported_capabilities, 1, 0),
699 SHELL_CMD_ARG(
700 set_default_settings, NULL,
701 "<Enable initiator role: true, false> <Enable reflector role: true, false> "
702 " <CS_SYNC antenna selection: 0x01 - 0x04, 0xFE, 0xFF> <Max TX power: -127 - 20>",
703 cmd_set_default_settings, 5, 0),
704 SHELL_CMD_ARG(read_remote_fae_table, NULL, "<None>", cmd_read_remote_fae_table, 1, 0),
705 SHELL_CMD_ARG(start_simple_cs_test, NULL, "<Role selection (initiator, reflector): 0, 1>",
706 cmd_cs_test_simple, 2, 0),
707 SHELL_CMD_ARG(stop_cs_test, NULL, "<None>", cmd_cs_stop_test, 1, 0),
708 SHELL_CMD_ARG(
709 create_config, NULL,
710 "<id> <context: local-only, local-remote> <role: initiator, reflector> "
711 "[rtt-none, pbr-none, both-none, pbr-rtt, pbr-both, both-pbr] [steps <min> "
712 "<max> <mode-0>] [aa-only, 32b-sound, 96b-sound, 32b-rand, 64b-rand, 96b-rand, "
713 "128b-rand] [phy-1m, phy-2m, phy-2m-2b] [chmap-rep <rep>] [hat-shape, x-shape] "
714 "[ch3c-jump <jump>] [chmap <XXXXXXXXXXXXXXXX>] (78-0) [chsel-3b, chsel-3c]",
715 cmd_create_config, 4, 15),
716 SHELL_CMD_ARG(remove_config, NULL, "<id>", cmd_remove_config, 2, 0),
717 SHELL_CMD_ARG(read_local_supported_capabilities, NULL, "<None>",
718 cmd_read_local_supported_capabilities, 1, 0),
719 SHELL_CMD_ARG(write_cached_remote_supported_capabilities, NULL, "<None>",
720 cmd_write_cached_remote_supported_capabilities, 1, 0),
721 SHELL_CMD_ARG(security_enable, NULL, "<None>", cmd_security_enable, 1, 0),
722 SHELL_CMD_ARG(set_channel_classification, NULL,
723 "<Byte 0> <Byte 1> <Byte 2> <Byte 3> "
724 "<Byte 4> <Byte 5> <Byte 6> <Byte 7> <Byte 8> <Byte 9>",
725 cmd_set_channel_classification, 11, 0),
726 SHELL_CMD_ARG(set_procedure_parameters, NULL, "<None>", cmd_set_procedure_parameters, 1, 0),
727 SHELL_CMD_ARG(procedure_enable, NULL, "<Config ID: 0 to 3> <Enable: 0, 1>",
728 cmd_procedure_enable, 3, 0),
729 SHELL_SUBCMD_SET_END);
730
cmd_cs(const struct shell * sh,size_t argc,char ** argv)731 static int cmd_cs(const struct shell *sh, size_t argc, char **argv)
732 {
733 if (argc == 1) {
734 shell_help(sh);
735
736 return SHELL_CMD_HELP_PRINTED;
737 }
738
739 shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
740
741 return -EINVAL;
742 }
743
744 SHELL_CMD_ARG_REGISTER(cs, &cs_cmds, "Bluetooth CS shell commands", cmd_cs, 1, 1);
745