80 lines
1.9 KiB
C
80 lines
1.9 KiB
C
/* Bluetooth Audio Content Control */
|
|
|
|
/*
|
|
* Copyright (c) 2020 Bose Corporation
|
|
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include <errno.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <zephyr/bluetooth/att.h>
|
|
#include <zephyr/bluetooth/audio/ccid.h>
|
|
#include <zephyr/bluetooth/gatt.h>
|
|
#include <zephyr/bluetooth/uuid.h>
|
|
#include <zephyr/sys/__assert.h>
|
|
|
|
struct ccid_search_param {
|
|
const struct bt_gatt_attr *attr;
|
|
uint8_t ccid;
|
|
};
|
|
|
|
static uint8_t ccid_attr_cb(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data)
|
|
{
|
|
struct ccid_search_param *search_param = user_data;
|
|
|
|
if (attr->read != NULL) {
|
|
uint8_t ccid = 0U;
|
|
ssize_t res;
|
|
|
|
res = attr->read(NULL, attr, &ccid, sizeof(ccid), 0);
|
|
|
|
if (res == sizeof(ccid) && search_param->ccid == ccid) {
|
|
search_param->attr = attr;
|
|
|
|
return BT_GATT_ITER_STOP;
|
|
}
|
|
}
|
|
|
|
return BT_GATT_ITER_CONTINUE;
|
|
}
|
|
|
|
const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid)
|
|
{
|
|
struct ccid_search_param search_param = {
|
|
.attr = NULL,
|
|
.ccid = ccid,
|
|
};
|
|
|
|
bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE, BT_ATT_LAST_ATTRIBUTE_HANDLE,
|
|
BT_UUID_CCID, NULL, 0, ccid_attr_cb, &search_param);
|
|
|
|
return search_param.attr;
|
|
}
|
|
|
|
int bt_ccid_alloc_value(void)
|
|
{
|
|
static uint8_t next_ccid_value;
|
|
const uint8_t tmp = next_ccid_value;
|
|
|
|
/* Verify that the CCID is unused and increment until we reach an unused value or until we
|
|
* reach our starting point
|
|
* This is not a perfect check as there may be services that are not registered that have
|
|
* allocated a CCID.
|
|
* Implementing a perfect solution would require a alloc and free API where we need to
|
|
* keep track of all allocated CCIDs, which requires additional memory for something that's
|
|
* very unlikely to be an issue.
|
|
*/
|
|
while (bt_ccid_find_attr(next_ccid_value) != NULL) {
|
|
next_ccid_value++;
|
|
if (tmp == next_ccid_value) {
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
return next_ccid_value++;
|
|
}
|