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;
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;
}
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,