1 /* Bluetooth Audio Content Control */
2
3 /*
4 * Copyright (c) 2020 Bose Corporation
5 * Copyright (c) 2021-2024 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9 #include <errno.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <sys/types.h>
13
14 #include <zephyr/bluetooth/att.h>
15 #include <zephyr/bluetooth/audio/ccid.h>
16 #include <zephyr/bluetooth/gatt.h>
17 #include <zephyr/bluetooth/uuid.h>
18 #include <zephyr/sys/__assert.h>
19
20 struct ccid_search_param {
21 const struct bt_gatt_attr *attr;
22 uint8_t ccid;
23 };
24
ccid_attr_cb(const struct bt_gatt_attr * attr,uint16_t handle,void * user_data)25 static uint8_t ccid_attr_cb(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data)
26 {
27 struct ccid_search_param *search_param = user_data;
28
29 if (attr->read != NULL) {
30 uint8_t ccid = 0U;
31 ssize_t res;
32
33 res = attr->read(NULL, attr, &ccid, sizeof(ccid), 0);
34
35 if (res == sizeof(ccid) && search_param->ccid == ccid) {
36 search_param->attr = attr;
37
38 return BT_GATT_ITER_STOP;
39 }
40 }
41
42 return BT_GATT_ITER_CONTINUE;
43 }
44
bt_ccid_find_attr(uint8_t ccid)45 const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid)
46 {
47 struct ccid_search_param search_param = {
48 .attr = NULL,
49 .ccid = ccid,
50 };
51
52 bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE, BT_ATT_LAST_ATTRIBUTE_HANDLE,
53 BT_UUID_CCID, NULL, 0, ccid_attr_cb, &search_param);
54
55 return search_param.attr;
56 }
57
bt_ccid_alloc_value(void)58 int bt_ccid_alloc_value(void)
59 {
60 static uint8_t next_ccid_value;
61 const uint8_t tmp = next_ccid_value;
62
63 /* Verify that the CCID is unused and increment until we reach an unused value or until we
64 * reach our starting point
65 * This is not a perfect check as there may be services that are not registered that have
66 * allocated a CCID.
67 * Implementing a perfect solution would require a alloc and free API where we need to
68 * keep track of all allocated CCIDs, which requires additional memory for something that's
69 * very unlikely to be an issue.
70 */
71 while (bt_ccid_find_attr(next_ccid_value) != NULL) {
72 next_ccid_value++;
73 if (tmp == next_ccid_value) {
74 return -ENOMEM;
75 }
76 }
77
78 return next_ccid_value++;
79 }
80