1 /** @file
2 * @brief Bluetooth VCP server 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 <errno.h>
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <string.h>
16
17 #include <zephyr/autoconf.h>
18 #include <zephyr/bluetooth/audio/aics.h>
19 #include <zephyr/bluetooth/audio/vocs.h>
20 #include <zephyr/bluetooth/conn.h>
21 #include <zephyr/bluetooth/audio/vcp.h>
22 #include <zephyr/shell/shell.h>
23 #include <zephyr/shell/shell_string_conv.h>
24 #include <zephyr/sys/util.h>
25 #include <zephyr/sys/util_macro.h>
26
27 #include "host/shell/bt.h"
28
29 static struct bt_vcp_included vcp_included;
30
vcp_vol_rend_state_cb(struct bt_conn * conn,int err,uint8_t volume,uint8_t mute)31 static void vcp_vol_rend_state_cb(struct bt_conn *conn, int err, uint8_t volume, uint8_t mute)
32 {
33 if (err) {
34 shell_error(ctx_shell, "VCP state get failed (%d)", err);
35 } else {
36 shell_print(ctx_shell, "VCP volume %u, mute %u", volume, mute);
37 }
38 }
39
vcp_vol_rend_flags_cb(struct bt_conn * conn,int err,uint8_t flags)40 static void vcp_vol_rend_flags_cb(struct bt_conn *conn, int err, uint8_t flags)
41 {
42 if (err) {
43 shell_error(ctx_shell, "VCP flags get failed (%d)", err);
44 } else {
45 shell_print(ctx_shell, "VCP flags 0x%02X", flags);
46 }
47 }
48
aics_state_cb(struct bt_aics * inst,int err,int8_t gain,uint8_t mute,uint8_t mode)49 static void aics_state_cb(struct bt_aics *inst, int err, int8_t gain,
50 uint8_t mute, uint8_t mode)
51 {
52 if (err) {
53 shell_error(ctx_shell,
54 "AICS state get failed (%d) for inst %p",
55 err, inst);
56 } else {
57 shell_print(ctx_shell,
58 "AICS inst %p state gain %d, mute %u, mode %u",
59 inst, gain, mute, mode);
60 }
61 }
62
aics_gain_setting_cb(struct bt_aics * inst,int err,uint8_t units,int8_t minimum,int8_t maximum)63 static void aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
64 int8_t minimum, int8_t maximum)
65 {
66 if (err) {
67 shell_error(ctx_shell,
68 "AICS gain settings get failed (%d) for inst %p",
69 err, inst);
70 } else {
71 shell_print(ctx_shell,
72 "AICS inst %p gain settings units %u, min %d, max %d",
73 inst, units, minimum, maximum);
74 }
75 }
76
aics_input_type_cb(struct bt_aics * inst,int err,uint8_t input_type)77 static void aics_input_type_cb(struct bt_aics *inst, int err,
78 uint8_t input_type)
79 {
80 if (err) {
81 shell_error(ctx_shell,
82 "AICS input type get failed (%d) for inst %p",
83 err, inst);
84 } else {
85 shell_print(ctx_shell, "AICS inst %p input type %u",
86 inst, input_type);
87 }
88 }
89
aics_status_cb(struct bt_aics * inst,int err,bool active)90 static void aics_status_cb(struct bt_aics *inst, int err, bool active)
91 {
92 if (err) {
93 shell_error(ctx_shell,
94 "AICS status get failed (%d) for inst %p",
95 err, inst);
96 } else {
97 shell_print(ctx_shell, "AICS inst %p status %s",
98 inst, active ? "active" : "inactive");
99 }
100
101 }
102
aics_description_cb(struct bt_aics * inst,int err,char * description)103 static void aics_description_cb(struct bt_aics *inst, int err,
104 char *description)
105 {
106 if (err) {
107 shell_error(ctx_shell,
108 "AICS description get failed (%d) for inst %p",
109 err, inst);
110 } else {
111 shell_print(ctx_shell, "AICS inst %p description %s",
112 inst, description);
113 }
114 }
115
vocs_state_cb(struct bt_vocs * inst,int err,int16_t offset)116 static void vocs_state_cb(struct bt_vocs *inst, int err, int16_t offset)
117 {
118 if (err) {
119 shell_error(ctx_shell, "VOCS state get failed (%d) for inst %p",
120 err, inst);
121 } else {
122 shell_print(ctx_shell, "VOCS inst %p offset %d", inst, offset);
123 }
124 }
125
vocs_location_cb(struct bt_vocs * inst,int err,uint32_t location)126 static void vocs_location_cb(struct bt_vocs *inst, int err, uint32_t location)
127 {
128 if (err) {
129 shell_error(ctx_shell,
130 "VOCS location get failed (%d) for inst %p",
131 err, inst);
132 } else {
133 shell_print(ctx_shell, "VOCS inst %p location %u",
134 inst, location);
135 }
136 }
137
vocs_description_cb(struct bt_vocs * inst,int err,char * description)138 static void vocs_description_cb(struct bt_vocs *inst, int err,
139 char *description)
140 {
141 if (err) {
142 shell_error(ctx_shell,
143 "VOCS description get failed (%d) for inst %p",
144 err, inst);
145 } else {
146 shell_print(ctx_shell, "VOCS inst %p description %s",
147 inst, description);
148 }
149 }
150
151 static struct bt_vcp_vol_rend_cb vcp_vol_rend_cbs = {
152 .state = vcp_vol_rend_state_cb,
153 .flags = vcp_vol_rend_flags_cb,
154 };
155
156 static struct bt_aics_cb aics_cbs = {
157 .state = aics_state_cb,
158 .gain_setting = aics_gain_setting_cb,
159 .type = aics_input_type_cb,
160 .status = aics_status_cb,
161 .description = aics_description_cb
162 };
163
164 static struct bt_vocs_cb vocs_cbs = {
165 .state = vocs_state_cb,
166 .location = vocs_location_cb,
167 .description = vocs_description_cb
168 };
169
cmd_vcp_vol_rend_init(const struct shell * sh,size_t argc,char ** argv)170 static int cmd_vcp_vol_rend_init(const struct shell *sh, size_t argc,
171 char **argv)
172 {
173 int result = 0;
174 struct bt_vcp_vol_rend_register_param vcp_register_param;
175 char input_desc[CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT][16];
176 char output_desc[CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT][16];
177 static const char assignment_operator[] = "=";
178
179 if (!ctx_shell) {
180 ctx_shell = sh;
181 }
182
183 memset(&vcp_register_param, 0, sizeof(vcp_register_param));
184
185 if (IS_ENABLED(CONFIG_BT_VCP_VOL_REND_VOCS)) {
186 for (int i = 0; i < ARRAY_SIZE(vcp_register_param.vocs_param); i++) {
187 vcp_register_param.vocs_param[i].location_writable = true;
188 vcp_register_param.vocs_param[i].desc_writable = true;
189 snprintf(output_desc[i], sizeof(output_desc[i]),
190 "Output %d", i + 1);
191 vcp_register_param.vocs_param[i].output_desc = output_desc[i];
192 vcp_register_param.vocs_param[i].cb = &vocs_cbs;
193 }
194 }
195
196 if (IS_ENABLED(CONFIG_BT_VCP_VOL_REND_AICS)) {
197 for (int i = 0; i < ARRAY_SIZE(vcp_register_param.aics_param); i++) {
198 vcp_register_param.aics_param[i].desc_writable = true;
199 snprintf(input_desc[i], sizeof(input_desc[i]),
200 "Input %d", i + 1);
201 vcp_register_param.aics_param[i].description = input_desc[i];
202 vcp_register_param.aics_param[i].type = BT_AICS_INPUT_TYPE_UNSPECIFIED;
203 vcp_register_param.aics_param[i].status = true;
204 vcp_register_param.aics_param[i].gain_mode = BT_AICS_MODE_MANUAL;
205 vcp_register_param.aics_param[i].units = 1;
206 vcp_register_param.aics_param[i].min_gain = -100;
207 vcp_register_param.aics_param[i].max_gain = 100;
208 vcp_register_param.aics_param[i].cb = &aics_cbs;
209 }
210 }
211
212 /* Default values */
213 vcp_register_param.step = 1;
214 vcp_register_param.mute = BT_VCP_STATE_UNMUTED;
215 vcp_register_param.volume = 100;
216
217 for (int i = 1; i < argc; i++) {
218 const char *operator = strstr(argv[i], assignment_operator);
219 const char *kwarg = operator ? operator + 1 : NULL;
220
221 if (kwarg) {
222 if (!strncmp(argv[i], "step", 4)) {
223 vcp_register_param.step = shell_strtoul(kwarg, 10, &result);
224 } else if (!strncmp(argv[i], "mute", 4)) {
225 vcp_register_param.mute = shell_strtobool(kwarg, 10, &result);
226 } else if (!strncmp(argv[i], "volume", 6)) {
227 vcp_register_param.volume = shell_strtoul(kwarg, 10, &result);
228 } else {
229 shell_help(sh);
230 return SHELL_CMD_HELP_PRINTED;
231 }
232 } else {
233 shell_help(sh);
234 return SHELL_CMD_HELP_PRINTED;
235 }
236
237 if (result != 0) {
238 shell_help(sh);
239 return SHELL_CMD_HELP_PRINTED;
240 }
241 }
242
243 vcp_register_param.cb = &vcp_vol_rend_cbs;
244
245 result = bt_vcp_vol_rend_register(&vcp_register_param);
246 if (result) {
247 shell_print(sh, "Fail: %d", result);
248 return result;
249 }
250
251 result = bt_vcp_vol_rend_included_get(&vcp_included);
252 if (result != 0) {
253 shell_error(sh, "Failed to get included services: %d", result);
254 return result;
255 }
256
257 return result;
258 }
259
cmd_vcp_vol_rend_volume_step(const struct shell * sh,size_t argc,char ** argv)260 static int cmd_vcp_vol_rend_volume_step(const struct shell *sh, size_t argc,
261 char **argv)
262 {
263 unsigned long step;
264 int result = 0;
265
266 step = shell_strtoul(argv[1], 0, &result);
267 if (result != 0) {
268 shell_error(sh, "Failed to parse step: %d", result);
269
270 return -ENOEXEC;
271 }
272
273 if (!IN_RANGE(step, 1, UINT8_MAX)) {
274 shell_error(sh, "Invalid step %lu", step);
275
276 return -ENOEXEC;
277 }
278
279 result = bt_vcp_vol_rend_set_step(step);
280 if (result) {
281 shell_print(sh, "Fail: %d", result);
282 }
283
284 return result;
285 }
286
cmd_vcp_vol_rend_state_get(const struct shell * sh,size_t argc,char ** argv)287 static int cmd_vcp_vol_rend_state_get(const struct shell *sh, size_t argc,
288 char **argv)
289 {
290 int result = bt_vcp_vol_rend_get_state();
291
292 if (result) {
293 shell_print(sh, "Fail: %d", result);
294 }
295
296 return result;
297 }
298
cmd_vcp_vol_rend_flags_get(const struct shell * sh,size_t argc,char ** argv)299 static int cmd_vcp_vol_rend_flags_get(const struct shell *sh, size_t argc,
300 char **argv)
301 {
302 int result = bt_vcp_vol_rend_get_flags();
303
304 if (result) {
305 shell_print(sh, "Fail: %d", result);
306 }
307
308 return result;
309 }
310
cmd_vcp_vol_rend_volume_down(const struct shell * sh,size_t argc,char ** argv)311 static int cmd_vcp_vol_rend_volume_down(const struct shell *sh, size_t argc,
312 char **argv)
313 {
314 int result = bt_vcp_vol_rend_vol_down();
315
316 if (result) {
317 shell_print(sh, "Fail: %d", result);
318 }
319
320 return result;
321 }
322
cmd_vcp_vol_rend_volume_up(const struct shell * sh,size_t argc,char ** argv)323 static int cmd_vcp_vol_rend_volume_up(const struct shell *sh, size_t argc,
324 char **argv)
325
326 {
327 int result = bt_vcp_vol_rend_vol_up();
328
329 if (result) {
330 shell_print(sh, "Fail: %d", result);
331 }
332
333 return result;
334 }
335
cmd_vcp_vol_rend_unmute_volume_down(const struct shell * sh,size_t argc,char ** argv)336 static int cmd_vcp_vol_rend_unmute_volume_down(const struct shell *sh,
337 size_t argc, char **argv)
338 {
339 int result = bt_vcp_vol_rend_unmute_vol_down();
340
341 if (result) {
342 shell_print(sh, "Fail: %d", result);
343 }
344
345 return result;
346 }
347
cmd_vcp_vol_rend_unmute_volume_up(const struct shell * sh,size_t argc,char ** argv)348 static int cmd_vcp_vol_rend_unmute_volume_up(const struct shell *sh,
349 size_t argc, char **argv)
350 {
351 int result = bt_vcp_vol_rend_unmute_vol_up();
352
353 if (result) {
354 shell_print(sh, "Fail: %d", result);
355 }
356
357 return result;
358 }
359
cmd_vcp_vol_rend_volume_set(const struct shell * sh,size_t argc,char ** argv)360 static int cmd_vcp_vol_rend_volume_set(const struct shell *sh, size_t argc,
361 char **argv)
362
363 {
364 unsigned long volume;
365 int result = 0;
366
367 volume = shell_strtoul(argv[1], 0, &result);
368 if (result != 0) {
369 shell_error(sh, "Failed to parse volume: %d", result);
370
371 return -ENOEXEC;
372 }
373
374 if (volume > UINT8_MAX) {
375 shell_error(sh, "Invalid volume %lu", volume);
376
377 return -ENOEXEC;
378 }
379
380 result = bt_vcp_vol_rend_set_vol(volume);
381 if (result) {
382 shell_print(sh, "Fail: %d", result);
383 }
384
385 return result;
386 }
387
cmd_vcp_vol_rend_unmute(const struct shell * sh,size_t argc,char ** argv)388 static int cmd_vcp_vol_rend_unmute(const struct shell *sh, size_t argc,
389 char **argv)
390 {
391 int result = bt_vcp_vol_rend_unmute();
392
393 if (result) {
394 shell_print(sh, "Fail: %d", result);
395 }
396
397 return result;
398 }
399
cmd_vcp_vol_rend_mute(const struct shell * sh,size_t argc,char ** argv)400 static int cmd_vcp_vol_rend_mute(const struct shell *sh, size_t argc,
401 char **argv)
402 {
403 int result = bt_vcp_vol_rend_mute();
404
405 if (result) {
406 shell_print(sh, "Fail: %d", result);
407 }
408
409 return result;
410 }
411
412 #if defined(CONFIG_BT_VCP_VOL_REND_VOCS)
cmd_vcp_vol_rend_vocs_state_get(const struct shell * sh,size_t argc,char ** argv)413 static int cmd_vcp_vol_rend_vocs_state_get(const struct shell *sh, size_t argc,
414 char **argv)
415 {
416 unsigned long index;
417 int result = 0;
418
419 index = shell_strtoul(argv[1], 0, &result);
420 if (result != 0) {
421 shell_error(sh, "Failed to parse index: %d", result);
422
423 return -ENOEXEC;
424 }
425
426 if (index > vcp_included.vocs_cnt) {
427 shell_error(sh, "Invalid index %lu", index);
428
429 return -ENOEXEC;
430 }
431
432 result = bt_vocs_state_get(vcp_included.vocs[index]);
433 if (result) {
434 shell_print(sh, "Fail: %d", result);
435 }
436
437 return result;
438 }
439
cmd_vcp_vol_rend_vocs_location_get(const struct shell * sh,size_t argc,char ** argv)440 static int cmd_vcp_vol_rend_vocs_location_get(const struct shell *sh,
441 size_t argc, char **argv)
442 {
443 unsigned long index;
444 int result = 0;
445
446 index = shell_strtoul(argv[1], 0, &result);
447 if (result != 0) {
448 shell_error(sh, "Failed to parse index: %d", result);
449
450 return -ENOEXEC;
451 }
452
453 if (index > vcp_included.vocs_cnt) {
454 shell_error(sh, "Invalid index %lu", index);
455
456 return -ENOEXEC;
457 }
458
459 result = bt_vocs_location_get(vcp_included.vocs[index]);
460 if (result) {
461 shell_print(sh, "Fail: %d", result);
462 }
463
464 return result;
465 }
466
cmd_vcp_vol_rend_vocs_location_set(const struct shell * sh,size_t argc,char ** argv)467 static int cmd_vcp_vol_rend_vocs_location_set(const struct shell *sh,
468 size_t argc, char **argv)
469 {
470 unsigned long location;
471 unsigned long index;
472 int result = 0;
473
474 if (default_conn == NULL) {
475 shell_error(sh, "Not connected");
476 return -ENOEXEC;
477 }
478
479 index = shell_strtoul(argv[1], 0, &result);
480 if (result != 0) {
481 shell_error(sh, "Failed to parse index: %d", result);
482
483 return -ENOEXEC;
484 }
485
486 if (index >= vcp_included.vocs_cnt) {
487 shell_error(sh, "Index shall be less than %u, was %lu",
488 vcp_included.vocs_cnt, index);
489
490 return -ENOEXEC;
491 }
492
493 location = shell_strtoul(argv[2], 0, &result);
494 if (result != 0) {
495 shell_error(sh, "Failed to parse location: %d", result);
496
497 return -ENOEXEC;
498 }
499
500 if (location > UINT32_MAX) {
501 shell_error(sh, "Invalid location %lu", location);
502
503 return -ENOEXEC;
504 }
505
506 result = bt_vocs_location_set(vcp_included.vocs[index], location);
507 if (result) {
508 shell_print(sh, "Fail: %d", result);
509 }
510
511 return result;
512 }
513
cmd_vcp_vol_rend_vocs_offset_set(const struct shell * sh,size_t argc,char ** argv)514 static int cmd_vcp_vol_rend_vocs_offset_set(const struct shell *sh, size_t argc,
515 char **argv)
516 {
517 unsigned long index;
518 int result = 0;
519 long offset;
520
521 if (default_conn == NULL) {
522 shell_error(sh, "Not connected");
523 return -ENOEXEC;
524 }
525
526 index = shell_strtoul(argv[1], 0, &result);
527 if (result != 0) {
528 shell_error(sh, "Failed to parse index: %d", result);
529
530 return -ENOEXEC;
531 }
532
533 if (index >= vcp_included.vocs_cnt) {
534 shell_error(sh, "Index shall be less than %u, was %lu",
535 vcp_included.vocs_cnt, index);
536
537 return -ENOEXEC;
538 }
539
540 offset = shell_strtol(argv[2], 0, &result);
541 if (result != 0) {
542 shell_error(sh, "Failed to parse offset: %d", result);
543
544 return -ENOEXEC;
545 }
546
547 if (offset > BT_VOCS_MAX_OFFSET || offset < BT_VOCS_MIN_OFFSET) {
548 shell_error(sh, "Offset shall be %d-%d, was %ld",
549 BT_VOCS_MIN_OFFSET, BT_VOCS_MAX_OFFSET, offset);
550 return -ENOEXEC;
551 }
552
553 result = bt_vocs_state_set(vcp_included.vocs[index], offset);
554 if (result) {
555 shell_print(sh, "Fail: %d", result);
556 }
557
558 return result;
559 }
560
cmd_vcp_vol_rend_vocs_output_description_get(const struct shell * sh,size_t argc,char ** argv)561 static int cmd_vcp_vol_rend_vocs_output_description_get(const struct shell *sh,
562 size_t argc,
563 char **argv)
564 {
565 unsigned long index;
566 int result = 0;
567
568 index = shell_strtoul(argv[1], 0, &result);
569 if (result != 0) {
570 shell_error(sh, "Failed to parse index: %d", result);
571
572 return -ENOEXEC;
573 }
574
575 if (index > vcp_included.vocs_cnt) {
576 shell_error(sh, "Invalid index %lu", index);
577
578 return -ENOEXEC;
579 }
580
581 result = bt_vocs_description_get(vcp_included.vocs[index]);
582 if (result) {
583 shell_print(sh, "Fail: %d", result);
584 }
585
586 return result;
587 }
588
cmd_vcp_vol_rend_vocs_output_description_set(const struct shell * sh,size_t argc,char ** argv)589 static int cmd_vcp_vol_rend_vocs_output_description_set(const struct shell *sh,
590 size_t argc,
591 char **argv)
592 {
593 unsigned long index;
594 int result = 0;
595
596 index = shell_strtoul(argv[1], 0, &result);
597 if (result != 0) {
598 shell_error(sh, "Failed to parse index: %d", result);
599
600 return -ENOEXEC;
601 }
602
603 if (index > vcp_included.vocs_cnt) {
604 shell_error(sh, "Invalid index %lu", index);
605
606 return -ENOEXEC;
607 }
608
609 result = bt_vocs_description_set(vcp_included.vocs[index], argv[2]);
610 if (result) {
611 shell_print(sh, "Fail: %d", result);
612 }
613
614 return result;
615 }
616 #endif /* CONFIG_BT_VCP_VOL_REND_VOCS */
617
618 #if defined(CONFIG_BT_VCP_VOL_REND_AICS)
cmd_vcp_vol_rend_aics_input_state_get(const struct shell * sh,size_t argc,char ** argv)619 static int cmd_vcp_vol_rend_aics_input_state_get(const struct shell *sh,
620 size_t argc, char **argv)
621 {
622 unsigned long index;
623 int result = 0;
624
625 index = shell_strtoul(argv[1], 0, &result);
626 if (result != 0) {
627 shell_error(sh, "Failed to parse index: %d", result);
628
629 return -ENOEXEC;
630 }
631
632 if (index > vcp_included.aics_cnt) {
633 shell_error(sh, "Invalid index %lu", index);
634
635 return -ENOEXEC;
636 }
637
638 result = bt_aics_state_get(vcp_included.aics[index]);
639 if (result) {
640 shell_print(sh, "Fail: %d", result);
641 }
642
643 return result;
644 }
645
cmd_vcp_vol_rend_aics_gain_setting_get(const struct shell * sh,size_t argc,char ** argv)646 static int cmd_vcp_vol_rend_aics_gain_setting_get(const struct shell *sh,
647 size_t argc, char **argv)
648 {
649 unsigned long index;
650 int result = 0;
651
652 index = shell_strtoul(argv[1], 0, &result);
653 if (result != 0) {
654 shell_error(sh, "Failed to parse index: %d", result);
655
656 return -ENOEXEC;
657 }
658
659 if (index > vcp_included.aics_cnt) {
660 shell_error(sh, "Invalid index %lu", index);
661
662 return -ENOEXEC;
663 }
664
665 result = bt_aics_gain_setting_get(vcp_included.aics[index]);
666 if (result) {
667 shell_print(sh, "Fail: %d", result);
668 }
669
670 return result;
671 }
672
cmd_vcp_vol_rend_aics_input_type_get(const struct shell * sh,size_t argc,char ** argv)673 static int cmd_vcp_vol_rend_aics_input_type_get(const struct shell *sh,
674 size_t argc, char **argv)
675 {
676 unsigned long index;
677 int result = 0;
678
679 index = shell_strtoul(argv[1], 0, &result);
680 if (result != 0) {
681 shell_error(sh, "Failed to parse index: %d", result);
682
683 return -ENOEXEC;
684 }
685
686 if (index > vcp_included.aics_cnt) {
687 shell_error(sh, "Invalid index %lu", index);
688
689 return -ENOEXEC;
690 }
691
692 result = bt_aics_type_get(vcp_included.aics[index]);
693 if (result) {
694 shell_print(sh, "Fail: %d", result);
695 }
696
697 return result;
698 }
699
cmd_vcp_vol_rend_aics_input_status_get(const struct shell * sh,size_t argc,char ** argv)700 static int cmd_vcp_vol_rend_aics_input_status_get(const struct shell *sh,
701 size_t argc, char **argv)
702 {
703 unsigned long index;
704 int result = 0;
705
706 index = shell_strtoul(argv[1], 0, &result);
707 if (result != 0) {
708 shell_error(sh, "Failed to parse index: %d", result);
709
710 return -ENOEXEC;
711 }
712
713 if (index > vcp_included.aics_cnt) {
714 shell_error(sh, "Invalid index %lu", index);
715
716 return -ENOEXEC;
717 }
718
719 result = bt_aics_status_get(vcp_included.aics[index]);
720 if (result) {
721 shell_print(sh, "Fail: %d", result);
722 }
723
724 return result;
725 }
726
cmd_vcp_vol_rend_aics_input_unmute(const struct shell * sh,size_t argc,char ** argv)727 static int cmd_vcp_vol_rend_aics_input_unmute(const struct shell *sh,
728 size_t argc, char **argv)
729 {
730 unsigned long index;
731 int result = 0;
732
733 index = shell_strtoul(argv[1], 0, &result);
734 if (result != 0) {
735 shell_error(sh, "Failed to parse index: %d", result);
736
737 return -ENOEXEC;
738 }
739
740 if (index > vcp_included.aics_cnt) {
741 shell_error(sh, "Invalid index %lu", index);
742
743 return -ENOEXEC;
744 }
745
746 result = bt_aics_unmute(vcp_included.aics[index]);
747 if (result) {
748 shell_print(sh, "Fail: %d", result);
749 }
750
751 return result;
752 }
753
cmd_vcp_vol_rend_aics_input_mute(const struct shell * sh,size_t argc,char ** argv)754 static int cmd_vcp_vol_rend_aics_input_mute(const struct shell *sh, size_t argc,
755 char **argv)
756 {
757 unsigned long index;
758 int result = 0;
759
760 index = shell_strtoul(argv[1], 0, &result);
761 if (result != 0) {
762 shell_error(sh, "Failed to parse index: %d", result);
763
764 return -ENOEXEC;
765 }
766
767 if (index > vcp_included.aics_cnt) {
768 shell_error(sh, "Invalid index %lu", index);
769
770 return -ENOEXEC;
771 }
772
773 result = bt_aics_mute(vcp_included.aics[index]);
774 if (result) {
775 shell_print(sh, "Fail: %d", result);
776 }
777
778 return result;
779 }
780
cmd_vcp_vol_rend_aics_manual_input_gain_set(const struct shell * sh,size_t argc,char ** argv)781 static int cmd_vcp_vol_rend_aics_manual_input_gain_set(const struct shell *sh,
782 size_t argc,
783 char **argv)
784 {
785 unsigned long index;
786 int result = 0;
787
788 index = shell_strtoul(argv[1], 0, &result);
789 if (result != 0) {
790 shell_error(sh, "Failed to parse index: %d", result);
791
792 return -ENOEXEC;
793 }
794
795 if (index > vcp_included.aics_cnt) {
796 shell_error(sh, "Invalid index %lu", index);
797
798 return -ENOEXEC;
799 }
800
801 result = bt_aics_manual_gain_set(vcp_included.aics[index]);
802 if (result) {
803 shell_print(sh, "Fail: %d", result);
804 }
805
806 return result;
807 }
808
cmd_vcp_vol_rend_aics_auto_input_gain_set(const struct shell * sh,size_t argc,char ** argv)809 static int cmd_vcp_vol_rend_aics_auto_input_gain_set(const struct shell *sh,
810 size_t argc,
811 char **argv)
812 {
813 unsigned long index;
814 int result = 0;
815
816 index = shell_strtoul(argv[1], 0, &result);
817 if (result != 0) {
818 shell_error(sh, "Failed to parse index: %d", result);
819
820 return -ENOEXEC;
821 }
822
823 if (index > vcp_included.aics_cnt) {
824 shell_error(sh, "Invalid index %lu", index);
825
826 return -ENOEXEC;
827 }
828
829 result = bt_aics_automatic_gain_set(vcp_included.aics[index]);
830 if (result) {
831 shell_print(sh, "Fail: %d", result);
832 }
833
834 return result;
835 }
836
cmd_vcp_vol_rend_aics_gain_set(const struct shell * sh,size_t argc,char ** argv)837 static int cmd_vcp_vol_rend_aics_gain_set(const struct shell *sh, size_t argc,
838 char **argv)
839 {
840 unsigned long index;
841 int result = 0;
842 long gain;
843
844 index = shell_strtoul(argv[1], 0, &result);
845 if (result != 0) {
846 shell_error(sh, "Could not parse index: %d", result);
847
848 return -ENOEXEC;
849 }
850
851 if (index >= vcp_included.aics_cnt) {
852 shell_error(sh, "Index shall be less than %u, was %lu",
853 vcp_included.aics_cnt, index);
854
855 return -ENOEXEC;
856 }
857
858 gain = shell_strtol(argv[2], 0, &result);
859 if (result != 0) {
860 shell_error(sh, "Could not parse gain: %d", result);
861
862 return -ENOEXEC;
863 }
864
865 if (gain > INT8_MAX || gain < INT8_MIN) {
866 shell_error(sh, "Gain shall be %d-%d, was %ld",
867 INT8_MIN, INT8_MAX, gain);
868
869 return -ENOEXEC;
870 }
871
872 result = bt_aics_gain_set(vcp_included.aics[index], gain);
873 if (result) {
874 shell_print(sh, "Fail: %d", result);
875 }
876
877 return result;
878 }
879
cmd_vcp_vol_rend_aics_input_description_get(const struct shell * sh,size_t argc,char ** argv)880 static int cmd_vcp_vol_rend_aics_input_description_get(const struct shell *sh,
881 size_t argc, char **argv)
882 {
883 unsigned long index;
884 int result = 0;
885
886 index = shell_strtoul(argv[1], 0, &result);
887 if (result != 0) {
888 shell_error(sh, "Failed to parse index: %d", result);
889
890 return -ENOEXEC;
891 }
892
893 if (index > vcp_included.aics_cnt) {
894 shell_error(sh, "Invalid index %lu", index);
895
896 return -ENOEXEC;
897 }
898 result = bt_aics_description_get(vcp_included.aics[index]);
899 if (result) {
900 shell_print(sh, "Fail: %d", result);
901 }
902
903 return result;
904 }
905
cmd_vcp_vol_rend_aics_input_description_set(const struct shell * sh,size_t argc,char ** argv)906 static int cmd_vcp_vol_rend_aics_input_description_set(const struct shell *sh,
907 size_t argc, char **argv)
908 {
909 unsigned long index;
910 int result = 0;
911
912 index = shell_strtoul(argv[1], 0, &result);
913 if (result != 0) {
914 shell_error(sh, "Failed to parse index: %d", result);
915
916 return -ENOEXEC;
917 }
918
919 if (index > vcp_included.aics_cnt) {
920 shell_error(sh, "Invalid index %lu", index);
921
922 return -ENOEXEC;
923 }
924
925 result = bt_aics_description_set(vcp_included.aics[index], argv[2]);
926 if (result) {
927 shell_print(sh, "Fail: %d", result);
928 }
929
930 return result;
931 }
932 #endif /* CONFIG_BT_VCP_VOL_REND_AICS */
933
cmd_vcp_vol_rend(const struct shell * sh,size_t argc,char ** argv)934 static int cmd_vcp_vol_rend(const struct shell *sh, size_t argc, char **argv)
935 {
936 if (argc > 1) {
937 shell_error(sh, "%s unknown parameter: %s",
938 argv[0], argv[1]);
939 } else {
940 shell_error(sh, "%s Missing subcommand", argv[0]);
941 }
942
943 return -ENOEXEC;
944 }
945
946 SHELL_STATIC_SUBCMD_SET_CREATE(vcp_vol_rend_cmds,
947 SHELL_CMD_ARG(init, NULL,
948 "Initialize the service and register callbacks "
949 "[step=<uint>] [mute=<bool>] [volume=<uint>]",
950 cmd_vcp_vol_rend_init, 1, 3),
951 SHELL_CMD_ARG(state_get, NULL,
952 "Get volume state of the VCP server. Should be done "
953 "before sending any control messages",
954 cmd_vcp_vol_rend_state_get, 1, 0),
955 SHELL_CMD_ARG(flags_get, NULL,
956 "Read volume flags",
957 cmd_vcp_vol_rend_flags_get, 1, 0),
958 SHELL_CMD_ARG(volume_down, NULL,
959 "Turn the volume down",
960 cmd_vcp_vol_rend_volume_down, 1, 0),
961 SHELL_CMD_ARG(volume_up, NULL,
962 "Turn the volume up",
963 cmd_vcp_vol_rend_volume_up, 1, 0),
964 SHELL_CMD_ARG(unmute_volume_down, NULL,
965 "Turn the volume down, and unmute",
966 cmd_vcp_vol_rend_unmute_volume_down, 1, 0),
967 SHELL_CMD_ARG(unmute_volume_up, NULL,
968 "Turn the volume up, and unmute",
969 cmd_vcp_vol_rend_unmute_volume_up, 1, 0),
970 SHELL_CMD_ARG(volume_set, NULL,
971 "Set an absolute volume <volume>",
972 cmd_vcp_vol_rend_volume_set, 2, 0),
973 SHELL_CMD_ARG(unmute, NULL,
974 "Unmute",
975 cmd_vcp_vol_rend_unmute, 1, 0),
976 SHELL_CMD_ARG(mute, NULL,
977 "Mute",
978 cmd_vcp_vol_rend_mute, 1, 0),
979 SHELL_CMD_ARG(step, NULL,
980 "Set step size",
981 cmd_vcp_vol_rend_volume_step, 2, 0),
982 #if defined(CONFIG_BT_VCP_VOL_REND_VOCS)
983 SHELL_CMD_ARG(vocs_state_get, NULL,
984 "Get the offset state of a VOCS instance <inst_index>",
985 cmd_vcp_vol_rend_vocs_state_get, 2, 0),
986 SHELL_CMD_ARG(vocs_location_get, NULL,
987 "Get the location of a VOCS instance <inst_index>",
988 cmd_vcp_vol_rend_vocs_location_get, 2, 0),
989 SHELL_CMD_ARG(vocs_location_set, NULL,
990 "Set the location of a VOCS instance <inst_index> "
991 "<location>",
992 cmd_vcp_vol_rend_vocs_location_set, 3, 0),
993 SHELL_CMD_ARG(vocs_offset_set, NULL,
994 "Set the offset for a VOCS instance <inst_index> "
995 "<offset>",
996 cmd_vcp_vol_rend_vocs_offset_set, 3, 0),
997 SHELL_CMD_ARG(vocs_output_description_get, NULL,
998 "Get the output description of a VOCS instance "
999 "<inst_index>",
1000 cmd_vcp_vol_rend_vocs_output_description_get, 2, 0),
1001 SHELL_CMD_ARG(vocs_output_description_set, NULL,
1002 "Set the output description of a VOCS instance "
1003 "<inst_index> <description>",
1004 cmd_vcp_vol_rend_vocs_output_description_set, 3, 0),
1005 #endif /* CONFIG_BT_VCP_VOL_REND_VOCS */
1006 #if defined(CONFIG_BT_VCP_VOL_REND_AICS)
1007 SHELL_CMD_ARG(aics_input_state_get, NULL,
1008 "Get the input state of a AICS instance <inst_index>",
1009 cmd_vcp_vol_rend_aics_input_state_get, 2, 0),
1010 SHELL_CMD_ARG(aics_gain_setting_get, NULL,
1011 "Get the gain settings of a AICS instance <inst_index>",
1012 cmd_vcp_vol_rend_aics_gain_setting_get, 2, 0),
1013 SHELL_CMD_ARG(aics_input_type_get, NULL,
1014 "Get the input type of a AICS instance <inst_index>",
1015 cmd_vcp_vol_rend_aics_input_type_get, 2, 0),
1016 SHELL_CMD_ARG(aics_input_status_get, NULL,
1017 "Get the input status of a AICS instance <inst_index>",
1018 cmd_vcp_vol_rend_aics_input_status_get, 2, 0),
1019 SHELL_CMD_ARG(aics_input_unmute, NULL,
1020 "Unmute the input of a AICS instance <inst_index>",
1021 cmd_vcp_vol_rend_aics_input_unmute, 2, 0),
1022 SHELL_CMD_ARG(aics_input_mute, NULL,
1023 "Mute the input of a AICS instance <inst_index>",
1024 cmd_vcp_vol_rend_aics_input_mute, 2, 0),
1025 SHELL_CMD_ARG(aics_manual_input_gain_set, NULL,
1026 "Set the gain mode of a AICS instance to manual "
1027 "<inst_index>",
1028 cmd_vcp_vol_rend_aics_manual_input_gain_set, 2, 0),
1029 SHELL_CMD_ARG(aics_automatic_input_gain_set, NULL,
1030 "Set the gain mode of a AICS instance to automatic "
1031 "<inst_index>",
1032 cmd_vcp_vol_rend_aics_auto_input_gain_set, 2, 0),
1033 SHELL_CMD_ARG(aics_gain_set, NULL,
1034 "Set the gain in dB of a AICS instance <inst_index> "
1035 "<gain (-128 to 127)>",
1036 cmd_vcp_vol_rend_aics_gain_set, 3, 0),
1037 SHELL_CMD_ARG(aics_input_description_get, NULL,
1038 "Read the input description of a AICS instance "
1039 "<inst_index>",
1040 cmd_vcp_vol_rend_aics_input_description_get, 2, 0),
1041 SHELL_CMD_ARG(aics_input_description_set, NULL,
1042 "Set the input description of a AICS instance "
1043 "<inst_index> <description>",
1044 cmd_vcp_vol_rend_aics_input_description_set, 3, 0),
1045 #endif /* CONFIG_BT_VCP_VOL_REND_AICS */
1046 SHELL_SUBCMD_SET_END
1047 );
1048
1049 SHELL_CMD_ARG_REGISTER(vcp_vol_rend, &vcp_vol_rend_cmds,
1050 "Bluetooth VCP Volume Renderer shell commands",
1051 cmd_vcp_vol_rend, 1, 1);
1052