All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/4] shared/gatt-db: Add service events.
@ 2014-12-03 16:26 Arman Uguray
  2014-12-03 16:26 ` [PATCH BlueZ 1/4] shared/gatt-server: Hold a reference to gatt-db Arman Uguray
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Arman Uguray @ 2014-12-03 16:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Arman Uguray

This patch set introduces service added/removed events to gatt-db.
gatt-db now allows callbacks to be registered, which are called when a
service is marked as active/inactive or when they get removed from the
database.

Also included is a small fix to gatt-server so that it holds a reference
to its associated gatt-db.

Arman Uguray (4):
  shared/gatt-server: Hold a reference to gatt-db.
  shared/gatt-db: Add service added/removed events.
  tools/btgatt-client: Observe service events.
  TODO: gatt-db service events added.

 TODO                     |   7 --
 src/shared/gatt-db.c     | 195 +++++++++++++++++++++++++++++++++++++++++++----
 src/shared/gatt-db.h     |  39 ++++++----
 src/shared/gatt-server.c |   5 +-
 tools/btgatt-client.c    |  28 +++++++
 5 files changed, 234 insertions(+), 40 deletions(-)

-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 1/4] shared/gatt-server: Hold a reference to gatt-db.
  2014-12-03 16:26 [PATCH BlueZ 0/4] shared/gatt-db: Add service events Arman Uguray
@ 2014-12-03 16:26 ` Arman Uguray
  2014-12-03 16:26 ` [PATCH BlueZ 2/4] shared/gatt-db: Add service added/removed events Arman Uguray
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Arman Uguray @ 2014-12-03 16:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Arman Uguray

Now that gatt-db is reference counted, gatt-server should hold a
reference to it.
---
 src/shared/gatt-server.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
index ef91289..3f3db56 100644
--- a/src/shared/gatt-server.c
+++ b/src/shared/gatt-server.c
@@ -129,6 +129,7 @@ static void bt_gatt_server_free(struct bt_gatt_server *server)
 
 	queue_destroy(server->prep_queue, prep_write_data_destroy);
 
+	gatt_db_unref(server->db);
 	bt_att_unref(server->att);
 	free(server);
 }
@@ -1177,14 +1178,14 @@ struct bt_gatt_server *bt_gatt_server_new(struct gatt_db *db,
 {
 	struct bt_gatt_server *server;
 
-	if (!att)
+	if (!att || !db)
 		return NULL;
 
 	server = new0(struct bt_gatt_server, 1);
 	if (!server)
 		return NULL;
 
-	server->db = db;
+	server->db = gatt_db_ref(db);
 	server->att = bt_att_ref(att);
 	server->mtu = MAX(mtu, BT_ATT_DEFAULT_LE_MTU);
 	server->max_prep_queue_len = DEFAULT_MAX_PREP_QUEUE_LEN;
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 2/4] shared/gatt-db: Add service added/removed events.
  2014-12-03 16:26 [PATCH BlueZ 0/4] shared/gatt-db: Add service events Arman Uguray
  2014-12-03 16:26 ` [PATCH BlueZ 1/4] shared/gatt-server: Hold a reference to gatt-db Arman Uguray
@ 2014-12-03 16:26 ` Arman Uguray
  2014-12-03 16:26 ` [PATCH BlueZ 3/4] tools/btgatt-client: Observe service events Arman Uguray
  2014-12-03 16:26 ` [PATCH BlueZ 4/4] TODO: gatt-db service events added Arman Uguray
  3 siblings, 0 replies; 5+ messages in thread
From: Arman Uguray @ 2014-12-03 16:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Arman Uguray

This patch adds support to gatt-db for sending events when services are
added to and removed from the database:

  1. Added the gatt_db_register function which can be used to register
     service_added and service_removed callbacks.

  2. Added the gatt_db_unregister function which can be used to
     unregister previously added callbacks. This function can be safely
     called from within a service added/removed callback.

  3. The service added/removed callbacks are tied to
     gatt_db_service_set_active. The added callback is called when a
     service gets marked as active and vice versa.

  4. The service_removed callback will get called if a service is
     removed from the database.
---
 src/shared/gatt-db.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++-----
 src/shared/gatt-db.h |  39 +++++++----
 2 files changed, 203 insertions(+), 31 deletions(-)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 238872c..f96131d 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -51,6 +51,20 @@ struct gatt_db {
 	int ref_count;
 	uint16_t next_handle;
 	struct queue *services;
+
+	struct queue *notify_list;
+	bool in_notify;
+	bool need_notify_cleanup;
+	unsigned int next_notify_id;
+};
+
+struct notify {
+	unsigned int id;
+	bool removed;
+	gatt_db_attribute_cb_t service_added;
+	gatt_db_attribute_cb_t service_removed;
+	gatt_db_destroy_func_t destroy;
+	void *user_data;
 };
 
 struct pending_read {
@@ -89,6 +103,7 @@ struct gatt_db_attribute {
 };
 
 struct gatt_db_service {
+	struct gatt_db *db;
 	bool active;
 	uint16_t num_handles;
 	struct gatt_db_attribute **attributes;
@@ -168,16 +183,97 @@ struct gatt_db *gatt_db_new(void)
 		return NULL;
 	}
 
+	db->notify_list = queue_new();
+	if (!db->notify_list) {
+		queue_destroy(db->services, NULL);
+		free(db);
+		return NULL;
+	}
+
 	db->next_handle = 0x0001;
 
 	return gatt_db_ref(db);
 }
 
+static void notify_destroy(void *data)
+{
+	struct notify *notify = data;
+
+	if (notify->destroy)
+		notify->destroy(notify->user_data);
+
+	free(notify);
+}
+
+static bool match_notify_id(const void *a, const void *b)
+{
+	const struct notify *notify = a;
+	unsigned int id = PTR_TO_UINT(b);
+
+	return notify->id == id;
+}
+
+static bool match_notify_removed(const void *a, const void *b)
+{
+	const struct notify *notify = a;
+
+	return notify->removed;
+}
+
+struct notify_data {
+	struct gatt_db_attribute *attr;
+	bool added;
+};
+
+static void handle_notify(void *data, void *user_data)
+{
+	struct notify *notify = data;
+	struct notify_data *notify_data = user_data;
+
+	if (notify->removed)
+		return;
+
+	if (notify_data->added)
+		notify->service_added(notify_data->attr, notify->user_data);
+	else
+		notify->service_removed(notify_data->attr, notify->user_data);
+}
+
+static void notify_service_changed(struct gatt_db *db,
+						struct gatt_db_service *service,
+						bool added)
+{
+	struct notify_data data;
+
+	if (queue_isempty(db->notify_list))
+		return;
+
+	data.attr = service->attributes[0];
+	data.added = added;
+
+	gatt_db_ref(db);
+
+	db->in_notify = true;
+	queue_foreach(db->notify_list, handle_notify, &data);
+	db->in_notify = false;
+
+	if (db->need_notify_cleanup) {
+		queue_remove_all(db->notify_list, match_notify_removed, NULL,
+								notify_destroy);
+		db->need_notify_cleanup = false;
+	}
+
+	gatt_db_unref(db);
+}
+
 static void gatt_db_service_destroy(void *data)
 {
 	struct gatt_db_service *service = data;
 	int i;
 
+	if (service->active)
+		notify_service_changed(service->db, service, false);
+
 	for (i = 0; i < service->num_handles; i++)
 		attribute_destroy(service->attributes[i]);
 
@@ -190,6 +286,11 @@ static void gatt_db_destroy(struct gatt_db *db)
 	if (!db)
 		return;
 
+	/*
+	 * Clear the notify list before clearing the services to prevent the
+	 * latter from sending service_removed events.
+	 */
+	queue_destroy(db->notify_list, notify_destroy);
 	queue_destroy(db->services, gatt_db_service_destroy);
 	free(db);
 }
@@ -433,6 +534,7 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
 			goto fail;
 	}
 
+	service->db = db;
 	service->attributes[0]->handle = handle;
 	service->num_handles = num_handles;
 
@@ -455,6 +557,62 @@ struct gatt_db_attribute *gatt_db_add_service(struct gatt_db *db,
 								num_handles);
 }
 
+unsigned int gatt_db_register(struct gatt_db *db,
+					gatt_db_attribute_cb_t service_added,
+					gatt_db_attribute_cb_t service_removed,
+					void *user_data,
+					gatt_db_destroy_func_t destroy)
+{
+	struct notify *notify;
+
+	if (!db || !(service_added || service_removed))
+		return 0;
+
+	notify = new0(struct notify, 1);
+	if (!notify)
+		return 0;
+
+	notify->service_added = service_added;
+	notify->service_removed = service_removed;
+	notify->destroy = destroy;
+	notify->user_data = user_data;
+
+	if (db->next_notify_id < 1)
+		db->next_notify_id = 1;
+
+	notify->id = db->next_notify_id++;
+
+	if (!queue_push_tail(db->notify_list, notify)) {
+		free(notify);
+		return 0;
+	}
+
+	return notify->id;
+}
+
+bool gatt_db_unregister(struct gatt_db *db, unsigned int id)
+{
+	struct notify *notify;
+
+	if (!db || !id)
+		return false;
+
+	notify = queue_find(db->notify_list, match_notify_id, UINT_TO_PTR(id));
+	if (!notify)
+		return false;
+
+	if (!db->in_notify) {
+		queue_remove(db->notify_list, notify);
+		notify_destroy(notify);
+		return true;
+	}
+
+	notify->removed = true;
+	db->need_notify_cleanup = true;
+
+	return true;
+}
+
 static uint16_t get_attribute_index(struct gatt_db_service *service,
 							int end_offset)
 {
@@ -636,10 +794,15 @@ gatt_db_service_add_included(struct gatt_db_attribute *attrib,
 
 bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active)
 {
+	struct gatt_db_service *service;
+
 	if (!attrib)
 		return false;
 
-	attrib->service->active = active;
+	service = attrib->service;
+	service->active = active;
+
+	notify_service_changed(service->db, service, active);
 
 	return true;
 }
@@ -858,14 +1021,14 @@ void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
 	queue_foreach(db->services, find_information, &data);
 }
 
-void gatt_db_foreach_service(struct gatt_db *db, gatt_db_foreach_t func,
+void gatt_db_foreach_service(struct gatt_db *db, gatt_db_attribute_cb_t func,
 							void *user_data)
 {
 	gatt_db_foreach_service_in_range(db, func, user_data, 0x0001, 0xffff);
 }
 
 struct foreach_data {
-	gatt_db_foreach_t func;
+	gatt_db_attribute_cb_t func;
 	void *user_data;
 	uint16_t start, end;
 };
@@ -885,10 +1048,10 @@ static void foreach_service_in_range(void *data, void *user_data)
 }
 
 void gatt_db_foreach_service_in_range(struct gatt_db *db,
-							gatt_db_foreach_t func,
-							void *user_data,
-							uint16_t start_handle,
-							uint16_t end_handle)
+						gatt_db_attribute_cb_t func,
+						void *user_data,
+						uint16_t start_handle,
+						uint16_t end_handle)
 {
 	struct foreach_data data;
 
@@ -904,9 +1067,9 @@ void gatt_db_foreach_service_in_range(struct gatt_db *db,
 }
 
 void gatt_db_service_foreach(struct gatt_db_attribute *attrib,
-							const bt_uuid_t *uuid,
-							gatt_db_foreach_t func,
-							void *user_data)
+						const bt_uuid_t *uuid,
+						gatt_db_attribute_cb_t func,
+						void *user_data)
 {
 	struct gatt_db_service *service;
 	struct gatt_db_attribute *attr;
@@ -930,15 +1093,15 @@ void gatt_db_service_foreach(struct gatt_db_attribute *attrib,
 }
 
 void gatt_db_service_foreach_char(struct gatt_db_attribute *attrib,
-							gatt_db_foreach_t func,
-							void *user_data)
+						gatt_db_attribute_cb_t func,
+						void *user_data)
 {
 	gatt_db_service_foreach(attrib, &characteristic_uuid, func, user_data);
 }
 
 void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib,
-							gatt_db_foreach_t func,
-							void *user_data)
+						gatt_db_attribute_cb_t func,
+						void *user_data)
 {
 	struct gatt_db_service *service;
 	struct gatt_db_attribute *attr;
@@ -970,8 +1133,8 @@ void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib,
 }
 
 void gatt_db_service_foreach_incl(struct gatt_db_attribute *attrib,
-							gatt_db_foreach_t func,
-							void *user_data)
+						gatt_db_attribute_cb_t func,
+						void *user_data)
 {
 	gatt_db_service_foreach(attrib, &included_service_uuid, func,
 								user_data);
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 5db9f9b..987ccf4 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -102,30 +102,39 @@ void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
 							struct queue *queue);
 
 
-typedef void (*gatt_db_foreach_t)(struct gatt_db_attribute *attrib,
+typedef void (*gatt_db_attribute_cb_t)(struct gatt_db_attribute *attrib,
 							void *user_data);
-void gatt_db_foreach_service(struct gatt_db *db, gatt_db_foreach_t func,
+
+void gatt_db_foreach_service(struct gatt_db *db, gatt_db_attribute_cb_t func,
 							void *user_data);
 void gatt_db_foreach_service_in_range(struct gatt_db *db,
-							gatt_db_foreach_t func,
-							void *user_data,
-							uint16_t start_handle,
-							uint16_t end_handle);
+						gatt_db_attribute_cb_t func,
+						void *user_data,
+						uint16_t start_handle,
+						uint16_t end_handle);
 
 void gatt_db_service_foreach(struct gatt_db_attribute *attrib,
-							const bt_uuid_t *uuid,
-							gatt_db_foreach_t func,
-							void *user_data);
+						const bt_uuid_t *uuid,
+						gatt_db_attribute_cb_t func,
+						void *user_data);
 void gatt_db_service_foreach_char(struct gatt_db_attribute *attrib,
-							gatt_db_foreach_t func,
-							void *user_data);
+						gatt_db_attribute_cb_t func,
+						void *user_data);
 void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib,
-							gatt_db_foreach_t func,
-							void *user_data);
+						gatt_db_attribute_cb_t func,
+						void *user_data);
 void gatt_db_service_foreach_incl(struct gatt_db_attribute *attrib,
-							gatt_db_foreach_t func,
-							void *user_data);
+						gatt_db_attribute_cb_t func,
+						void *user_data);
+
+typedef void (*gatt_db_destroy_func_t)(void *user_data);
 
+unsigned int gatt_db_register(struct gatt_db *db,
+					gatt_db_attribute_cb_t service_added,
+					gatt_db_attribute_cb_t service_removed,
+					void *user_data,
+					gatt_db_destroy_func_t destroy);
+bool gatt_db_unregister(struct gatt_db *db, unsigned int id);
 
 struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
 							uint16_t handle);
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 3/4] tools/btgatt-client: Observe service events.
  2014-12-03 16:26 [PATCH BlueZ 0/4] shared/gatt-db: Add service events Arman Uguray
  2014-12-03 16:26 ` [PATCH BlueZ 1/4] shared/gatt-server: Hold a reference to gatt-db Arman Uguray
  2014-12-03 16:26 ` [PATCH BlueZ 2/4] shared/gatt-db: Add service added/removed events Arman Uguray
@ 2014-12-03 16:26 ` Arman Uguray
  2014-12-03 16:26 ` [PATCH BlueZ 4/4] TODO: gatt-db service events added Arman Uguray
  3 siblings, 0 replies; 5+ messages in thread
From: Arman Uguray @ 2014-12-03 16:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Arman Uguray

tools/btgatt-client now registers service added/removed callbacks in
which it logs a message about the affected service.
---
 tools/btgatt-client.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index 2a2067b..fe94ae8 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -99,6 +99,31 @@ static void ready_cb(bool success, uint8_t att_ecode, void *user_data);
 static void service_changed_cb(uint16_t start_handle, uint16_t end_handle,
 							void *user_data);
 
+static void log_service_event(struct gatt_db_attribute *attr, const char *str)
+{
+	char uuid_str[MAX_LEN_UUID_STR];
+	bt_uuid_t uuid;
+	uint16_t start, end;
+
+	gatt_db_attribute_get_service_uuid(attr, &uuid);
+	bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+
+	gatt_db_attribute_get_service_handles(attr, &start, &end);
+
+	PRLOG("%s - UUID: %s start: 0x%04x end: 0x%04x\n", str, uuid_str,
+								start, end);
+}
+
+static void service_added_cb(struct gatt_db_attribute *attr, void *user_data)
+{
+	log_service_event(attr, "Service Added");
+}
+
+static void service_removed_cb(struct gatt_db_attribute *attr, void *user_data)
+{
+	log_service_event(attr, "Service Removed");
+}
+
 static struct client *client_create(int fd, uint16_t mtu)
 {
 	struct client *cli;
@@ -150,6 +175,9 @@ static struct client *client_create(int fd, uint16_t mtu)
 		return NULL;
 	}
 
+	gatt_db_register(cli->db, service_added_cb, service_removed_cb,
+								NULL, NULL);
+
 	if (verbose) {
 		bt_att_set_debug(att, att_debug_cb, "att: ", NULL);
 		bt_gatt_client_set_debug(cli->gatt, gatt_debug_cb, "gatt: ",
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 4/4] TODO: gatt-db service events added.
  2014-12-03 16:26 [PATCH BlueZ 0/4] shared/gatt-db: Add service events Arman Uguray
                   ` (2 preceding siblings ...)
  2014-12-03 16:26 ` [PATCH BlueZ 3/4] tools/btgatt-client: Observe service events Arman Uguray
@ 2014-12-03 16:26 ` Arman Uguray
  3 siblings, 0 replies; 5+ messages in thread
From: Arman Uguray @ 2014-12-03 16:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Arman Uguray

---
 TODO | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/TODO b/TODO
index e8b0ab1..ca3779b 100644
--- a/TODO
+++ b/TODO
@@ -155,13 +155,6 @@ ATT/GATT (new shared stack)
   Priority: Medium
   Complexity: C4
 
-- Add service_added and service_removed callbacks to shared/gatt-db which should
-  get triggered via bt_gatt_service_set_active and when services get add or
-  removed.
-
-  Priority: Medium
-  Complexity: C2
-
 - Implement the client portion of doc/gatt-api.txt using shared/gatt-client once
   plugin/profile code uses it.
 
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-12-03 16:26 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-03 16:26 [PATCH BlueZ 0/4] shared/gatt-db: Add service events Arman Uguray
2014-12-03 16:26 ` [PATCH BlueZ 1/4] shared/gatt-server: Hold a reference to gatt-db Arman Uguray
2014-12-03 16:26 ` [PATCH BlueZ 2/4] shared/gatt-db: Add service added/removed events Arman Uguray
2014-12-03 16:26 ` [PATCH BlueZ 3/4] tools/btgatt-client: Observe service events Arman Uguray
2014-12-03 16:26 ` [PATCH BlueZ 4/4] TODO: gatt-db service events added Arman Uguray

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.