diff --git a/include/zephyr/bluetooth/audio/micp.h b/include/zephyr/bluetooth/audio/micp.h index 62c10544061e2e7..ce2e3133bce9caa 100644 --- a/include/zephyr/bluetooth/audio/micp.h +++ b/include/zephyr/bluetooth/audio/micp.h @@ -20,6 +20,7 @@ */ #include +#include <../../subsys/bluetooth/audio/micp_internal.h> #include @@ -36,13 +37,14 @@ extern "C" { /** Application error codes */ #define BT_MICP_ERR_MUTE_DISABLED 0x80 #define BT_MICP_ERR_VAL_OUT_OF_RANGE 0x81 +#define BT_MICP_ERR_INVALID_COUNTER 0x82 /** Microphone Control Profile mute states */ #define BT_MICP_MUTE_UNMUTED 0x00 #define BT_MICP_MUTE_MUTED 0x01 #define BT_MICP_MUTE_DISABLED 0x02 -/** @brief Opaque Microphone Controller instance. */ +///** @brief Opaque Microphone Controller instance. */ struct bt_micp_mic_ctlr; /** @brief Register parameters structure for Microphone Control Service */ @@ -272,35 +274,6 @@ int bt_micp_mic_ctlr_mute_get(struct bt_micp_mic_ctlr *mic_ctlr); */ int bt_micp_mic_ctlr_cb_register(struct bt_micp_mic_ctlr_cb *cb); -/** - * @brief Get the start handle and end handle a Microphone Controller instance - * - * @param mic_ctlr Microphone Controller instance pointer. - * @param mute_handle Mute characteristic handle. - * - * @return 0 if success, errno on failure. - */ -int bt_micp_mic_ctlr_chrc_get(const struct bt_micp_mic_ctlr *mic_ctlr, uint16_t *mute_handle); - -/** - * @brief Get handles of each characteristic of AICS. - * - * @param micp_included Included Services containing array of pointers to AICS instances. - * @param state_handle state handle. - * @param gain_handle gain handle. - * @param type_handle type handle. - * @param status_handle status handle. - * @param control_handle control handle. - * @param desc_handle desc handle. - * - * @return 0 if success, errno on failure. - */ -int bt_micp_mic_ctlr_aics_chrc_get(const struct bt_micp_included micp_included, - uint16_t *state_handle, uint16_t *gain_handle, - uint16_t *type_handle, - uint16_t *status_handle, uint16_t *control_handle, - uint16_t *desc_handle); - #ifdef __cplusplus } #endif diff --git a/subsys/bluetooth/audio/micp_internal.h b/subsys/bluetooth/audio/micp_internal.h new file mode 100644 index 000000000000000..f542642228a3245 --- /dev/null +++ b/subsys/bluetooth/audio/micp_internal.h @@ -0,0 +1,35 @@ +/** @file + * @brief Internal APIs for Bluetooth MICP. + */ + +/* + * Copyright (c) 2020 Bose Corporation + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MICP_INTERNAL_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MICP_INTERNAL_ +#include +#include + +struct bt_micp_mic_ctlr { + uint16_t start_handle; + uint16_t end_handle; + uint16_t mute_handle; + struct bt_gatt_subscribe_params mute_sub_params; + struct bt_gatt_discover_params mute_sub_disc_params; + + bool busy; + uint8_t mute_val_buf[1]; /* Mute value is a single octet */ + struct bt_gatt_write_params write_params; + struct bt_gatt_read_params read_params; + struct bt_gatt_discover_params discover_params; + struct bt_conn *conn; + + uint8_t aics_inst_cnt; + struct bt_aics *aics[CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT]; +}; + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MICP_INTERNAL_ */ diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 94b9b86f07c5c21..849a20c72e00f09 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -19,7 +19,8 @@ #include #include #include -#include <../../subsys/bluetooth/audio/aics_internal.h> + +#include "micp_internal.h" #include @@ -30,24 +31,6 @@ LOG_MODULE_REGISTER(bt_micp_mic_ctlr, CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL); /* Callback functions */ static struct bt_micp_mic_ctlr_cb *micp_mic_ctlr_cb; -struct bt_micp_mic_ctlr { - uint16_t start_handle; - uint16_t end_handle; - uint16_t mute_handle; - struct bt_gatt_subscribe_params mute_sub_params; - struct bt_gatt_discover_params mute_sub_disc_params; - - bool busy; - uint8_t mute_val_buf[1]; /* Mute value is a single octet */ - struct bt_gatt_write_params write_params; - struct bt_gatt_read_params read_params; - struct bt_gatt_discover_params discover_params; - struct bt_conn *conn; - - uint8_t aics_inst_cnt; - struct bt_aics *aics[CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST]; -}; - static struct bt_micp_mic_ctlr mic_ctlrs[CONFIG_BT_MAX_CONN]; static struct bt_uuid *mics_uuid = BT_UUID_MICS; @@ -516,47 +499,6 @@ int bt_micp_mic_ctlr_conn_get(const struct bt_micp_mic_ctlr *mic_ctlr, struct bt return 0; } -int bt_micp_mic_ctlr_chrc_get(const struct bt_micp_mic_ctlr *mic_ctlr, uint16_t *mute_handle) -{ - CHECKIF(mic_ctlr == NULL) - { - LOG_DBG("NULL mic_ctlr pointer"); - return -EINVAL; - } - - if (mic_ctlr->conn == NULL) { - LOG_DBG("mic_ctlr pointer not associated with a connection. " - "Do discovery first"); - return -ENOTCONN; - } - - *mute_handle = mic_ctlr->mute_handle; - - return 0; -} - -int bt_micp_mic_ctlr_aics_chrc_get(const struct bt_micp_included micp_included, - uint16_t *state_handle, uint16_t *gain_handle, - uint16_t *type_handle, - uint16_t *status_handle, uint16_t *control_handle, - uint16_t *desc_handle) -{ - CHECKIF(micp_included.aics == NULL) - { - LOG_DBG("NULL AICS instance"); - return -EINVAL; - } - - *state_handle = micp_included.aics[0]->cli.state_handle; - *gain_handle = micp_included.aics[0]->cli.gain_handle; - *type_handle = micp_included.aics[0]->cli.type_handle; - *status_handle = micp_included.aics[0]->cli.status_handle; - *control_handle = micp_included.aics[0]->cli.control_handle; - *desc_handle = micp_included.aics[0]->cli.desc_handle; - - return 0; -} - int bt_micp_mic_ctlr_mute_get(struct bt_micp_mic_ctlr *mic_ctlr) { int err; diff --git a/tests/bluetooth/tester/CMakeLists.txt b/tests/bluetooth/tester/CMakeLists.txt index e44159223fc1638..2ad9b1ba2479688 100644 --- a/tests/bluetooth/tester/CMakeLists.txt +++ b/tests/bluetooth/tester/CMakeLists.txt @@ -39,3 +39,8 @@ endif() if(CONFIG_BT_HAS) target_sources(app PRIVATE src/btp_has.c) endif() + +if(CONFIG_BT_MICP_MIC_DEV) + target_sources(app PRIVATE src/btp_micp.c) + target_sources(app PRIVATE src/btp_aics.c) +endif() \ No newline at end of file diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index d8903d56cb6f283..12c077fe85d3aa0 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -15,6 +15,12 @@ CONFIG_BT_BUF_EVT_RX_COUNT=16 CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_CMD_TX_SIZE=255 +# MICP +CONFIG_BT_MICP_MIC_DEV=y +CONFIG_BT_MICP_MIC_CTLR=y +CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST=1 +CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT=1 + # ASCS CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 diff --git a/tests/bluetooth/tester/src/btp/btp.h b/tests/bluetooth/tester/src/btp/btp.h index 3edbf6b036fb281..4d3305bc1077b71 100644 --- a/tests/bluetooth/tester/src/btp/btp.h +++ b/tests/bluetooth/tester/src/btp/btp.h @@ -24,6 +24,7 @@ #include "btp_ascs.h" #include "btp_bap.h" #include "btp_has.h" +#include "btp_micp.h" #define BTP_MTU 1024 #define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) @@ -47,8 +48,10 @@ #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_MICS 17 -#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_HAS +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_MICS #define BTP_STATUS_SUCCESS 0x00 #define BTP_STATUS_FAILED 0x01 diff --git a/tests/bluetooth/tester/src/btp/btp_aics.h b/tests/bluetooth/tester/src/btp/btp_aics.h index 41a5239059193f3..7806e4d5ae0d785 100644 --- a/tests/bluetooth/tester/src/btp/btp_aics.h +++ b/tests/bluetooth/tester/src/btp/btp_aics.h @@ -7,8 +7,25 @@ */ #include +#include /*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 btp_aics_instance aics_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_aics_status_ev(struct bt_conn *conn, bool active); +void btp_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]; @@ -16,20 +33,113 @@ struct btp_aics_read_supported_commands_rp { #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 +struct btp_aics_mute_cmd { + bt_addr_le_t address; +} __packed; + #define BTP_AICS_UNMUTE 0x04 +struct btp_aics_unmute_cmd { + bt_addr_le_t address; +} __packed; + #define BTP_AICS_MAN_GAIN 0x05 +struct btp_aics_manual_gain_cmd { + bt_addr_le_t address; +} __packed; + #define BTP_AICS_AUTO_GAIN 0x06 +struct btp_aics_auto_gain_cmd { + bt_addr_le_t address; +} __packed; + #define BTP_AICS_MAN_GAIN_ONLY 0x07 +struct btp_aics_man_gain_only_cmd { + bt_addr_le_t address; +} __packed; + #define BTP_AICS_AUTO_GAIN_ONLY 0x08 +struct btp_aics_auto_gain_only_cmd { + bt_addr_le_t address; +} __packed; -#define BTP_AICS_DESCRIPTION 0x09 +#define BTP_AICS_DESCRIPTION_SET 0x09 struct btp_aics_audio_desc_cmd { uint8_t desc_len; uint8_t desc[0]; } __packed; #define BTP_AICS_MUTE_DISABLE 0x0a +struct btp_aics_mute_disable_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_AICS_GAIN_SETTING_PROP 0x0b +struct btp_aics_gain_setting_prop_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_AICS_TYPE 0x0c +struct btp_aics_type_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_AICS_STATUS 0x0d +struct btp_aics_status_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_AICS_STATE 0x0e +struct btp_aics_state_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_AICS_DESCRIPTION 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_AICS_STATE_CHANGED_EV 0x81 +struct btp_aics_state_changed_ev { + bt_addr_le_t address; +} __packed; + +#define BTP_GAIN_SETTING_PROPERTIES_EV 0x82 +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 0x83 +struct btp_aics_input_type_ev { + bt_addr_le_t address; + uint8_t input_type; +} __packed; + +#define BTP_AICS_STATUS_EV 0x84 +struct btp_aics_status_ev { + bt_addr_le_t address; + bool active; +} __packed; + +#define BTP_AICS_DESCRIPTION_EV 0x85 +struct btp_aics_description_ev { + bt_addr_le_t address; + uint8_t data_len; + char data[0]; +} __packed; \ No newline at end of file diff --git a/tests/bluetooth/tester/src/btp/btp_micp.h b/tests/bluetooth/tester/src/btp/btp_micp.h new file mode 100644 index 000000000000000..053b7c247f7761d --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_micp.h @@ -0,0 +1,50 @@ +/* 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_DISCOVER 0x02 +struct btp_micp_discover_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MICP_MUTE_READ 0x03 +struct btp_micp_mute_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MICP_MUTE 0x04 +struct btp_micp_mute_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MICP_DISCOVERY_STATUS_SUCCESS 0x00 +#define BTP_MICP_DISCOVERY_STATUS_FAILED 0x01 + +/* 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; \ No newline at end of file diff --git a/tests/bluetooth/tester/src/btp/bttester.h b/tests/bluetooth/tester/src/btp/bttester.h index a68cb3c5c737ad8..50aacd81bf88dc8 100644 --- a/tests/bluetooth/tester/src/btp/bttester.h +++ b/tests/bluetooth/tester/src/btp/bttester.h @@ -89,3 +89,6 @@ uint8_t tester_unregister_bap(void); uint8_t tester_init_has(void); uint8_t tester_unregister_has(void); + +uint8_t tester_init_micp(void); +uint8_t tester_unregister_micp(void); diff --git a/tests/bluetooth/tester/src/btp_aics.c b/tests/bluetooth/tester/src/btp_aics.c new file mode 100644 index 000000000000000..b5c19a3cae0df37 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_aics.c @@ -0,0 +1,457 @@ +/* btp_aics.c - Bluetooth AICS Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "bap_endpoint.h" +#include +#include + +#define LOG_MODULE_NAME bttester_aics +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL +); + +#include "btp/btp.h" + +#define BT_AICS_MAX_INPUT_DESCRIPTION_SIZE 16 +#define BT_AICS_MAX_OUTPUT_DESCRIPTION_SIZE 16 + +struct btp_aics_instance aics_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_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); + tester_set_bit(rp->data, BTP_AICS_GAIN_SETTING_PROP); + tester_set_bit(rp->data, BTP_AICS_TYPE); + tester_set_bit(rp->data, BTP_AICS_STATUS); + tester_set_bit(rp->data, BTP_AICS_STATE); + + /* octet 1 */ + tester_set_bit(rp->data, BTP_AICS_DESCRIPTION); + + *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; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + bt_addr_le_copy(&ev.address, info.le.dst); + + 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_aics_state_changed_ev(struct bt_conn *conn) +{ + struct btp_aics_state_changed_ev ev; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + bt_addr_le_copy(&ev.address, info.le.dst); + + tester_event(BTP_SERVICE_ID_AICS, BTP_AICS_STATE_CHANGED_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; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + bt_addr_le_copy(&ev.address, info.le.dst); + + 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; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + bt_addr_le_copy(&ev.address, info.le.dst); + + ev.input_type = input_type; + + tester_event(BTP_SERVICE_ID_AICS, BTP_AICS_INPUT_TYPE_EV, &ev, sizeof(ev)); +} + +void btp_aics_status_ev(struct bt_conn *conn, bool active) +{ + struct btp_aics_status_ev ev; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + bt_addr_le_copy(&ev.address, info.le.dst); + + ev.active = active; + + tester_event(BTP_SERVICE_ID_AICS, BTP_AICS_STATUS_EV, &ev, sizeof(ev)); +} + +void btp_aics_description_ev(struct bt_conn *conn, uint8_t data_len, char *description) +{ + struct btp_aics_description_ev *ev; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + + net_buf_simple_init(rx_ev_buf, 0); + + ev = net_buf_simple_add(rx_ev_buf, sizeof(*ev)); + + bt_addr_le_copy(&ev->address, info.le.dst); + + 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); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_gain_set(aics_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) +{ + LOG_DBG("Unmute"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_unmute(aics_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) +{ + LOG_DBG("Mute"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_mute(aics_instance.aics[i]) != 0) { + return BTP_STATUS_FAILED; + } + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t aics_state(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + LOG_DBG("AICS State"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_state_get(aics_instance.aics[i]) != 0) { + return BTP_STATUS_FAILED; + } + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t aics_type(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + LOG_DBG("AICS Type"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_type_get(aics_instance.aics[i]) != 0) { + return BTP_STATUS_FAILED; + } + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t aics_status(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + LOG_DBG("AICS Status"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_status_get(aics_instance.aics[i]) != 0) { + return BTP_STATUS_FAILED; + } + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t aics_gain_setting_prop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + LOG_DBG("AICS Gain settings properties"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_gain_setting_get(aics_instance.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 set manual gain mode"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_manual_gain_set(aics_instance.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 set automatic gain mode"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_automatic_gain_set(aics_instance.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 (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_gain_set_manual_only(aics_instance.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 (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_gain_set_auto_only(aics_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 mute disable"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_disable_mute(aics_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; + } + + memcpy(description, cp->desc, cp->desc_len); + description[cp->desc_len] = '\0'; + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_description_set(aics_instance.aics[i], description) != 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) +{ + LOG_DBG("AICS Description"); + + for (uint8_t i = 0; i < aics_instance.aics_cnt; i++) { + if (bt_aics_description_get(aics_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, + .expect_len = sizeof(struct btp_aics_gain_setting_prop_cmd), + .func = aics_gain_setting_prop, + }, + { + .opcode = BTP_AICS_MUTE_DISABLE, + .expect_len = sizeof(struct btp_aics_mute_disable_cmd), + .func = aics_mute_disable, + }, + { + .opcode = BTP_AICS_MAN_GAIN, + .expect_len = sizeof(struct btp_aics_manual_gain_cmd), + .func = aics_man_gain, + }, + { + .opcode = BTP_AICS_AUTO_GAIN, + .expect_len = sizeof(struct btp_aics_auto_gain_cmd), + .func = aics_auto_gain, + }, + { + .opcode = BTP_AICS_AUTO_GAIN_ONLY, + .expect_len = sizeof(struct btp_aics_auto_gain_only_cmd), + .func = aics_auto_gain_only, + }, + { + .opcode = BTP_AICS_MAN_GAIN_ONLY, + .expect_len = sizeof(struct btp_aics_man_gain_only_cmd), + .func = aics_man_gain_only, + }, + { + .opcode = BTP_AICS_DESCRIPTION_SET, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = aics_desc_set, + }, + { + .opcode = BTP_AICS_DESCRIPTION, + .expect_len = sizeof(struct btp_aics_desc_cmd), + .func = aics_desc, + }, + { + .opcode = BTP_AICS_TYPE, + .expect_len = sizeof(struct btp_aics_type_cmd), + .func = aics_type, + }, + { + .opcode = BTP_AICS_STATUS, + .expect_len = sizeof(struct btp_aics_status_cmd), + .func = aics_status, + }, + { + .opcode = BTP_AICS_STATE, + .expect_len = sizeof(struct btp_aics_state_cmd), + .func = aics_state, + }, +}; + +uint8_t tester_init_aics(void) +{ + tester_register_command_handlers(BTP_SERVICE_ID_AICS, aics_handlers, + ARRAY_SIZE(aics_handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t tester_unregister_aics(void) +{ + return BTP_STATUS_SUCCESS; +} \ No newline at end of file diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index b0b9a366a93cb8d..81f4afdd910062c 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -77,6 +77,9 @@ static uint8_t supported_services(const void *cmd, uint16_t cmd_len, #if defined(CONFIG_BT_HAS) || defined(CONFIG_BT_HAS_CLIENT) tester_set_bit(rp->data, BTP_SERVICE_ID_HAS); #endif /* CONFIG_BT_HAS */ +#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; @@ -142,6 +145,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: @@ -220,6 +226,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: diff --git a/tests/bluetooth/tester/src/btp_micp.c b/tests/bluetooth/tester/src/btp_micp.c new file mode 100644 index 000000000000000..a66f7db2f6dca1d --- /dev/null +++ b/tests/bluetooth/tester/src/btp_micp.c @@ -0,0 +1,391 @@ +/* btp_micp.c - Bluetooth MICP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include <../../subsys/bluetooth/audio/micp_internal.h> +#include <../../subsys/bluetooth/audio/aics_internal.h> +#include "bap_endpoint.h" +#include +#include + +#define LOG_MODULE_NAME bttester_micp +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL +); + +#include "btp/btp.h" + +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_instance; +#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; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + bt_addr_le_copy(&ev.address, info.le.dst); + + 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; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + bt_addr_le_copy(&ev.address, info.le.dst); + + 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); +} + +/* MICP AICS Callbacks */ +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_unmute_cb(struct bt_aics *inst, int err) +{ + struct bt_conn *conn; + + bt_aics_client_conn_get(inst, &conn); + btp_send_aics_state_changed_ev(conn); + + LOG_DBG("AICS state callback (%d)", err); +} + +static void aics_mute_cb(struct bt_aics *inst, int err) +{ + struct bt_conn *conn; + + bt_aics_client_conn_get(inst, &conn); + btp_send_aics_state_changed_ev(conn); + + LOG_DBG("AICS state callback (%d)", err); +} + +static void aics_set_gain_cb(struct bt_aics *inst, int err) +{ + struct bt_conn *conn; + + bt_aics_client_conn_get(inst, &conn); + btp_send_aics_state_changed_ev(conn); + + LOG_DBG("AICS set gain cb (%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_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_aics_description_ev(conn, data_len, description); + + LOG_DBG("AICS description callback (%d)", err); +} + +static void aics_set_manual_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_conn *conn; + + bt_aics_client_conn_get(inst, &conn); + btp_send_aics_state_changed_ev(conn); + + LOG_DBG("AICS Set manual gain mode cb (%d)", err); +} + +static void aics_set_automatic_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_conn *conn; + + bt_aics_client_conn_get(inst, &conn); + btp_send_aics_state_changed_ev(conn); + + LOG_DBG("AICS Set manual gain mode cb (%d)", err); +} + +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, + .set_gain = aics_set_gain_cb, + .unmute = aics_unmute_cb, + .mute = aics_mute_cb, + .set_manual_mode = aics_set_manual_mode_cb, + .set_auto_mode = aics_set_automatic_mode_cb +}; + +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 != 0) { + LOG_DBG("Discovery failed (%d)", err); + return BTP_MICP_DISCOVERY_STATUS_FAILED; + } else { + 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_instance.aics_cnt = micp_included.aics_cnt; + aics_instance.aics = micp_included.aics; + bt_aics_client_cb_register(aics_instance.aics[0], &aics_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); + + return BTP_MICP_DISCOVERY_STATUS_SUCCESS; +} + +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_DISCOVER); + tester_set_bit(rp->data, BTP_MICP_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 != 0) { + 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 != 0) { + 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) +{ + LOG_DBG(""); + + if (bt_micp_mic_ctlr_mute(mic_ctlr) != 0) { + 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_DISCOVER, + .expect_len = sizeof(struct btp_micp_discover_cmd), + .func = micp_discover, + }, + { + .opcode = BTP_MICP_MUTE_READ, + .expect_len = sizeof(struct btp_micp_mute_read_cmd), + .func = micp_mute_read, + }, + { + .opcode = BTP_MICP_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 != 0) { + 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; +} diff --git a/tests/bluetooth/tester/src/btp_vcp.c b/tests/bluetooth/tester/src/btp_vcp.c index 744adf8ddc18a8d..e43b91e16fde039 100644 --- a/tests/bluetooth/tester/src/btp_vcp.c +++ b/tests/bluetooth/tester/src/btp_vcp.c @@ -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 #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_instance; /* Volume Control Service */ static uint8_t vcs_supported_commands(const void *cmd, uint16_t cmd_len, @@ -158,30 +161,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) { @@ -219,203 +198,6 @@ static struct bt_aics_cb aics_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) @@ -570,6 +352,10 @@ uint8_t tester_init_vcs(void) return BTP_STATUS_FAILED; } + aics_instance.aics_cnt = included.aics_cnt; + aics_instance.aics = included.aics; + bt_aics_client_cb_register(aics_instance.aics[0], &aics_cb); + tester_register_command_handlers(BTP_SERVICE_ID_VCS, vcs_handlers, ARRAY_SIZE(vcs_handlers)); @@ -581,19 +367,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,