diff --git a/android/gatt.c b/android/gatt.c
index 3a35bd6..b749705 100644
--- a/android/gatt.c
+++ b/android/gatt.c
return ret;
}
+struct find_by_type_request_data {
+ struct gatt_device *device;
+ uint8_t *search_value;
+ size_t search_vlen;
+ uint8_t error;
+};
+
+static void find_by_type_request_cb(struct gatt_db_attribute *attrib,
+ void *user_data)
+{
+ struct find_by_type_request_data *find_data = user_data;
+ struct pending_request *request_data;
+
+ if (find_data->error)
+ return;
+
+ request_data = new0(struct pending_request, 1);
+ if (!request_data) {
+ find_data->error = ATT_ECODE_INSUFF_RESOURCES;
+ return;
+ }
+
+ request_data->filter_value = malloc0(find_data->search_vlen);
+ if (!request_data->filter_value) {
+ destroy_pending_request(request_data);
+ find_data->error = ATT_ECODE_INSUFF_RESOURCES;
+ return;
+ }
+
+ request_data->state = REQUEST_INIT;
+ request_data->attrib = attrib;
+ request_data->filter_vlen = find_data->search_vlen;
+ memcpy(request_data->filter_value, find_data->search_value,
+ find_data->search_vlen);
+
+ queue_push_tail(find_data->device->pending_requests, request_data);
+}
+
static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len,
struct gatt_device *device)
{
uint8_t search_value[cmd_len];
size_t search_vlen;
uint16_t start, end;
- struct queue *q;
bt_uuid_t uuid;
uint16_t len;
+ struct find_by_type_request_data data;
DBG("");
if (start > end || start == 0)
return ATT_ECODE_INVALID_HANDLE;
- q = queue_new();
- if (!q)
- return ATT_ECODE_UNLIKELY;
+ data.error = 0;
+ data.search_vlen = search_vlen;
+ data.search_value = search_value;
+ data.device = device;
- gatt_db_find_by_type(gatt_db, start, end, &uuid, q);
+ gatt_db_find_by_type(gatt_db, start, end, &uuid,
+ find_by_type_request_cb, &data);
- if (queue_isempty(q)) {
+ if (data.error == ATT_ECODE_ATTR_NOT_FOUND) {
size_t mtu;
uint8_t *rsp = g_attrib_get_buffer(device->attrib, &mtu);
len = enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
ATT_ECODE_ATTR_NOT_FOUND, rsp, mtu);
g_attrib_send(device->attrib, 0, rsp, len, NULL, NULL, NULL);
- queue_destroy(q, NULL);
return 0;
}
- while (queue_peek_head(q)) {
- struct gatt_db_attribute *attrib = queue_pop_head(q);
- struct pending_request *data;
-
- data = new0(struct pending_request, 1);
- if (!data) {
- queue_destroy(q, NULL);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
+ if (!data.error)
+ process_dev_pending_requests(device, ATT_OP_FIND_BY_TYPE_REQ);
- data->filter_value = malloc0(search_vlen);
- if (!data->filter_value) {
- destroy_pending_request(data);
- queue_destroy(q, NULL);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
-
- data->state = REQUEST_INIT;
- data->attrib = attrib;
- data->filter_vlen = search_vlen;
- memcpy(data->filter_value, search_value, search_vlen);
-
- queue_push_tail(device->pending_requests, data);
- }
-
- queue_destroy(q, NULL);
-
- process_dev_pending_requests(device, ATT_OP_FIND_BY_TYPE_REQ);
-
- return 0;
+ return data.error;
}
static void write_confirm(struct gatt_db_attribute *attrib,
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 6768892..10dfcbb 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
uint16_t length, void *user_data);
+static void get_first_attribute(struct gatt_db_attribute *attrib,
+ void *user_data)
+{
+ struct gatt_db_attribute **stored = user_data;
+
+ if (*stored)
+ return;
+
+ *stored = attrib;
+}
+
static void service_changed_complete(struct discovery_op *op, bool success,
uint8_t att_ecode)
{
struct service_changed_op *next_sc_op;
uint16_t start_handle = op->start;
uint16_t end_handle = op->end;
- struct gatt_db_attribute *attr;
+ struct gatt_db_attribute *attr = NULL;
bt_uuid_t uuid;
- struct queue *q;
client->in_svc_chngd = false;
return;
}
- /* Check if the GATT service was among the changed services */
- q = queue_new();
- if (!q)
- return;
-
bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
- gatt_db_find_by_type(client->db, start_handle, end_handle, &uuid, q);
- if (queue_isempty(q)) {
- queue_destroy(q, NULL);
+ gatt_db_find_by_type(client->db, start_handle, end_handle, &uuid,
+ get_first_attribute, &attr);
+ if (!attr)
return;
- }
-
- attr = queue_pop_head(q);
- queue_destroy(q, NULL);
/* The GATT service was modified. Re-register the handler for
* indications from the "Service Changed" characteristic.
{
struct bt_gatt_client *client = op->client;
bool registered;
- struct gatt_db_attribute *attr;
+ struct gatt_db_attribute *attr = NULL;
bt_uuid_t uuid;
- struct queue *q;
client->in_init = false;
if (!success)
goto fail;
- q = queue_new();
- if (!q)
- goto fail;
-
bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
- gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid, q);
- if (queue_isempty(q)) {
- queue_destroy(q, NULL);
+ gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid,
+ get_first_attribute, &attr);
+ if (!attr) {
client->ready = true;
goto done;
}
- attr = queue_pop_head(q);
- queue_destroy(q, NULL);
-
/* Register an indication handler for the "Service Changed"
* characteristic and report ready only if the handler is registered
* successfully. Temporarily set "ready" to true so that we can register
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 74c3e70..7177a0b 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
}
struct find_by_type_value_data {
- struct queue *queue;
bt_uuid_t uuid;
uint16_t start_handle;
uint16_t end_handle;
+ gatt_db_attribute_cb_t func;
+ void *user_data;
};
static void find_by_type(void *data, void *user_data)
if (bt_uuid_cmp(&search_data->uuid, &attribute->uuid))
continue;
- queue_push_tail(search_data->queue, attribute);
+ search_data->func(attribute, search_data->user_data);
}
}
void gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
- uint16_t end_handle,
- const bt_uuid_t *type,
- struct queue *queue)
+ uint16_t end_handle,
+ const bt_uuid_t *type,
+ gatt_db_attribute_cb_t func,
+ void *user_data)
{
struct find_by_type_value_data data;
data.uuid = *type;
data.start_handle = start_handle;
data.end_handle = end_handle;
- data.queue = queue;
+ data.func = func;
+ data.user_data = user_data;
queue_foreach(db->services, find_by_type, &data);
}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index f188944..9fc1b11 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active);
bool gatt_db_service_get_active(struct gatt_db_attribute *attrib);
+typedef void (*gatt_db_attribute_cb_t)(struct gatt_db_attribute *attrib,
+ void *user_data);
+
void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle,
const bt_uuid_t type,
struct queue *queue);
void gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
- uint16_t end_handle,
- const bt_uuid_t *type,
- struct queue *queue);
+ uint16_t end_handle,
+ const bt_uuid_t *type,
+ gatt_db_attribute_cb_t func,
+ void *user_data);
void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle,
struct queue *queue);
-typedef void (*gatt_db_attribute_cb_t)(struct gatt_db_attribute *attrib,
- void *user_data);
-
void gatt_db_foreach_service(struct gatt_db *db, const bt_uuid_t *uuid,
gatt_db_attribute_cb_t func,
void *user_data);