Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v5 06/17] heartrate: Discover characteristics descriptors
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

---
 profiles/heartrate/heartrate.c | 72 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 02a4617..69d6d51 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -55,6 +55,13 @@ struct heartrate {
 struct characteristic {
 	struct gatt_char	attr;
 	struct heartrate	*hr;
+	GSList			*desc;
+};
+
+struct descriptor {
+	struct characteristic	*ch;
+	uint16_t		handle;
+	bt_uuid_t		uuid;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -92,6 +99,15 @@ find_heartrate_adapter(struct btd_adapter *adapter)
 	return l->data;
 }
 
+static void destroy_char(gpointer user_data)
+{
+	struct characteristic *c = user_data;
+
+	g_slist_free_full(c->desc, g_free);
+
+	g_free(c);
+}
+
 static void destroy_heartrate_device(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -103,7 +119,7 @@ static void destroy_heartrate_device(gpointer user_data)
 		g_attrib_unref(hr->attrib);
 
 	if (hr->chars != NULL)
-		g_slist_free_full(hr->chars, g_free);
+		g_slist_free_full(hr->chars, destroy_char);
 
 	btd_device_unref(hr->dev);
 	g_free(hr->svc_range);
@@ -128,6 +144,44 @@ static void process_heartrate_char(struct characteristic *ch)
 		DBG("Body Sensor Location supported by client");
 }
 
+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_heartrate_cb(GSList *characteristics, guint8 status,
 							gpointer user_data)
 {
@@ -143,6 +197,7 @@ static void configure_heartrate_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;
@@ -154,6 +209,21 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 		hr->chars = g_slist_append(hr->chars, ch);
 
 		process_heartrate_char(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 != hr->svc_range->end) {
+			end = hr->svc_range->end;
+		} else {
+			continue;
+		}
+
+		gatt_find_info(hr->attrib, start, end, discover_desc_cb, ch);
 	}
 }
 
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v5 05/17] heartrate: Process characteristics
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds stub to process discovered characteristics.

---
 lib/uuid.h                     |  2 ++
 profiles/heartrate/heartrate.c | 10 ++++++++++
 2 files changed, 12 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 3488e66..0a9db51 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,8 @@ extern "C" {
 #define SAP_UUID		"0000112D-0000-1000-8000-00805f9b34fb"
 
 #define HEART_RATE_UUID			"0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_CONTROL_POINT_UUID	"00002a39-0000-1000-8000-00805f9b34fb"
+#define BODY_SENSOR_LOCATION_UUID	"00002a38-0000-1000-8000-00805f9b34fb"
 
 #define HEALTH_THERMOMETER_UUID		"00001809-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_MEASUREMENT_UUID	"00002a1c-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index e4147cf..02a4617 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -120,6 +120,14 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hra);
 }
 
+static void process_heartrate_char(struct characteristic *ch)
+{
+	if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
+		DBG("Heart Rate Control Point supported by client");
+	 else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0)
+		DBG("Body Sensor Location supported by client");
+}
+
 static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 							gpointer user_data)
 {
@@ -144,6 +152,8 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 		ch->hr = hr;
 
 		hr->chars = g_slist_append(hr->chars, ch);
+
+		process_heartrate_char(ch);
 	}
 }
 
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v5 04/17] heartrate: Discover characteristics
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds support to discover Heart Rate Service characteristics when
connected to remote device.

---
 profiles/heartrate/heartrate.c | 49 +++++++++++++++++++++++++++++++++++++++++-
 profiles/heartrate/heartrate.h |  3 ++-
 profiles/heartrate/manager.c   | 22 ++++++++++++++++++-
 3 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 918546e..e4147cf 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -48,6 +48,13 @@ struct heartrate {
 	struct heartrate_adapter	*hra;
 	GAttrib				*attrib;
 	guint				attioid;
+	struct att_range		*svc_range;
+	GSList				*chars;
+};
+
+struct characteristic {
+	struct gatt_char	attr;
+	struct heartrate	*hr;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -95,7 +102,11 @@ static void destroy_heartrate_device(gpointer user_data)
 	if (hr->attrib != NULL)
 		g_attrib_unref(hr->attrib);
 
+	if (hr->chars != NULL)
+		g_slist_free_full(hr->chars, g_free);
+
 	btd_device_unref(hr->dev);
+	g_free(hr->svc_range);
 	g_free(hr);
 }
 
@@ -109,6 +120,33 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hra);
 }
 
+static void configure_heartrate_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover Heart Rate 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;
@@ -116,6 +154,10 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 	DBG("GATT Connected");
 
 	hr->attrib = g_attrib_ref(attrib);
+
+	gatt_discover_char(hr->attrib, hr->svc_range->start,
+					hr->svc_range->end, NULL,
+					configure_heartrate_cb, hr);
 }
 
 static void attio_disconnected_cb(gpointer user_data)
@@ -153,7 +195,8 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
 	destroy_heartrate_adapter(hra);
 }
 
-int heartrate_device_register(struct btd_device *device)
+int heartrate_device_register(struct btd_device *device,
+						struct gatt_primary *pattr)
 {
 	struct heartrate_adapter *hra;
 	struct btd_adapter *adapter;
@@ -172,6 +215,10 @@ int heartrate_device_register(struct btd_device *device)
 
 	hra->devices = g_slist_prepend(hra->devices, hr);
 
+	hr->svc_range = g_new0(struct att_range, 1);
+	hr->svc_range->start = pattr->range.start;
+	hr->svc_range->end = pattr->range.end;
+
 	hr->attioid = btd_device_add_attio_callback(device,
 						attio_connected_cb,
 						attio_disconnected_cb,
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 486f5b3..ec3ed7a 100644
--- a/profiles/heartrate/heartrate.h
+++ b/profiles/heartrate/heartrate.h
@@ -22,5 +22,6 @@
 
 int heartrate_adapter_register(struct btd_adapter *adapter);
 void heartrate_adapter_unregister(struct btd_adapter *adapter);
-int heartrate_device_register(struct btd_device *device);
+int heartrate_device_register(struct btd_device *device,
+						struct gatt_primary *pattr);
 void heartrate_device_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index 2a9326d..d7d7ae4 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -34,6 +34,14 @@
 #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_adapter_probe(struct btd_adapter *adapter)
 {
 	return heartrate_adapter_register(adapter);
@@ -46,7 +54,19 @@ static void heartrate_adapter_remove(struct btd_adapter *adapter)
 
 static int heartrate_device_probe(struct btd_device *device, GSList *uuids)
 {
-	return heartrate_device_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_device_register(device, pattr);
 }
 
 static void heartrate_device_remove(struct btd_device *device)
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v5 03/17] heartrate: Add attio callbacks
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/heartrate/heartrate.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 17514c0..918546e 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -31,7 +31,12 @@
 
 #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_adapter {
 	struct btd_adapter	*adapter;
@@ -41,6 +46,8 @@ struct heartrate_adapter {
 struct heartrate {
 	struct btd_device		*dev;
 	struct heartrate_adapter	*hra;
+	GAttrib				*attrib;
+	guint				attioid;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -82,6 +89,12 @@ static void destroy_heartrate_device(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
 
+	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);
 }
@@ -90,9 +103,31 @@ static void destroy_heartrate_adapter(gpointer user_data)
 {
 	struct heartrate_adapter *hra = user_data;
 
+	if (hra->devices != NULL)
+		g_slist_free_full(hra->devices, destroy_heartrate_device);
+
 	g_free(hra);
 }
 
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("GATT Connected");
+
+	hr->attrib = g_attrib_ref(attrib);
+}
+
+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_adapter_register(struct btd_adapter *adapter)
 {
 	struct heartrate_adapter *hra;
@@ -137,6 +172,11 @@ int heartrate_device_register(struct btd_device *device)
 
 	hra->devices = g_slist_prepend(hra->devices, hr);
 
+	hr->attioid = btd_device_add_attio_callback(device,
+						attio_connected_cb,
+						attio_disconnected_cb,
+						hr);
+
 	return 0;
 }
 
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v5 02/17] heartrate: Add Heart Rate Profile client
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds initial support for the Heart Rate Profile client.

---
 Makefile.am                    |   9 ++-
 lib/uuid.h                     |   2 +
 profiles/heartrate/heartrate.c | 165 +++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |  26 +++++++
 profiles/heartrate/main.c      |  52 +++++++++++++
 profiles/heartrate/manager.c   |  76 +++++++++++++++++++
 profiles/heartrate/manager.h   |  24 ++++++
 7 files changed, 352 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 372111a..808a81f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -211,7 +211,7 @@ endif
 
 if GATTMODULES
 builtin_modules += thermometer alert time gatt_example proximity deviceinfo \
-			gatt
+			gatt heartrate
 builtin_sources += profiles/thermometer/main.c \
 			profiles/thermometer/manager.h \
 			profiles/thermometer/manager.c \
@@ -240,7 +240,12 @@ builtin_sources += profiles/thermometer/main.c \
 			profiles/deviceinfo/deviceinfo.c \
 			profiles/gatt/main.c profiles/gatt/manager.h \
 			profiles/gatt/manager.c profiles/gatt/gas.h \
-			profiles/gatt/gas.c
+			profiles/gatt/gas.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 aa6efdf..3488e66 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..17514c0
--- /dev/null
+++ b/profiles/heartrate/heartrate.c
@@ -0,0 +1,165 @@
+/*
+ *
+ *  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 <stdbool.h>
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "heartrate.h"
+
+struct heartrate_adapter {
+	struct btd_adapter	*adapter;
+	GSList			*devices;
+};
+
+struct heartrate {
+	struct btd_device		*dev;
+	struct heartrate_adapter	*hra;
+};
+
+static GSList *heartrate_adapters = NULL;
+
+static gint cmp_adapter(gconstpointer a, gconstpointer b)
+{
+	const struct heartrate_adapter *hra = a;
+	const struct btd_adapter *adapter = b;
+
+	if (adapter == hra->adapter)
+		return 0;
+
+	return -1;
+}
+
+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 struct heartrate_adapter *
+find_heartrate_adapter(struct btd_adapter *adapter)
+{
+	GSList *l = g_slist_find_custom(heartrate_adapters, adapter,
+								cmp_adapter);
+	if (!l)
+		return NULL;
+
+	return l->data;
+}
+
+static void destroy_heartrate_device(gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	btd_device_unref(hr->dev);
+	g_free(hr);
+}
+
+static void destroy_heartrate_adapter(gpointer user_data)
+{
+	struct heartrate_adapter *hra = user_data;
+
+	g_free(hra);
+}
+
+int heartrate_adapter_register(struct btd_adapter *adapter)
+{
+	struct heartrate_adapter *hra;
+
+	hra = g_new0(struct heartrate_adapter, 1);
+	hra->adapter = adapter;
+
+	heartrate_adapters = g_slist_prepend(heartrate_adapters, hra);
+
+	return 0;
+}
+
+void heartrate_adapter_unregister(struct btd_adapter *adapter)
+{
+	struct heartrate_adapter *hra;
+
+	hra = find_heartrate_adapter(adapter);
+	if (hra == NULL)
+		return;
+
+	heartrate_adapters = g_slist_remove(heartrate_adapters, hra);
+
+	destroy_heartrate_adapter(hra);
+}
+
+int heartrate_device_register(struct btd_device *device)
+{
+	struct heartrate_adapter *hra;
+	struct btd_adapter *adapter;
+	struct heartrate *hr;
+
+	adapter = device_get_adapter(device);
+
+	hra = find_heartrate_adapter(adapter);
+
+	if (hra == NULL)
+		return -1;
+
+	hr = g_new0(struct heartrate, 1);
+	hr->dev = btd_device_ref(device);
+	hr->hra = hra;
+
+	hra->devices = g_slist_prepend(hra->devices, hr);
+
+	return 0;
+}
+
+void heartrate_device_unregister(struct btd_device *device)
+{
+	struct heartrate_adapter *hra;
+	struct btd_adapter *adapter;
+	struct heartrate *hr;
+	GSList *l;
+
+	adapter = device_get_adapter(device);
+
+	hra = find_heartrate_adapter(adapter);
+	if (hra == NULL)
+		return;
+
+	l = g_slist_find_custom(hra->devices, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	hr = l->data;
+
+	hra->devices = g_slist_remove(hra->devices, hr);
+
+	destroy_heartrate_device(hr);
+}
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
new file mode 100644
index 0000000..486f5b3
--- /dev/null
+++ b/profiles/heartrate/heartrate.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *  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_adapter_register(struct btd_adapter *adapter);
+void heartrate_adapter_unregister(struct btd_adapter *adapter);
+int heartrate_device_register(struct btd_device *device);
+void heartrate_device_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..2a9326d
--- /dev/null
+++ b/profiles/heartrate/manager.c
@@ -0,0 +1,76 @@
+/*
+ *
+ *  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 <stdbool.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "heartrate.h"
+#include "manager.h"
+
+static int heartrate_adapter_probe(struct btd_adapter *adapter)
+{
+	return heartrate_adapter_register(adapter);
+}
+
+static void heartrate_adapter_remove(struct btd_adapter *adapter)
+{
+	heartrate_adapter_unregister(adapter);
+}
+
+static int heartrate_device_probe(struct btd_device *device, GSList *uuids)
+{
+	return heartrate_device_register(device);
+}
+
+static void heartrate_device_remove(struct btd_device *device)
+{
+	heartrate_device_unregister(device);
+}
+
+static struct btd_profile hrp_profile = {
+	.name		= "Heart Rate GATT Driver",
+	.remote_uuids	= BTD_UUIDS(HEART_RATE_UUID),
+
+	.device_probe	= heartrate_device_probe,
+	.device_remove	= heartrate_device_remove,
+
+	.adapter_probe	= heartrate_adapter_probe,
+	.adapter_remove	= heartrate_adapter_remove,
+};
+
+int heartrate_manager_init(void)
+{
+	return btd_profile_register(&hrp_profile);
+}
+
+void heartrate_manager_exit(void)
+{
+	btd_profile_unregister(&hrp_profile);
+}
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.11.3


^ permalink raw reply related

* [PATCH v5 01/17] Heart Rate Profile API
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

---
 doc/heartrate-api.txt | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 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..4ce96d8
--- /dev/null
+++ b/doc/heartrate-api.txt
@@ -0,0 +1,84 @@
+			 Heart Rate API description
+****************************************
+
+Copyright (C) 2012	Santiago Carot-Nemesio <sancane@gmail.com>
+Copyright (C) 2012	Tieto Poland
+
+Heart Rate Manager hierarchy
+============================
+
+Service		org.bluez
+Interface	org.bluez.HeartRateManager
+Object path	[variable prefix]/{hci0,hci1,...}
+
+Methods		RegisterWatcher(object agent)
+
+			Registers a watcher to monitor heart rate measurements.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		UnregisterWatcher(object agent)
+
+			Unregisters a watcher.
+
+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.
+
+		Reset()
+
+			Restart the accumulation of energy expended from zero.
+
+			Possible Errors: org.bluez.Error.NotSupported
+
+Properties	String Location (optional) [readonly]
+
+			Possible values: "Other", "Chest", "Wrist","Finger",
+					"Hand", "Earlobe", "Foot"
+
+		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(object device, dict measurement)
+
+			This callback is called whenever a heart rate
+			measurement is received from the heart rate device.
+
+			Measurement:
+
+				uint16 Value:
+
+					Measurement value expressed in beats per
+					minute (bpm)
+
+				uint16 Energy (optional):
+
+					Accumulated energy expended in kilo Joules
+
+				boolean Contact (optional):
+
+					true if skin contact is detected by sensor,
+					false otherwise
+
+				array{uint16} Interval (optional):
+
+					RR-Interval values which represent the time
+					between two consecutive R waves in an ECG.
+					Values are ordered starting from oldest to
+					most recent.
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v5 00/17] Heart Rate Profile plugin
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Hi,

Here's v5 which is what v4 should be.


Andrzej Kaczmarek (6):
  heartrate: Add attio callbacks
  heartrate: Enable measurement when watchers are registered
  heartrate: Read Heart Rate Control Point characteristics
  heartrate: Handle characteristics value changed notification
  heartrate: Process Heart Rate Measurement characteristics
  heartrate: Add Reset method

Rafal Garbat (10):
  heartrate: Add Heart Rate Profile client
  heartrate: Discover characteristics
  heartrate: Process characteristics
  heartrate: Discover characteristics descriptors
  heartrate: Process characteristics descriptors
  heartrate: Add HeartRateManager interface
  heartrate: Read Body Sensor Location characteristics
  heartrate: Add GetProperties method
  heartrate: Add HeartRateWatcher interface to default policy
  heartrate: Add test script

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

 Makefile.am                    |   9 +-
 Makefile.tools                 |   4 +-
 doc/heartrate-api.txt          |  84 ++++
 lib/uuid.h                     |   5 +
 profiles/heartrate/heartrate.c | 971 +++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |  27 ++
 profiles/heartrate/main.c      |  52 +++
 profiles/heartrate/manager.c   |  96 ++++
 profiles/heartrate/manager.h   |  24 +
 src/bluetooth.conf             |   1 +
 test/test-heartrate            | 103 +++++
 11 files changed, 1372 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.11.3


^ permalink raw reply

* [PATCH obexd v1 3/3] MAP: Add set delete status function
From: Sunil Kumar Behera @ 2012-09-13 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sunil Kumar Behera

This function will inform MAP server to modify
the delete status of a given message.
---
 plugins/mas.c              |   18 ++++++++++++++++++
 plugins/messages-dummy.c   |    7 +++++++
 plugins/messages-tracker.c |    7 +++++++
 plugins/messages.h         |   15 +++++++++++++++
 4 files changed, 47 insertions(+)

diff --git a/plugins/mas.c b/plugins/mas.c
index 14e7478..735c02d 100644
--- a/plugins/mas.c
+++ b/plugins/mas.c
@@ -47,6 +47,7 @@
 #include "messages.h"
 
 #define READ_STATUS_REQ 0
+#define DELETE_STATUS_REQ 1
 
 /* Channel number according to bluez doc/assigned-numbers.txt */
 #define MAS_CHANNEL	16
@@ -515,6 +516,20 @@ static void set_read_status_cb(void *session, int err, void *user_data)
 		obex_object_set_io_flags(mas, G_IO_OUT, 0);
 }
 
+static void set_delete_status_cb(void *session, int err, void *user_data)
+{
+	struct mas_session *mas = user_data;
+
+	DBG("");
+
+	mas->finished = TRUE;
+
+	if (err < 0)
+		obex_object_set_io_flags(mas, G_IO_ERR, err);
+	else
+		obex_object_set_io_flags(mas, G_IO_OUT, 0);
+}
+
 static int mas_setpath(struct obex_session *os, void *user_data)
 {
 	const char *name;
@@ -696,6 +711,9 @@ static void *message_set_status_open(const char *name, int oflag, mode_t mode,
 	if (indicator == READ_STATUS_REQ)
 		*err = messages_set_read(mas->backend_data, name, value,
 						set_read_status_cb, mas);
+	else if (indicator == DELETE_STATUS_REQ)
+		*err = messages_set_delete(mas->backend_data, name, value,
+						set_delete_status_cb, mas);
 	else
 		*err = -EBADR;
 
diff --git a/plugins/messages-dummy.c b/plugins/messages-dummy.c
index 78e20ae..e498784 100644
--- a/plugins/messages-dummy.c
+++ b/plugins/messages-dummy.c
@@ -359,6 +359,13 @@ int messages_set_read(void *session, const char *handle, uint8_t value,
 	return -ENOSYS;
 }
 
+int messages_set_delete(void *session, const char *handle, uint8_t value,
+					messages_set_delete_cb callback,
+					void *user_data)
+{
+	return -ENOSYS;
+}
+
 void messages_abort(void *s)
 {
 	struct session *session = s;
diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index 1516dc7..2c7541b 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -333,6 +333,13 @@ int messages_set_read(void *session, const char *handle, uint8_t value,
 	return -ENOSYS;
 }
 
+int messages_set_delete(void *session, const char *handle, uint8_t value,
+					messages_set_delete_cb callback,
+					void *user_data)
+{
+	return -ENOSYS;
+}
+
 void messages_abort(void *session)
 {
 }
diff --git a/plugins/messages.h b/plugins/messages.h
index 45579d3..a514514 100644
--- a/plugins/messages.h
+++ b/plugins/messages.h
@@ -293,6 +293,21 @@ typedef void (*messages_set_read_cb)(void *session, int err, void *user_data);
 int messages_set_read(void *session, const char *handle, uint8_t value,
 				messages_set_read_cb callback, void *user_data);
 
+/* Informs Message Server to modify delete status of a given message.
+ *
+ * session: Backend session.
+ * handle: Unique identifier to the message.
+ * value: Indicates the new value of the delete status for a given message.
+ * Callback shall be called for every delete status update request
+ *	recieved from MCE.
+ * user_data: User data if any to be sent.
+ */
+typedef void (*messages_set_delete_cb)(void *session, int err, void *user_data);
+
+int messages_set_delete(void *session, const char *handle, uint8_t value,
+					messages_set_delete_cb callback,
+					void *user_data);
+
 /* Aborts currently pending request.
  *
  * session: Backend session.
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH obexd v1 2/3] MAP: Add set read status function
From: Sunil Kumar Behera @ 2012-09-13 13:43 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sunil Kumar Behera

This function will inform MAP server to modify the
read status of a given message.
---
 plugins/mas.c              |   25 +++++++++++++++++++++++++
 plugins/messages-dummy.c   |    6 ++++++
 plugins/messages-tracker.c |    6 ++++++
 plugins/messages.h         |   13 +++++++++++++
 4 files changed, 50 insertions(+)

diff --git a/plugins/mas.c b/plugins/mas.c
index f2ff9e6..14e7478 100644
--- a/plugins/mas.c
+++ b/plugins/mas.c
@@ -46,6 +46,8 @@
 
 #include "messages.h"
 
+#define READ_STATUS_REQ 0
+
 /* Channel number according to bluez doc/assigned-numbers.txt */
 #define MAS_CHANNEL	16
 
@@ -499,6 +501,20 @@ static void update_inbox_cb(void *session, int err, void *user_data)
 		obex_object_set_io_flags(mas, G_IO_OUT, 0);
 }
 
+static void set_read_status_cb(void *session, int err, void *user_data)
+{
+	struct mas_session *mas = user_data;
+
+	DBG("");
+
+	mas->finished = TRUE;
+
+	if (err < 0)
+		obex_object_set_io_flags(mas, G_IO_ERR, err);
+	else
+		obex_object_set_io_flags(mas, G_IO_OUT, 0);
+}
+
 static int mas_setpath(struct obex_session *os, void *user_data)
 {
 	const char *name;
@@ -677,6 +693,15 @@ static void *message_set_status_open(const char *name, int oflag, mode_t mode,
 		return NULL;
 	}
 
+	if (indicator == READ_STATUS_REQ)
+		*err = messages_set_read(mas->backend_data, name, value,
+						set_read_status_cb, mas);
+	else
+		*err = -EBADR;
+
+	if (*err < 0)
+		return NULL;
+
 	return mas;
 }
 
diff --git a/plugins/messages-dummy.c b/plugins/messages-dummy.c
index a47f143..78e20ae 100644
--- a/plugins/messages-dummy.c
+++ b/plugins/messages-dummy.c
@@ -353,6 +353,12 @@ int messages_update_inbox(void *session, messages_update_inbox_cb callback,
 	return -ENOSYS;
 }
 
+int messages_set_read(void *session, const char *handle, uint8_t value,
+				messages_set_read_cb callback, void *user_data)
+{
+	return -ENOSYS;
+}
+
 void messages_abort(void *s)
 {
 	struct session *session = s;
diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index 92c1767..1516dc7 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -327,6 +327,12 @@ int messages_update_inbox(void *session, messages_update_inbox_cb callback,
 	return -ENOSYS;
 }
 
+int messages_set_read(void *session, const char *handle, uint8_t value,
+				messages_set_read_cb callback, void *user_data)
+{
+	return -ENOSYS;
+}
+
 void messages_abort(void *session)
 {
 }
diff --git a/plugins/messages.h b/plugins/messages.h
index 669f7c2..45579d3 100644
--- a/plugins/messages.h
+++ b/plugins/messages.h
@@ -279,6 +279,19 @@ typedef void (*messages_update_inbox_cb)(void *session, int err,
 
 int messages_update_inbox(void *session, messages_update_inbox_cb callback,
 							void *user_data);
+/* Informs Message Server to modify read status of a given message.
+ *
+ * session: Backend session.
+ * handle: Unique identifier to the message.
+ * value: Indicates the new value of the read status for a given message.
+ * Callback shall be called for every read status update request
+ *	recieved from MCE.
+ * user_data: User data if any to be sent.
+ */
+typedef void (*messages_set_read_cb)(void *session, int err, void *user_data);
+
+int messages_set_read(void *session, const char *handle, uint8_t value,
+				messages_set_read_cb callback, void *user_data);
 
 /* Aborts currently pending request.
  *
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH obexd v1 1/3] MAP: Add binding to support SetMessageStatus function
From: Sunil Kumar Behera @ 2012-09-13 13:42 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sunil Kumar Behera

Add message_set_status_open binding in MIME driver
to support SetMessageStatus function.
---
 plugins/mas.c |   33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/plugins/mas.c b/plugins/mas.c
index 1c9199d..f2ff9e6 100644
--- a/plugins/mas.c
+++ b/plugins/mas.c
@@ -649,6 +649,37 @@ static void *message_update_open(const char *name, int oflag, mode_t mode,
 		return mas;
 }
 
+static void *message_set_status_open(const char *name, int oflag, mode_t mode,
+					void *driver_data, size_t *size,
+					int *err)
+
+{
+	struct mas_session *mas = driver_data;
+	uint8_t indicator;
+	uint8_t value;
+
+	DBG("");
+
+	if (oflag == O_RDONLY) {
+		*err = -EBADR;
+		return NULL;
+	}
+
+	if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSINDICATOR,
+					&indicator)) {
+		*err = -EBADR;
+		return NULL;
+	}
+
+	if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSVALUE,
+					&value)) {
+		*err = -EBADR;
+		return NULL;
+	}
+
+	return mas;
+}
+
 static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
 								uint8_t *hi)
 {
@@ -784,7 +815,7 @@ static struct obex_mime_type_driver mime_message_status = {
 	.target = MAS_TARGET,
 	.target_size = TARGET_SIZE,
 	.mimetype = "x-bt/messageStatus",
-	.open = any_open,
+	.open = message_set_status_open,
 	.close = any_close,
 	.read = any_read,
 	.write = any_write,
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH v4 00/17] Heart Rate Profile plugin
From: Andrzej Kaczmarek @ 2012-09-13 13:35 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org
In-Reply-To: <1347538401-6417-1-git-send-email-andrzej.kaczmarek@tieto.com>

Hi again,

On 09/13/2012 02:13 PM, Kaczmarek Andrzej wrote:
> Hi,
>
> Changes since v3:
> * rebased due to profile code moved to separate files
>
<snip>

Please ignore v4, I rebased older version of patches by mistake. Will 
send proper v5 shortly.

BR,
Andrzej

^ permalink raw reply

* Re: [PATCH] Add support for Logitech Harmony Adapter for PS3
From: David Dillow @ 2012-09-13 13:26 UTC (permalink / raw)
  To: Antonio Ospite
  Cc: David Herrmann, Luiz Augusto von Dentz, Bastien Nocera,
	linux-bluetooth
In-Reply-To: <20120913003628.ce5babb2a66d09fe17fa15de@studenti.unina.it>

On Thu, 2012-09-13 at 00:36 +0200, Antonio Ospite wrote:
> I too will take a look during the week-end about writing a kernel
> driver, if it's not that much of an effort I might take the project
> (no promises yet). I have a PS3 BD remote Bastien donated.
> 
> David AFAICS from profiles/input/fakehid.c[1], a custom report has to be
> decoded and appropriate input events have to be sent.

I spent some time last night, and have made some progress in
understanding the HID layer. I'm fixing up the report descriptor and
massaging the raw packets to match in an effort to use the common input
code. evtest isn't showing output yet, but I think I'm close.

I only have the Logitech adapter, which does not seem to need the
bitmask handling in fakehid.c -- could you
watch /sys/kernel/debug/hid/0005:*/events while pressing the buttons
that are listed in the ps3remote_bits list -- looks like back/circle,
cross, triangle (options), etc. I'm guessing those are needed for some
devices, but the Harmony adapter just sends the codes needed in
ps3remote_keymap, so it doesn't seem I need to care about the bitmap,
except I'm sure it was done for a reason...

Thanks,
Dave


^ permalink raw reply

* [PATCH obexd 8/8] client: Avoid extra copies while passing apparam to transfer
From: Luiz Augusto von Dentz @ 2012-09-13 13:07 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1347541621-26858-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

By passing directly the reference to GObexApparam it is no longer
necessary to use intermediate buffers to pass data around.
---
 client/map.c      | 29 ++++++++---------------
 client/pbap.c     | 42 +++++++++++----------------------
 client/transfer.c | 69 +++++++++++++++++++------------------------------------
 client/transfer.h |  6 ++---
 4 files changed, 47 insertions(+), 99 deletions(-)

diff --git a/client/map.c b/client/map.c
index 4b5f8a2..e78cd68 100644
--- a/client/map.c
+++ b/client/map.c
@@ -248,17 +248,14 @@ static DBusMessage *get_folder_listing(struct map_data *map,
 	struct obc_transfer *transfer;
 	GError *err = NULL;
 	DBusMessage *reply;
-	guint8 buf[8];
-	gsize len;
-
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-	g_obex_apparam_free(apparam);
 
 	transfer = obc_transfer_get("x-obex/folder-listing", NULL, NULL, &err);
-	if (transfer == NULL)
+	if (transfer == NULL) {
+		g_obex_apparam_free(apparam);
 		goto fail;
+	}
 
-	obc_transfer_set_params(transfer, buf, len);
+	obc_transfer_set_apparam(transfer, apparam);
 
 	if (obc_session_queue(map->session, transfer, folder_listing_cb, map,
 								&err)) {
@@ -383,8 +380,6 @@ static DBusMessage *map_msg_get(DBusConnection *connection,
 	GError *err = NULL;
 	DBusMessage *reply;
 	GObexApparam *apparam;
-	guint8 buf[6];
-	gsize len;
 
 	if (dbus_message_get_args(message, NULL,
 				DBUS_TYPE_STRING, &target_file,
@@ -402,11 +397,8 @@ static DBusMessage *map_msg_get(DBusConnection *connection,
 								attachment);
 	apparam = g_obex_apparam_set_uint8(apparam, MAP_AP_CHARSET,
 								CHARSET_UTF8);
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-
-	obc_transfer_set_params(transfer, buf, len);
 
-	g_obex_apparam_free(apparam);
+	obc_transfer_set_apparam(transfer, apparam);
 
 	if (!obc_session_queue(msg->data->session, transfer, NULL, NULL, &err))
 		goto fail;
@@ -739,17 +731,14 @@ static DBusMessage *get_message_listing(struct map_data *map,
 	struct obc_transfer *transfer;
 	GError *err = NULL;
 	DBusMessage *reply;
-	guint8 buf[1024];
-	gsize len;
-
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-	g_obex_apparam_free(apparam);
 
 	transfer = obc_transfer_get("x-bt/MAP-msg-listing", folder, NULL, &err);
-	if (transfer == NULL)
+	if (transfer == NULL) {
+		g_obex_apparam_free(apparam);
 		goto fail;
+	}
 
-	obc_transfer_set_params(transfer, buf, len);
+	obc_transfer_set_apparam(transfer, apparam);
 
 	if (obc_session_queue(map->session, transfer, message_listing_cb, map,
 								&err)) {
diff --git a/client/pbap.c b/client/pbap.c
index a8db1cf..ea4a023 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -250,17 +250,11 @@ static void read_return_apparam(struct obc_transfer *transfer,
 				guint16 *phone_book_size, guint8 *new_missed_calls)
 {
 	GObexApparam *apparam;
-	const guint8 *data;
-	size_t size;
 
 	*phone_book_size = 0;
 	*new_missed_calls = 0;
 
-	data = obc_transfer_get_params(transfer, &size);
-	if (data == NULL)
-		return;
-
-	apparam = g_obex_apparam_decode(data, size);
+	apparam = obc_transfer_get_apparam(transfer);
 	if (apparam == NULL)
 		return;
 
@@ -269,7 +263,6 @@ static void read_return_apparam(struct obc_transfer *transfer,
 	g_obex_apparam_get_uint8(apparam, NEWMISSEDCALLS_TAG,
 							new_missed_calls);
 
-
 	g_obex_apparam_free(apparam);
 }
 
@@ -533,20 +526,17 @@ static DBusMessage *pull_phonebook(struct pbap_data *pbap,
 	struct pending_request *request;
 	struct obc_transfer *transfer;
 	char *name;
-	guint8 buf[32];
-	gsize len;
 	session_callback_t func;
 	DBusMessage *reply;
 	GError *err = NULL;
 
 	name = g_strconcat(pbap->path, ".vcf", NULL);
 
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-	g_obex_apparam_free(apparam);
-
 	transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, &err);
-	if (transfer == NULL)
+	if (transfer == NULL) {
+		g_obex_apparam_free(apparam);
 		goto fail;
+	}
 
 	switch (type) {
 	case PULLPHONEBOOK:
@@ -562,7 +552,7 @@ static DBusMessage *pull_phonebook(struct pbap_data *pbap,
 		return NULL;
 	}
 
-	obc_transfer_set_params(transfer, buf, len);
+	obc_transfer_set_apparam(transfer, apparam);
 
 	if (!obc_session_queue(pbap->session, transfer, func, request, &err)) {
 		if (request != NULL)
@@ -592,19 +582,16 @@ static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
 {
 	struct pending_request *request;
 	struct obc_transfer *transfer;
-	guint8 buf[272];
-	gsize len;
 	GError *err = NULL;
 	DBusMessage *reply;
 
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-	g_obex_apparam_free(apparam);
-
 	transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
-	if (transfer == NULL)
+	if (transfer == NULL) {
+		g_obex_apparam_free(apparam);
 		goto fail;
+	}
 
-	obc_transfer_set_params(transfer, buf, len);
+	obc_transfer_set_apparam(transfer, apparam);
 
 	request = pending_request_new(pbap, message);
 	if (obc_session_queue(pbap->session, transfer,
@@ -711,17 +698,14 @@ static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
 	struct obc_transfer *transfer;
 	DBusMessage *reply;
 	GError *err = NULL;
-	guint8 buf[32];
-	gsize len;
-
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-	g_obex_apparam_free(apparam);
 
 	transfer = obc_transfer_get("x-bt/vcard", name, targetfile, &err);
-	if (transfer == NULL)
+	if (transfer == NULL) {
+		g_obex_apparam_free(apparam);
 		goto fail;
+	}
 
-	obc_transfer_set_params(transfer, buf, len);
+	obc_transfer_set_apparam(transfer, apparam);
 
 	if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
 		goto fail;
diff --git a/client/transfer.c b/client/transfer.c
index e9fabfb..bd5277b 100644
--- a/client/transfer.c
+++ b/client/transfer.c
@@ -57,15 +57,10 @@ struct transfer_callback {
 	void *data;
 };
 
-struct obc_transfer_params {
-	void *data;
-	size_t size;
-};
-
 struct obc_transfer {
 	GObex *obex;
+	GObexApparam *apparam;
 	guint8 op;
-	struct obc_transfer_params *params;
 	struct transfer_callback *callback;
 	DBusConnection *conn;
 	DBusMessage *msg;
@@ -273,10 +268,8 @@ static void obc_transfer_free(struct obc_transfer *transfer)
 	if (transfer->fd > 0)
 		close(transfer->fd);
 
-	if (transfer->params != NULL) {
-		g_free(transfer->params->data);
-		g_free(transfer->params);
-	}
+	if (transfer->apparam != NULL)
+		g_obex_apparam_free(transfer->apparam);
 
 	if (transfer->conn)
 		dbus_connection_unref(transfer->conn);
@@ -529,6 +522,7 @@ static void get_xfer_progress_first(GObex *obex, GError *err, GObexPacket *rsp,
 	struct obc_transfer *transfer = user_data;
 	GObexPacket *req;
 	GObexHeader *hdr;
+	GObexApparam *apparam;
 	const guint8 *buf;
 	gsize len;
 	guint8 rspcode;
@@ -550,17 +544,9 @@ static void get_xfer_progress_first(GObex *obex, GError *err, GObexPacket *rsp,
 
 	hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_APPARAM);
 	if (hdr) {
-		g_obex_header_get_bytes(hdr, &buf, &len);
-		if (len != 0) {
-			if (transfer->params == NULL)
-				transfer->params =
-					g_new0(struct obc_transfer_params, 1);
-			else
-				g_free(transfer->params->data);
-
-			transfer->params->data = g_memdup(buf, len);
-			transfer->params->size = len;
-		}
+		apparam = g_obex_header_get_apparam(hdr);
+		if (apparam != NULL)
+			obc_transfer_set_apparam(transfer, apparam);
 	}
 
 	hdr = g_obex_packet_get_body(rsp);
@@ -642,6 +628,7 @@ static gboolean report_progress(gpointer data)
 static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
 {
 	GObexPacket *req;
+	GObexHeader *hdr;
 
 	if (transfer->xfer > 0) {
 		g_set_error(err, OBC_TRANSFER_ERROR, -EALREADY,
@@ -659,10 +646,10 @@ static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
 		g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type,
 						strlen(transfer->type) + 1);
 
-	if (transfer->params != NULL)
-		g_obex_packet_add_bytes(req, G_OBEX_HDR_APPARAM,
-						transfer->params->data,
-						transfer->params->size);
+	if (transfer->apparam != NULL) {
+		hdr = g_obex_header_new_apparam(transfer->apparam);
+		g_obex_packet_add_header(req, hdr);
+	}
 
 	transfer->xfer = g_obex_send_req(transfer->obex, req,
 						FIRST_PACKET_TIMEOUT,
@@ -683,6 +670,7 @@ static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
 static gboolean transfer_start_put(struct obc_transfer *transfer, GError **err)
 {
 	GObexPacket *req;
+	GObexHeader *hdr;
 
 	if (transfer->xfer > 0) {
 		g_set_error(err, OBC_TRANSFER_ERROR, -EALREADY,
@@ -703,10 +691,10 @@ static gboolean transfer_start_put(struct obc_transfer *transfer, GError **err)
 	if (transfer->size < UINT32_MAX)
 		g_obex_packet_add_uint32(req, G_OBEX_HDR_LENGTH, transfer->size);
 
-	if (transfer->params != NULL)
-		g_obex_packet_add_bytes(req, G_OBEX_HDR_APPARAM,
-						transfer->params->data,
-						transfer->params->size);
+	if (transfer->apparam != NULL) {
+		hdr = g_obex_header_new_apparam(transfer->apparam);
+		g_obex_packet_add_header(req, hdr);
+	}
 
 	transfer->xfer = g_obex_put_req_pkt(transfer->obex, req,
 					put_xfer_progress, xfer_complete,
@@ -744,31 +732,20 @@ guint8 obc_transfer_get_operation(struct obc_transfer *transfer)
 	return transfer->op;
 }
 
-void obc_transfer_set_params(struct obc_transfer *transfer,
-						const void *data, size_t size)
+void obc_transfer_set_apparam(struct obc_transfer *transfer, void *data)
 {
-	if (transfer->params != NULL) {
-		g_free(transfer->params->data);
-		g_free(transfer->params);
-	}
+	if (transfer->apparam != NULL)
+		g_obex_apparam_free(transfer->apparam);
 
 	if (data == NULL)
 		return;
 
-	transfer->params = g_new0(struct obc_transfer_params, 1);
-	transfer->params->data = g_memdup(data, size);
-	transfer->params->size = size;
+	transfer->apparam = data;
 }
 
-const void *obc_transfer_get_params(struct obc_transfer *transfer, size_t *size)
+void *obc_transfer_get_apparam(struct obc_transfer *transfer)
 {
-	if (transfer->params == NULL)
-		return NULL;
-
-	if (size != NULL)
-		*size = transfer->params->size;
-
-	return transfer->params->data;
+	return transfer->apparam;
 }
 
 int obc_transfer_get_contents(struct obc_transfer *transfer, char **contents,
diff --git a/client/transfer.h b/client/transfer.h
index 968903a..f7d0423 100644
--- a/client/transfer.h
+++ b/client/transfer.h
@@ -50,10 +50,8 @@ gboolean obc_transfer_start(struct obc_transfer *transfer, void *obex,
 								GError **err);
 guint8 obc_transfer_get_operation(struct obc_transfer *transfer);
 
-void obc_transfer_set_params(struct obc_transfer *transfer,
-						const void *data, size_t size);
-const void *obc_transfer_get_params(struct obc_transfer *transfer,
-								size_t *size);
+void obc_transfer_set_apparam(struct obc_transfer *transfer, void *data);
+void *obc_transfer_get_apparam(struct obc_transfer *transfer);
 int obc_transfer_get_contents(struct obc_transfer *transfer, char **contents,
 								size_t *size);
 
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 7/8] test: Update map-client to work with changes in Message.Get
From: Luiz Augusto von Dentz @ 2012-09-13 13:07 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1347541621-26858-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 test/map-client | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/map-client b/test/map-client
index dbb67df..2075844 100755
--- a/test/map-client
+++ b/test/map-client
@@ -117,7 +117,7 @@ class MapClient:
 		path = self.path + "/message" + handle
 		obj = bus.get_object("org.bluez.obex.client", path)
 		msg = dbus.Interface(obj, "org.bluez.obex.Message")
-		msg.Get("",reply_handler=self.create_transfer_reply,
+		msg.Get("", True, reply_handler=self.create_transfer_reply,
 						error_handler=self.error)
 
 if  __name__ == '__main__':
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 6/8] client: Fix not sending parameters to get message in map module
From: Luiz Augusto von Dentz @ 2012-09-13 13:06 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1347541621-26858-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Attachment and charset are mandatory, so Message.Get now takes an
additional boolean parameter which the user application should set
if it wants the attachments to be downloaded, charset is always set
to UTF8.
---
 client/map.c       | 20 +++++++++++++++++++-
 doc/client-api.txt |  2 +-
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/client/map.c b/client/map.c
index cf3d8ed..4b5f8a2 100644
--- a/client/map.c
+++ b/client/map.c
@@ -53,6 +53,8 @@
 #define DEFAULT_COUNT 1024
 #define DEFAULT_OFFSET 0
 
+#define CHARSET_UTF8 1
+
 static const char * const filter_list[] = {
 	"subject",
 	"timestamp",
@@ -377,11 +379,16 @@ static DBusMessage *map_msg_get(DBusConnection *connection,
 	struct map_msg *msg = user_data;
 	struct obc_transfer *transfer;
 	const char *target_file;
+	gboolean attachment;
 	GError *err = NULL;
 	DBusMessage *reply;
+	GObexApparam *apparam;
+	guint8 buf[6];
+	gsize len;
 
 	if (dbus_message_get_args(message, NULL,
 				DBUS_TYPE_STRING, &target_file,
+				DBUS_TYPE_BOOLEAN, &attachment,
 				DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
 				ERROR_INTERFACE ".InvalidArguments", NULL);
@@ -391,6 +398,16 @@ static DBusMessage *map_msg_get(DBusConnection *connection,
 	if (transfer == NULL)
 		goto fail;
 
+	apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_ATTACHMENT,
+								attachment);
+	apparam = g_obex_apparam_set_uint8(apparam, MAP_AP_CHARSET,
+								CHARSET_UTF8);
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+
+	obc_transfer_set_params(transfer, buf, len);
+
+	g_obex_apparam_free(apparam);
+
 	if (!obc_session_queue(msg->data->session, transfer, NULL, NULL, &err))
 		goto fail;
 
@@ -405,7 +422,8 @@ fail:
 
 static const GDBusMethodTable map_msg_methods[] = {
 	{ GDBUS_METHOD("Get",
-			GDBUS_ARGS({ "targetfile", "s" }),
+			GDBUS_ARGS({ "targetfile", "s" },
+						{ "attachment", "b" }),
 			GDBUS_ARGS({ "transfer", "o" },
 						{ "properties", "a{sv}" }),
 			map_msg_get) },
diff --git a/doc/client-api.txt b/doc/client-api.txt
index f78b8fe..25fd3e4 100644
--- a/doc/client-api.txt
+++ b/doc/client-api.txt
@@ -520,7 +520,7 @@ Service		org.bluez.obex.client
 Interface	org.bluez.obex.Message
 Object path	[variable prefix]/{session0,session1,...}/{message0,...}
 
-Methods		object, dict Get(string targetfile)
+Methods		object, dict Get(string targetfile, boolean attachment)
 
 			Download message and store it in the target file.
 
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 5/8] test: Update map-client to work with changes in MessageAccess interface
From: Luiz Augusto von Dentz @ 2012-09-13 13:06 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1347541621-26858-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 test/map-client | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/test/map-client b/test/map-client
index ac1a8ca..dbb67df 100755
--- a/test/map-client
+++ b/test/map-client
@@ -105,15 +105,15 @@ class MapClient:
 		self.map.SetFolder(new_dir)
 
 	def list_folders(self):
-		for i in self.map.GetFolderListing(dict()):
+		for i in self.map.ListFolders(dict()):
 			print "%s/" % (i["Name"])
 
 	def list_messages(self, folder):
-		ret = self.map.GetMessageListing(folder, dict())
+		ret = self.map.ListMessages(folder, dict())
 		print pformat(unwrap(ret))
 
 	def get_message(self, handle):
-		self.map.GetMessageListing("", dict())
+		self.map.ListMessages("", dict())
 		path = self.path + "/message" + handle
 		obj = bus.get_object("org.bluez.obex.client", path)
 		msg = dbus.Interface(obj, "org.bluez.obex.Message")
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 4/8] client-doc: Update documentation of MessageAccess interface
From: Luiz Augusto von Dentz @ 2012-09-13 13:06 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1347541621-26858-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 doc/client-api.txt | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 66 insertions(+), 3 deletions(-)

diff --git a/doc/client-api.txt b/doc/client-api.txt
index f447789..f78b8fe 100644
--- a/doc/client-api.txt
+++ b/doc/client-api.txt
@@ -368,7 +368,7 @@ Methods		void SetFolder(string name)
 			Set working directory for current session, *name* may
 			be the directory name or '..[/dir]'.
 
-		array{dict} GetFolderListing(dict filter)
+		array{dict} ListFolders(dict filter)
 
 			Returns a dictionary containing information about
 			the current folder content.
@@ -377,12 +377,22 @@ Methods		void SetFolder(string name)
 
 				string Name : Folder name
 
-		array{object, dict} GetMessageListing(string folder,
-								dict filter)
+			Possible filters: Offset and MaxCount
+
+		array{string} ListFilterFields()
+
+			Return all available fields that can be used in Fields
+			filter.
+
+		array{object, dict} ListMessages(string folder, dict filter)
 
 			Returns an array containing the messages found in the
 			given folder.
 
+			Possible Filters: Offset, MaxCount, Fields, Type,
+			PeriodStart, PeriodEnd, Status, Recipient, Sender,
+			Priority
+
 			Each message is represented by an object path followed
 			by a dictionary of the properties.
 
@@ -450,6 +460,59 @@ Methods		void SetFolder(string name)
 
 					Message protected flag
 
+Filter:		uint16 Offset:
+
+			Offset of the first item, default is 0
+
+		uint16 MaxCount:
+
+			Maximum number of items, default is 1024
+
+		array{string} Fields:
+
+			Message fields, default is all values.
+
+			Possible values can be query with ListFilterFields.
+
+		array{string} Types:
+
+			Filter messages by type.
+
+			Possible values: "sms", "email", "mms".
+
+		string PeriodBegin:
+
+			Filter messages by starting period.
+
+			Possible values: Date in "YYYYMMDDTHHMMSS" format.
+
+		string PeriodEnd:
+
+			Filter messages by ending period.
+
+			Possible values: Date in "YYYYMMDDTHHMMSS" format.
+
+		boolean Read:
+
+			Filter messages by read flag.
+
+			Possible values: True for read or False for unread
+
+		string Recipient:
+
+			Filter messages by recipient address.
+
+		string Sender:
+
+			Filter messages by sender address.
+
+		gboolean Priority:
+
+			Filter messages by priority flag.
+
+			Possible values: True for high priority or False for
+			non-high priority
+
 Message hierarchy
 =================
 
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 3/8] client: Add MessageAccess.ListFilterFields
From: Luiz Augusto von Dentz @ 2012-09-13 13:06 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1347541621-26858-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 client/map.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/client/map.c b/client/map.c
index 6d1b0f2..cf3d8ed 100644
--- a/client/map.c
+++ b/client/map.c
@@ -1011,6 +1011,41 @@ static DBusMessage *map_list_messages(DBusConnection *connection,
 	return get_message_listing(map, message, folder, apparam);
 }
 
+static gchar **get_filter_strs(uint64_t filter, gint *size)
+{
+	gchar **list, **item;
+	gint i;
+
+	list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
+
+	item = list;
+
+	for (i = 0; filter_list[i] != NULL; i++)
+		if (filter & (1ULL << i))
+			*(item++) = g_strdup(filter_list[i]);
+
+	*item = NULL;
+	*size = item - list;
+	return list;
+}
+
+static DBusMessage *map_list_filter_fields(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	gchar **filters = NULL;
+	gint size;
+	DBusMessage *reply;
+
+	filters = get_filter_strs(FILTER_ALL, &size);
+	reply = dbus_message_new_method_return(message);
+	dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
+				DBUS_TYPE_STRING, &filters, size,
+				DBUS_TYPE_INVALID);
+
+	g_strfreev(filters);
+	return reply;
+}
+
 static const GDBusMethodTable map_methods[] = {
 	{ GDBUS_ASYNC_METHOD("SetFolder",
 				GDBUS_ARGS({ "name", "s" }), NULL,
@@ -1023,6 +1058,10 @@ static const GDBusMethodTable map_methods[] = {
 			GDBUS_ARGS({ "folder", "s" }, { "filter", "a{sv}" }),
 			GDBUS_ARGS({ "messages", "a{oa{sv}}" }),
 			map_list_messages) },
+	{ GDBUS_METHOD("ListFilterFields",
+			NULL,
+			GDBUS_ARGS({ "fields", "as" }),
+			map_list_filter_fields) },
 	{ }
 };
 
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 2/8] client: Rename MessageAccess method GetMessagesListing to ListMessages
From: Luiz Augusto von Dentz @ 2012-09-13 13:06 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1347541621-26858-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

In addition to that add missing parsing of the filters
---
 client/map.c | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 302 insertions(+), 15 deletions(-)

diff --git a/client/map.c b/client/map.c
index a7bdf08..6d1b0f2 100644
--- a/client/map.c
+++ b/client/map.c
@@ -26,6 +26,7 @@
 
 #include <errno.h>
 #include <string.h>
+#include <stdio.h>
 #include <glib.h>
 #include <gdbus.h>
 
@@ -52,6 +53,29 @@
 #define DEFAULT_COUNT 1024
 #define DEFAULT_OFFSET 0
 
+static const char * const filter_list[] = {
+	"subject",
+	"timestamp",
+	"sender",
+	"sender-address",
+	"recipient",
+	"recipient-address",
+	"type",
+	"size",
+	"status",
+	"text",
+	"attachment",
+	"priority",
+	"read",
+	"sent",
+	"protected",
+	"replyto",
+	NULL
+};
+
+#define FILTER_BIT_MAX	15
+#define FILTER_ALL	0xFF
+
 struct map_data {
 	struct obc_session *session;
 	DBusMessage *msg;
@@ -689,28 +713,26 @@ done:
 	dbus_message_unref(map->msg);
 }
 
-static DBusMessage *map_get_message_listing(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
+static DBusMessage *get_message_listing(struct map_data *map,
+							DBusMessage *message,
+							const char *folder,
+							GObexApparam *apparam)
 {
-	struct map_data *map = user_data;
 	struct obc_transfer *transfer;
-	const char *folder;
-	DBusMessageIter msg_iter;
 	GError *err = NULL;
 	DBusMessage *reply;
+	guint8 buf[1024];
+	gsize len;
 
-	dbus_message_iter_init(message, &msg_iter);
-
-	if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING)
-		return g_dbus_create_error(message,
-				ERROR_INTERFACE ".InvalidArguments", NULL);
-
-	dbus_message_iter_get_basic(&msg_iter, &folder);
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	g_obex_apparam_free(apparam);
 
 	transfer = obc_transfer_get("x-bt/MAP-msg-listing", folder, NULL, &err);
 	if (transfer == NULL)
 		goto fail;
 
+	obc_transfer_set_params(transfer, buf, len);
+
 	if (obc_session_queue(map->session, transfer, message_listing_cb, map,
 								&err)) {
 		map->msg = dbus_message_ref(message);
@@ -724,6 +746,271 @@ fail:
 	return reply;
 }
 
+static uint64_t get_filter_mask(const char *filterstr)
+{
+	int i;
+
+	if (!filterstr)
+		return 0;
+
+	if (!g_ascii_strcasecmp(filterstr, "ALL"))
+		return FILTER_ALL;
+
+	for (i = 0; filter_list[i] != NULL; i++)
+		if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
+			return 1ULL << i;
+
+	return 0;
+}
+
+static int set_field(guint32 *filter, const char *filterstr)
+{
+	guint64 mask;
+
+	mask = get_filter_mask(filterstr);
+
+	if (mask == 0)
+		return -EINVAL;
+
+	*filter |= mask;
+	return 0;
+}
+
+static GObexApparam *parse_fields(GObexApparam *apparam, DBusMessageIter *iter)
+{
+	DBusMessageIter array;
+	guint32 filter = 0;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return NULL;
+
+	dbus_message_iter_recurse(iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+		const char *string;
+
+		dbus_message_iter_get_basic(&array, &string);
+
+		if (set_field(&filter, string) < 0)
+			return NULL;
+
+		dbus_message_iter_next(&array);
+	}
+
+	return g_obex_apparam_set_uint32(apparam, MAP_AP_PARAMETERMASK,
+								filter);
+}
+
+static GObexApparam *parse_filter_type(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	DBusMessageIter array;
+	guint8 types = 0;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return NULL;
+
+	dbus_message_iter_recurse(iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+		const char *string;
+
+		dbus_message_iter_get_basic(&array, &string);
+
+		if (!g_ascii_strcasecmp(string, "sms"))
+			types |= 0x03; /* SMS_GSM and SMS_CDMA */
+		else if (!g_ascii_strcasecmp(string, "email"))
+			types |= 0x04; /* EMAIL */
+		else if (!g_ascii_strcasecmp(string, "mms"))
+			types |= 0x08; /* MMS */
+		else
+			return NULL;
+	}
+
+	return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERMESSAGETYPE,
+									types);
+}
+
+static GObexApparam *parse_period_begin(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	const char *string;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &string);
+
+	return g_obex_apparam_set_string(apparam, MAP_AP_FILTERPERIODBEGIN,
+								string);
+}
+
+static GObexApparam *parse_period_end(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	const char *string;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &string);
+
+	return g_obex_apparam_set_string(apparam, MAP_AP_FILTERPERIODEND,
+								string);
+}
+
+static GObexApparam *parse_filter_read(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	guint8 status = 0;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &status);
+
+	status = (status) ? 0x01 : 0x02;
+
+	return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERREADSTATUS,
+								status);
+}
+
+static GObexApparam *parse_filter_recipient(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	const char *string;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &string);
+
+	return g_obex_apparam_set_string(apparam, MAP_AP_FILTERRECIPIENT,
+								string);
+}
+
+static GObexApparam *parse_filter_sender(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	const char *string;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &string);
+
+	return g_obex_apparam_set_string(apparam, MAP_AP_FILTERORIGINATOR,
+								string);
+}
+
+static GObexApparam *parse_filter_priority(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	guint8 priority;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &priority);
+
+	priority = (priority) ? 0x01 : 0x02;
+
+	return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERPRIORITY,
+								priority);
+}
+
+static GObexApparam *parse_message_filters(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	DBusMessageIter array;
+
+	DBG("");
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return NULL;
+
+	dbus_message_iter_recurse(iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+		const char *key;
+		DBusMessageIter value, entry;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
+
+		if (strcasecmp(key, "Offset") == 0) {
+			if (parse_offset(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "MaxCount") == 0) {
+			if (parse_max_count(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Fields") == 0) {
+			if (parse_fields(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Types") == 0) {
+			if (parse_filter_type(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "PeriodBegin") == 0) {
+			if (parse_period_begin(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "PeriodEnd") == 0) {
+			if (parse_period_end(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Read") == 0) {
+			if (parse_filter_read(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Recipient") == 0) {
+			if (parse_filter_recipient(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Sender") == 0) {
+			if (parse_filter_sender(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Priority") == 0) {
+			if (parse_filter_priority(apparam, &value) == NULL)
+				return NULL;
+		}
+
+		dbus_message_iter_next(&array);
+	}
+
+	return apparam;
+}
+
+static DBusMessage *map_list_messages(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct map_data *map = user_data;
+	const char *folder;
+	GObexApparam *apparam;
+	DBusMessageIter args;
+
+	dbus_message_iter_init(message, &args);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	dbus_message_iter_get_basic(&args, &folder);
+
+	apparam = g_obex_apparam_set_uint16(NULL, MAP_AP_MAXLISTCOUNT,
+							DEFAULT_COUNT);
+	apparam = g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET,
+							DEFAULT_OFFSET);
+
+	dbus_message_iter_next(&args);
+
+	if (parse_message_filters(apparam, &args) == NULL) {
+		g_obex_apparam_free(apparam);
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+	}
+
+	return get_message_listing(map, message, folder, apparam);
+}
+
 static const GDBusMethodTable map_methods[] = {
 	{ GDBUS_ASYNC_METHOD("SetFolder",
 				GDBUS_ARGS({ "name", "s" }), NULL,
@@ -732,10 +1019,10 @@ static const GDBusMethodTable map_methods[] = {
 			GDBUS_ARGS({ "filters", "a{sv}" }),
 			GDBUS_ARGS({ "content", "aa{sv}" }),
 			map_list_folders) },
-	{ GDBUS_ASYNC_METHOD("GetMessageListing",
-			GDBUS_ARGS({ "folder", "s" }, { "filter", "a{ss}" }),
+	{ GDBUS_ASYNC_METHOD("ListMessages",
+			GDBUS_ARGS({ "folder", "s" }, { "filter", "a{sv}" }),
 			GDBUS_ARGS({ "messages", "a{oa{sv}}" }),
-			map_get_message_listing) },
+			map_list_messages) },
 	{ }
 };
 
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 1/8] client: Rename MessageAccess method GetFolderListing to ListFolders
From: Luiz Augusto von Dentz @ 2012-09-13 13:06 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

In addition to that add missing parsing of the filters.
---
 client/map.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 102 insertions(+), 7 deletions(-)

diff --git a/client/map.c b/client/map.c
index 4f07fcb..a7bdf08 100644
--- a/client/map.c
+++ b/client/map.c
@@ -29,8 +29,11 @@
 #include <glib.h>
 #include <gdbus.h>
 
+#include <gobex-apparam.h>
+
 #include "dbus.h"
 #include "log.h"
+#include "map_ap.h"
 
 #include "map.h"
 #include "transfer.h"
@@ -46,6 +49,9 @@
 #define ERROR_INTERFACE "org.bluez.obex.Error"
 #define MAS_UUID "00001132-0000-1000-8000-00805f9b34fb"
 
+#define DEFAULT_COUNT 1024
+#define DEFAULT_OFFSET 0
+
 struct map_data {
 	struct obc_session *session;
 	DBusMessage *msg;
@@ -209,18 +215,25 @@ done:
 	dbus_message_unref(map->msg);
 }
 
-static DBusMessage *map_get_folder_listing(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
+static DBusMessage *get_folder_listing(struct map_data *map,
+							DBusMessage *message,
+							GObexApparam *apparam)
 {
-	struct map_data *map = user_data;
 	struct obc_transfer *transfer;
 	GError *err = NULL;
 	DBusMessage *reply;
+	guint8 buf[8];
+	gsize len;
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	g_obex_apparam_free(apparam);
 
 	transfer = obc_transfer_get("x-obex/folder-listing", NULL, NULL, &err);
 	if (transfer == NULL)
 		goto fail;
 
+	obc_transfer_set_params(transfer, buf, len);
+
 	if (obc_session_queue(map->session, transfer, folder_listing_cb, map,
 								&err)) {
 		map->msg = dbus_message_ref(message);
@@ -234,6 +247,88 @@ fail:
 	return reply;
 }
 
+static GObexApparam *parse_offset(GObexApparam *apparam, DBusMessageIter *iter)
+{
+	guint16 num;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &num);
+
+	return g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET, num);
+}
+
+static GObexApparam *parse_max_count(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	guint16 num;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &num);
+
+	return g_obex_apparam_set_uint16(apparam, MAP_AP_MAXLISTCOUNT, num);
+}
+
+static GObexApparam *parse_folder_filters(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	DBusMessageIter array;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return NULL;
+
+	dbus_message_iter_recurse(iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+		const char *key;
+		DBusMessageIter value, entry;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
+
+		if (strcasecmp(key, "Offset") == 0) {
+			if (parse_offset(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "MaxCount") == 0) {
+			if (parse_max_count(apparam, &value) == NULL)
+				return NULL;
+		}
+
+		dbus_message_iter_next(&array);
+	}
+
+	return apparam;
+}
+
+static DBusMessage *map_list_folders(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct map_data *map = user_data;
+	GObexApparam *apparam;
+	DBusMessageIter args;
+
+	dbus_message_iter_init(message, &args);
+
+	apparam = g_obex_apparam_set_uint16(NULL, MAP_AP_MAXLISTCOUNT,
+							DEFAULT_COUNT);
+	apparam = g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET,
+							DEFAULT_OFFSET);
+
+	if (parse_folder_filters(apparam, &args) == NULL) {
+		g_obex_apparam_free(apparam);
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+	}
+
+	return get_folder_listing(map, message, apparam);
+}
+
 static void map_msg_free(void *data)
 {
 	struct map_msg *msg = data;
@@ -633,10 +728,10 @@ static const GDBusMethodTable map_methods[] = {
 	{ GDBUS_ASYNC_METHOD("SetFolder",
 				GDBUS_ARGS({ "name", "s" }), NULL,
 				map_setpath) },
-	{ GDBUS_ASYNC_METHOD("GetFolderListing",
-					GDBUS_ARGS({ "filter", "a{ss}" }),
-					GDBUS_ARGS({ "content", "aa{sv}" }),
-					map_get_folder_listing) },
+	{ GDBUS_ASYNC_METHOD("ListFolders",
+			GDBUS_ARGS({ "filters", "a{sv}" }),
+			GDBUS_ARGS({ "content", "aa{sv}" }),
+			map_list_folders) },
 	{ GDBUS_ASYNC_METHOD("GetMessageListing",
 			GDBUS_ARGS({ "folder", "s" }, { "filter", "a{ss}" }),
 			GDBUS_ARGS({ "messages", "a{oa{sv}}" }),
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH v2 10/10] battery: Support persistent battery level
From: chen.ganir @ 2012-09-13 13:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347541403-11780-1-git-send-email-chen.ganir@ti.com>

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

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

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 355c7b4..6808f1e 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -27,6 +27,8 @@
 #include <glib.h>
 #include <bluetooth/uuid.h>
 #include <stdbool.h>
+#include <sys/file.h>
+#include <stdlib.h>
 
 #include "adapter.h"
 #include "device.h"
@@ -37,6 +39,10 @@
 #include "gatt.h"
 #include "battery.h"
 #include "log.h"
+#include "storage.h"
+
+#define BATTERY_KEY_FORMAT	"%17s#%04X"
+#define BATTERY_LEVEL_FORMAT	"%03d"
 
 struct battery {
 	struct btd_device	*dev;		/* Device reference */
@@ -77,10 +83,103 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static inline int create_filename(char *buf, size_t size,
+				const bdaddr_t *bdaddr, const char *name)
+{
+	char addr[18];
+
+	ba2str(bdaddr, addr);
+
+	return create_name(buf, size, STORAGEDIR, addr, name);
+}
+
+static int store_battery_char(struct characteristic *chr)
+{
+	char filename[PATH_MAX + 1], addr[18], key[23];
+	bdaddr_t sba, dba;
+	char level[4];
+
+	adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+	device_get_address(chr->batt->dev, &dba, NULL);
+
+	create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+	ba2str(&dba, addr);
+
+	snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+	snprintf(level, sizeof(level), BATTERY_LEVEL_FORMAT, chr->level);
+
+	return textfile_caseput(filename, key, level);
+}
+
+static char *read_battery_char(struct characteristic *chr)
+{
+	char filename[PATH_MAX + 1], addr[18], key[23];
+	char *str, *strnew;
+	bdaddr_t sba, dba;
+
+	adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+	device_get_address(chr->batt->dev, &dba, NULL);
+
+	create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+	ba2str(&dba, addr);
+	snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+
+	str = textfile_caseget(filename, key);
+	if (str == NULL)
+		return NULL;
+
+	strnew = g_strdup(str);
+	g_free(str);
+
+	return strnew;
+}
+
+static void del_battery_char(struct characteristic *chr)
+{
+	char filename[PATH_MAX + 1], addr[18], key[23];
+	bdaddr_t sba, dba;
+
+	adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+	device_get_address(chr->batt->dev, &dba, NULL);
+
+	create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+	ba2str(&dba, addr);
+	snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+
+	textfile_casedel(filename, key);
+}
+
+static gboolean read_battery_level_value(struct characteristic *chr)
+{
+	char *str;
+
+	if (!chr)
+		return FALSE;
+
+	str = read_battery_char(chr);
+	if (!str)
+		return FALSE;
+
+	chr->level = atoi(str);
+
+	btd_device_set_battery_opt(chr->devbatt, BATTERY_OPT_LEVEL, chr->level,
+						BATTERY_OPT_INVALID);
+
+	g_free(str);
+	return TRUE;
+}
+
 static void char_free(gpointer user_data)
 {
 	struct characteristic *c = user_data;
 
+	del_battery_char(c);
+
 	g_slist_free_full(c->desc, g_free);
 
 	btd_device_remove_battery(c->devbatt);
@@ -148,6 +247,8 @@ static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
 	ch->level = value[0];
 	btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_LEVEL, ch->level,
 						BATTERY_OPT_INVALID);
+
+	store_battery_char(ch);
 }
 
 static void process_batteryservice_char(struct characteristic *ch)
@@ -313,6 +414,7 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 	}
 
 	att_data_list_free(list);
+
 }
 
 static void configure_battery_cb(GSList *characteristics, guint8 status,
@@ -364,7 +466,8 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 						   batterylevel_refresh_cb,
 						   BATTERY_OPT_INVALID);
 
-			process_batteryservice_char(ch);
+			if (!read_battery_level_value(ch))
+				process_batteryservice_char(ch);
 		}
 	}
 }
@@ -425,7 +528,7 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 		GSList *l;
 		for (l = batt->chars; l; l = l->next) {
 			struct characteristic *c = l->data;
-			if (!c->canNotify)
+			if (!read_battery_level_value(c) && !c->canNotify)
 				process_batteryservice_char(c);
 		}
 	}
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 09/10] battery: Add support for notifications
From: chen.ganir @ 2012-09-13 13:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347541403-11780-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.
---
 profiles/battery/battery.c |   98 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index b2850e4..355c7b4 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -43,6 +43,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 */
 };
 
@@ -56,6 +57,7 @@ struct characteristic {
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
 	uint8_t			level;		/* Battery level */
+	gboolean		canNotify;	/* Char can notify flag */
 };
 
 struct descriptor {
@@ -86,6 +88,14 @@ static void char_free(gpointer user_data)
 	g_free(c);
 }
 
+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;
@@ -99,6 +109,14 @@ static void battery_free(gpointer user_data)
 	if (batt->attrib != NULL)
 		g_attrib_unref(batt->attrib);
 
+	if (batt->attrib != NULL) {
+		if (batt->attnotid) {
+			g_attrib_unregister(batt->attrib, batt->attnotid);
+			batt->attnotid = 0;
+		}
+
+		g_attrib_unref(batt->attrib);
+	}
 	btd_device_unref(batt->dev);
 	g_free(batt->svc_range);
 	g_free(batt);
@@ -140,6 +158,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 gint device_battery_cmp(gconstpointer a, gconstpointer b)
 {
 	const struct characteristic *ch = a;
@@ -178,6 +208,19 @@ static void batterylevel_refresh_cb(struct btd_battery *batt)
 		process_batteryservice_char(ch);
 }
 
+static void enable_battery_notification(struct characteristic *ch,
+								uint16_t handle)
+{
+	uint8_t atval[2];
+	uint16_t val;
+
+	val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+
+	att_put_u16(val, atval);
+	gatt_write_char(ch->batt->attrib, handle, atval, 2,
+				batterylevel_enable_notify_cb, ch);
+}
+
 static void batterylevel_presentation_format_desc_cb(guint8 status,
 						const guint8 *pdu, guint16 len,
 						gpointer user_data)
@@ -213,6 +256,14 @@ static void process_batterylevel_desc(struct descriptor *desc)
 	char uuidstr[MAX_LEN_UUID_STR];
 	bt_uuid_t btuuid;
 
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
+						BATTERY_LEVEL_UUID) == 0) {
+		enable_battery_notification(ch, desc->handle);
+		return;
+	}
+
 	bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
 
 	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
@@ -318,12 +369,54 @@ 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)
+{
+	if (!pdu) {
+		error("Battery level notification: Invalid pdu length");
+		return;
+	}
+
+	c->level = pdu[1];
+
+	btd_device_set_battery_opt(c->devbatt, BATTERY_OPT_LEVEL, c->level,
+							BATTERY_OPT_INVALID);
+}
+
+static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct 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,
@@ -332,7 +425,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);
 		}
 	}
 }
@@ -341,6 +435,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 v2 08/10] battery: Read Battery level characteristic
From: chen.ganir @ 2012-09-13 13:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347541403-11780-1-git-send-email-chen.ganir@ti.com>

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

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

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 3a2e604..b2850e4 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -55,6 +55,7 @@ struct characteristic {
 	GSList			*desc;		/* Descriptors */
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
+	uint8_t			level;		/* Battery level */
 };
 
 struct descriptor {
@@ -103,6 +104,80 @@ 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];
+	btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_LEVEL, ch->level,
+						BATTERY_OPT_INVALID);
+}
+
+static void process_batteryservice_char(struct characteristic *ch)
+{
+	if (g_strcmp0(ch->attr.uuid, BATTERY_LEVEL_UUID) == 0) {
+		gatt_read_char(ch->batt->attrib, ch->attr.value_handle, 0,
+						read_batterylevel_cb, ch);
+	}
+}
+
+static gint device_battery_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const struct btd_battery *batt = b;
+
+	if (batt == ch->devbatt)
+		return 0;
+
+	return -1;
+}
+
+static struct characteristic *find_battery_char(struct btd_battery *db)
+{
+	GSList *l, *b;
+
+	for (l = servers; l != NULL; l = g_slist_next(l)) {
+		struct battery *batt = l->data;
+
+		b = g_slist_find_custom(batt->chars, db, device_battery_cmp);
+		if (!b)
+			return NULL;
+
+		return b->data;
+	}
+
+	return NULL;
+}
+
+static void batterylevel_refresh_cb(struct btd_battery *batt)
+{
+	struct characteristic *ch;
+
+	ch = find_battery_char(batt);
+
+	if (ch)
+		process_batteryservice_char(ch);
+}
+
 static void batterylevel_presentation_format_desc_cb(guint8 status,
 						const guint8 *pdu, guint16 len,
 						gpointer user_data)
@@ -233,6 +308,12 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 							discover_desc_cb, ch);
 
 			ch->devbatt = btd_device_add_battery(ch->batt->dev);
+			btd_device_set_battery_opt(ch->devbatt,
+						   BATTERY_OPT_REFRESH_FUNC,
+						   batterylevel_refresh_cb,
+						   BATTERY_OPT_INVALID);
+
+			process_batteryservice_char(ch);
 		}
 	}
 }
@@ -247,6 +328,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 v2 07/10] battery: Add Battery to device
From: chen.ganir @ 2012-09-13 13:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347541403-11780-1-git-send-email-chen.ganir@ti.com>

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

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

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index c368768..3a2e604 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -49,6 +49,7 @@ struct battery {
 static GSList *servers;
 
 struct characteristic {
+	struct btd_battery	*devbatt;	/* device_battery pointer */
 	struct gatt_char	attr;		/* Characteristic */
 	struct battery		*batt;		/* Parent Battery Service */
 	GSList			*desc;		/* Descriptors */
@@ -79,6 +80,8 @@ static void char_free(gpointer user_data)
 
 	g_slist_free_full(c->desc, g_free);
 
+	btd_device_remove_battery(c->devbatt);
+
 	g_free(c);
 }
 
@@ -228,6 +231,8 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 
 			gatt_find_info(batt->attrib, start, end,
 							discover_desc_cb, ch);
+
+			ch->devbatt = btd_device_add_battery(ch->batt->dev);
 		}
 	}
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 06/10] battery: Get Battery ID
From: chen.ganir @ 2012-09-13 13:03 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347541403-11780-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.
---
 lib/uuid.h                 |    1 +
 profiles/battery/battery.c |   98 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 77 insertions(+), 22 deletions(-)

diff --git a/lib/uuid.h b/lib/uuid.h
index 58ad0b3..5c1b3ff 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -57,6 +57,7 @@ extern "C" {
 #define DEVICE_INFORMATION_UUID	"0000180a-0000-1000-8000-00805f9b34fb"
 
 #define BATTERY_SERVICE_UUID	"0000180f-0000-1000-8000-00805f9b34fb"
+#define BATTERY_LEVEL_UUID	"00002a19-0000-1000-8000-00805f9b34fb"
 
 #define GATT_UUID		"00001801-0000-1000-8000-00805f9b34fb"
 #define IMMEDIATE_ALERT_UUID	"00001802-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index dada15b..c368768 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -52,6 +52,8 @@ struct characteristic {
 	struct gatt_char	attr;		/* Characteristic */
 	struct battery		*batt;		/* Parent Battery Service */
 	GSList			*desc;		/* Descriptors */
+	uint8_t			ns;		/* Battery Namespace */
+	uint16_t		description;	/* Battery description */
 };
 
 struct descriptor {
@@ -98,6 +100,53 @@ static void battery_free(gpointer user_data)
 	g_free(batt);
 }
 
+static void batterylevel_presentation_format_desc_cb(guint8 status,
+						const guint8 *pdu, guint16 len,
+						gpointer user_data)
+{
+	struct descriptor *desc = user_data;
+	uint8_t value[ATT_MAX_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)
 {
@@ -131,6 +180,7 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 			desc->uuid = att_get_uuid128(&value[2]);
 
 		ch->desc = g_slist_append(ch->desc, desc);
+		process_batterylevel_desc(desc);
 	}
 
 	att_data_list_free(list);
@@ -150,31 +200,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


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