Bluetooth: MICP: Allow for multiple mic_ctrl cb registers

Modify the MICP microphone controller callbacks to support
multiple registers by making it into a linked list.

This allow for multiple applications to get the information
from procedures or notifications.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2023-12-20 11:02:20 +01:00 committed by Anas Nashif
commit 562166b685
2 changed files with 219 additions and 87 deletions

View file

@ -2,7 +2,7 @@
/*
* Copyright (c) 2020 Bose Corporation
* Copyright (c) 2020-2022 Nordic Semiconductor ASA
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -28,7 +28,7 @@ LOG_MODULE_REGISTER(bt_micp_mic_ctlr, CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL);
#include "common/bt_str.h"
/* Callback functions */
static struct bt_micp_mic_ctlr_cb *micp_mic_ctlr_cb;
static sys_slist_t micp_mic_ctlr_cbs = SYS_SLIST_STATIC_INIT(&micp_mic_ctlr_cbs);
static struct bt_micp_mic_ctlr mic_ctlrs[CONFIG_BT_MAX_CONN];
static const struct bt_uuid *mics_uuid = BT_UUID_MICS;
@ -38,8 +38,46 @@ static struct bt_micp_mic_ctlr *mic_ctlr_get_by_conn(const struct bt_conn *conn)
return &mic_ctlrs[bt_conn_index(conn)];
}
static uint8_t mute_notify_handler(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params,
static void micp_mic_ctlr_mute_changed(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute_val)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->mute) {
listener->mute(mic_ctlr, err, mute_val);
}
}
}
static void micp_mic_ctlr_mute_written(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute_val)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (mute_val == BT_MICP_MUTE_UNMUTED) {
if (listener->unmute_written) {
listener->unmute_written(mic_ctlr, err);
}
} else {
if (listener->mute_written) {
listener->mute_written(mic_ctlr, err);
}
}
}
}
static void micp_mic_ctlr_discover_complete(struct bt_micp_mic_ctlr *mic_ctlr, int err)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->discover) {
listener->discover(mic_ctlr, err, err == 0 ? mic_ctlr->aics_inst_cnt : 0U);
}
}
}
static uint8_t mute_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
const void *data, uint16_t length)
{
uint8_t *mute_val;
@ -55,13 +93,10 @@ static uint8_t mute_notify_handler(struct bt_conn *conn,
if (length == sizeof(*mute_val)) {
mute_val = (uint8_t *)data;
LOG_DBG("Mute %u", *mute_val);
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->mute != NULL) {
micp_mic_ctlr_cb->mute(mic_ctlr, 0, *mute_val);
}
} else {
LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*mute_val));
micp_mic_ctlr_mute_changed(mic_ctlr, 0, *mute_val);
}
} else {
LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*mute_val));
}
return BT_GATT_ITER_CONTINUE;
@ -89,9 +124,7 @@ static uint8_t micp_mic_ctlr_read_mute_cb(struct bt_conn *conn, uint8_t err,
}
}
if (micp_mic_ctlr_cb != NULL && micp_mic_ctlr_cb->mute != NULL) {
micp_mic_ctlr_cb->mute(mic_ctlr, cb_err, mute_val);
}
micp_mic_ctlr_mute_changed(mic_ctlr, cb_err, mute_val);
return BT_GATT_ITER_STOP;
}
@ -106,18 +139,7 @@ static void micp_mic_ctlr_write_mics_mute_cb(struct bt_conn *conn, uint8_t err,
mic_ctlr->busy = false;
if (mute_val == BT_MICP_MUTE_UNMUTED) {
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->unmute_written != NULL) {
micp_mic_ctlr_cb->unmute_written(mic_ctlr, err);
}
} else {
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->mute_written != NULL) {
micp_mic_ctlr_cb->mute_written(mic_ctlr, err);
}
}
micp_mic_ctlr_mute_written(mic_ctlr, err, mute_val);
}
#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
@ -136,21 +158,143 @@ static struct bt_micp_mic_ctlr *lookup_micp_by_aics(const struct bt_aics *aics)
return NULL;
}
static void aics_discover_cb(struct bt_aics *inst, int err)
static void micp_mic_ctlr_aics_state_cb(struct bt_aics *inst, int err, int8_t gain, uint8_t mute,
uint8_t mode)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.state) {
listener->aics_cb.state(inst, err, gain, mute, mode);
}
}
}
static void micp_mic_ctlr_aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
int8_t minimum, int8_t maximum)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.gain_setting) {
listener->aics_cb.gain_setting(inst, err, units, minimum, maximum);
}
}
}
static void micp_mic_ctlr_aics_type_cb(struct bt_aics *inst, int err, uint8_t type)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.type) {
listener->aics_cb.type(inst, err, type);
}
}
}
static void micp_mic_ctlr_aics_status_cb(struct bt_aics *inst, int err, bool active)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.status) {
listener->aics_cb.status(inst, err, active);
}
}
}
static void micp_mic_ctlr_aics_description_cb(struct bt_aics *inst, int err, char *description)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.description) {
listener->aics_cb.description(inst, err, description);
}
}
}
static void micp_mic_ctlr_aics_discover_cb(struct bt_aics *inst, int err)
{
struct bt_micp_mic_ctlr *mic_ctlr = lookup_micp_by_aics(inst);
struct bt_micp_mic_ctlr_cb *listener, *next;
if (mic_ctlr == NULL) {
LOG_ERR("Could not lookup mic_ctlr from aics");
micp_mic_ctlr_discover_complete(mic_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY));
return;
}
if (err == 0) {
/* Continue discovery of included services */
err = bt_gatt_discover(mic_ctlr->conn,
&mic_ctlr->discover_params);
err = bt_gatt_discover(mic_ctlr->conn, &mic_ctlr->discover_params);
}
if (err != 0) {
LOG_DBG("Discover failed (err %d)", err);
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->discover != NULL) {
micp_mic_ctlr_cb->discover(mic_ctlr, err, 0);
micp_mic_ctlr_discover_complete(mic_ctlr, err);
}
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.discover) {
listener->aics_cb.discover(inst, err);
}
}
}
static void micp_mic_ctlr_aics_set_gain_cb(struct bt_aics *inst, int err)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.set_gain) {
listener->aics_cb.set_gain(inst, err);
}
}
}
static void micp_mic_ctlr_aics_unmute_cb(struct bt_aics *inst, int err)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.unmute) {
listener->aics_cb.unmute(inst, err);
}
}
}
static void micp_mic_ctlr_aics_mute_cb(struct bt_aics *inst, int err)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.mute) {
listener->aics_cb.mute(inst, err);
}
}
}
static void micp_mic_ctlr_aics_set_manual_mode_cb(struct bt_aics *inst, int err)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.set_manual_mode) {
listener->aics_cb.set_manual_mode(inst, err);
}
}
}
static void micp_mic_ctlr_aics_set_auto_mode_cb(struct bt_aics *inst, int err)
{
struct bt_micp_mic_ctlr_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) {
if (listener->aics_cb.set_auto_mode) {
listener->aics_cb.set_auto_mode(inst, err);
}
}
}
@ -166,11 +310,7 @@ static uint8_t micp_discover_include_func(
LOG_DBG("Discover include complete for MICS: %u AICS", mic_ctlr->aics_inst_cnt);
(void)memset(params, 0, sizeof(*params));
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->discover != NULL) {
micp_mic_ctlr_cb->discover(mic_ctlr, 0,
mic_ctlr->aics_inst_cnt);
}
micp_mic_ctlr_discover_complete(mic_ctlr, 0);
return BT_GATT_ITER_STOP;
}
@ -201,12 +341,9 @@ static uint8_t micp_discover_include_func(
&param);
if (err != 0) {
LOG_DBG("AICS Discover failed (err %d)", err);
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->discover != NULL) {
micp_mic_ctlr_cb->discover(mic_ctlr, err,
0);
}
micp_mic_ctlr_discover_complete(mic_ctlr, err);
}
return BT_GATT_ITER_STOP;
}
}
@ -241,17 +378,12 @@ static uint8_t micp_discover_func(struct bt_conn *conn,
&mic_ctlr->discover_params);
if (err != 0) {
LOG_DBG("Discover AICS failed (err %d)", err);
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->discover != NULL) {
micp_mic_ctlr_cb->discover(mic_ctlr, err, 0);
}
micp_mic_ctlr_discover_complete(mic_ctlr, err);
}
} else {
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->discover != NULL) {
micp_mic_ctlr_cb->discover(mic_ctlr, err, 0);
}
micp_mic_ctlr_discover_complete(mic_ctlr, err);
}
return BT_GATT_ITER_STOP;
}
@ -299,10 +431,8 @@ static uint8_t primary_discover_func(struct bt_conn *conn,
if (attr == NULL) {
LOG_DBG("Could not find a MICS instance on the server");
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->discover != NULL) {
micp_mic_ctlr_cb->discover(mic_ctlr, -ENODATA, 0);
}
micp_mic_ctlr_discover_complete(mic_ctlr, -ENODATA);
return BT_GATT_ITER_STOP;
}
@ -327,10 +457,7 @@ static uint8_t primary_discover_func(struct bt_conn *conn,
err = bt_gatt_discover(conn, &mic_ctlr->discover_params);
if (err != 0) {
LOG_DBG("Discover failed (err %d)", err);
if (micp_mic_ctlr_cb != NULL &&
micp_mic_ctlr_cb->discover != NULL) {
micp_mic_ctlr_cb->discover(mic_ctlr, err, 0);
}
micp_mic_ctlr_discover_complete(mic_ctlr, err);
}
return BT_GATT_ITER_STOP;
@ -405,19 +532,34 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi
static bool initialized;
if (!initialized) {
for (int i = 0; i < ARRAY_SIZE(mic_ctlr->aics); i++) {
mic_ctlr->aics[i] = bt_aics_client_free_instance_get();
for (size_t i = 0U; i < ARRAY_SIZE(mic_ctlrs); i++) {
for (size_t j = 0U; j < ARRAY_SIZE(mic_ctlr->aics); j++) {
static struct bt_aics_cb aics_cb = {
.state = micp_mic_ctlr_aics_state_cb,
.gain_setting = micp_mic_ctlr_aics_gain_setting_cb,
.type = micp_mic_ctlr_aics_type_cb,
.status = micp_mic_ctlr_aics_status_cb,
.description = micp_mic_ctlr_aics_description_cb,
.discover = micp_mic_ctlr_aics_discover_cb,
.set_gain = micp_mic_ctlr_aics_set_gain_cb,
.unmute = micp_mic_ctlr_aics_unmute_cb,
.mute = micp_mic_ctlr_aics_mute_cb,
.set_manual_mode = micp_mic_ctlr_aics_set_manual_mode_cb,
.set_auto_mode = micp_mic_ctlr_aics_set_auto_mode_cb,
};
if (mic_ctlr->aics[i] == NULL) {
return -ENOMEM;
mic_ctlrs[i].aics[j] = bt_aics_client_free_instance_get();
if (mic_ctlrs[i].aics[j] == NULL) {
return -ENOMEM;
}
bt_aics_client_cb_register(mic_ctlrs[i].aics[j], &aics_cb);
}
bt_aics_client_cb_register(mic_ctlr->aics[i],
&micp_mic_ctlr_cb->aics_cb);
}
}
initialized = true;
initialized = true;
}
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
mic_ctlr->conn = bt_conn_ref(conn);
@ -437,33 +579,20 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi
int bt_micp_mic_ctlr_cb_register(struct bt_micp_mic_ctlr_cb *cb)
{
#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
struct bt_aics_cb *aics_cb = NULL;
struct bt_micp_mic_ctlr_cb *tmp;
if (cb != NULL) {
/* Ensure that the cb->aics_cb.discover is the aics_discover_cb */
CHECKIF(cb->aics_cb.discover != NULL &&
cb->aics_cb.discover != aics_discover_cb) {
LOG_ERR("AICS discover callback shall not be set");
return -EINVAL;
}
cb->aics_cb.discover = aics_discover_cb;
aics_cb = &cb->aics_cb;
CHECKIF(cb == NULL) {
return -EINVAL;
}
for (int i = 0; i < ARRAY_SIZE(mic_ctlrs); i++) {
for (int j = 0; j < ARRAY_SIZE(mic_ctlrs[i].aics); j++) {
struct bt_aics *aics = mic_ctlrs[i].aics[j];
if (aics != NULL) {
bt_aics_client_cb_register(aics, aics_cb);
}
SYS_SLIST_FOR_EACH_CONTAINER(&micp_mic_ctlr_cbs, tmp, _node) {
if (tmp == cb) {
LOG_DBG("Already registered");
return -EALREADY;
}
}
#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
micp_mic_ctlr_cb = cb;
sys_slist_append(&micp_mic_ctlr_cbs, &cb->_node);
return 0;
}