blob: b8c0b534a2cb772cd638421e9d55c9842adf6073 [file] [log] [blame]
/*
* Copyright (c) 2021-2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef CONFIG_BT_MICP_MIC_CTLR
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/audio/micp.h>
#include "common.h"
#define AICS_DESC_SIZE 64
extern enum bst_result_t bst_result;
static struct bt_micp_mic_ctlr *mic_ctlr;
static struct bt_micp_included micp_included;
static volatile bool g_bt_init;
static volatile bool g_is_connected;
static volatile bool g_discovery_complete;
static volatile bool g_write_complete;
static volatile uint8_t g_mute;
static volatile uint8_t g_aics_count;
static volatile int8_t g_aics_gain;
static volatile uint8_t g_aics_input_mute;
static volatile uint8_t g_aics_mode;
static volatile uint8_t g_aics_input_type;
static volatile uint8_t g_aics_units;
static volatile uint8_t g_aics_gain_max;
static volatile uint8_t g_aics_gain_min;
static volatile bool g_aics_active = true;
static char g_aics_desc[AICS_DESC_SIZE];
static volatile bool g_cb;
static void aics_state_cb(struct bt_aics *inst, int err, int8_t gain,
uint8_t mute, uint8_t mode)
{
if (err != 0) {
FAIL("AICS state cb err (%d)", err);
return;
}
g_aics_gain = gain;
g_aics_input_mute = mute;
g_aics_mode = mode;
g_cb = true;
}
static void aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
int8_t minimum, int8_t maximum)
{
if (err != 0) {
FAIL("AICS gain setting cb err (%d)", err);
return;
}
g_aics_units = units;
g_aics_gain_min = minimum;
g_aics_gain_max = maximum;
g_cb = true;
}
static void aics_input_type_cb(struct bt_aics *inst, int err,
uint8_t input_type)
{
if (err != 0) {
FAIL("AICS input type cb err (%d)", err);
return;
}
g_aics_input_type = input_type;
g_cb = true;
}
static void aics_status_cb(struct bt_aics *inst, int err, bool active)
{
if (err != 0) {
FAIL("AICS status cb err (%d)", err);
return;
}
g_aics_active = active;
g_cb = true;
}
static void aics_description_cb(struct bt_aics *inst, int err,
char *description)
{
if (err != 0) {
FAIL("AICS description cb err (%d)", err);
return;
}
if (strlen(description) > sizeof(g_aics_desc) - 1) {
printk("Warning: AICS description (%zu) is larger than buffer (%zu)\n",
strlen(description), sizeof(g_aics_desc) - 1);
}
strncpy(g_aics_desc, description, sizeof(g_aics_desc) - 1);
g_aics_desc[sizeof(g_aics_desc) - 1] = '\0';
g_cb = true;
}
static void aics_write_cb(struct bt_aics *inst, int err)
{
if (err != 0) {
FAIL("AICS write failed (%d)\n", err);
return;
}
g_write_complete = true;
}
static void micp_mic_ctlr_discover_cb(struct bt_micp_mic_ctlr *mic_ctlr,
int err,
uint8_t aics_count)
{
if (err != 0) {
FAIL("MICS could not be discovered (%d)\n", err);
return;
}
g_aics_count = aics_count;
g_discovery_complete = true;
}
static void micp_mic_ctlr_mute_written_cb(struct bt_micp_mic_ctlr *mic_ctlr,
int err)
{
if (err != 0) {
FAIL("mic_ctlr mute write failed (%d)\n", err);
return;
}
g_write_complete = true;
}
static void micp_mic_ctlr_unmute_written_cb(struct bt_micp_mic_ctlr *mic_ctlr,
int err)
{
if (err != 0) {
FAIL("mic_ctlr unmute write failed (%d)\n", err);
return;
}
g_write_complete = true;
}
static void micp_mic_ctlr_mute_cb(struct bt_micp_mic_ctlr *mic_ctlr, int err,
uint8_t mute)
{
if (err != 0) {
FAIL("mic_ctlr mute read failed (%d)\n", err);
return;
}
g_mute = mute;
g_cb = true;
}
static struct bt_micp_mic_ctlr_cb micp_mic_ctlr_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,
.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_write_cb,
.unmute = aics_write_cb,
.mute = aics_write_cb,
.set_manual_mode = aics_write_cb,
.set_auto_mode = aics_write_cb,
}
};
static void connected(struct bt_conn *conn, uint8_t err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
if (err != 0) {
bt_conn_unref(default_conn);
default_conn = NULL;
FAIL("Failed to connect to %s (%u)\n", addr, err);
return;
}
printk("Connected to %s\n", addr);
g_is_connected = true;
}
static void bt_ready(int err)
{
if (err != 0) {
FAIL("Bluetooth discover failed (err %d)\n", err);
return;
}
g_bt_init = true;
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};
static int test_aics(void)
{
int err;
int8_t expected_gain;
uint8_t expected_input_mute;
uint8_t expected_mode;
uint8_t expected_input_type;
char expected_aics_desc[AICS_DESC_SIZE];
struct bt_conn *cached_conn;
printk("Getting AICS client conn\n");
err = bt_aics_client_conn_get(micp_included.aics[0], &cached_conn);
if (err != 0) {
FAIL("Could not get AICS client conn (err %d)\n", err);
return err;
}
if (cached_conn != default_conn) {
FAIL("Cached conn was not the conn used to discover");
return -ENOTCONN;
}
printk("Getting AICS state\n");
g_cb = false;
err = bt_aics_state_get(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not get AICS state (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_cb);
printk("AICS state get\n");
printk("Getting AICS gain setting\n");
g_cb = false;
err = bt_aics_gain_setting_get(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not get AICS gain setting (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_cb);
printk("AICS gain setting get\n");
printk("Getting AICS input type\n");
expected_input_type = BT_AICS_INPUT_TYPE_UNSPECIFIED;
g_cb = false;
err = bt_aics_type_get(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not get AICS input type (err %d)\n", err);
return err;
}
/* Expect and wait for input_type from init */
WAIT_FOR_COND(g_cb && expected_input_type == g_aics_input_type);
printk("AICS input type get\n");
printk("Getting AICS status\n");
g_cb = false;
err = bt_aics_status_get(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not get AICS status (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_cb);
printk("AICS status get\n");
printk("Getting AICS description\n");
g_cb = false;
err = bt_aics_description_get(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not get AICS description (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_cb);
printk("AICS description get\n");
printk("Setting AICS mute\n");
expected_input_mute = BT_AICS_STATE_MUTED;
g_write_complete = g_cb = false;
err = bt_aics_mute(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not set AICS mute (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_aics_input_mute == expected_input_mute &&
g_cb && g_write_complete);
printk("AICS mute set\n");
printk("Setting AICS unmute\n");
expected_input_mute = BT_AICS_STATE_UNMUTED;
g_write_complete = g_cb = false;
err = bt_aics_unmute(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not set AICS unmute (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_aics_input_mute == expected_input_mute &&
g_cb && g_write_complete);
printk("AICS unmute set\n");
printk("Setting AICS auto mode\n");
expected_mode = BT_AICS_MODE_AUTO;
g_write_complete = g_cb = false;
err = bt_aics_automatic_gain_set(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not set AICS auto mode (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_aics_mode == expected_mode && g_cb && g_write_complete);
printk("AICS auto mode set\n");
printk("Setting AICS manual mode\n");
expected_mode = BT_AICS_MODE_MANUAL;
g_write_complete = g_cb = false;
err = bt_aics_manual_gain_set(micp_included.aics[0]);
if (err != 0) {
FAIL("Could not set AICS manual mode (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_aics_mode == expected_mode && g_cb && g_write_complete);
printk("AICS manual mode set\n");
printk("Setting AICS gain\n");
expected_gain = g_aics_gain_max - 1;
g_write_complete = g_cb = false;
err = bt_aics_gain_set(micp_included.aics[0], expected_gain);
if (err != 0) {
FAIL("Could not set AICS gain (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_aics_gain == expected_gain && g_cb && g_write_complete);
printk("AICS gain set\n");
printk("Setting AICS Description\n");
strncpy(expected_aics_desc, "New Input Description",
sizeof(expected_aics_desc));
expected_aics_desc[sizeof(expected_aics_desc) - 1] = '\0';
g_cb = false;
err = bt_aics_description_set(micp_included.aics[0],
expected_aics_desc);
if (err != 0) {
FAIL("Could not set AICS Description (err %d)\n", err);
return err;
}
WAIT_FOR_COND(g_cb &&
(strncmp(expected_aics_desc, g_aics_desc,
sizeof(expected_aics_desc)) == 0));
printk("AICS Description set\n");
printk("AICS passed\n");
return 0;
}
static void test_main(void)
{
int err;
uint8_t expected_mute;
struct bt_conn *cached_conn;
err = bt_enable(bt_ready);
if (err != 0) {
FAIL("Bluetooth discover failed (err %d)\n", err);
return;
}
bt_micp_mic_ctlr_cb_register(&micp_mic_ctlr_cbs);
WAIT_FOR_COND(g_bt_init);
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
if (err != 0) {
FAIL("Scanning failed to start (err %d)\n", err);
return;
}
printk("Scanning successfully started\n");
WAIT_FOR_COND(g_is_connected);
err = bt_micp_mic_ctlr_discover(default_conn, &mic_ctlr);
if (err != 0) {
FAIL("Failed to discover MICS %d", err);
}
WAIT_FOR_COND(g_discovery_complete);
err = bt_micp_mic_ctlr_included_get(mic_ctlr, &micp_included);
if (err != 0) {
FAIL("Failed to get mic_ctlr context (err %d)\n", err);
return;
}
printk("Getting mic_ctlr conn\n");
err = bt_micp_mic_ctlr_conn_get(mic_ctlr, &cached_conn);
if (err != 0) {
FAIL("Failed to get mic_ctlr conn (err %d)\n", err);
return;
}
if (cached_conn != default_conn) {
FAIL("Cached conn was not the conn used to discover");
return;
}
printk("Getting mic_ctlr mute state\n");
g_cb = false;
err = bt_micp_mic_ctlr_mute_get(mic_ctlr);
if (err != 0) {
FAIL("Could not get mic_ctlr mute state (err %d)\n", err);
return;
}
WAIT_FOR_COND(g_cb);
printk("mic_ctlr mute state received\n");
printk("Muting mic_ctlr\n");
expected_mute = 1;
g_write_complete = g_cb = false;
err = bt_micp_mic_ctlr_mute(mic_ctlr);
if (err != 0) {
FAIL("Could not mute mic_ctlr (err %d)\n", err);
return;
}
WAIT_FOR_COND(g_mute == expected_mute && g_cb && g_write_complete);
printk("mic_ctlr muted\n");
printk("Unmuting mic_ctlr\n");
expected_mute = 0;
g_write_complete = g_cb = false;
err = bt_micp_mic_ctlr_unmute(mic_ctlr);
if (err != 0) {
FAIL("Could not unmute mic_ctlr (err %d)\n", err);
return;
}
WAIT_FOR_COND(g_mute == expected_mute && g_cb && g_write_complete);
printk("mic_ctlr unmuted\n");
if (CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST > 0 && g_aics_count > 0) {
if (test_aics()) {
return;
}
}
PASS("mic_ctlr Passed\n");
}
static const struct bst_test_instance test_micp[] = {
{
.test_id = "micp_mic_ctlr",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = test_main
},
BSTEST_END_MARKER
};
struct bst_test_list *test_micp_mic_ctlr_install(struct bst_test_list *tests)
{
return bst_add_tests(tests, test_micp);
}
#else
struct bst_test_list *test_micp_mic_ctlr_install(struct bst_test_list *tests)
{
return tests;
}
#endif /* CONFIG_BT_MICP_MIC_CTLR */