1 /* btp_vcp.c - Bluetooth VCP Tester */
2 
3 /*
4  * Copyright (c) 2022 Codecoup
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/bluetooth/bluetooth.h>
13 #include <zephyr/bluetooth/audio/vcp.h>
14 #include <zephyr/bluetooth/audio/aics.h>
15 #include <zephyr/bluetooth/audio/vocs.h>
16 #include <zephyr/sys/util.h>
17 #include "btp/btp.h"
18 
19 #include <../../subsys/bluetooth/audio/micp_internal.h>
20 #include <../../subsys/bluetooth/audio/aics_internal.h>
21 #include <../../subsys/bluetooth/audio/vcp_internal.h>
22 #include <../../subsys/bluetooth/audio/vocs_internal.h>
23 #include <zephyr/logging/log.h>
24 
25 #define LOG_MODULE_NAME bttester_vcp
26 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
27 
28 #define BT_AICS_MAX_INPUT_DESCRIPTION_SIZE 16
29 #define BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE 16
30 
31 static struct bt_vcp_vol_rend_register_param vcp_register_param;
32 static struct bt_vcp_vol_ctlr *vol_ctlr;
33 static struct bt_vcp_included included;
34 extern struct btp_aics_instance aics_server_instance;
35 extern struct btp_aics_instance aics_client_instance;
36 extern struct bt_aics_cb aics_client_cb;
37 
38 struct service_handles {
39 	struct {
40 		uint16_t ctrl_pt;
41 		uint16_t flags;
42 		uint16_t state;
43 	} vcp_handles;
44 
45 	struct {
46 		uint16_t state;
47 		uint16_t location;
48 		uint16_t control;
49 		uint16_t desc;
50 	} vocs_handles;
51 
52 	struct {
53 		uint16_t mute;
54 		uint16_t state;
55 		uint16_t gain;
56 		uint16_t type;
57 		uint16_t status;
58 		uint16_t control;
59 		uint16_t desc;
60 	} aics_handles;
61 };
62 
63 struct service_handles chrc_handles;
64 
65 /* Volume Control Service */
vcs_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)66 static uint8_t vcs_supported_commands(const void *cmd, uint16_t cmd_len,
67 				      void *rsp, uint16_t *rsp_len)
68 {
69 	struct btp_vcs_read_supported_commands_rp *rp = rsp;
70 
71 	/* octet 0 */
72 	tester_set_bit(rp->data, BTP_VCS_READ_SUPPORTED_COMMANDS);
73 	tester_set_bit(rp->data, BTP_VCS_SET_VOL);
74 	tester_set_bit(rp->data, BTP_VCS_VOL_UP);
75 	tester_set_bit(rp->data, BTP_VCS_VOL_DOWN);
76 	tester_set_bit(rp->data, BTP_VCS_MUTE);
77 	tester_set_bit(rp->data, BTP_VCS_UNMUTE);
78 
79 	*rsp_len = sizeof(*rp) + 1;
80 
81 	return BTP_STATUS_SUCCESS;
82 }
83 
set_volume(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)84 static uint8_t set_volume(const void *cmd, uint16_t cmd_len,
85 			  void *rsp, uint16_t *rsp_len)
86 {
87 	const struct btp_vcs_set_vol_cmd *cp = cmd;
88 
89 	LOG_DBG("Set volume 0x%02x", cp->volume);
90 
91 	if (bt_vcp_vol_rend_set_vol(cp->volume) != 0) {
92 		return BTP_STATUS_FAILED;
93 	}
94 
95 	return BTP_STATUS_SUCCESS;
96 }
97 
vol_up(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)98 static uint8_t vol_up(const void *cmd, uint16_t cmd_len,
99 		      void *rsp, uint16_t *rsp_len)
100 {
101 	LOG_DBG("Volume Up");
102 
103 	if (bt_vcp_vol_rend_vol_up() != 0) {
104 		return BTP_STATUS_FAILED;
105 	}
106 
107 	return BTP_STATUS_SUCCESS;
108 }
109 
vol_down(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)110 static uint8_t vol_down(const void *cmd, uint16_t cmd_len,
111 			void *rsp, uint16_t *rsp_len)
112 {
113 	LOG_DBG("Volume Down");
114 
115 	if (bt_vcp_vol_rend_vol_down() != 0) {
116 		return BTP_STATUS_FAILED;
117 	}
118 
119 	return BTP_STATUS_SUCCESS;
120 }
121 
mute(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)122 static uint8_t mute(const void *cmd, uint16_t cmd_len,
123 		    void *rsp, uint16_t *rsp_len)
124 {
125 	LOG_DBG("Mute");
126 
127 	if (bt_vcp_vol_rend_mute() != 0) {
128 		return BTP_STATUS_FAILED;
129 	}
130 
131 	return BTP_STATUS_SUCCESS;
132 }
133 
unmute(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)134 static uint8_t unmute(const void *cmd, uint16_t cmd_len,
135 		      void *rsp, uint16_t *rsp_len)
136 {
137 	LOG_DBG("Unmute");
138 
139 	if (bt_vcp_vol_rend_unmute() != 0) {
140 		return BTP_STATUS_FAILED;
141 	}
142 
143 	return BTP_STATUS_SUCCESS;
144 }
145 
vcs_state_cb(struct bt_conn * conn,int err,uint8_t volume,uint8_t mute)146 static void vcs_state_cb(struct bt_conn *conn, int err, uint8_t volume, uint8_t mute)
147 {
148 	LOG_DBG("VCP state cb err (%d)", err);
149 }
150 
vcs_flags_cb(struct bt_conn * conn,int err,uint8_t flags)151 static void vcs_flags_cb(struct bt_conn *conn, int err, uint8_t flags)
152 {
153 	LOG_DBG("VCP flags cb err (%d)", err);
154 }
155 
156 static struct bt_vcp_vol_rend_cb vcs_cb = {
157 	.state = vcs_state_cb,
158 	.flags = vcs_flags_cb,
159 };
160 
161 static const struct btp_handler vcs_handlers[] = {
162 	{
163 		.opcode = BTP_VCS_READ_SUPPORTED_COMMANDS,
164 		.index = BTP_INDEX_NONE,
165 		.expect_len = 0,
166 		.func = vcs_supported_commands,
167 	},
168 	{
169 		.opcode = BTP_VCS_SET_VOL,
170 		.expect_len = sizeof(struct btp_vcs_set_vol_cmd),
171 		.func = set_volume,
172 	},
173 	{
174 		.opcode = BTP_VCS_VOL_UP,
175 		.expect_len = 0,
176 		.func = vol_up,
177 	},
178 	{
179 		.opcode = BTP_VCS_VOL_DOWN,
180 		.expect_len = 0,
181 		.func = vol_down,
182 	},
183 	{
184 		.opcode = BTP_VCS_MUTE,
185 		.expect_len = 0,
186 		.func = mute,
187 	},
188 	{
189 		.opcode = BTP_VCS_UNMUTE,
190 		.expect_len = 0,
191 		.func = unmute,
192 	},
193 };
194 
195 /* Volume Offset Control Service */
vocs_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)196 static uint8_t vocs_supported_commands(const void *cmd, uint16_t cmd_len,
197 				       void *rsp, uint16_t *rsp_len)
198 {
199 	struct btp_vocs_read_supported_commands_rp *rp = rsp;
200 
201 	/* octet 0 */
202 	tester_set_bit(rp->data, BTP_VOCS_READ_SUPPORTED_COMMANDS);
203 	tester_set_bit(rp->data, BTP_VOCS_UPDATE_LOC);
204 	tester_set_bit(rp->data, BTP_VOCS_UPDATE_DESC);
205 	tester_set_bit(rp->data, BTP_VOCS_STATE_GET);
206 	tester_set_bit(rp->data, BTP_VOCS_LOCATION_GET);
207 	tester_set_bit(rp->data, BTP_VOCS_OFFSET_STATE_SET);
208 
209 	*rsp_len = sizeof(*rp) + 1;
210 
211 	return BTP_STATUS_SUCCESS;
212 }
213 
vocs_state_cb(struct bt_vocs * inst,int err,int16_t offset)214 static void vocs_state_cb(struct bt_vocs *inst, int err, int16_t offset)
215 {
216 	LOG_DBG("VOCS state callback err (%d)", err);
217 }
218 
vocs_location_cb(struct bt_vocs * inst,int err,uint32_t location)219 static void vocs_location_cb(struct bt_vocs *inst, int err, uint32_t location)
220 {
221 	LOG_DBG("VOCS location callback err (%d)", err);
222 }
223 
vocs_description_cb(struct bt_vocs * inst,int err,char * description)224 static void vocs_description_cb(struct bt_vocs *inst, int err,
225 				char *description)
226 {
227 	LOG_DBG("VOCS desctripion callback (%d)", err);
228 }
229 
230 static struct bt_vocs_cb vocs_cb = {
231 	.state = vocs_state_cb,
232 	.location = vocs_location_cb,
233 	.description = vocs_description_cb
234 };
235 
btp_send_vocs_state_ev(struct bt_conn * conn,uint8_t att_status,int16_t offset)236 static void btp_send_vocs_state_ev(struct bt_conn *conn, uint8_t att_status, int16_t offset)
237 {
238 	struct btp_vocs_offset_state_ev ev;
239 
240 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
241 
242 	ev.att_status = att_status;
243 	ev.offset = sys_cpu_to_le16(offset);
244 
245 	tester_event(BTP_SERVICE_ID_VOCS, BTP_VOCS_OFFSET_STATE_EV, &ev, sizeof(ev));
246 }
247 
btp_send_vocs_location_ev(struct bt_conn * conn,uint8_t att_status,uint32_t location)248 static void btp_send_vocs_location_ev(struct bt_conn *conn, uint8_t att_status, uint32_t location)
249 {
250 	struct btp_vocs_audio_location_ev ev;
251 
252 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
253 
254 	ev.att_status = att_status;
255 	ev.location = sys_cpu_to_le32(location);
256 
257 	tester_event(BTP_SERVICE_ID_VOCS, BTP_VOCS_AUDIO_LOCATION_EV, &ev, sizeof(ev));
258 }
259 
btp_send_vocs_procedure_ev(struct bt_conn * conn,uint8_t att_status,uint8_t opcode)260 static void btp_send_vocs_procedure_ev(struct bt_conn *conn, uint8_t att_status, uint8_t opcode)
261 {
262 	struct btp_vocs_procedure_ev ev;
263 
264 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
265 
266 	ev.att_status = att_status;
267 	ev.opcode = opcode;
268 
269 	tester_event(BTP_SERVICE_ID_VOCS, BTP_VOCS_PROCEDURE_EV, &ev, sizeof(ev));
270 }
271 
vcp_vocs_state_cb(struct bt_vocs * inst,int err,int16_t offset)272 static void vcp_vocs_state_cb(struct bt_vocs *inst, int err, int16_t offset)
273 {
274 	struct bt_conn *conn;
275 
276 	bt_vocs_client_conn_get(inst, &conn);
277 	btp_send_vocs_state_ev(conn, err, offset);
278 
279 	LOG_DBG("VOCS Offset State callback");
280 }
281 
vcp_vocs_location_cb(struct bt_vocs * inst,int err,uint32_t location)282 static void vcp_vocs_location_cb(struct bt_vocs *inst, int err, uint32_t location)
283 {
284 	struct bt_conn *conn;
285 
286 	bt_vocs_client_conn_get(inst, &conn);
287 	btp_send_vocs_location_ev(conn, err, location);
288 
289 	LOG_DBG("VOCS location callback err (%d)", err);
290 }
291 
vcp_vocs_description_cb(struct bt_vocs * inst,int err,char * description)292 static void vcp_vocs_description_cb(struct bt_vocs *inst, int err,
293 				char *description)
294 {
295 	LOG_DBG("VOCS desctripion callback (%d)", err);
296 }
297 
vcp_vocs_set_offset_cb(struct bt_vocs * inst,int err)298 static void vcp_vocs_set_offset_cb(struct bt_vocs *inst, int err)
299 {
300 	struct bt_conn *conn;
301 
302 	bt_vocs_client_conn_get(inst, &conn);
303 	btp_send_vocs_procedure_ev(conn, err, BTP_VOCS_OFFSET_STATE_SET);
304 
305 	LOG_DBG("VOCS Set Offset callback (%d)", err);
306 }
307 
308 static struct bt_vocs_cb vocs_cl_cb = {
309 	.state = vcp_vocs_state_cb,
310 	.location = vcp_vocs_location_cb,
311 	.description = vcp_vocs_description_cb,
312 #if defined(CONFIG_BT_VOCS_CLIENT)
313 	.set_offset = vcp_vocs_set_offset_cb
314 #endif /* CONFIG_BT_VOCS_CLIENT */
315 };
316 
vocs_audio_desc(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)317 static uint8_t vocs_audio_desc(const void *cmd, uint16_t cmd_len,
318 			       void *rsp, uint16_t *rsp_len)
319 {
320 	const struct btp_vocs_audio_desc_cmd *cp = cmd;
321 	char description[BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE];
322 
323 	if (cmd_len < sizeof(*cp) ||
324 	    cmd_len != sizeof(*cp) + cp->desc_len) {
325 		return BTP_STATUS_FAILED;
326 	}
327 
328 	if (cp->desc_len >= sizeof(description)) {
329 		return BTP_STATUS_FAILED;
330 	}
331 
332 	memcpy(description, cp->desc, cp->desc_len);
333 	description[cp->desc_len] = '\0';
334 
335 	for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT; i++) {
336 		if (bt_vocs_description_set(included.vocs[i], description) != 0) {
337 			return BTP_STATUS_FAILED;
338 		}
339 	}
340 
341 	return BTP_STATUS_SUCCESS;
342 }
343 
vocs_audio_loc(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)344 static uint8_t vocs_audio_loc(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
345 {
346 	const struct btp_vocs_audio_loc_cmd *cp = cmd;
347 	uint32_t loc = sys_le32_to_cpu(cp->loc);
348 
349 	for (uint8_t i = 0; i < included.vocs_cnt; i++) {
350 		if (bt_vocs_location_set(included.vocs[i], loc) != 0) {
351 			return BTP_STATUS_FAILED;
352 		}
353 	}
354 
355 	return BTP_STATUS_SUCCESS;
356 }
357 
vocs_state_get(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)358 static uint8_t vocs_state_get(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
359 {
360 	int err;
361 
362 	LOG_DBG("Volume Offset Control Service offset state get");
363 
364 	err = bt_vocs_state_get(included.vocs[0]);
365 	if (err) {
366 		return BTP_STATUS_FAILED;
367 	}
368 
369 	return BTP_STATUS_SUCCESS;
370 }
371 
vocs_state_set(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)372 static uint8_t vocs_state_set(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
373 {
374 	const struct btp_vocs_offset_set_cmd *cp = cmd;
375 	int16_t offset = sys_le16_to_cpu(cp->offset);
376 	int err;
377 
378 	LOG_DBG("VCP CTLR Set absolute volume %d", offset);
379 
380 	err = bt_vocs_state_set(included.vocs[0], cp->offset);
381 	if (err) {
382 		return BTP_STATUS_FAILED;
383 	}
384 
385 	return BTP_STATUS_SUCCESS;
386 }
387 
vocs_audio_location_get(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)388 static uint8_t vocs_audio_location_get(const void *cmd, uint16_t cmd_len, void *rsp,
389 				       uint16_t *rsp_len)
390 {
391 	int err;
392 
393 	LOG_DBG("Volume Offset Control Service Audio Location get");
394 
395 	err = bt_vocs_location_get(included.vocs[0]);
396 	if (err) {
397 		return BTP_STATUS_FAILED;
398 	}
399 
400 	return BTP_STATUS_SUCCESS;
401 }
402 
403 static const struct btp_handler vocs_handlers[] = {
404 	{
405 		.opcode = BTP_VOCS_READ_SUPPORTED_COMMANDS,
406 		.index = BTP_INDEX_NONE,
407 		.expect_len = 0,
408 		.func = vocs_supported_commands,
409 	},
410 	{
411 		.opcode = BTP_VOCS_UPDATE_DESC,
412 		.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
413 		.func = vocs_audio_desc,
414 	},
415 	{
416 		.opcode = BTP_VOCS_UPDATE_LOC,
417 		.expect_len = sizeof(struct btp_vocs_audio_loc_cmd),
418 		.func = vocs_audio_loc,
419 	},
420 	{
421 		.opcode = BTP_VOCS_STATE_GET,
422 		.expect_len = sizeof(struct btp_vocs_state_get_cmd),
423 		.func = vocs_state_get,
424 	},
425 	{
426 		.opcode = BTP_VOCS_LOCATION_GET,
427 		.expect_len = sizeof(struct btp_vocs_location_get_cmd),
428 		.func = vocs_audio_location_get,
429 	},
430 	{
431 		.opcode = BTP_VOCS_OFFSET_STATE_SET,
432 		.expect_len = sizeof(struct btp_vocs_offset_set_cmd),
433 		.func = vocs_state_set,
434 	},
435 };
436 
437 /* AICS Callbacks */
aics_state_cb(struct bt_aics * inst,int err,int8_t gain,uint8_t mute,uint8_t mode)438 static void aics_state_cb(struct bt_aics *inst, int err, int8_t gain,
439 			  uint8_t mute, uint8_t mode)
440 {
441 	LOG_DBG("AICS state callback (%d)", err);
442 }
443 
aics_gain_setting_cb(struct bt_aics * inst,int err,uint8_t units,int8_t minimum,int8_t maximum)444 static void aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
445 				 int8_t minimum, int8_t maximum)
446 {
447 	LOG_DBG("AICS gain setting callback (%d)", err);
448 }
449 
aics_input_type_cb(struct bt_aics * inst,int err,uint8_t input_type)450 static void aics_input_type_cb(struct bt_aics *inst, int err,
451 			       uint8_t input_type)
452 {
453 	LOG_DBG("AICS input type callback (%d)", err);
454 }
455 
aics_status_cb(struct bt_aics * inst,int err,bool active)456 static void aics_status_cb(struct bt_aics *inst, int err, bool active)
457 {
458 	LOG_DBG("AICS status callback (%d)", err);
459 }
460 
aics_description_cb(struct bt_aics * inst,int err,char * description)461 static void aics_description_cb(struct bt_aics *inst, int err,
462 				char *description)
463 {
464 	LOG_DBG("AICS description callback (%d)", err);
465 }
466 
467 struct bt_aics_cb aics_server_cb = {
468 	.state = aics_state_cb,
469 	.gain_setting = aics_gain_setting_cb,
470 	.type = aics_input_type_cb,
471 	.status = aics_status_cb,
472 	.description = aics_description_cb,
473 };
474 
475 /* General profile handling */
set_register_params(uint8_t gain_mode)476 static void set_register_params(uint8_t gain_mode)
477 {
478 	char input_desc[CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT]
479 		       [BT_AICS_MAX_INPUT_DESCRIPTION_SIZE];
480 	char output_desc[CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT]
481 			[BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE];
482 
483 	memset(&vcp_register_param, 0, sizeof(vcp_register_param));
484 
485 	for (size_t i = 0; i < ARRAY_SIZE(vcp_register_param.vocs_param); i++) {
486 		vcp_register_param.vocs_param[i].location_writable = true;
487 		vcp_register_param.vocs_param[i].desc_writable = true;
488 		snprintf(output_desc[i], sizeof(output_desc[i]),
489 			 "Output %zu", i + 1);
490 		vcp_register_param.vocs_param[i].output_desc = output_desc[i];
491 		vcp_register_param.vocs_param[i].cb = &vocs_cb;
492 	}
493 
494 	for (size_t i = 0; i < ARRAY_SIZE(vcp_register_param.aics_param); i++) {
495 		vcp_register_param.aics_param[i].desc_writable = true;
496 		snprintf(input_desc[i], sizeof(input_desc[i]),
497 			 "Input %zu", i + 1);
498 		vcp_register_param.aics_param[i].description = input_desc[i];
499 		vcp_register_param.aics_param[i].type = BT_AICS_INPUT_TYPE_DIGITAL;
500 		vcp_register_param.aics_param[i].status = 1;
501 		vcp_register_param.aics_param[i].gain_mode = gain_mode;
502 		vcp_register_param.aics_param[i].units = 1;
503 		vcp_register_param.aics_param[i].min_gain = 0;
504 		vcp_register_param.aics_param[i].max_gain = 100;
505 		vcp_register_param.aics_param[i].cb = &aics_server_cb;
506 	}
507 
508 	vcp_register_param.step = 1;
509 	vcp_register_param.mute = BT_VCP_STATE_UNMUTED;
510 	vcp_register_param.volume = 100;
511 	vcp_register_param.cb = &vcs_cb;
512 }
513 
tester_init_vcs(void)514 uint8_t tester_init_vcs(void)
515 {
516 	int err;
517 
518 	set_register_params(BT_AICS_MODE_MANUAL);
519 
520 	err = bt_vcp_vol_rend_register(&vcp_register_param);
521 	if (err) {
522 		return BTP_STATUS_FAILED;
523 	}
524 
525 	err = bt_vcp_vol_rend_included_get(&included);
526 	if (err) {
527 		return BTP_STATUS_FAILED;
528 	}
529 
530 	aics_server_instance.aics_cnt = included.aics_cnt;
531 	aics_server_instance.aics = included.aics;
532 
533 	tester_register_command_handlers(BTP_SERVICE_ID_VCS, vcs_handlers,
534 					 ARRAY_SIZE(vcs_handlers));
535 
536 	return BTP_STATUS_SUCCESS;
537 }
538 
tester_unregister_vcs(void)539 uint8_t tester_unregister_vcs(void)
540 {
541 	return BTP_STATUS_SUCCESS;
542 }
543 
tester_init_vocs(void)544 uint8_t tester_init_vocs(void)
545 {
546 	tester_register_command_handlers(BTP_SERVICE_ID_VOCS, vocs_handlers,
547 					 ARRAY_SIZE(vocs_handlers));
548 
549 	return BTP_STATUS_SUCCESS;
550 }
551 
tester_unregister_vocs(void)552 uint8_t tester_unregister_vocs(void)
553 {
554 	return BTP_STATUS_SUCCESS;
555 }
556 
557 /* Volume Control Profile */
btp_send_vcp_found_ev(struct bt_conn * conn,uint8_t att_status,const struct service_handles * chrc_handles)558 static void btp_send_vcp_found_ev(struct bt_conn *conn, uint8_t att_status,
559 				  const struct service_handles *chrc_handles)
560 {
561 	struct btp_vcp_discovered_ev ev;
562 
563 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
564 
565 	ev.att_status = att_status;
566 	ev.vcs_handles.control_handle = sys_cpu_to_le16(chrc_handles->vcp_handles.ctrl_pt);
567 	ev.vcs_handles.flag_handle = sys_cpu_to_le16(chrc_handles->vcp_handles.flags);
568 	ev.vcs_handles.state_handle = sys_cpu_to_le16(chrc_handles->vcp_handles.state);
569 	ev.vocs_handles.state_handle = sys_cpu_to_le16(chrc_handles->vocs_handles.state);
570 	ev.vocs_handles.location_handle = sys_cpu_to_le16(chrc_handles->vocs_handles.location);
571 	ev.vocs_handles.control_handle = sys_cpu_to_le16(chrc_handles->vocs_handles.control);
572 	ev.vocs_handles.desc_handle = sys_cpu_to_le16(chrc_handles->vocs_handles.desc);
573 	ev.aics_handles.state_handle = sys_cpu_to_le16(chrc_handles->aics_handles.state);
574 	ev.aics_handles.gain_handle = sys_cpu_to_le16(chrc_handles->aics_handles.gain);
575 	ev.aics_handles.type_handle = sys_cpu_to_le16(chrc_handles->aics_handles.type);
576 	ev.aics_handles.status_handle = sys_cpu_to_le16(chrc_handles->aics_handles.status);
577 	ev.aics_handles.control_handle = sys_cpu_to_le16(chrc_handles->aics_handles.control);
578 	ev.aics_handles.desc_handle = sys_cpu_to_le16(chrc_handles->aics_handles.desc);
579 
580 	tester_event(BTP_SERVICE_ID_VCP, BTP_VCP_DISCOVERED_EV, &ev, sizeof(ev));
581 }
582 
btp_send_vcp_state_ev(struct bt_conn * conn,uint8_t att_status,uint8_t volume,uint8_t mute)583 static void btp_send_vcp_state_ev(struct bt_conn *conn, uint8_t att_status, uint8_t volume,
584 				  uint8_t mute)
585 {
586 	struct btp_vcp_state_ev ev;
587 
588 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
589 
590 	ev.att_status = att_status;
591 	ev.volume = volume;
592 	ev.mute = mute;
593 
594 	tester_event(BTP_SERVICE_ID_VCP, BTP_VCP_STATE_EV, &ev, sizeof(ev));
595 }
596 
btp_send_vcp_volume_flags_ev(struct bt_conn * conn,uint8_t att_status,uint8_t flags)597 static void btp_send_vcp_volume_flags_ev(struct bt_conn *conn, uint8_t att_status, uint8_t flags)
598 {
599 	struct btp_vcp_volume_flags_ev ev;
600 
601 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
602 
603 	ev.att_status = att_status;
604 	ev.flags = flags;
605 
606 	tester_event(BTP_SERVICE_ID_VCP, BTP_VCP_FLAGS_EV, &ev, sizeof(ev));
607 }
608 
btp_send_vcp_procedure_ev(struct bt_conn * conn,uint8_t att_status,uint8_t opcode)609 static void btp_send_vcp_procedure_ev(struct bt_conn *conn, uint8_t att_status, uint8_t opcode)
610 {
611 	struct btp_vcp_procedure_ev ev;
612 
613 	bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
614 
615 	ev.att_status = att_status;
616 	ev.opcode = opcode;
617 
618 	tester_event(BTP_SERVICE_ID_VCP, BTP_VCP_PROCEDURE_EV, &ev, sizeof(ev));
619 }
620 
vcp_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)621 static uint8_t vcp_supported_commands(const void *cmd, uint16_t cmd_len,
622 				      void *rsp, uint16_t *rsp_len)
623 {
624 	struct btp_vcp_read_supported_commands_rp *rp = rsp;
625 
626 	/* octet 0 */
627 	tester_set_bit(rp->data, BTP_VCP_READ_SUPPORTED_COMMANDS);
628 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_DISCOVER);
629 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_STATE_READ);
630 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_FLAGS_READ);
631 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_VOL_DOWN);
632 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_VOL_UP);
633 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_UNMUTE_VOL_DOWN);
634 
635 	/* octet 1 */
636 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_UNMUTE_VOL_UP);
637 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_SET_VOL);
638 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_UNMUTE);
639 	tester_set_bit(rp->data, BTP_VCP_VOL_CTLR_MUTE);
640 
641 	*rsp_len = sizeof(*rp) + 1;
642 
643 	return BTP_STATUS_SUCCESS;
644 }
645 
vcp_vol_ctlr_discover_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t vocs_count,uint8_t aics_count)646 static void vcp_vol_ctlr_discover_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t vocs_count,
647 				     uint8_t aics_count)
648 {
649 	struct bt_conn *conn;
650 
651 	if (err) {
652 		LOG_DBG("Discovery failed (%d)", err);
653 		return;
654 	}
655 
656 	LOG_DBG("Discovery done with %u VOCS, %u AICS",
657 		vocs_count, aics_count);
658 
659 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
660 
661 	if (bt_vcp_vol_ctlr_included_get(vol_ctlr, &included) != 0) {
662 		LOG_DBG("Could not get included services");
663 		memset(&chrc_handles.vocs_handles, 0, sizeof(chrc_handles.vocs_handles));
664 		memset(&chrc_handles.aics_handles, 0, sizeof(chrc_handles.aics_handles));
665 	} else {
666 		aics_client_instance.aics_cnt = included.aics_cnt;
667 		aics_client_instance.aics = included.aics;
668 		bt_vocs_client_cb_register(vol_ctlr->vocs[0], &vocs_cl_cb);
669 		bt_aics_client_cb_register(vol_ctlr->aics[0], &aics_client_cb);
670 
671 		struct bt_vocs_client *vocs_cli =
672 			CONTAINER_OF(vol_ctlr->vocs[0], struct bt_vocs_client, vocs);
673 		struct bt_aics_client *aics_cli = &vol_ctlr->aics[0]->cli;
674 
675 		chrc_handles.vocs_handles.state = vocs_cli->state_handle;
676 		chrc_handles.vocs_handles.location = vocs_cli->location_handle;
677 		chrc_handles.vocs_handles.control = vocs_cli->control_handle;
678 		chrc_handles.vocs_handles.desc = vocs_cli->desc_handle;
679 		chrc_handles.aics_handles.state = aics_cli->state_handle;
680 		chrc_handles.aics_handles.gain = aics_cli->gain_handle;
681 		chrc_handles.aics_handles.type = aics_cli->type_handle;
682 		chrc_handles.aics_handles.status = aics_cli->status_handle;
683 		chrc_handles.aics_handles.control = aics_cli->control_handle;
684 		chrc_handles.aics_handles.desc = aics_cli->desc_handle;
685 	}
686 
687 	chrc_handles.vcp_handles.ctrl_pt = vol_ctlr->control_handle;
688 	chrc_handles.vcp_handles.flags = vol_ctlr->vol_flag_handle;
689 	chrc_handles.vcp_handles.state = vol_ctlr->state_handle;
690 	btp_send_vcp_found_ev(conn, err, &chrc_handles);
691 }
692 
vcp_vol_ctlr_state_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t volume,uint8_t mute)693 static void vcp_vol_ctlr_state_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t volume,
694 				  uint8_t mute)
695 {
696 	struct bt_conn *conn;
697 
698 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
699 	btp_send_vcp_state_ev(conn, err, volume, mute);
700 
701 	LOG_DBG("VCP Volume CTLR State callback");
702 }
703 
vcp_vol_ctlr_flags_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t flags)704 static void vcp_vol_ctlr_flags_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err, uint8_t flags)
705 {
706 	struct bt_conn *conn;
707 
708 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
709 	btp_send_vcp_volume_flags_ev(conn, err, flags);
710 
711 	LOG_DBG("VCP CTLR Volume Flags callback");
712 }
713 
vcp_vol_ctlr_vol_down_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)714 static void vcp_vol_ctlr_vol_down_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
715 {
716 	struct bt_conn *conn;
717 
718 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
719 	btp_send_vcp_procedure_ev(conn, err, BTP_VCP_VOL_CTLR_VOL_DOWN);
720 
721 	LOG_DBG("VCP CTLR Volume down callback");
722 }
723 
vcp_vol_ctlr_vol_up_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)724 static void vcp_vol_ctlr_vol_up_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
725 {
726 	struct bt_conn *conn;
727 
728 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
729 	btp_send_vcp_procedure_ev(conn, err, BTP_VCP_VOL_CTLR_VOL_UP);
730 
731 	LOG_DBG("VCP CTLR Volume down callback");
732 }
733 
vcp_vol_ctlr_unmute_vol_down_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)734 static void vcp_vol_ctlr_unmute_vol_down_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
735 {
736 	struct bt_conn *conn;
737 
738 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
739 	btp_send_vcp_procedure_ev(conn, err, BTP_VCP_VOL_CTLR_UNMUTE_VOL_DOWN);
740 
741 	LOG_DBG("VCP CTLR Volume down and unmute callback");
742 }
743 
vcp_vol_ctlr_unmute_vol_up_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)744 static void vcp_vol_ctlr_unmute_vol_up_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
745 {
746 	struct bt_conn *conn;
747 
748 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
749 	btp_send_vcp_procedure_ev(conn, err, BTP_VCP_VOL_CTLR_UNMUTE_VOL_UP);
750 
751 	LOG_DBG("VCP CTLR Volume down and unmute callback");
752 }
753 
vcp_vol_ctlr_set_vol_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)754 static void vcp_vol_ctlr_set_vol_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
755 {
756 	struct bt_conn *conn;
757 
758 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
759 	btp_send_vcp_procedure_ev(conn, err, BTP_VCP_VOL_CTLR_SET_VOL);
760 
761 	LOG_DBG("VCP CTLR Set absolute volume callback");
762 }
763 
vcp_vol_ctlr_unmute_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)764 static void vcp_vol_ctlr_unmute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
765 {
766 	struct bt_conn *conn;
767 
768 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
769 	btp_send_vcp_procedure_ev(conn, err, BTP_VCP_VOL_CTLR_UNMUTE);
770 
771 	LOG_DBG("VCP CTLR Volume down and unmute callback");
772 }
773 
vcp_vol_ctlr_mute_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)774 static void vcp_vol_ctlr_mute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
775 {
776 	struct bt_conn *conn;
777 
778 	bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
779 	btp_send_vcp_procedure_ev(conn, err, BTP_VCP_VOL_CTLR_MUTE);
780 
781 	LOG_DBG("VCP CTLR Set absolute volume callback");
782 }
783 
784 static struct bt_vcp_vol_ctlr_cb vcp_cbs = {
785 	.discover = vcp_vol_ctlr_discover_cb,
786 	.state = vcp_vol_ctlr_state_cb,
787 	.flags = vcp_vol_ctlr_flags_cb,
788 	.vol_down = vcp_vol_ctlr_vol_down_cb,
789 	.vol_up = vcp_vol_ctlr_vol_up_cb,
790 	.mute = vcp_vol_ctlr_mute_cb,
791 	.unmute = vcp_vol_ctlr_unmute_cb,
792 	.vol_down_unmute = vcp_vol_ctlr_unmute_vol_down_cb,
793 	.vol_up_unmute = vcp_vol_ctlr_unmute_vol_up_cb,
794 	.vol_set = vcp_vol_ctlr_set_vol_cb
795 };
796 
vcp_discover(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)797 static uint8_t vcp_discover(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
798 {
799 	const struct btp_vcp_discover_cmd *cp = cmd;
800 	struct bt_conn *conn;
801 	int err;
802 
803 	conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
804 	if (!conn) {
805 		LOG_ERR("Unknown connection");
806 		return BTP_STATUS_FAILED;
807 	}
808 
809 	err = bt_vcp_vol_ctlr_discover(conn, &vol_ctlr);
810 	if (err) {
811 		LOG_DBG("Fail: %d", err);
812 		return BTP_STATUS_FAILED;
813 	}
814 
815 	return BTP_STATUS_SUCCESS;
816 }
817 
vcp_state_read(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)818 static uint8_t vcp_state_read(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
819 {
820 	int err;
821 
822 	LOG_DBG("VCP State read");
823 
824 	err = bt_vcp_vol_ctlr_read_state(vol_ctlr);
825 	if (err) {
826 		return BTP_STATUS_FAILED;
827 	}
828 
829 	return BTP_STATUS_SUCCESS;
830 }
831 
vcp_volume_flags_read(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)832 static uint8_t vcp_volume_flags_read(const void *cmd, uint16_t cmd_len, void *rsp,
833 				     uint16_t *rsp_len)
834 {
835 	int err;
836 
837 	LOG_DBG("VCP Volume Flags read");
838 
839 	err = bt_vcp_vol_ctlr_read_flags(vol_ctlr);
840 	if (err) {
841 		return BTP_STATUS_FAILED;
842 	}
843 
844 	return BTP_STATUS_SUCCESS;
845 }
846 
vcp_ctlr_vol_down(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)847 static uint8_t vcp_ctlr_vol_down(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
848 {
849 	int err;
850 
851 	LOG_DBG("VCP CTLR Volume down");
852 
853 	err = bt_vcp_vol_ctlr_vol_down(vol_ctlr);
854 	if (err) {
855 		return BTP_STATUS_FAILED;
856 	}
857 
858 	return BTP_STATUS_SUCCESS;
859 }
860 
vcp_ctlr_vol_up(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)861 static uint8_t vcp_ctlr_vol_up(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
862 {
863 	int err;
864 
865 	LOG_DBG("VCP CTLR Volume up");
866 
867 	err = bt_vcp_vol_ctlr_vol_up(vol_ctlr);
868 	if (err) {
869 		return BTP_STATUS_FAILED;
870 	}
871 
872 	return BTP_STATUS_SUCCESS;
873 }
874 
vcp_ctlr_unmute_vol_down(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)875 static uint8_t vcp_ctlr_unmute_vol_down(const void *cmd, uint16_t cmd_len, void *rsp,
876 					uint16_t *rsp_len)
877 {
878 	int err;
879 
880 	LOG_DBG("VCP CTLR Unmute, vol down");
881 
882 	err = bt_vcp_vol_ctlr_unmute_vol_down(vol_ctlr);
883 	if (err) {
884 		return BTP_STATUS_FAILED;
885 	}
886 
887 	return BTP_STATUS_SUCCESS;
888 }
889 
vcp_ctlr_unmute_vol_up(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)890 static uint8_t vcp_ctlr_unmute_vol_up(const void *cmd, uint16_t cmd_len, void *rsp,
891 				      uint16_t *rsp_len)
892 {
893 	int err;
894 
895 	LOG_DBG("VCP CTLR Unmute, Volume up");
896 
897 	err = bt_vcp_vol_ctlr_unmute_vol_up(vol_ctlr);
898 	if (err) {
899 		return BTP_STATUS_FAILED;
900 	}
901 
902 	return BTP_STATUS_SUCCESS;
903 }
904 
vcp_ctlr_set_vol(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)905 static uint8_t vcp_ctlr_set_vol(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
906 {
907 	const struct btp_vcp_ctlr_set_vol_cmd *cp = cmd;
908 	int err;
909 
910 	LOG_DBG("VCP CTLR Set absolute volume %d", cp->volume);
911 
912 	err = bt_vcp_vol_ctlr_set_vol(vol_ctlr, cp->volume);
913 	if (err) {
914 		return BTP_STATUS_FAILED;
915 	}
916 
917 	return BTP_STATUS_SUCCESS;
918 }
919 
vcp_ctlr_unmute(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)920 static uint8_t vcp_ctlr_unmute(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
921 {
922 	int err;
923 
924 	LOG_DBG("VCP CTLR Unmute");
925 
926 	err = bt_vcp_vol_ctlr_unmute(vol_ctlr);
927 	if (err) {
928 		return BTP_STATUS_FAILED;
929 	}
930 
931 	return BTP_STATUS_SUCCESS;
932 }
933 
vcp_ctlr_mute(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)934 static uint8_t vcp_ctlr_mute(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
935 {
936 	int err;
937 
938 	LOG_DBG("VCP CTLR Mute");
939 
940 	err = bt_vcp_vol_ctlr_mute(vol_ctlr);
941 	if (err) {
942 		return BTP_STATUS_FAILED;
943 	}
944 
945 	return BTP_STATUS_SUCCESS;
946 }
947 
948 static const struct btp_handler vcp_handlers[] = {
949 	{
950 		.opcode = BTP_VCP_READ_SUPPORTED_COMMANDS,
951 		.index = BTP_INDEX_NONE,
952 		.expect_len = 0,
953 		.func = vcp_supported_commands,
954 	},
955 	{
956 		.opcode = BTP_VCP_VOL_CTLR_DISCOVER,
957 		.expect_len = sizeof(struct btp_vcp_discover_cmd),
958 		.func = vcp_discover,
959 	},
960 	{
961 		.opcode = BTP_VCP_VOL_CTLR_STATE_READ,
962 		.expect_len = sizeof(struct btp_vcp_state_read_cmd),
963 		.func = vcp_state_read,
964 	},
965 	{
966 		.opcode = BTP_VCP_VOL_CTLR_FLAGS_READ,
967 		.expect_len = sizeof(struct btp_vcp_flags_read_cmd),
968 		.func = vcp_volume_flags_read,
969 	},
970 	{
971 		.opcode = BTP_VCP_VOL_CTLR_VOL_DOWN,
972 		.expect_len = sizeof(struct btp_vcp_ctlr_vol_down_cmd),
973 		.func = vcp_ctlr_vol_down,
974 	},
975 	{
976 		.opcode = BTP_VCP_VOL_CTLR_VOL_UP,
977 		.expect_len = sizeof(struct btp_vcp_ctlr_vol_up_cmd),
978 		.func = vcp_ctlr_vol_up,
979 	},
980 	{
981 		.opcode = BTP_VCP_VOL_CTLR_UNMUTE_VOL_DOWN,
982 		.expect_len = sizeof(struct btp_vcp_ctlr_unmute_vol_down_cmd),
983 		.func = vcp_ctlr_unmute_vol_down,
984 	},
985 	{
986 		.opcode = BTP_VCP_VOL_CTLR_UNMUTE_VOL_UP,
987 		.expect_len = sizeof(struct btp_vcp_ctlr_unmute_vol_up_cmd),
988 		.func = vcp_ctlr_unmute_vol_up,
989 	},
990 	{
991 		.opcode = BTP_VCP_VOL_CTLR_SET_VOL,
992 		.expect_len = sizeof(struct btp_vcp_ctlr_set_vol_cmd),
993 		.func = vcp_ctlr_set_vol,
994 	},
995 	{
996 		.opcode = BTP_VCP_VOL_CTLR_UNMUTE,
997 		.expect_len = sizeof(struct btp_vcp_ctlr_unmute_cmd),
998 		.func = vcp_ctlr_unmute,
999 	},
1000 	{
1001 		.opcode = BTP_VCP_VOL_CTLR_MUTE,
1002 		.expect_len = sizeof(struct btp_vcp_ctlr_mute_cmd),
1003 		.func = vcp_ctlr_mute,
1004 	},
1005 };
1006 
tester_init_vcp(void)1007 uint8_t tester_init_vcp(void)
1008 {
1009 	int err;
1010 
1011 	err = bt_vcp_vol_ctlr_cb_register(&vcp_cbs);
1012 
1013 	if (err) {
1014 		LOG_DBG("Failed to register callbacks: %d", err);
1015 		return BTP_STATUS_FAILED;
1016 	}
1017 
1018 	tester_register_command_handlers(BTP_SERVICE_ID_VCP, vcp_handlers,
1019 					 ARRAY_SIZE(vcp_handlers));
1020 
1021 	return BTP_STATUS_SUCCESS;
1022 }
1023 
tester_unregister_vcp(void)1024 uint8_t tester_unregister_vcp(void)
1025 {
1026 	int err;
1027 
1028 	err = bt_vcp_vol_ctlr_cb_unregister(&vcp_cbs);
1029 	if (err != 0) {
1030 		LOG_DBG("Failed to unregister callbacks: %d", err);
1031 		return BTP_STATUS_FAILED;
1032 	}
1033 
1034 	return BTP_STATUS_SUCCESS;
1035 }
1036