* [RFC BlueZ 14/33] doc: Add Observer D-Bus API documentation
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
This is a "high level" API for Observer GAP role.
---
doc/adapter-api.txt | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 23f0a2f..9e2e652 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -173,6 +173,57 @@ Methods dict GetProperties()
Possible errors: org.bluez.Error.DoesNotExist
+ void RegisterServiceObserver(object observer,
+ uint16 match_value)
+
+ Registers an observer agent to monitor Service Data
+ broadcasts. This agent will be notified whenever a
+ broadcast is received that matches that filter. It is
+ possible use same object path for two observers:
+ Service Data and Manufacturer Specific Data.
+
+ The match_value parameter must be the 16-bit UUID for
+ the service whose data is to be monitored.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+
+ void RegisterManufacturerObserver(object observer,
+ uint16 match_value)
+
+ Registers an observer agent to monitor Manufacturer
+ Specific Data broadcasts. This agent will be notified
+ whenever a broadcast is received that matches that
+ filter. It is possible use same object path for two
+ observers: Service Data and Manufacturer Specific Data.
+
+ The match_value parameter must be the 16-bit Company
+ Identifier Code for the manufacturer whose data is to
+ be monitored.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+
+ void UnregisterServiceObserver(object observer)
+
+ Unregisters a Service Data observer. Broadcasts will
+ not be notified to this agent anymore. The observer
+ will be destroyed only if no Manufacturer Specific Data
+ was registered with the same object path.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.DoesNotExist
+
+ void UnregisterManufacturerObserver(object observer)
+
+ Unregisters a Manufacturer Specific Data observer.
+ Broadcasts will not be notified to this agent anymore.
+ The observer will be destroyed only if no Service Data
+ was registered with the same object path.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.DoesNotExist
+
Signals PropertyChanged(string name, variant value)
This signal indicates a changed value of the given
@@ -275,3 +326,27 @@ Properties string Address [readonly]
List of 128-bit UUIDs that represents the available
local services.
+
+Observer hierarchy
+==================
+
+Service unique name
+Interface org.bluez.Observer
+Object path freely definable
+
+Methods void ServiceReceived(string address, uint16 uuid, variant data)
+
+ This callback gets called when a broadcast data has
+ arrived that matches filter used in
+ RegisterServiceObserver.
+
+ Note: data is a bytearray.
+
+ void ManufacturerReceived(string address, uint16 cid,
+ variant data)
+
+ This callback gets called when a broadcast data has
+ arrived that matches filter used in
+ RegisterManufacturerObserver.
+
+ Note: data is a bytearray.
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 15/33] adapter: Add D-Bus API for Observer GAP Role
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
From: Jefferson Delfes <jefferson.delfes@openbossa.org>
Implement dummy calls for register or unregister Observer Agents.
---
src/adapter.c | 38 ++++++++++++++++++++++++++++++++++++++
src/bluetooth.conf | 1 +
2 files changed, 39 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 50779fd..36c285a 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1617,6 +1617,30 @@ static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
return dbus_message_new_method_return(msg);
}
+static DBusMessage *register_service_observer(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_service_observer(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *register_manufobserver(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_manufobserver(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
static const GDBusMethodTable adapter_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
@@ -1658,6 +1682,20 @@ static const GDBusMethodTable adapter_methods[] = {
{ GDBUS_METHOD("UnregisterAgent",
GDBUS_ARGS({ "agent", "o" }), NULL,
unregister_agent) },
+ { GDBUS_METHOD("RegisterServiceObserver",
+ GDBUS_ARGS({ "observer", "o" }, { "match_value", "q" }),
+ NULL,
+ register_service_observer) },
+ { GDBUS_METHOD("UnregisterServiceObserver",
+ GDBUS_ARGS({ "observer", "o" }), NULL,
+ unregister_service_observer) },
+ { GDBUS_METHOD("RegisterManufacturerObserver",
+ GDBUS_ARGS({ "observer", "o" }, { "match_value", "q" }),
+ NULL,
+ register_manufobserver) },
+ { GDBUS_METHOD("UnregisterManufacturerObserver",
+ GDBUS_ARGS({ "observer", "o" }), NULL,
+ unregister_manufobserver) },
{ }
};
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 664dbd9..a2fef4f 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -14,6 +14,7 @@
<allow send_interface="org.bluez.HandsfreeAgent"/>
<allow send_interface="org.bluez.MediaEndpoint"/>
<allow send_interface="org.bluez.MediaPlayer"/>
+ <allow send_interface="org.bluez.Observer"/>
<allow send_interface="org.bluez.Watcher"/>
<allow send_interface="org.bluez.ThermometerWatcher"/>
</policy>
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 16/33] observer: Add RegisterServiceObserver() D-Bus method
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
From: Jefferson Delfes <jefferson.delfes@openbossa.org>
An observer for Service Data must be registered using
RegisterServiceObserver() D-Bus method so it can receive any advertising
which matches with the filter used.
---
src/adapter.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 36c285a..27692f9 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1620,6 +1620,26 @@ static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
static DBusMessage *register_service_observer(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ struct btd_adapter *adapter = data;
+ const char *path, *sender = dbus_message_get_sender(msg);
+ unsigned int uuid;
+ int err;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_UINT16, &uuid,
+ DBUS_TYPE_INVALID) == FALSE)
+ return btd_error_invalid_args(msg);
+
+ err = mgmt_set_observer(adapter->dev_id, TRUE);
+ if (err < 0) {
+ error("Failed to set Observer: %s (%d)", strerror(-err), -err);
+
+ return btd_error_failed(msg, strerror(-err));
+ }
+
+ DBG("Service Data Observer registered for hci%d at %s:%s",
+ adapter->dev_id, sender, path);
+
return dbus_message_new_method_return(msg);
}
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 17/33] observer: Add UnregisterServiceObserver() D-Bus method
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
Unregister an observer for Service Data and avoid to send broadcaster to
this agent.
---
src/adapter.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 27692f9..b437cf6 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1646,6 +1646,21 @@ static DBusMessage *register_service_observer(DBusConnection *conn,
static DBusMessage *unregister_service_observer(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ const char *path, *sender = dbus_message_get_sender(msg);
+ struct btd_adapter *adapter = data;
+ int err;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE)
+ return btd_error_invalid_args(msg);
+
+ err = mgmt_set_observer(adapter->dev_id, FALSE);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ DBG("Service Data Observer unregistered for hci%d at %s:%s",
+ adapter->dev_id, sender, path);
+
return dbus_message_new_method_return(msg);
}
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 18/33] observer: Add RegisterManufacturerObserver() D-Bus method
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
An observer for Manufacturer Specific Data must be registered using
RegisterManufacturerObserver() D-Bus method so it can receive any
advertising which matches with the filter used.
---
src/adapter.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index b437cf6..e5237b5 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1667,6 +1667,26 @@ static DBusMessage *unregister_service_observer(DBusConnection *conn,
static DBusMessage *register_manufobserver(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ struct btd_adapter *adapter = data;
+ const char *path, *sender = dbus_message_get_sender(msg);
+ unsigned int company_id;
+ int err;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_UINT16, &company_id,
+ DBUS_TYPE_INVALID) == FALSE)
+ return btd_error_invalid_args(msg);
+
+ err = mgmt_set_observer(adapter->dev_id, TRUE);
+ if (err < 0) {
+ error("Failed to set Observer: %s (%d)", strerror(-err), -err);
+
+ return btd_error_failed(msg, strerror(-err));
+ }
+
+ DBG("Manufacturer Specific Data Observer registered for hci%d at %s:%s",
+ adapter->dev_id, sender, path);
+
return dbus_message_new_method_return(msg);
}
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 19/33] observer: Add UnregisterManufacturerObserver() D-Bus method
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
Unregister an observer for Manufacturer Specific Data and avoid to send
broadcaster to this agent.
---
src/adapter.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index e5237b5..b2c052f 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1693,6 +1693,21 @@ static DBusMessage *register_manufobserver(DBusConnection *conn,
static DBusMessage *unregister_manufobserver(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ const char *path, *sender = dbus_message_get_sender(msg);
+ struct btd_adapter *adapter = data;
+ int err;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE)
+ return btd_error_invalid_args(msg);
+
+ err = mgmt_set_observer(adapter->dev_id, FALSE);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ DBG("Manufacturer Specific Data Observer unregistered for hci%d at "
+ "%s:%s", adapter->dev_id, sender, path);
+
return dbus_message_new_method_return(msg);
}
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 20/33] observer: Add watchers and filters for observers
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
The adapter will keep a list of observers to listening for advertising.
The new observer is added on the list when it is registered.
When an observer is registered, the filter must be stored to be used
after receiving a new advertising. The observer only will received the
data from advertising if the filter matches.
---
src/adapter.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 171 insertions(+), 8 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index b2c052f..3b8cbcd 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -82,6 +82,10 @@
#define OFF_TIMER 3
+/* Filter Types (for Observer) */
+#define FILTER_SERVICE_UUID 0x01
+#define FILTER_COMPANY_IC 0x02
+
static DBusConnection *connection = NULL;
static GSList *adapter_drivers = NULL;
@@ -103,6 +107,16 @@ struct service_auth {
struct btd_adapter *adapter;
};
+struct observer_watcher {
+ struct btd_adapter *adapter;
+ guint id; /* Listener id */
+ uint8_t filter_type; /* Filer type: Service or Manufacturer
+ * data */
+ void *filter_data; /* Value of filter */
+ char *sender; /* DBus sender */
+ char *path; /* DBus path */
+};
+
struct btd_adapter {
uint16_t dev_id;
gboolean up;
@@ -132,6 +146,7 @@ struct btd_adapter {
GSList *devices; /* Devices structure pointers */
GSList *mode_sessions; /* Request Mode sessions */
GSList *disc_sessions; /* Discovery sessions */
+ GSList *observers; /* Observer watchers */
guint discov_id; /* Discovery timer */
gboolean discovering; /* Discovery active */
gboolean discov_suspended; /* Discovery suspended */
@@ -1617,10 +1632,85 @@ static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
return dbus_message_new_method_return(msg);
}
+static void destroy_observer(gpointer user_data)
+{
+ struct observer_watcher *obs = user_data;
+
+ btd_adapter_unref(obs->adapter);
+
+ g_dbus_remove_watch(connection, obs->id);
+
+ g_free(obs->path);
+ g_free(obs->sender);
+ g_free(obs);
+}
+
+static gint cmp_observer(gconstpointer a, gconstpointer b)
+{
+ const struct observer_watcher *obs = a;
+ const struct observer_watcher *match = b;
+ int ret;
+
+ ret = g_strcmp0(obs->sender, match->sender);
+ if (ret != 0)
+ return ret;
+
+ ret = g_strcmp0(obs->path, match->path);
+ if (ret != 0)
+ return ret;
+
+ return obs->filter_type - match->filter_type;
+}
+
+static struct observer_watcher *find_observer(GSList *list, const char *sender,
+ const char *path, uint8_t filter)
+{
+ struct observer_watcher *match;
+ GSList *l;
+
+ match = g_new0(struct observer_watcher, 1);
+ match->sender = g_strdup(sender);
+ match->path = g_strdup(path);
+ match->filter_type = filter;
+
+ l = g_slist_find_custom(list, match, cmp_observer);
+ g_free(match->sender);
+ g_free(match->path);
+ g_free(match);
+
+ return (l ? l->data : NULL);
+}
+
+static void observer_exit(DBusConnection *conn, void *user_data)
+{
+ struct observer_watcher *obs = user_data;
+ struct btd_adapter *adapter = obs->adapter;
+
+ if (obs->filter_type == FILTER_SERVICE_UUID)
+ DBG("Service Data Observer watcher %s disconnected", obs->path);
+ else
+ DBG("Manufacturer Data Observer watcher %s disconnected",
+ obs->path);
+
+ adapter->observers = g_slist_remove(adapter->observers, obs);
+
+ if (adapter->observers == NULL) {
+ int err;
+
+ err = mgmt_set_observer(adapter->dev_id, FALSE);
+ if (err < 0)
+ error("Failed to set Observer: %s (%d)",
+ strerror(-err), -err);
+ }
+
+ destroy_observer(obs);
+}
+
static DBusMessage *register_service_observer(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct btd_adapter *adapter = data;
+ struct observer_watcher *obs;
const char *path, *sender = dbus_message_get_sender(msg);
unsigned int uuid;
int err;
@@ -1630,8 +1720,26 @@ static DBusMessage *register_service_observer(DBusConnection *conn,
DBUS_TYPE_INVALID) == FALSE)
return btd_error_invalid_args(msg);
+ obs = find_observer(adapter->observers, sender, path,
+ FILTER_SERVICE_UUID);
+ if (obs)
+ return btd_error_already_exists(msg);
+
+ obs = g_new0(struct observer_watcher, 1);
+ obs->filter_type = FILTER_SERVICE_UUID;
+ obs->filter_data = GUINT_TO_POINTER(uuid);
+ obs->sender = g_strdup(sender);
+ obs->path = g_strdup(path);
+ obs->adapter = btd_adapter_ref(adapter);
+ obs->id = g_dbus_add_disconnect_watch(conn, sender, observer_exit,
+ obs, NULL);
+
+ adapter->observers = g_slist_prepend(adapter->observers, obs);
+
err = mgmt_set_observer(adapter->dev_id, TRUE);
if (err < 0) {
+ adapter->observers = g_slist_remove(adapter->observers, obs);
+ destroy_observer(obs);
error("Failed to set Observer: %s (%d)", strerror(-err), -err);
return btd_error_failed(msg, strerror(-err));
@@ -1648,15 +1756,28 @@ static DBusMessage *unregister_service_observer(DBusConnection *conn,
{
const char *path, *sender = dbus_message_get_sender(msg);
struct btd_adapter *adapter = data;
- int err;
+ struct observer_watcher *obs;
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID) == FALSE)
return btd_error_invalid_args(msg);
- err = mgmt_set_observer(adapter->dev_id, FALSE);
- if (err < 0)
- return btd_error_failed(msg, strerror(-err));
+ obs = find_observer(adapter->observers, sender, path,
+ FILTER_SERVICE_UUID);
+ if (obs == NULL)
+ return btd_error_does_not_exist(msg);
+
+ adapter->observers = g_slist_remove(adapter->observers, obs);
+ g_dbus_remove_watch(connection, obs->id);
+ destroy_observer(obs);
+
+ if (adapter->observers == NULL) {
+ int err;
+
+ err = mgmt_set_observer(adapter->dev_id, FALSE);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+ }
DBG("Service Data Observer unregistered for hci%d at %s:%s",
adapter->dev_id, sender, path);
@@ -1668,6 +1789,7 @@ static DBusMessage *register_manufobserver(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct btd_adapter *adapter = data;
+ struct observer_watcher *obs;
const char *path, *sender = dbus_message_get_sender(msg);
unsigned int company_id;
int err;
@@ -1677,8 +1799,26 @@ static DBusMessage *register_manufobserver(DBusConnection *conn,
DBUS_TYPE_INVALID) == FALSE)
return btd_error_invalid_args(msg);
+ obs = find_observer(adapter->observers, sender, path,
+ FILTER_COMPANY_IC);
+ if (obs)
+ return btd_error_already_exists(msg);
+
+ obs = g_new0(struct observer_watcher, 1);
+ obs->filter_type = FILTER_COMPANY_IC;
+ obs->filter_data = GUINT_TO_POINTER(company_id);
+ obs->sender = g_strdup(sender);
+ obs->path = g_strdup(path);
+ obs->adapter = btd_adapter_ref(adapter);
+ obs->id = g_dbus_add_disconnect_watch(conn, sender, observer_exit,
+ obs, NULL);
+
+ adapter->observers = g_slist_prepend(adapter->observers, obs);
+
err = mgmt_set_observer(adapter->dev_id, TRUE);
if (err < 0) {
+ adapter->observers = g_slist_remove(adapter->observers, obs);
+ destroy_observer(obs);
error("Failed to set Observer: %s (%d)", strerror(-err), -err);
return btd_error_failed(msg, strerror(-err));
@@ -1695,15 +1835,28 @@ static DBusMessage *unregister_manufobserver(DBusConnection *conn,
{
const char *path, *sender = dbus_message_get_sender(msg);
struct btd_adapter *adapter = data;
- int err;
+ struct observer_watcher *obs;
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID) == FALSE)
return btd_error_invalid_args(msg);
- err = mgmt_set_observer(adapter->dev_id, FALSE);
- if (err < 0)
- return btd_error_failed(msg, strerror(-err));
+ obs = find_observer(adapter->observers, sender, path,
+ FILTER_COMPANY_IC);
+ if (obs == NULL)
+ return btd_error_does_not_exist(msg);
+
+ adapter->observers = g_slist_remove(adapter->observers, obs);
+ g_dbus_remove_watch(connection, obs->id);
+ destroy_observer(obs);
+
+ if (adapter->observers == NULL) {
+ int err;
+
+ err = mgmt_set_observer(adapter->dev_id, FALSE);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+ }
DBG("Manufacturer Specific Data Observer unregistered for hci%d at "
"%s:%s", adapter->dev_id, sender, path);
@@ -2470,6 +2623,16 @@ static void adapter_free(gpointer user_data)
g_slist_free(adapter->oor_devices);
+ if (adapter->observers) {
+ int err;
+
+ err = mgmt_set_observer(adapter->dev_id, FALSE);
+ if (err < 0)
+ error("Failed to set Observer: %s (%d)",
+ strerror(-err), -err);
+ g_slist_free_full(adapter->observers, destroy_observer);
+ }
+
g_free(adapter->path);
g_free(adapter->name);
g_free(adapter);
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 21/33] eir: Add manufacturer and service data fields
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
From: Jefferson Delfes <jefferson.delfes@openbossa.org>
For advertising, there are another possible fields, Service Data and
Manufacturer Specific Data.
---
src/eir.c | 43 +++++++++++++++++++++++++++++++++++++++++++
src/eir.h | 16 ++++++++++++++++
2 files changed, 59 insertions(+)
diff --git a/src/eir.c b/src/eir.c
index 9d42917..676e303 100644
--- a/src/eir.c
+++ b/src/eir.c
@@ -38,12 +38,32 @@
#include "glib-helper.h"
#include "eir.h"
+static void svc_data_free(void *p)
+{
+ struct svc_data *sdata = p;
+
+ g_free(sdata->data);
+ g_free(sdata);
+}
+
+static void manuf_data_free(void *p)
+{
+ struct manuf_data *mdata = p;
+
+ g_free(mdata->data);
+ g_free(mdata);
+}
+
void eir_data_free(struct eir_data *eir)
{
g_slist_free_full(eir->services, g_free);
eir->services = NULL;
g_free(eir->name);
eir->name = NULL;
+ g_slist_free_full(eir->svcs_data, svc_data_free);
+ eir->svcs_data = NULL;
+ g_slist_free_full(eir->manufs_data, manuf_data_free);
+ eir->manufs_data = NULL;
}
static void eir_parse_uuid16(struct eir_data *eir, void *data, uint8_t len)
@@ -107,6 +127,8 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
while (len < eir_len - 1) {
uint8_t field_len = eir_data[0];
uint8_t data_len, *data = &eir_data[2];
+ struct svc_data *sdata;
+ struct manuf_data *mdata;
/* Check for the end of EIR */
if (field_len == 0)
@@ -163,11 +185,32 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
memcpy(eir->dev_class, data, 3);
break;
+ case EIR_SVC_DATA:
+ if (data_len < 2)
+ break;
+ sdata = g_new(struct svc_data, 1);
+ sdata->uuid = bt_get_le16(data);
+ sdata->data_len = data_len - 2;
+ sdata->data = g_memdup(data + 2, data_len - 2);
+ eir->svcs_data = g_slist_append(eir->svcs_data, sdata);
+ break;
+
case EIR_GAP_APPEARANCE:
if (data_len < 2)
break;
eir->appearance = bt_get_le16(data);
break;
+
+ case EIR_MANUF_DATA:
+ if (data_len < 2)
+ break;
+ mdata = g_new(struct manuf_data, 1);
+ mdata->company_id = bt_get_le16(data);
+ mdata->data_len = data_len - 2;
+ mdata->data = g_memdup(data + 2, data_len - 2);
+ eir->manufs_data = g_slist_append(eir->manufs_data,
+ mdata);
+ break;
}
eir_data += field_len + 1;
diff --git a/src/eir.h b/src/eir.h
index 3c81024..f8e6c7c 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -34,13 +34,27 @@
#define EIR_TX_POWER 0x0A /* transmit power level */
#define EIR_CLASS_OF_DEV 0x0D /* Class of Device */
#define EIR_DEVICE_ID 0x10 /* device ID */
+#define EIR_SVC_DATA 0x16 /* service data */
#define EIR_GAP_APPEARANCE 0x19 /* GAP appearance */
+#define EIR_MANUF_DATA 0xFF /* manufacturer specific data */
struct uuid_info {
uuid_t uuid;
uint8_t svc_hint;
};
+struct svc_data {
+ uint16_t uuid;
+ uint8_t data_len;
+ uint8_t *data;
+};
+
+struct manuf_data {
+ uint16_t company_id;
+ uint8_t data_len;
+ uint8_t *data;
+};
+
struct eir_data {
GSList *services;
int flags;
@@ -48,6 +62,8 @@ struct eir_data {
uint8_t dev_class[3];
uint16_t appearance;
gboolean name_complete;
+ GSList *svcs_data;
+ GSList *manufs_data;
};
void eir_data_free(struct eir_data *eir);
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 22/33] observer: Add ServiceReceived() and ManufacturerReceived() D-Bus method
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
When an advertising matches with the filter registered in
RegisterServiceObserver() or RegisterManufacturerObserver(), the
respective data is sent to all observers registered with this filter
using ServiceReceived() or ManufacturerReceived(), respectively.
---
src/adapter.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 3b8cbcd..cd0a1b4 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -168,6 +168,11 @@ struct btd_adapter {
GSList *loaded_drivers;
};
+struct broadcast_data {
+ struct eir_data *eir_data;
+ char peer_addr[18];
+};
+
static void dev_info_free(void *data)
{
struct remote_dev_info *dev = data;
@@ -3107,6 +3112,106 @@ static char *read_stored_data(bdaddr_t *local, bdaddr_t *peer,
return textfile_get(filename, key);
}
+static void service_received(struct observer_watcher *obs, char *peer_addr,
+ struct svc_data *sdata)
+{
+ const char *paddr = peer_addr;
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(obs->sender, obs->path,
+ "org.bluez.Observer",
+ "ServiceReceived");
+ if (msg == NULL) {
+ error("Unable to allocate new ServiceReceived method");
+ return;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_UINT16, &sdata->uuid,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &sdata->data, sdata->data_len,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_set_no_reply(msg, TRUE);
+ g_dbus_send_message(connection, msg);
+}
+
+static void manufacturer_received(struct observer_watcher *obs,
+ char *peer_addr, struct manuf_data *mdata)
+{
+ const char *paddr = peer_addr;
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(obs->sender, obs->path,
+ "org.bluez.Observer",
+ "ManufacturerReceived");
+ if (msg == NULL) {
+ error("Unable to allocate new ManufacturerReceived method");
+ return;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_UINT16, &mdata->company_id,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &mdata->data, mdata->data_len,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_set_no_reply(msg, TRUE);
+ g_dbus_send_message(connection, msg);
+}
+
+static void update_observer(gpointer data, gpointer user_data)
+{
+ struct observer_watcher *obs = data;
+ struct broadcast_data *bdata = user_data;
+ struct eir_data *eir = bdata->eir_data;
+ GSList *l;
+
+ if (obs->filter_type == FILTER_SERVICE_UUID) {
+ for (l = eir->svcs_data; l != NULL; l = g_slist_next(l)) {
+ struct svc_data *sdata = l->data;
+ uint16_t uuid = GPOINTER_TO_UINT(obs->filter_data);
+
+ if (uuid == sdata->uuid)
+ service_received(obs, bdata->peer_addr, sdata);
+ }
+ } else if (obs->filter_type == FILTER_COMPANY_IC) {
+ for (l = eir->manufs_data; l != NULL; l = g_slist_next(l)) {
+ struct manuf_data *mdata = l->data;
+ uint16_t company_id =
+ GPOINTER_TO_UINT(obs->filter_data);
+
+ if (company_id == mdata->company_id)
+ manufacturer_received(obs, bdata->peer_addr,
+ mdata);
+ }
+ }
+}
+
+static void adapter_broadcast_received(struct btd_adapter *adapter,
+ bdaddr_t *bdaddr, struct eir_data *eir_data)
+{
+ struct broadcast_data *bdata;
+
+ /* No observers listening for advertising */
+ if (adapter->observers == NULL)
+ return;
+
+ /* No service/manufacturer data was sent */
+ if (eir_data->svcs_data == NULL && eir_data->manufs_data == NULL)
+ return;
+
+ bdata = g_new(struct broadcast_data, 1);
+ bdata->eir_data = eir_data;
+ ba2str(bdaddr, bdata->peer_addr);
+
+ DBG("Broadcast received from %s", bdata->peer_addr);
+
+ g_slist_foreach(adapter->observers, update_observer, bdata);
+
+ g_free(bdata);
+}
+
void adapter_update_found_devices(struct btd_adapter *adapter,
bdaddr_t *bdaddr, uint8_t bdaddr_type,
int8_t rssi, uint8_t confirm_name,
@@ -3126,6 +3231,9 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
return;
}
+ /* Send advertsing to observers */
+ adapter_broadcast_received(adapter, bdaddr, &eir_data);
+
dev_class = eir_data.dev_class[0] | (eir_data.dev_class[1] << 8) |
(eir_data.dev_class[2] << 16);
if (dev_class != 0)
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 23/33] observer: Add python test script
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
---
test/test-observer | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
create mode 100755 test/test-observer
diff --git a/test/test-observer b/test/test-observer
new file mode 100755
index 0000000..110f487
--- /dev/null
+++ b/test/test-observer
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+
+'''Observer test script
+'''
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+
+def dbus_data(data):
+ return "".join(["%02x" % c for c in data])
+
+class Observer(dbus.service.Object):
+ @dbus.service.method("org.bluez.Observer",
+ in_signature="sqv", out_signature="")
+ def ServiceReceived(self, address, uuid, value):
+ print("[ " + address + " ]")
+ print(" Service UUID = 0x%04x" % int(uuid))
+ print(" Data = %s" % dbus_data(value))
+ print()
+
+ @dbus.service.method("org.bluez.Observer",
+ in_signature="sqv", out_signature="")
+ def ManufacturerReceived(self, address, cid, value):
+ print("[ " + address + " ]")
+ print(" Company ID = 0x%04x" % int(cid))
+ print(" Data = %s" % dbus_data(value))
+ print()
+
+def property_changed(name, value):
+ print("PropertyChanged('%s', '%s')" % (name, value))
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+ option_list = [
+ make_option("-i", "--adapter", action="store",
+ type="string", dest="adapter"),
+ make_option("-s", "--service", action="store",
+ type="int", dest="service_uuid",
+ help="Service UUID (e.g. \"0x0001\")"),
+ make_option("-c", "--company", action="store",
+ type="int", dest="company_id",
+ help="Company Identifier Code (e.g. \"0x0002\")"),
+ ]
+
+ parser = OptionParser(option_list=option_list)
+
+ (options, args) = parser.parse_args()
+
+ if not options.service_uuid and not options.company_id:
+ parser.error("At least one option is required: -c or -s")
+
+ if options.adapter:
+ adapter_path = manager.FindAdapter(options.adapter)
+ else:
+ adapter_path = manager.DefaultAdapter()
+
+ adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.bluez.Adapter")
+
+ bus.add_signal_receiver(property_changed, bus_name="org.bluez",
+ dbus_interface="org.bluez.Adapter",
+ signal_name="PropertyChanged")
+
+ path = "/test/observer"
+ observer = Observer(bus, path)
+
+ if options.service_uuid:
+ adapter.RegisterServiceObserver(path, dbus.UInt16(options.service_uuid))
+
+ if options.company_id:
+ adapter.RegisterManufacturerObserver(path, dbus.UInt16(options.company_id))
+
+ mainloop = GObject.MainLoop()
+ mainloop.run()
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 24/33] doc: Add Broadcaster D-Bus API documentation
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
This is a "high level" API for Broadcaster GAP role.
---
doc/adapter-api.txt | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 9e2e652..139a1a2 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -224,6 +224,51 @@ Methods dict GetProperties()
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.DoesNotExist
+ void SetServiceData(uint16 uuid, variant data)
+
+ Set Service Data for broadcast. Different applications
+ can register different Adv. data types, and they are
+ all concatenated to form the Adv. data. Broadcasting is
+ enabled as soon as the first SetServiceData() call is
+ made.
+
+ This method can be used to update service data already
+ being broadcasted.
+
+ Use ClearBroadcastData() to release any Adv. data for
+ the application. Advertising data is also released when
+ application exits, and once the last Broadcaster exits,
+ advertising is disabled.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void SetManufacturerData(uint16 cid, variant data)
+
+ Set Manufacturer Specific Data for broadcast. Different
+ applications can register different Adv. data types,
+ and they are all concatenated to form the Adv. data.
+ Broadcasting is enabled as soon as the first
+ SetManufacturerData() call is made.
+
+ This method can be used to update manufacturer data
+ already being broadcasted.
+
+ Use ClearBroadcastData() to release any Adv. data for
+ the application. Advertising data is also released when
+ application exits, and once the last Broadcaster exits,
+ advertising is disabled.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void ClearBroadcastData()
+
+ This method will release any previously set Advertising
+ data.
+
+ Possible errors: org.bluez.Error.Failed
+
Signals PropertyChanged(string name, variant value)
This signal indicates a changed value of the given
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 25/33] adapter: Add D-Bus API for Broadcaster GAP Role
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
From: Jefferson Delfes <jefferson.delfes@openbossa.org>
Implement dummy calls for register or unregister Broadcaster.
---
src/adapter.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index cd0a1b4..61abb34 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1869,6 +1869,24 @@ static DBusMessage *unregister_manufobserver(DBusConnection *conn,
return dbus_message_new_method_return(msg);
}
+static DBusMessage *set_service_data(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_manufacturer_data(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *clear_broadcast_data(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
static const GDBusMethodTable adapter_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
@@ -1924,6 +1942,14 @@ static const GDBusMethodTable adapter_methods[] = {
{ GDBUS_METHOD("UnregisterManufacturerObserver",
GDBUS_ARGS({ "observer", "o" }), NULL,
unregister_manufobserver) },
+ { GDBUS_METHOD("SetServiceData", GDBUS_ARGS({ "uuid", "q" },
+ { "data", "ay" }), NULL,
+ set_service_data) },
+ { GDBUS_METHOD("SetManufacturerData", GDBUS_ARGS({ "company_id", "q" },
+ { "data", "ay" }), NULL,
+ set_manufacturer_data) },
+ { GDBUS_METHOD("ClearBroadcastData", NULL, NULL,
+ clear_broadcast_data) },
{ }
};
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 26/33] lib: Maximum value to advertising and scan response
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
Create a constant to define the maximum lenght to advertising and scan
response data format.
---
lib/hci.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/hci.h b/lib/hci.h
index f90ac26..c93b1c6 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -1496,17 +1496,19 @@ typedef struct {
} __attribute__ ((packed)) le_read_advertising_channel_tx_power_rp;
#define LE_READ_ADVERTISING_CHANNEL_TX_POWER_RP_SIZE 2
+#define HCI_LE_MAX_ADV_DATA_LENGTH 31
+
#define OCF_LE_SET_ADVERTISING_DATA 0x0008
typedef struct {
uint8_t length;
- uint8_t data[31];
+ uint8_t data[HCI_LE_MAX_ADV_DATA_LENGTH];
} __attribute__ ((packed)) le_set_advertising_data_cp;
#define LE_SET_ADVERTISING_DATA_CP_SIZE 32
#define OCF_LE_SET_SCAN_RESPONSE_DATA 0x0009
typedef struct {
uint8_t length;
- uint8_t data[31];
+ uint8_t data[HCI_LE_MAX_ADV_DATA_LENGTH];
} __attribute__ ((packed)) le_set_scan_response_data_cp;
#define LE_SET_SCAN_RESPONSE_DATA_CP_SIZE 32
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 27/33] broadcaster: Add SetServiceData() D-Bus method
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
From: Jefferson Delfes <jefferson.delfes@openbossa.org>
Receive the service UUID with advertising data will be set in device.
---
src/adapter.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 61abb34..118e633 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1872,6 +1872,23 @@ static DBusMessage *unregister_manufobserver(DBusConnection *conn,
static DBusMessage *set_service_data(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ struct btd_adapter *adapter = data;
+ const char *sender;
+ uint16_t uuid;
+ uint8_t *sdata;
+ int ssize;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &uuid,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &sdata, &ssize,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ sender = dbus_message_get_sender(msg);
+
+ DBG("Service Data Broadcaster registered for hci%d at %s",
+ adapter->dev_id, sender);
+
return dbus_message_new_method_return(msg);
}
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 28/33] broadcaster: Add SetManufacturerData() D-Bus method
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
Receive the Company Identifier Code with advertising data will be set in
device.
---
src/adapter.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 118e633..94c813c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1895,6 +1895,23 @@ static DBusMessage *set_service_data(DBusConnection *conn,
static DBusMessage *set_manufacturer_data(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ struct btd_adapter *adapter = data;
+ const char *sender;
+ uint16_t company_id;
+ uint8_t *mdata;
+ int msize;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &company_id,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &mdata, &msize,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ sender = dbus_message_get_sender(msg);
+
+ DBG("Manufacturer Specific Data Broadcaster registered for hci%d at %s",
+ adapter->dev_id, sender);
+
return dbus_message_new_method_return(msg);
}
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 29/33] broadcaster: Add list of broadcasters session
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
From: Jefferson Delfes <jefferson.delfes@openbossa.org>
The adapter will keep a list of broadcasters which set new values of
advertising. The new broadcaster is added on the list when the function
SetServiceData() or SetManufacturerData() is called.
---
src/adapter.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/eir.h | 3 ++
2 files changed, 138 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 94c813c..3041d6c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -117,6 +117,17 @@ struct observer_watcher {
char *path; /* DBus path */
};
+struct bcast_session {
+ struct btd_adapter *adapter;
+ guint id;
+ char *owner;
+ uint8_t data_type;
+ uint16_t data_id;
+ uint8_t data_len;
+ /* Reserve 2 octets for ServiceUUID/CompanyId */
+ uint8_t data[EIR_DATA_MAX_LEN - sizeof(uint16_t)];
+};
+
struct btd_adapter {
uint16_t dev_id;
gboolean up;
@@ -147,6 +158,7 @@ struct btd_adapter {
GSList *mode_sessions; /* Request Mode sessions */
GSList *disc_sessions; /* Discovery sessions */
GSList *observers; /* Observer watchers */
+ GSList *bcast_sessions; /* Broadcast sessions */
guint discov_id; /* Discovery timer */
gboolean discovering; /* Discovery active */
gboolean discov_suspended; /* Discovery suspended */
@@ -1869,10 +1881,84 @@ static DBusMessage *unregister_manufobserver(DBusConnection *conn,
return dbus_message_new_method_return(msg);
}
+static void free_bcast_session(gpointer user_data)
+{
+ struct bcast_session *session = user_data;
+
+ btd_adapter_unref(session->adapter);
+
+ g_dbus_remove_watch(connection, session->id);
+
+ g_free(session->owner);
+ g_free(session);
+}
+
+static gint cmp_bcast_session(gconstpointer a, gconstpointer b)
+{
+ const struct bcast_session *session = a;
+ const struct bcast_session *match = b;
+ int ret;
+
+ ret = g_strcmp0(session->owner, match->owner);
+ if (ret)
+ return ret;
+
+ ret = session->data_type - match->data_type;
+ if (ret)
+ return ret;
+
+ return session->data_id - match->data_id;
+}
+
+static struct bcast_session *find_bcast_session(GSList *list,
+ const char *sender, uint8_t type, uint16_t data_id)
+{
+ struct bcast_session *match;
+ GSList *l;
+
+ match = g_new0(struct bcast_session, 1);
+ match->owner = g_strdup(sender);
+ match->data_type = type;
+ match->data_id = data_id;
+
+ l = g_slist_find_custom(list, match, cmp_bcast_session);
+ g_free(match->owner);
+ g_free(match);
+
+ return (l ? l->data : NULL);
+}
+
+static void bcast_session_exit(DBusConnection *conn, void *user_data)
+{
+ struct bcast_session *session = user_data;
+ struct btd_adapter *adapter = session->adapter;
+ uint8_t type = session->data_type;
+
+ if (type == EIR_SVC_DATA)
+ DBG("Service Data Broadcaster watcher %s disconnected",
+ session->owner);
+ else
+ DBG("Manufacturer Data Broadcasterer watcher %s disconnected",
+ session->owner);
+
+ adapter->bcast_sessions = g_slist_remove(adapter->bcast_sessions,
+ session);
+ free_bcast_session(session);
+
+ /* FIXME: Stop advertising, send data blob from others apps to kernel
+ * with same type and restart advertising*/
+}
+
+static void update_adv_data(struct btd_adapter *adapter,
+ struct bcast_session *session, uint8_t *data, int size)
+{
+}
+
static DBusMessage *set_service_data(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct btd_adapter *adapter = data;
+ struct bcast_session *session;
const char *sender;
uint16_t uuid;
uint8_t *sdata;
@@ -1886,9 +1972,28 @@ static DBusMessage *set_service_data(DBusConnection *conn,
sender = dbus_message_get_sender(msg);
+ session = find_bcast_session(adapter->bcast_sessions, sender,
+ EIR_SVC_DATA, uuid);
+ if (session) {
+ update_adv_data(adapter, session, sdata, ssize);
+ goto done;
+ }
+
+ session = g_new(struct bcast_session, 1);
+ session->data_id = uuid;
+ session->owner = g_strdup(sender);
+ session->adapter = btd_adapter_ref(adapter);
+ session->id = g_dbus_add_disconnect_watch(conn, sender,
+ bcast_session_exit, session,
+ NULL);
+
+ adapter->bcast_sessions = g_slist_prepend(adapter->bcast_sessions,
+ session);
+
DBG("Service Data Broadcaster registered for hci%d at %s",
adapter->dev_id, sender);
+done:
return dbus_message_new_method_return(msg);
}
@@ -1896,6 +2001,7 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct btd_adapter *adapter = data;
+ struct bcast_session *session;
const char *sender;
uint16_t company_id;
uint8_t *mdata;
@@ -1909,9 +2015,28 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
sender = dbus_message_get_sender(msg);
+ session = find_bcast_session(adapter->bcast_sessions, sender,
+ EIR_MANUF_DATA, company_id);
+ if (session != NULL) {
+ update_adv_data(adapter, session, mdata, msize);
+ goto done;
+ }
+
+ session = g_new(struct bcast_session, 1);
+ session->data_id = company_id;
+ session->owner = g_strdup(sender);
+ session->adapter = btd_adapter_ref(adapter);
+ session->id = g_dbus_add_disconnect_watch(conn, sender,
+ bcast_session_exit, session,
+ NULL);
+
+ adapter->bcast_sessions = g_slist_prepend(adapter->bcast_sessions,
+ session);
+
DBG("Manufacturer Specific Data Broadcaster registered for hci%d at %s",
adapter->dev_id, sender);
+done:
return dbus_message_new_method_return(msg);
}
@@ -2698,6 +2823,16 @@ static void adapter_free(gpointer user_data)
g_slist_free_full(adapter->observers, destroy_observer);
}
+ if (adapter->bcast_sessions) {
+ int err;
+
+ err = mgmt_set_broadcaster(adapter->dev_id, FALSE);
+ if (err < 0)
+ error("Failed to set Broadcaster: %s (%d)",
+ strerror(-err), -err);
+ g_slist_free_full(adapter->bcast_sessions, free_bcast_session);
+ }
+
g_free(adapter->path);
g_free(adapter->name);
g_free(adapter);
diff --git a/src/eir.h b/src/eir.h
index f8e6c7c..428fc36 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -38,6 +38,9 @@
#define EIR_GAP_APPEARANCE 0x19 /* GAP appearance */
#define EIR_MANUF_DATA 0xFF /* manufacturer specific data */
+/* Reserve 2 octets for length and data type */
+#define EIR_DATA_MAX_LEN (HCI_MAX_EIR_LENGTH - 2)
+
struct uuid_info {
uuid_t uuid;
uint8_t svc_hint;
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 30/33] broadcaster: Build and send ADV/EIR data blob to kernel
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
SetServiceData() and SetManufacturerData() operations will save all data
and send the ADV/EIR data to kernel. The ADV/EIR data will added in the
current one.
Note: For now, the maximum ADV/EIR data length is limited to 236
(HCI_MAX_EIR_LENGTH - 4) octets. This is need to reserve 2 octets for
length and data type and more 2 octets for UUID/CompanyID. If the
ADV/EIR data from new broadcaster session try to insert more octets than
236 bytes the operation will fail.
---
src/adapter.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 122 insertions(+), 5 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 3041d6c..02306a1 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -86,6 +86,9 @@
#define FILTER_SERVICE_UUID 0x01
#define FILTER_COMPANY_IC 0x02
+/* Flags for Broadcaster */
+#define BCAST_DATA_NORMAL_PRIORITY 0x00
+
static DBusConnection *connection = NULL;
static GSList *adapter_drivers = NULL;
@@ -1928,6 +1931,60 @@ static struct bcast_session *find_bcast_session(GSList *list,
return (l ? l->data : NULL);
}
+static void send_advdata_blob(struct btd_adapter *adapter,
+ struct bcast_session *session)
+{
+ uint8_t data[EIR_DATA_MAX_LEN];
+ uint16_t *u16 = (void *) data;
+ int err;
+
+ bt_put_unaligned(htobs(session->data_id), u16);
+ memcpy(data + sizeof(session->data_id), session->data,
+ session->data_len);
+
+ err = mgmt_set_controller_data(adapter->dev_id,
+ BCAST_DATA_NORMAL_PRIORITY,
+ session->data_type, data,
+ session->data_len + sizeof(session->data_id));
+ if (err < 0)
+ error("Failed to set controller data in Broadcaster: %s (%d)",
+ strerror(-err), -err);
+}
+
+static void restore_bcast_type(struct btd_adapter *adapter, uint8_t type)
+{
+ GSList *l;
+ int err;
+
+ err = mgmt_set_broadcaster(adapter->dev_id, FALSE);
+ if (err < 0) {
+ error("Failed to set Broadcaster: %s (%d)", strerror(-err),
+ -err);
+ return;
+ }
+
+ err = mgmt_unset_controller_data(adapter->dev_id, type);
+ if (err < 0) {
+ error("Failed to unset controller data: %s (%d)",
+ strerror(-err), -err);
+ return;
+ }
+
+ for (l = adapter->bcast_sessions; l; l = g_slist_next(l)) {
+ struct bcast_session *session = l->data;
+
+ if (session->data_type == type)
+ send_advdata_blob(adapter, session);
+ }
+
+ if (adapter->bcast_sessions) {
+ err = mgmt_set_broadcaster(adapter->dev_id, TRUE);
+ if (err < 0)
+ error("Failed to set Broadcaster: %s (%d)",
+ strerror(-err), -err);
+ }
+}
+
static void bcast_session_exit(DBusConnection *conn, void *user_data)
{
struct bcast_session *session = user_data;
@@ -1943,10 +2000,10 @@ static void bcast_session_exit(DBusConnection *conn, void *user_data)
adapter->bcast_sessions = g_slist_remove(adapter->bcast_sessions,
session);
- free_bcast_session(session);
- /* FIXME: Stop advertising, send data blob from others apps to kernel
- * with same type and restart advertising*/
+ restore_bcast_type(adapter, type);
+
+ free_bcast_session(session);
}
static void update_adv_data(struct btd_adapter *adapter,
@@ -1962,7 +2019,7 @@ static DBusMessage *set_service_data(DBusConnection *conn,
const char *sender;
uint16_t uuid;
uint8_t *sdata;
- int ssize;
+ int ssize, err;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &uuid,
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
@@ -1970,6 +2027,12 @@ static DBusMessage *set_service_data(DBusConnection *conn,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
+ /* It will accept new ADV/EIR data only if there is space for complete
+ * data. Reserve 2 octets for Service UUID */
+ if (ssize + sizeof(uint16_t) > EIR_DATA_MAX_LEN)
+ return btd_error_failed(msg, "New ADV/EIR data is bigger than"
+ " permitted");
+
sender = dbus_message_get_sender(msg);
session = find_bcast_session(adapter->bcast_sessions, sender,
@@ -1981,8 +2044,13 @@ static DBusMessage *set_service_data(DBusConnection *conn,
session = g_new(struct bcast_session, 1);
session->data_id = uuid;
+ session->data_len = ssize;
session->owner = g_strdup(sender);
session->adapter = btd_adapter_ref(adapter);
+ session->data_type = EIR_SVC_DATA;
+
+ memcpy(session->data, sdata, ssize);
+
session->id = g_dbus_add_disconnect_watch(conn, sender,
bcast_session_exit, session,
NULL);
@@ -1990,11 +2058,30 @@ static DBusMessage *set_service_data(DBusConnection *conn,
adapter->bcast_sessions = g_slist_prepend(adapter->bcast_sessions,
session);
+ err = mgmt_set_broadcaster(adapter->dev_id, FALSE);
+ if (err < 0)
+ goto failed;
+
+ send_advdata_blob(adapter, session);
+
+ err = mgmt_set_broadcaster(adapter->dev_id, TRUE);
+ if (err < 0)
+ goto failed;
+
DBG("Service Data Broadcaster registered for hci%d at %s",
adapter->dev_id, sender);
done:
return dbus_message_new_method_return(msg);
+
+failed:
+ error("Failed to set Broadcaster: %s (%d)", strerror(-err), -err);
+
+ adapter->bcast_sessions = g_slist_remove(adapter->bcast_sessions,
+ session);
+ free_bcast_session(session);
+
+ return btd_error_failed(msg, strerror(-err));
}
static DBusMessage *set_manufacturer_data(DBusConnection *conn,
@@ -2005,7 +2092,7 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
const char *sender;
uint16_t company_id;
uint8_t *mdata;
- int msize;
+ int msize, err;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &company_id,
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
@@ -2013,6 +2100,12 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
+ /* It will accept new ADV/EIR data only if there is space for complete
+ * data. Reserve 2 octets for Company Identifier Code */
+ if (msize + sizeof(uint16_t) > EIR_DATA_MAX_LEN)
+ return btd_error_failed(msg, "New ADV/EIR data is bigger than"
+ " permitted");
+
sender = dbus_message_get_sender(msg);
session = find_bcast_session(adapter->bcast_sessions, sender,
@@ -2024,8 +2117,13 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
session = g_new(struct bcast_session, 1);
session->data_id = company_id;
+ session->data_len = msize;
session->owner = g_strdup(sender);
session->adapter = btd_adapter_ref(adapter);
+ session->data_type = EIR_MANUF_DATA;
+
+ memcpy(session->data, mdata, msize);
+
session->id = g_dbus_add_disconnect_watch(conn, sender,
bcast_session_exit, session,
NULL);
@@ -2033,11 +2131,30 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
adapter->bcast_sessions = g_slist_prepend(adapter->bcast_sessions,
session);
+ err = mgmt_set_broadcaster(adapter->dev_id, FALSE);
+ if (err < 0)
+ goto failed;
+
+ send_advdata_blob(adapter, session);
+
+ err = mgmt_set_broadcaster(adapter->dev_id, TRUE);
+ if (err < 0)
+ goto failed;
+
DBG("Manufacturer Specific Data Broadcaster registered for hci%d at %s",
adapter->dev_id, sender);
done:
return dbus_message_new_method_return(msg);
+
+failed:
+ error("Failed to set Broadcaster: %s (%d)", strerror(-err), -err);
+
+ adapter->bcast_sessions = g_slist_remove(adapter->bcast_sessions,
+ session);
+ free_bcast_session(session);
+
+ return btd_error_failed(msg, strerror(-err));
}
static DBusMessage *clear_broadcast_data(DBusConnection *conn,
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 31/33] broadcaster: Add ClearBroadcastData() D-Bus method
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
The ClearBroadcastData() function will clean all data (Service Data or
Manufacturer Specific Data) set by the current application. All data set
by any other application will be kept.
---
src/adapter.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 02306a1..bbf6b06 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2157,9 +2157,89 @@ failed:
return btd_error_failed(msg, strerror(-err));
}
+static void restore_bcast_data(gpointer data, gpointer user_data)
+{
+ struct bcast_session *session = data, *cleared = user_data;
+
+ if (session == cleared)
+ return;
+
+ if (session->data_type != cleared->data_type)
+ return;
+
+ send_advdata_blob(session->adapter, session);
+}
+
+static gint cmp_bcast_session_owner(gconstpointer a, gconstpointer b)
+{
+ const struct bcast_session *session = a;
+ const char *owner = b;
+
+ return g_strcmp0(session->owner, owner);
+}
+
+static gboolean find_bcast_session_by_owner(struct btd_adapter *adapter,
+ const char *sender,
+ struct bcast_session **session)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(adapter->bcast_sessions, sender,
+ cmp_bcast_session_owner);
+ if (!l)
+ return FALSE;
+
+ if (session)
+ *session = l->data;
+
+ return TRUE;
+}
+
static DBusMessage *clear_broadcast_data(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ struct btd_adapter *adapter = data;
+ struct bcast_session *session;
+ const char *sender;
+ int err;
+
+ sender = dbus_message_get_sender(msg);
+
+ DBG("Clear all data int broadcaster registered for hci%d at %s",
+ adapter->dev_id, sender);
+
+ err = mgmt_set_broadcaster(adapter->dev_id, FALSE);
+ if (err < 0)
+ error("Failed to set Broadcaster: %s (%d)", strerror(-err),
+ -err);
+
+ while (find_bcast_session_by_owner(adapter, sender, &session)) {
+ uint8_t type = session->data_type;
+
+ err = mgmt_unset_controller_data(adapter->dev_id, type);
+ if (err < 0)
+ error("Failed to set Broadcaster: %s (%d)",
+ strerror(-err), -err);
+
+ /* mgmt_unset_controller_data() also clears broadcast data from
+ * other clients with the same data type, so they need to be
+ * restored. */
+ g_slist_foreach(adapter->bcast_sessions, restore_bcast_data,
+ session);
+
+ adapter->bcast_sessions =
+ g_slist_remove(adapter->bcast_sessions, session);
+
+ free_bcast_session(session);
+ }
+
+ if (adapter->bcast_sessions) {
+ err = mgmt_set_broadcaster(adapter->dev_id, TRUE);
+ if (err < 0)
+ error("Failed to set Broadcaster: %s (%d)",
+ strerror(-err), -err);
+ }
+
return dbus_message_new_method_return(msg);
}
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 32/33] broadcaster: Update some data of already broadcast value
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
To update a data set previously, it is need to use same identifier
Service UUID or Company Identifier Code in SetServiceData() and
SetManufacturerData(), respectively.
---
src/adapter.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index bbf6b06..84535cd 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2009,6 +2009,10 @@ static void bcast_session_exit(DBusConnection *conn, void *user_data)
static void update_adv_data(struct btd_adapter *adapter,
struct bcast_session *session, uint8_t *data, int size)
{
+ session->data_len = size;
+ memcpy(session->data, data, size);
+
+ restore_bcast_type(adapter, session->data_type);
}
static DBusMessage *set_service_data(DBusConnection *conn,
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 33/33] broadcaster: Add python test script
From: Bruna Moreira @ 2012-08-27 17:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087005-24693-1-git-send-email-bruna.moreira@openbossa.org>
---
test/test-broadcaster | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100755 test/test-broadcaster
diff --git a/test/test-broadcaster b/test/test-broadcaster
new file mode 100755
index 0000000..35283b1
--- /dev/null
+++ b/test/test-broadcaster
@@ -0,0 +1,76 @@
+#!/usr/bin/python
+
+'''Broadcaster test script
+'''
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+import time
+
+def property_changed(name, value):
+ print("PropertyChanged('%s', '%s')" % (name, value))
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ option_list = [
+ make_option("-i", "--adapter", action="store",
+ type="string", dest="adapter"),
+ make_option("-s", "--service", action="store",
+ type="int", dest="service",
+ help="Format: Service UUID (0xNNNN) followed by" +
+ " Service Data (e.g. aa bb cc)"),
+ make_option("-m", "--manufacturer", action="store",
+ type="int", dest="manufacturer",
+ help="Format: Company Identifier Code (0xNNNN)" +
+ " followed by Manufacturer Specific Data (e.g. 11 22 aa)"),
+ ]
+
+ parser = OptionParser(option_list=option_list,
+ usage="Usage: %prog <-s uuid | -m cid> <data bytes in hex>")
+
+ (options, args) = parser.parse_args()
+ if not args:
+ parser.error("Hex encoded data is required.")
+
+ if options.service and options.manufacturer:
+ parser.error("options -m and -s are mutually exclusive")
+
+ try:
+ data = dbus.Array(map(lambda i: dbus.Byte(int(i, 16)), args))
+ except ValueError:
+ parser.error("Invalid data. Should be hex encoded bytes" +
+ " separated by whitespace.")
+
+ manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+ if options.adapter:
+ adapter_path = manager.FindAdapter(options.adapter)
+ else:
+ adapter_path = manager.DefaultAdapter()
+
+ adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.bluez.Adapter")
+
+ bus.add_signal_receiver(property_changed, bus_name="org.bluez",
+ dbus_interface="org.bluez.Adapter",
+ signal_name="PropertyChanged")
+
+ if options.service:
+ adapter.SetServiceData(dbus.UInt16(options.service), data)
+
+ if options.manufacturer:
+ adapter.SetManufacturerData(dbus.UInt16(options.manufacturer), data)
+
+ mainloop = GObject.MainLoop()
+ mainloop.run()
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 00/22] alert: GATT ANP/PASP server role implementation
From: Anderson Lizardo @ 2012-08-27 17:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
Hi,
This series contain the current implementation for ANP/PASP server roles. The
D-Bus API was based on discussions on BlueZ meeting, and later improvements.
Note that this implementation is not finished yet, we are submitting now for
early feedback. Most importantly, it lacks support for notifications (essential
for ANP) and the enabling/disabling ANP alerts using the control point.
The series contain a test python script and API documentation.
Comments/suggestions are welcome.
Anderson Lizardo (11):
doc: Introduce Alert API
alert: Introduce manager abstraction layer
alert: Add adapter driver
alert: Initial Alert Notification
alert: Add initial support for UnreadAlert D-Bus method
alert: Add per adapter attribute handle information
alert: Update Supported New/Unread Category characteristic values
alert: Update new alert characteristic value
alert: Update unread alert characteristic value
alert: Implement MuteOnce command
alert: Update Alert Status and Ringer Setting characteristic values
Bruna Moreira (4):
alert: Add Phone Alert Service
alert: Add Ringer Control Point characteristic
alert: Add Ringer Setting characteristic
alert: Add Alert Status characteristic
Eder Ruiz Maria (7):
alert: Add initial support for RegisterAlert D-Bus method
alert: Implement category registration in RegisterAlert()
alert: Add initial support for NewAlert D-Bus method
alert: Add support for automatic unregister when agent leave D-Bus
alert: Add support to call MuteOnce()
alert: Add support to call SetRinger()
alert: Add test script
Makefile.am | 3 +-
doc/alert-api.txt | 124 ++++++++
profiles/alert/main.c | 6 +-
profiles/alert/manager.c | 40 +++
profiles/alert/manager.h | 26 ++
profiles/alert/server.c | 768 ++++++++++++++++++++++++++++++++++++++++++++++
test/test-alert | 167 ++++++++++
7 files changed, 1130 insertions(+), 4 deletions(-)
create mode 100644 doc/alert-api.txt
create mode 100644 profiles/alert/manager.c
create mode 100644 profiles/alert/manager.h
create mode 100755 test/test-alert
--
1.7.9.5
^ permalink raw reply
* [RFC BlueZ 01/22] doc: Introduce Alert API
From: Anderson Lizardo @ 2012-08-27 17:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1346087526-15107-1-git-send-email-anderson.lizardo@openbossa.org>
This API will be implemented and initially used by Phone Alert Status
and Alert Notification GATT profiles (server role).
---
doc/alert-api.txt | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 124 insertions(+)
create mode 100644 doc/alert-api.txt
diff --git a/doc/alert-api.txt b/doc/alert-api.txt
new file mode 100644
index 0000000..79d65b8
--- /dev/null
+++ b/doc/alert-api.txt
@@ -0,0 +1,124 @@
+BlueZ D-Bus Alert API description
+*********************************
+
+Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT
+
+Introduction
+------------
+
+Currently, there are two different GATT server profiles that depend on
+receiving alerts or notifications from the platform: Phone Alert Status (PASP)
+and Alert Notification (ANP). PASP is very specific to mobile phones, and also
+allows limited control to alerts (i.e. mute once or switch to a silent mode).
+
+This document presents a unified API that allows to register and notify alerts,
+and to control some alerts (using the provided agent object).
+
+
+Alert hierarchy
+===============
+
+Service org.bluez
+Interface org.bluez.Alert
+Object path /org/bluez
+
+Methods void RegisterAlert(string category, object agent)
+
+ Register a new alert category and an agent for it. This
+ means the application will be responsible for notifying
+ BlueZ of any alerts of that category, using the
+ NewAlert() method.
+
+ Supported ANP categories: simple, email, news, call,
+ missed_call, sms_mms, voice_mail, schedule,
+ high_priority, instant_message
+ Supported PASP categories: ringer, vibrate, display
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+ void NewAlert(string category, uint16 count, string description)
+
+ Notify BlueZ of new alert(s) for the given category. The
+ description is relative to the last received alert and
+ can be sender name, caller ID, title, or other
+ information specific to the category.
+
+ For ringer, vibrate and display categories, valid
+ descriptions are "active" and "not active". Alerts from
+ ringer category also accept "enabled" and "disabled",
+ depending on whether ringer is in silent mode or not.
+
+ Description must not exceed 18 bytes when encoded in
+ UTF-8 format, otherwise an error is returned. If there
+ is no description, an empty string should be used.
+
+ The count argument contains the number of alerts not
+ yet acknowledged by the user on the UI. To save D-Bus
+ traffic, events that may generate multiple alerts at
+ the same time (like email, sms, news) should trigger a
+ single NewAlert().
+
+ If there are more than 254 new alerts, count must be
+ set to 255. PASP alerts should always set count to 1.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+ void UnreadAlert(string category, uint16 count)
+
+ Some services (like SMS and e-mail) keep track of
+ number of unread items. This method allows to update
+ this counter, so peer devices can be notified using
+ Alert Notification Profile.
+
+ If there are more than 254 unread alerts, count must be
+ set to 255.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+Alert Agent hierarchy
+=====================
+
+Service org.bluez
+Interface org.bluez.AlertAgent
+Object path freely definable
+
+Methods void MuteOnce()
+
+ This method is only called if "ringer" alert category
+ is specified when registering the agent.
+
+ Mute the ringer once (e.g. during a incoming call). If
+ ringer is not active, does nothing.
+
+ void SetRinger(string mode)
+
+ This method is only called if "ringer" alert category
+ is specified when registering the agent.
+
+ Set ringer to the specified mode. If mode is "enabled",
+ ringer is set to the default mode, as defined by the
+ current active profile. If mode is "disabled", ringer
+ will not activate on incoming calls, until it is set
+ back to "enabled" mode.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+ void Suspend(string category)
+
+ Suspend alerts for this category, which means that
+ new/unread alerts should not be reported to save D-Bus
+ traffic. This means that no client has enabled this
+ alert yet.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+ void Resume(string category)
+
+ Resume alerts for this category.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+ void Release()
+
+ Release this agent. At this point, it will be not used
+ by BlueZ anymore and can be destroyed by the owner.
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 02/22] alert: Introduce manager abstraction layer
From: Anderson Lizardo @ 2012-08-27 17:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1346087526-15107-1-git-send-email-anderson.lizardo@openbossa.org>
This abstraction layer makes the GATT Phone Alert Status and Alert
Notification implementation consistent with other GATT profiles.
---
Makefile.am | 3 ++-
profiles/alert/main.c | 6 +++---
profiles/alert/manager.c | 40 ++++++++++++++++++++++++++++++++++++++++
profiles/alert/manager.h | 26 ++++++++++++++++++++++++++
4 files changed, 71 insertions(+), 4 deletions(-)
create mode 100644 profiles/alert/manager.c
create mode 100644 profiles/alert/manager.h
diff --git a/Makefile.am b/Makefile.am
index 4977a05..1088991 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -219,7 +219,8 @@ builtin_sources += profiles/thermometer/main.c \
profiles/thermometer/thermometer.h \
profiles/thermometer/thermometer.c \
profiles/alert/main.c profiles/alert/server.h \
- profiles/alert/server.c \
+ profiles/alert/server.c profiles/alert/manager.h \
+ profiles/alert/manager.c \
profiles/time/main.c profiles/time/server.h \
profiles/time/server.c profiles/time/manager.c \
profiles/time/manager.h \
diff --git a/profiles/alert/main.c b/profiles/alert/main.c
index ec4ab6d..5e6910a 100644
--- a/profiles/alert/main.c
+++ b/profiles/alert/main.c
@@ -33,7 +33,7 @@
#include "plugin.h"
#include "hcid.h"
#include "log.h"
-#include "server.h"
+#include "manager.h"
static int alert_init(void)
{
@@ -42,7 +42,7 @@ static int alert_init(void)
return -ENOTSUP;
}
- return alert_server_init();
+ return alert_manager_init();
}
static void alert_exit(void)
@@ -50,7 +50,7 @@ static void alert_exit(void)
if (!main_opts.gatt_enabled)
return;
- alert_server_exit();
+ alert_manager_exit();
}
BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
diff --git a/profiles/alert/manager.c b/profiles/alert/manager.c
new file mode 100644
index 0000000..eb2d627
--- /dev/null
+++ b/profiles/alert/manager.c
@@ -0,0 +1,40 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Copyright (C) 2012 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 "manager.h"
+#include "server.h"
+
+int alert_manager_init(void)
+{
+ return alert_server_init();
+}
+
+void alert_manager_exit(void)
+{
+ alert_server_exit();
+}
diff --git a/profiles/alert/manager.h b/profiles/alert/manager.h
new file mode 100644
index 0000000..e4c6bd0
--- /dev/null
+++ b/profiles/alert/manager.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Copyright (C) 2012 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 alert_manager_init(void);
+void alert_manager_exit(void);
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 03/22] alert: Add adapter driver
From: Anderson Lizardo @ 2012-08-27 17:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1346087526-15107-1-git-send-email-anderson.lizardo@openbossa.org>
---
profiles/alert/server.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index d91b156..3fda23d 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -26,13 +26,32 @@
#include <config.h>
#endif
+#include "adapter.h"
#include "server.h"
+static int alert_server_probe(struct btd_adapter *adapter)
+{
+ return 0;
+}
+
+static void alert_server_remove(struct btd_adapter *adapter)
+{
+}
+
+struct btd_adapter_driver alert_server_driver = {
+ .name = "gatt-alert-server",
+ .probe = alert_server_probe,
+ .remove = alert_server_remove,
+};
+
int alert_server_init(void)
{
+ btd_register_adapter_driver(&alert_server_driver);
+
return 0;
}
void alert_server_exit(void)
{
+ btd_unregister_adapter_driver(&alert_server_driver);
}
--
1.7.9.5
^ permalink raw reply related
* [RFC BlueZ 04/22] alert: Add Phone Alert Service
From: Anderson Lizardo @ 2012-08-27 17:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1346087526-15107-1-git-send-email-anderson.lizardo@openbossa.org>
From: Bruna Moreira <bruna.moreira@openbossa.org>
---
profiles/alert/server.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 3fda23d..cbf751f 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -26,11 +26,33 @@
#include <config.h>
#endif
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "att.h"
#include "adapter.h"
+#include "gatt-service.h"
+#include "gattrib.h"
+#include "gatt.h"
#include "server.h"
+#define PHONE_ALERT_STATUS_SVC_UUID 0x180E
+
+static void register_phone_alert_service(struct btd_adapter *adapter)
+{
+ bt_uuid_t uuid;
+
+ bt_uuid16_create(&uuid, PHONE_ALERT_STATUS_SVC_UUID);
+
+ /* Phone Alert Status Service */
+ gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+ GATT_OPT_INVALID);
+}
+
static int alert_server_probe(struct btd_adapter *adapter)
{
+ register_phone_alert_service(adapter);
+
return 0;
}
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox