2014-09-24 22:57:40

by Scott James Remnant

[permalink] [raw]
Subject: [PATCH] core: add D-Bus property for TxPower

This is presented as a raw property rather than a parsed "PathLoss"
property because in the case of many devices, this specific field will
not be present and instead the TX power will have to be parsed from
manufacturer-specific data anyway.

It's better therefore to document the Path Loss equation rather than
hide it.
---
doc/device-api.txt | 12 ++++++++++++
src/adapter.c | 6 ++++--
src/device.c | 41 +++++++++++++++++++++++++++++++++++++++++
src/device.h | 1 +
4 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/doc/device-api.txt b/doc/device-api.txt
index 86d8af8..68388e9 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -193,3 +193,15 @@ Properties string Address [readonly]

Received Signal Strength Indicator of the remote
device (inquiry or advertising).
+
+ int16 TxPower [readonly, optional]
+
+ Transmission power claimed by the remote device
+ (inquiry or advertising). Many devices may not make
+ this available at all, or may incorporate this data
+ into a manufacturer or service-specific field instead.
+
+ However the remote transmission power is obtained,
+ path loss can be calculated by the equation:
+
+ Path Loss = Tx Power - RSSI
diff --git a/src/adapter.c b/src/adapter.c
index 92ee1a0..1b44dc5 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1585,16 +1585,17 @@ static int compare_sender(gconstpointer a, gconstpointer b)
return g_strcmp0(client->owner, sender);
}

-static void invalidate_rssi(gpointer a)
+static void invalidate_inquiry_data(gpointer a)
{
struct btd_device *dev = a;

device_set_rssi(dev, 0);
+ device_set_tx_power(dev, 127);
}

static void discovery_cleanup(struct btd_adapter *adapter)
{
- g_slist_free_full(adapter->discovery_found, invalidate_rssi);
+ g_slist_free_full(adapter->discovery_found, invalidate_inquiry_data);
adapter->discovery_found = NULL;
}

@@ -4715,6 +4716,7 @@ static void update_found_devices(struct btd_adapter *adapter,

device_set_legacy(dev, legacy);
device_set_rssi(dev, rssi);
+ device_set_tx_power(dev, eir_data.tx_power);

if (eir_data.appearance != 0)
device_set_appearance(dev, eir_data.appearance);
diff --git a/src/device.c b/src/device.c
index 875a5c5..d4ebf4f 100644
--- a/src/device.c
+++ b/src/device.c
@@ -219,6 +219,7 @@ struct btd_device {

bool legacy;
int8_t rssi;
+ int8_t tx_power;

GIOChannel *att_io;
guint cleanup_id;
@@ -812,6 +813,28 @@ static gboolean dev_property_exists_rssi(const GDBusPropertyTable *property,
return TRUE;
}

+static gboolean dev_property_get_tx_power(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device *dev = data;
+ dbus_int16_t val = dev->tx_power;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT16, &val);
+
+ return TRUE;
+}
+
+static gboolean dev_property_exists_tx_power(const GDBusPropertyTable *property,
+ void *data)
+{
+ struct btd_device *dev = data;
+
+ if (dev->tx_power == 127)
+ return FALSE;
+
+ return TRUE;
+}
+
static gboolean dev_property_get_trusted(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -1957,6 +1980,8 @@ static const GDBusPropertyTable device_properties[] = {
{ "Blocked", "b", dev_property_get_blocked, dev_property_set_blocked },
{ "LegacyPairing", "b", dev_property_get_legacy },
{ "RSSI", "n", dev_property_get_rssi, NULL, dev_property_exists_rssi },
+ { "TxPower", "n", dev_property_get_tx_power, NULL,
+ dev_property_exists_tx_power },
{ "Connected", "b", dev_property_get_connected },
{ "UUIDs", "as", dev_property_get_uuids },
{ "Modalias", "s", dev_property_get_modalias, NULL,
@@ -4107,6 +4132,22 @@ void device_set_rssi(struct btd_device *device, int8_t rssi)
DEVICE_INTERFACE, "RSSI");
}

+void device_set_tx_power(struct btd_device *device, int8_t tx_power)
+{
+ if (!device)
+ return;
+
+ if (device->tx_power == tx_power)
+ return;
+
+ DBG("tx_power %d", tx_power);
+
+ device->tx_power = tx_power;
+
+ g_dbus_emit_property_changed(dbus_conn, device->path,
+ DEVICE_INTERFACE, "TxPower");
+}
+
static gboolean start_discovery(gpointer user_data)
{
struct btd_device *device = user_data;
diff --git a/src/device.h b/src/device.h
index 2e0473e..b568593 100644
--- a/src/device.h
+++ b/src/device.h
@@ -88,6 +88,7 @@ void btd_device_set_trusted(struct btd_device *device, gboolean trusted);
void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type);
void device_set_legacy(struct btd_device *device, bool legacy);
void device_set_rssi(struct btd_device *device, int8_t rssi);
+void device_set_tx_power(struct btd_device *device, int8_t tx_power);
bool btd_device_is_connected(struct btd_device *dev);
uint8_t btd_device_get_bdaddr_type(struct btd_device *dev);
bool device_is_retrying(struct btd_device *device);
--
2.1.0.rc2.206.gedb03e5



2014-09-24 22:57:42

by Scott James Remnant

[permalink] [raw]
Subject: [PATCH] core: add D-Bus property for ServiceData

Since the standard doesn't make any specific requirement that a UUID
present in a Service Data field be also present in a specific UUIDs
field, the UUIDs are also added to that list as well.
---
doc/device-api.txt | 9 ++++++
src/adapter.c | 1 +
src/device.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/device.h | 1 +
src/eir.c | 72 +++++++++++++++++++++++++++++++++++++++++++++
src/eir.h | 11 +++++++
6 files changed, 179 insertions(+)

diff --git a/doc/device-api.txt b/doc/device-api.txt
index 4df6ec9..7d4813a 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -134,6 +134,15 @@ Properties string Address [readonly]
List of 128-bit UUIDs that represents the available
remote services.

+ array{struct of data} ServiceData [readonly, optional]
+
+ List of service-specific data obtained from the device.
+ Each array member is a struct of string containing the
+ 128-bit UUID of the service and an array of bytes
+ containing the service data.
+
+ Duplicate entries for a single service are permitted.
+
array{struct of data} ManufacturerData [readonly, optional]

List of manufacturer-specific data obtained from the
diff --git a/src/adapter.c b/src/adapter.c
index 037a3c3..15b4132 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -4739,6 +4739,7 @@ static void update_found_devices(struct btd_adapter *adapter,
eir_data.did_version);

device_add_eir_uuids(dev, eir_data.services);
+ device_set_eir_service_data(dev, eir_data.service_data);
device_set_eir_manufacturer_data(dev, eir_data.manufacturer_data);

eir_data_free(&eir_data);
diff --git a/src/device.c b/src/device.c
index 3e7a7b4..5df3117 100644
--- a/src/device.c
+++ b/src/device.c
@@ -175,6 +175,7 @@ struct btd_device {
bool svc_refreshed;
GSList *svc_callbacks;
GSList *eir_uuids;
+ GSList *eir_service_data;
GSList *eir_manufacturer_data;
char name[MAX_NAME_LENGTH + 1];
char *alias;
@@ -517,6 +518,8 @@ static void device_free(gpointer user_data)
{
struct btd_device *device = user_data;

+ g_slist_free_full(device->eir_service_data,
+ (GDestroyNotify)eir_service_data_free);
g_slist_free_full(device->eir_manufacturer_data,
(GDestroyNotify)eir_manufacturer_data_free);
g_slist_free_full(device->uuids, g_free);
@@ -974,6 +977,55 @@ static gboolean dev_property_get_uuids(const GDBusPropertyTable *property,
return TRUE;
}

+static gboolean dev_property_exists_service_data(
+ const GDBusPropertyTable *property, void *data)
+{
+ struct btd_device *dev = data;
+
+ return dev->eir_service_data != NULL;
+}
+
+static gboolean dev_property_get_service_data(
+ const GDBusPropertyTable *property, DBusMessageIter *iter, void *data)
+{
+ struct btd_device *dev = data;
+ DBusMessageIter entry;
+ GSList *l;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING, &entry);
+
+ for (l = dev->eir_service_data; l != NULL; l = l->next) {
+ struct eir_service_data *service_data = l->data;
+ DBusMessageIter member, array;
+ char *uuid_str;
+
+ uuid_str = bt_uuid2string(&service_data->uuid);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_STRUCT,
+ NULL, &member);
+ dbus_message_iter_append_basic(&member, DBUS_TYPE_STRING,
+ &uuid_str);
+
+ dbus_message_iter_open_container(&member, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING, &array);
+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+ &(service_data->data), service_data->len);
+ dbus_message_iter_close_container(&member, &array);
+
+ dbus_message_iter_close_container(&entry, &member);
+
+ g_free(uuid_str);
+ }
+
+ dbus_message_iter_close_container(iter, &entry);
+
+ return TRUE;
+}
+
static gboolean dev_property_exists_manufacturer_data(
const GDBusPropertyTable *property, void *data)
{
@@ -1381,6 +1433,37 @@ void device_add_eir_uuids(struct btd_device *dev, GSList *uuids)
DEVICE_INTERFACE, "UUIDs");
}

+void device_set_eir_service_data(struct btd_device *dev, GSList *service_data)
+{
+ GSList *l;
+ bool changed = false;
+
+ if (dev->eir_service_data) {
+ g_slist_free_full(dev->eir_service_data,
+ (GDestroyNotify)eir_service_data_free);
+ dev->eir_service_data = NULL;
+ changed = true;
+ }
+
+ for (l = service_data; l != NULL; l = l->next) {
+ struct eir_service_data *data = l->data;
+ struct eir_service_data *new_data;
+
+ new_data = g_new0(struct eir_service_data, 1);
+ new_data->uuid = data->uuid;
+ new_data->data = g_memdup(data->data, data->len);
+ new_data->len = data->len;
+
+ dev->eir_service_data = g_slist_append(dev->eir_service_data,
+ new_data);
+ changed = true;
+ }
+
+ if (changed)
+ g_dbus_emit_property_changed(dbus_conn, dev->path,
+ DEVICE_INTERFACE, "ServiceData");
+}
+
void device_set_eir_manufacturer_data(struct btd_device *dev,
GSList *manufacturer_data)
{
@@ -2064,6 +2147,8 @@ static const GDBusPropertyTable device_properties[] = {
dev_property_exists_tx_power },
{ "Connected", "b", dev_property_get_connected },
{ "UUIDs", "as", dev_property_get_uuids },
+ { "ServiceData", "a(say)", dev_property_get_service_data, NULL,
+ dev_property_exists_service_data },
{ "ManufacturerData", "a(qay)", dev_property_get_manufacturer_data,
NULL, dev_property_exists_manufacturer_data },
{ "Modalias", "s", dev_property_get_modalias, NULL,
diff --git a/src/device.h b/src/device.h
index 783833a..e8bb7e8 100644
--- a/src/device.h
+++ b/src/device.h
@@ -72,6 +72,7 @@ void btd_device_gatt_set_service_changed(struct btd_device *device,
bool device_attach_attrib(struct btd_device *dev, GIOChannel *io);
void btd_device_add_uuid(struct btd_device *device, const char *uuid);
void device_add_eir_uuids(struct btd_device *dev, GSList *uuids);
+void device_set_eir_service_data(struct btd_device *dev, GSList *service_data);
void device_set_eir_manufacturer_data(struct btd_device *dev,
GSList *manufacturer_data);
void device_probe_profile(gpointer a, gpointer b);
diff --git a/src/eir.c b/src/eir.c
index d4594d6..d3e00ad 100644
--- a/src/eir.c
+++ b/src/eir.c
@@ -43,6 +43,12 @@

#define EIR_OOB_MIN (2 + 6)

+void eir_service_data_free(struct eir_service_data *service_data)
+{
+ g_free(service_data->data);
+ service_data->data = NULL;
+}
+
void eir_manufacturer_data_free(struct eir_manufacturer_data *manufacturer_data)
{
g_free(manufacturer_data->data);
@@ -53,6 +59,9 @@ void eir_data_free(struct eir_data *eir)
{
g_slist_free_full(eir->services, free);
eir->services = NULL;
+ g_slist_free_full(eir->service_data,
+ (GDestroyNotify)eir_service_data_free);
+ eir->service_data = NULL;
g_slist_free_full(eir->manufacturer_data,
(GDestroyNotify)eir_manufacturer_data_free);
eir->manufacturer_data = NULL;
@@ -123,6 +132,56 @@ static void eir_parse_uuid128(struct eir_data *eir, const uint8_t *data,
}
}

+static void eir_parse_service_data(struct eir_data *eir, uint8_t type,
+ const uint8_t *data, uint8_t len)
+{
+ struct eir_service_data *service_data;
+ uuid_t service;
+ char *uuid_str;
+ int k;
+
+ service.type = type;
+ switch (service.type) {
+ case SDP_UUID16:
+ if (len < 2)
+ return;
+ service.value.uuid16 = get_le16(data);
+ data += 2;
+ len -= 2;
+ break;
+ case SDP_UUID32:
+ if (len < 4)
+ return;
+ service.value.uuid32 = get_le32(data);
+ data += 4;
+ len -= 4;
+ break;
+ case SDP_UUID128:
+ if (len < 16)
+ return;
+ for (k = 0; k < 16; k++)
+ service.value.uuid128.data[k] = data[16 - k - 1];
+ data += 16;
+ len -= 16;
+ break;
+ default:
+ /* Type of UUID unknown */
+ return;
+ }
+
+ uuid_str = bt_uuid2string(&service);
+ if (!uuid_str)
+ return;
+ eir->services = g_slist_append(eir->services, uuid_str);
+
+ service_data = g_new0(struct eir_service_data, 1);
+ service_data->uuid = service;
+ service_data->data = g_memdup(data, len);
+ service_data->len = len;
+
+ eir->service_data = g_slist_append(eir->service_data, service_data);
+}
+
static void eir_parse_manufacturer_data(struct eir_data *eir,
const uint8_t *data, uint8_t len)
{
@@ -267,6 +326,19 @@ void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
eir->did_version = data[6] | (data[7] << 8);
break;

+ case EIR_SERVICE_DATA_UUID16:
+ eir_parse_service_data(eir, SDP_UUID16, data, data_len);
+ break;
+
+ case EIR_SERVICE_DATA_UUID32:
+ eir_parse_service_data(eir, SDP_UUID32, data, data_len);
+ break;
+
+ case EIR_SERVICE_DATA_UUID128:
+ eir_parse_service_data(eir, SDP_UUID128,
+ data, data_len);
+ break;
+
case EIR_MANUFACTURER_DATA:
eir_parse_manufacturer_data(eir, data, data_len);
break;
diff --git a/src/eir.h b/src/eir.h
index 65ba18a..701f12d 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -36,6 +36,9 @@
#define EIR_SSP_HASH 0x0E /* SSP Hash */
#define EIR_SSP_RANDOMIZER 0x0F /* SSP Randomizer */
#define EIR_DEVICE_ID 0x10 /* device ID */
+#define EIR_SERVICE_DATA_UUID16 0x16 /* 16-bit UUID with service data */
+#define EIR_SERVICE_DATA_UUID32 0x20 /* 32-bit UUID with service data */
+#define EIR_SERVICE_DATA_UUID128 0x21 /* 128-bit UUID with service data */
#define EIR_GAP_APPEARANCE 0x19 /* GAP appearance */
#define EIR_MANUFACTURER_DATA 0xFF /* Manufacturer-specific data */

@@ -50,6 +53,7 @@

struct eir_data {
GSList *services;
+ GSList *service_data;
GSList *manufacturer_data;
unsigned int flags;
char *name;
@@ -66,12 +70,19 @@ struct eir_data {
uint16_t did_source;
};

+struct eir_service_data {
+ uuid_t uuid;
+ uint8_t *data;
+ uint8_t len;
+};
+
struct eir_manufacturer_data {
uint16_t vendor;
uint8_t *data;
uint8_t len;
};

+void eir_service_data_free(struct eir_service_data *service_data);
void eir_manufacturer_data_free(struct eir_manufacturer_data *
manufacturer_data);
void eir_data_free(struct eir_data *eir);
--
2.1.0.rc2.206.gedb03e5


2014-09-24 22:57:41

by Scott James Remnant

[permalink] [raw]
Subject: [PATCH] core: add D-Bus property for ManufacturerData

---
doc/device-api.txt | 10 +++++++
src/adapter.c | 1 +
src/device.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/device.h | 2 ++
src/eir.c | 30 ++++++++++++++++++++
src/eir.h | 10 +++++++
6 files changed, 135 insertions(+)

diff --git a/doc/device-api.txt b/doc/device-api.txt
index 68388e9..4df6ec9 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -134,6 +134,16 @@ Properties string Address [readonly]
List of 128-bit UUIDs that represents the available
remote services.

+ array{struct of data} ManufacturerData [readonly, optional]
+
+ List of manufacturer-specific data obtained from the
+ device. Each array member is a struct of uint16
+ containing the vendor identifier and an array of bytes
+ containing the manufacturer data.
+
+ Duplicate entries for a single manufacturer are
+ permitted.
+
boolean Paired [readonly]

Indicates if the remote device is paired.
diff --git a/src/adapter.c b/src/adapter.c
index 1b44dc5..037a3c3 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -4739,6 +4739,7 @@ static void update_found_devices(struct btd_adapter *adapter,
eir_data.did_version);

device_add_eir_uuids(dev, eir_data.services);
+ device_set_eir_manufacturer_data(dev, eir_data.manufacturer_data);

eir_data_free(&eir_data);

diff --git a/src/device.c b/src/device.c
index d4ebf4f..3e7a7b4 100644
--- a/src/device.c
+++ b/src/device.c
@@ -66,6 +66,7 @@
#include "textfile.h"
#include "storage.h"
#include "attrib-server.h"
+#include "eir.h"

#define IO_CAPABILITY_NOINPUTNOOUTPUT 0x03

@@ -174,6 +175,7 @@ struct btd_device {
bool svc_refreshed;
GSList *svc_callbacks;
GSList *eir_uuids;
+ GSList *eir_manufacturer_data;
char name[MAX_NAME_LENGTH + 1];
char *alias;
uint32_t class;
@@ -515,6 +517,8 @@ static void device_free(gpointer user_data)
{
struct btd_device *device = user_data;

+ g_slist_free_full(device->eir_manufacturer_data,
+ (GDestroyNotify)eir_manufacturer_data_free);
g_slist_free_full(device->uuids, g_free);
g_slist_free_full(device->primaries, g_free);
g_slist_free_full(device->attios, g_free);
@@ -970,6 +974,50 @@ static gboolean dev_property_get_uuids(const GDBusPropertyTable *property,
return TRUE;
}

+static gboolean dev_property_exists_manufacturer_data(
+ const GDBusPropertyTable *property, void *data)
+{
+ struct btd_device *dev = data;
+
+ return dev->eir_manufacturer_data != NULL;
+}
+
+static gboolean dev_property_get_manufacturer_data(
+ const GDBusPropertyTable *property, DBusMessageIter *iter, void *data)
+{
+ struct btd_device *dev = data;
+ DBusMessageIter entry;
+ GSList *l;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_UINT16_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING, &entry);
+
+ for (l = dev->eir_manufacturer_data; l != NULL; l = l->next) {
+ struct eir_manufacturer_data *manufacturer_data = l->data;
+ DBusMessageIter member, array;
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_STRUCT,
+ NULL, &member);
+ dbus_message_iter_append_basic(&member, DBUS_TYPE_UINT16,
+ &manufacturer_data->vendor);
+
+ dbus_message_iter_open_container(&member, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING, &array);
+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+ &manufacturer_data->data, manufacturer_data->len);
+ dbus_message_iter_close_container(&member, &array);
+
+ dbus_message_iter_close_container(&entry, &member);
+ }
+
+ dbus_message_iter_close_container(iter, &entry);
+
+ return TRUE;
+}
+
static gboolean dev_property_get_modalias(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -1333,6 +1381,38 @@ void device_add_eir_uuids(struct btd_device *dev, GSList *uuids)
DEVICE_INTERFACE, "UUIDs");
}

+void device_set_eir_manufacturer_data(struct btd_device *dev,
+ GSList *manufacturer_data)
+{
+ GSList *l;
+ bool changed = false;
+
+ if (dev->eir_service_data) {
+ g_slist_free_full(dev->eir_manufacturer_data,
+ (GDestroyNotify)eir_manufacturer_data_free);
+ dev->eir_manufacturer_data = NULL;
+ changed = true;
+ }
+
+ for (l = manufacturer_data; l != NULL; l = l->next) {
+ struct eir_manufacturer_data *data = l->data;
+ struct eir_manufacturer_data *new_data;
+
+ new_data = g_new0(struct eir_manufacturer_data, 1);
+ new_data->vendor = data->vendor;
+ new_data->data = g_memdup(data->data, data->len);
+ new_data->len = data->len;
+
+ dev->eir_manufacturer_data = g_slist_append(
+ dev->eir_manufacturer_data, new_data);
+ changed = true;
+ }
+
+ if (changed)
+ g_dbus_emit_property_changed(dbus_conn, dev->path,
+ DEVICE_INTERFACE, "ManufacturerData");
+}
+
static struct btd_service *find_connectable_service(struct btd_device *dev,
const char *uuid)
{
@@ -1984,6 +2064,8 @@ static const GDBusPropertyTable device_properties[] = {
dev_property_exists_tx_power },
{ "Connected", "b", dev_property_get_connected },
{ "UUIDs", "as", dev_property_get_uuids },
+ { "ManufacturerData", "a(qay)", dev_property_get_manufacturer_data,
+ NULL, dev_property_exists_manufacturer_data },
{ "Modalias", "s", dev_property_get_modalias, NULL,
dev_property_exists_modalias },
{ "Adapter", "o", dev_property_get_adapter },
diff --git a/src/device.h b/src/device.h
index b568593..783833a 100644
--- a/src/device.h
+++ b/src/device.h
@@ -72,6 +72,8 @@ void btd_device_gatt_set_service_changed(struct btd_device *device,
bool device_attach_attrib(struct btd_device *dev, GIOChannel *io);
void btd_device_add_uuid(struct btd_device *device, const char *uuid);
void device_add_eir_uuids(struct btd_device *dev, GSList *uuids);
+void device_set_eir_manufacturer_data(struct btd_device *dev,
+ GSList *manufacturer_data);
void device_probe_profile(gpointer a, gpointer b);
void device_remove_profile(gpointer a, gpointer b);
struct btd_adapter *device_get_adapter(struct btd_device *device);
diff --git a/src/eir.c b/src/eir.c
index d22ad91..d4594d6 100644
--- a/src/eir.c
+++ b/src/eir.c
@@ -43,10 +43,19 @@

#define EIR_OOB_MIN (2 + 6)

+void eir_manufacturer_data_free(struct eir_manufacturer_data *manufacturer_data)
+{
+ g_free(manufacturer_data->data);
+ manufacturer_data->data = NULL;
+}
+
void eir_data_free(struct eir_data *eir)
{
g_slist_free_full(eir->services, free);
eir->services = NULL;
+ g_slist_free_full(eir->manufacturer_data,
+ (GDestroyNotify)eir_manufacturer_data_free);
+ eir->manufacturer_data = NULL;
g_free(eir->name);
eir->name = NULL;
g_free(eir->hash);
@@ -114,6 +123,23 @@ static void eir_parse_uuid128(struct eir_data *eir, const uint8_t *data,
}
}

+static void eir_parse_manufacturer_data(struct eir_data *eir,
+ const uint8_t *data, uint8_t len)
+{
+ struct eir_manufacturer_data *manufacturer_data;
+
+ if (len < 2)
+ return;
+
+ manufacturer_data = g_new0(struct eir_manufacturer_data, 1);
+ manufacturer_data->vendor = get_le16(data);
+ manufacturer_data->data = g_memdup(data + 2, len - 2);
+ manufacturer_data->len = len - 2;
+
+ eir->manufacturer_data = g_slist_append(eir->manufacturer_data,
+ manufacturer_data);
+}
+
static char *name2utf8(const uint8_t *name, uint8_t len)
{
char utf8_name[HCI_MAX_NAME_LENGTH + 2];
@@ -240,6 +266,10 @@ void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
eir->did_product = data[4] | (data[5] << 8);
eir->did_version = data[6] | (data[7] << 8);
break;
+
+ case EIR_MANUFACTURER_DATA:
+ eir_parse_manufacturer_data(eir, data, data_len);
+ break;
}

eir_data += field_len + 1;
diff --git a/src/eir.h b/src/eir.h
index e486fa2..65ba18a 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -37,6 +37,7 @@
#define EIR_SSP_RANDOMIZER 0x0F /* SSP Randomizer */
#define EIR_DEVICE_ID 0x10 /* device ID */
#define EIR_GAP_APPEARANCE 0x19 /* GAP appearance */
+#define EIR_MANUFACTURER_DATA 0xFF /* Manufacturer-specific data */

/* Flags Descriptions */
#define EIR_LIM_DISC 0x01 /* LE Limited Discoverable Mode */
@@ -49,6 +50,7 @@

struct eir_data {
GSList *services;
+ GSList *manufacturer_data;
unsigned int flags;
char *name;
uint32_t class;
@@ -64,6 +66,14 @@ struct eir_data {
uint16_t did_source;
};

+struct eir_manufacturer_data {
+ uint16_t vendor;
+ uint8_t *data;
+ uint8_t len;
+};
+
+void eir_manufacturer_data_free(struct eir_manufacturer_data *
+ manufacturer_data);
void eir_data_free(struct eir_data *eir);
void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len);
int eir_parse_oob(struct eir_data *eir, uint8_t *eir_data, uint16_t eir_len);
--
2.1.0.rc2.206.gedb03e5


2014-12-09 09:10:16

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH] core: add D-Bus property for ServiceData

Hi Scott, Johan,

On Mon, Dec 8, 2014 at 8:43 PM, Johan Hedberg <[email protected]> wrote:
> Hi Scott,
>
> On Wed, Sep 24, 2014, Scott James Remnant wrote:
>> Since the standard doesn't make any specific requirement that a UUID
>> present in a Service Data field be also present in a specific UUIDs
>> field, the UUIDs are also added to that list as well.
>> ---
>> doc/device-api.txt | 9 ++++++
>> src/adapter.c | 1 +
>> src/device.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> src/device.h | 1 +
>> src/eir.c | 72 +++++++++++++++++++++++++++++++++++++++++++++
>> src/eir.h | 11 +++++++
>> 6 files changed, 179 insertions(+)
>
> This too looks fine, but the documentation and EIR parsing parts should
> be split into their own patches.

Another possibility would be to add a Data property to
org.bluez.GattService1, but then if the service is not gatt based
perhaps we need something else. I had actually plans to introduce a
generic Service interface as a plugin, it was originally meant to
provide a better control over connections for classic, the interface
documentation can be found here:

https://gitorious.org/bluez/vudentzs-clone/source/b19b4b043fff27e6c3bdbb5e5eefef9b7c0de95b:doc/service-api.txt

This could be exposed in the same object as org.bluez.GattService1 but
we would need to align because right now the paths are different,
having another Property would be easy to add and we can mark some
properties optional in case they don't make sense in LE.


--
Luiz Augusto von Dentz

2014-12-08 21:57:30

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH] core: add D-Bus property for TxPower

Hi Scott,

On Thu, Sep 25, 2014 at 1:57 AM, Scott James Remnant <[email protected]> wrote:
> This is presented as a raw property rather than a parsed "PathLoss"
> property because in the case of many devices, this specific field will
> not be present and instead the TX power will have to be parsed from
> manufacturer-specific data anyway.
>
> It's better therefore to document the Path Loss equation rather than
> hide it.

Im trying to understand your reasoning here, so TxPower is better
because is what you can get from manufacturer data? If we have RSSI
and Tx Power we could just do the math and expose as PathLoss don't
we?

> ---
> doc/device-api.txt | 12 ++++++++++++
> src/adapter.c | 6 ++++--
> src/device.c | 41 +++++++++++++++++++++++++++++++++++++++++
> src/device.h | 1 +
> 4 files changed, 58 insertions(+), 2 deletions(-)
>
> diff --git a/doc/device-api.txt b/doc/device-api.txt
> index 86d8af8..68388e9 100644
> --- a/doc/device-api.txt
> +++ b/doc/device-api.txt
> @@ -193,3 +193,15 @@ Properties string Address [readonly]
>
> Received Signal Strength Indicator of the remote
> device (inquiry or advertising).
> +
> + int16 TxPower [readonly, optional]
> +
> + Transmission power claimed by the remote device
> + (inquiry or advertising). Many devices may not make
> + this available at all, or may incorporate this data
> + into a manufacturer or service-specific field instead.
> +
> + However the remote transmission power is obtained,
> + path loss can be calculated by the equation:
> +
> + Path Loss = Tx Power - RSSI
> diff --git a/src/adapter.c b/src/adapter.c
> index 92ee1a0..1b44dc5 100644
> --- a/src/adapter.c
> +++ b/src/adapter.c
> @@ -1585,16 +1585,17 @@ static int compare_sender(gconstpointer a, gconstpointer b)
> return g_strcmp0(client->owner, sender);
> }
>
> -static void invalidate_rssi(gpointer a)
> +static void invalidate_inquiry_data(gpointer a)
> {
> struct btd_device *dev = a;
>
> device_set_rssi(dev, 0);
> + device_set_tx_power(dev, 127);
> }
>
> static void discovery_cleanup(struct btd_adapter *adapter)
> {
> - g_slist_free_full(adapter->discovery_found, invalidate_rssi);
> + g_slist_free_full(adapter->discovery_found, invalidate_inquiry_data);
> adapter->discovery_found = NULL;
> }
>
> @@ -4715,6 +4716,7 @@ static void update_found_devices(struct btd_adapter *adapter,
>
> device_set_legacy(dev, legacy);
> device_set_rssi(dev, rssi);
> + device_set_tx_power(dev, eir_data.tx_power);
>
> if (eir_data.appearance != 0)
> device_set_appearance(dev, eir_data.appearance);
> diff --git a/src/device.c b/src/device.c
> index 875a5c5..d4ebf4f 100644
> --- a/src/device.c
> +++ b/src/device.c
> @@ -219,6 +219,7 @@ struct btd_device {
>
> bool legacy;
> int8_t rssi;
> + int8_t tx_power;
>
> GIOChannel *att_io;
> guint cleanup_id;
> @@ -812,6 +813,28 @@ static gboolean dev_property_exists_rssi(const GDBusPropertyTable *property,
> return TRUE;
> }
>
> +static gboolean dev_property_get_tx_power(const GDBusPropertyTable *property,
> + DBusMessageIter *iter, void *data)
> +{
> + struct btd_device *dev = data;
> + dbus_int16_t val = dev->tx_power;
> +
> + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT16, &val);
> +
> + return TRUE;
> +}
> +
> +static gboolean dev_property_exists_tx_power(const GDBusPropertyTable *property,
> + void *data)
> +{
> + struct btd_device *dev = data;
> +
> + if (dev->tx_power == 127)
> + return FALSE;
> +
> + return TRUE;
> +}
> +
> static gboolean dev_property_get_trusted(const GDBusPropertyTable *property,
> DBusMessageIter *iter, void *data)
> {
> @@ -1957,6 +1980,8 @@ static const GDBusPropertyTable device_properties[] = {
> { "Blocked", "b", dev_property_get_blocked, dev_property_set_blocked },
> { "LegacyPairing", "b", dev_property_get_legacy },
> { "RSSI", "n", dev_property_get_rssi, NULL, dev_property_exists_rssi },
> + { "TxPower", "n", dev_property_get_tx_power, NULL,
> + dev_property_exists_tx_power },
> { "Connected", "b", dev_property_get_connected },
> { "UUIDs", "as", dev_property_get_uuids },
> { "Modalias", "s", dev_property_get_modalias, NULL,
> @@ -4107,6 +4132,22 @@ void device_set_rssi(struct btd_device *device, int8_t rssi)
> DEVICE_INTERFACE, "RSSI");
> }
>
> +void device_set_tx_power(struct btd_device *device, int8_t tx_power)
> +{
> + if (!device)
> + return;
> +
> + if (device->tx_power == tx_power)
> + return;
> +
> + DBG("tx_power %d", tx_power);
> +
> + device->tx_power = tx_power;
> +
> + g_dbus_emit_property_changed(dbus_conn, device->path,
> + DEVICE_INTERFACE, "TxPower");
> +}
> +
> static gboolean start_discovery(gpointer user_data)
> {
> struct btd_device *device = user_data;
> diff --git a/src/device.h b/src/device.h
> index 2e0473e..b568593 100644
> --- a/src/device.h
> +++ b/src/device.h
> @@ -88,6 +88,7 @@ void btd_device_set_trusted(struct btd_device *device, gboolean trusted);
> void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type);
> void device_set_legacy(struct btd_device *device, bool legacy);
> void device_set_rssi(struct btd_device *device, int8_t rssi);
> +void device_set_tx_power(struct btd_device *device, int8_t tx_power);
> bool btd_device_is_connected(struct btd_device *dev);
> uint8_t btd_device_get_bdaddr_type(struct btd_device *dev);
> bool device_is_retrying(struct btd_device *device);
> --
> 2.1.0.rc2.206.gedb03e5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html



--
Luiz Augusto von Dentz

2014-12-08 18:43:10

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH] core: add D-Bus property for ServiceData

Hi Scott,

On Wed, Sep 24, 2014, Scott James Remnant wrote:
> Since the standard doesn't make any specific requirement that a UUID
> present in a Service Data field be also present in a specific UUIDs
> field, the UUIDs are also added to that list as well.
> ---
> doc/device-api.txt | 9 ++++++
> src/adapter.c | 1 +
> src/device.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/device.h | 1 +
> src/eir.c | 72 +++++++++++++++++++++++++++++++++++++++++++++
> src/eir.h | 11 +++++++
> 6 files changed, 179 insertions(+)

This too looks fine, but the documentation and EIR parsing parts should
be split into their own patches.

Johan

2014-12-08 18:39:51

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH] core: add D-Bus property for TxPower

Hi Scott,

On Wed, Sep 24, 2014, Scott James Remnant wrote:
> This is presented as a raw property rather than a parsed "PathLoss"
> property because in the case of many devices, this specific field will
> not be present and instead the TX power will have to be parsed from
> manufacturer-specific data anyway.
>
> It's better therefore to document the Path Loss equation rather than
> hide it.
> ---
> doc/device-api.txt | 12 ++++++++++++
> src/adapter.c | 6 ++++--
> src/device.c | 41 +++++++++++++++++++++++++++++++++++++++++
> src/device.h | 1 +
> 4 files changed, 58 insertions(+), 2 deletions(-)

I don't have any particular objections to this patch except that the
API documentation should be in a separate patch.

Johan

2014-12-08 18:41:51

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH] core: add D-Bus property for ManufacturerData

Hi Scott,

On Wed, Sep 24, 2014, Scott James Remnant wrote:
> ---
> doc/device-api.txt | 10 +++++++
> src/adapter.c | 1 +
> src/device.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/device.h | 2 ++
> src/eir.c | 30 ++++++++++++++++++++
> src/eir.h | 10 +++++++
> 6 files changed, 135 insertions(+)

The D-Bus property part of this patch looks ok'ish, however we've
already got manufacturer data parsing upstream so that needs to be
removed (and the rest adapted to the upstream API for this). The D-Bus
documentation should also be split to a separate patch.

Johan