1 /** @file
2 * @brief Bluetooth MICP shell.
3 *
4 * Copyright (c) 2020 Bose Corporation
5 * Copyright (c) 2020-2022 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/types.h>
11 #include <zephyr/bluetooth/conn.h>
12 #include <zephyr/bluetooth/audio/micp.h>
13 #include <zephyr/shell/shell.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16
17 #include "shell/bt.h"
18
micp_mic_dev_mute_cb(uint8_t mute)19 static void micp_mic_dev_mute_cb(uint8_t mute)
20 {
21 shell_print(ctx_shell, "Mute value %u", mute);
22 }
23
24 static struct bt_micp_mic_dev_cb micp_mic_dev_cbs = {
25 .mute = micp_mic_dev_mute_cb,
26 };
27
28 #if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
29 static struct bt_micp_included micp_included;
30
micp_mic_dev_aics_state_cb(struct bt_aics * inst,int err,int8_t gain,uint8_t mute,uint8_t mode)31 static void micp_mic_dev_aics_state_cb(struct bt_aics *inst, int err,
32 int8_t gain, uint8_t mute, uint8_t mode)
33 {
34 if (err != 0) {
35 shell_error(ctx_shell, "AICS state get failed (%d) for "
36 "inst %p", err, inst);
37 } else {
38 shell_print(ctx_shell, "AICS inst %p state gain %d, mute %u, "
39 "mode %u", inst, gain, mute, mode);
40 }
41
42 }
micp_mic_dev_aics_gain_setting_cb(struct bt_aics * inst,int err,uint8_t units,int8_t minimum,int8_t maximum)43 static void micp_mic_dev_aics_gain_setting_cb(struct bt_aics *inst, int err,
44 uint8_t units, int8_t minimum,
45 int8_t maximum)
46 {
47 if (err != 0) {
48 shell_error(ctx_shell, "AICS gain settings get failed (%d) for "
49 "inst %p", err, inst);
50 } else {
51 shell_print(ctx_shell, "AICS inst %p gain settings units %u, "
52 "min %d, max %d", inst, units, minimum,
53 maximum);
54 }
55
56 }
micp_mic_dev_aics_input_type_cb(struct bt_aics * inst,int err,uint8_t input_type)57 static void micp_mic_dev_aics_input_type_cb(struct bt_aics *inst, int err,
58 uint8_t input_type)
59 {
60 if (err != 0) {
61 shell_error(ctx_shell, "AICS input type get failed (%d) for "
62 "inst %p", err, inst);
63 } else {
64 shell_print(ctx_shell, "AICS inst %p input type %u",
65 inst, input_type);
66 }
67
68 }
micp_mic_dev_aics_status_cb(struct bt_aics * inst,int err,bool active)69 static void micp_mic_dev_aics_status_cb(struct bt_aics *inst, int err,
70 bool active)
71 {
72 if (err != 0) {
73 shell_error(ctx_shell, "AICS status get failed (%d) for "
74 "inst %p", err, inst);
75 } else {
76 shell_print(ctx_shell, "AICS inst %p status %s",
77 inst, active ? "active" : "inactive");
78 }
79
80 }
micp_mic_dev_aics_description_cb(struct bt_aics * inst,int err,char * description)81 static void micp_mic_dev_aics_description_cb(struct bt_aics *inst, int err,
82 char *description)
83 {
84 if (err != 0) {
85 shell_error(ctx_shell, "AICS description get failed (%d) for "
86 "inst %p", err, inst);
87 } else {
88 shell_print(ctx_shell, "AICS inst %p description %s",
89 inst, description);
90 }
91 }
92
93 static struct bt_aics_cb aics_cb = {
94 .state = micp_mic_dev_aics_state_cb,
95 .gain_setting = micp_mic_dev_aics_gain_setting_cb,
96 .type = micp_mic_dev_aics_input_type_cb,
97 .status = micp_mic_dev_aics_status_cb,
98 .description = micp_mic_dev_aics_description_cb,
99 };
100 #endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
101
cmd_micp_mic_dev_param(const struct shell * sh,size_t argc,char ** argv)102 static int cmd_micp_mic_dev_param(const struct shell *sh, size_t argc,
103 char **argv)
104 {
105 int result;
106 struct bt_micp_mic_dev_register_param micp_param;
107
108 if (ctx_shell == NULL) {
109 ctx_shell = sh;
110 }
111
112 (void)memset(&micp_param, 0, sizeof(micp_param));
113
114 #if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
115 char input_desc[CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT][16];
116
117 for (int i = 0; i < ARRAY_SIZE(micp_param.aics_param); i++) {
118 micp_param.aics_param[i].desc_writable = true;
119 snprintf(input_desc[i], sizeof(input_desc[i]),
120 "Input %d", i + 1);
121 micp_param.aics_param[i].description = input_desc[i];
122 micp_param.aics_param[i].type = BT_AICS_INPUT_TYPE_UNSPECIFIED;
123 micp_param.aics_param[i].status = true;
124 micp_param.aics_param[i].gain_mode = BT_AICS_MODE_MANUAL;
125 micp_param.aics_param[i].units = 1;
126 micp_param.aics_param[i].min_gain = -100;
127 micp_param.aics_param[i].max_gain = 100;
128 micp_param.aics_param[i].cb = &aics_cb;
129 }
130 #endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
131
132 micp_param.cb = &micp_mic_dev_cbs;
133
134 result = bt_micp_mic_dev_register(&micp_param);
135 if (result != 0) {
136 shell_error(sh, "MICP register failed: %d", result);
137 return result;
138 }
139
140 shell_print(sh, "MICP initialized: %d", result);
141
142 #if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
143 result = bt_micp_mic_dev_included_get(&micp_included);
144 if (result != 0) {
145 shell_error(sh, "MICP get failed: %d", result);
146 }
147 #endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
148
149 return result;
150 }
151
cmd_micp_mic_dev_mute_get(const struct shell * sh,size_t argc,char ** argv)152 static int cmd_micp_mic_dev_mute_get(const struct shell *sh, size_t argc,
153 char **argv)
154 {
155 int result = bt_micp_mic_dev_mute_get();
156
157 if (result != 0) {
158 shell_error(sh, "Fail: %d", result);
159 }
160
161 return result;
162 }
163
cmd_micp_mic_dev_mute(const struct shell * sh,size_t argc,char ** argv)164 static int cmd_micp_mic_dev_mute(const struct shell *sh, size_t argc,
165 char **argv)
166 {
167 int result = bt_micp_mic_dev_mute();
168
169 if (result != 0) {
170 shell_error(sh, "Fail: %d", result);
171 }
172
173 return result;
174 }
175
cmd_micp_mic_dev_unmute(const struct shell * sh,size_t argc,char ** argv)176 static int cmd_micp_mic_dev_unmute(const struct shell *sh, size_t argc,
177 char **argv)
178 {
179 int result = bt_micp_mic_dev_unmute();
180
181 if (result != 0) {
182 shell_error(sh, "Fail: %d", result);
183 }
184
185 return result;
186 }
187
cmd_micp_mic_dev_mute_disable(const struct shell * sh,size_t argc,char ** argv)188 static int cmd_micp_mic_dev_mute_disable(const struct shell *sh, size_t argc,
189 char **argv)
190 {
191 int result = bt_micp_mic_dev_mute_disable();
192
193 if (result != 0) {
194 shell_error(sh, "Fail: %d", result);
195 }
196
197 return result;
198 }
199
200 #if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
cmd_micp_mic_dev_aics_deactivate(const struct shell * sh,size_t argc,char ** argv)201 static int cmd_micp_mic_dev_aics_deactivate(const struct shell *sh, size_t argc,
202 char **argv)
203 {
204 unsigned long index;
205 int result = 0;
206
207 index = shell_strtoul(argv[1], 0, &result);
208 if (result != 0) {
209 shell_error(sh, "Could not parse index: %d", result);
210
211 return -ENOEXEC;
212 }
213
214 if (index >= micp_included.aics_cnt) {
215 shell_error(sh, "Index shall be less than %u, was %lu",
216 micp_included.aics_cnt, index);
217
218 return -ENOEXEC;
219 }
220
221 result = bt_aics_deactivate(micp_included.aics[index]);
222 if (result != 0) {
223 shell_error(sh, "Fail: %d", result);
224 }
225
226 return result;
227 }
228
cmd_micp_mic_dev_aics_activate(const struct shell * sh,size_t argc,char ** argv)229 static int cmd_micp_mic_dev_aics_activate(const struct shell *sh, size_t argc,
230 char **argv)
231 {
232 unsigned long index;
233 int result = 0;
234
235 index = shell_strtoul(argv[1], 0, &result);
236 if (result != 0) {
237 shell_error(sh, "Could not parse index: %d", result);
238
239 return -ENOEXEC;
240 }
241
242 if (index >= micp_included.aics_cnt) {
243 shell_error(sh, "Index shall be less than %u, was %lu",
244 micp_included.aics_cnt, index);
245
246 return -ENOEXEC;
247 }
248
249 result = bt_aics_activate(micp_included.aics[index]);
250 if (result != 0) {
251 shell_error(sh, "Fail: %d", result);
252 }
253
254 return result;
255 }
256
cmd_micp_mic_dev_aics_input_state_get(const struct shell * sh,size_t argc,char ** argv)257 static int cmd_micp_mic_dev_aics_input_state_get(const struct shell *sh,
258 size_t argc, char **argv)
259 {
260 unsigned long index;
261 int result = 0;
262
263 index = shell_strtoul(argv[1], 0, &result);
264 if (result != 0) {
265 shell_error(sh, "Could not parse index: %d", result);
266
267 return -ENOEXEC;
268 }
269
270 if (index >= micp_included.aics_cnt) {
271 shell_error(sh, "Index shall be less than %u, was %lu",
272 micp_included.aics_cnt, index);
273
274 return -ENOEXEC;
275 }
276
277 result = bt_aics_state_get(micp_included.aics[index]);
278 if (result != 0) {
279 shell_error(sh, "Fail: %d", result);
280 }
281
282 return result;
283 }
284
cmd_micp_mic_dev_aics_gain_setting_get(const struct shell * sh,size_t argc,char ** argv)285 static int cmd_micp_mic_dev_aics_gain_setting_get(const struct shell *sh,
286 size_t argc, char **argv)
287 {
288 unsigned long index;
289 int result = 0;
290
291 index = shell_strtoul(argv[1], 0, &result);
292 if (result != 0) {
293 shell_error(sh, "Could not parse index: %d", result);
294
295 return -ENOEXEC;
296 }
297
298 if (index >= micp_included.aics_cnt) {
299 shell_error(sh, "Index shall be less than %u, was %lu",
300 micp_included.aics_cnt, index);
301
302 return -ENOEXEC;
303 }
304
305 result = bt_aics_gain_setting_get(micp_included.aics[index]);
306 if (result != 0) {
307 shell_error(sh, "Fail: %d", result);
308 }
309
310 return result;
311 }
312
cmd_micp_mic_dev_aics_input_type_get(const struct shell * sh,size_t argc,char ** argv)313 static int cmd_micp_mic_dev_aics_input_type_get(const struct shell *sh,
314 size_t argc, char **argv)
315 {
316 unsigned long index;
317 int result = 0;
318
319 index = shell_strtoul(argv[1], 0, &result);
320 if (result != 0) {
321 shell_error(sh, "Could not parse index: %d", result);
322
323 return -ENOEXEC;
324 }
325
326 if (index >= micp_included.aics_cnt) {
327 shell_error(sh, "Index shall be less than %u, was %lu",
328 micp_included.aics_cnt, index);
329
330 return -ENOEXEC;
331 }
332
333 result = bt_aics_type_get(micp_included.aics[index]);
334 if (result != 0) {
335 shell_error(sh, "Fail: %d", result);
336 }
337
338 return result;
339 }
340
cmd_micp_mic_dev_aics_input_status_get(const struct shell * sh,size_t argc,char ** argv)341 static int cmd_micp_mic_dev_aics_input_status_get(const struct shell *sh,
342 size_t argc, char **argv)
343 {
344 unsigned long index;
345 int result = 0;
346
347 index = shell_strtoul(argv[1], 0, &result);
348 if (result != 0) {
349 shell_error(sh, "Could not parse index: %d", result);
350
351 return -ENOEXEC;
352 }
353
354 if (index >= micp_included.aics_cnt) {
355 shell_error(sh, "Index shall be less than %u, was %lu",
356 micp_included.aics_cnt, index);
357
358 return -ENOEXEC;
359 }
360
361 result = bt_aics_status_get(micp_included.aics[index]);
362 if (result != 0) {
363 shell_error(sh, "Fail: %d", result);
364 }
365
366 return result;
367 }
368
cmd_micp_mic_dev_aics_input_unmute(const struct shell * sh,size_t argc,char ** argv)369 static int cmd_micp_mic_dev_aics_input_unmute(const struct shell *sh,
370 size_t argc, char **argv)
371 {
372 unsigned long index;
373 int result = 0;
374
375 index = shell_strtoul(argv[1], 0, &result);
376 if (result != 0) {
377 shell_error(sh, "Could not parse index: %d", result);
378
379 return -ENOEXEC;
380 }
381
382 if (index >= micp_included.aics_cnt) {
383 shell_error(sh, "Index shall be less than %u, was %lu",
384 micp_included.aics_cnt, index);
385
386 return -ENOEXEC;
387 }
388
389 result = bt_aics_unmute(micp_included.aics[index]);
390 if (result != 0) {
391 shell_error(sh, "Fail: %d", result);
392 }
393
394 return result;
395 }
396
cmd_micp_mic_dev_aics_input_mute(const struct shell * sh,size_t argc,char ** argv)397 static int cmd_micp_mic_dev_aics_input_mute(const struct shell *sh, size_t argc,
398 char **argv)
399 {
400 unsigned long index;
401 int result = 0;
402
403 index = shell_strtoul(argv[1], 0, &result);
404 if (result != 0) {
405 shell_error(sh, "Could not parse index: %d", result);
406
407 return -ENOEXEC;
408 }
409
410 if (index >= micp_included.aics_cnt) {
411 shell_error(sh, "Index shall be less than %u, was %lu",
412 micp_included.aics_cnt, index);
413
414 return -ENOEXEC;
415 }
416
417 result = bt_aics_mute(micp_included.aics[index]);
418 if (result != 0) {
419 shell_error(sh, "Fail: %d", result);
420 }
421
422 return result;
423 }
424
cmd_micp_mic_dev_aics_manual_input_gain_set(const struct shell * sh,size_t argc,char ** argv)425 static int cmd_micp_mic_dev_aics_manual_input_gain_set(const struct shell *sh,
426 size_t argc, char **argv)
427 {
428 unsigned long index;
429 int result = 0;
430
431 index = shell_strtoul(argv[1], 0, &result);
432 if (result != 0) {
433 shell_error(sh, "Could not parse index: %d", result);
434
435 return -ENOEXEC;
436 }
437
438 if (index >= micp_included.aics_cnt) {
439 shell_error(sh, "Index shall be less than %u, was %lu",
440 micp_included.aics_cnt, index);
441
442 return -ENOEXEC;
443 }
444
445 result = bt_aics_manual_gain_set(micp_included.aics[index]);
446 if (result != 0) {
447 shell_error(sh, "Fail: %d", result);
448 }
449
450 return result;
451 }
452
cmd_micp_mic_dev_aics_automatic_input_gain_set(const struct shell * sh,size_t argc,char ** argv)453 static int cmd_micp_mic_dev_aics_automatic_input_gain_set(const struct shell *sh,
454 size_t argc,
455 char **argv)
456 {
457 unsigned long index;
458 int result = 0;
459
460 index = shell_strtoul(argv[1], 0, &result);
461 if (result != 0) {
462 shell_error(sh, "Could not parse index: %d", result);
463
464 return -ENOEXEC;
465 }
466
467 if (index >= micp_included.aics_cnt) {
468 shell_error(sh, "Index shall be less than %u, was %lu",
469 micp_included.aics_cnt, index);
470
471 return -ENOEXEC;
472 }
473
474 result = bt_aics_automatic_gain_set(micp_included.aics[index]);
475 if (result != 0) {
476 shell_error(sh, "Fail: %d", result);
477 }
478
479 return result;
480 }
481
cmd_micp_mic_dev_aics_gain_set(const struct shell * sh,size_t argc,char ** argv)482 static int cmd_micp_mic_dev_aics_gain_set(const struct shell *sh, size_t argc,
483 char **argv)
484 {
485 unsigned long index;
486 int result = 0;
487 long gain;
488
489 index = shell_strtoul(argv[1], 0, &result);
490 if (result != 0) {
491 shell_error(sh, "Could not parse index: %d", result);
492
493 return -ENOEXEC;
494 }
495
496 if (index >= micp_included.aics_cnt) {
497 shell_error(sh, "Index shall be less than %u, was %lu",
498 micp_included.aics_cnt, index);
499
500 return -ENOEXEC;
501 }
502
503 if (index >= micp_included.aics_cnt) {
504 shell_error(sh, "Index shall be less than %u, was %lu",
505 micp_included.aics_cnt, index);
506
507 return -ENOEXEC;
508 }
509
510 gain = shell_strtol(argv[2], 0, &result);
511 if (result != 0) {
512 shell_error(sh, "Could not parse gain: %d", result);
513
514 return -ENOEXEC;
515 }
516
517 if (!IN_RANGE(gain, INT8_MIN, INT8_MAX)) {
518 shell_error(sh, "Gain shall be %d-%d, was %ld",
519 INT8_MIN, INT8_MAX, gain);
520
521 return -ENOEXEC;
522 }
523
524 result = bt_aics_gain_set(micp_included.aics[index], gain);
525 if (result != 0) {
526 shell_error(sh, "Fail: %d", result);
527 }
528
529 return result;
530 }
531
cmd_micp_mic_dev_aics_input_description_get(const struct shell * sh,size_t argc,char ** argv)532 static int cmd_micp_mic_dev_aics_input_description_get(const struct shell *sh,
533 size_t argc, char **argv)
534 {
535 unsigned long index;
536 int result = 0;
537
538 index = shell_strtoul(argv[1], 0, &result);
539 if (result != 0) {
540 shell_error(sh, "Could not parse index: %d", result);
541
542 return -ENOEXEC;
543 }
544
545 if (index >= micp_included.aics_cnt) {
546 shell_error(sh, "Index shall be less than %u, was %lu",
547 micp_included.aics_cnt, index);
548
549 return -ENOEXEC;
550 }
551
552 result = bt_aics_description_get(micp_included.aics[index]);
553 if (result != 0) {
554 shell_error(sh, "Fail: %d", result);
555 }
556
557 return result;
558 }
559
cmd_micp_mic_dev_aics_input_description_set(const struct shell * sh,size_t argc,char ** argv)560 static int cmd_micp_mic_dev_aics_input_description_set(const struct shell *sh,
561 size_t argc, char **argv)
562 {
563 unsigned long index;
564 int result = 0;
565
566 index = shell_strtoul(argv[1], 0, &result);
567 if (result != 0) {
568 shell_error(sh, "Could not parse index: %d", result);
569
570 return -ENOEXEC;
571 }
572
573 if (index >= micp_included.aics_cnt) {
574 shell_error(sh, "Index shall be less than %u, was %lu",
575 micp_included.aics_cnt, index);
576
577 return -ENOEXEC;
578 }
579
580 result = bt_aics_description_set(micp_included.aics[index], argv[2]);
581 if (result != 0) {
582 shell_error(sh, "Fail: %d", result);
583 }
584
585 return result;
586 }
587 #endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
588
cmd_micp_mic_dev(const struct shell * sh,size_t argc,char ** argv)589 static int cmd_micp_mic_dev(const struct shell *sh, size_t argc, char **argv)
590 {
591 if (argc > 1) {
592 shell_error(sh, "%s unknown parameter: %s",
593 argv[0], argv[1]);
594 } else {
595 shell_error(sh, "%s Missing subcommand", argv[0]);
596 }
597
598 return -ENOEXEC;
599 }
600
601 SHELL_STATIC_SUBCMD_SET_CREATE(micp_mic_dev_cmds,
602 SHELL_CMD_ARG(init, NULL,
603 "Initialize the service and register callbacks",
604 cmd_micp_mic_dev_param, 1, 0),
605 SHELL_CMD_ARG(mute_get, NULL,
606 "Get the mute state",
607 cmd_micp_mic_dev_mute_get, 1, 0),
608 SHELL_CMD_ARG(mute, NULL,
609 "Mute the MICP server",
610 cmd_micp_mic_dev_mute, 1, 0),
611 SHELL_CMD_ARG(unmute, NULL,
612 "Unmute the MICP server",
613 cmd_micp_mic_dev_unmute, 1, 0),
614 SHELL_CMD_ARG(mute_disable, NULL,
615 "Disable the MICP mute",
616 cmd_micp_mic_dev_mute_disable, 1, 0),
617 #if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
618 SHELL_CMD_ARG(aics_deactivate, NULL,
619 "Deactivates a AICS instance <inst_index>",
620 cmd_micp_mic_dev_aics_deactivate, 2, 0),
621 SHELL_CMD_ARG(aics_activate, NULL,
622 "Activates a AICS instance <inst_index>",
623 cmd_micp_mic_dev_aics_activate, 2, 0),
624 SHELL_CMD_ARG(aics_input_state_get, NULL,
625 "Get the input state of a AICS instance <inst_index>",
626 cmd_micp_mic_dev_aics_input_state_get, 2, 0),
627 SHELL_CMD_ARG(aics_gain_setting_get, NULL,
628 "Get the gain settings of a AICS instance <inst_index>",
629 cmd_micp_mic_dev_aics_gain_setting_get, 2, 0),
630 SHELL_CMD_ARG(aics_input_type_get, NULL,
631 "Get the input type of a AICS instance <inst_index>",
632 cmd_micp_mic_dev_aics_input_type_get, 2, 0),
633 SHELL_CMD_ARG(aics_input_status_get, NULL,
634 "Get the input status of a AICS instance <inst_index>",
635 cmd_micp_mic_dev_aics_input_status_get, 2, 0),
636 SHELL_CMD_ARG(aics_input_unmute, NULL,
637 "Unmute the input of a AICS instance <inst_index>",
638 cmd_micp_mic_dev_aics_input_unmute, 2, 0),
639 SHELL_CMD_ARG(aics_input_mute, NULL,
640 "Mute the input of a AICS instance <inst_index>",
641 cmd_micp_mic_dev_aics_input_mute, 2, 0),
642 SHELL_CMD_ARG(aics_manual_input_gain_set, NULL,
643 "Set the gain mode of a AICS instance to manual "
644 "<inst_index>",
645 cmd_micp_mic_dev_aics_manual_input_gain_set, 2, 0),
646 SHELL_CMD_ARG(aics_automatic_input_gain_set, NULL,
647 "Set the gain mode of a AICS instance to automatic "
648 "<inst_index>",
649 cmd_micp_mic_dev_aics_automatic_input_gain_set, 2, 0),
650 SHELL_CMD_ARG(aics_gain_set, NULL,
651 "Set the gain in dB of a AICS instance <inst_index> "
652 "<gain (-128 to 127)>",
653 cmd_micp_mic_dev_aics_gain_set, 3, 0),
654 SHELL_CMD_ARG(aics_input_description_get, NULL,
655 "Get the input description of a AICS instance "
656 "<inst_index>",
657 cmd_micp_mic_dev_aics_input_description_get, 2, 0),
658 SHELL_CMD_ARG(aics_input_description_set, NULL,
659 "Set the input description of a AICS instance "
660 "<inst_index> <description>",
661 cmd_micp_mic_dev_aics_input_description_set, 3, 0),
662 #endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
663 SHELL_SUBCMD_SET_END
664 );
665
666 SHELL_CMD_ARG_REGISTER(micp_mic_dev, &micp_mic_dev_cmds,
667 "Bluetooth MICP Microphone Device shell commands", cmd_micp_mic_dev, 1, 1);
668