1 /*  Bluetooth Audio Content Control */
2 
3 /*
4  * Copyright (c) 2020 Bose Corporation
5  * Copyright (c) 2021 Nordic Semiconductor ASA
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <sys/types.h>
12 
13 #include <zephyr/bluetooth/att.h>
14 #include <zephyr/bluetooth/gatt.h>
15 #include <zephyr/bluetooth/uuid.h>
16 #include <zephyr/sys/__assert.h>
17 
18 #include "ccid_internal.h"
19 
bt_ccid_get_value(void)20 uint8_t bt_ccid_get_value(void)
21 {
22 	static uint8_t ccid_value;
23 
24 	/* By spec, the CCID can take all values up to and including 0xFF.
25 	 * But since this is a value we provide, we do not have to use all of
26 	 * them.  254 CCID values on a device should be plenty, the last one
27 	 * can be used to prevent wraparound.
28 	 */
29 	__ASSERT(ccid_value != UINT8_MAX,
30 		 "Cannot allocate any more control control IDs");
31 
32 	return ccid_value++;
33 }
34 
35 struct ccid_search_param {
36 	const struct bt_gatt_attr *attr;
37 	uint8_t ccid;
38 };
39 
ccid_attr_cb(const struct bt_gatt_attr * attr,uint16_t handle,void * user_data)40 static uint8_t ccid_attr_cb(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data)
41 {
42 	struct ccid_search_param *search_param = user_data;
43 
44 	if (attr->read != NULL) {
45 		uint8_t ccid = 0U;
46 		ssize_t res;
47 
48 		res = attr->read(NULL, attr, &ccid, sizeof(ccid), 0);
49 
50 		if (res == sizeof(ccid) && search_param->ccid == ccid) {
51 			search_param->attr = attr;
52 
53 			return BT_GATT_ITER_STOP;
54 		}
55 	}
56 
57 	return BT_GATT_ITER_CONTINUE;
58 }
59 
bt_ccid_find_attr(uint8_t ccid)60 const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid)
61 {
62 	struct ccid_search_param search_param = {
63 		.attr = NULL,
64 		.ccid = ccid,
65 	};
66 
67 	bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE, BT_ATT_LAST_ATTRIBUTE_HANDLE,
68 				  BT_UUID_CCID, NULL, 0, ccid_attr_cb, &search_param);
69 
70 	return search_param.attr;
71 }
72