linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/9] Add GATT Client Battery Service
@ 2012-08-08 14:26 chen.ganir
  2012-08-08 14:26 ` [PATCH v3 1/9] Battery: Add Battery Service GATT Client chen.ganir
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Add suupport for LE GATT Client Battery Service.

This plugin adds battery list to the btd_device, exposes DBUS API to list the
device batteries, and allows querying for battery information. In addition this
patch allows getting notifications for battery level changes.

Look at doc/device-api.txt and doc/battery-api.txt for more information.

This is version 3 of this patch set, rebased on top of the latest sources and 
fixes issues reported on the ML.

Chen Ganir (9):
  Battery: Add Battery Service GATT Client
  Battery: Add connection logic
  Battery: Discover Characteristic Descriptors
  Battery: Get Battery ID
  Battery: Add Battery list to btd_device
  Battery: Add Battery D-BUS API
  Battery: Read Battery level characteristic
  Battery: Add support for notifications
  Battery: Emit property changed on first read

 Makefile.am                |   10 +-
 doc/battery-api.txt        |   38 ++++
 doc/device-api.txt         |    5 +
 profiles/battery/battery.c |  536 ++++++++++++++++++++++++++++++++++++++++++++
 profiles/battery/battery.h |   26 +++
 profiles/battery/main.c    |   67 ++++++
 profiles/battery/manager.c |   71 ++++++
 profiles/battery/manager.h |   24 ++
 src/device.c               |   65 ++++++
 src/device.h               |    3 +
 10 files changed, 843 insertions(+), 2 deletions(-)
 create mode 100644 doc/battery-api.txt
 create mode 100644 profiles/battery/battery.c
 create mode 100644 profiles/battery/battery.h
 create mode 100644 profiles/battery/main.c
 create mode 100644 profiles/battery/manager.c
 create mode 100644 profiles/battery/manager.h

-- 
1.7.9.5


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

* [PATCH v3 1/9] Battery: Add Battery Service GATT Client
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-08 14:26 ` [PATCH v3 2/9] Battery: Add connection logic chen.ganir
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Add support for the Battery Service Gatt Client side.
---
 Makefile.am                |   10 ++++-
 profiles/battery/battery.c |   88 ++++++++++++++++++++++++++++++++++++++++++++
 profiles/battery/battery.h |   24 ++++++++++++
 profiles/battery/main.c    |   53 ++++++++++++++++++++++++++
 profiles/battery/manager.c |   62 +++++++++++++++++++++++++++++++
 profiles/battery/manager.h |   24 ++++++++++++
 6 files changed, 259 insertions(+), 2 deletions(-)
 create mode 100644 profiles/battery/battery.c
 create mode 100644 profiles/battery/battery.h
 create mode 100644 profiles/battery/main.c
 create mode 100644 profiles/battery/manager.c
 create mode 100644 profiles/battery/manager.h

diff --git a/Makefile.am b/Makefile.am
index 45a811c..710350e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -211,7 +211,8 @@ builtin_sources += profiles/health/hdp_main.c profiles/health/hdp_types.h \
 endif
 
 if GATTMODULES
-builtin_modules += thermometer alert time gatt_example proximity deviceinfo
+builtin_modules += thermometer alert time gatt_example proximity deviceinfo \
+            battery
 builtin_sources += profiles/thermometer/main.c \
 			profiles/thermometer/manager.h \
 			profiles/thermometer/manager.c \
@@ -237,7 +238,12 @@ builtin_sources += profiles/thermometer/main.c \
 			profiles/deviceinfo/manager.h \
 			profiles/deviceinfo/manager.c \
 			profiles/deviceinfo/deviceinfo.h \
-			profiles/deviceinfo/deviceinfo.c
+			profiles/deviceinfo/deviceinfo.c \
+			profiles/battery/main.c \
+			profiles/battery/manager.c \
+			profiles/battery/manager.h \
+			profiles/battery/battery.c \
+			profiles/battery/battery.h
 endif
 
 builtin_modules += formfactor
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
new file mode 100644
index 0000000..7ed5707
--- /dev/null
+++ b/profiles/battery/battery.c
@@ -0,0 +1,88 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "battery.h"
+
+struct battery {
+	struct btd_device	*dev;		/* Device reference */
+};
+
+static GSList *servers;
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+	const struct battery *batt = a;
+	const struct btd_device *dev = b;
+
+	if (dev == batt->dev)
+		return 0;
+
+	return -1;
+}
+
+static void battery_free(gpointer user_data)
+{
+	struct battery *batt = user_data;
+
+	btd_device_unref(batt->dev);
+	g_free(batt);
+}
+
+
+int battery_register(struct btd_device *device)
+{
+	struct battery *batt;
+
+	batt = g_new0(struct battery, 1);
+	batt->dev = btd_device_ref(device);
+
+	servers = g_slist_prepend(servers, batt);
+
+	return 0;
+}
+
+void battery_unregister(struct btd_device *device)
+{
+	struct battery *batt;
+	GSList *l;
+
+	l = g_slist_find_custom(servers, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	batt = l->data;
+	servers = g_slist_remove(servers, batt);
+
+	battery_free(batt);
+}
diff --git a/profiles/battery/battery.h b/profiles/battery/battery.h
new file mode 100644
index 0000000..9933343
--- /dev/null
+++ b/profiles/battery/battery.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int battery_register(struct btd_device *device);
+void battery_unregister(struct btd_device *device);
diff --git a/profiles/battery/main.c b/profiles/battery/main.c
new file mode 100644
index 0000000..47f4249
--- /dev/null
+++ b/profiles/battery/main.c
@@ -0,0 +1,53 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "hcid.h"
+#include "plugin.h"
+#include "manager.h"
+#include "log.h"
+
+static int battery_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		DBG("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return battery_manager_init();
+}
+
+static void battery_exit(void)
+{
+	battery_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(battery, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, battery_init,
+			battery_exit)
diff --git a/profiles/battery/manager.c b/profiles/battery/manager.c
new file mode 100644
index 0000000..84b85a3
--- /dev/null
+++ b/profiles/battery/manager.c
@@ -0,0 +1,62 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <glib.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "battery.h"
+#include "manager.h"
+
+#define BATTERY_SERVICE_UUID		"0000180f-0000-1000-8000-00805f9b34fb"
+
+static int battery_driver_probe(struct btd_device *device, GSList *uuids)
+{
+	return battery_register(device);
+}
+
+static void battery_driver_remove(struct btd_device *device)
+{
+	battery_unregister(device);
+}
+
+static struct btd_device_driver battery_device_driver = {
+	.name	= "battery-driver",
+	.uuids	= BTD_UUIDS(BATTERY_SERVICE_UUID),
+	.probe	= battery_driver_probe,
+	.remove	= battery_driver_remove
+};
+
+int battery_manager_init(void)
+{
+	return btd_register_device_driver(&battery_device_driver);
+}
+
+void battery_manager_exit(void)
+{
+	btd_unregister_device_driver(&battery_device_driver);
+}
diff --git a/profiles/battery/manager.h b/profiles/battery/manager.h
new file mode 100644
index 0000000..b2c849f
--- /dev/null
+++ b/profiles/battery/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int battery_manager_init(void);
+void battery_manager_exit(void);
-- 
1.7.9.5


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

* [PATCH v3 2/9] Battery: Add connection logic
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
  2012-08-08 14:26 ` [PATCH v3 1/9] Battery: Add Battery Service GATT Client chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-08 14:26 ` [PATCH v3 3/9] Battery: Discover Characteristic Descriptors chen.ganir
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Add connection logic to the Battery Plugin. When the driver is
loaded, it will request a connection to the remote device and
release the connection request when destroyed.
---
 profiles/battery/battery.c |   91 ++++++++++++++++++++++++++++++++++++++++++++
 profiles/battery/battery.h |    2 +
 profiles/battery/manager.c |    2 -
 3 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 7ed5707..f9ef73d 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -29,17 +29,29 @@
 
 #include "adapter.h"
 #include "device.h"
+#include "gattrib.h"
+#include "attio.h"
 #include "att.h"
 #include "gattrib.h"
 #include "gatt.h"
 #include "battery.h"
+#include "log.h"
 
 struct battery {
 	struct btd_device	*dev;		/* Device reference */
+	GAttrib			*attrib;	/* GATT connection */
+	guint			attioid;	/* Att watcher id */
+	struct att_range	*svc_range;	/* Battery range */
+	GSList			*chars;		/* Characteristics */
 };
 
 static GSList *servers;
 
+struct characteristic {
+	struct gatt_char	attr;	/* Characteristic */
+	struct battery		*batt;	/* Parent Battery Service */
+};
+
 static gint cmp_device(gconstpointer a, gconstpointer b)
 {
 	const struct battery *batt = a;
@@ -55,20 +67,99 @@ static void battery_free(gpointer user_data)
 {
 	struct battery *batt = user_data;
 
+	if (batt->chars != NULL)
+		g_slist_free_full(batt->chars, g_free);
+
+	if (batt->attioid > 0)
+		btd_device_remove_attio_callback(batt->dev, batt->attioid);
+
+	if (batt->attrib != NULL)
+		g_attrib_unref(batt->attrib);
+
 	btd_device_unref(batt->dev);
 	g_free(batt);
 }
 
+static void configure_battery_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct battery *batt = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover Battery characteristics: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	for (l = characteristics; l; l = l->next) {
+		struct gatt_char *c = l->data;
+		struct characteristic *ch;
+
+		ch = g_new0(struct characteristic, 1);
+		ch->attr.handle = c->handle;
+		ch->attr.properties = c->properties;
+		ch->attr.value_handle = c->value_handle;
+		memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+		ch->batt = batt;
+
+		batt->chars = g_slist_append(batt->chars, ch);
+	}
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct battery *batt = user_data;
+
+	batt->attrib = g_attrib_ref(attrib);
+
+	if (batt->chars == NULL) {
+		gatt_discover_char(batt->attrib, batt->svc_range->start,
+					batt->svc_range->end, NULL,
+					configure_battery_cb, batt);
+	}
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct battery *batt = user_data;
+
+	g_attrib_unref(batt->attrib);
+	batt->attrib = NULL;
+}
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct gatt_primary *prim = a;
+	const char *uuid = b;
+
+	return g_strcmp0(prim->uuid, uuid);
+}
 
 int battery_register(struct btd_device *device)
 {
 	struct battery *batt;
+	struct gatt_primary *prim;
+	GSList *primaries, *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, BATTERY_SERVICE_UUID,
+							primary_uuid_cmp);
+	prim = l->data;
 
 	batt = g_new0(struct battery, 1);
 	batt->dev = btd_device_ref(device);
 
+	batt->svc_range = g_new0(struct att_range, 1);
+	batt->svc_range->start = prim->range.start;
+	batt->svc_range->end = prim->range.end;
+
 	servers = g_slist_prepend(servers, batt);
 
+	batt->attioid = btd_device_add_attio_callback(device,
+				attio_connected_cb, attio_disconnected_cb,
+				batt);
 	return 0;
 }
 
diff --git a/profiles/battery/battery.h b/profiles/battery/battery.h
index 9933343..801186d 100644
--- a/profiles/battery/battery.h
+++ b/profiles/battery/battery.h
@@ -20,5 +20,7 @@
  *
  */
 
+#define BATTERY_SERVICE_UUID		"0000180f-0000-1000-8000-00805f9b34fb"
+
 int battery_register(struct btd_device *device);
 void battery_unregister(struct btd_device *device);
diff --git a/profiles/battery/manager.c b/profiles/battery/manager.c
index 84b85a3..22b8b20 100644
--- a/profiles/battery/manager.c
+++ b/profiles/battery/manager.c
@@ -32,8 +32,6 @@
 #include "battery.h"
 #include "manager.h"
 
-#define BATTERY_SERVICE_UUID		"0000180f-0000-1000-8000-00805f9b34fb"
-
 static int battery_driver_probe(struct btd_device *device, GSList *uuids)
 {
 	return battery_register(device);
-- 
1.7.9.5


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

* [PATCH v3 3/9] Battery: Discover Characteristic Descriptors
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
  2012-08-08 14:26 ` [PATCH v3 1/9] Battery: Add Battery Service GATT Client chen.ganir
  2012-08-08 14:26 ` [PATCH v3 2/9] Battery: Add connection logic chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-08 14:26 ` [PATCH v3 4/9] Battery: Get Battery ID chen.ganir
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Discover all characteristic descriptors, and build a descriptor
list
---
 profiles/battery/battery.c |   62 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index f9ef73d..f93fdbc 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -50,6 +50,13 @@ static GSList *servers;
 struct characteristic {
 	struct gatt_char	attr;	/* Characteristic */
 	struct battery		*batt;	/* Parent Battery Service */
+	GSList				*desc;	/* Descriptors */
+};
+
+struct descriptor {
+	struct characteristic	*ch;	/* Parent Characteristic */
+	uint16_t		handle;	/* Descriptor Handle */
+	bt_uuid_t		uuid;	/* UUID */
 };
 
 static gint cmp_device(gconstpointer a, gconstpointer b)
@@ -80,7 +87,47 @@ static void battery_free(gpointer user_data)
 	g_free(batt);
 }
 
+static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct att_data_list *list;
+	uint8_t format;
+	int i;
+
+	if (status != 0) {
+		error("Discover all characteristic descriptors failed [%s]: %s",
+					ch->attr.uuid, att_ecode2str(status));
+		return;
+	}
+
+	list = dec_find_info_resp(pdu, len, &format);
+	if (list == NULL)
+		return;
+
+	for (i = 0; i < list->num; i++) {
+		struct descriptor *desc;
+		uint8_t *value;
+
+		value = list->data[i];
+		desc = g_new0(struct descriptor, 1);
+		desc->handle = att_get_u16(value);
+		desc->ch = ch;
+
+		if (format == 0x01)
+			desc->uuid = att_get_uuid16(&value[2]);
+		else
+			desc->uuid = att_get_uuid128(&value[2]);
+
+		ch->desc = g_slist_append(ch->desc, desc);
+	}
+
+	att_data_list_free(list);
+}
+
+
 static void configure_battery_cb(GSList *characteristics, guint8 status,
+
 							gpointer user_data)
 {
 	struct battery *batt = user_data;
@@ -95,6 +142,7 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 	for (l = characteristics; l; l = l->next) {
 		struct gatt_char *c = l->data;
 		struct characteristic *ch;
+		uint16_t start, end;
 
 		ch = g_new0(struct characteristic, 1);
 		ch->attr.handle = c->handle;
@@ -104,6 +152,20 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 		ch->batt = batt;
 
 		batt->chars = g_slist_append(batt->chars, ch);
+
+		start = c->value_handle + 1;
+
+		if (l->next != NULL) {
+			struct gatt_char *c = l->next->data;
+			if (start == c->handle)
+				continue;
+			end = c->handle - 1;
+		} else if (c->value_handle != batt->svc_range->end)
+			end = batt->svc_range->end;
+		else
+			continue;
+
+		gatt_find_info(batt->attrib, start, end, discover_desc_cb, ch);
 	}
 }
 
-- 
1.7.9.5


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

* [PATCH v3 4/9] Battery: Get Battery ID
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
                   ` (2 preceding siblings ...)
  2012-08-08 14:26 ` [PATCH v3 3/9] Battery: Discover Characteristic Descriptors chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-08 14:26 ` [PATCH v3 5/9] Battery: Add Battery list to btd_device chen.ganir
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Read the battery level format characteristic descriptor to get the
unique namespace and description values.
---
 profiles/battery/battery.c |  112 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 85 insertions(+), 27 deletions(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index f93fdbc..a33ac8c 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -37,6 +37,8 @@
 #include "battery.h"
 #include "log.h"
 
+#define BATTERY_LEVEL_UUID	"00002a19-0000-1000-8000-00805f9b34fb"
+
 struct battery {
 	struct btd_device	*dev;		/* Device reference */
 	GAttrib			*attrib;	/* GATT connection */
@@ -48,15 +50,17 @@ struct battery {
 static GSList *servers;
 
 struct characteristic {
-	struct gatt_char	attr;	/* Characteristic */
-	struct battery		*batt;	/* Parent Battery Service */
+	struct gatt_char	attr;		/* Characteristic */
+	struct battery		*batt;		/* Parent Battery Service */
 	GSList				*desc;	/* Descriptors */
+	uint8_t			ns;		/* Battery Namespace */
+	uint16_t		description;	/* Battery description */
 };
 
 struct descriptor {
-	struct characteristic	*ch;	/* Parent Characteristic */
-	uint16_t		handle;	/* Descriptor Handle */
-	bt_uuid_t		uuid;	/* UUID */
+	struct characteristic	*ch;		/* Parent Characteristic */
+	uint16_t		handle;		/* Descriptor Handle */
+	bt_uuid_t		uuid;		/* UUID */
 };
 
 static gint cmp_device(gconstpointer a, gconstpointer b)
@@ -87,6 +91,55 @@ static void battery_free(gpointer user_data)
 	g_free(batt);
 }
 
+static void batterylevel_presentation_format_desc_cb(guint8 status,
+						const guint8 *pdu, guint16 len,
+						gpointer user_data)
+{
+	struct descriptor *desc = user_data;
+	uint8_t value[ATT_MAX_MTU];
+	int vlen;
+
+	if (status != 0) {
+		error("Presentation Format desc read failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (!vlen) {
+		error("Presentation Format desc read failed: Protocol error\n");
+		return;
+	}
+
+	if (vlen < 7) {
+		error("Presentation Format desc read failed: Invalid range");
+		return;
+	}
+
+	desc->ch->ns = value[4];
+	desc->ch->description = att_get_u16(&value[5]);
+}
+
+
+static void process_batterylevel_desc(struct descriptor *desc)
+{
+	struct characteristic *ch = desc->ch;
+	char uuidstr[MAX_LEN_UUID_STR];
+	bt_uuid_t btuuid;
+
+	bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
+
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+		gatt_read_char(ch->batt->attrib, desc->handle, 0,
+				batterylevel_presentation_format_desc_cb, desc);
+		return;
+	}
+
+	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+	DBG("Ignored descriptor %s characteristic %s", uuidstr,	ch->attr.uuid);
+}
+
+
 static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 							gpointer user_data)
 {
@@ -120,6 +173,7 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 			desc->uuid = att_get_uuid128(&value[2]);
 
 		ch->desc = g_slist_append(ch->desc, desc);
+		process_batterylevel_desc(desc);
 	}
 
 	att_data_list_free(list);
@@ -141,31 +195,35 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 
 	for (l = characteristics; l; l = l->next) {
 		struct gatt_char *c = l->data;
-		struct characteristic *ch;
-		uint16_t start, end;
-
-		ch = g_new0(struct characteristic, 1);
-		ch->attr.handle = c->handle;
-		ch->attr.properties = c->properties;
-		ch->attr.value_handle = c->value_handle;
-		memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
-		ch->batt = batt;
 
-		batt->chars = g_slist_append(batt->chars, ch);
-
-		start = c->value_handle + 1;
-
-		if (l->next != NULL) {
-			struct gatt_char *c = l->next->data;
-			if (start == c->handle)
+		if (g_strcmp0(c->uuid, BATTERY_LEVEL_UUID) == 0) {
+			struct characteristic *ch;
+			uint16_t start, end;
+
+			ch = g_new0(struct characteristic, 1);
+			ch->attr.handle = c->handle;
+			ch->attr.properties = c->properties;
+			ch->attr.value_handle = c->value_handle;
+			memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+			ch->batt = batt;
+
+			batt->chars = g_slist_append(batt->chars, ch);
+
+			start = c->value_handle + 1;
+
+			if (l->next != NULL) {
+				struct gatt_char *c = l->next->data;
+				if (start == c->handle)
+					continue;
+				end = c->handle - 1;
+			} else if (c->value_handle != batt->svc_range->end)
+				end = batt->svc_range->end;
+			else
 				continue;
-			end = c->handle - 1;
-		} else if (c->value_handle != batt->svc_range->end)
-			end = batt->svc_range->end;
-		else
-			continue;
 
-		gatt_find_info(batt->attrib, start, end, discover_desc_cb, ch);
+			gatt_find_info(batt->attrib, start, end,
+							discover_desc_cb, ch);
+		}
 	}
 }
 
-- 
1.7.9.5


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

* [PATCH v3 5/9] Battery: Add Battery list to btd_device
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
                   ` (3 preceding siblings ...)
  2012-08-08 14:26 ` [PATCH v3 4/9] Battery: Get Battery ID chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-08 14:26 ` [PATCH v3 6/9] Battery: Add Battery D-BUS API chen.ganir
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Add peer battery list to the btd_device. New property added to Device
called Batteries.
---
 doc/device-api.txt         |    5 ++++
 profiles/battery/battery.c |   14 ++++++++--
 src/device.c               |   65 ++++++++++++++++++++++++++++++++++++++++++++
 src/device.h               |    3 ++
 4 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/doc/device-api.txt b/doc/device-api.txt
index 1f0dc96..5d760b1 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -179,3 +179,8 @@ Properties	string Address [readonly]
 			Note that this property can exhibit false-positives
 			in the case of Bluetooth 2.1 (or newer) devices that
 			have disabled Extended Inquiry Response support.
+
+		array{string} Batteries [readonly]
+
+			List of device battery object paths that represents the available
+			batteries on the remote device.
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index a33ac8c..3f79c1f 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -50,6 +50,7 @@ struct battery {
 static GSList *servers;
 
 struct characteristic {
+	char			*path;          /* object path */
 	struct gatt_char	attr;		/* Characteristic */
 	struct battery		*batt;		/* Parent Battery Service */
 	GSList				*desc;	/* Descriptors */
@@ -151,12 +152,12 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 	if (status != 0) {
 		error("Discover all characteristic descriptors failed [%s]: %s",
 					ch->attr.uuid, att_ecode2str(status));
-		return;
+		goto update_char;
 	}
 
 	list = dec_find_info_resp(pdu, len, &format);
 	if (list == NULL)
-		return;
+		goto update_char;
 
 	for (i = 0; i < list->num; i++) {
 		struct descriptor *desc;
@@ -177,6 +178,14 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 	}
 
 	att_data_list_free(list);
+
+update_char:
+	ch->path = g_strdup_printf("%s/BATT-%02X-%04X",
+				device_get_path(ch->batt->dev),
+				ch->ns,
+				ch->description);
+
+	device_add_battery(ch->batt->dev, ch->path);
 }
 
 
@@ -206,7 +215,6 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 			ch->attr.value_handle = c->value_handle;
 			memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
 			ch->batt = batt;
-
 			batt->chars = g_slist_append(batt->chars, ch);
 
 			start = c->value_handle + 1;
diff --git a/src/device.c b/src/device.c
index 45ad1ae..98331db 100644
--- a/src/device.c
+++ b/src/device.c
@@ -124,6 +124,10 @@ struct att_callbacks {
 	gpointer user_data;
 };
 
+struct btd_battery {
+	char *path;
+};
+
 struct btd_device {
 	bdaddr_t	bdaddr;
 	uint8_t		bdaddr_type;
@@ -169,6 +173,7 @@ struct btd_device {
 
 	GIOChannel      *att_io;
 	guint		cleanup_id;
+	GSList		*batteries;
 };
 
 static uint16_t uuid_list[] = {
@@ -259,6 +264,7 @@ static void device_free(gpointer user_data)
 	g_slist_free_full(device->primaries, g_free);
 	g_slist_free_full(device->attios, g_free);
 	g_slist_free_full(device->attios_offline, g_free);
+	g_slist_free_full(device->batteries, g_free);
 
 	attio_cleanup(device);
 
@@ -433,6 +439,15 @@ static DBusMessage *get_properties(DBusConnection *conn,
 	ptr = adapter_get_path(adapter);
 	dict_append_entry(&dict, "Adapter", DBUS_TYPE_OBJECT_PATH, &ptr);
 
+	/* Batteries */
+	str = g_new0(char *, g_slist_length(device->batteries) + 1);
+	for (i = 0, l = device->batteries; l; l = l->next, i++) {
+		struct btd_battery *b = l->data;
+		str[i] = b->path;
+	}
+	dict_append_array(&dict, "Batteries", DBUS_TYPE_OBJECT_PATH, &str, i);
+	g_free(str);
+
 	dbus_message_iter_close_container(&iter, &dict);
 
 	return reply;
@@ -1215,6 +1230,9 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
 	g_slist_free(device->drivers);
 	device->drivers = NULL;
 
+	g_slist_free(device->batteries);
+	device->batteries = NULL;
+
 	attrib_client_unregister(device->services);
 
 	btd_device_unref(device);
@@ -3143,3 +3161,50 @@ void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
 	device_set_product(device, product_id);
 	device_set_version(device, product_ver);
 }
+
+static void batteries_changed(struct btd_device *device)
+{
+	DBusConnection *conn = get_dbus_connection();
+	char **batteries;
+	GSList *l;
+	int i;
+
+	batteries = g_new0(char *, g_slist_length(device->batteries) + 1);
+	for (i = 0, l = device->batteries; l; l = l->next, i++) {
+		struct btd_battery *batt = l->data;
+		batteries[i] = batt->path;
+	}
+
+	emit_array_property_changed(conn, device->path, DEVICE_INTERFACE,
+				    "Batteries", DBUS_TYPE_STRING, &batteries,
+				    i);
+
+	g_free(batteries);
+}
+
+void device_add_battery(struct btd_device *device, char *path)
+{
+	struct btd_battery *batt;
+
+	batt = g_new0(struct btd_battery, 1);
+	batt->path = g_strdup(path);
+	device->batteries = g_slist_append(device->batteries, batt);
+	batteries_changed(device);
+}
+
+void device_remove_battery(struct btd_device *device, char *path)
+{
+	GSList *l;
+
+	for (l = device->batteries; l; l = l->next) {
+		struct btd_battery *b = l->data;
+
+		if (g_strcmp0(path, b->path) == 0) {
+			device->batteries = g_slist_remove(device->batteries, b);
+			g_free(b->path);
+			g_free(b);
+			batteries_changed(device);
+			return;
+		}
+	}
+}
diff --git a/src/device.h b/src/device.h
index 26e17f7..db71a8a 100644
--- a/src/device.h
+++ b/src/device.h
@@ -126,3 +126,6 @@ int device_unblock(DBusConnection *conn, struct btd_device *device,
 void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
 			uint16_t vendor_id, uint16_t product_id,
 			uint16_t product_ver);
+
+void device_add_battery(struct btd_device *device, char *path);
+void device_remove_battery(struct btd_device *device, char *path);
-- 
1.7.9.5


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

* [PATCH v3 6/9] Battery: Add Battery D-BUS API
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
                   ` (4 preceding siblings ...)
  2012-08-08 14:26 ` [PATCH v3 5/9] Battery: Add Battery list to btd_device chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-08 14:26 ` [PATCH v3 7/9] Battery: Read Battery level characteristic chen.ganir
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Add Battery level specific API
---
 doc/battery-api.txt        |   33 +++++++++++++++++
 profiles/battery/battery.c |   87 +++++++++++++++++++++++++++++++++++++++++---
 profiles/battery/battery.h |    2 +-
 profiles/battery/main.c    |   18 ++++++++-
 profiles/battery/manager.c |   19 ++++++++--
 profiles/battery/manager.h |    2 +-
 6 files changed, 147 insertions(+), 14 deletions(-)
 create mode 100644 doc/battery-api.txt

diff --git a/doc/battery-api.txt b/doc/battery-api.txt
new file mode 100644
index 0000000..f8c1e43
--- /dev/null
+++ b/doc/battery-api.txt
@@ -0,0 +1,33 @@
+BlueZ D-Bus Battery API description
+****************************************
+
+	Texas Instruments, Inc. <chen.ganir@ti.com>
+
+Battery Service hierarchy
+=====================================
+
+Service		org.bluez
+Interface	org.bluez.Battery
+Object path	[variable prefix]/{hci0,..}/dev_XX_XX_XX_XX_XX_XX/BATT-NN-DDDD
+
+
+Methods	dict GetProperties()
+
+			Returns all properties for the interface. See the
+			Properties section for the available properties.
+
+Properties	byte Namespace [readonly]
+
+			Namespace value from the battery format characteristic
+			descriptor.Combined with Description provides a unique
+			battery identifyer if multiple batteries are supported.
+
+		uint16 Description [readonly]
+
+			Description value from the battery format characteristic
+			descriptor. Combined with Namespace provides a unique
+			battery identifyer if multiple batteries are supported.
+
+		byte Level [readonly]
+
+			Battery level (0-100).
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 3f79c1f..2f616e0 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -24,7 +24,9 @@
 #include <config.h>
 #endif
 
-#include <glib.h>
+#include <gdbus.h>
+#include <errno.h>
+#include <dbus/dbus.h>
 #include <bluetooth/uuid.h>
 
 #include "adapter.h"
@@ -34,12 +36,16 @@
 #include "att.h"
 #include "gattrib.h"
 #include "gatt.h"
+#include "dbus-common.h"
 #include "battery.h"
 #include "log.h"
 
+#define BATTERY_INTERFACE	"org.bluez.Battery"
+
 #define BATTERY_LEVEL_UUID	"00002a19-0000-1000-8000-00805f9b34fb"
 
 struct battery {
+	DBusConnection		*conn;		/* The connection to the bus */
 	struct btd_device	*dev;		/* Device reference */
 	GAttrib			*attrib;	/* GATT connection */
 	guint			attioid;	/* Att watcher id */
@@ -64,6 +70,28 @@ struct descriptor {
 	bt_uuid_t		uuid;		/* UUID */
 };
 
+static void char_free(gpointer user_data)
+{
+	struct characteristic *c = user_data;
+
+	g_slist_free_full(c->desc, g_free);
+
+	g_free(c);
+}
+
+static void char_interface_free(gpointer user_data)
+{
+	struct characteristic *c = user_data;
+	device_remove_battery(c->batt->dev, c->path);
+
+	g_dbus_unregister_interface(c->batt->conn,
+			c->path, BATTERY_INTERFACE);
+
+	g_free(c->path);
+
+	char_free(c);
+}
+
 static gint cmp_device(gconstpointer a, gconstpointer b)
 {
 	const struct battery *batt = a;
@@ -80,7 +108,7 @@ static void battery_free(gpointer user_data)
 	struct battery *batt = user_data;
 
 	if (batt->chars != NULL)
-		g_slist_free_full(batt->chars, g_free);
+		g_slist_free_full(batt->chars, char_interface_free);
 
 	if (batt->attioid > 0)
 		btd_device_remove_attio_callback(batt->dev, batt->attioid);
@@ -88,7 +116,10 @@ static void battery_free(gpointer user_data)
 	if (batt->attrib != NULL)
 		g_attrib_unref(batt->attrib);
 
+
+	dbus_connection_unref(batt->conn);
 	btd_device_unref(batt->dev);
+	g_free(batt->svc_range);
 	g_free(batt);
 }
 
@@ -140,6 +171,41 @@ static void process_batterylevel_desc(struct descriptor *desc)
 	DBG("Ignored descriptor %s characteristic %s", uuidstr,	ch->attr.uuid);
 }
 
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct characteristic *c = data;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(msg);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	dict_append_entry(&dict, "Namespace", DBUS_TYPE_BYTE, &c->ns);
+
+	dict_append_entry(&dict, "Description", DBUS_TYPE_UINT16,
+							&c->description);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
+static GDBusMethodTable battery_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+				NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+				get_properties) },
+	{ }
+};
 
 static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 							gpointer user_data)
@@ -185,10 +251,17 @@ update_char:
 				ch->ns,
 				ch->description);
 
-	device_add_battery(ch->batt->dev, ch->path);
+	if (!g_dbus_register_interface(ch->batt->conn, ch->path,
+				BATTERY_INTERFACE,
+				battery_methods, NULL, NULL,
+				ch, NULL)) {
+		error("D-Bus register interface %s failed",
+		      BATTERY_INTERFACE);
+	} else {
+		device_add_battery(ch->batt->dev, ch->path);
+	}
 }
 
-
 static void configure_battery_cb(GSList *characteristics, guint8 status,
 
 							gpointer user_data)
@@ -215,6 +288,7 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 			ch->attr.value_handle = c->value_handle;
 			memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
 			ch->batt = batt;
+
 			batt->chars = g_slist_append(batt->chars, ch);
 
 			start = c->value_handle + 1;
@@ -264,7 +338,7 @@ static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
 	return g_strcmp0(prim->uuid, uuid);
 }
 
-int battery_register(struct btd_device *device)
+int battery_register(DBusConnection *connection, struct btd_device *device)
 {
 	struct battery *batt;
 	struct gatt_primary *prim;
@@ -278,7 +352,7 @@ int battery_register(struct btd_device *device)
 
 	batt = g_new0(struct battery, 1);
 	batt->dev = btd_device_ref(device);
-
+	batt->conn = dbus_connection_ref(connection);
 	batt->svc_range = g_new0(struct att_range, 1);
 	batt->svc_range->start = prim->range.start;
 	batt->svc_range->end = prim->range.end;
@@ -288,6 +362,7 @@ int battery_register(struct btd_device *device)
 	batt->attioid = btd_device_add_attio_callback(device,
 				attio_connected_cb, attio_disconnected_cb,
 				batt);
+
 	return 0;
 }
 
diff --git a/profiles/battery/battery.h b/profiles/battery/battery.h
index 801186d..8231949 100644
--- a/profiles/battery/battery.h
+++ b/profiles/battery/battery.h
@@ -21,6 +21,6 @@
  */
 
 #define BATTERY_SERVICE_UUID		"0000180f-0000-1000-8000-00805f9b34fb"
+int battery_register(DBusConnection *conn, struct btd_device *device);
 
-int battery_register(struct btd_device *device);
 void battery_unregister(struct btd_device *device);
diff --git a/profiles/battery/main.c b/profiles/battery/main.c
index 47f4249..49c7249 100644
--- a/profiles/battery/main.c
+++ b/profiles/battery/main.c
@@ -25,7 +25,7 @@
 #endif
 
 #include <stdint.h>
-#include <glib.h>
+#include <gdbus.h>
 #include <errno.h>
 
 #include "hcid.h"
@@ -33,6 +33,8 @@
 #include "manager.h"
 #include "log.h"
 
+static DBusConnection *connection;
+
 static int battery_init(void)
 {
 	if (!main_opts.gatt_enabled) {
@@ -40,12 +42,24 @@ static int battery_init(void)
 		return -ENOTSUP;
 	}
 
-	return battery_manager_init();
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (connection == NULL)
+		return -EIO;
+
+	if (battery_manager_init(connection) < 0) {
+		dbus_connection_unref(connection);
+		return -EIO;
+	}
+
+	return 0;
 }
 
 static void battery_exit(void)
 {
 	battery_manager_exit();
+
+	dbus_connection_unref(connection);
+	connection = NULL;
 }
 
 BLUETOOTH_PLUGIN_DEFINE(battery, VERSION,
diff --git a/profiles/battery/manager.c b/profiles/battery/manager.c
index 22b8b20..13bc806 100644
--- a/profiles/battery/manager.c
+++ b/profiles/battery/manager.c
@@ -20,7 +20,7 @@
  *
  */
 
-#include <glib.h>
+#include <gdbus.h>
 #include <errno.h>
 #include <bluetooth/uuid.h>
 
@@ -32,9 +32,11 @@
 #include "battery.h"
 #include "manager.h"
 
+static DBusConnection *connection;
+
 static int battery_driver_probe(struct btd_device *device, GSList *uuids)
 {
-	return battery_register(device);
+	return battery_register(connection, device);
 }
 
 static void battery_driver_remove(struct btd_device *device)
@@ -49,12 +51,21 @@ static struct btd_device_driver battery_device_driver = {
 	.remove	= battery_driver_remove
 };
 
-int battery_manager_init(void)
+int battery_manager_init(DBusConnection *conn)
 {
-	return btd_register_device_driver(&battery_device_driver);
+	int ret;
+
+	ret = btd_register_device_driver(&battery_device_driver);
+	if (!ret)
+		connection = dbus_connection_ref(conn);
+
+	return ret;
 }
 
 void battery_manager_exit(void)
 {
 	btd_unregister_device_driver(&battery_device_driver);
+
+	dbus_connection_unref(connection);
+	connection = NULL;
 }
diff --git a/profiles/battery/manager.h b/profiles/battery/manager.h
index b2c849f..60acb1d 100644
--- a/profiles/battery/manager.h
+++ b/profiles/battery/manager.h
@@ -20,5 +20,5 @@
  *
  */
 
-int battery_manager_init(void);
+int battery_manager_init(DBusConnection *conn);
 void battery_manager_exit(void);
-- 
1.7.9.5


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

* [PATCH v3 7/9] Battery: Read Battery level characteristic
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
                   ` (5 preceding siblings ...)
  2012-08-08 14:26 ` [PATCH v3 6/9] Battery: Add Battery D-BUS API chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-08 14:26 ` [PATCH v3 8/9] Battery: Add support for notifications chen.ganir
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Add support for reading the battery level characteristic on
connection establishment.
---
 profiles/battery/battery.c |   45 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 2f616e0..467922b 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -62,6 +62,7 @@ struct characteristic {
 	GSList				*desc;	/* Descriptors */
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
+	uint8_t        level;
 };
 
 struct descriptor {
@@ -123,6 +124,40 @@ static void battery_free(gpointer user_data)
 	g_free(batt);
 }
 
+static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	uint8_t value[ATT_MAX_MTU];
+	int vlen;
+
+	if (status != 0) {
+		error("Failed to read Battery Level:%s", att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (!vlen) {
+		error("Failed to read Battery Level: Protocol error\n");
+		return;
+	}
+
+	if (vlen < 1) {
+		error("Failed to read Battery Level: Wrong pdu len");
+		return;
+	}
+
+	ch->level = value[0];
+}
+
+static void process_batteryservice_char(struct characteristic *ch)
+{
+	if (g_strcmp0(ch->attr.uuid, BATTERY_LEVEL_UUID) == 0) {
+		gatt_read_char(ch->batt->attrib, ch->attr.value_handle, 0,
+						read_batterylevel_cb, ch);
+	}
+}
+
 static void batterylevel_presentation_format_desc_cb(guint8 status,
 						const guint8 *pdu, guint16 len,
 						gpointer user_data)
@@ -195,6 +230,8 @@ static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
 	dict_append_entry(&dict, "Description", DBUS_TYPE_UINT16,
 							&c->description);
 
+	dict_append_entry(&dict, "Level", DBUS_TYPE_BYTE, &c->level);
+
 	dbus_message_iter_close_container(&iter, &dict);
 
 	return reply;
@@ -260,6 +297,8 @@ update_char:
 	} else {
 		device_add_battery(ch->batt->dev, ch->path);
 	}
+
+	process_batteryservice_char(ch);
 }
 
 static void configure_battery_cb(GSList *characteristics, guint8 status,
@@ -319,6 +358,12 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 		gatt_discover_char(batt->attrib, batt->svc_range->start,
 					batt->svc_range->end, NULL,
 					configure_battery_cb, batt);
+	} else {
+		GSList *l;
+		for (l = batt->chars; l; l = l->next) {
+			struct characteristic *c = l->data;
+			process_batteryservice_char(c);
+		}
 	}
 }
 
-- 
1.7.9.5


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

* [PATCH v3 8/9] Battery: Add support for notifications
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
                   ` (6 preceding siblings ...)
  2012-08-08 14:26 ` [PATCH v3 7/9] Battery: Read Battery level characteristic chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-08 14:26 ` [PATCH v3 9/9] Battery: Emit property changed on first read chen.ganir
  2012-08-15 13:50 ` [PATCH v3 0/9] Add GATT Client Battery Service Chen Ganir
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Add support for emitting PropertyChanged when a battery level
characteristic notification is sent from the peer device.
---
 doc/battery-api.txt        |    5 ++
 profiles/battery/battery.c |  112 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/doc/battery-api.txt b/doc/battery-api.txt
index f8c1e43..c40efc2 100644
--- a/doc/battery-api.txt
+++ b/doc/battery-api.txt
@@ -16,6 +16,11 @@ Methods	dict GetProperties()
 			Returns all properties for the interface. See the
 			Properties section for the available properties.
 
+Signals		PropertyChanged(string name, variant value)
+
+		This signal indicates a changed value of the given
+		property.
+
 Properties	byte Namespace [readonly]
 
 			Namespace value from the battery format characteristic
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 467922b..c5274bb 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -50,6 +50,7 @@ struct battery {
 	GAttrib			*attrib;	/* GATT connection */
 	guint			attioid;	/* Att watcher id */
 	struct att_range	*svc_range;	/* Battery range */
+	guint                   attnotid;       /* Att notifications id */
 	GSList			*chars;		/* Characteristics */
 };
 
@@ -63,6 +64,7 @@ struct characteristic {
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
 	uint8_t        level;
+	gboolean		canNotify;
 };
 
 struct descriptor {
@@ -104,6 +106,14 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const uint16_t *handle = b;
+
+	return ch->attr.value_handle - *handle;
+}
+
 static void battery_free(gpointer user_data)
 {
 	struct battery *batt = user_data;
@@ -117,6 +127,10 @@ static void battery_free(gpointer user_data)
 	if (batt->attrib != NULL)
 		g_attrib_unref(batt->attrib);
 
+	if (batt->attrib != NULL) {
+		g_attrib_unregister(batt->attrib, batt->attnotid);
+		g_attrib_unref(batt->attrib);
+	}
 
 	dbus_connection_unref(batt->conn);
 	btd_device_unref(batt->dev);
@@ -158,6 +172,18 @@ static void process_batteryservice_char(struct characteristic *ch)
 	}
 }
 
+static void batterylevel_enable_notify_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct characteristic *ch = (struct characteristic *)user_data;
+
+	if (status != 0) {
+		error("Could not enable batt level notification.");
+		ch->canNotify = FALSE;
+		process_batteryservice_char(ch);
+	}
+}
+
 static void batterylevel_presentation_format_desc_cb(guint8 status,
 						const guint8 *pdu, guint16 len,
 						gpointer user_data)
@@ -194,6 +220,21 @@ static void process_batterylevel_desc(struct descriptor *desc)
 	char uuidstr[MAX_LEN_UUID_STR];
 	bt_uuid_t btuuid;
 
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
+						BATTERY_LEVEL_UUID) == 0) {
+		uint8_t atval[2];
+		uint16_t val;
+
+		val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+
+		att_put_u16(val, atval);
+		gatt_write_char(ch->batt->attrib, desc->handle, atval, 2,
+					batterylevel_enable_notify_cb, ch);
+		return;
+	}
+
 	bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
 
 	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
@@ -244,6 +285,13 @@ static GDBusMethodTable battery_methods[] = {
 	{ }
 };
 
+static GDBusSignalTable battery_signals[] = {
+	{ GDBUS_SIGNAL("PropertyChanged",
+		GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+	{ }
+};
+
+
 static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 							gpointer user_data)
 {
@@ -290,7 +338,7 @@ update_char:
 
 	if (!g_dbus_register_interface(ch->batt->conn, ch->path,
 				BATTERY_INTERFACE,
-				battery_methods, NULL, NULL,
+				battery_methods, battery_signals, NULL,
 				ch, NULL)) {
 		error("D-Bus register interface %s failed",
 		      BATTERY_INTERFACE);
@@ -301,6 +349,12 @@ update_char:
 	process_batteryservice_char(ch);
 }
 
+static void emit_battery_level_changed(struct characteristic *c)
+{
+	emit_property_changed(c->batt->conn, c->path, BATTERY_INTERFACE,
+					"Level", DBUS_TYPE_BYTE, &c->level);
+}
+
 static void configure_battery_cb(GSList *characteristics, guint8 status,
 
 							gpointer user_data)
@@ -348,12 +402,63 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 	}
 }
 
+static void proc_batterylevel(struct characteristic *c, const uint8_t *pdu,
+						uint16_t len, gboolean final)
+{
+	uint8_t new_batt_level = 0;
+	gboolean changed = FALSE;
+
+	if (!pdu) {
+		error("Battery level notification: Invalid pdu length");
+		goto done;
+	}
+
+	new_batt_level = pdu[1];
+
+	if (new_batt_level != c->level)
+		changed = TRUE;
+
+	c->level = new_batt_level;
+
+done:
+	if (changed)
+		emit_battery_level_changed(c);
+}
+
+static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct battery *batt = user_data;
+	struct characteristic *ch;
+	uint16_t handle;
+	GSList *l;
+
+	if (len < 3) {
+		error("notif_handler: Bad pdu received");
+		return;
+	}
+
+	handle = att_get_u16(&pdu[1]);
+	l = g_slist_find_custom(batt->chars, &handle, cmp_char_val_handle);
+	if (l == NULL) {
+		error("notif_handler: Unexpected handle 0x%04x", handle);
+		return;
+	}
+
+	ch = l->data;
+	if (g_strcmp0(ch->attr.uuid, BATTERY_LEVEL_UUID) == 0) {
+		proc_batterylevel(ch, pdu, len, FALSE);
+	}
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct battery *batt = user_data;
 
 	batt->attrib = g_attrib_ref(attrib);
 
+	batt->attnotid = g_attrib_register(batt->attrib, ATT_OP_HANDLE_NOTIFY,
+						notif_handler, batt, NULL);
+
 	if (batt->chars == NULL) {
 		gatt_discover_char(batt->attrib, batt->svc_range->start,
 					batt->svc_range->end, NULL,
@@ -362,7 +467,8 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 		GSList *l;
 		for (l = batt->chars; l; l = l->next) {
 			struct characteristic *c = l->data;
-			process_batteryservice_char(c);
+			if (!c->canNotify)
+				process_batteryservice_char(c);
 		}
 	}
 }
@@ -371,6 +477,8 @@ static void attio_disconnected_cb(gpointer user_data)
 {
 	struct battery *batt = user_data;
 
+	g_attrib_unregister(batt->attrib, batt->attnotid);
+	batt->attnotid = 0;
 	g_attrib_unref(batt->attrib);
 	batt->attrib = NULL;
 }
-- 
1.7.9.5


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

* [PATCH v3 9/9] Battery: Emit property changed on first read
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
                   ` (7 preceding siblings ...)
  2012-08-08 14:26 ` [PATCH v3 8/9] Battery: Add support for notifications chen.ganir
@ 2012-08-08 14:26 ` chen.ganir
  2012-08-15 13:50 ` [PATCH v3 0/9] Add GATT Client Battery Service Chen Ganir
  9 siblings, 0 replies; 11+ messages in thread
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

From: Chen Ganir <chen.ganir@ti.com>

Emit battery level property changed upon connection, on first read.
---
 profiles/battery/battery.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index c5274bb..2874fb2 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -138,6 +138,12 @@ static void battery_free(gpointer user_data)
 	g_free(batt);
 }
 
+static void emit_battery_level_changed(struct characteristic *c)
+{
+	emit_property_changed(c->batt->conn, c->path, BATTERY_INTERFACE,
+					"Level", DBUS_TYPE_BYTE, &c->level);
+}
+
 static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
 							gpointer user_data)
 {
@@ -162,6 +168,7 @@ static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
 	}
 
 	ch->level = value[0];
+	emit_battery_level_changed(ch);
 }
 
 static void process_batteryservice_char(struct characteristic *ch)
@@ -349,12 +356,6 @@ update_char:
 	process_batteryservice_char(ch);
 }
 
-static void emit_battery_level_changed(struct characteristic *c)
-{
-	emit_property_changed(c->batt->conn, c->path, BATTERY_INTERFACE,
-					"Level", DBUS_TYPE_BYTE, &c->level);
-}
-
 static void configure_battery_cb(GSList *characteristics, guint8 status,
 
 							gpointer user_data)
-- 
1.7.9.5


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

* Re: [PATCH v3 0/9] Add GATT Client Battery Service
  2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
                   ` (8 preceding siblings ...)
  2012-08-08 14:26 ` [PATCH v3 9/9] Battery: Emit property changed on first read chen.ganir
@ 2012-08-15 13:50 ` Chen Ganir
  9 siblings, 0 replies; 11+ messages in thread
From: Chen Ganir @ 2012-08-15 13:50 UTC (permalink / raw)
  To: chen.ganir; +Cc: linux-bluetooth, jprvita

Ping ?

On 08/08/2012 05:26 PM, chen.ganir@ti.com wrote:
> From: Chen Ganir <chen.ganir@ti.com>
>
> Add suupport for LE GATT Client Battery Service.
>
> This plugin adds battery list to the btd_device, exposes DBUS API to list the
> device batteries, and allows querying for battery information. In addition this
> patch allows getting notifications for battery level changes.
>
> Look at doc/device-api.txt and doc/battery-api.txt for more information.
>
> This is version 3 of this patch set, rebased on top of the latest sources and
> fixes issues reported on the ML.
>
> Chen Ganir (9):
>    Battery: Add Battery Service GATT Client
>    Battery: Add connection logic
>    Battery: Discover Characteristic Descriptors
>    Battery: Get Battery ID
>    Battery: Add Battery list to btd_device
>    Battery: Add Battery D-BUS API
>    Battery: Read Battery level characteristic
>    Battery: Add support for notifications
>    Battery: Emit property changed on first read
>
>   Makefile.am                |   10 +-
>   doc/battery-api.txt        |   38 ++++
>   doc/device-api.txt         |    5 +
>   profiles/battery/battery.c |  536 ++++++++++++++++++++++++++++++++++++++++++++
>   profiles/battery/battery.h |   26 +++
>   profiles/battery/main.c    |   67 ++++++
>   profiles/battery/manager.c |   71 ++++++
>   profiles/battery/manager.h |   24 ++
>   src/device.c               |   65 ++++++
>   src/device.h               |    3 +
>   10 files changed, 843 insertions(+), 2 deletions(-)
>   create mode 100644 doc/battery-api.txt
>   create mode 100644 profiles/battery/battery.c
>   create mode 100644 profiles/battery/battery.h
>   create mode 100644 profiles/battery/main.c
>   create mode 100644 profiles/battery/manager.c
>   create mode 100644 profiles/battery/manager.h
>


-- 
BR,
Chen Ganir



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

end of thread, other threads:[~2012-08-15 13:50 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-08 14:26 [PATCH v3 0/9] Add GATT Client Battery Service chen.ganir
2012-08-08 14:26 ` [PATCH v3 1/9] Battery: Add Battery Service GATT Client chen.ganir
2012-08-08 14:26 ` [PATCH v3 2/9] Battery: Add connection logic chen.ganir
2012-08-08 14:26 ` [PATCH v3 3/9] Battery: Discover Characteristic Descriptors chen.ganir
2012-08-08 14:26 ` [PATCH v3 4/9] Battery: Get Battery ID chen.ganir
2012-08-08 14:26 ` [PATCH v3 5/9] Battery: Add Battery list to btd_device chen.ganir
2012-08-08 14:26 ` [PATCH v3 6/9] Battery: Add Battery D-BUS API chen.ganir
2012-08-08 14:26 ` [PATCH v3 7/9] Battery: Read Battery level characteristic chen.ganir
2012-08-08 14:26 ` [PATCH v3 8/9] Battery: Add support for notifications chen.ganir
2012-08-08 14:26 ` [PATCH v3 9/9] Battery: Emit property changed on first read chen.ganir
2012-08-15 13:50 ` [PATCH v3 0/9] Add GATT Client Battery Service Chen Ganir

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).