bluetooth: tester: MICP Client tests

Add support for MICP Client tests.

Signed-off-by: Piotr Narajowski <piotr.narajowski@codecoup.pl>
This commit is contained in:
Piotr Narajowski 2023-08-18 23:32:02 +02:00 committed by Carles Cufí
commit 925a8b65d5
10 changed files with 1052 additions and 279 deletions

View file

@ -43,3 +43,11 @@ endif()
if (CONFIG_BT_CSIP_SET_MEMBER)
target_sources(app PRIVATE src/btp_csis.c)
endif()
if(CONFIG_BT_MICP_MIC_DEV)
target_sources(app PRIVATE src/btp_micp.c)
endif()
if(CONFIG_BT_AICS)
target_sources(app PRIVATE src/btp_aics.c)
endif()

View file

@ -19,6 +19,12 @@ CONFIG_BT_BUF_CMD_TX_SIZE=255
# were freed too slow. The bt_bap_stream_ops.configured callback comes earlier.
CONFIG_BT_L2CAP_TX_BUF_COUNT=4
# MICP
CONFIG_BT_MICP_MIC_DEV=y
CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT=1
CONFIG_BT_MICP_MIC_CTLR=y
CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST=1
# ASCS
CONFIG_BT_ASCS_ASE_SNK_COUNT=2
CONFIG_BT_ASCS_ASE_SRC_COUNT=2

View file

@ -25,6 +25,7 @@
#include "btp_bap.h"
#include "btp_has.h"
#include "btp_csis.h"
#include "btp_micp.h"
#define BTP_MTU 1024
#define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr))
@ -48,6 +49,7 @@
#define BTP_SERVICE_ID_ASCS 13
#define BTP_SERVICE_ID_BAP 14
#define BTP_SERVICE_ID_HAS 15
#define BTP_SERVICE_ID_MICP 16
#define BTP_SERVICE_ID_CSIS 17
#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_CSIS

View file

@ -7,29 +7,125 @@
*/
#include <zephyr/sys/util.h>
#include <zephyr/bluetooth/conn.h>
/*AICS service */
struct btp_aics_instance {
/** Number of Audio Input Control Service instances */
uint8_t aics_cnt;
/** Array of pointers to Audio Input Control Service instances */
struct bt_aics **aics;
};
extern struct bt_aics_cb aics_client_cb;
extern struct btp_aics_instance aics_client_instance;
extern struct btp_aics_instance aics_server_instance;
void btp_send_aics_state_changed_ev(struct bt_conn *conn);
void btp_send_aics_state_ev(struct bt_conn *conn, int8_t gain, uint8_t mute, uint8_t mode);
void btp_send_gain_setting_properties_ev(struct bt_conn *conn, uint8_t units, int8_t minimum,
int8_t maximum);
void btp_send_aics_input_type_event(struct bt_conn *conn, uint8_t input_type);
void btp_send_aics_status_ev(struct bt_conn *conn, bool active);
void btp_send_aics_description_ev(struct bt_conn *conn, uint8_t data_len, char *description);
#define BTP_AICS_READ_SUPPORTED_COMMANDS 0x01
struct btp_aics_read_supported_commands_rp {
uint8_t data[0];
} __packed;
/* AICS client/server commands */
#define BTP_AICS_SET_GAIN 0x02
struct btp_aics_set_gain_cmd {
bt_addr_le_t address;
int8_t gain;
} __packed;
#define BTP_AICS_MUTE 0x03
#define BTP_AICS_UNMUTE 0x04
#define BTP_AICS_MAN_GAIN 0x05
#define BTP_AICS_AUTO_GAIN 0x06
#define BTP_AICS_MAN_GAIN_ONLY 0x07
#define BTP_AICS_AUTO_GAIN_ONLY 0x08
struct btp_aics_mute_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_AICS_DESCRIPTION 0x09
#define BTP_AICS_UNMUTE 0x04
struct btp_aics_unmute_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_AICS_MAN_GAIN_SET 0x05
struct btp_aics_manual_gain_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_AICS_AUTO_GAIN_SET 0x06
struct btp_aics_auto_gain_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_AICS_SET_MAN_GAIN_ONLY 0x07
#define BTP_AICS_SET_AUTO_GAIN_ONLY 0x08
#define BTP_AICS_AUDIO_DESCRIPTION_SET 0x09
struct btp_aics_audio_desc_cmd {
uint8_t desc_len;
uint8_t desc[0];
} __packed;
#define BTP_AICS_MUTE_DISABLE 0x0a
#define BTP_AICS_GAIN_SETTING_PROP_GET 0x0b
struct btp_aics_gain_setting_prop_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_AICS_TYPE_GET 0x0c
struct btp_aics_type_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_AICS_STATUS_GET 0x0d
struct btp_aics_status_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_AICS_STATE_GET 0x0e
struct btp_aics_state_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_AICS_DESCRIPTION_GET 0x0f
struct btp_aics_desc_cmd {
bt_addr_le_t address;
} __packed;
/* AICS events */
#define BTP_AICS_STATE_EV 0x80
struct btp_aics_state_ev {
bt_addr_le_t address;
int8_t gain;
uint8_t mute;
uint8_t mode;
} __packed;
#define BTP_GAIN_SETTING_PROPERTIES_EV 0x81
struct btp_gain_setting_properties_ev {
bt_addr_le_t address;
uint8_t units;
int8_t minimum;
int8_t maximum;
} __packed;
#define BTP_AICS_INPUT_TYPE_EV 0x82
struct btp_aics_input_type_ev {
bt_addr_le_t address;
uint8_t input_type;
} __packed;
#define BTP_AICS_STATUS_EV 0x83
struct btp_aics_status_ev {
bt_addr_le_t address;
bool active;
} __packed;
#define BTP_AICS_DESCRIPTION_EV 0x84
struct btp_aics_description_ev {
bt_addr_le_t address;
uint8_t data_len;
char data[0];
} __packed;

View file

@ -0,0 +1,47 @@
/* btp_micp.h - Bluetooth tester headers */
/*
* Copyright (c) 2023 Codecoup
*
* SPDX-License-Identifier: Apache-2.0
*/
/* MICP commands */
#define BTP_MICP_READ_SUPPORTED_COMMANDS 0x01
struct btp_micp_read_supported_commands_rp {
uint8_t data[0];
} __packed;
#define BTP_MICP_CTLR_DISCOVER 0x02
struct btp_micp_discover_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_MICP_CTLR_MUTE_READ 0x03
struct btp_micp_mute_read_cmd {
bt_addr_le_t address;
} __packed;
#define BTP_MICP_CTLR_MUTE 0x04
struct btp_micp_mute_cmd {
bt_addr_le_t address;
} __packed;
/* MICP events */
#define BTP_MICP_DISCOVERED_EV 0x80
struct btp_micp_discovered_ev {
bt_addr_le_t address;
uint16_t mute_handle;
uint16_t state_handle;
uint16_t gain_handle;
uint16_t type_handle;
uint16_t status_handle;
uint16_t control_handle;
uint16_t desc_handle;
} __packed;
#define BTP_MICP_MUTE_STATE_EV 0x81
struct btp_micp_mute_state_ev {
bt_addr_le_t address;
uint8_t mute;
} __packed;

View file

@ -92,3 +92,6 @@ uint8_t tester_unregister_has(void);
uint8_t tester_init_csis(void);
uint8_t tester_unregister_csis(void);
uint8_t tester_init_micp(void);
uint8_t tester_unregister_micp(void);

View file

@ -0,0 +1,566 @@
/* btp_aics.c - Bluetooth AICS Tester */
/*
* Copyright (c) 2023 Codecoup
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <errno.h>
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/micp.h>
#include <zephyr/bluetooth/audio/aics.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
#include "bap_endpoint.h"
#include "btp/btp.h"
#define LOG_MODULE_NAME bttester_aics
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
#define BT_AICS_MAX_INPUT_DESCRIPTION_SIZE 16
#define BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE 16
struct btp_aics_instance aics_client_instance;
struct btp_aics_instance aics_server_instance;
static struct net_buf_simple *rx_ev_buf = NET_BUF_SIMPLE(BT_AICS_MAX_INPUT_DESCRIPTION_SIZE +
sizeof(struct btp_aics_description_ev));
static uint8_t aics_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
struct btp_aics_read_supported_commands_rp *rp = rsp;
/* octet 0 */
tester_set_bit(rp->data, BTP_AICS_READ_SUPPORTED_COMMANDS);
tester_set_bit(rp->data, BTP_AICS_SET_GAIN);
tester_set_bit(rp->data, BTP_AICS_MUTE);
tester_set_bit(rp->data, BTP_AICS_UNMUTE);
tester_set_bit(rp->data, BTP_AICS_MAN_GAIN_SET);
tester_set_bit(rp->data, BTP_AICS_AUTO_GAIN_SET);
tester_set_bit(rp->data, BTP_AICS_SET_MAN_GAIN_ONLY);
/* octet 1 */
tester_set_bit(rp->data, BTP_AICS_SET_AUTO_GAIN_ONLY);
tester_set_bit(rp->data, BTP_AICS_AUDIO_DESCRIPTION_SET);
tester_set_bit(rp->data, BTP_AICS_MUTE_DISABLE);
tester_set_bit(rp->data, BTP_AICS_GAIN_SETTING_PROP_GET);
tester_set_bit(rp->data, BTP_AICS_TYPE_GET);
tester_set_bit(rp->data, BTP_AICS_STATUS_GET);
tester_set_bit(rp->data, BTP_AICS_STATE_GET);
/* octet 2 */
tester_set_bit(rp->data, BTP_AICS_DESCRIPTION_GET);
*rsp_len = sizeof(*rp) + 2;
return BTP_STATUS_SUCCESS;
}
void btp_send_aics_state_ev(struct bt_conn *conn, int8_t gain, uint8_t mute, uint8_t mode)
{
struct btp_aics_state_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.gain = gain;
ev.mute = mute;
ev.mode = mode;
tester_event(BTP_SERVICE_ID_AICS, BTP_AICS_STATE_EV, &ev, sizeof(ev));
}
void btp_send_gain_setting_properties_ev(struct bt_conn *conn, uint8_t units, int8_t minimum,
int8_t maximum)
{
struct btp_gain_setting_properties_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.units = units;
ev.minimum = minimum;
ev.maximum = maximum;
tester_event(BTP_SERVICE_ID_AICS, BTP_GAIN_SETTING_PROPERTIES_EV, &ev, sizeof(ev));
}
void btp_send_aics_input_type_event(struct bt_conn *conn, uint8_t input_type)
{
struct btp_aics_input_type_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.input_type = input_type;
tester_event(BTP_SERVICE_ID_AICS, BTP_AICS_INPUT_TYPE_EV, &ev, sizeof(ev));
}
void btp_send_aics_status_ev(struct bt_conn *conn, bool active)
{
struct btp_aics_status_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.active = active;
tester_event(BTP_SERVICE_ID_AICS, BTP_AICS_STATUS_EV, &ev, sizeof(ev));
}
void btp_send_aics_description_ev(struct bt_conn *conn, uint8_t data_len, char *description)
{
struct btp_aics_description_ev *ev;
net_buf_simple_init(rx_ev_buf, 0);
ev = net_buf_simple_add(rx_ev_buf, sizeof(*ev));
bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn));
ev->data_len = data_len;
memcpy(ev->data, description, data_len);
tester_event(BTP_SERVICE_ID_AICS, BTP_AICS_DESCRIPTION_EV, ev, sizeof(*ev) + data_len);
}
static uint8_t aics_set_gain(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_set_gain_cmd *cp = cmd;
LOG_DBG("AICS set gain %d", cp->gain);
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_gain_set(aics_client_instance.aics[0], cp->gain) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_gain_set(aics_server_instance.aics[i], cp->gain) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_unmute(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_unmute_cmd *cp = cmd;
LOG_DBG("AICS Unmute");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_unmute(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_unmute(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_mute(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_mute_cmd *cp = cmd;
LOG_DBG("AICS Mute");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_mute(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_mute(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_state_get(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_state_cmd *cp = cmd;
LOG_DBG("AICS State");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_state_get(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_state_get(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_type_get(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_type_cmd *cp = cmd;
LOG_DBG("AICS Type");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_type_get(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_type_get(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_status_get(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_status_cmd *cp = cmd;
LOG_DBG("AICS Status");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_status_get(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_status_get(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_gain_setting_prop_get(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_aics_gain_setting_prop_cmd *cp = cmd;
LOG_DBG("AICS Gain settings properties");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_gain_setting_get(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_gain_setting_get(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_man_gain_set(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_manual_gain_cmd *cp = cmd;
LOG_DBG("AICS set manual gain mode");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_manual_gain_set(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_manual_gain_set(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_auto_gain_set(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_auto_gain_cmd *cp = cmd;
LOG_DBG("AICS set automatic gain mode");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_automatic_gain_set(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_automatic_gain_set(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_set_man_gain_only(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
LOG_DBG("AICS manual gain only set");
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_gain_set_manual_only(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_set_auto_gain_only(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
LOG_DBG("AICS auto gain only set");
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_gain_set_auto_only(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_mute_disable(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
LOG_DBG("AICS disable mute");
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_disable_mute(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_desc_set(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_audio_desc_cmd *cp = cmd;
char description[BT_AICS_MAX_INPUT_DESCRIPTION_SIZE];
LOG_DBG("AICS set description");
if (cmd_len < sizeof(*cp) || cmd_len != sizeof(*cp) + cp->desc_len) {
return BTP_STATUS_FAILED;
}
if (cp->desc_len >= sizeof(description)) {
return BTP_STATUS_FAILED;
}
if (cp->desc_len > (BT_AICS_MAX_INPUT_DESCRIPTION_SIZE - 1)) {
return BTP_STATUS_FAILED;
}
memcpy(description, cp->desc, cp->desc_len);
description[cp->desc_len] = '\0';
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_description_set(aics_server_instance.aics[i], description) != 0) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_desc_get(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_desc_cmd *cp = cmd;
LOG_DBG("AICS Description");
if (!bt_addr_le_eq(&cp->address, BT_ADDR_LE_ANY)) {
if (bt_aics_description_get(aics_client_instance.aics[0]) != 0) {
return BTP_STATUS_FAILED;
}
} else {
for (uint8_t i = 0; i < aics_server_instance.aics_cnt; i++) {
if (bt_aics_description_get(aics_server_instance.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
}
return BTP_STATUS_SUCCESS;
}
static const struct btp_handler aics_handlers[] = {
{
.opcode = BTP_AICS_READ_SUPPORTED_COMMANDS,
.index = BTP_INDEX_NONE,
.expect_len = 0,
.func = aics_supported_commands,
},
{
.opcode = BTP_AICS_SET_GAIN,
.expect_len = sizeof(struct btp_aics_set_gain_cmd),
.func = aics_set_gain,
},
{
.opcode = BTP_AICS_MUTE,
.expect_len = sizeof(struct btp_aics_mute_cmd),
.func = aics_mute,
},
{
.opcode = BTP_AICS_UNMUTE,
.expect_len = sizeof(struct btp_aics_unmute_cmd),
.func = aics_unmute,
},
{
.opcode = BTP_AICS_GAIN_SETTING_PROP_GET,
.expect_len = sizeof(struct btp_aics_gain_setting_prop_cmd),
.func = aics_gain_setting_prop_get,
},
{
.opcode = BTP_AICS_MUTE_DISABLE,
.expect_len = 0,
.func = aics_mute_disable,
},
{
.opcode = BTP_AICS_MAN_GAIN_SET,
.expect_len = sizeof(struct btp_aics_manual_gain_cmd),
.func = aics_man_gain_set,
},
{
.opcode = BTP_AICS_AUTO_GAIN_SET,
.expect_len = sizeof(struct btp_aics_auto_gain_cmd),
.func = aics_auto_gain_set,
},
{
.opcode = BTP_AICS_SET_AUTO_GAIN_ONLY,
.expect_len = 0,
.func = aics_set_auto_gain_only,
},
{
.opcode = BTP_AICS_SET_MAN_GAIN_ONLY,
.expect_len = 0,
.func = aics_set_man_gain_only,
},
{
.opcode = BTP_AICS_AUDIO_DESCRIPTION_SET,
.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
.func = aics_desc_set,
},
{
.opcode = BTP_AICS_DESCRIPTION_GET,
.expect_len = sizeof(struct btp_aics_desc_cmd),
.func = aics_desc_get,
},
{
.opcode = BTP_AICS_TYPE_GET,
.expect_len = sizeof(struct btp_aics_type_cmd),
.func = aics_type_get,
},
{
.opcode = BTP_AICS_STATUS_GET,
.expect_len = sizeof(struct btp_aics_status_cmd),
.func = aics_status_get,
},
{
.opcode = BTP_AICS_STATE_GET,
.expect_len = sizeof(struct btp_aics_state_cmd),
.func = aics_state_get,
},
};
static void aics_state_cb(struct bt_aics *inst, int err, int8_t gain, uint8_t mute, uint8_t mode)
{
struct bt_conn *conn;
bt_aics_client_conn_get(inst, &conn);
btp_send_aics_state_ev(conn, gain, mute, 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)
{
struct bt_conn *conn;
bt_aics_client_conn_get(inst, &conn);
btp_send_gain_setting_properties_ev(conn, units, minimum, 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)
{
struct bt_conn *conn;
bt_aics_client_conn_get(inst, &conn);
btp_send_aics_input_type_event(conn, input_type);
LOG_DBG("AICS input type callback (%d)", err);
}
static void aics_status_cb(struct bt_aics *inst, int err, bool active)
{
struct bt_conn *conn;
bt_aics_client_conn_get(inst, &conn);
btp_send_aics_status_ev(conn, active);
LOG_DBG("AICS status callback (%d)", err);
}
static void aics_description_cb(struct bt_aics *inst, int err, char *description)
{
struct bt_conn *conn;
uint8_t data_len = strlen(description);
bt_aics_client_conn_get(inst, &conn);
btp_send_aics_description_ev(conn, data_len, description);
LOG_DBG("AICS description callback (%d)", err);
}
struct bt_aics_cb aics_client_cb = {
.state = aics_state_cb,
.gain_setting = aics_gain_setting_cb,
.type = aics_input_type_cb,
.status = aics_status_cb,
.description = aics_description_cb,
};
uint8_t tester_init_aics(void)
{
tester_register_command_handlers(BTP_SERVICE_ID_AICS, aics_handlers,
ARRAY_SIZE(aics_handlers));
return tester_init_vcs();
}
uint8_t tester_unregister_aics(void)
{
return BTP_STATUS_SUCCESS;
}

View file

@ -80,6 +80,9 @@ static uint8_t supported_services(const void *cmd, uint16_t cmd_len,
#if defined(CONFIG_BT_CSIP_SET_MEMBER)
tester_set_bit(rp->data, BTP_SERVICE_ID_CSIS);
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
#if defined(CONFIG_BT_MICP_MIC_DEV) || defined(CONFIG_BT_MICP_MIC_CTLR)
tester_set_bit(rp->data, BTP_SERVICE_ID_MICP);
#endif /* CONFIG_BT_MICP_MIC_DEV */
*rsp_len = sizeof(*rp) + 2;
@ -145,6 +148,9 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len,
case BTP_SERVICE_ID_BAP:
status = tester_init_bap();
break;
case BTP_SERVICE_ID_MICP:
status = tester_init_micp();
break;
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT or CONFIG_BT_BAP_UNICAST_SERVER */
#if defined(CONFIG_BT_HAS)
case BTP_SERVICE_ID_HAS:
@ -228,6 +234,9 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len,
case BTP_SERVICE_ID_BAP:
status = tester_unregister_bap();
break;
case BTP_SERVICE_ID_MICP:
status = tester_unregister_micp();
break;
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT or CONFIG_BT_BAP_UNICAST_SERVER */
#if defined(CONFIG_BT_HAS)
case BTP_SERVICE_ID_HAS:

View file

@ -0,0 +1,264 @@
/* btp_micp.c - Bluetooth MICP Tester */
/*
* Copyright (c) 2023 Codecoup
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <errno.h>
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/micp.h>
#include <zephyr/bluetooth/audio/aics.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
#include <../../subsys/bluetooth/audio/micp_internal.h>
#include <../../subsys/bluetooth/audio/aics_internal.h>
#include "bap_endpoint.h"
#include "btp/btp.h"
#define LOG_MODULE_NAME bttester_micp
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
static struct bt_micp_mic_ctlr *mic_ctlr;
#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
static struct bt_micp_included micp_included;
struct chrc_handles {
uint16_t mute_handle;
uint16_t state_handle;
uint16_t gain_handle;
uint16_t type_handle;
uint16_t status_handle;
uint16_t control_handle;
uint16_t desc_handle;
};
struct chrc_handles micp_handles;
extern struct btp_aics_instance aics_client_instance;
extern struct bt_aics_cb aics_client_cb;
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
static void btp_send_micp_found_ev(struct bt_conn *conn, const struct chrc_handles *micp_handles)
{
struct btp_micp_discovered_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.mute_handle = sys_cpu_to_le16(micp_handles->mute_handle);
ev.state_handle = sys_cpu_to_le16(micp_handles->state_handle);
ev.gain_handle = sys_cpu_to_le16(micp_handles->gain_handle);
ev.type_handle = sys_cpu_to_le16(micp_handles->type_handle);
ev.status_handle = sys_cpu_to_le16(micp_handles->status_handle);
ev.control_handle = sys_cpu_to_le16(micp_handles->control_handle);
ev.desc_handle = sys_cpu_to_le16(micp_handles->desc_handle);
tester_event(BTP_SERVICE_ID_MICP, BTP_MICP_DISCOVERED_EV, &ev, sizeof(ev));
}
static void btp_send_micp_mute_state_ev(struct bt_conn *conn, uint8_t mute)
{
struct btp_micp_mute_state_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.mute = mute;
tester_event(BTP_SERVICE_ID_MICP, BTP_MICP_MUTE_STATE_EV, &ev, sizeof(ev));
}
static void micp_mic_ctlr_mute_cb(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute)
{
struct bt_conn *conn;
bt_micp_mic_ctlr_conn_get(mic_ctlr, &conn);
btp_send_micp_mute_state_ev(conn, mute);
LOG_DBG("MICP Mute cb (%d)", err);
}
static void micp_mic_ctlr_mute_written_cb(struct bt_micp_mic_ctlr *mic_ctlr, int err)
{
struct bt_conn *conn;
uint8_t mute_state = bt_micp_mic_ctlr_mute_get(mic_ctlr);
bt_micp_mic_ctlr_conn_get(mic_ctlr, &conn);
btp_send_micp_mute_state_ev(conn, mute_state);
LOG_DBG("MICP Mute Written cb (%d))", err);
}
static void micp_mic_ctlr_unmute_written_cb(struct bt_micp_mic_ctlr *mic_ctlr, int err)
{
struct bt_conn *conn;
uint8_t mute_state = bt_micp_mic_ctlr_mute_get(mic_ctlr);
bt_micp_mic_ctlr_conn_get(mic_ctlr, &conn);
btp_send_micp_mute_state_ev(conn, mute_state);
LOG_DBG("MICP Mute Unwritten cb (%d))", err);
}
static void micp_mic_ctlr_discover_cb(struct bt_micp_mic_ctlr *mic_ctlr, int err,
uint8_t aics_count)
{
struct bt_conn *conn;
if (err) {
LOG_DBG("Discovery failed (%d)", err);
return;
}
LOG_DBG("Discovery done with %u AICS",
aics_count);
bt_micp_mic_ctlr_conn_get(mic_ctlr, &conn);
#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
if (bt_micp_mic_ctlr_included_get(mic_ctlr, &micp_included) != 0) {
LOG_DBG("Could not get included services");
memset(&micp_handles, 0, sizeof(micp_handles));
} else {
aics_client_instance.aics_cnt = micp_included.aics_cnt;
aics_client_instance.aics = micp_included.aics;
bt_aics_client_cb_register(aics_client_instance.aics[0], &aics_client_cb);
micp_handles.state_handle = micp_included.aics[0]->cli.state_handle;
micp_handles.gain_handle = micp_included.aics[0]->cli.gain_handle;
micp_handles.type_handle = micp_included.aics[0]->cli.type_handle;
micp_handles.status_handle = micp_included.aics[0]->cli.status_handle;
micp_handles.control_handle = micp_included.aics[0]->cli.control_handle;
micp_handles.desc_handle = micp_included.aics[0]->cli.desc_handle;
}
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
micp_handles.mute_handle = mic_ctlr->mute_handle;
btp_send_micp_found_ev(conn, &micp_handles);
}
static struct bt_micp_mic_ctlr_cb micp_cbs = {
.discover = micp_mic_ctlr_discover_cb,
.mute = micp_mic_ctlr_mute_cb,
.mute_written = micp_mic_ctlr_mute_written_cb,
.unmute_written = micp_mic_ctlr_unmute_written_cb,
};
static uint8_t micp_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
struct btp_micp_read_supported_commands_rp *rp = rsp;
/* octet 0 */
tester_set_bit(rp->data, BTP_MICP_READ_SUPPORTED_COMMANDS);
tester_set_bit(rp->data, BTP_MICP_CTLR_DISCOVER);
tester_set_bit(rp->data, BTP_MICP_CTLR_MUTE_READ);
tester_set_bit(rp->data, BTP_MICP_CTLR_MUTE);
*rsp_len = sizeof(*rp) + 1;
return BTP_STATUS_SUCCESS;
}
static uint8_t micp_discover(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_micp_discover_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_micp_mic_ctlr_discover(conn, &mic_ctlr);
if (err) {
LOG_DBG("Fail: %d", err);
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t micp_mute_read(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
int err;
LOG_DBG("Read mute");
err = bt_micp_mic_ctlr_mute_get(mic_ctlr);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t micp_mute(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
int err;
LOG_DBG("MICP Mute");
err = bt_micp_mic_ctlr_mute(mic_ctlr);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static const struct btp_handler micp_handlers[] = {
{
.opcode = BTP_MICP_READ_SUPPORTED_COMMANDS,
.index = BTP_INDEX_NONE,
.expect_len = 0,
.func = micp_supported_commands,
},
{
.opcode = BTP_MICP_CTLR_DISCOVER,
.expect_len = sizeof(struct btp_micp_discover_cmd),
.func = micp_discover,
},
{
.opcode = BTP_MICP_CTLR_MUTE_READ,
.expect_len = sizeof(struct btp_micp_mute_read_cmd),
.func = micp_mute_read,
},
{
.opcode = BTP_MICP_CTLR_MUTE,
.expect_len = sizeof(struct btp_micp_mute_cmd),
.func = micp_mute,
}
};
uint8_t tester_init_micp(void)
{
int err;
err = bt_micp_mic_ctlr_cb_register(&micp_cbs);
if (err) {
LOG_DBG("Failed to register callbacks: %d", err);
return BTP_STATUS_FAILED;
}
tester_register_command_handlers(BTP_SERVICE_ID_MICP, micp_handlers,
ARRAY_SIZE(micp_handlers));
return BTP_STATUS_SUCCESS;
}
uint8_t tester_unregister_micp(void)
{
(void)bt_micp_mic_ctlr_cb_register(NULL);
return BTP_STATUS_SUCCESS;
}

View file

@ -15,6 +15,8 @@
#include "zephyr/bluetooth/audio/vocs.h"
#include "zephyr/sys/util.h"
#include <../../subsys/bluetooth/audio/micp_internal.h>
#include <../../subsys/bluetooth/audio/aics_internal.h>
#include <zephyr/logging/log.h>
#define LOG_MODULE_NAME bttester_vcp
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
@ -26,6 +28,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
static struct bt_vcp_vol_rend_register_param vcp_register_param;
static struct bt_vcp_included included;
extern struct btp_aics_instance aics_server_instance;
/* Volume Control Service */
static uint8_t vcs_supported_commands(const void *cmd, uint16_t cmd_len,
@ -157,265 +160,6 @@ static const struct btp_handler vcs_handlers[] = {
},
};
/* Audio Input Control Service */
static uint8_t aics_supported_commands(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
struct btp_aics_read_supported_commands_rp *rp = rsp;
/* octet 0 */
tester_set_bit(rp->data, BTP_AICS_READ_SUPPORTED_COMMANDS);
tester_set_bit(rp->data, BTP_AICS_SET_GAIN);
tester_set_bit(rp->data, BTP_AICS_MUTE);
tester_set_bit(rp->data, BTP_AICS_UNMUTE);
tester_set_bit(rp->data, BTP_AICS_MUTE_DISABLE);
tester_set_bit(rp->data, BTP_AICS_MAN_GAIN);
tester_set_bit(rp->data, BTP_AICS_AUTO_GAIN);
tester_set_bit(rp->data, BTP_AICS_MAN_GAIN_ONLY);
tester_set_bit(rp->data, BTP_AICS_AUTO_GAIN_ONLY);
/* octet 1 */
tester_set_bit(rp->data, BTP_AICS_DESCRIPTION);
*rsp_len = sizeof(*rp) + 2;
return BTP_STATUS_SUCCESS;
}
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
};
static uint8_t aics_set_gain(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_set_gain_cmd *cp = cmd;
LOG_DBG("AICS set gain %d", cp->gain);
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
if (bt_aics_gain_set(included.aics[0], cp->gain) != 0) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_mute(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
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) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_mute_disable(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
LOG_DBG("AICS mute disable");
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
if (bt_aics_disable_mute(included.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_unmute(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
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) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_man_gain(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
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) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_auto_gain(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
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) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_auto_gain_only(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
LOG_DBG("AICS auto gain only set");
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
if (bt_aics_gain_set_auto_only(included.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_man_gain_only(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
LOG_DBG("AICS manual gain only set");
for (int i = 0; i < CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT; i++) {
if (bt_aics_gain_set_manual_only(included.aics[i]) != 0) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static uint8_t aics_desc(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_aics_audio_desc_cmd *cp = cmd;
char description[BT_AICS_MAX_INPUT_DESCRIPTION_SIZE];
LOG_DBG("AICS description");
if (cmd_len < sizeof(*cp) ||
cmd_len != sizeof(*cp) + cp->desc_len) {
return BTP_STATUS_FAILED;
}
if (cp->desc_len >= sizeof(description)) {
return BTP_STATUS_FAILED;
}
memcpy(description, cp->desc, cp->desc_len);
description[cp->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) {
return BTP_STATUS_FAILED;
}
}
return BTP_STATUS_SUCCESS;
}
static const struct btp_handler aics_handlers[] = {
{
.opcode = BTP_AICS_READ_SUPPORTED_COMMANDS,
.index = BTP_INDEX_NONE,
.expect_len = 0,
.func = aics_supported_commands,
},
{
.opcode = BTP_AICS_SET_GAIN,
.expect_len = sizeof(struct btp_aics_set_gain_cmd),
.func = aics_set_gain,
},
{
.opcode = BTP_AICS_MUTE,
.expect_len = 0,
.func = aics_mute,
},
{
.opcode = BTP_AICS_UNMUTE,
.expect_len = 0,
.func = aics_unmute,
},
{
.opcode = BTP_AICS_MUTE_DISABLE,
.expect_len = 0,
.func = aics_mute_disable,
},
{
.opcode = BTP_AICS_MAN_GAIN,
.expect_len = 0,
.func = aics_man_gain,
},
{
.opcode = BTP_AICS_AUTO_GAIN,
.expect_len = 0,
.func = aics_auto_gain,
},
{
.opcode = BTP_AICS_AUTO_GAIN_ONLY,
.expect_len = 0,
.func = aics_auto_gain_only,
},
{
.opcode = BTP_AICS_MAN_GAIN_ONLY,
.expect_len = 0,
.func = aics_man_gain_only,
},
{
.opcode = BTP_AICS_DESCRIPTION,
.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
.func = aics_desc,
},
};
/* Volume Offset Control Service */
static uint8_t vocs_supported_commands(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
@ -515,6 +259,44 @@ static const struct btp_handler vocs_handlers[] = {
},
};
/* AICS Callbacks */
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);
}
struct bt_aics_cb aics_server_cb = {
.state = aics_state_cb,
.gain_setting = aics_gain_setting_cb,
.type = aics_input_type_cb,
.status = aics_status_cb,
.description = aics_description_cb,
};
/* General profile handling */
static void set_register_params(uint8_t gain_mode)
{
@ -545,7 +327,7 @@ static void set_register_params(uint8_t 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.aics_param[i].cb = &aics_server_cb;
}
vcp_register_param.step = 1;
@ -570,6 +352,9 @@ uint8_t tester_init_vcs(void)
return BTP_STATUS_FAILED;
}
aics_server_instance.aics_cnt = included.aics_cnt;
aics_server_instance.aics = included.aics;
tester_register_command_handlers(BTP_SERVICE_ID_VCS, vcs_handlers,
ARRAY_SIZE(vcs_handlers));
@ -581,19 +366,6 @@ uint8_t tester_unregister_vcs(void)
return BTP_STATUS_SUCCESS;
}
uint8_t tester_init_aics(void)
{
tester_register_command_handlers(BTP_SERVICE_ID_AICS, aics_handlers,
ARRAY_SIZE(aics_handlers));
return tester_init_vcs();
}
uint8_t tester_unregister_aics(void)
{
return BTP_STATUS_SUCCESS;
}
uint8_t tester_init_vocs(void)
{
tester_register_command_handlers(BTP_SERVICE_ID_VOCS, vocs_handlers,