diff --git a/subsys/bluetooth/audio/micp_internal.h b/subsys/bluetooth/audio/micp_internal.h new file mode 100644 index 00000000000000..a68aaca7cdf831 --- /dev/null +++ b/subsys/bluetooth/audio/micp_internal.h @@ -0,0 +1,36 @@ +/** @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 3599287fdd5e4e..55fa6c3c5db306 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -19,9 +19,10 @@ #include #include #include - #include +#include "micp_internal.h" + LOG_MODULE_REGISTER(bt_micp_mic_ctlr, CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL); #include "common/bt_str.h" @@ -29,24 +30,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; diff --git a/tests/bluetooth/tester/CMakeLists.txt b/tests/bluetooth/tester/CMakeLists.txt index fb8f9114e41d21..71dbe85c2b3d6f 100644 --- a/tests/bluetooth/tester/CMakeLists.txt +++ b/tests/bluetooth/tester/CMakeLists.txt @@ -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() diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index c482c64b5dc42f..d974653083e8f0 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -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 diff --git a/tests/bluetooth/tester/src/btp/btp.h b/tests/bluetooth/tester/src/btp/btp.h index 5c0384c0b9f063..f925308fbc1545 100644 --- a/tests/bluetooth/tester/src/btp/btp.h +++ b/tests/bluetooth/tester/src/btp/btp.h @@ -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 diff --git a/tests/bluetooth/tester/src/btp/btp_aics.h b/tests/bluetooth/tester/src/btp/btp_aics.h index 41a5239059193f..0f3cba97a0e510 100644 --- a/tests/bluetooth/tester/src/btp/btp_aics.h +++ b/tests/bluetooth/tester/src/btp/btp_aics.h @@ -7,29 +7,125 @@ */ #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 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 +struct btp_aics_mute_cmd { + bt_addr_le_t address; +} __packed; + #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_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_DESCRIPTION 0x09 +#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; 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 00000000000000..000e879e5f47de --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_micp.h @@ -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; diff --git a/tests/bluetooth/tester/src/btp/bttester.h b/tests/bluetooth/tester/src/btp/bttester.h index b30eee70d44a66..e3ba93b0de7ca9 100644 --- a/tests/bluetooth/tester/src/btp/bttester.h +++ b/tests/bluetooth/tester/src/btp/bttester.h @@ -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); diff --git a/tests/bluetooth/tester/src/btp_aics.c b/tests/bluetooth/tester/src/btp_aics.c new file mode 100644 index 00000000000000..185053ab00bf22 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_aics.c @@ -0,0 +1,566 @@ +/* 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 +#include + +#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; +} diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index 36f92619bfce08..e1dafb09351a6d 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -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: diff --git a/tests/bluetooth/tester/src/btp_micp.c b/tests/bluetooth/tester/src/btp_micp.c new file mode 100644 index 00000000000000..52b071469aff81 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_micp.c @@ -0,0 +1,264 @@ +/* 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 +#include + +#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; +} diff --git a/tests/bluetooth/tester/src/btp_vcp.c b/tests/bluetooth/tester/src/btp_vcp.c index 744adf8ddc18a8..a0000b29c51a09 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_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,