From: Chen Ganir <[email protected]>
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
Ping ?
On 08/08/2012 05:26 PM, [email protected] wrote:
> From: Chen Ganir <[email protected]>
>
> 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
From: Chen Ganir <[email protected]>
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
From: Chen Ganir <[email protected]>
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
From: Chen Ganir <[email protected]>
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
From: Chen Ganir <[email protected]>
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. <[email protected]>
+
+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
From: Chen Ganir <[email protected]>
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
From: Chen Ganir <[email protected]>
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
From: Chen Ganir <[email protected]>
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
From: Chen Ganir <[email protected]>
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
From: Chen Ganir <[email protected]>
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