1 /** @file
2 * @brief Bluetooth VCP client 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
15 #include <zephyr/autoconf.h>
16 #include <zephyr/bluetooth/audio/aics.h>
17 #include <zephyr/bluetooth/audio/vcp.h>
18 #include <zephyr/bluetooth/audio/vocs.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/shell/shell.h>
21 #include <zephyr/shell/shell_string_conv.h>
22 #include <zephyr/sys/util.h>
23 #include <zephyr/types.h>
24
25 #include "host/shell/bt.h"
26
27 static struct bt_vcp_vol_ctlr *vcp_vol_ctlr;
28 static struct bt_vcp_included vcp_included;
29
vcs_discover_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t vocs_count,uint8_t aics_count)30 static void vcs_discover_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err,
31 uint8_t vocs_count, uint8_t aics_count)
32 {
33 if (err != 0) {
34 shell_error(ctx_shell, "VCP discover failed (%d)", err);
35 } else {
36 shell_print(ctx_shell, "VCP discover done with %u VOCS and %u AICS", vocs_count,
37 aics_count);
38
39 if (bt_vcp_vol_ctlr_included_get(vol_ctlr, &vcp_included)) {
40 shell_error(ctx_shell, "Could not get VCP context");
41 }
42 }
43 }
44
vcs_vol_down_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)45 static void vcs_vol_down_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
46 {
47 if (err != 0) {
48 shell_error(ctx_shell, "VCP vol_down failed (%d)", err);
49 } else {
50 shell_print(ctx_shell, "VCP vol_down done");
51 }
52 }
53
vcs_vol_up_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)54 static void vcs_vol_up_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
55 {
56 if (err != 0) {
57 shell_error(ctx_shell, "VCP vol_up failed (%d)", err);
58 } else {
59 shell_print(ctx_shell, "VCP vol_up done");
60 }
61 }
62
vcs_mute_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)63 static void vcs_mute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
64 {
65 if (err != 0) {
66 shell_error(ctx_shell, "VCP mute failed (%d)", err);
67 } else {
68 shell_print(ctx_shell, "VCP mute done");
69 }
70 }
71
vcs_unmute_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)72 static void vcs_unmute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
73 {
74 if (err != 0) {
75 shell_error(ctx_shell, "VCP unmute failed (%d)", err);
76 } else {
77 shell_print(ctx_shell, "VCP unmute done");
78 }
79 }
80
vcs_vol_down_unmute_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)81 static void vcs_vol_down_unmute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
82 {
83 if (err != 0) {
84 shell_error(ctx_shell, "VCP vol_down_unmute failed (%d)", err);
85 } else {
86 shell_print(ctx_shell, "VCP vol_down_unmute done");
87 }
88 }
89
vcs_vol_up_unmute_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)90 static void vcs_vol_up_unmute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
91 {
92 if (err != 0) {
93 shell_error(ctx_shell, "VCP vol_up_unmute failed (%d)", err);
94 } else {
95 shell_print(ctx_shell, "VCP vol_up_unmute done");
96 }
97 }
98
vcs_vol_set_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)99 static void vcs_vol_set_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
100 {
101 if (err != 0) {
102 shell_error(ctx_shell, "VCP vol_set failed (%d)", err);
103 } else {
104 shell_print(ctx_shell, "VCP vol_set done");
105 }
106 }
107
vcs_state_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t volume,uint8_t mute)108 static void vcs_state_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err,
109 uint8_t volume, uint8_t mute)
110 {
111 if (err != 0) {
112 shell_error(ctx_shell, "VCP state get failed (%d)", err);
113 } else {
114 shell_print(ctx_shell, "VCP volume %u, mute %u", volume, mute);
115 }
116 }
117
vcs_flags_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t flags)118 static void vcs_flags_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err,
119 uint8_t flags)
120 {
121 if (err != 0) {
122 shell_error(ctx_shell, "VCP flags get failed (%d)", err);
123 } else {
124 shell_print(ctx_shell, "VCP flags 0x%02X", flags);
125 }
126 }
127
128 #if CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0
vcs_aics_set_gain_cb(struct bt_aics * inst,int err)129 static void vcs_aics_set_gain_cb(struct bt_aics *inst, int err)
130 {
131 if (err != 0) {
132 shell_error(ctx_shell, "Set gain failed (%d) for inst %p",
133 err, inst);
134 } else {
135 shell_print(ctx_shell, "Gain set for inst %p", inst);
136 }
137 }
138
vcs_aics_unmute_cb(struct bt_aics * inst,int err)139 static void vcs_aics_unmute_cb(struct bt_aics *inst, int err)
140 {
141 if (err != 0) {
142 shell_error(ctx_shell, "Unmute failed (%d) for inst %p",
143 err, inst);
144 } else {
145 shell_print(ctx_shell, "Unmuted inst %p", inst);
146 }
147 }
148
vcs_aics_mute_cb(struct bt_aics * inst,int err)149 static void vcs_aics_mute_cb(struct bt_aics *inst, int err)
150 {
151 if (err != 0) {
152 shell_error(ctx_shell, "Mute failed (%d) for inst %p",
153 err, inst);
154 } else {
155 shell_print(ctx_shell, "Muted inst %p", inst);
156 }
157 }
158
vcs_aics_set_manual_mode_cb(struct bt_aics * inst,int err)159 static void vcs_aics_set_manual_mode_cb(struct bt_aics *inst, int err)
160 {
161 if (err != 0) {
162 shell_error(ctx_shell,
163 "Set manual mode failed (%d) for inst %p",
164 err, inst);
165 } else {
166 shell_print(ctx_shell, "Manual mode set for inst %p", inst);
167 }
168 }
169
vcs_aics_automatic_mode_cb(struct bt_aics * inst,int err)170 static void vcs_aics_automatic_mode_cb(struct bt_aics *inst, int err)
171 {
172 if (err != 0) {
173 shell_error(ctx_shell,
174 "Set automatic mode failed (%d) for inst %p",
175 err, inst);
176 } else {
177 shell_print(ctx_shell, "Automatic mode set for inst %p",
178 inst);
179 }
180 }
181
vcs_aics_state_cb(struct bt_aics * inst,int err,int8_t gain,uint8_t mute,uint8_t mode)182 static void vcs_aics_state_cb(struct bt_aics *inst, int err, int8_t gain,
183 uint8_t mute, uint8_t mode)
184 {
185 if (err != 0) {
186 shell_error(ctx_shell, "AICS state get failed (%d) for inst %p",
187 err, inst);
188 } else {
189 shell_print(ctx_shell,
190 "AICS inst %p state gain %d, mute %u, mode %u",
191 inst, gain, mute, mode);
192 }
193 }
194
vcs_aics_gain_setting_cb(struct bt_aics * inst,int err,uint8_t units,int8_t minimum,int8_t maximum)195 static void vcs_aics_gain_setting_cb(struct bt_aics *inst, int err,
196 uint8_t units, int8_t minimum,
197 int8_t maximum)
198 {
199 if (err != 0) {
200 shell_error(ctx_shell,
201 "AICS gain settings get failed (%d) for inst %p",
202 err, inst);
203 } else {
204 shell_print(ctx_shell,
205 "AICS inst %p gain settings units %u, min %d, max %d",
206 inst, units, minimum, maximum);
207 }
208 }
209
vcs_aics_input_type_cb(struct bt_aics * inst,int err,uint8_t input_type)210 static void vcs_aics_input_type_cb(struct bt_aics *inst, int err,
211 uint8_t input_type)
212 {
213 if (err != 0) {
214 shell_error(ctx_shell,
215 "AICS input type get failed (%d) for inst %p",
216 err, inst);
217 } else {
218 shell_print(ctx_shell, "AICS inst %p input type %u",
219 inst, input_type);
220 }
221 }
222
vcs_aics_status_cb(struct bt_aics * inst,int err,bool active)223 static void vcs_aics_status_cb(struct bt_aics *inst, int err, bool active)
224 {
225 if (err != 0) {
226 shell_error(ctx_shell,
227 "AICS status get failed (%d) for inst %p",
228 err, inst);
229 } else {
230 shell_print(ctx_shell, "AICS inst %p status %s",
231 inst, active ? "active" : "inactive");
232 }
233
234 }
vcs_aics_description_cb(struct bt_aics * inst,int err,char * description)235 static void vcs_aics_description_cb(struct bt_aics *inst, int err,
236 char *description)
237 {
238 if (err != 0) {
239 shell_error(ctx_shell,
240 "AICS description get failed (%d) for inst %p",
241 err, inst);
242 } else {
243 shell_print(ctx_shell, "AICS inst %p description %s",
244 inst, description);
245 }
246 }
247 #endif /* CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 */
248
249 #if CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0
vcs_vocs_set_offset_cb(struct bt_vocs * inst,int err)250 static void vcs_vocs_set_offset_cb(struct bt_vocs *inst, int err)
251 {
252 if (err != 0) {
253 shell_error(ctx_shell, "Set offset failed (%d) for inst %p",
254 err, inst);
255 } else {
256 shell_print(ctx_shell, "Offset set for inst %p", inst);
257 }
258 }
259
vcs_vocs_state_cb(struct bt_vocs * inst,int err,int16_t offset)260 static void vcs_vocs_state_cb(struct bt_vocs *inst, int err, int16_t offset)
261 {
262 if (err != 0) {
263 shell_error(ctx_shell, "VOCS state get failed (%d) for inst %p",
264 err, inst);
265 } else {
266 shell_print(ctx_shell, "VOCS inst %p offset %d", inst, offset);
267 }
268 }
269
vcs_vocs_location_cb(struct bt_vocs * inst,int err,uint32_t location)270 static void vcs_vocs_location_cb(struct bt_vocs *inst, int err,
271 uint32_t location)
272 {
273 if (err != 0) {
274 shell_error(ctx_shell,
275 "VOCS location get failed (%d) for inst %p",
276 err, inst);
277 } else {
278 shell_print(ctx_shell, "VOCS inst %p location %u",
279 inst, location);
280 }
281 }
282
vcs_vocs_description_cb(struct bt_vocs * inst,int err,char * description)283 static void vcs_vocs_description_cb(struct bt_vocs *inst, int err,
284 char *description)
285 {
286 if (err != 0) {
287 shell_error(ctx_shell,
288 "VOCS description get failed (%d) for inst %p",
289 err, inst);
290 } else {
291 shell_print(ctx_shell, "VOCS inst %p description %s",
292 inst, description);
293 }
294 }
295 #endif /* CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0 */
296
297 static struct bt_vcp_vol_ctlr_cb vcp_cbs = {
298 .discover = vcs_discover_cb,
299 .vol_down = vcs_vol_down_cb,
300 .vol_up = vcs_vol_up_cb,
301 .mute = vcs_mute_cb,
302 .unmute = vcs_unmute_cb,
303 .vol_down_unmute = vcs_vol_down_unmute_cb,
304 .vol_up_unmute = vcs_vol_up_unmute_cb,
305 .vol_set = vcs_vol_set_cb,
306
307 .state = vcs_state_cb,
308 .flags = vcs_flags_cb,
309
310 /* Audio Input Control Service */
311 #if CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0
312 .aics_cb = {
313 .state = vcs_aics_state_cb,
314 .gain_setting = vcs_aics_gain_setting_cb,
315 .type = vcs_aics_input_type_cb,
316 .status = vcs_aics_status_cb,
317 .description = vcs_aics_description_cb,
318 .set_gain = vcs_aics_set_gain_cb,
319 .unmute = vcs_aics_unmute_cb,
320 .mute = vcs_aics_mute_cb,
321 .set_manual_mode = vcs_aics_set_manual_mode_cb,
322 .set_auto_mode = vcs_aics_automatic_mode_cb,
323 },
324 #endif /* CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST > 0 */
325 #if CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0
326 .vocs_cb = {
327 .state = vcs_vocs_state_cb,
328 .location = vcs_vocs_location_cb,
329 .description = vcs_vocs_description_cb,
330 .set_offset = vcs_vocs_set_offset_cb,
331 }
332 #endif /* CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST > 0 */
333 };
334
cmd_vcp_vol_ctlr_discover(const struct shell * sh,size_t argc,char ** argv)335 static int cmd_vcp_vol_ctlr_discover(const struct shell *sh, size_t argc,
336 char **argv)
337 {
338 static bool cb_registered;
339 int result;
340
341 if (!ctx_shell) {
342 ctx_shell = sh;
343 }
344
345 if (!cb_registered) {
346 result = bt_vcp_vol_ctlr_cb_register(&vcp_cbs);
347 if (result != 0) {
348 shell_print(sh, "CB register failed: %d", result);
349 return result;
350 }
351
352 cb_registered = true;
353 }
354
355 if (default_conn == NULL) {
356 shell_error(sh, "Not connected");
357 return -ENOEXEC;
358 }
359
360 result = bt_vcp_vol_ctlr_discover(default_conn, &vcp_vol_ctlr);
361 if (result != 0) {
362 shell_print(sh, "Fail: %d", result);
363 }
364
365 return result;
366 }
367
cmd_vcp_vol_ctlr_state_get(const struct shell * sh,size_t argc,char ** argv)368 static int cmd_vcp_vol_ctlr_state_get(const struct shell *sh, size_t argc,
369 char **argv)
370 {
371 int result;
372
373 if (default_conn == NULL) {
374 shell_error(sh, "Not connected");
375 return -ENOEXEC;
376 }
377
378 result = bt_vcp_vol_ctlr_read_state(vcp_vol_ctlr);
379 if (result != 0) {
380 shell_print(sh, "Fail: %d", result);
381 }
382
383 return result;
384 }
385
cmd_vcp_vol_ctlr_flags_get(const struct shell * sh,size_t argc,char ** argv)386 static int cmd_vcp_vol_ctlr_flags_get(const struct shell *sh, size_t argc,
387 char **argv)
388 {
389 int result;
390
391 if (default_conn == NULL) {
392 shell_error(sh, "Not connected");
393 return -ENOEXEC;
394 }
395
396 result = bt_vcp_vol_ctlr_read_flags(vcp_vol_ctlr);
397 if (result != 0) {
398 shell_print(sh, "Fail: %d", result);
399 }
400
401 return result;
402 }
403
cmd_vcp_vol_ctlr_volume_down(const struct shell * sh,size_t argc,char ** argv)404 static int cmd_vcp_vol_ctlr_volume_down(const struct shell *sh, size_t argc,
405 char **argv)
406 {
407 int result;
408
409 if (default_conn == NULL) {
410 shell_error(sh, "Not connected");
411 return -ENOEXEC;
412 }
413
414 result = bt_vcp_vol_ctlr_vol_down(vcp_vol_ctlr);
415 if (result != 0) {
416 shell_print(sh, "Fail: %d", result);
417 }
418
419 return result;
420 }
421
cmd_vcp_vol_ctlr_volume_up(const struct shell * sh,size_t argc,char ** argv)422 static int cmd_vcp_vol_ctlr_volume_up(const struct shell *sh, size_t argc,
423 char **argv)
424
425 {
426 int result;
427
428 if (default_conn == NULL) {
429 shell_error(sh, "Not connected");
430 return -ENOEXEC;
431 }
432
433 result = bt_vcp_vol_ctlr_vol_up(vcp_vol_ctlr);
434 if (result != 0) {
435 shell_print(sh, "Fail: %d", result);
436 }
437
438 return result;
439 }
440
cmd_vcp_vol_ctlr_unmute_volume_down(const struct shell * sh,size_t argc,char ** argv)441 static int cmd_vcp_vol_ctlr_unmute_volume_down(const struct shell *sh,
442 size_t argc, char **argv)
443 {
444 int result;
445
446 if (default_conn == NULL) {
447 shell_error(sh, "Not connected");
448 return -ENOEXEC;
449 }
450
451 result = bt_vcp_vol_ctlr_unmute_vol_down(vcp_vol_ctlr);
452 if (result != 0) {
453 shell_print(sh, "Fail: %d", result);
454 }
455
456 return result;
457 }
458
cmd_vcp_vol_ctlr_unmute_volume_up(const struct shell * sh,size_t argc,char ** argv)459 static int cmd_vcp_vol_ctlr_unmute_volume_up(const struct shell *sh,
460 size_t argc, char **argv)
461 {
462 int result;
463
464 if (default_conn == NULL) {
465 shell_error(sh, "Not connected");
466 return -ENOEXEC;
467 }
468
469 result = bt_vcp_vol_ctlr_unmute_vol_up(vcp_vol_ctlr);
470 if (result != 0) {
471 shell_print(sh, "Fail: %d", result);
472 }
473
474 return result;
475 }
476
cmd_vcp_vol_ctlr_volume_set(const struct shell * sh,size_t argc,char ** argv)477 static int cmd_vcp_vol_ctlr_volume_set(const struct shell *sh, size_t argc,
478 char **argv)
479
480 {
481 unsigned long volume;
482 int result = 0;
483
484 if (default_conn == NULL) {
485 shell_error(sh, "Not connected");
486 return -ENOEXEC;
487 }
488
489 volume = shell_strtoul(argv[1], 0, &result);
490 if (result != 0) {
491 shell_error(sh, "Failed to parse volume: %d", result);
492
493 return -ENOEXEC;
494 }
495
496 if (volume > UINT8_MAX) {
497 shell_error(sh, "Volume shall be 0-255, was %lu", volume);
498
499 return -ENOEXEC;
500 }
501
502 result = bt_vcp_vol_ctlr_set_vol(vcp_vol_ctlr, volume);
503 if (result != 0) {
504 shell_print(sh, "Fail: %d", result);
505 }
506
507 return result;
508 }
509
510
cmd_vcp_vol_ctlr_unmute(const struct shell * sh,size_t argc,char ** argv)511 static int cmd_vcp_vol_ctlr_unmute(const struct shell *sh, size_t argc,
512 char **argv)
513 {
514 int result;
515
516 if (default_conn == NULL) {
517 shell_error(sh, "Not connected");
518 return -ENOEXEC;
519 }
520
521 result = bt_vcp_vol_ctlr_unmute(vcp_vol_ctlr);
522 if (result != 0) {
523 shell_print(sh, "Fail: %d", result);
524 }
525
526 return result;
527 }
528
cmd_vcp_vol_ctlr_mute(const struct shell * sh,size_t argc,char ** argv)529 static int cmd_vcp_vol_ctlr_mute(const struct shell *sh, size_t argc,
530 char **argv)
531 {
532 int result;
533
534 if (default_conn == NULL) {
535 shell_error(sh, "Not connected");
536 return -ENOEXEC;
537 }
538
539 result = bt_vcp_vol_ctlr_mute(vcp_vol_ctlr);
540 if (result != 0) {
541 shell_print(sh, "Fail: %d", result);
542 }
543
544 return result;
545 }
546
cmd_vcp_vol_ctlr_vocs_state_get(const struct shell * sh,size_t argc,char ** argv)547 static int cmd_vcp_vol_ctlr_vocs_state_get(const struct shell *sh, size_t argc,
548 char **argv)
549 {
550 unsigned long index;
551 int result = 0;
552
553 if (default_conn == NULL) {
554 shell_error(sh, "Not connected");
555 return -ENOEXEC;
556 }
557
558 index = shell_strtoul(argv[1], 0, &result);
559 if (result != 0) {
560 shell_error(sh, "Failed to parse index: %d", result);
561
562 return -ENOEXEC;
563 }
564
565 if (index >= vcp_included.vocs_cnt) {
566 shell_error(sh, "Index shall be less than %u, was %lu",
567 vcp_included.vocs_cnt, index);
568
569 return -ENOEXEC;
570 }
571
572 result = bt_vocs_state_get(vcp_included.vocs[index]);
573 if (result != 0) {
574 shell_print(sh, "Fail: %d", result);
575 }
576
577 return result;
578 }
579
cmd_vcp_vol_ctlr_vocs_location_get(const struct shell * sh,size_t argc,char ** argv)580 static int cmd_vcp_vol_ctlr_vocs_location_get(const struct shell *sh,
581 size_t argc, char **argv)
582 {
583 unsigned long index;
584 int result = 0;
585
586 if (default_conn == NULL) {
587 shell_error(sh, "Not connected");
588 return -ENOEXEC;
589 }
590
591 index = shell_strtoul(argv[1], 0, &result);
592 if (result != 0) {
593 shell_error(sh, "Failed to parse index: %d", result);
594
595 return -ENOEXEC;
596 }
597
598 if (index >= vcp_included.vocs_cnt) {
599 shell_error(sh, "Index shall be less than %u, was %lu",
600 vcp_included.vocs_cnt, index);
601
602 return -ENOEXEC;
603 }
604
605 result = bt_vocs_location_get(vcp_included.vocs[index]);
606 if (result != 0) {
607 shell_print(sh, "Fail: %d", result);
608 }
609
610 return result;
611 }
612
cmd_vcp_vol_ctlr_vocs_location_set(const struct shell * sh,size_t argc,char ** argv)613 static int cmd_vcp_vol_ctlr_vocs_location_set(const struct shell *sh,
614 size_t argc, char **argv)
615 {
616 unsigned long location;
617 unsigned long index;
618 int result = 0;
619
620 if (default_conn == NULL) {
621 shell_error(sh, "Not connected");
622 return -ENOEXEC;
623 }
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.vocs_cnt) {
633 shell_error(sh, "Index shall be less than %u, was %lu",
634 vcp_included.vocs_cnt, index);
635
636 return -ENOEXEC;
637 }
638
639 location = shell_strtoul(argv[2], 0, &result);
640 if (result != 0) {
641 shell_error(sh, "Failed to parse location: %d", result);
642
643 return -ENOEXEC;
644 }
645
646 if (location > UINT32_MAX) {
647 shell_error(sh, "Invalid location %lu", location);
648 return -ENOEXEC;
649
650 }
651
652 result = bt_vocs_location_set(vcp_included.vocs[index], location);
653 if (result != 0) {
654 shell_print(sh, "Fail: %d", result);
655 }
656
657 return result;
658 }
659
cmd_vcp_vol_ctlr_vocs_offset_set(const struct shell * sh,size_t argc,char ** argv)660 static int cmd_vcp_vol_ctlr_vocs_offset_set(const struct shell *sh,
661 size_t argc, char **argv)
662 {
663 unsigned long index;
664 int result = 0;
665 long offset;
666
667 if (default_conn == NULL) {
668 shell_error(sh, "Not connected");
669 return -ENOEXEC;
670 }
671
672 index = shell_strtoul(argv[1], 0, &result);
673 if (result != 0) {
674 shell_error(sh, "Failed to parse index: %d", result);
675
676 return -ENOEXEC;
677 }
678
679 if (index >= vcp_included.vocs_cnt) {
680 shell_error(sh, "Index shall be less than %u, was %lu",
681 vcp_included.vocs_cnt, index);
682
683 return -ENOEXEC;
684 }
685
686 offset = shell_strtol(argv[2], 0, &result);
687 if (result != 0) {
688 shell_error(sh, "Failed to parse offset: %d", result);
689
690 return -ENOEXEC;
691 }
692
693 if (!IN_RANGE(offset, BT_VOCS_MIN_OFFSET, BT_VOCS_MAX_OFFSET)) {
694 shell_error(sh, "Offset shall be %d-%d, was %ld",
695 BT_VOCS_MIN_OFFSET, BT_VOCS_MAX_OFFSET, offset);
696 return -ENOEXEC;
697 }
698
699 result = bt_vocs_state_set(vcp_included.vocs[index],
700 offset);
701 if (result != 0) {
702 shell_print(sh, "Fail: %d", result);
703 }
704
705 return result;
706 }
707
cmd_vcp_vol_ctlr_vocs_output_description_get(const struct shell * sh,size_t argc,char ** argv)708 static int cmd_vcp_vol_ctlr_vocs_output_description_get(const struct shell *sh,
709 size_t argc, char **argv)
710 {
711 unsigned long index;
712 int result = 0;
713
714 if (default_conn == NULL) {
715 shell_error(sh, "Not connected");
716 return -ENOEXEC;
717 }
718
719 index = shell_strtoul(argv[1], 0, &result);
720 if (result != 0) {
721 shell_error(sh, "Failed to parse index: %d", result);
722
723 return -ENOEXEC;
724 }
725
726 if (index >= vcp_included.vocs_cnt) {
727 shell_error(sh, "Index shall be less than %u, was %lu",
728 vcp_included.vocs_cnt, index);
729
730 return -ENOEXEC;
731 }
732
733 result = bt_vocs_description_get(vcp_included.vocs[index]);
734 if (result != 0) {
735 shell_print(sh, "Fail: %d", result);
736 }
737
738 return result;
739 }
740
cmd_vcp_vol_ctlr_vocs_output_description_set(const struct shell * sh,size_t argc,char ** argv)741 static int cmd_vcp_vol_ctlr_vocs_output_description_set(const struct shell *sh,
742 size_t argc, char **argv)
743 {
744 unsigned long index;
745 int result = 0;
746
747 if (default_conn == NULL) {
748 shell_error(sh, "Not connected");
749 return -ENOEXEC;
750 }
751
752 index = shell_strtoul(argv[1], 0, &result);
753 if (result != 0) {
754 shell_error(sh, "Failed to parse index: %d", result);
755
756 return -ENOEXEC;
757 }
758
759 if (index >= vcp_included.vocs_cnt) {
760 shell_error(sh, "Index shall be less than %u, was %lu",
761 vcp_included.vocs_cnt, index);
762
763 return -ENOEXEC;
764 }
765
766 result = bt_vocs_description_set(vcp_included.vocs[index], argv[2]);
767 if (result != 0) {
768 shell_print(sh, "Fail: %d", result);
769 }
770
771 return result;
772 }
773
cmd_vcp_vol_ctlr_aics_input_state_get(const struct shell * sh,size_t argc,char ** argv)774 static int cmd_vcp_vol_ctlr_aics_input_state_get(const struct shell *sh,
775 size_t argc, char **argv)
776 {
777 unsigned long index;
778 int result = 0;
779
780 if (default_conn == NULL) {
781 shell_error(sh, "Not connected");
782 return -ENOEXEC;
783 }
784
785 index = shell_strtoul(argv[1], 0, &result);
786 if (result != 0) {
787 shell_error(sh, "Failed to parse index: %d", result);
788
789 return -ENOEXEC;
790 }
791
792 if (index >= vcp_included.aics_cnt) {
793 shell_error(sh, "Index shall be less than %u, was %lu",
794 vcp_included.vocs_cnt, index);
795
796 return -ENOEXEC;
797 }
798
799 result = bt_aics_state_get(vcp_included.aics[index]);
800 if (result != 0) {
801 shell_print(sh, "Fail: %d", result);
802 }
803
804 return result;
805 }
806
cmd_vcp_vol_ctlr_aics_gain_setting_get(const struct shell * sh,size_t argc,char ** argv)807 static int cmd_vcp_vol_ctlr_aics_gain_setting_get(const struct shell *sh,
808 size_t argc, char **argv)
809 {
810 unsigned long index;
811 int result = 0;
812
813 if (default_conn == NULL) {
814 shell_error(sh, "Not connected");
815 return -ENOEXEC;
816 }
817
818 index = shell_strtoul(argv[1], 0, &result);
819 if (result != 0) {
820 shell_error(sh, "Failed to parse index: %d", result);
821
822 return -ENOEXEC;
823 }
824
825 if (index >= vcp_included.aics_cnt) {
826 shell_error(sh, "Index shall be less than %u, was %lu",
827 vcp_included.vocs_cnt, index);
828
829 return -ENOEXEC;
830 }
831
832 result = bt_aics_gain_setting_get(vcp_included.aics[index]);
833 if (result != 0) {
834 shell_print(sh, "Fail: %d", result);
835 }
836
837 return result;
838 }
839
cmd_vcp_vol_ctlr_aics_input_type_get(const struct shell * sh,size_t argc,char ** argv)840 static int cmd_vcp_vol_ctlr_aics_input_type_get(const struct shell *sh,
841 size_t argc, char **argv)
842 {
843 unsigned long index;
844 int result = 0;
845
846 if (default_conn == NULL) {
847 shell_error(sh, "Not connected");
848 return -ENOEXEC;
849 }
850
851 index = shell_strtoul(argv[1], 0, &result);
852 if (result != 0) {
853 shell_error(sh, "Failed to parse index: %d", result);
854
855 return -ENOEXEC;
856 }
857
858 if (index >= vcp_included.aics_cnt) {
859 shell_error(sh, "Index shall be less than %u, was %lu",
860 vcp_included.vocs_cnt, index);
861
862 return -ENOEXEC;
863 }
864
865 result = bt_aics_type_get(vcp_included.aics[index]);
866 if (result != 0) {
867 shell_print(sh, "Fail: %d", result);
868 }
869
870 return result;
871 }
872
cmd_vcp_vol_ctlr_aics_input_status_get(const struct shell * sh,size_t argc,char ** argv)873 static int cmd_vcp_vol_ctlr_aics_input_status_get(const struct shell *sh,
874 size_t argc, char **argv)
875 {
876 unsigned long index;
877 int result = 0;
878
879 if (default_conn == NULL) {
880 shell_error(sh, "Not connected");
881 return -ENOEXEC;
882 }
883
884 index = shell_strtoul(argv[1], 0, &result);
885 if (result != 0) {
886 shell_error(sh, "Failed to parse index: %d", result);
887
888 return -ENOEXEC;
889 }
890
891 if (index >= vcp_included.aics_cnt) {
892 shell_error(sh, "Index shall be less than %u, was %lu",
893 vcp_included.vocs_cnt, index);
894
895 return -ENOEXEC;
896 }
897
898 result = bt_aics_status_get(vcp_included.aics[index]);
899 if (result != 0) {
900 shell_print(sh, "Fail: %d", result);
901 }
902
903 return result;
904 }
905
cmd_vcp_vol_ctlr_aics_input_unmute(const struct shell * sh,size_t argc,char ** argv)906 static int cmd_vcp_vol_ctlr_aics_input_unmute(const struct shell *sh,
907 size_t argc, char **argv)
908 {
909 unsigned long index;
910 int result = 0;
911
912 if (default_conn == NULL) {
913 shell_error(sh, "Not connected");
914 return -ENOEXEC;
915 }
916
917 index = shell_strtoul(argv[1], 0, &result);
918 if (result != 0) {
919 shell_error(sh, "Failed to parse index: %d", result);
920
921 return -ENOEXEC;
922 }
923
924 if (index >= vcp_included.aics_cnt) {
925 shell_error(sh, "Index shall be less than %u, was %lu",
926 vcp_included.vocs_cnt, index);
927
928 return -ENOEXEC;
929 }
930
931 result = bt_aics_unmute(vcp_included.aics[index]);
932 if (result != 0) {
933 shell_print(sh, "Fail: %d", result);
934 }
935
936 return result;
937 }
938
cmd_vcp_vol_ctlr_aics_input_mute(const struct shell * sh,size_t argc,char ** argv)939 static int cmd_vcp_vol_ctlr_aics_input_mute(const struct shell *sh,
940 size_t argc, char **argv)
941 {
942 unsigned long index;
943 int result = 0;
944
945 if (default_conn == NULL) {
946 shell_error(sh, "Not connected");
947 return -ENOEXEC;
948 }
949
950 index = shell_strtoul(argv[1], 0, &result);
951 if (result != 0) {
952 shell_error(sh, "Failed to parse index: %d", result);
953
954 return -ENOEXEC;
955 }
956
957 if (index >= vcp_included.aics_cnt) {
958 shell_error(sh, "Index shall be less than %u, was %lu",
959 vcp_included.vocs_cnt, index);
960
961 return -ENOEXEC;
962 }
963
964 result = bt_aics_mute(vcp_included.aics[index]);
965 if (result != 0) {
966 shell_print(sh, "Fail: %d", result);
967 }
968
969 return result;
970 }
971
cmd_vcp_vol_ctlr_aics_manual_input_gain_set(const struct shell * sh,size_t argc,char ** argv)972 static int cmd_vcp_vol_ctlr_aics_manual_input_gain_set(const struct shell *sh,
973 size_t argc, char **argv)
974 {
975 unsigned long index;
976 int result = 0;
977
978 if (default_conn == NULL) {
979 shell_error(sh, "Not connected");
980 return -ENOEXEC;
981 }
982
983 index = shell_strtoul(argv[1], 0, &result);
984 if (result != 0) {
985 shell_error(sh, "Failed to parse index: %d", result);
986
987 return -ENOEXEC;
988 }
989
990 if (index >= vcp_included.aics_cnt) {
991 shell_error(sh, "Index shall be less than %u, was %lu",
992 vcp_included.vocs_cnt, index);
993
994 return -ENOEXEC;
995 }
996
997 result = bt_aics_manual_gain_set(vcp_included.aics[index]);
998 if (result != 0) {
999 shell_print(sh, "Fail: %d", result);
1000 }
1001
1002 return result;
1003 }
1004
cmd_vcp_vol_ctlr_aics_auto_input_gain_set(const struct shell * sh,size_t argc,char ** argv)1005 static int cmd_vcp_vol_ctlr_aics_auto_input_gain_set(const struct shell *sh,
1006 size_t argc, char **argv)
1007 {
1008 unsigned long index;
1009 int result = 0;
1010
1011 if (default_conn == NULL) {
1012 shell_error(sh, "Not connected");
1013 return -ENOEXEC;
1014 }
1015
1016 index = shell_strtoul(argv[1], 0, &result);
1017 if (result != 0) {
1018 shell_error(sh, "Failed to parse index: %d", result);
1019
1020 return -ENOEXEC;
1021 }
1022
1023 if (index >= vcp_included.aics_cnt) {
1024 shell_error(sh, "Index shall be less than %u, was %lu",
1025 vcp_included.vocs_cnt, index);
1026
1027 return -ENOEXEC;
1028 }
1029
1030 result = bt_aics_automatic_gain_set(vcp_included.aics[index]);
1031 if (result != 0) {
1032 shell_print(sh, "Fail: %d", result);
1033 }
1034
1035 return result;
1036 }
1037
cmd_vcp_vol_ctlr_aics_gain_set(const struct shell * sh,size_t argc,char ** argv)1038 static int cmd_vcp_vol_ctlr_aics_gain_set(const struct shell *sh, size_t argc,
1039 char **argv)
1040 {
1041 unsigned long index;
1042 int result = 0;
1043 long gain;
1044
1045 if (default_conn == NULL) {
1046 shell_error(sh, "Not connected");
1047 return -ENOEXEC;
1048 }
1049
1050 index = shell_strtoul(argv[1], 0, &result);
1051 if (result != 0) {
1052 shell_error(sh, "Could not parse index: %d", result);
1053 return -ENOEXEC;
1054 }
1055
1056 if (index >= vcp_included.aics_cnt) {
1057 shell_error(sh, "Index shall be less than %u, was %lu",
1058 vcp_included.aics_cnt, index);
1059 return -ENOEXEC;
1060 }
1061
1062 gain = shell_strtol(argv[2], 0, &result);
1063 if (result != 0) {
1064 shell_error(sh, "Could not parse gain: %d", result);
1065 return -ENOEXEC;
1066 }
1067
1068 if (!IN_RANGE(gain, INT8_MIN, INT8_MAX)) {
1069 shell_error(sh, "Gain shall be %d-%d, was %ld",
1070 INT8_MIN, INT8_MAX, gain);
1071 return -ENOEXEC;
1072 }
1073
1074 result = bt_aics_gain_set(vcp_included.aics[index], gain);
1075 if (result != 0) {
1076 shell_print(sh, "Fail: %d", result);
1077 }
1078
1079 return result;
1080 }
1081
cmd_vcp_vol_ctlr_aics_input_description_get(const struct shell * sh,size_t argc,char ** argv)1082 static int cmd_vcp_vol_ctlr_aics_input_description_get(const struct shell *sh,
1083 size_t argc, char **argv)
1084 {
1085 unsigned long index;
1086 int result = 0;
1087
1088 if (default_conn == NULL) {
1089 shell_error(sh, "Not connected");
1090 return -ENOEXEC;
1091 }
1092
1093 index = shell_strtoul(argv[1], 0, &result);
1094 if (result != 0) {
1095 shell_error(sh, "Failed to parse index: %d", result);
1096
1097 return -ENOEXEC;
1098 }
1099
1100 if (index >= vcp_included.aics_cnt) {
1101 shell_error(sh, "Index shall be less than %u, was %lu",
1102 vcp_included.vocs_cnt, index);
1103
1104 return -ENOEXEC;
1105 }
1106
1107 result = bt_aics_description_get(vcp_included.aics[index]);
1108 if (result != 0) {
1109 shell_print(sh, "Fail: %d", result);
1110 }
1111
1112 return result;
1113 }
1114
cmd_vcp_vol_ctlr_aics_input_description_set(const struct shell * sh,size_t argc,char ** argv)1115 static int cmd_vcp_vol_ctlr_aics_input_description_set(const struct shell *sh,
1116 size_t argc, char **argv)
1117 {
1118 unsigned long index;
1119 int result = 0;
1120
1121 if (default_conn == NULL) {
1122 shell_error(sh, "Not connected");
1123 return -ENOEXEC;
1124 }
1125
1126 index = shell_strtoul(argv[1], 0, &result);
1127 if (result != 0) {
1128 shell_error(sh, "Failed to parse index: %d", result);
1129
1130 return -ENOEXEC;
1131 }
1132
1133 if (index >= vcp_included.aics_cnt) {
1134 shell_error(sh, "Index shall be less than %u, was %lu",
1135 vcp_included.vocs_cnt, index);
1136
1137 return -ENOEXEC;
1138 }
1139
1140 result = bt_aics_description_set(vcp_included.aics[index], argv[2]);
1141 if (result != 0) {
1142 shell_print(sh, "Fail: %d", result);
1143 }
1144
1145 return result;
1146 }
1147
cmd_vcp_vol_ctlr(const struct shell * sh,size_t argc,char ** argv)1148 static int cmd_vcp_vol_ctlr(const struct shell *sh, size_t argc, char **argv)
1149 {
1150 if (argc > 1) {
1151 shell_error(sh, "%s unknown parameter: %s",
1152 argv[0], argv[1]);
1153 } else {
1154 shell_error(sh, "%s Missing subcommand", argv[0]);
1155 }
1156
1157 return -ENOEXEC;
1158 }
1159
1160 SHELL_STATIC_SUBCMD_SET_CREATE(vcp_vol_ctlr_cmds,
1161 SHELL_CMD_ARG(discover, NULL,
1162 "Discover VCP and included services for current "
1163 "connection",
1164 cmd_vcp_vol_ctlr_discover, 1, 0),
1165 SHELL_CMD_ARG(state_get, NULL,
1166 "Get volume state of the VCP server. Should be done "
1167 "before sending any control messages",
1168 cmd_vcp_vol_ctlr_state_get, 1, 0),
1169 SHELL_CMD_ARG(flags_get, NULL,
1170 "Read volume flags",
1171 cmd_vcp_vol_ctlr_flags_get, 1, 0),
1172 SHELL_CMD_ARG(volume_down, NULL,
1173 "Turn the volume down",
1174 cmd_vcp_vol_ctlr_volume_down, 1, 0),
1175 SHELL_CMD_ARG(volume_up, NULL,
1176 "Turn the volume up",
1177 cmd_vcp_vol_ctlr_volume_up, 1, 0),
1178 SHELL_CMD_ARG(unmute_volume_down, NULL,
1179 "Turn the volume down, and unmute",
1180 cmd_vcp_vol_ctlr_unmute_volume_down, 1, 0),
1181 SHELL_CMD_ARG(unmute_volume_up, NULL,
1182 "Turn the volume up, and unmute",
1183 cmd_vcp_vol_ctlr_unmute_volume_up, 1, 0),
1184 SHELL_CMD_ARG(volume_set, NULL,
1185 "Set an absolute volume <volume>",
1186 cmd_vcp_vol_ctlr_volume_set, 2, 0),
1187 SHELL_CMD_ARG(unmute, NULL,
1188 "Unmute",
1189 cmd_vcp_vol_ctlr_unmute, 1, 0),
1190 SHELL_CMD_ARG(mute, NULL,
1191 "Mute",
1192 cmd_vcp_vol_ctlr_mute, 1, 0),
1193 SHELL_CMD_ARG(vocs_state_get, NULL,
1194 "Get the offset state of a VOCS instance <inst_index>",
1195 cmd_vcp_vol_ctlr_vocs_state_get, 2, 0),
1196 SHELL_CMD_ARG(vocs_location_get, NULL,
1197 "Get the location of a VOCS instance <inst_index>",
1198 cmd_vcp_vol_ctlr_vocs_location_get, 2, 0),
1199 SHELL_CMD_ARG(vocs_location_set, NULL,
1200 "Set the location of a VOCS instance <inst_index> "
1201 "<location>",
1202 cmd_vcp_vol_ctlr_vocs_location_set, 3, 0),
1203 SHELL_CMD_ARG(vocs_offset_set, NULL,
1204 "Set the offset for a VOCS instance <inst_index> "
1205 "<offset>",
1206 cmd_vcp_vol_ctlr_vocs_offset_set, 3, 0),
1207 SHELL_CMD_ARG(vocs_output_description_get, NULL,
1208 "Get the output description of a VOCS instance "
1209 "<inst_index>",
1210 cmd_vcp_vol_ctlr_vocs_output_description_get, 2, 0),
1211 SHELL_CMD_ARG(vocs_output_description_set, NULL,
1212 "Set the output description of a VOCS instance "
1213 "<inst_index> <description>",
1214 cmd_vcp_vol_ctlr_vocs_output_description_set, 3, 0),
1215 SHELL_CMD_ARG(aics_input_state_get, NULL,
1216 "Get the input state of a AICS instance <inst_index>",
1217 cmd_vcp_vol_ctlr_aics_input_state_get, 2, 0),
1218 SHELL_CMD_ARG(aics_gain_setting_get, NULL,
1219 "Get the gain settings of a AICS instance <inst_index>",
1220 cmd_vcp_vol_ctlr_aics_gain_setting_get, 2, 0),
1221 SHELL_CMD_ARG(aics_input_type_get, NULL,
1222 "Get the input type of a AICS instance <inst_index>",
1223 cmd_vcp_vol_ctlr_aics_input_type_get, 2, 0),
1224 SHELL_CMD_ARG(aics_input_status_get, NULL,
1225 "Get the input status of a AICS instance <inst_index>",
1226 cmd_vcp_vol_ctlr_aics_input_status_get, 2, 0),
1227 SHELL_CMD_ARG(aics_input_unmute, NULL,
1228 "Unmute the input of a AICS instance <inst_index>",
1229 cmd_vcp_vol_ctlr_aics_input_unmute, 2, 0),
1230 SHELL_CMD_ARG(aics_input_mute, NULL,
1231 "Mute the input of a AICS instance <inst_index>",
1232 cmd_vcp_vol_ctlr_aics_input_mute, 2, 0),
1233 SHELL_CMD_ARG(aics_manual_input_gain_set, NULL,
1234 "Set the gain mode of a AICS instance to manual "
1235 "<inst_index>",
1236 cmd_vcp_vol_ctlr_aics_manual_input_gain_set, 2, 0),
1237 SHELL_CMD_ARG(aics_automatic_input_gain_set, NULL,
1238 "Set the gain mode of a AICS instance to automatic "
1239 "<inst_index>",
1240 cmd_vcp_vol_ctlr_aics_auto_input_gain_set, 2, 0),
1241 SHELL_CMD_ARG(aics_gain_set, NULL,
1242 "Set the gain of a AICS instance <inst_index> <gain>",
1243 cmd_vcp_vol_ctlr_aics_gain_set, 3, 0),
1244 SHELL_CMD_ARG(aics_input_description_get, NULL,
1245 "Read the input description of a AICS instance "
1246 "<inst_index>",
1247 cmd_vcp_vol_ctlr_aics_input_description_get, 2, 0),
1248 SHELL_CMD_ARG(aics_input_description_set, NULL,
1249 "Set the input description of a AICS instance "
1250 "<inst_index> <description>",
1251 cmd_vcp_vol_ctlr_aics_input_description_set, 3, 0),
1252 SHELL_SUBCMD_SET_END
1253 );
1254
1255 SHELL_CMD_ARG_REGISTER(vcp_vol_ctlr, &vcp_vol_ctlr_cmds,
1256 "Bluetooth VCP client shell commands",
1257 cmd_vcp_vol_ctlr, 1, 1);
1258