* [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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ messages in thread
end of thread, other threads:[~2013-01-07 19:41 UTC | newest]
Thread overview: 10+ 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
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).