bluetooth: tester: Add VCP & IAS test handling
This commit introduces Volume Control Profile and Immediate Alert Service into btp. VCP includes: Audio Input Control Service Volume Control Service Volume Offset Control Service Signed-off-by: Szymon Czapracki <szymon.czapracki@codecoup.pl>
This commit is contained in:
parent
1d8681965c
commit
7941a88121
11 changed files with 827 additions and 1 deletions
|
@ -9,6 +9,7 @@ project(tester)
|
|||
|
||||
zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
|
||||
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/bluetooth/mesh)
|
||||
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/bluetooth/audio)
|
||||
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/bluetooth/host)
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
|
@ -23,3 +24,9 @@ endif()
|
|||
if(CONFIG_BT_MESH)
|
||||
target_sources(app PRIVATE src/btp_mesh.c)
|
||||
endif()
|
||||
|
||||
target_sources_ifdef(CONFIG_BT_VCP_VOL_REND app PRIVATE src/btp_vcp.c)
|
||||
|
||||
if(CONFIG_BT_IAS OR CONFIG_BT_IAS_CLIENT)
|
||||
target_sources(app PRIVATE src/btp_ias.c)
|
||||
endif()
|
||||
|
|
|
@ -56,5 +56,27 @@ CONFIG_BT_MESH_MSG_CACHE_SIZE=10
|
|||
|
||||
CONFIG_BT_TINYCRYPT_ECC=y
|
||||
CONFIG_BT_TESTING=y
|
||||
CONFIG_UTF8=y
|
||||
|
||||
CONFIG_UART_CONSOLE=n
|
||||
|
||||
# LE Audio Section
|
||||
CONFIG_BT_AUDIO=y
|
||||
|
||||
# Volume Offset Control Service
|
||||
CONFIG_BT_VOCS_MAX_INSTANCE_COUNT=2
|
||||
CONFIG_BT_VOCS_CLIENT_MAX_INSTANCE_COUNT=2
|
||||
|
||||
# Audio Input Control Service
|
||||
CONFIG_BT_AICS_MAX_INSTANCE_COUNT=4
|
||||
CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT=4
|
||||
|
||||
#Volume Control
|
||||
CONFIG_BT_VCP_VOL_REND=y
|
||||
CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT=2
|
||||
CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT=2
|
||||
CONFIG_BT_VCP_VOL_REND_LOG_LEVEL_DBG=y
|
||||
|
||||
# IAS
|
||||
CONFIG_BT_IAS=y
|
||||
CONFIG_BT_IAS_CLIENT=y
|
||||
|
|
|
@ -60,7 +60,7 @@ static void supported_commands(uint8_t *data, uint16_t len)
|
|||
|
||||
static void supported_services(uint8_t *data, uint16_t len)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
uint8_t buf[2];
|
||||
struct core_read_supported_services_rp *rp = (void *) buf;
|
||||
|
||||
(void)memset(buf, 0, sizeof(buf));
|
||||
|
@ -74,6 +74,18 @@ static void supported_services(uint8_t *data, uint16_t len)
|
|||
#if defined(CONFIG_BT_MESH)
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_MESH);
|
||||
#endif /* CONFIG_BT_MESH */
|
||||
#if defined(CONFIG_BT_VCP_VOL_REND)
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_VCS);
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
#if defined(CONFIG_BT_IAS) || defined(CONFIG_BT_IAS_CLIENT)
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_IAS);
|
||||
#endif /* CONFIG_BT_IAS */
|
||||
#if defined(CONFIG_BT_AICS) || defined(CONFIG_BT_AICS_CLIENT)
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_AICS);
|
||||
#endif /*CONFIG_BT_AICS */
|
||||
#if defined(CONFIG_BT_VOCS) || defined(CONFIG_BT_VOCS_CLIENT)
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_VOCS);
|
||||
#endif /* CONFIG_BT_VOCS */
|
||||
|
||||
tester_send(BTP_SERVICE_ID_CORE, CORE_READ_SUPPORTED_SERVICES,
|
||||
BTP_INDEX_NONE, (uint8_t *) rp, sizeof(buf));
|
||||
|
@ -105,6 +117,26 @@ static void register_service(uint8_t *data, uint16_t len)
|
|||
status = tester_init_mesh();
|
||||
break;
|
||||
#endif /* CONFIG_BT_MESH */
|
||||
#if defined(CONFIG_BT_VCP_VOL_REND)
|
||||
case BTP_SERVICE_ID_VCS:
|
||||
status = tester_init_vcp();
|
||||
break;
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
#if defined(CONFIG_BT_VOCS) || defined(CONFIG_BT_VOCS_CLIENT)
|
||||
case BTP_SERVICE_ID_VOCS:
|
||||
status = tester_init_vcp();
|
||||
break;
|
||||
#endif /* CONFIG_BT_VOCS */
|
||||
#if defined(CONFIG_BT_AICS) || defined(CONFIG_BT_AICS_CLIENT)
|
||||
case BTP_SERVICE_ID_AICS:
|
||||
status = tester_init_vcp();
|
||||
break;
|
||||
#endif /* CONFIG_BT_AICS */
|
||||
#if defined(CONFIG_BT_IAS) || defined(CONFIG_BT_IAS_CLIENT)
|
||||
case BTP_SERVICE_ID_IAS:
|
||||
status = BTP_STATUS_SUCCESS;
|
||||
break;
|
||||
#endif /* CONFIG_BT_IAS */
|
||||
default:
|
||||
LOG_WRN("unknown id: 0x%02x", cmd->id);
|
||||
status = BTP_STATUS_FAILED;
|
||||
|
@ -138,6 +170,21 @@ static void unregister_service(uint8_t *data, uint16_t len)
|
|||
status = tester_unregister_mesh();
|
||||
break;
|
||||
#endif /* CONFIG_BT_MESH */
|
||||
#if defined(CONFIG_BT_VCP_VOL_REND)
|
||||
case BTP_SERVICE_ID_VCS:
|
||||
status = tester_unregister_vcp();
|
||||
break;
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
#if defined(CONFIG_BT_AICS) || defined(CONFIG_BT_AICS_CLIENT)
|
||||
case BTP_SERVICE_ID_AICS:
|
||||
status = tester_unregister_vcp();
|
||||
break;
|
||||
#endif /* CONFIG_BT_AICS */
|
||||
#if defined(CONFIG_BT_VOCS) || defined(CONFIG_BT_VOCS_CLIENT)
|
||||
case BTP_SERVICE_ID_VOCS:
|
||||
status = tester_unregister_vcp();
|
||||
break;
|
||||
#endif /* CONFIG_BT_VOCS */
|
||||
default:
|
||||
LOG_WRN("unknown id: 0x%x", cmd->id);
|
||||
status = BTP_STATUS_FAILED;
|
||||
|
@ -217,6 +264,24 @@ static void cmd_handler(void *p1, void *p2, void *p3)
|
|||
cmd->hdr.data, len);
|
||||
break;
|
||||
#endif /* CONFIG_BT_MESH */
|
||||
#if defined(CONFIG_BT_VCP_VOL_REND)
|
||||
case BTP_SERVICE_ID_VCS:
|
||||
tester_handle_vcs(cmd->hdr.opcode, cmd->hdr.index,
|
||||
cmd->hdr.data, len);
|
||||
break;
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
#if defined(CONFIG_BT_AICS)
|
||||
case BTP_SERVICE_ID_AICS:
|
||||
tester_handle_aics(cmd->hdr.opcode, cmd->hdr.index,
|
||||
cmd->hdr.data, len);
|
||||
break;
|
||||
#endif /* CONFIG_BT_AICS */
|
||||
#if defined(CONFIG_BT_VOCS)
|
||||
case BTP_SERVICE_ID_VOCS:
|
||||
tester_handle_vocs(cmd->hdr.opcode, cmd->hdr.index,
|
||||
cmd->hdr.data, len);
|
||||
break;
|
||||
#endif /* CONFIG_BT_VOCS */
|
||||
default:
|
||||
LOG_WRN("unknown service: 0x%x", cmd->hdr.service);
|
||||
tester_rsp(cmd->hdr.service, cmd->hdr.opcode,
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
#include "btp_gatt.h"
|
||||
#include "btp_l2cap.h"
|
||||
#include "btp_mesh.h"
|
||||
#include "btp_vcs.h"
|
||||
#include "btp_aics.h"
|
||||
#include "btp_vocs.h"
|
||||
#include "btp_ias.h"
|
||||
|
||||
#define BTP_MTU 1024
|
||||
#define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr))
|
||||
|
@ -27,6 +31,13 @@
|
|||
#define BTP_SERVICE_ID_GATT 2
|
||||
#define BTP_SERVICE_ID_L2CAP 3
|
||||
#define BTP_SERVICE_ID_MESH 4
|
||||
#define BTP_SERVICE_ID_MESH_MDL 5
|
||||
#define BTP_SERVICE_GATT_CLIENT 6
|
||||
#define BTP_SERVICE_GATT_SERVER 7
|
||||
#define BTP_SERVICE_ID_VCS 8
|
||||
#define BTP_SERVICE_ID_IAS 9
|
||||
#define BTP_SERVICE_ID_AICS 10
|
||||
#define BTP_SERVICE_ID_VOCS 11
|
||||
|
||||
#define BTP_STATUS_SUCCESS 0x00
|
||||
#define BTP_STATUS_FAILED 0x01
|
||||
|
|
30
tests/bluetooth/tester/src/btp/btp_aics.h
Normal file
30
tests/bluetooth/tester/src/btp/btp_aics.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* btp_aics.h - Bluetooth tester headers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#define AICS_READ_SUPPORTED_COMMANDS 0x01
|
||||
|
||||
#define AICS_SET_GAIN 0x02
|
||||
#define AICS_MUTE 0x03
|
||||
#define AICS_UNMUTE 0x04
|
||||
#define AICS_MAN_GAIN 0x05
|
||||
#define AICS_AUTO_GAIN 0x06
|
||||
#define AICS_MAN_GAIN_ONLY 0x07
|
||||
#define AICS_AUTO_GAIN_ONLY 0x08
|
||||
#define AICS_DESCRIPTION 0x09
|
||||
#define AICS_MUTE_DISABLE 0x0a
|
||||
|
||||
struct aics_set_gain {
|
||||
int8_t gain;
|
||||
} __packed;
|
||||
|
||||
struct aics_audio_desc {
|
||||
uint8_t desc_len;
|
||||
uint8_t desc[0];
|
||||
} __packed;
|
16
tests/bluetooth/tester/src/btp/btp_ias.h
Normal file
16
tests/bluetooth/tester/src/btp/btp_ias.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* btp_ias.h - Bluetooth tester headers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "zephyr/bluetooth/services/ias.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* events */
|
||||
#define IAS_EV_OUT_ALERT_ACTION 0x80
|
||||
struct ias_alert_action_ev {
|
||||
uint8_t alert_lvl;
|
||||
} __packed;
|
21
tests/bluetooth/tester/src/btp/btp_vcs.h
Normal file
21
tests/bluetooth/tester/src/btp/btp_vcs.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* btp_vcs.h - Bluetooth tester headers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#define VCS_READ_SUPPORTED_COMMANDS 0x01
|
||||
|
||||
#define VCS_SET_VOL 0x02
|
||||
#define VCS_VOL_UP 0x03
|
||||
#define VCS_VOL_DOWN 0x04
|
||||
#define VCS_MUTE 0x05
|
||||
#define VCS_UNMUTE 0x06
|
||||
|
||||
struct vcs_set_vol_cmd {
|
||||
uint8_t volume;
|
||||
} __packed;
|
23
tests/bluetooth/tester/src/btp/btp_vocs.h
Normal file
23
tests/bluetooth/tester/src/btp/btp_vocs.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* btp_vocs.h - Bluetooth tester headers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#define VOCS_READ_SUPPORTED_COMMANDS 0x01
|
||||
|
||||
#define VOCS_UPDATE_LOC 0x02
|
||||
#define VOCS_UPDATE_DESC 0x03
|
||||
|
||||
struct vocs_audio_desc {
|
||||
uint8_t desc_len;
|
||||
uint8_t desc[0];
|
||||
} __packed;
|
||||
|
||||
struct vocs_audio_loc {
|
||||
uint32_t loc;
|
||||
} __packed;
|
|
@ -7,6 +7,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/bluetooth/addr.h>
|
||||
|
||||
|
@ -43,6 +44,12 @@ uint8_t tester_init_mesh(void);
|
|||
uint8_t tester_unregister_mesh(void);
|
||||
void tester_handle_mesh(uint8_t opcode, uint8_t index, uint8_t *data, uint16_t len);
|
||||
|
||||
uint8_t tester_init_vcp(void);
|
||||
uint8_t tester_unregister_vcp(void);
|
||||
void tester_handle_vcs(uint8_t opcode, uint8_t index, uint8_t *data, uint16_t len);
|
||||
void tester_handle_aics(uint8_t opcode, uint8_t index, uint8_t *data, uint16_t len);
|
||||
void tester_handle_vocs(uint8_t opcode, uint8_t index, uint8_t *data, uint16_t len);
|
||||
|
||||
uint8_t tester_init_gap(void);
|
||||
uint8_t tester_unregister_gap(void);
|
||||
void tester_handle_gap(uint8_t opcode, uint8_t index, uint8_t *data,
|
||||
|
|
55
tests/bluetooth/tester/src/btp_ias.c
Normal file
55
tests/bluetooth/tester/src/btp_ias.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* btp_ias.c - Bluetooth IAS Server Tester */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr/bluetooth/services/ias.h>
|
||||
|
||||
#include "btp/btp.h"
|
||||
#include "zephyr/sys/byteorder.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
#define LOG_MODULE_NAME bttester_ias
|
||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||
|
||||
#define CONTROLLER_INDEX 0
|
||||
|
||||
/* Immediate Alert Service */
|
||||
static void alert_stop(void)
|
||||
{
|
||||
struct ias_alert_action_ev ev;
|
||||
|
||||
ev.alert_lvl = BT_IAS_ALERT_LVL_NO_ALERT;
|
||||
|
||||
tester_send(BTP_SERVICE_ID_IAS, IAS_EV_OUT_ALERT_ACTION,
|
||||
CONTROLLER_INDEX, (uint8_t *)&ev, sizeof(ev));
|
||||
}
|
||||
|
||||
static void alert_start(void)
|
||||
{
|
||||
struct ias_alert_action_ev ev;
|
||||
|
||||
ev.alert_lvl = BT_IAS_ALERT_LVL_MILD_ALERT;
|
||||
|
||||
tester_send(BTP_SERVICE_ID_IAS, IAS_EV_OUT_ALERT_ACTION,
|
||||
CONTROLLER_INDEX, (uint8_t *)&ev.alert_lvl, sizeof(ev));
|
||||
}
|
||||
|
||||
static void alert_high_start(void)
|
||||
{
|
||||
struct ias_alert_action_ev ev;
|
||||
|
||||
ev.alert_lvl = BT_IAS_ALERT_LVL_HIGH_ALERT;
|
||||
|
||||
tester_send(BTP_SERVICE_ID_IAS, IAS_EV_OUT_ALERT_ACTION,
|
||||
CONTROLLER_INDEX, (uint8_t *)&ev, sizeof(ev));
|
||||
}
|
||||
|
||||
BT_IAS_CB_DEFINE(ias_callbacks) = {
|
||||
.no_alert = alert_stop,
|
||||
.mild_alert = alert_start,
|
||||
.high_alert = alert_high_start,
|
||||
};
|
569
tests/bluetooth/tester/src/btp_vcp.c
Normal file
569
tests/bluetooth/tester/src/btp_vcp.c
Normal file
|
@ -0,0 +1,569 @@
|
|||
/* btp_vcp.c - Bluetooth VCP Tester */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/testing.h>
|
||||
#include <zephyr/bluetooth/audio/vcp.h>
|
||||
#include <zephyr/bluetooth/audio/aics.h>
|
||||
#include "zephyr/bluetooth/audio/vocs.h"
|
||||
#include "zephyr/sys/util.h"
|
||||
|
||||
#include <app_keys.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
#define LOG_MODULE_NAME bttester_vcp
|
||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||
|
||||
#include "btp/btp.h"
|
||||
|
||||
#define CONTROLLER_INDEX 0
|
||||
#define BT_AICS_MAX_INPUT_DESCRIPTION_SIZE 16
|
||||
#define BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE 16
|
||||
|
||||
struct bt_vcp_vol_rend_register_param vcp_register_param;
|
||||
struct bt_vcp_included included;
|
||||
|
||||
static void set_register_params(uint8_t gain_mode);
|
||||
uint8_t tester_init_vcp(void);
|
||||
|
||||
/* Volume Control Service */
|
||||
static void vcs_supported_commands(uint8_t *data, uint16_t len)
|
||||
{
|
||||
struct net_buf_simple *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE);
|
||||
|
||||
net_buf_simple_init(buf, 0);
|
||||
net_buf_simple_add_u8(buf, VCS_READ_SUPPORTED_COMMANDS);
|
||||
net_buf_simple_add_u8(buf, VCS_SET_VOL);
|
||||
net_buf_simple_add_u8(buf, VCS_VOL_UP);
|
||||
net_buf_simple_add_u8(buf, VCS_VOL_DOWN);
|
||||
net_buf_simple_add_u8(buf, VCS_MUTE);
|
||||
net_buf_simple_add_u8(buf, VCS_UNMUTE);
|
||||
|
||||
tester_send(BTP_SERVICE_ID_VCS, VCS_READ_SUPPORTED_COMMANDS,
|
||||
CONTROLLER_INDEX, buf->data, buf->len);
|
||||
}
|
||||
|
||||
static void set_volume(uint8_t *data)
|
||||
{
|
||||
const struct vcs_set_vol_cmd *cmd = (void *)data;
|
||||
uint8_t volume;
|
||||
|
||||
volume = cmd->volume;
|
||||
|
||||
LOG_DBG("Set volume 0x%02x", volume);
|
||||
|
||||
if (bt_vcp_vol_rend_set_vol(volume) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_SET_VOL,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_SET_VOL, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static void vol_up(void)
|
||||
{
|
||||
LOG_DBG("Volume Up");
|
||||
|
||||
if (bt_vcp_vol_rend_vol_up() != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_VOL_UP,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_VOL_UP, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static void vol_down(void)
|
||||
{
|
||||
LOG_DBG("Volume Down");
|
||||
|
||||
if (bt_vcp_vol_rend_vol_down() != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_VOL_DOWN,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_VOL_DOWN, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static void mute(void)
|
||||
{
|
||||
LOG_DBG("Mute");
|
||||
|
||||
if (bt_vcp_vol_rend_mute() != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_MUTE, CONTROLLER_INDEX,
|
||||
BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_MUTE, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static void unmute(void)
|
||||
{
|
||||
LOG_DBG("Unmute");
|
||||
|
||||
if (bt_vcp_vol_rend_unmute() != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_UNMUTE, CONTROLLER_INDEX,
|
||||
BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, VCS_UNMUTE, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static void vcs_state_cb(int err, uint8_t volume, uint8_t mute)
|
||||
{
|
||||
LOG_DBG("VCP state cb err (%d)", err);
|
||||
}
|
||||
|
||||
static void vcs_flags_cb(int err, uint8_t flags)
|
||||
{
|
||||
LOG_DBG("VCP flags cb err (%d)", err);
|
||||
}
|
||||
|
||||
static struct bt_vcp_vol_rend_cb vcs_cb = {
|
||||
.state = vcs_state_cb,
|
||||
.flags = vcs_flags_cb,
|
||||
};
|
||||
|
||||
void tester_handle_vcs(uint8_t opcode, uint8_t index, uint8_t *data,
|
||||
uint16_t len)
|
||||
{
|
||||
switch (opcode) {
|
||||
case VCS_READ_SUPPORTED_COMMANDS:
|
||||
vcs_supported_commands(data, len);
|
||||
break;
|
||||
case VCS_SET_VOL:
|
||||
set_volume(data);
|
||||
break;
|
||||
case VCS_VOL_UP:
|
||||
vol_up();
|
||||
break;
|
||||
case VCS_VOL_DOWN:
|
||||
vol_down();
|
||||
break;
|
||||
case VCS_MUTE:
|
||||
mute();
|
||||
break;
|
||||
case VCS_UNMUTE:
|
||||
unmute();
|
||||
break;
|
||||
default:
|
||||
tester_rsp(BTP_SERVICE_ID_VCS, opcode, index,
|
||||
BTP_STATUS_UNKNOWN_CMD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Audio Input Control Service */
|
||||
static void aics_supported_commands(uint8_t *data, uint16_t len)
|
||||
{
|
||||
struct net_buf_simple *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE);
|
||||
|
||||
net_buf_simple_init(buf, 0);
|
||||
net_buf_simple_add_u8(buf, AICS_READ_SUPPORTED_COMMANDS);
|
||||
net_buf_simple_add_u8(buf, AICS_SET_GAIN);
|
||||
net_buf_simple_add_u8(buf, AICS_MUTE);
|
||||
net_buf_simple_add_u8(buf, AICS_UNMUTE);
|
||||
net_buf_simple_add_u8(buf, AICS_MAN_GAIN);
|
||||
net_buf_simple_add_u8(buf, AICS_AUTO_GAIN);
|
||||
net_buf_simple_add_u8(buf, AICS_DESCRIPTION);
|
||||
|
||||
tester_send(BTP_SERVICE_ID_AICS, AICS_READ_SUPPORTED_COMMANDS,
|
||||
CONTROLLER_INDEX, buf->data, buf->len);
|
||||
}
|
||||
|
||||
static void aics_state_cb(struct bt_aics *inst, int err, int8_t gain,
|
||||
uint8_t mute, uint8_t mode)
|
||||
{
|
||||
LOG_DBG("AICS state callback (%d)", err);
|
||||
}
|
||||
|
||||
static void aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
|
||||
int8_t minimum, int8_t maximum)
|
||||
{
|
||||
LOG_DBG("AICS gain setting callback (%d)", err);
|
||||
}
|
||||
|
||||
static void aics_input_type_cb(struct bt_aics *inst, int err,
|
||||
uint8_t input_type)
|
||||
{
|
||||
LOG_DBG("AICS input type callback (%d)", err);
|
||||
}
|
||||
|
||||
static void aics_status_cb(struct bt_aics *inst, int err, bool active)
|
||||
{
|
||||
LOG_DBG("AICS status callback (%d)", err);
|
||||
}
|
||||
|
||||
static void aics_description_cb(struct bt_aics *inst, int err,
|
||||
char *description)
|
||||
{
|
||||
LOG_DBG("AICS description callback (%d)", err);
|
||||
}
|
||||
|
||||
static struct bt_aics_cb aics_cb = {
|
||||
.state = aics_state_cb,
|
||||
.gain_setting = aics_gain_setting_cb,
|
||||
.type = aics_input_type_cb,
|
||||
.status = aics_status_cb,
|
||||
.description = aics_description_cb
|
||||
};
|
||||
|
||||
void aics_set_gain(uint8_t *data)
|
||||
{
|
||||
const struct aics_set_gain *cmd = (void *)data;
|
||||
|
||||
const int8_t gain = cmd->gain;
|
||||
|
||||
LOG_DBG("AICS set gain %d", gain);
|
||||
|
||||
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
|
||||
if (bt_aics_gain_set(included.aics[0], gain) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_SET_GAIN,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_SET_GAIN, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void aics_mute(void)
|
||||
{
|
||||
LOG_DBG("AICS mute");
|
||||
|
||||
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
|
||||
if (bt_aics_mute(included.aics[i]) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_MUTE,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_MUTE, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void aics_unmute(void)
|
||||
{
|
||||
LOG_DBG("AICS unmute");
|
||||
|
||||
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
|
||||
if (bt_aics_unmute(included.aics[i]) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_UNMUTE,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_UNMUTE, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void aics_man_gain(void)
|
||||
{
|
||||
LOG_DBG("AICS manual gain set");
|
||||
|
||||
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
|
||||
if (bt_aics_manual_gain_set(included.aics[i]) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_MAN_GAIN,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_MAN_GAIN, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void aics_auto_gain(void)
|
||||
{
|
||||
LOG_DBG("AICS auto gain set");
|
||||
|
||||
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
|
||||
if (bt_aics_automatic_gain_set(included.aics[i]) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_AUTO_GAIN,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_AUTO_GAIN, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
/* TODO: Need new API function for this */
|
||||
void aics_auto_gain_only(void)
|
||||
{
|
||||
LOG_DBG("AICS auto gain only");
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_AUTO_GAIN_ONLY, CONTROLLER_INDEX,
|
||||
BTP_STATUS_FAILED);
|
||||
}
|
||||
|
||||
/* TODO: Need new API function for this */
|
||||
void aics_auto_man_only(void)
|
||||
{
|
||||
LOG_DBG("AICS manual gain only");
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_MAN_GAIN_ONLY, CONTROLLER_INDEX,
|
||||
BTP_STATUS_FAILED);
|
||||
}
|
||||
|
||||
/* TODO: Need new API function for this */
|
||||
void aics_mute_disable(void)
|
||||
{
|
||||
LOG_DBG("AICS mute disable");
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_MUTE_DISABLE,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
}
|
||||
|
||||
void aics_desc(uint8_t *data)
|
||||
{
|
||||
const struct aics_audio_desc *cmd = (void *) data;
|
||||
char description[BT_AICS_MAX_INPUT_DESCRIPTION_SIZE];
|
||||
|
||||
LOG_DBG("AICS description");
|
||||
|
||||
if (cmd->desc_len > BT_AICS_MAX_INPUT_DESCRIPTION_SIZE) {
|
||||
LOG_ERR("Too long input (%u chars required)",
|
||||
BT_AICS_MAX_INPUT_DESCRIPTION_SIZE);
|
||||
goto rsp;
|
||||
}
|
||||
|
||||
memcpy(description, cmd->desc, cmd->desc_len);
|
||||
description[cmd->desc_len] = '\0';
|
||||
|
||||
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
|
||||
if (bt_aics_description_set(included.aics[i], description) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_DESCRIPTION,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
rsp:
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, AICS_DESCRIPTION, CONTROLLER_INDEX,
|
||||
BTP_STATUS_FAILED);
|
||||
}
|
||||
|
||||
void tester_handle_aics(uint8_t opcode, uint8_t index, uint8_t *data, uint16_t len)
|
||||
{
|
||||
switch (opcode) {
|
||||
case AICS_READ_SUPPORTED_COMMANDS:
|
||||
aics_supported_commands(data, len);
|
||||
break;
|
||||
case AICS_SET_GAIN:
|
||||
aics_set_gain(data);
|
||||
break;
|
||||
case AICS_MUTE:
|
||||
aics_mute();
|
||||
break;
|
||||
case AICS_UNMUTE:
|
||||
aics_unmute();
|
||||
break;
|
||||
case AICS_MAN_GAIN:
|
||||
aics_man_gain();
|
||||
break;
|
||||
case AICS_AUTO_GAIN:
|
||||
aics_auto_gain();
|
||||
break;
|
||||
case AICS_MAN_GAIN_ONLY:
|
||||
aics_auto_gain_only();
|
||||
break;
|
||||
case AICS_AUTO_GAIN_ONLY:
|
||||
aics_auto_gain_only();
|
||||
break;
|
||||
case AICS_DESCRIPTION:
|
||||
aics_desc(data);
|
||||
break;
|
||||
case AICS_MUTE_DISABLE:
|
||||
aics_mute_disable();
|
||||
break;
|
||||
default:
|
||||
tester_rsp(BTP_SERVICE_ID_AICS, opcode, index,
|
||||
BTP_STATUS_UNKNOWN_CMD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Volume Offset Control Service */
|
||||
static void vocs_supported_commands(void)
|
||||
{
|
||||
struct net_buf_simple *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE);
|
||||
|
||||
net_buf_simple_init(buf, 0);
|
||||
net_buf_simple_add_u8(buf, VOCS_READ_SUPPORTED_COMMANDS);
|
||||
net_buf_simple_add_u8(buf, VOCS_UPDATE_LOC);
|
||||
net_buf_simple_add_u8(buf, VOCS_UPDATE_DESC);
|
||||
|
||||
tester_send(BTP_SERVICE_ID_VOCS, VOCS_READ_SUPPORTED_COMMANDS,
|
||||
CONTROLLER_INDEX, buf->data, buf->len);
|
||||
}
|
||||
|
||||
static void vocs_state_cb(struct bt_vocs *inst, int err, int16_t offset)
|
||||
{
|
||||
LOG_DBG("VOCS state callback err (%d)", err);
|
||||
}
|
||||
|
||||
static void vocs_location_cb(struct bt_vocs *inst, int err, uint32_t location)
|
||||
{
|
||||
LOG_DBG("VOCS location callback err (%d)", err);
|
||||
}
|
||||
|
||||
static void vocs_description_cb(struct bt_vocs *inst, int err,
|
||||
char *description)
|
||||
{
|
||||
LOG_DBG("VOCS desctripion callback (%d)", err);
|
||||
}
|
||||
|
||||
static struct bt_vocs_cb vocs_cb = {
|
||||
.state = vocs_state_cb,
|
||||
.location = vocs_location_cb,
|
||||
.description = vocs_description_cb
|
||||
};
|
||||
|
||||
void vocs_audio_desc(uint8_t *data)
|
||||
{
|
||||
struct vocs_audio_desc *cmd = (void *) data;
|
||||
char description[BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE];
|
||||
|
||||
LOG_DBG("VOCS description");
|
||||
|
||||
/* FIXME: Spec does not specify maximum desc length */
|
||||
if (cmd->desc_len >= BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE) {
|
||||
LOG_ERR("Too long input (%u chars required)", 16);
|
||||
goto rsp;
|
||||
}
|
||||
|
||||
memcpy(description, cmd->desc, cmd->desc_len);
|
||||
description[cmd->desc_len] = '\0';
|
||||
|
||||
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT; i++) {
|
||||
if (bt_vocs_description_set(included.vocs[i], description) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_VOCS, VOCS_UPDATE_DESC,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
rsp:
|
||||
tester_rsp(BTP_SERVICE_ID_VOCS, VOCS_UPDATE_DESC, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void vocs_audio_loc(uint8_t *data)
|
||||
{
|
||||
const struct vocs_audio_loc *cmd = (void *) data;
|
||||
|
||||
LOG_DBG("VOCS location");
|
||||
|
||||
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT; i++) {
|
||||
if (bt_vocs_location_set(included.vocs[i], cmd->loc) != 0) {
|
||||
tester_rsp(BTP_SERVICE_ID_VOCS, VOCS_UPDATE_LOC,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_VOCS, VOCS_UPDATE_LOC, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void tester_handle_vocs(uint8_t opcode, uint8_t index, uint8_t *data,
|
||||
uint16_t len)
|
||||
{
|
||||
switch (opcode) {
|
||||
case VOCS_READ_SUPPORTED_COMMANDS:
|
||||
vocs_supported_commands();
|
||||
break;
|
||||
case VOCS_UPDATE_DESC:
|
||||
vocs_audio_desc(data);
|
||||
break;
|
||||
case VOCS_UPDATE_LOC:
|
||||
vocs_audio_loc(data);
|
||||
break;
|
||||
default:
|
||||
tester_rsp(BTP_SERVICE_ID_VOCS, opcode, index,
|
||||
BTP_STATUS_UNKNOWN_CMD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* General profile handling */
|
||||
static void set_register_params(uint8_t gain_mode)
|
||||
{
|
||||
char input_desc[CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT]
|
||||
[BT_AICS_MAX_INPUT_DESCRIPTION_SIZE];
|
||||
char output_desc[CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT]
|
||||
[BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE];
|
||||
|
||||
memset(&vcp_register_param, 0, sizeof(vcp_register_param));
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(vcp_register_param.vocs_param); i++) {
|
||||
vcp_register_param.vocs_param[i].location_writable = true;
|
||||
vcp_register_param.vocs_param[i].desc_writable = true;
|
||||
snprintf(output_desc[i], sizeof(output_desc[i]),
|
||||
"Output %zu", i + 1);
|
||||
vcp_register_param.vocs_param[i].output_desc = output_desc[i];
|
||||
vcp_register_param.vocs_param[i].cb = &vocs_cb;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(vcp_register_param.aics_param); i++) {
|
||||
vcp_register_param.aics_param[i].desc_writable = true;
|
||||
snprintf(input_desc[i], sizeof(input_desc[i]),
|
||||
"Input %zu", i + 1);
|
||||
vcp_register_param.aics_param[i].description = input_desc[i];
|
||||
vcp_register_param.aics_param[i].type = BT_AICS_INPUT_TYPE_DIGITAL;
|
||||
vcp_register_param.aics_param[i].status = 1;
|
||||
vcp_register_param.aics_param[i].gain_mode = gain_mode;
|
||||
vcp_register_param.aics_param[i].units = 1;
|
||||
vcp_register_param.aics_param[i].min_gain = 0;
|
||||
vcp_register_param.aics_param[i].max_gain = 100;
|
||||
vcp_register_param.aics_param[i].cb = &aics_cb;
|
||||
}
|
||||
|
||||
vcp_register_param.step = 1;
|
||||
vcp_register_param.mute = BT_VCP_STATE_UNMUTED;
|
||||
vcp_register_param.volume = 100;
|
||||
vcp_register_param.cb = &vcs_cb;
|
||||
}
|
||||
|
||||
uint8_t tester_init_vcp(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
set_register_params(BT_AICS_MODE_MANUAL);
|
||||
|
||||
err = bt_vcp_vol_rend_register(&vcp_register_param);
|
||||
if (err) {
|
||||
return BTP_STATUS_FAILED;
|
||||
}
|
||||
|
||||
err = bt_vcp_vol_rend_included_get(&included);
|
||||
if (err) {
|
||||
return BTP_STATUS_FAILED;
|
||||
}
|
||||
|
||||
return BTP_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t tester_unregister_vcp(void)
|
||||
{
|
||||
return BTP_STATUS_SUCCESS;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue