Bluetooth: Add BT_GATT_CCC macro
BT_GATT_CCC uses _bt_gatt_ccc internal struct to handle peer configurations and special helpers to read and write to minimize the code necessary to handle CCC in the task. Note this not yet include handling of connection and disconnection but the idea is that the core would automatically disable the configurations while disconnected and re-enable once peer connect back. Change-Id: I89325b8a074766b9fd2423085565df669f7275e1 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
1d734fd60f
commit
e8e0fbe63a
2 changed files with 164 additions and 0 deletions
|
@ -290,6 +290,78 @@ int bt_gatt_attr_read_chrc(const bt_addr_le_t *peer,
|
|||
.user_data = _value, \
|
||||
}
|
||||
|
||||
struct bt_gatt_ccc_cfg {
|
||||
bt_addr_le_t peer;
|
||||
uint16_t value;
|
||||
};
|
||||
|
||||
struct _bt_gatt_ccc {
|
||||
struct bt_gatt_ccc_cfg *cfg;
|
||||
size_t cfg_len;
|
||||
uint16_t value;
|
||||
uint16_t value_handle;
|
||||
void (*cfg_changed)(uint16_t value);
|
||||
};
|
||||
|
||||
/** @brief Read Client Characteristic Configuration Attribute helper
|
||||
*
|
||||
* Read CCC attribute value storing the result into buffer after
|
||||
* enconding it.
|
||||
* NOTE: Only use this with attributes which user_data is a _bt_gatt_ccc.
|
||||
*
|
||||
* @param peer remote address
|
||||
* @param attr attribute to read
|
||||
* @param buf buffer to store the value read
|
||||
* @param len buffer length
|
||||
* @param offset start offset
|
||||
*
|
||||
* @return number of bytes read in case of success or negative values in
|
||||
* case of error.
|
||||
*/
|
||||
int bt_gatt_attr_read_ccc(const bt_addr_le_t *peer,
|
||||
const struct bt_gatt_attr *attr, void *buf,
|
||||
uint8_t len, uint16_t offset);
|
||||
|
||||
/** @brief Write Client Characteristic Configuration Attribute helper
|
||||
*
|
||||
* Write value in the buffer into CCC attribute.
|
||||
* NOTE: Only use this with attributes which user_data is a _bt_gatt_ccc.
|
||||
*
|
||||
* @param peer remote address
|
||||
* @param attr attribute to read
|
||||
* @param buf buffer to store the value read
|
||||
* @param len buffer length
|
||||
* @param offset start offset
|
||||
*
|
||||
* @return number of bytes written in case of success or negative values in
|
||||
* case of error.
|
||||
*/
|
||||
int bt_gatt_attr_write_ccc(const bt_addr_le_t *peer,
|
||||
const struct bt_gatt_attr *attr, const void *buf,
|
||||
uint8_t len, uint16_t offset);
|
||||
|
||||
/** @brief Client Characteristic Configuration Declaration Macro
|
||||
*
|
||||
* Helper macro to declare a CCC attribute.
|
||||
*
|
||||
* @param _handle descriptor attribute handle
|
||||
* @param _value_handle characteristic attribute value handle
|
||||
* @param _cfg initial configuration
|
||||
* @param _cfg_changed configuration changed callback
|
||||
*/
|
||||
#define BT_GATT_CCC(_handle, _value_handle, _cfg, _cfg_changed) \
|
||||
{ \
|
||||
.handle = _handle, \
|
||||
.uuid = (&(struct bt_uuid) { .type = BT_UUID_16, \
|
||||
.u16 = BT_UUID_GATT_CCC }), \
|
||||
.read = bt_gatt_attr_read_ccc, \
|
||||
.write = bt_gatt_attr_write_ccc, \
|
||||
.user_data = (&(struct _bt_gatt_ccc) { .cfg = _cfg, \
|
||||
.cfg_len = ARRAY_SIZE(_cfg), \
|
||||
.value_handle = _value_handle, \
|
||||
.cfg_changed = _cfg_changed, }),\
|
||||
}
|
||||
|
||||
/** @brief Descriptor Declaration Macro
|
||||
*
|
||||
* Helper macro to declare a descriptor attribute.
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include <bluetooth/uuid.h>
|
||||
#include <bluetooth/gatt.h>
|
||||
|
||||
#include "hci_core.h"
|
||||
|
||||
#if !defined(CONFIG_BLUETOOTH_DEBUG_GATT)
|
||||
#undef BT_DBG
|
||||
#define BT_DBG(fmt, ...)
|
||||
|
@ -173,3 +175,93 @@ void bt_gatt_foreach_attr(uint16_t start_handle, uint16_t end_handle,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int bt_gatt_attr_read_ccc(const bt_addr_le_t *peer,
|
||||
const struct bt_gatt_attr *attr, void *buf,
|
||||
uint8_t len, uint16_t offset)
|
||||
{
|
||||
struct _bt_gatt_ccc *ccc = attr->user_data;
|
||||
uint16_t value;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ccc->cfg_len; i++) {
|
||||
if (bt_addr_le_cmp(&ccc->cfg[i].peer, peer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
value = sys_cpu_to_le16(ccc->cfg[i].value);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Default to disable if there is no cfg for the peer */
|
||||
if (i == ccc->cfg_len) {
|
||||
value = 0x0000;
|
||||
}
|
||||
|
||||
return bt_gatt_attr_read(peer, attr, buf, len, offset, &value,
|
||||
sizeof(value));
|
||||
}
|
||||
|
||||
static void gatt_ccc_changed(struct _bt_gatt_ccc *ccc)
|
||||
{
|
||||
int i;
|
||||
uint16_t value = 0x0000;
|
||||
|
||||
for (i = 0; i < ccc->cfg_len; i++) {
|
||||
if (ccc->cfg[i].value > value) {
|
||||
value = ccc->cfg[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
if (value != ccc->value) {
|
||||
ccc->value = value;
|
||||
ccc->cfg_changed(value);
|
||||
}
|
||||
}
|
||||
|
||||
int bt_gatt_attr_write_ccc(const bt_addr_le_t *peer,
|
||||
const struct bt_gatt_attr *attr, const void *buf,
|
||||
uint8_t len, uint16_t offset)
|
||||
{
|
||||
struct _bt_gatt_ccc *ccc = attr->user_data;
|
||||
const uint16_t *data = buf;
|
||||
size_t i;
|
||||
|
||||
if (len != sizeof(*data) || offset) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ccc->cfg_len; i++) {
|
||||
/* Check for existing configuration */
|
||||
if (!bt_addr_le_cmp(&ccc->cfg[i].peer, peer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ccc->cfg_len) {
|
||||
for (i = 0; i < ccc->cfg_len; i++) {
|
||||
/* Check for unused configuration */
|
||||
if (!bt_addr_le_cmp(&ccc->cfg[i].peer,
|
||||
BT_ADDR_LE_ANY)) {
|
||||
bt_addr_le_copy(&ccc->cfg[i].peer, peer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ccc->cfg_len) {
|
||||
BT_WARN("No space to store CCC cfg");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ccc->cfg[i].value = sys_le16_to_cpu(*data);
|
||||
|
||||
BT_DBG("handle %u value %u\n", attr->handle, ccc->cfg[i].value);
|
||||
|
||||
/* Update cfg if don't match */
|
||||
if (ccc->cfg[i].value != ccc->value) {
|
||||
gatt_ccc_changed(ccc);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue