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