From 68115186219bbcc8e50fe8ebab343f5d545c36a1 Mon Sep 17 00:00:00 2001 From: Jakub Tyszkowski Date: Tue, 1 Apr 2014 17:19:25 +0200 Subject: [PATCH] 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 | 151 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 144 insertions(+), 7 deletions(-) diff --git a/android/gatt.c b/android/gatt.c index 51e7c07c5..07fe1613d 100644 --- a/android/gatt.c +++ b/android/gatt.c @@ -286,6 +286,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; @@ -1443,6 +1453,127 @@ 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 *cache) +{ + struct att_data_list *list; + guint8 format; + int i; + + list = dec_find_info_resp(pdu, len, &format); + if (!list) + 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("handle 0x%04x uuid %s", handle, uuidstr); + + descr = new0(struct descriptor, 1); + if (!descr) + continue; + + descr->id.instance = i; + descr->handle = handle; + descr->id.uuid = uuid128; + + if (!queue_push_tail(cache, descr)) + free(descr); + } + + att_data_list_free(list); +} + +struct discover_desc_data { + int32_t conn_id; + const struct element_id *srvc_id; + const struct characteristic *ch; + uint8_t primary; +}; + +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 (status) + error("gatt: Discover all char descriptors failed: %s", + att_ecode2str(status)); + else + cache_all_descr(pdu, len, data->ch->descriptors); + + descr = queue_peek_head(data->ch->descriptors); + + send_client_descr_notify(status, data->conn_id, data->primary, + data->srvc_id, &data->ch->id, + descr ? &descr->id : NULL); + + 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->ch = ch; + cb_data->primary = primary; + + 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; @@ -1489,17 +1620,23 @@ static void handle_client_get_descriptor(const void *buf, uint16_t len) } 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, -- 2.47.3