2014-04-01 15:19:22

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 0/5] Client descriptor operations

v2 changes:
* Rebased on top of latest changes and cleanups.
* Function flow was redesigned to minimize label jumps.

Jakub Tyszkowski (5):
android/gatt: Add queue for characteristic descriptors caching
android/gatt: Handle get descriptor client command
android/gatt: Add descriptors sending and caching for client
android/gatt: Add client read descriptor handler
android/gatt: Add client write descriptor handler

android/gatt.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 525 insertions(+), 4 deletions(-)

--
1.9.0



2014-04-03 14:27:43

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCHv2 0/5] Client descriptor operations

Hi Jakub,

On Tuesday 01 of April 2014 17:19:22 Jakub Tyszkowski wrote:
> v2 changes:
> * Rebased on top of latest changes and cleanups.
> * Function flow was redesigned to minimize label jumps.
>
> Jakub Tyszkowski (5):
> android/gatt: Add queue for characteristic descriptors caching
> android/gatt: Handle get descriptor client command
> android/gatt: Add descriptors sending and caching for client
> android/gatt: Add client read descriptor handler
> android/gatt: Add client write descriptor handler
>

I've pushed all patches (with quite a few fixes and cleanups though), thanks.

--
Best regards,
Szymon Janc

2014-04-01 15:19:26

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 4/5] android/gatt: Add client read descriptor handler

This patch adds descriptor reading. In case of providing wrong
descriptor, error status is being sent with notification.
---
android/gatt.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 141 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 2039920..6c3ecf0 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -49,6 +49,9 @@
#include "attrib/gatt.h"
#include "btio/btio.h"

+/* set according to android's bt_gatt_client.h */
+#define GATT_MAX_ATTR_LEN 600
+
#define GATT_SUCCESS 0x00000000
#define GATT_FAILURE 0x00000101

@@ -287,6 +290,17 @@ static bool match_char_by_higher_inst_id(const void *data,
return inst_id < ch->id.instance;
}

+static bool match_descr_by_element_id(const void *data, const void *user_data)
+{
+ const struct element_id *exp_id = user_data;
+ const struct descriptor *descr = data;
+
+ if (exp_id->instance == descr->id.instance)
+ return !bt_uuid_cmp(&descr->id.uuid, &exp_id->uuid);
+
+ return false;
+}
+
static bool match_descr_by_higher_inst_id(const void *data,
const void *user_data)
{
@@ -1885,12 +1899,138 @@ failed:
cmd->srvc_id.is_primary);
}

+static void send_client_descr_read_notify(int32_t status, const uint8_t *pdu,
+ guint16 len, int32_t conn_id,
+ const struct element_id *srvc,
+ const struct element_id *ch,
+ const struct element_id *descr,
+ uint8_t primary)
+{
+ uint8_t buf[IPC_MTU];
+ struct hal_ev_gatt_client_read_descriptor *ev = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ ev->status = status;
+ ev->conn_id = conn_id;
+
+ element_id_to_hal_srvc_id(srvc, primary, &ev->data.srvc_id);
+ element_id_to_hal_gatt_id(ch, &ev->data.char_id);
+ element_id_to_hal_gatt_id(descr, &ev->data.descr_id);
+
+ if (len && pdu)
+ ev->data.len = dec_read_resp(pdu, len, ev->data.value,
+ GATT_MAX_ATTR_LEN);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_READ_DESCRIPTOR,
+ sizeof(*ev) + ev->data.len, ev);
+}
+
+struct read_desc_data {
+ int32_t conn_id;
+ const struct element_id *srvc_id;
+ const struct element_id *char_id;
+ const struct element_id *descr_id;
+ uint8_t primary;
+};
+
+static void read_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct read_desc_data *cb_data = user_data;
+
+ if (status != 0)
+ error("gatt: Discover all char descriptors failed: %s\n",
+ att_ecode2str(status));
+
+ send_client_descr_read_notify(status, pdu, len, cb_data->conn_id,
+ cb_data->srvc_id, cb_data->char_id,
+ cb_data->descr_id, cb_data->primary);
+
+ free(cb_data);
+}
+
static void handle_client_read_descriptor(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_client_read_descriptor *cmd = buf;
+ struct read_desc_data *cb_data;
+ struct characteristic *ch;
+ struct descriptor *descr;
+ struct service *srvc;
+ struct element_id char_id;
+ struct element_id descr_id;
+ struct element_id srvc_id;
+ struct gatt_device *dev;
+ int32_t conn_id = 0;
+ uint8_t primary;
+ uint8_t status;
+
DBG("");

+ conn_id = cmd->conn_id;
+ primary = cmd->srvc_id.is_primary;
+
+ hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
+ hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
+ hal_gatt_id_to_element_id(&cmd->descr_id, &descr_id);
+
+ if (!find_service(conn_id, &srvc_id, &dev, &srvc)) {
+ error("gatt: Read descr. could not find service");
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ ch = queue_find(srvc->chars, match_char_by_element_id, &char_id);
+ if (!ch) {
+ error("gatt: Read descr. could not find characteristic");
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ descr = queue_find(ch->descriptors, match_descr_by_element_id,
+ &descr_id);
+ if (!descr) {
+ error("gatt: Read descr. could not find descriptor");
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ cb_data = new0(struct read_desc_data, 1);
+ if (!cb_data) {
+ error("gatt: Read descr. could not allocate callback data");
+
+ status = HAL_STATUS_NOMEM;
+ goto failed;
+ }
+
+ cb_data->conn_id = conn_id;
+ cb_data->srvc_id = &srvc->id;
+ cb_data->char_id = &ch->id;
+ cb_data->descr_id = &descr->id;
+ cb_data->primary = primary;
+
+ if (!gatt_read_char(dev->attrib, descr->handle, read_desc_cb,
+ cb_data)) {
+ free(cb_data);
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ if (status != HAL_STATUS_SUCCESS)
+ send_client_descr_read_notify(GATT_FAILURE, NULL, 0, conn_id,
+ &srvc_id, &char_id, &descr_id,
+ primary);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_CLIENT_READ_DESCRIPTOR, HAL_STATUS_FAILED);
+ HAL_OP_GATT_CLIENT_READ_DESCRIPTOR, status);
}

static void handle_client_write_descriptor(const void *buf, uint16_t len)
--
1.9.0


2014-04-01 15:19:24

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 2/5] android/gatt: Handle get descriptor client command

This adds basic get characteristic descriptor command handling. In case
of no descriptor, proper notification with bad status is being sent.
---
android/gatt.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 85 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 0e63df5..b496d8a 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -31,6 +31,7 @@
#include <glib.h>
#include <errno.h>
#include <sys/socket.h>
+#include <assert.h>

#include "ipc.h"
#include "ipc-common.h"
@@ -1419,12 +1420,95 @@ done:
HAL_OP_GATT_CLIENT_GET_CHARACTERISTIC, status);
}

+static void send_client_descr_notify(int32_t status, int32_t conn_id,
+ bool primary,
+ const struct element_id *srvc,
+ const struct element_id *ch,
+ const struct element_id *opt_descr)
+{
+ struct hal_ev_gatt_client_get_descriptor ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.status = status;
+ ev.conn_id = conn_id;
+
+ element_id_to_hal_srvc_id(srvc, primary, &ev.srvc_id);
+ element_id_to_hal_gatt_id(ch, &ev.char_id);
+
+ if (opt_descr)
+ element_id_to_hal_gatt_id(opt_descr, &ev.descr_id);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_GET_DESCRIPTOR, sizeof(ev), &ev);
+}
+
static void handle_client_get_descriptor(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_client_get_descriptor *cmd = buf;
+ struct descriptor *descr = NULL;
+ struct characteristic *ch;
+ struct service *srvc;
+ struct element_id srvc_id;
+ struct element_id char_id;
+ struct gatt_device *dev;
+ int32_t conn_id;
+ uint8_t primary;
+ uint8_t status;
+
DBG("");

+ if (len != sizeof(*cmd) + cmd->number * sizeof(cmd->gatt_id[0])) {
+ error("gatt: Get descr. bad cmd size (%u b), terminating", len);
+
+ raise(SIGTERM);
+ return;
+ }
+
+ assert(cmd->number);
+
+ conn_id = cmd->conn_id;
+ primary = cmd->srvc_id.is_primary;
+
+ hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
+ hal_gatt_id_to_element_id(&cmd->gatt_id[0], &char_id);
+
+ if (!find_service(conn_id, &srvc_id, &dev, &srvc)) {
+ error("gatt: Get descr. could not find service.");
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ ch = queue_find(srvc->chars, match_char_by_element_id, &char_id);
+ if (!ch) {
+ error("gatt: Get descr. could not find characteristic.");
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+
+ if (queue_isempty(ch->descriptors)) {
+ /* TODO: Build the cache */
+
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_OP_GATT_CLIENT_GET_DESCRIPTOR,
+ HAL_STATUS_FAILED);
+ return;
+ }
+
+ status = HAL_STATUS_FAILED;
+
+ /* TODO: Send from cache */
+
+failed:
+ send_client_descr_notify(descr ? GATT_SUCCESS : GATT_FAILURE, conn_id,
+ primary, &srvc_id, &char_id,
+ &descr->id);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_CLIENT_GET_DESCRIPTOR, HAL_STATUS_FAILED);
+ HAL_OP_GATT_CLIENT_GET_DESCRIPTOR, status);
}

struct read_char_data {
--
1.9.0


2014-04-01 15:19:27

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 5/5] android/gatt: Add client write descriptor handler

This adds writing descriptors. In case of providing invalid descriptor
error status is send with notification.
---
android/gatt.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 130 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 6c3ecf0..cee65ef 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2033,12 +2033,141 @@ failed:
HAL_OP_GATT_CLIENT_READ_DESCRIPTOR, status);
}

+struct write_descr_data {
+ int32_t conn_id;
+ const struct element_id *srvc_id;
+ const struct element_id *char_id;
+ const struct element_id *descr_id;
+ uint8_t primary;
+};
+
+static void send_client_descr_write_notify(int32_t status, int32_t conn_id,
+ const struct element_id *srvc,
+ const struct element_id *ch,
+ const struct element_id *descr,
+ uint8_t primary) {
+ uint8_t buf[IPC_MTU];
+ struct hal_ev_gatt_client_write_descriptor *ev = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ ev->status = status;
+ ev->conn_id = conn_id;
+
+ element_id_to_hal_srvc_id(srvc, primary, &ev->data.srvc_id);
+ element_id_to_hal_gatt_id(ch, &ev->data.char_id);
+ element_id_to_hal_gatt_id(descr, &ev->data.descr_id);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_WRITE_DESCRIPTOR,
+ sizeof(*ev), ev);
+}
+
+
+static void write_descr_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct read_desc_data *cb_data = user_data;
+
+ if (status != 0)
+ error("gatt: Write descriptors failed: %s\n",
+ att_ecode2str(status));
+
+ send_client_descr_write_notify(status, cb_data->conn_id,
+ cb_data->srvc_id, cb_data->char_id,
+ cb_data->descr_id, cb_data->primary);
+
+ free(cb_data);
+
+}
+
static void handle_client_write_descriptor(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_client_write_descriptor *cmd = buf;
+ struct write_descr_data *cb_data;
+ struct characteristic *ch;
+ struct descriptor *descr;
+ struct service *srvc;
+ struct element_id srvc_id;
+ struct element_id char_id;
+ struct element_id descr_id;
+ struct gatt_device *dev;
+ int32_t conn_id = 0;
+ uint8_t primary;
+ uint8_t status;
+
DBG("");

+ primary = cmd->srvc_id.is_primary;
+ conn_id = cmd->conn_id;
+
+ if (len != sizeof(*cmd) + cmd->len * sizeof(cmd->value[0])) {
+ error("gatt: Write descr. msg size invalid (%d bytes)", len);
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
+ hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
+ hal_gatt_id_to_element_id(&cmd->descr_id, &descr_id);
+
+ if (!find_service(cmd->conn_id, &srvc_id, &dev, &srvc)) {
+ error("gatt: Read descr. could not find service");
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ ch = queue_find(srvc->chars, match_char_by_element_id, &char_id);
+ if (!ch) {
+ error("gatt: Read descr. could not find characteristic");
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ descr = queue_find(ch->descriptors, match_descr_by_element_id,
+ &descr_id);
+ if (!descr) {
+ error("gatt: Read descr. could not find descriptor");
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ cb_data = new0(struct write_descr_data, 1);
+ if (!cb_data) {
+ error("gatt: Read descr. could not allocate callback data");
+
+ status = HAL_STATUS_NOMEM;
+ goto failed;
+ }
+
+ cb_data->conn_id = conn_id;
+ cb_data->srvc_id = &srvc->id;
+ cb_data->char_id = &ch->id;
+ cb_data->descr_id = &descr->id;
+ cb_data->primary = primary;
+
+ if (!gatt_write_char(dev->attrib, descr->handle, cmd->value,
+ cmd->len * sizeof(cmd->value[0]),
+ write_descr_cb, cb_data)) {
+ free(cb_data);
+
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ if (status != HAL_STATUS_SUCCESS)
+ send_client_descr_write_notify(GATT_FAILURE, conn_id, &srvc_id,
+ &char_id, &descr_id, primary);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_CLIENT_WRITE_DESCRIPTOR, HAL_STATUS_FAILED);
+ HAL_OP_GATT_CLIENT_WRITE_DESCRIPTOR, status);
}

static void handle_client_execute_write(const void *buf, uint16_t len)
--
1.9.0


2014-04-01 15:19:25

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 3/5] android/gatt: Add descriptors sending and caching for client

This adds descriptors caching at first get descriptor call. After that
descriptors are send from the cache.
---
android/gatt.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 152 insertions(+), 8 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index b496d8a..2039920 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -287,6 +287,16 @@ static bool match_char_by_higher_inst_id(const void *data,
return inst_id < ch->id.instance;
}

+static bool match_descr_by_higher_inst_id(const void *data,
+ const void *user_data)
+{
+ const struct descriptor *descr = data;
+ uint8_t instance = PTR_TO_INT(user_data);
+
+ /* For now we match instance as it is unique */
+ return instance < descr->id.instance;
+}
+
static bool match_char_by_instance(const void *data, const void *user_data)
{
const struct characteristic *ch = data;
@@ -1420,6 +1430,15 @@ done:
HAL_OP_GATT_CLIENT_GET_CHARACTERISTIC, status);
}

+struct discover_desc_data {
+ int32_t conn_id;
+ const struct element_id *srvc_id;
+ const struct element_id *char_id;
+ uint8_t primary;
+
+ struct queue *descriptors;
+};
+
static void send_client_descr_notify(int32_t status, int32_t conn_id,
bool primary,
const struct element_id *srvc,
@@ -1443,6 +1462,126 @@ static void send_client_descr_notify(int32_t status, int32_t conn_id,
HAL_EV_GATT_CLIENT_GET_DESCRIPTOR, sizeof(ev), &ev);
}

+
+static void cache_all_descr(const uint8_t *pdu, guint16 len,
+ struct queue *queue)
+{
+ struct att_data_list *list;
+ guint8 format;
+ int i;
+
+ list = dec_find_info_resp(pdu, len, &format);
+ if (!list || !queue)
+ return;
+
+ for (i = 0; i < list->num; i++) {
+ char uuidstr[MAX_LEN_UUID_STR];
+ struct descriptor *descr;
+ bt_uuid_t uuid128;
+ uint16_t handle;
+ uint8_t *value;
+ bt_uuid_t uuid;
+
+ value = list->data[i];
+ handle = get_le16(value);
+
+ if (format == ATT_FIND_INFO_RESP_FMT_16BIT) {
+ bt_uuid16_create(&uuid, get_le16(&value[2]));
+ bt_uuid_to_uuid128(&uuid, &uuid128);
+ } else {
+ uint128_t u128;
+
+ bswap_128(&value[2], &u128);
+ bt_uuid128_create(&uuid128, u128);
+ }
+
+ bt_uuid_to_string(&uuid128, uuidstr, MAX_LEN_UUID_STR);
+ DBG("gatt: Cached descriptor handle = 0x%04x, uuid = %s\n",
+ handle, uuidstr);
+
+ descr = new0(struct descriptor, 1);
+ if (!descr)
+ break;
+
+ descr->id.instance = i;
+ descr->handle = handle;
+ descr->id.uuid = uuid128;
+
+ if (!queue_push_tail(queue, descr))
+ free(descr);
+ }
+
+ att_data_list_free(list);
+}
+
+static void gatt_discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct discover_desc_data *data = user_data;
+ struct descriptor *descr;
+
+ if (!data) {
+ error("No user data");
+ return;
+ }
+
+ if (status != 0)
+ error("gatt: Discover all char descriptors failed: %s\n",
+ att_ecode2str(status));
+ else
+ cache_all_descr(pdu, len, data->descriptors);
+
+ descr = queue_peek_head(data->descriptors);
+ send_client_descr_notify(status, data->conn_id, data->primary,
+ data->srvc_id, data->char_id,
+ &descr->id);
+
+ free(data);
+}
+
+static bool build_descr_cache(int32_t conn_id, struct gatt_device *dev,
+ struct service *srvc, uint8_t primary,
+ struct characteristic *ch)
+{
+ struct discover_desc_data *cb_data;
+ struct characteristic *next_ch;
+ uint16_t start, end;
+
+ /* Clip range to given characteristic */
+ start = ch->ch.value_handle + 1;
+ end = srvc->primary.range.end;
+
+ /* Use next characteristic start as end. If there is none -
+ * service end is valid end.
+ * TODO: we should cache char end handle to avoid this search */
+ next_ch = queue_find(srvc->chars, match_char_by_higher_inst_id,
+ INT_TO_PTR(ch->id.instance));
+ if (next_ch)
+ end = next_ch->ch.handle - 1;
+
+ /* If there are no descriptors, notify with fail status. */
+ if (start > end)
+ return false;
+
+ cb_data = new0(struct discover_desc_data, 1);
+ if (!cb_data)
+ return false;
+
+ cb_data->conn_id = conn_id;
+ cb_data->srvc_id = &srvc->id;
+ cb_data->char_id = &ch->id;
+ cb_data->primary = primary;
+ cb_data->descriptors = ch->descriptors;
+
+ if (!gatt_discover_char_desc(dev->attrib, start, end,
+ gatt_discover_desc_cb, cb_data)) {
+ free(cb_data);
+ return false;
+ }
+
+ return true;
+}
+
static void handle_client_get_descriptor(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_get_descriptor *cmd = buf;
@@ -1488,19 +1627,24 @@ static void handle_client_get_descriptor(const void *buf, uint16_t len)
goto failed;
}

-
if (queue_isempty(ch->descriptors)) {
- /* TODO: Build the cache */
-
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
+ if (build_descr_cache(conn_id, dev, srvc, primary, ch)) {
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
HAL_OP_GATT_CLIENT_GET_DESCRIPTOR,
- HAL_STATUS_FAILED);
- return;
+ HAL_STATUS_SUCCESS);
+ return;
+ }
}

- status = HAL_STATUS_FAILED;
+ status = HAL_STATUS_SUCCESS;

- /* TODO: Send from cache */
+ /* Send from cache */
+ if (cmd->number > 1)
+ descr = queue_find(ch->descriptors,
+ match_descr_by_higher_inst_id,
+ INT_TO_PTR(cmd->gatt_id[1].inst_id));
+ else
+ descr = queue_peek_head(ch->descriptors);

failed:
send_client_descr_notify(descr ? GATT_SUCCESS : GATT_FAILURE, conn_id,
--
1.9.0


2014-04-01 15:19:23

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 1/5] android/gatt: Add queue for characteristic descriptors caching

This is where descriptors will be cached.
---
android/gatt.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 8bd7028..0e63df5 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -67,9 +67,16 @@ struct element_id {
uint8_t instance;
};

+struct descriptor {
+ struct element_id id;
+ uint16_t handle;
+};
+
struct characteristic {
struct element_id id;
struct gatt_char ch;
+
+ struct queue *descriptors;
};

struct service {
@@ -171,6 +178,17 @@ static void element_id_to_hal_gatt_id(const struct element_id *from,
uuid2android(&from->uuid, to->uuid);
}

+static void destroy_characteristic(void *data)
+{
+ struct characteristic *chars = data;
+
+ if (!chars)
+ return;
+
+ queue_destroy(chars->descriptors, free);
+ free(chars);
+}
+
static void destroy_service(void *data)
{
struct service *srvc = data;
@@ -178,7 +196,7 @@ static void destroy_service(void *data)
if (!srvc)
return;

- queue_destroy(srvc->chars, free);
+ queue_destroy(srvc->chars, destroy_characteristic);
free(srvc);
}

@@ -1268,6 +1286,12 @@ static void cache_all_srvc_chars(GSList *characteristics, struct queue *q)
continue;
}

+ ch->descriptors = queue_new();
+ if (!ch->descriptors) {
+ free(ch);
+ continue;
+ }
+
memcpy(&ch->ch, characteristics->data, sizeof(ch->ch));

bt_string_to_uuid(&uuid, ch->ch.uuid);
--
1.9.0