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 patch set is based on a patch set sent a few weeks ago, and it is now
rebased on top of the latest sources, and fixes some issues found during
testing.
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/batterystate/batterystate.c | 518 ++++++++++++++++++++++++++++++++++
profiles/batterystate/batterystate.h | 24 ++
profiles/batterystate/main.c | 67 +++++
profiles/batterystate/manager.c | 93 ++++++
profiles/batterystate/manager.h | 24 ++
src/device.c | 66 +++++
src/device.h | 3 +
10 files changed, 846 insertions(+), 2 deletions(-)
create mode 100644 doc/battery-api.txt
create mode 100644 profiles/batterystate/batterystate.c
create mode 100644 profiles/batterystate/batterystate.h
create mode 100644 profiles/batterystate/main.c
create mode 100644 profiles/batterystate/manager.c
create mode 100644 profiles/batterystate/manager.h
--
1.7.9.5
On 07/23/2012 11:08 PM, Claudio Takahasi wrote:
> Hi Chen Ganir:
>
> On Tue, Jul 17, 2012 at 10:59 AM, Chen Ganir <[email protected]> wrote:
>> Discover all characteristic descriptors, and build a descriptor
>> list
>> ---
>> profiles/batterystate/batterystate.c | 70 ++++++++++++++++++++++++++++++++++
>> 1 file changed, 70 insertions(+)
>>
>> diff --git a/profiles/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
>> index 40663f6..18045ed 100644
>> --- a/profiles/batterystate/batterystate.c
>> +++ b/profiles/batterystate/batterystate.c
>> @@ -50,8 +50,24 @@ 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 void char_free(gpointer user_data)
>> +{
>> + struct characteristic *c = user_data;
>> +
>> + g_slist_free_full(c->desc, g_free);
>> +
>> + g_free(c);
>> +}
>
> Please fix the following warning:
>
> profiles/batterystate/batterystate.c:62:13: error: 'char_free' defined
> but not used [-Werror=unused-function]
> cc1: all warnings being treated as errors
>
I'll do that.
Anything else for this patch set ?
> BR,
> Claudio
>
Thanks,
Chen Ganir.
--
*Chen Ganir***| Texas Instruments | *SW Engineer* Mobile Connectivity
Solutions| Direct: (972)-9-7906080 | Mobile: (972)-52-2438-406|Zarhin
26,Ra'anana, Israel |http://www.ti.com <http://www.ti.com/>
| [email protected] <mailto:[email protected]>
Hi Chen Ganir:
On Tue, Jul 17, 2012 at 10:59 AM, Chen Ganir <[email protected]> wrote:
> Discover all characteristic descriptors, and build a descriptor
> list
> ---
> profiles/batterystate/batterystate.c | 70 ++++++++++++++++++++++++++++++++++
> 1 file changed, 70 insertions(+)
>
> diff --git a/profiles/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
> index 40663f6..18045ed 100644
> --- a/profiles/batterystate/batterystate.c
> +++ b/profiles/batterystate/batterystate.c
> @@ -50,8 +50,24 @@ 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 void char_free(gpointer user_data)
> +{
> + struct characteristic *c = user_data;
> +
> + g_slist_free_full(c->desc, g_free);
> +
> + g_free(c);
> +}
Please fix the following warning:
profiles/batterystate/batterystate.c:62:13: error: 'char_free' defined
but not used [-Werror=unused-function]
cc1: all warnings being treated as errors
BR,
Claudio
Add Battery level specific API
---
doc/battery-api.txt | 33 ++++++++++++++
profiles/batterystate/batterystate.c | 80 +++++++++++++++++++++++++++++++---
profiles/batterystate/batterystate.h | 3 +-
profiles/batterystate/main.c | 18 +++++++-
profiles/batterystate/manager.c | 19 ++++++--
profiles/batterystate/manager.h | 2 +-
6 files changed, 142 insertions(+), 13 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..5d7510d
--- /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,hci1,...}/dev_XX_XX_XX_XX_XX_XX/BATTYYYY
+
+
+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/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
index ab6ee53..a1b9831 100644
--- a/profiles/batterystate/batterystate.c
+++ b/profiles/batterystate/batterystate.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 "batterystate.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 */
@@ -71,9 +77,22 @@ static void char_free(gpointer user_data)
g_slist_free_full(c->desc, g_free);
+ g_free(c->path);
+
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);
+
+ char_free(c);
+}
+
static gint cmp_device(gconstpointer a, gconstpointer b)
{
const struct battery *batt = a;
@@ -90,7 +109,7 @@ static void batterystate_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);
@@ -98,7 +117,10 @@ static void batterystate_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);
}
@@ -190,6 +212,44 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
att_data_list_free(list);
}
+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);
+
+ dict_append_entry(&dict, "Level", DBUS_TYPE_BYTE, &c->level);
+
+ 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 configure_batterystate_cb(GSList *characteristics, guint8 status,
gpointer user_data)
@@ -222,6 +282,15 @@ static void configure_batterystate_cb(GSList *characteristics, guint8 status,
device_add_battery(batt->dev, ch->path);
+ if (!g_dbus_register_interface(batt->conn, ch->path,
+ BATTERY_INTERFACE,
+ battery_methods, NULL, NULL,
+ ch, NULL)) {
+ error("D-Bus register interface %s failed",
+ BATTERY_INTERFACE);
+ continue;
+ }
+
batt->chars = g_slist_append(batt->chars, ch);
start = c->value_handle + 1;
@@ -263,14 +332,14 @@ static void attio_disconnected_cb(gpointer user_data)
batt->attrib = NULL;
}
-int batterystate_register(struct btd_device *device,
- struct gatt_primary *prim)
+int batterystate_register(DBusConnection *connection, struct btd_device *device,
+ struct gatt_primary *prim)
{
struct battery *batt;
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;
@@ -280,6 +349,7 @@ int batterystate_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/batterystate/batterystate.h b/profiles/batterystate/batterystate.h
index 2d30028..63b55bc 100644
--- a/profiles/batterystate/batterystate.h
+++ b/profiles/batterystate/batterystate.h
@@ -19,5 +19,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
-int batterystate_register(struct btd_device *device, struct gatt_primary *prim);
+int batterystate_register(DBusConnection *conn, struct btd_device *device,
+ struct gatt_primary *prim);
void batterystate_unregister(struct btd_device *device);
diff --git a/profiles/batterystate/main.c b/profiles/batterystate/main.c
index 360254b..a41952d 100644
--- a/profiles/batterystate/main.c
+++ b/profiles/batterystate/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 batterystate_init(void)
{
if (!main_opts.gatt_enabled) {
@@ -40,12 +42,24 @@ static int batterystate_init(void)
return -ENOTSUP;
}
- return batterystate_manager_init();
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL)
+ return -EIO;
+
+ if (batterystate_manager_init(connection) < 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ return 0;
}
static void batterystate_exit(void)
{
batterystate_manager_exit();
+
+ dbus_connection_unref(connection);
+ connection = NULL;
}
BLUETOOTH_PLUGIN_DEFINE(batterystate, VERSION,
diff --git a/profiles/batterystate/manager.c b/profiles/batterystate/manager.c
index 62076ac..5e52b16 100644
--- a/profiles/batterystate/manager.c
+++ b/profiles/batterystate/manager.c
@@ -20,7 +20,7 @@
*
*/
-#include <glib.h>
+#include <gdbus.h>
#include <errno.h>
#include <bluetooth/uuid.h>
@@ -34,6 +34,8 @@
#define BATTERY_SERVICE_UUID "0000180f-0000-1000-8000-00805f9b34fb"
+static DBusConnection *connection;
+
static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
{
const struct gatt_primary *prim = a;
@@ -56,7 +58,7 @@ static int batterystate_driver_probe(struct btd_device *device, GSList *uuids)
prim = l->data;
- return batterystate_register(device, prim);
+ return batterystate_register(connection, device, prim);
}
static void batterystate_driver_remove(struct btd_device *device)
@@ -71,12 +73,21 @@ static struct btd_device_driver battery_device_driver = {
.remove = batterystate_driver_remove
};
-int batterystate_manager_init(void)
+int batterystate_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 batterystate_manager_exit(void)
{
btd_unregister_device_driver(&battery_device_driver);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
}
diff --git a/profiles/batterystate/manager.h b/profiles/batterystate/manager.h
index 7f0bf15..9f99e70 100644
--- a/profiles/batterystate/manager.h
+++ b/profiles/batterystate/manager.h
@@ -20,5 +20,5 @@
*
*/
-int batterystate_manager_init(void);
+int batterystate_manager_init(DBusConnection *conn);
void batterystate_manager_exit(void);
--
1.7.9.5
Add peer battery list to the btd_device. New property added to Device
called Batteries.
---
doc/device-api.txt | 5 +++
profiles/batterystate/batterystate.c | 6 ++++
src/device.c | 66 ++++++++++++++++++++++++++++++++++
src/device.h | 3 ++
4 files changed, 80 insertions(+)
diff --git a/doc/device-api.txt b/doc/device-api.txt
index 0f34210..f8b1584 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -213,3 +213,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/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
index 49e0bc7..ab6ee53 100644
--- a/profiles/batterystate/batterystate.c
+++ b/profiles/batterystate/batterystate.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 */
@@ -215,6 +216,11 @@ static void configure_batterystate_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;
+ ch->path = g_strdup_printf("%s/BATT%04X",
+ device_get_path(batt->dev),
+ c->handle);
+
+ device_add_battery(batt->dev, ch->path);
batt->chars = g_slist_append(batt->chars, ch);
diff --git a/src/device.c b/src/device.c
index 09518f3..6ba8522 100644
--- a/src/device.c
+++ b/src/device.c
@@ -126,6 +126,10 @@ struct att_callbacks {
gpointer user_data;
};
+struct btd_battery {
+ char *path;
+};
+
struct btd_device {
bdaddr_t bdaddr;
uint8_t bdaddr_type;
@@ -171,6 +175,7 @@ struct btd_device {
GIOChannel *att_io;
guint cleanup_id;
+ GSList *batteries;
};
static uint16_t uuid_list[] = {
@@ -261,6 +266,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);
att_cleanup(device);
@@ -432,6 +438,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;
@@ -1218,6 +1233,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);
@@ -3163,3 +3181,51 @@ 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);
+ return;
+ }
+ }
+
+ batteries_changed(device);
+}
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
Add support for emitting PropertyChanged when a battery level
characteristic notification is sent from the peer device.
---
doc/battery-api.txt | 5 ++
profiles/batterystate/batterystate.c | 107 +++++++++++++++++++++++++++++++++-
2 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/doc/battery-api.txt b/doc/battery-api.txt
index 5d7510d..f31e7e5 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/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
index 152dc67..cbb5d5e 100644
--- a/profiles/batterystate/batterystate.c
+++ b/profiles/batterystate/batterystate.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 */
};
@@ -104,6 +105,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 batterystate_free(gpointer user_data)
{
struct battery *batt = user_data;
@@ -117,6 +126,10 @@ static void batterystate_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 +171,17 @@ static void process_batteryservice_char(struct characteristic *ch)
}
}
+static void batterylevel_enable_notify_cb(guint8 status, const guint8 *pdu,
+ guint16 len, gpointer user_data)
+{
+ char *msg = user_data;
+
+ if (status != 0)
+ error("Could not enable battery level notification: %s", msg);
+
+ g_free(msg);
+}
+
static void batterylevel_presentation_format_desc_cb(guint8 status,
const guint8 *pdu, guint16 len,
gpointer user_data)
@@ -194,6 +218,23 @@ 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;
+ char *msg;
+
+ val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+ msg = g_strdup("Enable BatteryLevel notification");
+
+ att_put_u16(val, atval);
+ gatt_write_char(ch->batt->attrib, desc->handle, atval, 2,
+ batterylevel_enable_notify_cb, msg);
+ return;
+ }
+
bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
@@ -277,6 +318,12 @@ static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
return reply;
}
+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 GDBusMethodTable battery_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
@@ -284,6 +331,11 @@ static GDBusMethodTable battery_methods[] = {
{ }
};
+static GDBusSignalTable battery_signals[] = {
+ { GDBUS_SIGNAL("PropertyChanged",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+ { }
+};
static void configure_batterystate_cb(GSList *characteristics, guint8 status,
gpointer user_data)
@@ -318,7 +370,7 @@ static void configure_batterystate_cb(GSList *characteristics, guint8 status,
if (!g_dbus_register_interface(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);
@@ -346,12 +398,63 @@ static void configure_batterystate_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,
@@ -369,6 +472,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
Emit battery level property changed upon connection, on first read.
---
profiles/batterystate/batterystate.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/profiles/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
index cbb5d5e..2349875 100644
--- a/profiles/batterystate/batterystate.c
+++ b/profiles/batterystate/batterystate.c
@@ -72,6 +72,8 @@ struct descriptor {
bt_uuid_t uuid; /* UUID */
};
+static void emit_battery_level_changed(struct characteristic *c);
+
static void char_free(gpointer user_data)
{
struct characteristic *c = user_data;
@@ -161,6 +163,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)
--
1.7.9.5
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
Read the battery level format characteristic descriptor to get the
unique namespace and description values.
---
profiles/batterystate/batterystate.c | 113 ++++++++++++++++++++++++++--------
1 file changed, 86 insertions(+), 27 deletions(-)
diff --git a/profiles/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
index 18045ed..49e0bc7 100644
--- a/profiles/batterystate/batterystate.c
+++ b/profiles/batterystate/batterystate.c
@@ -37,6 +37,8 @@
#include "batterystate.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,18 @@ 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 */
+ uint8_t level; /* Battery last known level */
};
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 void char_free(gpointer user_data)
@@ -96,6 +101,55 @@ static void batterystate_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)
{
@@ -129,6 +183,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);
@@ -149,31 +204,35 @@ static void configure_batterystate_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
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/batterystate/batterystate.c | 78 +++++++++++++++++++++++++++++++++-
profiles/batterystate/batterystate.h | 3 +-
profiles/batterystate/manager.c | 22 +++++++++-
3 files changed, 99 insertions(+), 4 deletions(-)
diff --git a/profiles/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
index 04c2e5e..40663f6 100644
--- a/profiles/batterystate/batterystate.c
+++ b/profiles/batterystate/batterystate.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 "batterystate.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,84 @@ static void batterystate_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_batterystate_cb(GSList *characteristics, guint8 status,
+ gpointer user_data)
+{
+ struct battery *batt = user_data;
+ GSList *l;
+
+ if (status != 0) {
+ error("Discover batterystate characteristics: %s",
+ att_ecode2str(status));
+ return;
+ }
-int batterystate_register(struct btd_device *device)
+ 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_batterystate_cb, batt);
+ }
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+ struct battery *batt = user_data;
+
+ g_attrib_unref(batt->attrib);
+ batt->attrib = NULL;
+}
+
+int batterystate_register(struct btd_device *device,
+ struct gatt_primary *prim)
{
struct battery *batt;
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/batterystate/batterystate.h b/profiles/batterystate/batterystate.h
index 9aedae7..2d30028 100644
--- a/profiles/batterystate/batterystate.h
+++ b/profiles/batterystate/batterystate.h
@@ -19,6 +19,5 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
-
-int batterystate_register(struct btd_device *device);
+int batterystate_register(struct btd_device *device, struct gatt_primary *prim);
void batterystate_unregister(struct btd_device *device);
diff --git a/profiles/batterystate/manager.c b/profiles/batterystate/manager.c
index 6718acf..62076ac 100644
--- a/profiles/batterystate/manager.c
+++ b/profiles/batterystate/manager.c
@@ -34,9 +34,29 @@
#define BATTERY_SERVICE_UUID "0000180f-0000-1000-8000-00805f9b34fb"
+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 batterystate_driver_probe(struct btd_device *device, GSList *uuids)
{
- return batterystate_register(device);
+ 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);
+ if (l == NULL)
+ return -EINVAL;
+
+ prim = l->data;
+
+ return batterystate_register(device, prim);
}
static void batterystate_driver_remove(struct btd_device *device)
--
1.7.9.5
Discover all characteristic descriptors, and build a descriptor
list
---
profiles/batterystate/batterystate.c | 70 ++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/profiles/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
index 40663f6..18045ed 100644
--- a/profiles/batterystate/batterystate.c
+++ b/profiles/batterystate/batterystate.c
@@ -50,8 +50,24 @@ 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 void char_free(gpointer user_data)
+{
+ struct characteristic *c = user_data;
+
+ g_slist_free_full(c->desc, g_free);
+
+ g_free(c);
+}
+
static gint cmp_device(gconstpointer a, gconstpointer b)
{
const struct battery *batt = a;
@@ -80,6 +96,45 @@ static void batterystate_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_batterystate_cb(GSList *characteristics, guint8 status,
gpointer user_data)
{
@@ -95,6 +150,7 @@ static void configure_batterystate_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 +160,20 @@ static void configure_batterystate_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
Add support for the Battery Service Gatt Client side.
---
Makefile.am | 10 +++-
profiles/batterystate/batterystate.c | 88 ++++++++++++++++++++++++++++++++++
profiles/batterystate/batterystate.h | 24 ++++++++++
profiles/batterystate/main.c | 53 ++++++++++++++++++++
profiles/batterystate/manager.c | 62 ++++++++++++++++++++++++
profiles/batterystate/manager.h | 24 ++++++++++
6 files changed, 259 insertions(+), 2 deletions(-)
create mode 100644 profiles/batterystate/batterystate.c
create mode 100644 profiles/batterystate/batterystate.h
create mode 100644 profiles/batterystate/main.c
create mode 100644 profiles/batterystate/manager.c
create mode 100644 profiles/batterystate/manager.h
diff --git a/Makefile.am b/Makefile.am
index 45a811c..e698718 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 \
+ batterystate
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/batterystate/main.c \
+ profiles/batterystate/manager.c \
+ profiles/batterystate/manager.h \
+ profiles/batterystate/batterystate.c \
+ profiles/batterystate/batterystate.h
endif
builtin_modules += formfactor
diff --git a/profiles/batterystate/batterystate.c b/profiles/batterystate/batterystate.c
new file mode 100644
index 0000000..04c2e5e
--- /dev/null
+++ b/profiles/batterystate/batterystate.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 "batterystate.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 batterystate_free(gpointer user_data)
+{
+ struct battery *batt = user_data;
+
+ btd_device_unref(batt->dev);
+ g_free(batt);
+}
+
+
+int batterystate_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 batterystate_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);
+
+ batterystate_free(batt);
+}
diff --git a/profiles/batterystate/batterystate.h b/profiles/batterystate/batterystate.h
new file mode 100644
index 0000000..9aedae7
--- /dev/null
+++ b/profiles/batterystate/batterystate.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 batterystate_register(struct btd_device *device);
+void batterystate_unregister(struct btd_device *device);
diff --git a/profiles/batterystate/main.c b/profiles/batterystate/main.c
new file mode 100644
index 0000000..360254b
--- /dev/null
+++ b/profiles/batterystate/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 batterystate_init(void)
+{
+ if (!main_opts.gatt_enabled) {
+ DBG("GATT is disabled");
+ return -ENOTSUP;
+ }
+
+ return batterystate_manager_init();
+}
+
+static void batterystate_exit(void)
+{
+ batterystate_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(batterystate, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, batterystate_init,
+ batterystate_exit)
diff --git a/profiles/batterystate/manager.c b/profiles/batterystate/manager.c
new file mode 100644
index 0000000..6718acf
--- /dev/null
+++ b/profiles/batterystate/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 "batterystate.h"
+#include "manager.h"
+
+#define BATTERY_SERVICE_UUID "0000180f-0000-1000-8000-00805f9b34fb"
+
+static int batterystate_driver_probe(struct btd_device *device, GSList *uuids)
+{
+ return batterystate_register(device);
+}
+
+static void batterystate_driver_remove(struct btd_device *device)
+{
+ batterystate_unregister(device);
+}
+
+static struct btd_device_driver battery_device_driver = {
+ .name = "battery-driver",
+ .uuids = BTD_UUIDS(BATTERY_SERVICE_UUID),
+ .probe = batterystate_driver_probe,
+ .remove = batterystate_driver_remove
+};
+
+int batterystate_manager_init(void)
+{
+ return btd_register_device_driver(&battery_device_driver);
+}
+
+void batterystate_manager_exit(void)
+{
+ btd_unregister_device_driver(&battery_device_driver);
+}
diff --git a/profiles/batterystate/manager.h b/profiles/batterystate/manager.h
new file mode 100644
index 0000000..7f0bf15
--- /dev/null
+++ b/profiles/batterystate/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 batterystate_manager_init(void);
+void batterystate_manager_exit(void);
--
1.7.9.5