Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2 10/17] heartrate: Read Body Sensor Location characteristics
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

This patch reads and stores Body Sensor Location characteristics value.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 5464a9f..b73b357 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -56,6 +56,8 @@ struct heartrate {
 	guint				attioid;
 	struct att_range		*svc_range;
 	GSList				*chars;
+	gboolean			has_location;
+	uint8_t				location;
 };
 
 struct characteristic {
@@ -385,12 +387,44 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
 	{ }
 };
 
+static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct heartrate *hr = ch->hr;
+	uint8_t value;
+	ssize_t vlen;
+
+	if (status != 0) {
+		error("Body Sensor Location value read failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, &value, sizeof(value));
+	if (vlen < 0) {
+		error("Protocol error.");
+		return;
+	}
+
+	if (vlen != 1) {
+		error("Invalid length for Body Sensor Location");
+		return;
+	}
+
+	hr->has_location = TRUE;
+	hr->location = value;
+}
+
 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)
+	if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0) {
+		DBG("Heart Rate Control Point reset supported by client");
+	} else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
 		DBG("Body Sensor Location supported by client");
+		gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
+						read_sensor_location_cb, ch);
+	}
 }
 
 static void process_heartrate_desc(struct descriptor *desc)
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v2 09/17] heartrate: Enable measurement when watchers are registered
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346850348-21176-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch will enable measurement notification when first watcher is
registered or when device is connected and watcher is already registered.

Measurement will be disabled when last watcher is unregistered.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index a223fe0..5464a9f 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -101,6 +101,22 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const char *uuid = b;
+
+	return g_strcmp0(ch->attr.uuid, uuid);
+}
+
+static gint cmp_descriptor(gconstpointer a, gconstpointer b)
+{
+	const struct descriptor *desc = a;
+	const bt_uuid_t *uuid = b;
+
+	return bt_uuid_cmp(&desc->uuid, uuid);
+}
+
 static gint cmp_watcher(gconstpointer a, gconstpointer b)
 {
 	const struct watcher *watcher = a;
@@ -181,6 +197,91 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hra);
 }
 
+static struct characteristic *
+get_characteristic(struct heartrate *hr, const char *uuid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(hr->chars, uuid, cmp_char_uuid);
+	if (l == NULL)
+		return NULL;
+
+	return l->data;
+}
+
+static struct descriptor *get_descriptor(struct characteristic *ch,
+							const bt_uuid_t *uuid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
+	if (l == NULL)
+		return NULL;
+
+	return l->data;
+}
+
+static void char_write_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	char *msg = user_data;
+
+	if (status != 0)
+		error("%s failed", msg);
+
+	g_free(msg);
+}
+
+static void measurement_toggle(struct heartrate *hr, gboolean enable)
+{
+	struct characteristic *ch;
+	struct descriptor *desc;
+	bt_uuid_t btuuid;
+	uint8_t atval[2];
+	char *msg;
+
+	if (hr->attrib == NULL)
+		return;
+
+	ch = get_characteristic(hr, HEART_RATE_MEASUREMENT_UUID);
+	if (ch == NULL) {
+		DBG("Heart Rate Measurement characteristic not found");
+		return;
+	}
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	desc = get_descriptor(ch, &btuuid);
+	if (desc == NULL) {
+		DBG("Client Characteristic Configuration descriptor not found");
+		return;
+	}
+
+	if (enable) {
+		att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, atval);
+		msg = g_strdup("Enable measurement");
+	} else {
+		att_put_u16(0x0000, atval);
+		msg = g_strdup("Disable measurement");
+	}
+
+	gatt_write_char(hr->attrib, desc->handle, atval, 2, char_write_cb, msg);
+
+}
+
+static void measurement_enable(gpointer data, gpointer user_data)
+{
+	struct heartrate *hr = data;
+
+	measurement_toggle(hr, TRUE);
+}
+
+static void measurement_disable(gpointer data, gpointer user_data)
+{
+	struct heartrate *hr = data;
+
+	measurement_toggle(hr, FALSE);
+}
+
 static void watcher_exit(DBusConnection *conn, void *user_data)
 {
 	struct watcher *watcher = user_data;
@@ -190,6 +291,9 @@ static void watcher_exit(DBusConnection *conn, void *user_data)
 
 	hr->watchers = g_slist_remove(hr->watchers, watcher);
 	g_dbus_remove_watch(conn, watcher->id);
+
+	if (g_slist_length(hr->watchers) == 0)
+		g_slist_foreach(hr->devices, measurement_disable, 0);
 }
 
 static struct watcher *find_watcher(GSList *list, const char *sender,
@@ -236,6 +340,9 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
 	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
 						watcher, destroy_watcher);
 
+	if (g_slist_length(hra->watchers) == 0)
+		g_slist_foreach(hra->devices, measurement_enable, 0);
+
 	hra->watchers = g_slist_prepend(hra->watchers, watcher);
 
 	return dbus_message_new_method_return(msg);
@@ -262,6 +369,9 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
 	hr->watchers = g_slist_remove(hr->watchers, watcher);
 	g_dbus_remove_watch(get_dbus_connection(), watcher->id);
 
+	if (g_slist_length(hr->watchers) == 0)
+		g_slist_foreach(hr->devices, measurement_disable, 0);
+
 	return dbus_message_new_method_return(msg);
 }
 
@@ -291,9 +401,26 @@ static void process_heartrate_desc(struct descriptor *desc)
 
 	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
 
-	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0)
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+		uint8_t atval[2];
+		char *msg;
+
+		if (g_strcmp0(ch->attr.uuid, HEART_RATE_MEASUREMENT_UUID) != 0)
+			goto done;
+
+		if (g_slist_length(ch->hr->hra->watchers) == 0)
+			return;
+
+		att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, atval);
+		msg = g_strdup("Enable measurement");
+
+		gatt_write_char(ch->hr->attrib, desc->handle,
+					atval, 2, char_write_cb, msg);
+
 		return;
+	}
 
+done:
 	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
 	DBG("Ignored descriptor %s in characteristic %s", uuidstr,
 							ch->attr.uuid);
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v2 08/17] heartrate: Add HeartRateManager interface
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

This patch adds support for org.bluez.HeartRateManager interface on adapters
which allows to register and unregister per-adapter watcher.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index eec8ae0..a223fe0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -24,13 +24,16 @@
 #include <config.h>
 #endif
 
+#include <gdbus.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <glib.h>
 #include <bluetooth/uuid.h>
 
 #include "adapter.h"
+#include "dbus-common.h"
 #include "device.h"
+#include "error.h"
 #include "gattrib.h"
 #include "attio.h"
 #include "att.h"
@@ -38,9 +41,12 @@
 #include "heartrate.h"
 #include "log.h"
 
+#define HEART_RATE_MANAGER_IFACE "org.bluez.HeartRateManager"
+
 struct heartrate_adapter {
 	struct btd_adapter	*adapter;
 	GSList			*devices;
+	GSList			*watchers;
 };
 
 struct heartrate {
@@ -64,6 +70,13 @@ struct descriptor {
 	bt_uuid_t		uuid;
 };
 
+struct watcher {
+	struct heartrate_adapter	*hra;
+	guint				id;
+	char				*srv;
+	char				*path;
+};
+
 static GSList *heartrate_adapters = NULL;
 
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -88,6 +101,19 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+	const struct watcher *watcher = a;
+	const struct watcher *match = b;
+	int ret;
+
+	ret = g_strcmp0(watcher->srv, match->srv);
+	if (ret != 0)
+		return ret;
+
+	return g_strcmp0(watcher->path, match->path);
+}
+
 static struct heartrate_adapter *
 find_heartrate_adapter(struct btd_adapter *adapter)
 {
@@ -108,6 +134,22 @@ static void destroy_char(gpointer user_data)
 	g_free(c);
 }
 
+static void remove_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_free(watcher->path);
+	g_free(watcher->srv);
+	g_free(watcher);
+}
+
 static void destroy_heartrate_device(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -133,9 +175,106 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	if (hra->devices != NULL)
 		g_slist_free_full(hra->devices, destroy_heartrate_device);
 
+	if (hra->watchers != NULL)
+		g_slist_free_full(hra->watchers, remove_watcher);
+
 	g_free(hra);
 }
 
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+	struct watcher *watcher = user_data;
+	struct heartrate_adapter *hr = watcher->hra;
+
+	DBG("Heart Rate watcher %s disconnected", watcher->path);
+
+	hr->watchers = g_slist_remove(hr->watchers, watcher);
+	g_dbus_remove_watch(conn, watcher->id);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+							const char *path)
+{
+	struct watcher *match;
+	GSList *l;
+
+	match = g_new0(struct watcher, 1);
+	match->srv = g_strdup(sender);
+	match->path = g_strdup(path);
+
+	l = g_slist_find_custom(list, match, cmp_watcher);
+	destroy_watcher(match);
+
+	if (l != NULL)
+		return l->data;
+
+	return NULL;
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct heartrate_adapter *hra = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(hra->watchers, sender, path);
+	if (watcher != NULL)
+		return btd_error_already_exists(msg);
+
+	DBG("Heart Rate watcher %s registered", path);
+
+	watcher = g_new0(struct watcher, 1);
+	watcher->srv = g_strdup(sender);
+	watcher->path = g_strdup(path);
+	watcher->hra = hra;
+	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+						watcher, destroy_watcher);
+
+	hra->watchers = g_slist_prepend(hra->watchers, watcher);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct heartrate_adapter *hr = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(hr->watchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	DBG("Heart Rate watcher %s unregistered", path);
+
+	hr->watchers = g_slist_remove(hr->watchers, watcher);
+	g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_manager_methods[] = {
+	{ GDBUS_METHOD("RegisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			register_watcher) },
+	{ GDBUS_METHOD("UnregisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			unregister_watcher) },
+	{ }
+};
+
 static void process_heartrate_char(struct characteristic *ch)
 {
 	if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
@@ -275,6 +414,18 @@ int heartrate_adapter_register(struct btd_adapter *adapter)
 	hra = g_new0(struct heartrate_adapter, 1);
 	hra->adapter = adapter;
 
+	if (!g_dbus_register_interface(get_dbus_connection(),
+						adapter_get_path(adapter),
+						HEART_RATE_MANAGER_IFACE,
+						heartrate_manager_methods,
+						NULL, NULL, hra,
+						destroy_heartrate_adapter)) {
+		error("D-Bus failed to register %s interface",
+						HEART_RATE_MANAGER_IFACE);
+		destroy_heartrate_adapter(hra);
+		return -EIO;
+	}
+
 	heartrate_adapters = g_slist_prepend(heartrate_adapters, hra);
 
 	return 0;
@@ -290,7 +441,9 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
 
 	heartrate_adapters = g_slist_remove(heartrate_adapters, hra);
 
-	destroy_heartrate_adapter(hra);
+	g_dbus_unregister_interface(get_dbus_connection(),
+						adapter_get_path(hra->adapter),
+						HEART_RATE_MANAGER_IFACE);
 }
 
 int heartrate_device_register(struct btd_device *device,
-- 
1.7.11.3


^ permalink raw reply related

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

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

This patch adds stub to process discovered characteristics descriptors.

---
 lib/uuid.h                     |  1 +
 profiles/heartrate/heartrate.c | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 0a9db51..15a80a0 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,7 @@ extern "C" {
 #define SAP_UUID		"0000112D-0000-1000-8000-00805f9b34fb"
 
 #define HEART_RATE_UUID			"0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_MEASUREMENT_UUID	"00002a37-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"
 
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 69d6d51..eec8ae0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -144,6 +144,22 @@ static void process_heartrate_char(struct characteristic *ch)
 		DBG("Body Sensor Location supported by client");
 }
 
+static void process_heartrate_desc(struct descriptor *desc)
+{
+	struct characteristic *ch = desc->ch;
+	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)
+		return;
+
+	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+	DBG("Ignored descriptor %s in characteristic %s", uuidstr,
+							ch->attr.uuid);
+}
+
 static void discover_desc_cb(guint8 status, const guint8 *pdu,
 					guint16 len, gpointer user_data)
 {
@@ -177,6 +193,8 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
 			desc->uuid = att_get_uuid128(value + 2);
 
 		ch->desc = g_slist_append(ch->desc, desc);
+
+		process_heartrate_desc(desc);
 	}
 
 	att_data_list_free(list);
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v2 06/17] heartrate: Discover characteristics descriptors
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-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 v2 05/17] heartrate: Process characteristics
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-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 v2 04/17] heartrate: Discover characteristics
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-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 9d2446c..ff2da21 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -33,6 +33,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);
@@ -45,7 +53,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 v2 03/17] heartrate: Add attio callbacks
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346850348-21176-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 v2 02/17] heartrate: Add Heart Rate Profile client
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-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   |  75 +++++++++++++++++++
 profiles/heartrate/manager.h   |  24 ++++++
 7 files changed, 351 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 4977a05..cb36d91 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -212,7 +212,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 \
@@ -241,7 +241,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..9d2446c
--- /dev/null
+++ b/profiles/heartrate/manager.c
@@ -0,0 +1,75 @@
+/*
+ *
+ *  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 "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 v2 01/17] Heart Rate Profile API
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1346850348-21176-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

---
 doc/heartrate-api.txt | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 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..3afea78
--- /dev/null
+++ b/doc/heartrate-api.txt
@@ -0,0 +1,83 @@
+			 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 measure)
+
+			This callback is called whenever a heart rate
+			measurement is received from the heart rate device.
+			The unit for the Value is expressed in beats per
+			minute (bpm). The energy field is optional and
+			represents the accumulated energy expended in
+			kilo Joules since last time it was reset. Furthermore,
+			the device will be automatically reset when it
+			is needed.
+			The Contact field, if present, indicates
+			that the device supports contact sensor, besides it
+			will be true if skin contact is detected. The optional
+			interval field is an array containing RR-Interval
+			values which represent the time between two R-Wave
+			detections, where the RR-Interval value 0 is older
+			than the value 1 and so on.
+
+			Dict is defined as below:
+			{
+				"Value" : uint16,
+				"Energy" : uint16,
+				"Contact" : boolean,
+				"Interval" : array{uint16}
+			}
+
-- 
1.7.11.3


^ permalink raw reply related

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

Hi,

Here's v2 of HRP plugin implementation. Changes from v1 include:
- update to btd_profile
- API change: make watchers per-adapter instead of per-device
  there's new interface registered for adapter HeartRateManager to (un)register
  watchers and MeasurementReceived method in HeartRateWatcher interface has
  additional parameter with device object path
- API change: make "Location" device property
  "Location" is now device property, previously it was send with every single
  measurement which does not make sense since it's not part of measurement
  (unlike Temperature Type in HTP) and cannot change
- other small fixes and some refactoring so patches can be split better

Comments are welcome.


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          |  83 ++++
 lib/uuid.h                     |   5 +
 profiles/heartrate/heartrate.c | 971 +++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |  27 ++
 profiles/heartrate/main.c      |  52 +++
 profiles/heartrate/manager.c   |  95 ++++
 profiles/heartrate/manager.h   |  24 +
 src/bluetooth.conf             |   1 +
 test/test-heartrate            | 103 +++++
 11 files changed, 1370 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

* Re: [PATCH] input: Implement idle timeout for fakehid.
From: Johan Hedberg @ 2012-09-05 10:07 UTC (permalink / raw)
  To: Jeff Hansen; +Cc: linux-bluetooth
In-Reply-To: <1346077185-18377-1-git-send-email-x@jeffhansen.com>

Hi Jeff,

On Mon, Aug 27, 2012, Jeff Hansen wrote:
> +		fake->timeout = iconn->timeout * 1000;

Why not use the original iconn->timeout value and then use
g_timeout_add_seconds instead of g_timeout_add?

> +	guint		idle_timeout;
> +	uint32_t	timeout;

Why uint32_t instead of just int that iconn->timeout is?

> +static gboolean ps3remote_idle(gpointer data)
> +{
> +	struct fake_input *fake = data;
> +	input_device_request_disconnect(fake->idev);
> +	return FALSE;
> +}

Could you add an empty line before and after
input_device_request_disconnect for slightly better readability.

> +	if (fake->idle_timeout) {

For consistency with the rest of the code base please use > 0 for
checking for valid GSource IDs. I'd also just call it idle_id to avoid
confusion with "timeout" which is not a GSource ID.

> +		g_source_remove(fake->idle_timeout);
> +		fake->idle_timeout = 0;
> +	}
> +	if (fake->timeout)
> +		fake->idle_timeout = g_timeout_add(fake->timeout, ps3remote_idle, fake);

Please add an empty line before this second if statement and also do > 0
here.

> +	if (fake->idle_timeout) {

And > 0 again here.

Johan

^ permalink raw reply

* Re: [PATCH 1/2] mgmt: Add wrapper for Set SSP
From: Johan Hedberg @ 2012-09-05 10:00 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth
In-Reply-To: <1346157514-22119-1-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

On Tue, Aug 28, 2012, Andrzej Kaczmarek wrote:
> Wrap mgmt_set_mode for Set SSP into separate function to be consistent
> with other calls and have debug printout.
> ---
>  src/mgmt.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)

Both patches have been applied. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH obexd 2/7 v2] client: Add filters to PhonebookAccess.Pull
From: Johan Hedberg @ 2012-09-05  9:59 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1346157115-23933-2-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Tue, Aug 28, 2012, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This avoid D-Bus round trips and is more aligned with what has been
> proposed for MessageAccess interface.
> ---
>  client/pbap.c | 79 +++++++++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 53 insertions(+), 26 deletions(-)

This patch doesn't compile:

client/pbap.c: In function ‘pull_vcard_listing.constprop.10’:
client/pbap.c:614:21: error: ‘apparam’ may be used uninitialized in this function [-Werror=maybe-uninitialized]

Johan

^ permalink raw reply

* Re: [RFC v4 00/18] Unaligned memory access fixes
From: Johan Hedberg @ 2012-09-05  9:33 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1346769697-9930-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Tue, Sep 04, 2012, Szymon Janc wrote:
> Changes since V2:
> 
> - fixed issues pointed by Anderson
> - some other fixes, cleanups
> - proposed change to bt_get_unaligned macro (PATCH 15) to avoid offending
>   pointer cast, this allow to use this macro instead of memcpy (in places
>   where it is more clean compared to memcpy e.g. where memcpy requires
>   temporary variable) - this is not commonly used since most macro uses
>   are now replaced with helper functions.
> 
> -- 
> BR
> Szymon Janc
> 
> Szymon Janc (18):
>   Add helper functions for putting integers on unaligned memory address
>   sdp: Fix compilation errors due to unaligned memory access
>   sdp: Use bt_get_be* helpers instead of bt_get_unaligned
>   l2test: Fix compilation errors due to unaligned memory access
>   rctest: Fix compilation errors due to unaligned memory access
>   scotest: Fix compilation errors due to unaligned memory access
>   sap: Fix compilation errors due to unaligned memory access
>   adaptername: Refactor handle_inotify_cb
>   sdpd-request: Fix build errors due to unaligned memory access
>   sdpd-service: Fix build errors due to unaligned memory access
>   hciemu: Fix build errors due to unaligned memory access
>   avrcp: Fix compilation errors due to unaligned memory access
>   eir: Use bt_get_* helper functions to access unaligned memory
>   mgmt: Use bt_get_* helper functions to access unaligned memory
>   Refactor bt_get_unaligned macro
>   sap-u8500: Fix compile error due to unaligned memory access
>   monitor: Fix compilation errors due to unaligned memory access
>   sdp: Fix build error due to unaligned memory access
> 
>  attrib/att.h             |    6 +--
>  audio/avrcp.c            |   10 ++---
>  lib/bluetooth.h          |   89 +++++++++++++++++++++++++++++++++++++-------
>  lib/sdp.c                |   92 +++++++++++++++++++++++-----------------------
>  monitor/control.c        |    7 +++-
>  monitor/hcidump.c        |   21 +++++++----
>  plugins/adaptername.c    |   48 ++++++++++++------------
>  profiles/sap/sap-u8500.c |   10 +++--
>  profiles/sap/server.c    |    9 ++---
>  src/eir.c                |    6 ++-
>  src/mgmt.c               |   18 ++++-----
>  src/sdpd-request.c       |   62 ++++++++++++++++---------------
>  src/sdpd-service.c       |   21 +++++------
>  test/hciemu.c            |    6 ++-
>  test/l2test.c            |    9 +++--
>  test/rctest.c            |    5 ++-
>  test/scotest.c           |    5 ++-
>  17 files changed, 253 insertions(+), 171 deletions(-)

Patches 1-14 have been applied. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Bluetooth: mgmt: Implement support for passkey notification
From: Johan Hedberg @ 2012-09-05  9:28 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1346833772.21200.79.camel@aeonflux>

Hi Marcel,

On Wed, Sep 05, 2012, Marcel Holtmann wrote:
> Hi Johan,
> 
> > This patch adds support for Secure Simple Pairing with devices that have
> > KeyboardOnly as their IO capability. Such devices will cause a passkey
> > notification on our side and optionally also keypress notifications.
> > Without this patch some keyboards cannot be paired using the mgmt
> > interface.
> 
> can we see a mgmt-api.txt documentation patch as RFC first.

Actually I already pushed that yesterday. We can still change it of
course if you have improvement suggestions:

+Passkey Notify Event
+====================
+
+Event Code             0x0017
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Passkey (4 Octets)
+                       Entered (1 Octet)

And yes, I know some description for the event (and most other events in
mgmt-api.txt) would be good.

Johan

^ permalink raw reply

* Re: [PATCH] Bluetooth: mgmt: Implement support for passkey notification
From: Andrei Emeltchenko @ 2012-09-05  9:25 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1346832850-25061-1-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

nitpicks

On Wed, Sep 05, 2012 at 11:14:10AM +0300, Johan Hedberg wrote:
...
> +	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
> +	if (!conn)
> +		return;
> +
> +	switch (ev->type) {
> +	case HCI_KEYPRESS_STARTED:
> +		conn->passkey_entered = 0;
> +		return;
> +	case HCI_KEYPRESS_ENTERED:
> +		conn->passkey_entered++;
> +		break;
> +	case HCI_KEYPRESS_ERASED:
> +		conn->passkey_entered--;
> +		break;
> +	case HCI_KEYPRESS_CLEARED:
> +		conn->passkey_entered = 0;
> +		break;

Can we use the same style for switch like below:

...
> +	case HCI_EV_USER_PASSKEY_NOTIFY:
> +		hci_user_passkey_notify_evt(hdev, skb);
> +		break;
> +
> +	case HCI_EV_KEYPRESS_NOTIFY:
> +		hci_keypress_notify_evt(hdev, skb);
> +		break;
> +
>  	case HCI_EV_SIMPLE_PAIR_COMPLETE:
>  		hci_simple_pair_complete_evt(hdev, skb);
>  		break;

Best regards 
Andrei Emeltchenko 

^ permalink raw reply

* Re: [RFC v4 15/18] Refactor bt_get_unaligned macro
From: Szymon Janc @ 2012-09-05  9:03 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1346772105.21200.2.camel@aeonflux>

On Tuesday 04 of September 2012 18:21:45 Marcel Holtmann wrote:
> Hi Szymon,

Hi Marcel,

> 
> > Use extra parameter type for bt_get_unaligned to avoid pointer casting
> > which might trigger compile time errors due to unaligned memory access.
> > 
> > ---
> >  attrib/att.h       |    6 +++---
> >  lib/bluetooth.h    |   28 ++++++++++++++--------------
> >  lib/sdp.c          |   22 +++++++++++-----------
> >  src/sdpd-request.c |    4 ++--
> >  4 files changed, 30 insertions(+), 30 deletions(-)
> > 
> > diff --git a/attrib/att.h b/attrib/att.h
> > index a563255..6101dac 100644
> > --- a/attrib/att.h
> > +++ b/attrib/att.h
> > @@ -115,19 +115,19 @@ struct att_range {
> >  static inline uint8_t att_get_u8(const void *ptr)
> >  {
> >  	const uint8_t *u8_ptr = ptr;
> > -	return bt_get_unaligned(u8_ptr);
> > +	return bt_get_unaligned(u8_ptr, uint8_t);
> >  }
> >  
> >  static inline uint16_t att_get_u16(const void *ptr)
> >  {
> >  	const uint16_t *u16_ptr = ptr;
> > -	return btohs(bt_get_unaligned(u16_ptr));
> > +	return btohs(bt_get_unaligned(u16_ptr, uint16_t));
> >  }
> >  
> >  static inline uint32_t att_get_u32(const void *ptr)
> >  {
> >  	const uint32_t *u32_ptr = ptr;
> > -	return btohl(bt_get_unaligned(u32_ptr));
> > +	return btohl(bt_get_unaligned(u32_ptr, uint32_t));
> >  }
> >  
> >  static inline uint128_t att_get_u128(const void *ptr)
> > diff --git a/lib/bluetooth.h b/lib/bluetooth.h
> > index 161b7bd..898a122 100644
> > --- a/lib/bluetooth.h
> > +++ b/lib/bluetooth.h
> > @@ -137,10 +137,10 @@ enum {
> >  #endif
> >  
> >  /* Bluetooth unaligned access */
> > -#define bt_get_unaligned(ptr)			\
> > +#define bt_get_unaligned(ptr, type)		\
> >  ({						\
> >  	struct __attribute__((packed)) {	\
> > -		typeof(*(ptr)) __v;		\
> > +		type __v;			\
> >  	} *__p = (typeof(__p)) (ptr);		\
> >  	__p->__v;				\
> >  })
> 
> I am not in favor of this change at all. We should not need such a
> change. And in addition, it break the API.

On ARM (and possibly other architectures) with -Wcast-align one is not able to do:
uint8_t *ptr;
uint16_t *ptr2 = (uint16_t *)ptr;
int *ptr3 = (int *)ptr;
etc.

It leads to following error:
error: cast increases required alignment of target type [-Werror=cast-align]

..and this is what current version of that macro requires.
(BTW bt_put_unaligned suffers same issue)

In bluetoothd code we can replace all calls to that macro with (more or less
convenient) memcpy. But if that macro is considered part of API it may produce
compilation errors on projects that use -Wcast-align.

Any suggestions on how this could be solved are welcome.


> Regards
> 
> Marcel
> 

-- 
BR
Szymon Janc

^ permalink raw reply

* Re: [PATCH] Bluetooth: mgmt: Implement support for passkey notification
From: Marcel Holtmann @ 2012-09-05  8:29 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1346832850-25061-1-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> This patch adds support for Secure Simple Pairing with devices that have
> KeyboardOnly as their IO capability. Such devices will cause a passkey
> notification on our side and optionally also keypress notifications.
> Without this patch some keyboards cannot be paired using the mgmt
> interface.

can we see a mgmt-api.txt documentation patch as RFC first.

Regards

Marcel



^ permalink raw reply

* [PATCH] Bluetooth: mgmt: Implement support for passkey notification
From: Johan Hedberg @ 2012-09-05  8:14 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds support for Secure Simple Pairing with devices that have
KeyboardOnly as their IO capability. Such devices will cause a passkey
notification on our side and optionally also keypress notifications.
Without this patch some keyboards cannot be paired using the mgmt
interface.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/hci.h      |   18 +++++++++++
 include/net/bluetooth/hci_core.h |    5 +++
 include/net/bluetooth/mgmt.h     |    7 +++++
 net/bluetooth/hci_event.c        |   63 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/mgmt.c             |   16 ++++++++++
 5 files changed, 109 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 0f28f70..76b2b6b 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1249,6 +1249,24 @@ struct hci_ev_simple_pair_complete {
 	bdaddr_t bdaddr;
 } __packed;
 
+#define HCI_EV_USER_PASSKEY_NOTIFY	0x3b
+struct hci_ev_user_passkey_notify {
+	bdaddr_t	bdaddr;
+	__le32		passkey;
+} __packed;
+
+#define HCI_KEYPRESS_STARTED		0
+#define HCI_KEYPRESS_ENTERED		1
+#define HCI_KEYPRESS_ERASED		2
+#define HCI_KEYPRESS_CLEARED		3
+#define HCI_KEYPRESS_COMPLETED		4
+
+#define HCI_EV_KEYPRESS_NOTIFY		0x3c
+struct hci_ev_keypress_notify {
+	bdaddr_t	bdaddr;
+	__u8		type;
+} __packed;
+
 #define HCI_EV_REMOTE_HOST_FEATURES	0x3d
 struct hci_ev_remote_host_features {
 	bdaddr_t bdaddr;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index fa807a3..b998b9c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -303,6 +303,8 @@ struct hci_conn {
 	__u8		pin_length;
 	__u8		enc_key_size;
 	__u8		io_capability;
+	__u32		passkey_notify;
+	__u8		passkey_entered;
 	__u16		disc_timeout;
 	unsigned long	flags;
 
@@ -1016,6 +1018,9 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 				     u8 link_type, u8 addr_type, u8 status);
 int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 					 u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			     u8 link_type, u8 addr_type, u32 passkey,
+			     u8 entered);
 int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 		     u8 addr_type, u8 status);
 int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 1b48eff..22980a7 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -478,3 +478,10 @@ struct mgmt_ev_device_unblocked {
 struct mgmt_ev_device_unpaired {
 	struct mgmt_addr_info addr;
 } __packed;
+
+#define MGMT_EV_PASSKEY_NOTIFY		0x0017
+struct mgmt_ev_passkey_notify {
+	struct mgmt_addr_info addr;
+	__le32	passkey;
+	__u8	entered;
+} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 48d7302..22e01da 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3263,6 +3263,61 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
 		mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
 }
 
+static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_ev_user_passkey_notify *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s", hdev->name);
+
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (!conn)
+		return;
+
+	conn->passkey_notify = __le32_to_cpu(ev->passkey);
+	conn->passkey_entered = 0;
+
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+					 conn->dst_type, conn->passkey_notify,
+					 conn->passkey_entered);
+}
+
+static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_keypress_notify *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s", hdev->name);
+
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (!conn)
+		return;
+
+	switch (ev->type) {
+	case HCI_KEYPRESS_STARTED:
+		conn->passkey_entered = 0;
+		return;
+	case HCI_KEYPRESS_ENTERED:
+		conn->passkey_entered++;
+		break;
+	case HCI_KEYPRESS_ERASED:
+		conn->passkey_entered--;
+		break;
+	case HCI_KEYPRESS_CLEARED:
+		conn->passkey_entered = 0;
+		break;
+	case HCI_KEYPRESS_COMPLETED:
+		return;
+	}
+
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+					 conn->dst_type, conn->passkey_notify,
+					 conn->passkey_entered);
+}
+
 static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
 					 struct sk_buff *skb)
 {
@@ -3627,6 +3682,14 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_user_passkey_request_evt(hdev, skb);
 		break;
 
+	case HCI_EV_USER_PASSKEY_NOTIFY:
+		hci_user_passkey_notify_evt(hdev, skb);
+		break;
+
+	case HCI_EV_KEYPRESS_NOTIFY:
+		hci_keypress_notify_evt(hdev, skb);
+		break;
+
 	case HCI_EV_SIMPLE_PAIR_COMPLETE:
 		hci_simple_pair_complete_evt(hdev, skb);
 		break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 05d4b83..4c04c1e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3276,6 +3276,22 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 					  MGMT_OP_USER_PASSKEY_NEG_REPLY);
 }
 
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			     u8 link_type, u8 addr_type, u32 passkey,
+			     u8 entered)
+{
+	struct mgmt_ev_passkey_notify ev;
+
+	BT_DBG("%s", hdev->name);
+
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = link_to_bdaddr(link_type, addr_type);
+	ev.passkey = __cpu_to_le32(passkey);
+	ev.entered = entered;
+
+	return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
+}
+
 int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 		     u8 addr_type, u8 status)
 {
-- 
1.7.10.4


^ permalink raw reply related

* Re: [PATCH BlueZ v5 00/14] LE General Connection Establishment procedure
From: Chen Ganir @ 2012-09-05  5:00 UTC (permalink / raw)
  To: João Paulo Rechi Vita; +Cc: linux-bluetooth
In-Reply-To: <1346785482-13359-1-git-send-email-jprvita@openbossa.org>

João,

On 09/04/2012 10:04 PM, João Paulo Rechi Vita wrote:
> This series implement the LE General Connection Establishment procedure
> for LE connections.
>
> If there are LE bonded devices marked for auto connection they are added
> to a connect_list on the adapter. When there is any device on this list
> scan is performed continuously. When a device is found the connect_list
How do we stop this scan ? Do we need to remove all auto-connect settings?

> is checked. If that device is on the list scan is stopped and a
> connection attempt is made to that device.
Do we have a timeout for this ? What happens if we succeed ? Do we start 
scanning again if more devices are set to auto-connect ? What happens 
when we fail a connection ? Do we retry to the same or start scanning 
again ?

>
> If any client tries to perform discovery and the scan for the General
> Connection Establishment procedure is active, the discovery request is
> queued and performed right after the GCEP scan session finishes.
>
I'm am having difficulties understanding the logic here. You say that as 
long as we have bonded devices set for auto-connect, the GCE scan will 
run until a connection is made?. What happens if we do not find any 
device ? Do we scan forever?

This is a bit of a problem - device discovery can not be queued. 
Discovering devices is a user initiated command, and it should run 
whenever a client requires it. When a user requests for a list of 
devices, he expects to get the list. He does not care about background 
logic. The proper logic here is to pause the background scanning, 
discover devices (if LE scan reveals bonded devices that have 
auto-connect setting they should connect and then resume the discovery). 
After Device discovery is terminated, background connect scan should be 
continued.


> This series changes quite a lot the LE connection logic, but we've been
> testing and using this code at INdT for about 4 weeks. Any comments and
> more testing are appreciated.
>
> Claudio Takahasi (6):
>    core: Control connections based on adapter state
>    mgmt: Add LE scanning callback
>    core: Replace interleaved by LE scanning
>    core: Start LE scanning when a device requests
>    core: Queue discovery if scanning is active
>    core: Re-connect for ECONNRESET or ECONNABORTED
>
> João Paulo Rechi Vita (7):
>    mgmt: Print error message when start_discovery fails
>    core: Add compare function for bdaddr in a struct btd_device
>    core: Add a list of LE devices to connect
>    core: Use adapter connect list for LE connections
>    core: Mutually exclude concurrent connections
>    mgmt: Add address type to bonding debug message
>    core: Suspend scanning before connect on pairing
>
> Paulo Alcantara (1):
>    core: Disable unnecessary auto connections
>
>   src/adapter.c | 193 ++++++++++++++++++++++++++++++++++++++++++++-------
>   src/adapter.h |   5 ++
>   src/device.c  | 217 +++++++++++++++++++++++++++++-----------------------------
>   src/device.h  |   2 +
>   src/mgmt.c    |  44 +++++++++++-
>   src/mgmt.h    |   1 +
>   6 files changed, 325 insertions(+), 137 deletions(-)
>


BR,
Chen Ganir


^ permalink raw reply

* [PATCH BlueZ v5 14/14] core: Suspend scanning before connect on pairing
From: João Paulo Rechi Vita @ 2012-09-04 19:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1346785482-13359-1-git-send-email-jprvita@openbossa.org>

If there is a disconnected bonded device there will be a scanning
procedure active due to the General Connection Establishment Procedure.
This scan have to be suspended before trying to connect to the remote
device for pairing.
---
 src/device.c | 150 ++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 77 insertions(+), 73 deletions(-)

diff --git a/src/device.c b/src/device.c
index d0cebf4..81cd3b1 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1702,8 +1702,8 @@ send_reply:
 	else if (dbus_message_is_method_call(req->msg, ADAPTER_INTERFACE,
 						"CreateDevice")) {
 		if (err < 0) {
-			DBusMessage *reply;
-			reply = btd_error_failed(req->msg, strerror(-err));
+			DBusMessage *reply = btd_error_failed(req->msg,
+							strerror(-err));
 			g_dbus_send_message(req->conn, reply);
 			goto cleanup;
 		}
@@ -1915,6 +1915,38 @@ done:
 	browse_request_free(req);
 }
 
+static void bonding_request_free(struct bonding_req *bonding)
+{
+	struct btd_device *device;
+
+	if (!bonding)
+		return;
+
+	if (bonding->listener_id)
+		g_dbus_remove_watch(bonding->conn, bonding->listener_id);
+
+	if (bonding->msg)
+		dbus_message_unref(bonding->msg);
+
+	if (bonding->conn)
+		dbus_connection_unref(bonding->conn);
+
+	device = bonding->device;
+	g_free(bonding);
+
+	if (!device)
+		return;
+
+	device->bonding = NULL;
+
+	if (!device->agent)
+		return;
+
+	agent_cancel(device->agent);
+	agent_free(device->agent);
+	device->agent = NULL;
+}
+
 static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
 {
 	struct att_callbacks *attcb = user_data;
@@ -1944,6 +1976,21 @@ static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
 
 	if (attcb->success)
 		attcb->success(user_data);
+
+	if (device->bonding) {
+		/* this is a LE device during pairing */
+		int err = adapter_create_bonding(device->adapter,
+				&device->bdaddr, device->bdaddr_type,
+				agent_get_io_capability(device->agent));
+		if (err < 0) {
+			DBusMessage *reply = btd_error_failed(
+					device->bonding->msg, strerror(-err));
+			g_dbus_send_message(device->bonding->conn, reply);
+			bonding_request_cancel(device->bonding);
+			bonding_request_free(device->bonding);
+		}
+	}
+
 done:
 	g_free(attcb);
 }
@@ -1995,16 +2042,30 @@ GIOChannel *device_att_connect(gpointer user_data)
 	attcb->user_data = device;
 
 	if (device_is_bredr(device)) {
-		io = bt_io_connect(att_connect_cb,
-					attcb, NULL, &gerr,
+		io = bt_io_connect(att_connect_cb, attcb, NULL, &gerr,
 					BT_IO_OPT_SOURCE_BDADDR, &sba,
 					BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
 					BT_IO_OPT_PSM, ATT_PSM,
 					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
 					BT_IO_OPT_INVALID);
+	} else if (device->bonding) {
+		/* this is a LE device during pairing, using low sec level */
+		io = bt_io_connect(att_connect_cb, attcb, NULL, &gerr,
+				BT_IO_OPT_SOURCE_BDADDR, &sba,
+				BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
+				BT_IO_OPT_DEST_TYPE, device->bdaddr_type,
+				BT_IO_OPT_CID, ATT_CID,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+		if (io == NULL) {
+			DBusMessage *reply = btd_error_failed(
+					device->bonding->msg, gerr->message);
+			g_dbus_send_message(device->bonding->conn, reply);
+			bonding_request_cancel(device->bonding);
+			bonding_request_free(device->bonding);
+		}
 	} else {
-		io = bt_io_connect(att_connect_cb,
-				attcb, NULL, &gerr,
+		io = bt_io_connect(att_connect_cb, attcb, NULL, &gerr,
 				BT_IO_OPT_SOURCE_BDADDR, &sba,
 				BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
 				BT_IO_OPT_DEST_TYPE, device->bdaddr_type,
@@ -2330,38 +2391,6 @@ static DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status)
 	}
 }
 
-static void bonding_request_free(struct bonding_req *bonding)
-{
-	struct btd_device *device;
-
-	if (!bonding)
-		return;
-
-	if (bonding->listener_id)
-		g_dbus_remove_watch(bonding->conn, bonding->listener_id);
-
-	if (bonding->msg)
-		dbus_message_unref(bonding->msg);
-
-	if (bonding->conn)
-		dbus_connection_unref(bonding->conn);
-
-	device = bonding->device;
-	g_free(bonding);
-
-	if (!device)
-		return;
-
-	device->bonding = NULL;
-
-	if (!device->agent)
-		return;
-
-	agent_cancel(device->agent);
-	agent_free(device->agent);
-	device->agent = NULL;
-}
-
 void device_set_paired(struct btd_device *device, gboolean value)
 {
 	DBusConnection *conn = get_dbus_connection();
@@ -2455,41 +2484,6 @@ DBusMessage *device_create_bonding(struct btd_device *device,
 	if (device_is_bonded(device))
 		return btd_error_already_exists(msg);
 
-	if (device_is_le(device)) {
-		struct att_callbacks *attcb;
-		GError *gerr = NULL;
-		bdaddr_t sba;
-
-		adapter_get_address(adapter, &sba);
-
-		attcb = g_new0(struct att_callbacks, 1);
-		attcb->user_data = device;
-
-		device->att_io = bt_io_connect(att_connect_cb,
-				attcb, NULL, &gerr,
-				BT_IO_OPT_SOURCE_BDADDR, &sba,
-				BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
-				BT_IO_OPT_DEST_TYPE, device->bdaddr_type,
-				BT_IO_OPT_CID, ATT_CID,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
-				BT_IO_OPT_INVALID);
-
-		if (device->att_io == NULL) {
-			DBusMessage *reply = btd_error_failed(msg,
-								gerr->message);
-
-			error("Bonding bt_io_connect(): %s", gerr->message);
-			g_error_free(gerr);
-			g_free(attcb);
-			return reply;
-		}
-	}
-
-	err = adapter_create_bonding(adapter, &device->bdaddr,
-					device->bdaddr_type, capability);
-	if (err < 0)
-		return btd_error_failed(msg, strerror(-err));
-
 	bonding = bonding_request_new(conn, msg, device, agent_path,
 					capability);
 
@@ -2501,6 +2495,16 @@ DBusMessage *device_create_bonding(struct btd_device *device,
 	device->bonding = bonding;
 	bonding->device = device;
 
+	if (device_is_le(device)) {
+		adapter_connect_list_add(adapter, device);
+		return NULL;
+	}
+
+	err = adapter_create_bonding(adapter, &device->bdaddr,
+					device->bdaddr_type, capability);
+	if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
 	return NULL;
 }
 
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v5 13/14] mgmt: Add address type to bonding debug message
From: João Paulo Rechi Vita @ 2012-09-04 19:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1346785482-13359-1-git-send-email-jprvita@openbossa.org>

---
 src/mgmt.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/mgmt.c b/src/mgmt.c
index 8e69778..991075c 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -2371,7 +2371,8 @@ int mgmt_create_bonding(int index, bdaddr_t *bdaddr, uint8_t addr_type, uint8_t
 	char addr[18];
 
 	ba2str(bdaddr, addr);
-	DBG("hci%d bdaddr %s io_cap 0x%02x", index, addr, io_cap);
+	DBG("hci%d bdaddr %s type %d io_cap 0x%02x",
+					index, addr, addr_type, io_cap);
 
 	memset(buf, 0, sizeof(buf));
 	hdr->opcode = htobs(MGMT_OP_PAIR_DEVICE);
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v5 12/14] core: Re-connect for ECONNRESET or ECONNABORTED
From: João Paulo Rechi Vita @ 2012-09-04 19:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1346785482-13359-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch keeps scanning and re-connections active if the disconnection
reason is ECONNRESET(Remote Initiated Disconnection).

Re-connection is a behaviour determined by Profiles or by the upper
layer(user actions). For instance, HoG requires re-connection always
active, no matter if the previous disconnection reason was page timeout
or remote initiated disconnection (ECONNRESET). Some devices disconnects
after some idle time, connectable advertises are sent by the peripheral
when commanded by the user(eg: key pressed). Disconnection can be also
triggered by the local host (ECONNABORTED) using command line tools or
Disconnect method in the Device interface.

The peripheral dictates the re-connection controlling the connectable
advertises, BlueZ(central) needs to keep the scanning always active to
able to detect the advertises and trigger the connection.
---
 src/device.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/device.c b/src/device.c
index f9a0f3c..d0cebf4 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1845,10 +1845,18 @@ static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
 
 	g_slist_foreach(device->attios, attio_disconnected, NULL);
 
-	if (device->auto_connect == FALSE || err != ETIMEDOUT)
+	if (device->auto_connect == FALSE) {
+		DBG("Automatic connection disabled");
 		goto done;
+	}
 
-	adapter_connect_list_add(device_get_adapter(device), device);
+	/*
+	 * Keep scanning/re-connection active if disconnection reason
+	 * is page timeout, remote user terminated connection or local
+	 * initiated disconnection.
+	 */
+	if (err == ETIMEDOUT || err == ECONNRESET || err == ECONNABORTED)
+		adapter_connect_list_add(device_get_adapter(device), device);
 
 done:
 	attio_cleanup(device);
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v5 11/14] core: Disable unnecessary auto connections
From: João Paulo Rechi Vita @ 2012-09-04 19:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Paulo Alcantara
In-Reply-To: <1346785482-13359-1-git-send-email-jprvita@openbossa.org>

From: Paulo Alcantara <paulo.alcantara@openbossa.org>

BlueZ host disconnects the link when encryption fails. ECONNABORTED
error is returned by the kernel when the connection is terminated by the
local host. This scenario commonly happens when authentication fails due
PIN or Key Missing.
---
 src/device.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/device.c b/src/device.c
index 92bf4ae..f9a0f3c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1945,6 +1945,9 @@ static void att_error_cb(const GError *gerr, gpointer user_data)
 	struct att_callbacks *attcb = user_data;
 	struct btd_device *device = attcb->user_data;
 
+	if (g_error_matches(gerr, BT_IO_ERROR, ECONNABORTED))
+		return;
+
 	if (device->auto_connect == FALSE)
 		return;
 
-- 
1.7.11.4


^ 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