linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 7/9] Battery: Read Battery level characteristic
  2012-07-17 13:59 [PATCH 0/9] Add GATT Client Battery Service Chen Ganir
@ 2012-07-17 13:59 ` Chen Ganir
  0 siblings, 0 replies; 11+ messages in thread
From: Chen Ganir @ 2012-07-17 13:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Chen Ganir

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

diff --git a/profiles/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
index a1b9831..152dc67 100644
--- a/profiles/batterystate/batterystate.c
+++ b/profiles/batterystate/batterystate.c
@@ -124,6 +124,40 @@ static void batterystate_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)
@@ -291,6 +325,7 @@ static void configure_batterystate_cb(GSList *characteristics, guint8 status,
 				continue;
 			}
 
+			process_batteryservice_char(ch);
 			batt->chars = g_slist_append(batt->chars, ch);
 
 			start = c->value_handle + 1;
@@ -321,6 +356,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_batterystate_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 0/9] Battery Profile implementation
@ 2013-01-07 19:40 Paulo Borges
  2013-01-07 19:40 ` [PATCH 1/9] battery: Add generic device battery documentation Paulo Borges
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Paulo Borges

This patch series implements GATT Battery profile, and it is based on
the work of Chen Ganir.

Battery Profile is mandatory for HoG (HID over GATT).

What has been done upon the previous version:

* bugfixes
* new storage schema using key-files
* compliant with object manager

Although I've changed all commits in the series, I just took the
authorship of commits modified meaninfuly.

Chen Ganir (6):
  battery: Add GATT Battery Client Service skeleton
  battery: Discover Characteristic Descriptors
  battery: Get Battery ID
  battery: Add Battery to device
  battery: Read Battery level characteristic
  battery: Add support for notifications

Paulo Borges (3):
  battery: Add generic device battery documentation
  battery: Implement Generic device battery
  battery: Support persistent battery level

 Makefile.plugins           |    3 +
 doc/battery-api.txt        |   24 ++
 lib/uuid.h                 |    3 +
 profiles/battery/battery.c |  638 ++++++++++++++++++++++++++++++++++++++++++++
 src/device.c               |  140 ++++++++++
 src/device.h               |   15 ++
 test/test-device           |   15 ++
 7 files changed, 838 insertions(+)
 create mode 100644 doc/battery-api.txt
 create mode 100644 profiles/battery/battery.c

-- 
1.7.9.5


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

* [PATCH 1/9] battery: Add generic device battery documentation
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
@ 2013-01-07 19:40 ` Paulo Borges
  2013-01-07 19:40 ` [PATCH 2/9] battery: Implement Generic device battery Paulo Borges
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Paulo Borges

Add documentation for the generic battery D-Bus interface.
---
 doc/battery-api.txt |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 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..9267bbd
--- /dev/null
+++ b/doc/battery-api.txt
@@ -0,0 +1,24 @@
+BlueZ D-Bus Battery API description
+***********************************
+
+	Texas Instruments, Inc. <chen.ganir@ti.com>
+
+Device Battery hierarchy
+========================
+
+Service		org.bluez
+Interface	org.bluez.Battery1
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/BATTYYYY
+
+Methods		Refresh()
+
+			Refresh the battery level. If the battery level changed,
+			the Level signal will be sent with the new value.
+
+Properties	uint16 Level [readonly]
+
+			Battery level (0-100).
+
+		object Device [readonly]
+
+			Device object that owns the battery.
-- 
1.7.9.5


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

* [PATCH 2/9] battery: Implement Generic device battery
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
  2013-01-07 19:40 ` [PATCH 1/9] battery: Add generic device battery documentation Paulo Borges
@ 2013-01-07 19:40 ` Paulo Borges
  2013-01-07 19:40 ` [PATCH 3/9] battery: Add GATT Battery Client Service skeleton Paulo Borges
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Paulo Borges

Add implementation for the generic battery in bluetooth device.
This patch adds new D-Bus interface for adding/removing/changing
peer device battery status, allowing management of remote device
batteries.
---
 src/device.c     |  140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/device.h     |   15 ++++++
 test/test-device |   15 ++++++
 3 files changed, 170 insertions(+)

diff --git a/src/device.c b/src/device.c
index 20099e6..bbd0bbf 100644
--- a/src/device.c
+++ b/src/device.c
@@ -187,6 +187,7 @@ struct btd_device {
 	int8_t		rssi;
 
 	gint		ref;
+	GSList		*batteries;
 
 	GIOChannel	*att_io;
 	guint		cleanup_id;
@@ -331,6 +332,24 @@ static void store_device_info(struct btd_device *device)
 	device->store_id = g_idle_add(store_device_info_cb, device);
 }
 
+struct btd_battery {
+	uint16_t		level;
+	char			*path;
+	struct btd_device	*device;
+	refresh_battery_cb	refresh;
+};
+
+static void battery_free(gpointer user_data)
+{
+	struct btd_battery *b = user_data;
+
+	g_dbus_unregister_interface(btd_get_dbus_connection(), b->path,
+							BATTERY_INTERFACE);
+	btd_device_unref(b->device);
+	g_free(b->path);
+	g_free(b);
+}
+
 static void browse_request_free(struct browse_req *req)
 {
 	if (req->listener_id)
@@ -393,6 +412,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, battery_free);
 
 	attio_cleanup(device);
 
@@ -4111,3 +4131,123 @@ void btd_device_set_pnpid(struct btd_device *device, uint16_t source,
 
 	store_device_info(device);
 }
+
+static DBusMessage *refresh_batt_level(DBusConnection *conn,
+						  DBusMessage *msg, void *data)
+{
+	struct btd_battery *b = data;
+
+	if (!b->refresh)
+		return btd_error_not_supported(msg);
+
+	b->refresh(b);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static gboolean battery_property_get_level(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct btd_battery *batt = data;
+	uint16_t level = batt->level;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &level);
+
+	return TRUE;
+}
+
+static gboolean battery_property_get_device(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct btd_battery *batt = data;
+	const char *str = device_get_path(batt->device);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
+
+	return TRUE;
+}
+
+static GDBusMethodTable battery_methods[] = {
+	{ GDBUS_METHOD("Refresh",
+		NULL, NULL,
+		refresh_batt_level) },
+	{ }
+};
+
+static const GDBusPropertyTable battery_properties[] = {
+	{ "Level", "q",  battery_property_get_level },
+	{ "Device", "o", battery_property_get_device },
+	{ }
+};
+
+struct btd_battery *btd_device_add_battery(struct btd_device *device)
+{
+	struct btd_battery *batt;
+
+	batt = g_new0(struct btd_battery, 1);
+	batt->path = g_strdup_printf("%s/BATT%04X", device->path,
+					     g_slist_length(device->batteries));
+
+	if (!g_dbus_register_interface(btd_get_dbus_connection(), batt->path,
+			BATTERY_INTERFACE, battery_methods, NULL,
+			battery_properties, batt, NULL)) {
+		error("D-Bus register interface %s failed", BATTERY_INTERFACE);
+		g_free(batt->path);
+		g_free(batt);
+		return NULL;
+	}
+
+	batt->device = btd_device_ref(device);
+	device->batteries = g_slist_append(device->batteries, batt);
+
+	return batt;
+}
+
+void btd_device_remove_battery(struct btd_battery *batt)
+{
+	struct btd_device *dev = batt->device;
+
+	dev->batteries = g_slist_remove(dev->batteries, batt);
+
+	battery_free(batt);
+}
+
+gboolean btd_device_set_battery_opt(struct btd_battery *batt,
+						    battery_option_t opt1, ...)
+{
+	va_list args;
+	battery_option_t opt = opt1;
+	int level;
+
+	if (!batt)
+		return FALSE;
+
+	va_start(args, opt1);
+
+	while (opt != BATTERY_OPT_INVALID) {
+		switch (opt) {
+		case BATTERY_OPT_LEVEL:
+			level = va_arg(args, int);
+			if (level != batt->level) {
+				batt->level = level;
+				g_dbus_emit_property_changed(
+					btd_get_dbus_connection(),
+					batt->path, BATTERY_INTERFACE,
+					"Level");
+			}
+			break;
+		case BATTERY_OPT_REFRESH_FUNC:
+			batt->refresh = va_arg(args, refresh_battery_cb);
+			break;
+		default:
+			error("Unknown option %d", opt);
+			return FALSE;
+		}
+
+		opt = va_arg(args, int);
+	}
+
+	va_end(args);
+
+	return TRUE;
+}
diff --git a/src/device.h b/src/device.h
index ae70690..0f7babd 100644
--- a/src/device.h
+++ b/src/device.h
@@ -23,8 +23,18 @@
  */
 
 #define DEVICE_INTERFACE	"org.bluez.Device1"
+#define BATTERY_INTERFACE	"org.bluez.Battery1"
 
 struct btd_device;
+struct btd_battery;
+
+typedef void (*refresh_battery_cb) (struct btd_battery *batt);
+
+typedef enum {
+	BATTERY_OPT_INVALID = 0,
+	BATTERY_OPT_LEVEL,
+	BATTERY_OPT_REFRESH_FUNC,
+} battery_option_t;
 
 struct btd_device *device_create(struct btd_adapter *adapter,
 				const char *address, uint8_t bdaddr_type);
@@ -116,3 +126,8 @@ void device_profile_connected(struct btd_device *dev,
 					struct btd_profile *profile, int err);
 void device_profile_disconnected(struct btd_device *dev,
 					struct btd_profile *profile, int err);
+
+struct btd_battery *btd_device_add_battery(struct btd_device *device);
+void btd_device_remove_battery(struct btd_battery *batt);
+gboolean btd_device_set_battery_opt(struct btd_battery *batt,
+						    battery_option_t opt1, ...);
diff --git a/test/test-device b/test/test-device
index 3d7b852..ee144f1 100755
--- a/test/test-device
+++ b/test/test-device
@@ -27,6 +27,7 @@ if (len(args) < 1):
 	print("Usage: %s <command>" % (sys.argv[0]))
 	print("")
 	print("  list")
+	print("  batteries <address>")
 	print("  create <address>")
 	print("  remove <address|path>")
 	print("  connect <address> [profile]")
@@ -196,5 +197,19 @@ if (args[0] == "blocked"):
 			props.Set("org.bluez.Device1", "Blocked", value)
 	sys.exit(0)
 
+if (args[0] == "batteries"):
+	if (len(args) < 2):
+		print("Need address parameter")
+	else:
+		BATT_INTERFACE = "org.bluez.Battery1"
+		objs = bluezutils.get_managed_objects()
+		device = bluezutils.find_device(args[1], options.dev_id)
+		batteries = [path for path, ifaces in objs.iteritems()
+			if (lambda obj: obj and obj.get("Device") ==
+			device.object_path)(ifaces.get(BATT_INTERFACE))]
+		for batt in batteries:
+			print(batt)
+	sys.exit(0)
+
 print("Unknown command")
 sys.exit(1)
-- 
1.7.9.5


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

* [PATCH 3/9] battery: Add GATT Battery Client Service skeleton
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
  2013-01-07 19:40 ` [PATCH 1/9] battery: Add generic device battery documentation Paulo Borges
  2013-01-07 19:40 ` [PATCH 2/9] battery: Implement Generic device battery Paulo Borges
@ 2013-01-07 19:40 ` Paulo Borges
  2013-01-07 19:40 ` [PATCH 4/9] battery: Discover Characteristic Descriptors Paulo Borges
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Chen Ganir

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

Add support for the Battery Service Gatt Client side. Implement
the basic skeleton.
---
 Makefile.plugins           |    3 +
 lib/uuid.h                 |    2 +
 profiles/battery/battery.c |  214 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 219 insertions(+)
 create mode 100644 profiles/battery/battery.c

diff --git a/Makefile.plugins b/Makefile.plugins
index faab011..33694b1 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -79,6 +79,9 @@ builtin_sources += profiles/scanparam/scan.c
 builtin_modules += deviceinfo
 builtin_sources += profiles/deviceinfo/deviceinfo.c
 
+builtin_modules += battery
+builtin_sources += profiles/battery/battery.c
+
 if EXPERIMENTAL
 builtin_modules += alert
 builtin_sources += profiles/alert/server.c
diff --git a/lib/uuid.h b/lib/uuid.h
index 1e8188a..8736749 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -56,6 +56,8 @@ extern "C" {
 #define PNPID_UUID		"00002a50-0000-1000-8000-00805f9b34fb"
 #define DEVICE_INFORMATION_UUID	"0000180a-0000-1000-8000-00805f9b34fb"
 
+#define BATTERY_SERVICE_UUID	"0000180f-0000-1000-8000-00805f9b34fb"
+
 #define GATT_UUID		"00001801-0000-1000-8000-00805f9b34fb"
 #define IMMEDIATE_ALERT_UUID	"00001802-0000-1000-8000-00805f9b34fb"
 #define LINK_LOSS_UUID		"00001803-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
new file mode 100644
index 0000000..73c06ff
--- /dev/null
+++ b/profiles/battery/battery.c
@@ -0,0 +1,214 @@
+/*
+ *
+ *  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 <stdbool.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "plugin.h"
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attrib/gatt.h"
+#include "attio.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 */
+};
+
+struct characteristic {
+	struct gatt_char	attr;		/* Characteristic */
+	struct battery		*batt;		/* Parent Battery Service */
+};
+
+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;
+
+	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);
+}
+
+static int battery_register(struct btd_device *device)
+{
+	struct battery *batt;
+	struct gatt_primary *prim;
+	GSList *primaries, *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	while ((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);
+
+		primaries = g_slist_remove(primaries, prim);
+	}
+
+	return 0;
+}
+
+static void battery_unregister(struct btd_device *device)
+{
+	struct battery *batt;
+	GSList *l;
+
+	while ((l = g_slist_find_custom(servers, device, cmp_device))) {
+		batt = l->data;
+		servers = g_slist_remove(servers, batt);
+
+		battery_free(batt);
+	}
+}
+
+static int battery_driver_probe(struct btd_profile *p,
+						struct btd_device *device,
+						GSList *uuids)
+{
+	return battery_register(device);
+}
+
+static void battery_driver_remove(struct btd_profile *p,
+						struct btd_device *device)
+{
+	battery_unregister(device);
+}
+
+static struct btd_profile battery_profile = {
+	.name		= "battery",
+	.remote_uuids	= BTD_UUIDS(BATTERY_SERVICE_UUID),
+	.device_probe	= battery_driver_probe,
+	.device_remove	= battery_driver_remove
+};
+
+static int battery_manager_init(void)
+{
+	return btd_profile_register(&battery_profile);
+}
+
+static void battery_manager_exit(void)
+{
+	btd_profile_unregister(&battery_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(battery, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+				battery_manager_init, battery_manager_exit)
-- 
1.7.9.5


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

* [PATCH 4/9] battery: Discover Characteristic Descriptors
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
                   ` (2 preceding siblings ...)
  2013-01-07 19:40 ` [PATCH 3/9] battery: Add GATT Battery Client Service skeleton Paulo Borges
@ 2013-01-07 19:40 ` Paulo Borges
  2013-01-07 19:41 ` [PATCH 5/9] battery: Get Battery ID Paulo Borges
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Chen Ganir

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

Discover all characteristic descriptors, and build a descriptor
list. Presentation Format Descriptor and Client Characteristic
Configuration descriptors are searched.
---
 profiles/battery/battery.c |   72 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 73c06ff..8e7e4c5 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -49,6 +49,13 @@ struct battery {
 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 GSList *servers;
@@ -64,12 +71,21 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+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 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_free);
 
 	if (batt->attioid > 0)
 		btd_device_remove_attio_callback(batt->dev, batt->attioid);
@@ -78,9 +94,48 @@ static void battery_free(gpointer user_data)
 		g_attrib_unref(batt->attrib);
 
 	btd_device_unref(batt->dev);
+	g_free(batt->svc_range);
 	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)
 {
@@ -96,6 +151,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;
@@ -105,6 +161,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 5/9] battery: Get Battery ID
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
                   ` (3 preceding siblings ...)
  2013-01-07 19:40 ` [PATCH 4/9] battery: Discover Characteristic Descriptors Paulo Borges
@ 2013-01-07 19:41 ` Paulo Borges
  2013-01-07 19:41 ` [PATCH 6/9] battery: Add Battery to device Paulo Borges
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Chen Ganir

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

Read the battery level format characteristic descriptor to get the
unique namespace and description values.
---
 lib/uuid.h                 |    1 +
 profiles/battery/battery.c |   53 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 8736749..3abdd44 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -57,6 +57,7 @@ extern "C" {
 #define DEVICE_INFORMATION_UUID	"0000180a-0000-1000-8000-00805f9b34fb"
 
 #define BATTERY_SERVICE_UUID	"0000180f-0000-1000-8000-00805f9b34fb"
+#define BATTERY_LEVEL_UUID	"00002a19-0000-1000-8000-00805f9b34fb"
 
 #define GATT_UUID		"00001801-0000-1000-8000-00805f9b34fb"
 #define IMMEDIATE_ALERT_UUID	"00001802-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 8e7e4c5..8bbfaf7 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -50,6 +50,8 @@ struct characteristic {
 	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 {
@@ -98,6 +100,53 @@ 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_VALUE_LEN];
+	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 < 0) {
+		error("Presentation Format desc read failed: Protocol error");
+		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,
+				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)
 {
@@ -131,6 +180,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);
@@ -153,6 +203,9 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 		struct characteristic *ch;
 		uint16_t start, end;
 
+		if (g_strcmp0(c->uuid, BATTERY_LEVEL_UUID) != 0)
+			continue;
+
 		ch = g_new0(struct characteristic, 1);
 		ch->attr.handle = c->handle;
 		ch->attr.properties = c->properties;
-- 
1.7.9.5


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

* [PATCH 6/9] battery: Add Battery to device
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
                   ` (4 preceding siblings ...)
  2013-01-07 19:41 ` [PATCH 5/9] battery: Get Battery ID Paulo Borges
@ 2013-01-07 19:41 ` Paulo Borges
  2013-01-07 19:41 ` [PATCH 7/9] battery: Read Battery level characteristic Paulo Borges
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Chen Ganir

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

Add/Remove battery from device
---
 profiles/battery/battery.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 8bbfaf7..fef83d9 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -47,6 +47,7 @@ struct battery {
 };
 
 struct characteristic {
+	struct btd_battery	*devbatt;	/* device_battery pointer */
 	struct gatt_char	attr;		/* Characteristic */
 	struct battery		*batt;		/* Parent Battery Service */
 	GSList			*desc;		/* Descriptors */
@@ -79,6 +80,8 @@ static void char_free(gpointer user_data)
 
 	g_slist_free_full(c->desc, g_free);
 
+	btd_device_remove_battery(c->devbatt);
+
 	g_free(c);
 }
 
@@ -217,6 +220,8 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 
 		start = c->value_handle + 1;
 
+		ch->devbatt = btd_device_add_battery(ch->batt->dev);
+
 		if (l->next != NULL) {
 			struct gatt_char *c = l->next->data;
 			if (start == c->handle)
-- 
1.7.9.5


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

* [PATCH 7/9] battery: Read Battery level characteristic
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
                   ` (5 preceding siblings ...)
  2013-01-07 19:41 ` [PATCH 6/9] battery: Add Battery to device Paulo Borges
@ 2013-01-07 19:41 ` Paulo Borges
  2013-01-07 19:41 ` [PATCH 8/9] battery: Add support for notifications Paulo Borges
  2013-01-07 19:41 ` [PATCH 9/9] battery: Support persistent battery level Paulo Borges
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Chen Ganir

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

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

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index fef83d9..186bb1c 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -53,6 +53,7 @@ struct characteristic {
 	GSList			*desc;		/* Descriptors */
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
+	uint8_t			level;		/* Battery level */
 };
 
 struct descriptor {
@@ -103,6 +104,78 @@ 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_VALUE_LEN];
+	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 < 0) {
+		error("Failed to read Battery Level: Protocol error");
+		return;
+	}
+
+	if (vlen != 1) {
+		error("Failed to read Battery Level: Wrong pdu len");
+		return;
+	}
+
+	ch->level = value[0];
+	btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_LEVEL, ch->level,
+						BATTERY_OPT_INVALID);
+}
+
+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,
+						read_batterylevel_cb, ch);
+	}
+}
+
+static gint device_battery_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const struct btd_battery *batt = b;
+
+	if (batt == ch->devbatt)
+		return 0;
+
+	return -1;
+}
+
+static struct characteristic *find_battery_char(struct btd_battery *db)
+{
+	GSList *l, *b;
+
+	for (l = servers; l != NULL; l = g_slist_next(l)) {
+		struct battery *batt = l->data;
+
+		b = g_slist_find_custom(batt->chars, db, device_battery_cmp);
+		if (b && batt->attrib)
+			return b->data;
+	}
+
+	return NULL;
+}
+
+static void batterylevel_refresh_cb(struct btd_battery *batt)
+{
+	struct characteristic *ch;
+
+	ch = find_battery_char(batt);
+
+	if (ch)
+		process_batteryservice_char(ch);
+}
+
 static void batterylevel_presentation_format_desc_cb(guint8 status,
 						const guint8 *pdu, guint16 len,
 						gpointer user_data)
@@ -220,8 +293,15 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 
 		start = c->value_handle + 1;
 
+		process_batteryservice_char(ch);
+
 		ch->devbatt = btd_device_add_battery(ch->batt->dev);
 
+		btd_device_set_battery_opt(ch->devbatt,
+						   BATTERY_OPT_REFRESH_FUNC,
+						   batterylevel_refresh_cb,
+						   BATTERY_OPT_INVALID);
+
 		if (l->next != NULL) {
 			struct gatt_char *c = l->next->data;
 			if (start == c->handle)
@@ -246,6 +326,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 8/9] battery: Add support for notifications
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
                   ` (6 preceding siblings ...)
  2013-01-07 19:41 ` [PATCH 7/9] battery: Read Battery level characteristic Paulo Borges
@ 2013-01-07 19:41 ` Paulo Borges
  2013-01-07 19:41 ` [PATCH 9/9] battery: Support persistent battery level Paulo Borges
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: 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.
---
 profiles/battery/battery.c |   79 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 78 insertions(+), 1 deletion(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 186bb1c..2ef4f6b 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -54,6 +54,8 @@ struct characteristic {
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
 	uint8_t			level;		/* Battery level */
+	gboolean		can_notify;	/* Char can notify flag */
+	guint			notifyid;
 };
 
 struct descriptor {
@@ -79,6 +81,9 @@ static void char_free(gpointer user_data)
 {
 	struct characteristic *c = user_data;
 
+	if (c->notifyid && c->batt->attrib != NULL)
+		g_attrib_unregister(c->batt->attrib, c->notifyid);
+
 	g_slist_free_full(c->desc, g_free);
 
 	btd_device_remove_battery(c->devbatt);
@@ -140,6 +145,44 @@ static void process_batteryservice_char(struct characteristic *ch)
 	}
 }
 
+static void proc_batterylevel(struct characteristic *c, const uint8_t *pdu,
+						uint16_t len, gboolean final)
+{
+	if (!pdu) {
+		error("Battery level notification: Invalid pdu length");
+		return;
+	}
+
+	c->level = pdu[1];
+
+	btd_device_set_battery_opt(c->devbatt, BATTERY_OPT_LEVEL, c->level,
+							BATTERY_OPT_INVALID);
+}
+
+static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+
+	proc_batterylevel(ch, pdu, len, FALSE);
+}
+
+static void batterylevel_enable_notify_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct battery *batt = ch->batt;
+
+	if (status != 0) {
+		error("Could not enable batt level notification.");
+		ch->can_notify = FALSE;
+		process_batteryservice_char(ch);
+	}
+
+	ch->notifyid = g_attrib_register(batt->attrib,
+				ATT_OP_HANDLE_NOTIFY, ch->attr.value_handle,
+				notif_handler, ch, NULL);
+}
+
 static gint device_battery_cmp(gconstpointer a, gconstpointer b)
 {
 	const struct characteristic *ch = a;
@@ -176,6 +219,21 @@ static void batterylevel_refresh_cb(struct btd_battery *batt)
 		process_batteryservice_char(ch);
 }
 
+static void enable_battery_notification(struct characteristic *ch,
+								uint16_t handle)
+{
+	uint8_t atval[2];
+	uint16_t val;
+
+	val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+
+	ch->can_notify = TRUE;
+
+	att_put_u16(val, atval);
+	gatt_write_char(ch->batt->attrib, handle, atval, 2,
+				batterylevel_enable_notify_cb, ch);
+}
+
 static void batterylevel_presentation_format_desc_cb(guint8 status,
 						const guint8 *pdu, guint16 len,
 						gpointer user_data)
@@ -211,6 +269,14 @@ 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) {
+		enable_battery_notification(ch, desc->handle);
+		return;
+	}
+
 	bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
 
 	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
@@ -330,7 +396,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->can_notify)
+				process_batteryservice_char(c);
 		}
 	}
 }
@@ -338,6 +405,16 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 static void attio_disconnected_cb(gpointer user_data)
 {
 	struct battery *batt = user_data;
+	GSList *l;
+
+	for (l = batt->chars; l; l = l->next) {
+		struct characteristic *c = l->data;
+
+		if (c->notifyid) {
+			g_attrib_unregister(batt->attrib, c->notifyid);
+			c->notifyid = 0;
+		}
+	}
 
 	g_attrib_unref(batt->attrib);
 	batt->attrib = NULL;
-- 
1.7.9.5


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

* [PATCH 9/9] battery: Support persistent battery level
  2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
                   ` (7 preceding siblings ...)
  2013-01-07 19:41 ` [PATCH 8/9] battery: Add support for notifications Paulo Borges
@ 2013-01-07 19:41 ` Paulo Borges
  8 siblings, 0 replies; 11+ messages in thread
From: Paulo Borges @ 2013-01-07 19:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Paulo Borges

Store battery level when read, and use the level from storage
when connecting, to reduce GATT traffic.
---
 profiles/battery/battery.c |  137 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 135 insertions(+), 2 deletions(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 2ef4f6b..e4a6e53 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -27,6 +27,8 @@
 #include <glib.h>
 #include <bluetooth/uuid.h>
 #include <stdbool.h>
+#include <sys/file.h>
+#include <stdlib.h>
 
 #include "adapter.h"
 #include "device.h"
@@ -37,6 +39,11 @@
 #include "attrib/gatt.h"
 #include "attio.h"
 #include "log.h"
+#include "storage.h"
+
+#define BATTERY_FILE		"batteries"
+#define BATTERY_GROUP_FORMAT	"%04X"
+#define BATTERY_KEY_LEVEL	"Level"
 
 struct battery {
 	struct btd_device	*dev;		/* Device reference */
@@ -77,10 +84,133 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gboolean store_battery_char(struct characteristic *chr)
+{
+	GKeyFile *key_file;
+	char filename[PATH_MAX + 1];
+	char adapter_addr[18];
+	char device_addr[18];
+	char group[5];
+	char *str;
+	gsize length = 0;
+
+	ba2str(adapter_get_address(device_get_adapter(chr->batt->dev)),
+								adapter_addr);
+	ba2str(device_get_address(chr->batt->dev), device_addr);
+
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/" BATTERY_FILE,
+						adapter_addr, device_addr);
+
+	snprintf(group, sizeof(group), BATTERY_GROUP_FORMAT, chr->attr.handle);
+
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+	g_key_file_set_integer(key_file, group, BATTERY_KEY_LEVEL, chr->level);
+
+	create_file(filename, S_IRUSR | S_IWUSR);
+
+	str = g_key_file_to_data(key_file, &length, NULL);
+	g_file_set_contents(filename, str, length, NULL);
+
+	g_free(str);
+	g_key_file_free(key_file);
+
+	return TRUE;
+}
+
+static int read_battery_char(struct characteristic *chr)
+{
+	GKeyFile *key_file;
+	char filename[PATH_MAX + 1];
+	char adapter_addr[18];
+	char device_addr[18];
+	char group[5];
+	int chr_value;
+
+	ba2str(adapter_get_address(device_get_adapter(chr->batt->dev)),
+								adapter_addr);
+	ba2str(device_get_address(chr->batt->dev), device_addr);
+
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/" BATTERY_FILE,
+						adapter_addr, device_addr);
+
+	snprintf(group, sizeof(group), BATTERY_GROUP_FORMAT, chr->attr.handle);
+
+	key_file = g_key_file_new();
+	if (!g_key_file_load_from_file(key_file, filename, 0, NULL)) {
+		g_key_file_free(key_file);
+		return 0;
+	}
+
+	chr_value = g_key_file_get_integer(key_file, group, BATTERY_KEY_LEVEL,
+									NULL);
+	g_key_file_free(key_file);
+
+	return chr_value;
+}
+
+static void del_battery_char(struct characteristic *chr)
+{
+	GKeyFile *key_file;
+	char filename[PATH_MAX + 1];
+	char adapter_addr[18];
+	char device_addr[18];
+	char group[5];
+	char *str;
+	gsize length = 0;
+
+	ba2str(adapter_get_address(device_get_adapter(chr->batt->dev)),
+								adapter_addr);
+	ba2str(device_get_address(chr->batt->dev), device_addr);
+
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/" BATTERY_FILE,
+						adapter_addr, device_addr);
+
+	snprintf(group, sizeof(group), BATTERY_GROUP_FORMAT, chr->attr.handle);
+
+	key_file = g_key_file_new();
+	if (!g_key_file_load_from_file(key_file, filename, 0, NULL)) {
+		g_key_file_free(key_file);
+		return;
+	}
+
+	g_key_file_remove_key(key_file, group, BATTERY_KEY_LEVEL, NULL);
+
+	create_file(filename, S_IRUSR | S_IWUSR);
+
+	str = g_key_file_to_data(key_file, &length, NULL);
+	g_file_set_contents(filename, str, length, NULL);
+
+	g_free(str);
+	g_key_file_free(key_file);
+}
+
+static gboolean read_battery_level_value(struct characteristic *chr)
+{
+	int level;
+
+	if (!chr)
+		return FALSE;
+
+	level = read_battery_char(chr);
+	if (!level)
+		return FALSE;
+
+	chr->level = level;
+
+	btd_device_set_battery_opt(chr->devbatt, BATTERY_OPT_LEVEL, chr->level,
+						BATTERY_OPT_INVALID);
+
+	return TRUE;
+}
+
 static void char_free(gpointer user_data)
 {
 	struct characteristic *c = user_data;
 
+	del_battery_char(c);
+
 	if (c->notifyid && c->batt->attrib != NULL)
 		g_attrib_unregister(c->batt->attrib, c->notifyid);
 
@@ -135,6 +265,8 @@ static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
 	ch->level = value[0];
 	btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_LEVEL, ch->level,
 						BATTERY_OPT_INVALID);
+
+	store_battery_char(ch);
 }
 
 static void process_batteryservice_char(struct characteristic *ch)
@@ -359,7 +491,8 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 
 		start = c->value_handle + 1;
 
-		process_batteryservice_char(ch);
+		if (!read_battery_level_value(ch))
+			process_batteryservice_char(ch);
 
 		ch->devbatt = btd_device_add_battery(ch->batt->dev);
 
@@ -396,7 +529,7 @@ 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;
-			if (!c->can_notify)
+			if (!read_battery_level_value(c) && !c->can_notify)
 				process_batteryservice_char(c);
 		}
 	}
-- 
1.7.9.5


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

end of thread, other threads:[~2013-01-07 19:41 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
2013-01-07 19:40 ` [PATCH 1/9] battery: Add generic device battery documentation Paulo Borges
2013-01-07 19:40 ` [PATCH 2/9] battery: Implement Generic device battery Paulo Borges
2013-01-07 19:40 ` [PATCH 3/9] battery: Add GATT Battery Client Service skeleton Paulo Borges
2013-01-07 19:40 ` [PATCH 4/9] battery: Discover Characteristic Descriptors Paulo Borges
2013-01-07 19:41 ` [PATCH 5/9] battery: Get Battery ID Paulo Borges
2013-01-07 19:41 ` [PATCH 6/9] battery: Add Battery to device Paulo Borges
2013-01-07 19:41 ` [PATCH 7/9] battery: Read Battery level characteristic Paulo Borges
2013-01-07 19:41 ` [PATCH 8/9] battery: Add support for notifications Paulo Borges
2013-01-07 19:41 ` [PATCH 9/9] battery: Support persistent battery level Paulo Borges
  -- strict thread matches above, loose matches on Subject: below --
2012-07-17 13:59 [PATCH 0/9] Add GATT Client Battery Service Chen Ganir
2012-07-17 13:59 ` [PATCH 7/9] Battery: Read Battery level characteristic 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).