diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 7a76234..64c598f 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
+#define UUID_BYTES (BT_GATT_UUID_SIZE * sizeof(uint8_t))
+
+struct service_list {
+ bt_gatt_service_t service;
+ struct service_list *next;
+};
+
struct bt_gatt_client {
struct bt_att *att;
int ref_count;
bt_gatt_client_destroy_func_t debug_destroy;
void *debug_data;
+ struct service_list *svc_head, *svc_tail;
bool in_init;
+ bool ready;
};
+static bool gatt_client_add_service(struct bt_gatt_client *client,
+ uint16_t start, uint16_t end,
+ uint8_t uuid[BT_GATT_UUID_SIZE])
+{
+ struct service_list *list;
+
+ list = new0(struct service_list, 1);
+ if (!list)
+ return false;
+
+ list->service.start_handle = start;
+ list->service.end_handle = end;
+ memcpy(list->service.uuid, uuid, UUID_BYTES);
+
+ if (!client->svc_head)
+ client->svc_head = client->svc_tail = list;
+ else {
+ client->svc_tail->next = list;
+ client->svc_tail = list;
+ }
+
+ return true;
+}
+
+static void service_destroy_characteristics(bt_gatt_service_t *service)
+{
+ unsigned int i;
+
+ for (i = 0; i < service->num_chrcs; i++)
+ free((bt_gatt_descriptor_t *) service->chrcs[i].descs);
+
+ free((bt_gatt_characteristic_t *) service->chrcs);
+}
+
+static void gatt_client_clear_services(struct bt_gatt_client *client)
+{
+ struct service_list *l, *tmp;
+
+ l = client->svc_head;
+
+ while (l) {
+ service_destroy_characteristics(&l->service);
+ tmp = l;
+ l = tmp->next;
+ free(tmp);
+ }
+
+ client->svc_head = client->svc_tail = NULL;
+}
+
struct async_op {
struct bt_gatt_client *client;
int ref_count;
struct bt_gatt_client *client = op->client;
struct bt_gatt_iter iter;
uint16_t start, end;
- uint8_t uuid[16];
+ uint8_t uuid[BT_GATT_UUID_SIZE];
char uuid_str[MAX_LEN_UUID_STR];
bt_uuid_t tmp;
bt_gatt_result_service_count(result));
while (bt_gatt_iter_next_service(&iter, &start, &end, uuid)) {
- /* TODO: discover characteristics and store the service. */
-
/* Log debug message. */
tmp.type = BT_UUID128;
memcpy(tmp.value.u128.data, uuid, sizeof(uuid));
util_debug(client->debug_callback, client->debug_data,
"start: 0x%04x, end: 0x%04x, uuid: %s",
start, end, uuid_str);
+
+ /* Store the service */
+ if (!gatt_client_add_service(client, start, end, uuid)) {
+ util_debug(client->debug_callback, client->debug_data,
+ "Failed to store service");
+
+ gatt_client_clear_services(client);
+
+ success = false;
+ goto done;
+ }
}
done:
client->in_init = false;
+ if (success)
+ client->ready = true;
+
if (client->ready_callback)
client->ready_callback(success, att_ecode, client->ready_data);
}
{
struct async_op *op;
- if (client->in_init)
+ if (client->in_init || client->ready)
return false;
op = new0(struct async_op, 1);
free(client);
}
+bool bt_gatt_client_is_ready(struct bt_gatt_client *client)
+{
+ return (client && client->ready);
+}
+
bool bt_gatt_client_set_ready_handler(struct bt_gatt_client *client,
bt_gatt_client_callback_t callback,
void *user_data,
return true;
}
+
+bool bt_gatt_service_iter_init(struct bt_gatt_service_iter *iter,
+ struct bt_gatt_client *client)
+{
+ if (!iter || !client)
+ return false;
+
+ if (client->in_init)
+ return false;
+
+ memset(iter, 0, sizeof(*iter));
+ iter->client = client;
+ iter->ptr = NULL;
+
+ return true;
+}
+
+bool bt_gatt_service_iter_next(struct bt_gatt_service_iter *iter,
+ bt_gatt_service_t *service)
+{
+ struct service_list *l;
+
+ if (!iter || !service)
+ return false;
+
+ l = iter->ptr;
+
+ if (!l)
+ l = iter->client->svc_head;
+ else
+ l = l->next;
+
+ if (!l)
+ return false;
+
+ *service = l->service;
+ iter->ptr = l;
+
+ return true;
+}
+
+bool bt_gatt_service_iter_next_by_handle(struct bt_gatt_service_iter *iter,
+ uint16_t start_handle,
+ bt_gatt_service_t *service)
+{
+ while (bt_gatt_service_iter_next(iter, service)) {
+ if (service->start_handle == start_handle)
+ return true;
+ }
+
+ return false;
+}
+
+bool bt_gatt_service_iter_next_by_uuid(struct bt_gatt_service_iter *iter,
+ const uint8_t uuid[BT_GATT_UUID_SIZE],
+ bt_gatt_service_t *service)
+{
+ while (bt_gatt_service_iter_next(iter, service)) {
+ if (memcmp(service->uuid, uuid, UUID_BYTES) == 0)
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 65da93c..a4cd132 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
#include <stdbool.h>
#include <stdint.h>
+#include <stddef.h>
+
+#define BT_GATT_UUID_SIZE 16
struct bt_gatt_client;
void *user_data);
typedef void (*bt_gatt_client_debug_func_t)(const char *str, void *user_data);
+bool bt_gatt_client_is_ready(struct bt_gatt_client *client);
bool bt_gatt_client_set_ready_handler(struct bt_gatt_client *client,
bt_gatt_client_callback_t callback,
void *user_data,
bt_gatt_client_debug_func_t callback,
void *user_data,
bt_gatt_client_destroy_func_t destroy);
+
+typedef struct {
+ uint16_t handle;
+ uint8_t uuid[BT_GATT_UUID_SIZE];
+} bt_gatt_descriptor_t;
+
+typedef struct {
+ uint16_t handle;
+ uint16_t value_handle;
+ uint8_t properties;
+ uint8_t uuid[BT_GATT_UUID_SIZE];
+ const bt_gatt_descriptor_t *descs;
+ size_t num_descs;
+} bt_gatt_characteristic_t;
+
+typedef struct {
+ uint16_t start_handle;
+ uint16_t end_handle;
+ uint8_t uuid[BT_GATT_UUID_SIZE];
+ const bt_gatt_characteristic_t *chrcs;
+ size_t num_chrcs;
+} bt_gatt_service_t;
+
+struct bt_gatt_service_iter {
+ struct bt_gatt_client *client;
+ void *ptr;
+};
+
+bool bt_gatt_service_iter_init(struct bt_gatt_service_iter *iter,
+ struct bt_gatt_client *client);
+bool bt_gatt_service_iter_next(struct bt_gatt_service_iter *iter,
+ bt_gatt_service_t *service);
+bool bt_gatt_service_iter_next_by_handle(struct bt_gatt_service_iter *iter,
+ uint16_t start_handle,
+ bt_gatt_service_t *service);
+bool bt_gatt_service_iter_next_by_uuid(struct bt_gatt_service_iter *iter,
+ const uint8_t uuid[BT_GATT_UUID_SIZE],
+ bt_gatt_service_t *service);