Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 03/13] heartrate: Add conn logic and attio callbacks
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Handle connection to the remote device when the
Heart Rate plugin is loaded.

---
 profiles/heartrate/heartrate.c |   86 +++++++++++++++++++++++++++++++++++++++-
 profiles/heartrate/heartrate.h |    2 +-
 profiles/heartrate/manager.c   |   22 +++++++++-
 3 files changed, 107 insertions(+), 3 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 9bd93c5..1114cff 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -30,10 +30,24 @@
 
 #include "adapter.h"
 #include "device.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gatt.h"
 #include "heartrate.h"
+#include "log.h"
 
 struct heartrate {
 	struct btd_device	*dev;  /*Device reference*/
+	GAttrib			*attrib; /*GATT connection*/
+	guint			attioid; /*ATT watcher id*/
+	struct att_range	*svc_range; /*Heart Rate range*/
+	GSList			*chars; /*Characteristics*/
+};
+
+struct characteristic {
+	struct gatt_char	attr; /*Characteristic*/
+	struct heartrate	*hr; /*Parent Heart Rate Service*/
 };
 
 static GSList *hr_servers = NULL;
@@ -53,19 +67,89 @@ static void heartrate_destroy(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
 
+	if (hr->chars != NULL)
+		g_slist_free_full(hr->chars, g_free);
+
+	if (hr->attioid > 0)
+		btd_device_remove_attio_callback(hr->dev, hr->attioid);
+
+	if (hr->attrib != NULL)
+		g_attrib_unref(hr->attrib);
+
 	btd_device_unref(hr->dev);
+	g_free(hr->svc_range);
 	g_free(hr);
+
+}
+
+static void configure_heartrate_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover heartrate 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->hr = hr;
+
+		hr->chars = g_slist_append(hr->chars, ch);
+	}
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("GATT Connected");
+
+	hr->attrib = g_attrib_ref(attrib);
+
+	if (hr->chars == NULL)
+		gatt_discover_char(hr->attrib, hr->svc_range->start,
+						hr->svc_range->end, NULL,
+						configure_heartrate_cb, hr);
 }
 
-int heartrate_register(struct btd_device *device)
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("GATT Disconnected");
+
+	g_attrib_unref(hr->attrib);
+	hr->attrib = NULL;
+}
+
+int heartrate_register(struct btd_device *device, struct gatt_primary *pattr)
 {
 	struct heartrate *hr;
 
 	hr = g_new0(struct heartrate, 1);
 	hr->dev = btd_device_ref(device);
 
+	hr->svc_range = g_new0(struct att_range, 1);
+	hr->svc_range->start = pattr->range.start;
+	hr->svc_range->end = pattr->range.end;
+
 	hr_servers = g_slist_prepend(hr_servers, hr);
 
+	hr->attioid = btd_device_add_attio_callback(device,
+						attio_connected_cb,
+						attio_disconnected_cb ,
+						hr);
 	return 0;
 }
 void heartrate_unregister(struct btd_device *device)
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 8d4271c..1d2ba89 100644
--- a/profiles/heartrate/heartrate.h
+++ b/profiles/heartrate/heartrate.h
@@ -20,5 +20,5 @@
  *
  */
 
-int heartrate_register(struct btd_device *device);
+int heartrate_register(struct btd_device *device, struct gatt_primary *pattr);
 void heartrate_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index da6c7ef..6ba059d 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -32,9 +32,29 @@
 #include "heartrate.h"
 #include "manager.h"
 
+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 heartrate_driver_probe(struct btd_device *device, GSList *uuids)
 {
-	return heartrate_register(device);
+	struct gatt_primary *pattr;
+	GSList *primaries, *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, HEART_RATE_UUID,
+							primary_uuid_cmp);
+	if (l == NULL)
+		return -EINVAL;
+
+	pattr = l->data;
+
+	return heartrate_register(device, pattr);
 }
 
 static void heartrate_driver_remove(struct btd_device *device)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 02/13] heartrate: Add Heart Rate Service GATT client skeleton
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Add initial support for the Heart Rate Service GATT
Client side.

---
 Makefile.am                    |   10 ++++-
 lib/uuid.h                     |    2 +
 profiles/heartrate/heartrate.c |   84 ++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |   24 ++++++++++++
 profiles/heartrate/main.c      |   52 +++++++++++++++++++++++++
 profiles/heartrate/manager.c   |   60 ++++++++++++++++++++++++++++
 profiles/heartrate/manager.h   |   24 ++++++++++++
 7 files changed, 254 insertions(+), 2 deletions(-)
 create mode 100644 profiles/heartrate/heartrate.c
 create mode 100644 profiles/heartrate/heartrate.h
 create mode 100644 profiles/heartrate/main.c
 create mode 100644 profiles/heartrate/manager.c
 create mode 100644 profiles/heartrate/manager.h

diff --git a/Makefile.am b/Makefile.am
index 45a811c..594ea56 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 \
+	heartrate
 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/heartrate/main.c \
+			profiles/heartrate/manager.c \
+			profiles/heartrate/manager.h \
+			profiles/heartrate/heartrate.c \
+			profiles/heartrate/heartrate.h
 endif
 
 builtin_modules += formfactor
diff --git a/lib/uuid.h b/lib/uuid.h
index 2c2b351..99b88cc 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -63,6 +63,8 @@ extern "C" {
 
 #define SAP_UUID		"0000112D-0000-1000-8000-00805f9b34fb"
 
+#define HEART_RATE_UUID		"0000180d-0000-1000-8000-00805f9b34fb"
+
 #define HEALTH_THERMOMETER_UUID		"00001809-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_MEASUREMENT_UUID	"00002a1c-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_TYPE_UUID		"00002a1d-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
new file mode 100644
index 0000000..9bd93c5
--- /dev/null
+++ b/profiles/heartrate/heartrate.c
@@ -0,0 +1,84 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 <errno.h>
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "heartrate.h"
+
+struct heartrate {
+	struct btd_device	*dev;  /*Device reference*/
+};
+
+static GSList *hr_servers = NULL;
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+	const struct heartrate *hr = a;
+	const struct btd_device *dev = b;
+
+	if (dev == hr->dev)
+		return 0;
+
+	return -1;
+}
+
+static void heartrate_destroy(gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	btd_device_unref(hr->dev);
+	g_free(hr);
+}
+
+int heartrate_register(struct btd_device *device)
+{
+	struct heartrate *hr;
+
+	hr = g_new0(struct heartrate, 1);
+	hr->dev = btd_device_ref(device);
+
+	hr_servers = g_slist_prepend(hr_servers, hr);
+
+	return 0;
+}
+void heartrate_unregister(struct btd_device *device)
+{
+	struct heartrate *hr;
+	GSList *l;
+
+	l = g_slist_find_custom(hr_servers, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	hr = l->data;
+	hr_servers = g_slist_remove(hr_servers, hr);
+
+	heartrate_destroy(hr);
+}
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
new file mode 100644
index 0000000..8d4271c
--- /dev/null
+++ b/profiles/heartrate/heartrate.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 heartrate_register(struct btd_device *device);
+void heartrate_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/main.c b/profiles/heartrate/main.c
new file mode 100644
index 0000000..40f34bc
--- /dev/null
+++ b/profiles/heartrate/main.c
@@ -0,0 +1,52 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static int heartrate_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		DBG("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return heartrate_manager_init();
+}
+
+static void heartrate_exit(void)
+{
+	heartrate_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(heartrate, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+					heartrate_init, heartrate_exit)
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
new file mode 100644
index 0000000..da6c7ef
--- /dev/null
+++ b/profiles/heartrate/manager.c
@@ -0,0 +1,60 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 <gdbus.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "heartrate.h"
+#include "manager.h"
+
+static int heartrate_driver_probe(struct btd_device *device, GSList *uuids)
+{
+	return heartrate_register(device);
+}
+
+static void heartrate_driver_remove(struct btd_device *device)
+{
+	heartrate_unregister(device);
+}
+
+static struct btd_device_driver heartrate_device_driver = {
+	.name	= "heart-rate-driver",
+	.uuids	= BTD_UUIDS(HEART_RATE_UUID),
+	.probe	= heartrate_driver_probe,
+	.remove	= heartrate_driver_remove
+};
+
+int heartrate_manager_init(void)
+{
+	return btd_register_device_driver(&heartrate_device_driver);
+}
+
+void heartrate_manager_exit(void)
+{
+	btd_unregister_device_driver(&heartrate_device_driver);
+}
diff --git a/profiles/heartrate/manager.h b/profiles/heartrate/manager.h
new file mode 100644
index 0000000..de799f6
--- /dev/null
+++ b/profiles/heartrate/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 heartrate_manager_init(void);
+void heartrate_manager_exit(void);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 01/13] Heart Rate Profile API
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat, Santiago Carot-Nemesio
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

From: Santiago Carot-Nemesio <sancane@gmail.com>

---
 doc/heartrate-api.txt |   74 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 doc/heartrate-api.txt

diff --git a/doc/heartrate-api.txt b/doc/heartrate-api.txt
new file mode 100644
index 0000000..2738e20
--- /dev/null
+++ b/doc/heartrate-api.txt
@@ -0,0 +1,74 @@
+BlueZ D-Bus Heart Rate API description
+****************************************
+
+Copyright (C) 2012	Santiago Carot-Nemesio <sancane@gmail.com>
+
+Heart Rate Profile hierarchy
+============================
+
+Service		org.bluez
+Interface	org.bluez.HeartRate
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods		dict GetProperties()
+
+			Returns all properties for the interface. See the
+			Properties section for the available properties.
+
+		RegisterWatcher(object agent)
+
+			Registers a watcher to monitor heart rate measurements.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		UnregisterWatcher(object agent)
+
+			Unregisters a watcher.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+					org.bluez.Error.NotFound
+
+		Reset()
+
+			Restart the accumulation of energy expended from zero.
+
+			Possible Errors: org.bluez.Error.NotSupported
+
+Properties	boolean ResetSupported [readonly]
+
+			True if energy expended is supported.
+
+Heart Rate Watcher hierarchy
+
+============================
+Service		unique name
+Interface	org.bluez.HeartRateWatcher
+Object path	freely definable
+
+Methods		void MeasurementReceived(dict measure)
+
+			This callback is called whenever a heart rate
+			measurement is received from the heart rate device.
+			The unit for the Value is expressed in beats per
+			minute (bpm). The energy field is optional and
+			represents the accumulated energy expended in
+			kilo Joules since last time it was reset. Furthermore,
+			the device will be automatically reset when it
+			is needed.
+			The Contact field, if present, indicates
+			that the device supports contact sensor, besides it
+			will be true if skin contact is detected. The optional
+			interval field is an array containing RR-Interval
+			values which represent the time between two R-Wave
+			detections, where the RR-Interval value 0 is older
+			than the value 1 and so on.
+
+			Dict is defined as below:
+			{
+				"Value" : uint16,
+				"Energy" : uint16,
+				"Contact" : boolean,
+				"Location" : ("Other", "Chest", "Wrist","Finger",
+					"Hand", "Earlobe", "Foot"),
+				"Interval" : array{uint16}
+			}
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 00/13] Add Heart Rate Service
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat

Add support for GATT Client Heart Rate Service.

This patchset adds Heart Rate client service, exposed on Heart Rate 
DBus API by Santiago Carot-Nemesio <sancane@gmail.com>. It allows 
registering and unregistering watchers, handling measurement notifications
and reseting Control Point. It bases on Thermometer service. Python 
test script is included. Tested against Polar H7 1013EE Heart Rate Sensor.

Rafal Garbat (12):
  heartrate: Add Heart Rate Service GATT client skeleton
  heartrate: Add conn logic and attio callbacks
  heartrate: Discover Characteristic Descriptors
  heartrate: Process Heart Rate Descriptors
  heartrate: Add DBus connection logic
  heartrate: Process Heart Rate Characteristics
  heartrate: Add notification support
  heartrate: Process measurements
  heartrate: Add support for Control Point Reset
  heartrate: Add GetProperties method handle
  heartrate: Add org.bluez.HeartRateWatcher iface to default policy
  heartrate: Add Heart Rate test script

Santiago Carot-Nemesio (1):
  Heart Rate Profile API

 Makefile.am                    |   10 +-
 Makefile.tools                 |    4 +-
 doc/heartrate-api.txt          |   74 ++++
 lib/uuid.h                     |    5 +
 profiles/heartrate/heartrate.c |  855 ++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |   25 ++
 profiles/heartrate/main.c      |   68 ++++
 profiles/heartrate/manager.c   |   93 +++++
 profiles/heartrate/manager.h   |   24 ++
 src/bluetooth.conf             |    1 +
 test/test-heartrate            |   78 ++++
 11 files changed, 1233 insertions(+), 4 deletions(-)
 create mode 100644 doc/heartrate-api.txt
 create mode 100644 profiles/heartrate/heartrate.c
 create mode 100644 profiles/heartrate/heartrate.h
 create mode 100644 profiles/heartrate/main.c
 create mode 100644 profiles/heartrate/manager.c
 create mode 100644 profiles/heartrate/manager.h
 create mode 100755 test/test-heartrate

-- 
1.7.9.5


^ permalink raw reply

* [PATCH 3/3] audio: Remove legacy MPEG endpoint
From: chanyeol.park @ 2012-08-09  6:09 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344492568-22777-1-git-send-email-chanyeol.park@samsung.com>

From: Chan-yeol Park <chanyeol.park@samsung.com>


diff --git a/audio/a2dp.c b/audio/a2dp.c
index fc8f1b7..05eb777 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -411,105 +411,6 @@ done:
 	return FALSE;
 }
 
-static gboolean mpeg_setconf_ind(struct avdtp *session,
-					struct avdtp_local_sep *sep,
-					struct avdtp_stream *stream,
-					GSList *caps,
-					avdtp_set_configuration_cb cb,
-					void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-	struct a2dp_setup *setup;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: Set_Configuration_Ind", sep);
-	else
-		DBG("Source %p: Set_Configuration_Ind", sep);
-
-	setup = a2dp_setup_get(session);
-	if (!setup)
-		return FALSE;
-
-	a2dp_sep->stream = stream;
-	setup->sep = a2dp_sep;
-	setup->stream = stream;
-	setup->setconf_cb = cb;
-
-	for (; caps != NULL; caps = g_slist_next(caps)) {
-		struct avdtp_service_capability *cap = caps->data;
-
-		if (cap->category == AVDTP_DELAY_REPORTING &&
-					!a2dp_sep->delay_reporting) {
-			setup->err = g_new(struct avdtp_error, 1);
-			avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
-					AVDTP_UNSUPPORTED_CONFIGURATION);
-			goto done;
-		}
-	}
-
-done:
-	g_idle_add(auto_config, setup);
-	return TRUE;
-}
-
-static gboolean mpeg_getcap_ind(struct avdtp *session,
-				struct avdtp_local_sep *sep,
-				gboolean get_all,
-				GSList **caps, uint8_t *err, void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-	struct avdtp_service_capability *media_transport, *media_codec;
-	struct mpeg_codec_cap mpeg_cap;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: Get_Capability_Ind", sep);
-	else
-		DBG("Source %p: Get_Capability_Ind", sep);
-
-	*caps = NULL;
-
-	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-						NULL, 0);
-
-	*caps = g_slist_append(*caps, media_transport);
-
-	memset(&mpeg_cap, 0, sizeof(struct mpeg_codec_cap));
-
-	mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-	mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
-
-	mpeg_cap.frequency = ( MPEG_SAMPLING_FREQ_48000 |
-				MPEG_SAMPLING_FREQ_44100 |
-				MPEG_SAMPLING_FREQ_32000 |
-				MPEG_SAMPLING_FREQ_24000 |
-				MPEG_SAMPLING_FREQ_22050 |
-				MPEG_SAMPLING_FREQ_16000 );
-
-	mpeg_cap.channel_mode = ( MPEG_CHANNEL_MODE_JOINT_STEREO |
-					MPEG_CHANNEL_MODE_STEREO |
-					MPEG_CHANNEL_MODE_DUAL_CHANNEL |
-					MPEG_CHANNEL_MODE_MONO );
-
-	mpeg_cap.layer = ( MPEG_LAYER_MP3 | MPEG_LAYER_MP2 | MPEG_LAYER_MP1 );
-
-	mpeg_cap.bitrate = 0xFFFF;
-
-	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap,
-						sizeof(mpeg_cap));
-
-	*caps = g_slist_append(*caps, media_codec);
-
-	if (get_all) {
-		struct avdtp_service_capability *delay_reporting;
-		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
-								NULL, 0);
-		*caps = g_slist_append(*caps, delay_reporting);
-	}
-
-	return TRUE;
-}
-
-
 static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret)
 {
 	if (ret == FALSE) {
@@ -1105,21 +1006,6 @@ static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
 	return TRUE;
 }
 
-static gboolean delayreport_ind(struct avdtp *session,
-				struct avdtp_local_sep *sep,
-				uint8_t rseid, uint16_t delay,
-				uint8_t *err, void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: DelayReport_Ind", sep);
-	else
-		DBG("Source %p: DelayReport_Ind", sep);
-
-	return TRUE;
-}
-
 static gboolean endpoint_delayreport_ind(struct avdtp *session,
 						struct avdtp_local_sep *sep,
 						uint8_t rseid, uint16_t delay,
@@ -1189,19 +1075,6 @@ static struct avdtp_sep_cfm cfm = {
 	.delay_report		= delay_report_cfm,
 };
 
-static struct avdtp_sep_ind mpeg_ind = {
-	.get_capability		= mpeg_getcap_ind,
-	.set_configuration	= mpeg_setconf_ind,
-	.get_configuration	= getconf_ind,
-	.open			= open_ind,
-	.start			= start_ind,
-	.suspend		= suspend_ind,
-	.close			= close_ind,
-	.abort			= abort_ind,
-	.reconfigure		= reconf_ind,
-	.delayreport		= delayreport_ind,
-};
-
 static struct avdtp_sep_ind endpoint_ind = {
 	.get_capability		= endpoint_getcap_ind,
 	.set_configuration	= endpoint_setconf_ind,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 2/3] audio: Remove legacy SBC endpoint
From: chanyeol.park @ 2012-08-09  6:09 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344492568-22777-1-git-send-email-chanyeol.park@samsung.com>

From: Chan-yeol Park <chanyeol.park@samsung.com>


diff --git a/audio/a2dp.c b/audio/a2dp.c
index a4369f5..fc8f1b7 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -411,134 +411,6 @@ done:
 	return FALSE;
 }
 
-static gboolean sbc_setconf_ind(struct avdtp *session,
-					struct avdtp_local_sep *sep,
-					struct avdtp_stream *stream,
-					GSList *caps,
-					avdtp_set_configuration_cb cb,
-					void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-	struct a2dp_setup *setup;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: Set_Configuration_Ind", sep);
-	else
-		DBG("Source %p: Set_Configuration_Ind", sep);
-
-	setup = a2dp_setup_get(session);
-	if (!setup)
-		return FALSE;
-
-	a2dp_sep->stream = stream;
-	setup->sep = a2dp_sep;
-	setup->stream = stream;
-	setup->setconf_cb = cb;
-
-	/* Check valid settings */
-	for (; caps != NULL; caps = g_slist_next(caps)) {
-		struct avdtp_service_capability *cap = caps->data;
-		struct avdtp_media_codec_capability *codec_cap;
-		struct sbc_codec_cap *sbc_cap;
-
-		if (cap->category == AVDTP_DELAY_REPORTING &&
-					!a2dp_sep->delay_reporting) {
-			setup->err = g_new(struct avdtp_error, 1);
-			avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
-						AVDTP_UNSUPPORTED_CONFIGURATION);
-			goto done;
-		}
-
-		if (cap->category != AVDTP_MEDIA_CODEC)
-			continue;
-
-		if (cap->length < sizeof(struct sbc_codec_cap))
-			continue;
-
-		codec_cap = (void *) cap->data;
-
-		if (codec_cap->media_codec_type != A2DP_CODEC_SBC)
-			continue;
-
-		sbc_cap = (void *) codec_cap;
-
-		if (sbc_cap->min_bitpool < MIN_BITPOOL ||
-					sbc_cap->max_bitpool > MAX_BITPOOL) {
-			setup->err = g_new(struct avdtp_error, 1);
-			avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC,
-					AVDTP_UNSUPPORTED_CONFIGURATION);
-			goto done;
-		}
-	}
-
-done:
-	g_idle_add(auto_config, setup);
-	return TRUE;
-}
-
-static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
-				gboolean get_all, GSList **caps, uint8_t *err,
-				void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-	struct avdtp_service_capability *media_transport, *media_codec;
-	struct sbc_codec_cap sbc_cap;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: Get_Capability_Ind", sep);
-	else
-		DBG("Source %p: Get_Capability_Ind", sep);
-
-	*caps = NULL;
-
-	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-						NULL, 0);
-
-	*caps = g_slist_append(*caps, media_transport);
-
-	memset(&sbc_cap, 0, sizeof(struct sbc_codec_cap));
-
-	sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-	sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
-
-	sbc_cap.frequency = ( SBC_SAMPLING_FREQ_48000 |
-				SBC_SAMPLING_FREQ_44100 |
-				SBC_SAMPLING_FREQ_32000 |
-				SBC_SAMPLING_FREQ_16000 );
-
-	sbc_cap.channel_mode = ( SBC_CHANNEL_MODE_JOINT_STEREO |
-					SBC_CHANNEL_MODE_STEREO |
-					SBC_CHANNEL_MODE_DUAL_CHANNEL |
-					SBC_CHANNEL_MODE_MONO );
-
-	sbc_cap.block_length = ( SBC_BLOCK_LENGTH_16 |
-					SBC_BLOCK_LENGTH_12 |
-					SBC_BLOCK_LENGTH_8 |
-					SBC_BLOCK_LENGTH_4 );
-
-	sbc_cap.subbands = ( SBC_SUBBANDS_8 | SBC_SUBBANDS_4 );
-
-	sbc_cap.allocation_method = ( SBC_ALLOCATION_LOUDNESS |
-					SBC_ALLOCATION_SNR );
-
-	sbc_cap.min_bitpool = MIN_BITPOOL;
-	sbc_cap.max_bitpool = MAX_BITPOOL;
-
-	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
-						sizeof(sbc_cap));
-
-	*caps = g_slist_append(*caps, media_codec);
-
-	if (get_all) {
-		struct avdtp_service_capability *delay_reporting;
-		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
-								NULL, 0);
-		*caps = g_slist_append(*caps, delay_reporting);
-	}
-
-	return TRUE;
-}
-
 static gboolean mpeg_setconf_ind(struct avdtp *session,
 					struct avdtp_local_sep *sep,
 					struct avdtp_stream *stream,
@@ -1317,19 +1189,6 @@ static struct avdtp_sep_cfm cfm = {
 	.delay_report		= delay_report_cfm,
 };
 
-static struct avdtp_sep_ind sbc_ind = {
-	.get_capability		= sbc_getcap_ind,
-	.set_configuration	= sbc_setconf_ind,
-	.get_configuration	= getconf_ind,
-	.open			= open_ind,
-	.start			= start_ind,
-	.suspend		= suspend_ind,
-	.close			= close_ind,
-	.abort			= abort_ind,
-	.reconfigure		= reconf_ind,
-	.delayreport		= delayreport_ind,
-};
-
 static struct avdtp_sep_ind mpeg_ind = {
 	.get_capability		= mpeg_getcap_ind,
 	.set_configuration	= mpeg_setconf_ind,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 1/3] audio: Remove unused local A2DP endpoints reference
From: chanyeol.park @ 2012-08-09  6:09 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344492568-22777-1-git-send-email-chanyeol.park@samsung.com>

From: Chan-yeol Park <chanyeol.park@samsung.com>


diff --git a/audio/a2dp.c b/audio/a2dp.c
index db4bb13..a4369f5 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -1562,7 +1562,6 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
 	GSList **l;
 	uint32_t *record_id;
 	sdp_record_t *record;
-	struct avdtp_sep_ind *ind;
 
 	server = find_server(servers, src);
 	if (server == NULL) {
@@ -1585,17 +1584,11 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
 
 	sep = g_new0(struct a2dp_sep, 1);
 
-	if (endpoint) {
-		ind = &endpoint_ind;
-		goto proceed;
-	}
-
-	ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
-
-proceed:
 	sep->lsep = avdtp_register_sep(&server->src, type,
 					AVDTP_MEDIA_TYPE_AUDIO, codec,
-					delay_reporting, ind, &cfm, sep);
+					delay_reporting, &endpoint_ind,
+					&cfm, sep);
+
 	if (sep->lsep == NULL) {
 		g_free(sep);
 		if (err)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 0/3] Remove remained local A2DP endpoints
From: chanyeol.park @ 2012-08-09  6:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Chan-yeol Park <chanyeol.park@samsung.com>

Local A2DP endpoints are not used anymore.
So reference, structures, and functions related to them should be removed.

If somebody wants to remain these for the reference,
 they could see git log history.

Chan-yeol Park (3):
  audio: Remove unused local A2DP endpoints reference
  audio: Remove legacy SBC endpoint
  audio: Remove legacy MPEG endpoint

 audio/a2dp.c |  281 +---------------------------------------------------------
 1 file changed, 3 insertions(+), 278 deletions(-)

-- 
1.7.9.5


^ permalink raw reply

* Re: [PATCH BlueZ V3 3/5] AVRCP: Add browsing channel support
From: Syam Sidhardhan @ 2012-08-08 20:14 UTC (permalink / raw)
  To: Vani-dineshbhai PATEL
  Cc: User Name, Luiz Augusto, Lucas De Marchi, Joohi, Vani
In-Reply-To: <1344409007-13601-1-git-send-email-vani.patel@stericsson.com>

Hi Vani,

On Wed, Aug 8, 2012 at 12:26 PM, Vani-dineshbhai PATEL
<vani.patel@stericsson.com> wrote:
> From: Vani Patel <vani.patel@stericsson.com>
>
> Implements browsing channel creation and release.
> ---
>  audio/avctp.c |  234 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
>  1 files changed, 215 insertions(+), 19 deletions(-)
>
> diff --git a/audio/avctp.c b/audio/avctp.c
> index 33ca007..69bb6a8 100644
> --- a/audio/avctp.c
> +++ b/audio/avctp.c
> @@ -41,6 +41,7 @@
>  #include <bluetooth/bluetooth.h>
>  #include <bluetooth/sdp.h>
>  #include <bluetooth/uuid.h>
> +#include <bluetooth/l2cap.h>
>
>  #include <glib.h>
>
> @@ -119,6 +120,7 @@ struct avctp_state_callback {
>  struct avctp_server {
>         bdaddr_t src;
>         GIOChannel *control_io;
> +       GIOChannel *browsing_io;
>         GSList *sessions;
>  };
>
> @@ -137,9 +139,12 @@ struct avctp {
>         int uinput;
>
>         GIOChannel *control_io;
> +       GIOChannel *browsing_io;
>         guint control_io_id;
> +       guint browsing_io_id;
>
>         uint16_t control_mtu;
> +       uint16_t browsing_mtu;
>
>         uint8_t key_quirks[256];
>         GSList *handlers;
> @@ -326,6 +331,17 @@ static void avctp_disconnected(struct avctp *session)
>         if (!session)
>                 return;
>
> +       if (session->browsing_io) {
> +               g_io_channel_shutdown(session->browsing_io, TRUE, NULL);
> +               g_io_channel_unref(session->browsing_io);
> +               session->browsing_io = NULL;
> +       }
> +
> +       if (session->browsing_io_id) {
> +               g_source_remove(session->browsing_io_id);
> +               session->browsing_io_id = 0;
> +       }
> +
>         if (session->control_io) {
>                 g_io_channel_shutdown(session->control_io, TRUE, NULL);
>                 g_io_channel_unref(session->control_io);
> @@ -432,6 +448,42 @@ static void handle_response(struct avctp *session, struct avctp_header *avctp,
>         }
>  }
>
> +static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
> +                               gpointer data)
> +{
> +       struct avctp *session = data;
> +       uint8_t  *buf;
> +       struct avctp_header *avctp;
> +       int ret, sock;
> +
> +       buf = (uint8_t *)malloc(session->browsing_mtu);

Here make use of g_new0() otherwise need to validate for buf != NULL.
Also Space required after typecasting. Btb typecasting is not required here.

> +       if (!(cond & G_IO_IN))

Memory leak buf here. Instead of return FALSE use goto failed.

> +               return FALSE;
> +
> +       sock = g_io_channel_unix_get_fd(session->browsing_io);
> +       ret = read(sock, buf, session->browsing_mtu);
> +
> +       if (ret <= 0)
> +               goto failed;
> +
> +       if ((unsigned int) ret < sizeof(struct avctp_header)) {
> +               error("Too small AVRCP packet on browsing channel");
> +               goto failed;
> +       }
> +
> +       avctp = (struct avctp_header *) buf;
> +
> +       if (avctp->packet_type != AVCTP_PACKET_SINGLE)
> +               goto failed;
> +
> +       free(buf);
> +       return TRUE;
> +
> +failed:
> +       free(buf);
> +       return FALSE;
> +}
> +
>  static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
>                                 gpointer data)
>  {
> @@ -614,6 +666,47 @@ static void init_uinput(struct avctp *session)
>                 DBG("AVRCP: uinput initialized for %s", address);
>  }
>
> +static void avctp_connect_browsing_cb(GIOChannel *chan,
> +                                       GError *err,
> +                                       gpointer data)
> +{
> +       struct avctp *session = data;
> +       char address[18];
> +       uint16_t imtu;
> +       GError *gerr = NULL;
> +
> +       if (err) {
> +               error("Browsing: %s", err->message);
> +               g_io_channel_shutdown(chan, TRUE, NULL);
> +               g_io_channel_unref(chan);
> +               session->browsing_io = NULL;
> +               return;
> +       }
> +
> +       bt_io_get(chan, BT_IO_L2CAP, &gerr,
> +                       BT_IO_OPT_DEST, &address,
> +                       BT_IO_OPT_IMTU, &imtu,
> +                       BT_IO_OPT_INVALID);
> +       if (gerr) {
> +               error("%s", gerr->message);
> +               g_io_channel_shutdown(chan, TRUE, NULL);
> +               g_io_channel_unref(chan);
> +               session->browsing_io = NULL;
> +               error("%s", gerr->message);
> +               g_error_free(gerr);
> +               return;
> +       }
> +
> +       if (!session->browsing_io)
> +               session->browsing_io = g_io_channel_ref(chan);
> +
> +       session->browsing_mtu = imtu;
> +
> +       session->browsing_io_id = g_io_add_watch(chan,
> +                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
> +                               (GIOFunc) session_browsing_cb, session);
> +}
> +
>  static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
>  {
>         struct avctp *session = data;
> @@ -652,6 +745,32 @@ static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
>                                 (GIOFunc) session_cb, session);
>  }
>
> +static void auth_browsing_cb(DBusError *derr, void *user_data)
> +{
> +       struct avctp *session = user_data;
> +       GError *err = NULL;
> +
> +       if (session->browsing_io_id) {
> +               g_source_remove(session->browsing_io_id);
> +               session->browsing_io_id = 0;
> +       }
> +
> +       if (derr && dbus_error_is_set(derr)) {
> +               error("Browsing Access denied: %s", derr->message);
> +               return;
> +       }
> +
> +       if (!bt_io_accept(session->browsing_io, avctp_connect_browsing_cb,
> +                                               session, NULL, &err)) {
> +               error("Browsing bt_io_accept: %s", err->message);
> +               if (session && session->browsing_io) {
> +                       g_io_channel_unref(session->browsing_io);
> +                       session->browsing_io = NULL;
> +               }
> +               g_error_free(err);
> +       }
> +}
> +
>  static void auth_cb(DBusError *derr, void *user_data)
>  {
>         struct avctp *session = user_data;
> @@ -730,6 +849,65 @@ static struct avctp *avctp_get_internal(const bdaddr_t *src,
>         return session;
>  }
>
> +static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
> +                                               struct audio_device *dev)
> +{
> +       if (session->control_io) {
> +               error("Refusing unexpected connect from");
> +               goto drop;
> +       }
> +
> +       avctp_set_state(session, AVCTP_STATE_CONNECTING);
> +       session->control_io = g_io_channel_ref(chan);
> +
> +       if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
> +                                               auth_cb, session) < 0)
> +               goto drop;
> +
> +       session->control_io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
> +                                               G_IO_NVAL, session_cb, session);
> +       return;
> +
> +drop:
> +       if (!session || !session->control_io)
> +               g_io_channel_shutdown(chan, TRUE, NULL);
> +
> +       if (session && session->control_io)
> +               g_io_channel_unref(session->control_io);
> +
> +       if (session)
> +               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
> +}
> +
> +static void avctp_browsing_confirm(struct avctp *session, GIOChannel *chan,
> +                                               struct audio_device *dev)
> +{
> +
> +       if (!session->control_io) {
> +               error("Browsing: Refusing unexpected connect from");
> +               goto drop;
> +       }
> +
> +       if (session->browsing_io) {
> +               error("Browsing channel already exists");
> +               goto drop;
> +       }
> +
> +       session->browsing_io = g_io_channel_ref(chan);
> +
> +       if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
> +                                               auth_browsing_cb, session) < 0)
> +               goto drop;
> +       return;
> +
> +drop:
> +       if (!session || !session->control_io || !session->browsing_io)
> +               g_io_channel_shutdown(chan, TRUE, NULL);
> +
> +       if (session && session->browsing_io)
> +               g_io_channel_unref(session->browsing_io);
> +}
> +
>  static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
>  {
>         struct avctp *session;
> @@ -737,11 +915,13 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
>         char address[18];
>         bdaddr_t src, dst;
>         GError *err = NULL;
> +       uint16_t psm;
>
>         bt_io_get(chan, BT_IO_L2CAP, &err,
>                         BT_IO_OPT_SOURCE_BDADDR, &src,
>                         BT_IO_OPT_DEST_BDADDR, &dst,
>                         BT_IO_OPT_DEST, address,
> +                       BT_IO_OPT_PSM, &psm,
>                         BT_IO_OPT_INVALID);
>         if (err) {
>                 error("%s", err->message);
> @@ -772,40 +952,40 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
>                         goto drop;
>         }
>
> -       if (session->control_io) {
> -               error("Refusing unexpected connect from %s", address);
> -               goto drop;
> +       switch (psm) {
> +       case AVCTP_CONTROL_PSM:
> +               avctp_control_confirm(session, chan, dev);
> +               break;
> +       case AVCTP_BROWSING_PSM:
> +               avctp_browsing_confirm(session, chan, dev);
> +               break;
>         }
>
> -       avctp_set_state(session, AVCTP_STATE_CONNECTING);
> -       session->control_io = g_io_channel_ref(chan);
> -
> -       if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
> -                                               auth_cb, session) < 0)
> -               goto drop;
> -
> -       session->control_io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
> -                                               G_IO_NVAL, session_cb, session);
>         return;
>
>  drop:
> -       if (!session || !session->control_io)
> -               g_io_channel_shutdown(chan, TRUE, NULL);
> -       if (session)
> +       if (session && session->browsing_io)
> +               g_io_channel_unref(session->browsing_io);
> +
> +       if (session && session->control_io)
> +               g_io_channel_unref(session->control_io);
> +
> +       if (session && psm == AVCTP_CONTROL_PSM)
>                 avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
>  }
>
> -static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master)
> +static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master,
> +                                               uint8_t mode, uint16_t psm)
>  {
>         GError *err = NULL;
>         GIOChannel *io;
> -
>         io = bt_io_listen(BT_IO_L2CAP, NULL, avctp_confirm_cb, NULL,
>                                 NULL, &err,
>                                 BT_IO_OPT_SOURCE_BDADDR, src,
> -                               BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
> +                               BT_IO_OPT_PSM, psm,
>                                 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
>                                 BT_IO_OPT_MASTER, master,
> +                               BT_IO_OPT_MODE, mode,
>                                 BT_IO_OPT_INVALID);
>         if (!io) {
>                 error("%s", err->message);
> @@ -825,12 +1005,25 @@ int avctp_register(const bdaddr_t *src, gboolean master)
>
>         server = g_new0(struct avctp_server, 1);
>
> -       server->control_io = avctp_server_socket(src, master);
> +       server->control_io = avctp_server_socket(src, master, L2CAP_MODE_BASIC,
> +                                                       AVCTP_CONTROL_PSM);
>         if (!server->control_io) {
>                 g_free(server);
>                 return -1;
>         }
>
> +       server->browsing_io = avctp_server_socket(src, master, L2CAP_MODE_ERTM,
> +                                                       AVCTP_BROWSING_PSM);
> +       if (!server->browsing_io) {
> +               if (server->control_io) {
> +                       g_io_channel_shutdown(server->control_io, TRUE, NULL);
> +                       g_io_channel_unref(server->control_io);
> +                       server->control_io = NULL;
> +               }
> +               g_free(server);
> +               return -1;
> +       }
> +
>         bacpy(&server->src, src);
>
>         servers = g_slist_append(servers, server);
> @@ -862,6 +1055,9 @@ void avctp_unregister(const bdaddr_t *src)
>                 avctp_disconnected(server->sessions->data);
>
>         servers = g_slist_remove(servers, server);
> +       g_io_channel_shutdown(server->browsing_io, TRUE, NULL);
> +       g_io_channel_unref(server->browsing_io);
> +       server->browsing_io = NULL;
>
>         g_io_channel_shutdown(server->control_io, TRUE, NULL);
>         g_io_channel_unref(server->control_io);
> --
> 1.7.5.4

Thanks,
Syam.

^ permalink raw reply

* Re: [PATCH BlueZ V4 4/5] AVRCP: Register/Unregister Browsing handler
From: Syam Sidhardhan @ 2012-08-08 19:29 UTC (permalink / raw)
  To: Vani-dineshbhai PATEL
  Cc: User Name, Luiz Augusto, Lucas De Marchi, Joohi, Vani
In-Reply-To: <1344409046-18394-1-git-send-email-vani.patel@stericsson.com>

Hi Vani,

On Wed, Aug 8, 2012 at 12:27 PM, Vani-dineshbhai PATEL
<vani.patel@stericsson.com> wrote:
> From: Vani Patel <vani.patel@stericsson.com>
>
> Add functions to register and unregister Browsing
> handler
> ---
>  audio/avctp.c |   26 ++++++++++++++++++++++++++
>  audio/avctp.h |    8 ++++++++
>  2 files changed, 34 insertions(+), 0 deletions(-)
>
> diff --git a/audio/avctp.c b/audio/avctp.c
> index 96c5605..b5f84aa 100644
> --- a/audio/avctp.c
> +++ b/audio/avctp.c
> @@ -157,6 +157,11 @@ struct avctp_pdu_handler {
>         unsigned int id;
>  };
>
> +struct avctp_browsing_pdu_handler {
> +       avctp_browsing_pdu_cb cb;
> +       void *user_data;
> +};
> +
>  static struct {
>         const char *name;
>         uint8_t avc;
> @@ -176,6 +181,7 @@ static GSList *callbacks = NULL;
>  static GSList *servers = NULL;
>  static GSList *control_handlers = NULL;
>  static uint8_t id = 0;
> +static struct avctp_browsing_pdu_handler *browsing_handler = NULL;
>
>  static void auth_cb(DBusError *derr, void *user_data);
>
> @@ -1251,6 +1257,18 @@ unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_control_pdu_cb cb,
>         return handler->id;
>  }
>
> +unsigned int avctp_register_browsing_pdu_handler(avctp_browsing_pdu_cb cb,
> +                                                       void *user_data)
> +{
> +       unsigned int id = 0;
> +
> +       browsing_handler = g_new(struct avctp_browsing_pdu_handler, 1);
> +       browsing_handler->cb = cb;
> +       browsing_handler->user_data = user_data;
> +
> +       return ++id;
> +}
> +
>  gboolean avctp_unregister_pdu_handler(unsigned int id)
>  {
>         GSList *l;
> @@ -1269,6 +1287,14 @@ gboolean avctp_unregister_pdu_handler(unsigned int id)
>         return FALSE;
>  }
>
> +gboolean avctp_unregister_browsing_pdu_handler()
> +{
> +       if (browsing_handler)

Checking for the browsing_handler is not required, as g_free()
internally do the check.

> +               g_free(browsing_handler);
> +
> +       return TRUE;
> +}
> +
>  struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst)
>  {
>         struct avctp *session;
> diff --git a/audio/avctp.h b/audio/avctp.h
> index b80e300..3e1dabe 100644
> --- a/audio/avctp.h
> +++ b/audio/avctp.h
> @@ -83,6 +83,10 @@ typedef size_t (*avctp_control_pdu_cb) (struct avctp *session,
>  typedef gboolean (*avctp_rsp_cb) (struct avctp *session, uint8_t code,
>                                         uint8_t subunit, uint8_t *operands,
>                                         size_t operand_count, void *user_data);
> +typedef size_t (*avctp_browsing_pdu_cb) (struct avctp *session,
> +                                       uint8_t transaction,
> +                                       uint8_t *operands, size_t operand_count,
> +                                       void *user_data);
>
>  unsigned int avctp_add_state_cb(avctp_state_cb cb, void *user_data);
>  gboolean avctp_remove_state_cb(unsigned int id);
> @@ -98,6 +102,10 @@ unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_control_pdu_cb cb,
>                                                         void *user_data);
>  gboolean avctp_unregister_pdu_handler(unsigned int id);
>
> +unsigned int avctp_register_browsing_pdu_handler(avctp_browsing_pdu_cb cb,
> +                                                       void *user_data);
> +
> +gboolean avctp_unregister_browsing_pdu_handler();
>  int avctp_send_passthrough(struct avctp *session, uint8_t op);
>  int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
>                                 uint8_t code, uint8_t subunit,
> --
> 1.7.5.4

Thanks,
Syam.

^ permalink raw reply

* Re: [PATCH BlueZ V4 5/5] AVRCP: Add handler for browsing pdu
From: Syam Sidhardhan @ 2012-08-08 19:22 UTC (permalink / raw)
  To: Vani-dineshbhai PATEL
  Cc: User Name, Luiz Augusto, Lucas De Marchi, Joohi, Vani
In-Reply-To: <1344409069-19556-1-git-send-email-vani.patel@stericsson.com>

Hi Vani,

On Wed, Aug 8, 2012 at 12:27 PM, Vani-dineshbhai PATEL
<vani.patel@stericsson.com> wrote:
> From: Vani Patel <vani.patel@stericsson.com>
>
> Implement generic handling of browsing
> PDU IDs
> ---
>  audio/avctp.c |   27 ++++++++++++++++++--
>  audio/avrcp.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 97 insertions(+), 3 deletions(-)
>
> diff --git a/audio/avctp.c b/audio/avctp.c
> index b5f84aa..7bbcecc 100644
> --- a/audio/avctp.c
> +++ b/audio/avctp.c
> @@ -458,9 +458,9 @@ static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
>                                 gpointer data)
>  {
>         struct avctp *session = data;
> -       uint8_t  *buf;
> +       uint8_t *operands, *buf;
>         struct avctp_header *avctp;
> -       int ret, sock;
> +       int ret, packet_size, operand_count, sock;
>
>         buf = (uint8_t *)malloc(session->browsing_mtu);

Need a space after typecasting.

>         if (!(cond & G_IO_IN))
> @@ -472,6 +472,8 @@ static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
>         if (ret <= 0)
>                 goto failed;
>
> +       DBG("Got %d bytes of data for AVCTP Browsing session %p", ret, session);
> +
>         if ((unsigned int) ret < sizeof(struct avctp_header)) {
>                 error("Too small AVRCP packet on browsing channel");
>                 goto failed;
> @@ -479,9 +481,28 @@ static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
>
>         avctp = (struct avctp_header *) buf;
>
> +       DBG("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, "
> +                       "PID 0x%04X",
> +                       avctp->transaction, avctp->packet_type,
> +                       avctp->cr, avctp->ipid, ntohs(avctp->pid));
> +
>         if (avctp->packet_type != AVCTP_PACKET_SINGLE)
>                 goto failed;

It's better to have a  blank line here.

> +       operands = buf + AVCTP_HEADER_LENGTH;
> +       ret -= AVCTP_HEADER_LENGTH;
> +       operand_count = ret;
> +
> +       packet_size = AVCTP_HEADER_LENGTH;
> +       avctp->cr = AVCTP_RESPONSE;
> +       if (browsing_handler)
> +               packet_size += browsing_handler->cb(session, avctp->transaction,
> +                       operands, operand_count, browsing_handler->user_data);
>
> +       if (packet_size !=0 ) {

Space required after '!=' and space prohibited before ')'

> +               ret = write(sock, buf, packet_size);
> +               if (ret != packet_size)
> +                       goto failed;
> +       }
>         free(buf);
>         return TRUE;
>
> diff --git a/audio/avrcp.c b/audio/avrcp.c
> index 9d29073..deba4a6 100644
> --- a/audio/avrcp.c
> +++ b/audio/avrcp.c
> @@ -94,6 +94,9 @@
>  #define AVRCP_ABORT_CONTINUING         0x41
>  #define AVRCP_SET_ABSOLUTE_VOLUME      0x50
>
> +#define AVRCP_INVALID_BROWSING_PDU     0x00
> +
> +#define AVRCP_GENERAL_REJECT           0xA0
>  /* Capabilities for AVRCP_GET_CAPABILITIES pdu */
>  #define CAP_COMPANY_ID         0x02
>  #define CAP_EVENTS_SUPPORTED   0x03
> @@ -140,6 +143,12 @@ struct avrcp_header {
>  #error "Unknown byte order"
>  #endif
>
> +struct avrcp_browsing_header {
> +       uint8_t browsing_pdu;
> +       uint16_t param_len;
> +} __attribute__ ((packed));
> +#define AVRCP_BROWSING_HEADER_LENGTH 3
> +
>  #define AVRCP_MTU      (AVC_MTU - AVC_HEADER_LENGTH)
>  #define AVRCP_PDU_MTU  (AVRCP_MTU - AVRCP_HEADER_LENGTH)
>
> @@ -163,7 +172,9 @@ struct avrcp_player {
>         struct audio_device *dev;
>
>         unsigned int control_handler;
> +       unsigned int browsing_handler;
>         uint16_t registered_events;
> +       uint8_t transaction;
>         uint8_t transaction_events[AVRCP_EVENT_LAST + 1];
>         struct pending_pdu *pending_pdu;
>
> @@ -1075,6 +1086,15 @@ static struct control_pdu_handler {
>                 { },
>  };
>
> +static struct pdu_browsing_handler {
> +       uint8_t browsing_pdu;
> +       void (*func) (struct avrcp_player *player,
> +                                       struct avrcp_browsing_header *pdu);
> +       } browsing_handlers[] = {
> +               { AVRCP_INVALID_BROWSING_PDU,
> +                                       NULL },
> +};
> +
>  /* handle vendordep pdu inside an avctp packet */
>  static size_t handle_vendordep_pdu(struct avctp *session, uint8_t transaction,
>                                         uint8_t *code, uint8_t *subunit,
> @@ -1134,6 +1154,49 @@ err_metadata:
>         return AVRCP_HEADER_LENGTH + 1;
>  }
>
> +static size_t handle_browsing_pdu(struct avctp *session,
> +                                       uint8_t transaction, uint8_t *operands,
> +                                       size_t operand_count, void *user_data)
> +{
> +       struct avrcp_player *player = user_data;
> +       struct pdu_browsing_handler *b_handler;
> +       struct avrcp_browsing_header *avrcp_browsing = (void *) operands;
> +       uint8_t status;
> +
> +       operand_count += AVRCP_BROWSING_HEADER_LENGTH;
> +
> +       for (b_handler = browsing_handlers; b_handler; b_handler++) {
> +               if (b_handler->browsing_pdu == AVRCP_INVALID_BROWSING_PDU) {
> +                       b_handler = NULL;
> +                       break;
> +               }
> +               if (b_handler->browsing_pdu == avrcp_browsing->browsing_pdu)
> +                       break;
> +       }
> +
> +       if (!b_handler) {
> +               avrcp_browsing->browsing_pdu = AVRCP_GENERAL_REJECT;
> +               status = AVRCP_STATUS_INVALID_COMMAND;
> +               goto err;
> +       }
> +
> +       if (!b_handler->func) {
> +               status = AVRCP_STATUS_INVALID_PARAM;
> +               avrcp_browsing->param_len = htons(sizeof(status));
> +               goto err;
> +       }
> +       player->transaction = transaction;
> +       b_handler->func(player, avrcp_browsing);
> +       return AVRCP_BROWSING_HEADER_LENGTH + ntohs(avrcp_browsing->param_len);
> +
> +err:
> +       avrcp_browsing->param_len = htons(sizeof(status));
> +       memcpy(&operands[AVRCP_BROWSING_HEADER_LENGTH], &status,
> +                                                       (sizeof(status)));
> +       return AVRCP_BROWSING_HEADER_LENGTH + sizeof(status);
> +}
> +
> +
>  size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands)
>  {
>         struct avrcp_header *pdu = (void *) operands;
> @@ -1233,6 +1296,10 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
>                         avctp_unregister_pdu_handler(player->control_handler);
>                         player->control_handler = 0;
>                 }
> +               if (player->browsing_handler) {
> +                       avctp_unregister_browsing_pdu_handler();
> +                       player->browsing_handler = 0;
> +               }
>
>                 break;
>         case AVCTP_STATE_CONNECTING:
> @@ -1244,6 +1311,12 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
>                                                         AVC_OP_VENDORDEP,
>                                                         handle_vendordep_pdu,
>                                                         player);
> +               if (!player->browsing_handler)
> +                       player->browsing_handler =
> +                                       avctp_register_browsing_pdu_handler(
> +                                                       handle_browsing_pdu,
> +                                                       player);
> +
>                 break;
>         case AVCTP_STATE_CONNECTED:
>                 rec = btd_device_get_record(dev->btd_dev, AVRCP_TARGET_UUID);
> --
> 1.7.5.4
>

It's always better to run checkpatch.pl script on the patches before
sending to the ML. It can capture the coding style issues.

Thanks,
Syam.

^ permalink raw reply

* [RFC BlueZ] doc: Introduce Alert API
From: Anderson Lizardo @ 2012-08-08 18:23 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo

This API will be implemented and initially used by Phone Alert Status
and Alert Notification GATT profiles (server role).
---
 doc/alert-api.txt |   95 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)
 create mode 100644 doc/alert-api.txt

diff --git a/doc/alert-api.txt b/doc/alert-api.txt
new file mode 100644
index 0000000..209c4da
--- /dev/null
+++ b/doc/alert-api.txt
@@ -0,0 +1,95 @@
+BlueZ D-Bus Alert API description
+*********************************
+
+Copyright (C) 2012  Instituto Nokia de Tecnologia - INdT
+
+Introduction
+------------
+
+Currently, there are two different GATT server profiles that depend on
+receiving alerts or notifications from the platform: Phone Alert Status (PASP)
+and Alert Notification (ANP). Additionally, PASP is very specific to mobile
+phones, and also allow limited control to alerts (i.e. mute once, or switch to
+a silent mode).
+
+This document presents a unified API that allows to register, 
+
+Alert hierarchy
+===============
+
+Service		org.bluez
+Interface	org.bluez.Alert
+Object path	/org/bluez
+
+Methods		void RegisterAlert(string category)
+
+			Register a new alert category. This means the
+			application will be responsible for notifying BlueZ of
+			any alerts of that category, using the Alert() method.
+
+			Supported categories: generic, email, news, call,
+			missed_call, sms_mms, voice_mail, schedule,
+			instant_message, ringer, vibrate, display.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void RegisterAgent(string category, object agent)
+
+			Register a new agent for the alert category. The agent
+			object methods to be called depend on the category. The
+			currently supported category is "ringer", with methods
+			MuteOnce() and SetRingerMode().
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void NewAlert(string category, string description)
+
+			Notify BlueZ of a new alert for the given category. The
+			description can be sender name, called ID, title, or
+			other information specific to the alert. For ringer,
+			vibrate and display categories, valid descriptions are
+			"active" and "not active".
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void UnreadAlertCount(string category, uint16 count)
+
+			Some services (like SMS and e-mail) keep track of
+			number of unread items. This method allows to update
+			this counter, so peer devices can read it using Alert
+			Notification Profile.
+
+			Note that just calling NewAlert() will not implicitly
+			increment the unread count for a category. The
+			application must call this method to increase or
+			decrease the unread counter.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+Alert Agent hierarchy
+=====================
+
+Service		org.bluez
+Interface	org.bluez.AlertAgent
+Object path	freely definable
+
+Methods		void MuteOnce()
+
+			This method is only called if "ringer" alert category
+			is specified when registering the agent.
+
+			Mute the ringer once (e.g. during a incoming call). If
+			ringer is not active, does nothing.
+
+		void SetRingerMode(string mode)
+
+			This method is only called if "ringer" alert category
+			is specified when registering the agent.
+
+			Set ringer to the specified mode. If mode is "normal",
+			ringer is set to the default mode, as defined by the
+			current active profile. If mode is "silent", ringer
+			will not activate on incoming calls, until it is set
+			back to "normal" mode.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v3 9/9] Battery: Emit property changed on first read
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 8/9] Battery: Add support for notifications
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 7/9] Battery: Read Battery level characteristic
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 6/9] Battery: Add Battery D-BUS API
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 5/9] Battery: Add Battery list to btd_device
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 4/9] Battery: Get Battery ID
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 3/9] Battery: Discover Characteristic Descriptors
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 2/9] Battery: Add connection logic
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 1/9] Battery: Add Battery Service GATT Client
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir
In-Reply-To: <1344435980-9866-1-git-send-email-chen.ganir@ti.com>

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

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

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


^ permalink raw reply related

* [PATCH v3 0/9] Add GATT Client Battery Service
From: chen.ganir @ 2012-08-08 14:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: jprvita, Chen Ganir

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

Add suupport for LE GATT Client Battery Service.

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

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

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

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

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

-- 
1.7.9.5


^ permalink raw reply

* Re: [RFC v3 2/2] Bluetooth: mgmt: Add device disconnect reason
From: Marcel Holtmann @ 2012-08-08 13:52 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: linux-bluetooth, Mikel Astiz
In-Reply-To: <1344411753-10124-3-git-send-email-mikel.astiz.oss@gmail.com>

Hi Mikel,

> MGMT_EV_DEVICE_DISCONNECTED will now expose the disconnection reason to
> userland, distinguishing four possible values:
> 
> 	0x00	Reason not known or unspecified
> 	0x01	ACL connection timeout
> 	0x02	ACL connection terminated by local host
> 	0x03	ACL connection terminated by remote host

I think we need to leave ACL out here. Since that is not how we defined
what a connection is in mgmt terms.

> Note that the local/remote distinction just determines which side
> terminated the low-level ACL connection, regardless of the disconnection
> of the higher-level profiles.
> 
> This can sometimes be misleading and thus must be used with care. For
> example, some hardware combinations would report a locally initiated
> disconnection even if the user turned Bluetooth off in the remote side.

Please make sure that this comment makes it also into the API
description.

> 
> Signed-off-by: Mikel Astiz <mikel.astiz@bmw-carit.de>
> ---
>  include/net/bluetooth/hci_core.h |    2 +-
>  include/net/bluetooth/mgmt.h     |    8 ++++++++
>  net/bluetooth/hci_event.c        |   24 +++++++++++++++++++++---
>  net/bluetooth/mgmt.c             |    9 +++++----
>  4 files changed, 35 insertions(+), 8 deletions(-)
> 
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 41d9439..4fb0323 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -1004,7 +1004,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
>  			  u8 addr_type, u32 flags, u8 *name, u8 name_len,
>  			  u8 *dev_class);
>  int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
> -			     u8 link_type, u8 addr_type);
> +			     u8 link_type, u8 addr_type, u8 reason);
>  int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
>  			   u8 link_type, u8 addr_type, u8 status);
>  int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
> diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
> index 4348ee8..e8b86e0 100644
> --- a/include/net/bluetooth/mgmt.h
> +++ b/include/net/bluetooth/mgmt.h
> @@ -405,7 +405,15 @@ struct mgmt_ev_device_connected {
>  	__u8	eir[0];
>  } __packed;
>  

Please also list MGMT_DEV_DISCONN_UNKNOWN here.

> +#define MGMT_DEV_DISCONN_TIMEOUT	0x01
> +#define MGMT_DEV_DISCONN_LOCAL_HOST	0x02
> +#define MGMT_DEV_DISCONN_REMOTE		0x03
> +
>  #define MGMT_EV_DEVICE_DISCONNECTED	0x000C
> +struct mgmt_ev_device_disconnected {
> +	struct mgmt_addr_info addr;
> +	__u8	reason;
> +} __packed;
>  
>  #define MGMT_EV_CONNECT_FAILED		0x000D
>  struct mgmt_ev_connect_failed {
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 0386e1e..1323341 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -29,6 +29,7 @@
>  
>  #include <net/bluetooth/bluetooth.h>
>  #include <net/bluetooth/hci_core.h>
> +#include <net/bluetooth/mgmt.h>
>  
>  /* Handle HCI Event packets */
>  
> @@ -1906,12 +1907,29 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
>  
>  	if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
>  	    (conn->type == ACL_LINK || conn->type == LE_LINK)) {
> -		if (ev->status != 0)
> +		if (ev->status != 0) {

While at it, turn this into if (ev->status).

>  			mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
>  					       conn->dst_type, ev->status);
> -		else
> +		} else {
> +			u8 reason = 0;
> +
> +			switch (ev->reason) {
> +			case HCI_ERROR_CONNECTION_TIMEOUT:
> +				reason = MGMT_DEV_DISCONN_TIMEOUT;
> +				break;
> +			case HCI_ERROR_REMOTE_USER_TERM:
> +			case HCI_ERROR_REMOTE_LOW_RESOURCES:
> +			case HCI_ERROR_REMOTE_POWER_OFF:
> +				reason = MGMT_DEV_DISCONN_REMOTE;
> +				break;
> +			case HCI_ERROR_LOCAL_HOST_TERM:
> +				reason = MGMT_DEV_DISCONN_LOCAL_HOST;
> +				break;
> +			}

I would prefer a helper function to turn HCI error into reason.

> +
>  			mgmt_device_disconnected(hdev, &conn->dst, conn->type,
> -						 conn->dst_type);
> +						 conn->dst_type, reason);
> +		}
>  	}
>  
>  	if (ev->status == 0) {
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index a3329cb..05d4b83 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -3077,16 +3077,17 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
>  }
>  
>  int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
> -			     u8 link_type, u8 addr_type)
> +			     u8 link_type, u8 addr_type, u8 reason)
>  {
> -	struct mgmt_addr_info ev;
> +	struct mgmt_ev_device_disconnected ev;
>  	struct sock *sk = NULL;
>  	int err;
>  
>  	mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
>  
> -	bacpy(&ev.bdaddr, bdaddr);
> -	ev.type = link_to_bdaddr(link_type, addr_type);
> +	bacpy(&ev.addr.bdaddr, bdaddr);
> +	ev.addr.type = link_to_bdaddr(link_type, addr_type);
> +	ev.reason = reason;
>  
>  	err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
>  			 sk);

Otherwise I am fine with this.

Regards

Marcel



^ permalink raw reply

* Re: [RFC v3 1/2] Bluetooth: Add more HCI error codes
From: Marcel Holtmann @ 2012-08-08 13:48 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: linux-bluetooth, Mikel Astiz
In-Reply-To: <1344411753-10124-2-git-send-email-mikel.astiz.oss@gmail.com>

Hi Mikel,

> Add more HCI error codes as defined in the specification.
> 
> Signed-off-by: Mikel Astiz <mikel.astiz@bmw-carit.de>
> ---
>  include/net/bluetooth/hci.h |    3 +++
>  1 files changed, 3 insertions(+), 0 deletions(-)

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel



^ permalink raw reply

* [PATCH] Write discoverable mode on storage after HCI response
From: chanyeol.park @ 2012-08-08 13:03 UTC (permalink / raw)
  To: linux-bluetooth

From: Chan-yeol Park <chanyeol.park@samsung.com>

Right after HCI mode command is sent, Bluez writes mode value
on the storage. but in case of DiscoverableTimeout, storage value
is not updated like adapter->mode value. So this logic is moved.
---
 src/adapter.c |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index acb845e..1b8e3b0 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -302,7 +302,6 @@ static int set_mode(struct btd_adapter *adapter, uint8_t new_mode,
 
 done:
 	modestr = mode2str(new_mode);
-	write_device_mode(&adapter->bdaddr, modestr);
 
 	DBG("%s", modestr);
 
@@ -2244,6 +2243,12 @@ static void set_mode_complete(struct btd_adapter *adapter)
 		adapter->mode_sessions = NULL;
 	}
 
+	modestr = mode2str(adapter->mode);
+
+	DBG("%s", modestr);
+
+	write_device_mode(&adapter->bdaddr, modestr);
+
 	if (adapter->pending_mode == NULL)
 		return;
 
@@ -2268,10 +2273,6 @@ static void set_mode_complete(struct btd_adapter *adapter)
 		g_dbus_send_message(connection, reply);
 	}
 
-	modestr = mode2str(adapter->mode);
-
-	DBG("%s", modestr);
-
 	/* restore if the mode doesn't matches the pending */
 	if (err != 0) {
 		write_device_mode(&adapter->bdaddr, modestr);
-- 
1.7.9.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox