struct bt_gatt_client *client;
struct queue *pending_svcs;
struct queue *pending_chrcs;
- struct queue *svcs;
struct gatt_db_attribute *cur_svc;
bool success;
uint16_t start;
uint16_t end;
uint16_t last;
+ uint16_t svc_first;
+ uint16_t svc_last;
int ref_count;
discovery_op_complete_func_t complete_func;
discovery_op_fail_func_t failure_func;
{
queue_destroy(op->pending_svcs, NULL);
queue_destroy(op->pending_chrcs, free);
- queue_destroy(op->svcs, NULL);
free(op);
}
op = new0(struct discovery_op, 1);
op->pending_svcs = queue_new();
op->pending_chrcs = queue_new();
- op->svcs = queue_new();
op->client = client;
op->complete_func = complete_func;
op->failure_func = failure_func;
struct discovery_op *op = user_data;
struct bt_gatt_client *client = op->client;
struct bt_gatt_iter iter;
- struct gatt_db_attribute *attr, *tmp;
+ struct gatt_db_attribute *attr;
uint16_t handle, start, end;
uint128_t u128;
bt_uuid_t uuid;
goto failed;
}
- /* Get the currently processed service */
- attr = op->cur_svc;
- if (!attr)
- goto failed;
-
if (!result || !bt_gatt_iter_init(&iter, result))
goto failed;
"handle: 0x%04x, start: 0x%04x, end: 0x%04x,"
"uuid: %s", handle, start, end, uuid_str);
- tmp = gatt_db_get_attribute(client->db, start);
- if (!tmp)
+ attr = gatt_db_get_attribute(client->db, start);
+ if (!attr)
goto failed;
- tmp = gatt_db_service_add_included(attr, tmp);
- if (!tmp)
+ attr = gatt_db_insert_included(client->db, handle, attr);
+ if (!attr)
goto failed;
/*
* these entries, the correct handle must be assigned to the new
* attribute.
*/
- if (gatt_db_attribute_get_handle(tmp) != handle)
+ if (gatt_db_attribute_get_handle(attr) != handle)
goto failed;
}
next:
- /* Move on to the next service */
- attr = queue_pop_head(op->pending_svcs);
- if (!attr) {
- /*
- * We have processed all include definitions. Move on to
- * characteristics.
- */
- attr = queue_pop_head(op->svcs);
- if (!attr)
- goto failed;
-
- if (!gatt_db_attribute_get_service_handles(attr, &start, &end))
- goto failed;
-
- op->cur_svc = attr;
-
- client->discovery_req = bt_gatt_discover_characteristics(
- client->att,
- start, end,
+ client->discovery_req = bt_gatt_discover_characteristics(client->att,
+ op->svc_first,
+ op->svc_last,
discover_chrcs_cb,
discovery_op_ref(op),
discovery_op_unref);
- if (client->discovery_req)
- return;
-
- util_debug(client->debug_callback, client->debug_data,
- "Failed to start characteristic discovery");
- discovery_op_unref(op);
- goto failed;
- }
-
- queue_push_tail(op->svcs, attr);
- op->cur_svc = attr;
- if (!gatt_db_attribute_get_service_handles(attr, &start, &end))
- goto failed;
-
- if (start == end)
- goto next;
-
- client->discovery_req = bt_gatt_discover_included_services(client->att,
- start, end,
- discover_incl_cb,
- discovery_op_ref(op),
- discovery_op_unref);
if (client->discovery_req)
return;
util_debug(client->debug_callback, client->debug_data,
- "Failed to start included discovery");
+ "Failed to start characteristic discovery");
discovery_op_unref(op);
-
failed:
discovery_op_complete(op, false, att_ecode);
}
*discovering = false;
while ((chrc_data = queue_pop_head(op->pending_chrcs))) {
- attr = gatt_db_service_insert_characteristic(op->cur_svc,
+ struct gatt_db_attribute *svc;
+ uint16_t start, end;
+
+ attr = gatt_db_insert_characteristic(client->db,
chrc_data->value_handle,
&chrc_data->uuid, 0,
chrc_data->properties,
chrc_data->value_handle)
goto failed;
+ /* Adjust current service */
+ svc = gatt_db_get_service(client->db, chrc_data->value_handle);
+ if (op->cur_svc != svc) {
+ queue_remove(op->pending_svcs, svc);
+
+ /* Done with the current service */
+ gatt_db_service_set_active(op->cur_svc, true);
+ op->cur_svc = svc;
+ }
+
+ gatt_db_attribute_get_service_handles(svc, &start, &end);
+
+ /*
+ * Ajust end_handle in case the next chrc is not within the
+ * same service.
+ */
+ if (chrc_data->end_handle > end)
+ chrc_data->end_handle = end;
+
/*
* check for descriptors presence, before initializing the
* desc_handle and avoid integer overflow during desc_handle
free(chrc_data);
continue;
}
+
desc_start = chrc_data->value_handle + 1;
client->discovery_req = bt_gatt_discover_descriptors(
struct bt_gatt_client *client = op->client;
struct bt_gatt_iter iter;
struct gatt_db_attribute *attr;
- uint16_t handle, start, end;
+ uint16_t handle;
uint128_t u128;
bt_uuid_t uuid;
char uuid_str[MAX_LEN_UUID_STR];
"handle: 0x%04x, uuid: %s",
handle, uuid_str);
- attr = gatt_db_service_insert_descriptor(op->cur_svc, handle,
+ attr = gatt_db_insert_descriptor(client->db, handle,
&uuid, 0, NULL, NULL,
NULL);
- if (!attr)
+ if (!attr) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to insert descriptor at 0x%04x",
+ handle);
goto failed;
+ }
if (gatt_db_attribute_get_handle(attr) != handle)
goto failed;
/* Done with the current service */
gatt_db_service_set_active(op->cur_svc, true);
- attr = queue_pop_head(op->svcs);
- if (!attr)
- goto done;
-
- if (!gatt_db_attribute_get_service_handles(attr, &start, &end))
- goto failed;
-
- if (start == end)
- goto next;
-
- /* Move on to the next service */
- op->cur_svc = attr;
-
- client->discovery_req = bt_gatt_discover_characteristics(client->att,
- start, end,
- discover_chrcs_cb,
- discovery_op_ref(op),
- discovery_op_unref);
- if (client->discovery_req)
- return;
-
- util_debug(client->debug_callback, client->debug_data,
- "Failed to start characteristic discovery");
- discovery_op_unref(op);
+ goto done;
failed:
success = false;
struct discovery_op *op = user_data;
struct bt_gatt_client *client = op->client;
struct bt_gatt_iter iter;
- struct gatt_db_attribute *attr;
struct chrc *chrc_data;
uint16_t start, end, value;
uint8_t properties;
goto done;
}
- if (!op->cur_svc || !result || !bt_gatt_iter_init(&iter, result))
+ if (!result || !bt_gatt_iter_init(&iter, result))
goto failed;
chrc_count = bt_gatt_result_characteristic_count(result);
/* Done with the current service */
gatt_db_service_set_active(op->cur_svc, true);
- attr = queue_pop_head(op->svcs);
- if (!attr)
- goto done;
-
- if (!gatt_db_attribute_get_service_handles(attr, &start, &end))
- goto failed;
-
- if (start == end)
- goto next;
-
- /* Move on to the next service */
- op->cur_svc = attr;
-
- client->discovery_req = bt_gatt_discover_characteristics(client->att,
- start, end,
- discover_chrcs_cb,
- discovery_op_ref(op),
- discovery_op_unref);
- if (client->discovery_req)
- return;
-
- util_debug(client->debug_callback, client->debug_data,
- "Failed to start characteristic discovery");
- discovery_op_unref(op);
+ goto done;
failed:
success = false;
discovery_op_complete(op, success, att_ecode);
}
+static void discovery_found_service(struct discovery_op *op,
+ struct gatt_db_attribute *attr,
+ uint16_t start, uint16_t end)
+{
+ /* Skip if service already active */
+ if (!gatt_db_service_get_active(attr)) {
+ queue_push_tail(op->pending_svcs, attr);
+
+ /* Update discovery range */
+ if (!op->svc_first || op->svc_first > start)
+ op->svc_first = start;
+ if (op->svc_last < end)
+ op->svc_last = end;
+ }
+
+ /* Update last handle */
+ if (end > op->last)
+ op->last = end;
+}
+
static void discover_secondary_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
}
}
- /* Skip if service already active */
- if (!gatt_db_service_get_active(attr))
- queue_push_tail(op->pending_svcs, attr);
-
- /* Update last handle */
- if (end > op->last)
- op->last = end;
+ /* Update pending list */
+ discovery_found_service(op, attr, start, end);
}
next:
- /* Sequentially discover included services */
- attr = queue_pop_head(op->pending_svcs);
-
- /* Complete with success if queue is empty */
- if (!attr) {
- success = true;
- goto done;
- }
-
- /*
- * Store the service in the svcs queue to be reused during
- * characteristics discovery later.
- */
- queue_push_tail(op->svcs, attr);
- op->cur_svc = attr;
-
- if (!gatt_db_attribute_get_service_handles(attr, &start, &end)) {
- success = false;
- goto done;
- }
-
client->discovery_req = bt_gatt_discover_included_services(client->att,
- start, end,
+ op->svc_first,
+ op->svc_last,
discover_incl_cb,
discovery_op_ref(op),
discovery_op_unref);
}
}
- /* Skip if service already active */
- if (!gatt_db_service_get_active(attr))
- queue_push_tail(op->pending_svcs, attr);
-
- /* Update last handle */
- if (end > op->last)
- op->last = end;
+ /* Update pending list */
+ discovery_found_service(op, attr, start, end);
}
secondary:
}
struct gatt_db_attribute *
+gatt_db_insert_characteristic(struct gatt_db *db,
+ uint16_t handle,
+ const bt_uuid_t *uuid,
+ uint32_t permissions,
+ uint8_t properties,
+ gatt_db_read_t read_func,
+ gatt_db_write_t write_func,
+ void *user_data)
+{
+ struct gatt_db_attribute *attrib;
+
+ attrib = gatt_db_get_service(db, handle);
+ if (!attrib)
+ return NULL;
+
+ return service_insert_characteristic(attrib->service, handle, uuid,
+ permissions, properties,
+ read_func, write_func,
+ user_data);
+}
+
+struct gatt_db_attribute *
gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
uint16_t handle,
const bt_uuid_t *uuid,
}
struct gatt_db_attribute *
+gatt_db_insert_descriptor(struct gatt_db *db,
+ uint16_t handle,
+ const bt_uuid_t *uuid,
+ uint32_t permissions,
+ gatt_db_read_t read_func,
+ gatt_db_write_t write_func,
+ void *user_data)
+{
+ struct gatt_db_attribute *attrib;
+
+ attrib = gatt_db_get_service(db, handle);
+ if (!attrib)
+ return NULL;
+
+ return service_insert_descriptor(attrib->service, handle, uuid,
+ permissions, read_func, write_func,
+ user_data);
+}
+
+struct gatt_db_attribute *
gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
uint16_t handle,
const bt_uuid_t *uuid,
user_data);
}
-struct gatt_db_attribute *
-gatt_db_service_add_included(struct gatt_db_attribute *attrib,
+static struct gatt_db_attribute *
+service_insert_included(struct gatt_db_service *service, uint16_t handle,
struct gatt_db_attribute *include)
{
- struct gatt_db_service *service, *included;
+ struct gatt_db_service *included;
uint8_t value[MAX_INCLUDED_VALUE_LEN];
uint16_t included_handle, len = 0;
int index;
- if (!attrib || !include)
- return NULL;
-
- service = attrib->service;
included = include->service;
/* Adjust include to point to the first attribute */
if (!index)
return NULL;
- service->attributes[index] = new_attribute(service, 0,
+ /* Check if handle is in within service range */
+ if (handle && handle <= service->attributes[0]->handle)
+ return NULL;
+
+ if (!handle)
+ handle = get_handle_at_index(service, index - 1) + 1;
+
+ service->attributes[index] = new_attribute(service, handle,
&included_service_uuid,
value, len);
if (!service->attributes[index])
return attribute_update(service, index);
}
+struct gatt_db_attribute *
+gatt_db_service_add_included(struct gatt_db_attribute *attrib,
+ struct gatt_db_attribute *include)
+{
+ if (!attrib || !include)
+ return NULL;
+
+ return service_insert_included(attrib->service, 0, include);
+}
+
+struct gatt_db_attribute *
+gatt_db_service_insert_included(struct gatt_db_attribute *attrib,
+ uint16_t handle,
+ struct gatt_db_attribute *include)
+{
+ if (!attrib || !handle || !include)
+ return NULL;
+
+ return service_insert_included(attrib->service, handle, include);
+}
+
+struct gatt_db_attribute *
+gatt_db_insert_included(struct gatt_db *db, uint16_t handle,
+ struct gatt_db_attribute *include)
+{
+ struct gatt_db_attribute *attrib;
+
+ attrib = gatt_db_get_service(db, handle);
+ if (!attrib)
+ return NULL;
+
+ return service_insert_included(attrib->service, handle, include);
+}
+
bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active)
{
struct gatt_db_service *service;
return (start <= handle) && (handle <= end);
}
-struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
+struct gatt_db_attribute *gatt_db_get_service(struct gatt_db *db,
uint16_t handle)
{
struct gatt_db_service *service;
- int i;
if (!db || !handle)
return NULL;
service = queue_find(db->services, find_service_for_handle,
- UINT_TO_PTR(handle));
+ UINT_TO_PTR(handle));
if (!service)
return NULL;
+ return service->attributes[0];
+}
+
+struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
+ uint16_t handle)
+{
+ struct gatt_db_attribute *attrib;
+ struct gatt_db_service *service;
+ int i;
+
+ attrib = gatt_db_get_service(db, handle);
+ if (!attrib)
+ return NULL;
+
+ service = attrib->service;
+
for (i = 0; i < service->num_handles; i++) {
if (!service->attributes[i])
continue;