2012-11-09 08:55:42

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 00/15] thermometer plugin updates

Hi,

Here are few patches to update thermometer plugin with features already
implemented in other plugins:
- store attributes handles directly in thermometer structure instead of
nested lists of structures which we need to traverse later (and we
only need 3 handles stored to support all use cases)
- register attio handlers for specific handles instead of one ind and
notif handler globally
- change properties handling to DBus.Properties
- and some minor fixes

This is tested with PTS 4.5.3. There's only problem with patch #9 which
"breaks" testcase TP/THF/CO/BV-09-I - this is because PTS sends invalid
properties for Measurement Interval characteristic (it does not have
indicate property so we do not register ind handler for it). I already
filled issue on PTS.

Comments are welcome.


Andrzej Kaczmarek (15):
thermometer: Store Temperature Measurement CCC handle in struct
thermometer: Store Intermediate Temperature CCC handle in struct
thermometer: Store Measurement Interval value handle in struct
thermometer: Use dedicated handler for Intermediate Temperature
thermometer: Use dedicated handler for Temperature Measurement
thermometer: Use dedicated handler for Measurement Interval
thermometer: Remove descriptor structure
thermometer: Remove storage of all discovered characteristics
thermometer: Discover Measurement Interval descriptors only if needed
thermometer: Always write CCC value when connecting
thermometer: Make temp_type array static
thermometer: Add DBus.Properties support
thermometer: Remove legacy properties code
doc: Update thermometer API document
test: Update test-thermometer for DBus.Properties

doc/thermometer-api.txt | 18 -
profiles/thermometer/thermometer.c | 1008 +++++++++++++++++-------------------
test/test-thermometer | 13 +-
3 files changed, 478 insertions(+), 561 deletions(-)

--
1.8.0



2012-11-30 13:06:38

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH 00/15] thermometer plugin updates

Hi Andrzej,

On Fri, Nov 09, 2012, Andrzej Kaczmarek wrote:
> Here are few patches to update thermometer plugin with features already
> implemented in other plugins:
> - store attributes handles directly in thermometer structure instead of
> nested lists of structures which we need to traverse later (and we
> only need 3 handles stored to support all use cases)
> - register attio handlers for specific handles instead of one ind and
> notif handler globally
> - change properties handling to DBus.Properties
> - and some minor fixes
>
> This is tested with PTS 4.5.3. There's only problem with patch #9 which
> "breaks" testcase TP/THF/CO/BV-09-I - this is because PTS sends invalid
> properties for Measurement Interval characteristic (it does not have
> indicate property so we do not register ind handler for it). I already
> filled issue on PTS.
>
> Comments are welcome.
>
>
> Andrzej Kaczmarek (15):
> thermometer: Store Temperature Measurement CCC handle in struct
> thermometer: Store Intermediate Temperature CCC handle in struct
> thermometer: Store Measurement Interval value handle in struct
> thermometer: Use dedicated handler for Intermediate Temperature
> thermometer: Use dedicated handler for Temperature Measurement
> thermometer: Use dedicated handler for Measurement Interval
> thermometer: Remove descriptor structure
> thermometer: Remove storage of all discovered characteristics
> thermometer: Discover Measurement Interval descriptors only if needed
> thermometer: Always write CCC value when connecting
> thermometer: Make temp_type array static
> thermometer: Add DBus.Properties support
> thermometer: Remove legacy properties code
> doc: Update thermometer API document
> test: Update test-thermometer for DBus.Properties
>
> doc/thermometer-api.txt | 18 -
> profiles/thermometer/thermometer.c | 1008 +++++++++++++++++-------------------
> test/test-thermometer | 13 +-
> 3 files changed, 478 insertions(+), 561 deletions(-)

All patches in this set have been applied. Thanks.

Johan

2012-11-09 08:55:57

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 15/15] test: Update test-thermometer for DBus.Properties

---
test/test-thermometer | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/test/test-thermometer b/test/test-thermometer
index 2ca260f..d56a8b2 100755
--- a/test/test-thermometer
+++ b/test/test-thermometer
@@ -29,9 +29,9 @@ class Watcher(dbus.service.Object):
if "Type" in measure:
print("Type: ", measure["Type"])

-def property_changed(name, value):
-
- print("PropertyChanged('%s', '%s')" % (name, value))
+def properties_changed(interface, changed, invalidated):
+ for name, value in changed.iteritems():
+ print("Property %s changed: %s" % (name, str(value)))

if __name__ == "__main__":
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -71,9 +71,10 @@ if __name__ == "__main__":

device_path = adapter.FindDevice(options.address)

- bus.add_signal_receiver(property_changed, bus_name="org.bluez",
- dbus_interface="org.bluez.Thermometer",
- signal_name="PropertyChanged")
+ bus.add_signal_receiver(properties_changed, bus_name="org.bluez",
+ path=device_path,
+ dbus_interface="org.freedesktop.DBus.Properties",
+ signal_name="PropertiesChanged")

path = "/test/watcher"
watcher = Watcher(bus, path)
--
1.8.0


2012-11-09 08:55:54

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 12/15] thermometer: Add DBus.Properties support

This patch adds handlers required to support generic DBus.Properties
interface.
---
profiles/thermometer/thermometer.c | 116 ++++++++++++++++++++++++++++++++++++-
1 file changed, 115 insertions(+), 1 deletion(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 446f011..b98fe88 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -276,7 +276,12 @@ static void change_property(struct thermometer *t, const char *name,
DBUS_TYPE_UINT16, &t->min);
} else {
DBG("%s is not a thermometer property", name);
+ return;
}
+
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ device_get_path(t->dev),
+ THERMOMETER_INTERFACE, name);
}

static void update_watcher(gpointer data, gpointer user_data)
@@ -1114,6 +1119,114 @@ static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
return dbus_message_new_method_return(msg);
}

+static gboolean property_get_intermediate(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct thermometer *t = data;
+ dbus_bool_t val;
+
+ val = !!t->intermediate;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
+
+ return TRUE;
+}
+
+static gboolean property_get_interval(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct thermometer *t = data;
+
+ if (!t->has_interval)
+ return FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->interval);
+
+ return TRUE;
+}
+
+static void property_set_interval(const GDBusPropertyTable *property,
+ DBusMessageIter *iter,
+ GDBusPendingPropertySet id, void *data)
+{
+ struct thermometer *t = data;
+ struct tmp_interval_data *interval_data;
+ uint16_t val;
+ uint8_t atval[2];
+
+ if (t->interval_val_handle == 0)
+ return g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".NotSupported",
+ "Operation is not supported");
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+ return g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+
+ dbus_message_iter_get_basic(iter, &val);
+
+ if (val < t->min || val > t->max)
+ return g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+
+ att_put_u16(val, &atval[0]);
+
+ interval_data = g_new0(struct tmp_interval_data, 1);
+ interval_data->thermometer = t;
+ interval_data->interval = val;
+ gatt_write_char(t->attrib, t->interval_val_handle, atval, sizeof(atval),
+ write_interval_cb, interval_data);
+
+ g_dbus_pending_property_success(id);
+}
+
+static gboolean property_exists_interval(const GDBusPropertyTable *property,
+ void *data)
+{
+ struct thermometer *t = data;
+
+ return t->has_interval;
+}
+
+static gboolean property_get_maximum(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct thermometer *t = data;
+
+ if (!t->has_interval)
+ return FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->max);
+
+ return TRUE;
+}
+
+static gboolean property_get_minimum(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct thermometer *t = data;
+
+ if (!t->has_interval)
+ return FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->min);
+
+ return TRUE;
+}
+
+static const GDBusPropertyTable thermometer_properties[] = {
+ { "Intermediate", "b", property_get_intermediate },
+ { "Interval", "q", property_get_interval, property_set_interval,
+ property_exists_interval },
+ { "Maximum", "q", property_get_maximum, NULL,
+ property_exists_interval },
+ { "Minimum", "q", property_get_minimum, NULL,
+ property_exists_interval },
+ { }
+};
+
static const GDBusMethodTable thermometer_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
@@ -1191,7 +1304,8 @@ int thermometer_register(struct btd_device *device, struct gatt_primary *tattr)
if (!g_dbus_register_interface(btd_get_dbus_connection(),
path, THERMOMETER_INTERFACE,
thermometer_methods, thermometer_signals,
- NULL, t, destroy_thermometer)) {
+ thermometer_properties, t,
+ destroy_thermometer)) {
error("D-Bus failed to register %s interface",
THERMOMETER_INTERFACE);
destroy_thermometer(t);
--
1.8.0


2012-11-09 08:55:55

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 13/15] thermometer: Remove legacy properties code

This patch removes Get-/SetProperties methods along with PropertyChanged
signal which are now redundant after moving to generic DBus.Properties
interface.
---
profiles/thermometer/thermometer.c | 129 +------------------------------------
1 file changed, 2 insertions(+), 127 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index b98fe88..cb81da6 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -243,9 +243,6 @@ static void change_property(struct thermometer *t, const char *name,
return;

t->intermediate = *intermediate;
- emit_property_changed(device_get_path(t->dev),
- THERMOMETER_INTERFACE, name,
- DBUS_TYPE_BOOLEAN, &t->intermediate);
} else if (g_strcmp0(name, "Interval") == 0) {
uint16_t *interval = value;
if (t->has_interval && t->interval == *interval)
@@ -253,27 +250,18 @@ static void change_property(struct thermometer *t, const char *name,

t->has_interval = TRUE;
t->interval = *interval;
- emit_property_changed(device_get_path(t->dev),
- THERMOMETER_INTERFACE, name,
- DBUS_TYPE_UINT16, &t->interval);
} else if (g_strcmp0(name, "Maximum") == 0) {
uint16_t *max = value;
if (t->max == *max)
return;

t->max = *max;
- emit_property_changed(device_get_path(t->dev),
- THERMOMETER_INTERFACE, name,
- DBUS_TYPE_UINT16, &t->max);
} else if (g_strcmp0(name, "Minimum") == 0) {
uint16_t *min = value;
if (t->min == *min)
return;

t->min = *min;
- emit_property_changed(device_get_path(t->dev),
- THERMOMETER_INTERFACE, name,
- DBUS_TYPE_UINT16, &t->min);
} else {
DBG("%s is not a thermometer property", name);
return;
@@ -768,40 +756,6 @@ static void configure_thermometer_cb(GSList *characteristics, guint8 status,
}
}

-static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct thermometer *t = data;
- DBusMessageIter iter;
- DBusMessageIter dict;
- DBusMessage *reply;
-
- reply = dbus_message_new_method_return(msg);
- if (reply == NULL)
- return NULL;
-
- dbus_message_iter_init_append(reply, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
- dict_append_entry(&dict, "Intermediate", DBUS_TYPE_BOOLEAN,
- &t->intermediate);
-
- if (t->has_interval) {
- dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT16,
- &t->interval);
- dict_append_entry(&dict, "Maximum", DBUS_TYPE_UINT16, &t->max);
- dict_append_entry(&dict, "Minimum", DBUS_TYPE_UINT16, &t->min);
- }
-
- dbus_message_iter_close_container(&iter, &dict);
-
- return reply;
-}
-
static void write_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
@@ -824,68 +778,6 @@ done:
g_free(user_data);
}

-static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
- uint16_t value)
-{
- struct tmp_interval_data *data;
- uint8_t atval[2];
-
- if (t->attrib == NULL)
- return btd_error_not_connected(msg);
-
- if (t->interval_val_handle == 0)
- return btd_error_not_available(msg);
-
- if (value < t->min || value > t->max)
- return btd_error_invalid_args(msg);
-
- att_put_u16(value, &atval[0]);
-
- data = g_new0(struct tmp_interval_data, 1);
- data->thermometer = t;
- data->interval = value;
- gatt_write_char(t->attrib, t->interval_val_handle, atval, 2,
- write_interval_cb, data);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct thermometer *t = data;
- const char *property;
- DBusMessageIter iter;
- DBusMessageIter sub;
- uint16_t value;
-
- if (!dbus_message_iter_init(msg, &iter))
- return btd_error_invalid_args(msg);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&iter, &property);
- if (g_strcmp0("Interval", property) != 0)
- return btd_error_invalid_args(msg);
-
- if (!t->has_interval)
- return btd_error_not_available(msg);
-
- dbus_message_iter_next(&iter);
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_recurse(&iter, &sub);
-
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&sub, &value);
-
- return write_attr_interval(t, msg, value);
-}
-
static void enable_final_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
@@ -1227,22 +1119,6 @@ static const GDBusPropertyTable thermometer_properties[] = {
{ }
};

-static const GDBusMethodTable thermometer_methods[] = {
- { GDBUS_METHOD("GetProperties",
- NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
- get_properties) },
- { GDBUS_ASYNC_METHOD("SetProperty",
- GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
- set_property) },
- { }
-};
-
-static const GDBusSignalTable thermometer_signals[] = {
- { GDBUS_SIGNAL("PropertyChanged",
- GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
- { }
-};
-
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
{
struct thermometer *t = user_data;
@@ -1303,9 +1179,8 @@ int thermometer_register(struct btd_device *device, struct gatt_primary *tattr)

if (!g_dbus_register_interface(btd_get_dbus_connection(),
path, THERMOMETER_INTERFACE,
- thermometer_methods, thermometer_signals,
- thermometer_properties, t,
- destroy_thermometer)) {
+ NULL, NULL, thermometer_properties,
+ t, destroy_thermometer)) {
error("D-Bus failed to register %s interface",
THERMOMETER_INTERFACE);
destroy_thermometer(t);
--
1.8.0


2012-11-09 08:55:56

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 14/15] doc: Update thermometer API document

This patch updates thermometer-api.txt document to include changes in
properties handling.
---
doc/thermometer-api.txt | 18 ------------------
1 file changed, 18 deletions(-)

diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt
index 7b99800..cab115f 100644
--- a/doc/thermometer-api.txt
+++ b/doc/thermometer-api.txt
@@ -48,24 +48,6 @@ Interface org.bluez.Thermometer
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX


-Methods void SetProperty(string name, variant value)
-
- Changes the value of the specified property. Only
- read-write properties can be changed. On success
- this will emit a PropertyChanged signal.
-
- Possible Errors: org.bluez.Error.InvalidArguments
-
- dict GetProperties()
-
- Returns all properties for the interface. See the
- Properties section for the available properties.
-
-Signals PropertyChanged(string name, variant value)
-
- This signal indicates a changed value of the given
- property.
-
Properties boolean Intermediate [readonly]

True if the thermometer supports intermediate
--
1.8.0


2012-11-09 08:55:53

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 11/15] thermometer: Make temp_type array static

---
profiles/thermometer/thermometer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index ad1a41d..446f011 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -119,7 +119,7 @@ struct tmp_interval_data {

static GSList *thermometer_adapters = NULL;

-const char *temp_type[] = {
+static const char * const temp_type[] = {
"<reserved>",
"armpit",
"body",
--
1.8.0


2012-11-09 08:55:52

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 10/15] thermometer: Always write CCC value when connecting

This patch ensures that CCC values for Intermediate Temperature and
Termperature Measurement are always written when connecting to device.
This is to i.e. disable notifications and/or indications in case they
are already enabled (reconnection scenario) but we don't have watcher
registered so it's pointless for remote to send us data.
---
profiles/thermometer/thermometer.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 30f79b0..ad1a41d 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -550,19 +550,23 @@ static void process_thermometer_desc(struct characteristic *ch, uint16_t uuid,
if (g_strcmp0(ch->uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) {
ch->t->measurement_ccc_handle = handle;

- if (g_slist_length(ch->t->tadapter->fwatchers) == 0)
- return;
-
- val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
- msg = g_strdup("Enable Temperature Measurement indication");
+ if (g_slist_length(ch->t->tadapter->fwatchers) == 0) {
+ val = 0x0000;
+ msg = g_strdup("Disable Temperature Measurement ind");
+ } else {
+ val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+ msg = g_strdup("Enable Temperature Measurement ind");
+ }
} else if (g_strcmp0(ch->uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
ch->t->intermediate_ccc_handle = handle;

- if (g_slist_length(ch->t->tadapter->iwatchers) == 0)
- return;
-
- val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
- msg = g_strdup("Enable Intermediate Temperature notification");
+ if (g_slist_length(ch->t->tadapter->iwatchers) == 0) {
+ val = 0x0000;
+ msg = g_strdup("Disable Intermediate Temperature noti");
+ } else {
+ val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+ msg = g_strdup("Enable Intermediate Temperature noti");
+ }
} else if (g_strcmp0(ch->uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
msg = g_strdup("Enable Measurement Interval indication");
--
1.8.0


2012-11-09 08:55:49

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 07/15] thermometer: Remove descriptor structure

This patch removes descriptor structure which is now redundant since
useful data are now kept directly in thermometer structure.
---
profiles/thermometer/thermometer.c | 114 ++++++++++++++-----------------------
1 file changed, 43 insertions(+), 71 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index b01ac7a..462173d 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -92,16 +92,9 @@ struct thermometer {

struct characteristic {
struct gatt_char attr; /* Characteristic */
- GSList *desc; /* Descriptors */
struct thermometer *t; /* Thermometer where the char belongs */
};

-struct descriptor {
- struct characteristic *ch;
- uint16_t handle;
- bt_uuid_t uuid;
-};
-
struct watcher {
struct thermometer_adapter *tadapter;
guint id;
@@ -169,7 +162,6 @@ static void destroy_char(gpointer user_data)
{
struct characteristic *c = user_data;

- g_slist_free_full(c->desc, g_free);
g_free(c);
}

@@ -504,7 +496,7 @@ static void interval_ind_handler(const uint8_t *pdu, uint16_t len,
static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
- struct descriptor *desc = user_data;
+ struct thermometer *t = user_data;
uint8_t value[VALID_RANGE_DESC_SIZE];
uint16_t max, min;
ssize_t vlen;
@@ -534,8 +526,8 @@ static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
return;
}

- change_property(desc->ch->t, "Maximum", &max);
- change_property(desc->ch->t, "Minimum", &min);
+ change_property(t, "Maximum", &max);
+ change_property(t, "Minimum", &min);
}

static void write_ccc_cb(guint8 status, const guint8 *pdu,
@@ -549,67 +541,50 @@ static void write_ccc_cb(guint8 status, const guint8 *pdu,
g_free(msg);
}

-static void process_thermometer_desc(struct descriptor *desc)
+static void process_thermometer_desc(struct characteristic *ch, uint16_t uuid,
+ uint16_t handle)
{
- struct characteristic *ch = desc->ch;
- char uuidstr[MAX_LEN_UUID_STR];
- bt_uuid_t btuuid;
+ uint8_t atval[2];
+ uint16_t val;
+ char *msg;

- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ if (uuid == GATT_CHARAC_VALID_RANGE_UUID) {
+ if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+ gatt_read_char(ch->t->attrib, handle,
+ valid_range_desc_cb, ch->t);
+ return;
+ }

- if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
- uint8_t atval[2];
- uint16_t val;
- char *msg;
+ if (uuid != GATT_CLIENT_CHARAC_CFG_UUID)
+ return;

- if (g_strcmp0(ch->attr.uuid,
- TEMPERATURE_MEASUREMENT_UUID) == 0) {
- desc->ch->t->measurement_ccc_handle = desc->handle;
+ if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) {
+ ch->t->measurement_ccc_handle = handle;

- if (g_slist_length(ch->t->tadapter->fwatchers) == 0)
- return;
+ if (g_slist_length(ch->t->tadapter->fwatchers) == 0)
+ return;

- val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
- msg = g_strdup("Enable Temperature Measurement "
- "indication");
- } else if (g_strcmp0(ch->attr.uuid,
+ val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+ msg = g_strdup("Enable Temperature Measurement indication");
+ } else if (g_strcmp0(ch->attr.uuid,
INTERMEDIATE_TEMPERATURE_UUID) == 0) {
- desc->ch->t->intermediate_ccc_handle = desc->handle;
-
- if (g_slist_length(ch->t->tadapter->iwatchers) == 0)
- return;
-
- val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
- msg = g_strdup("Enable Intermediate Temperature "
- "notification");
- } else if (g_strcmp0(ch->attr.uuid,
- MEASUREMENT_INTERVAL_UUID) == 0) {
- val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
- msg = g_strdup("Enable Measurement Interval "
- "indication");
- } else {
- goto done;
- }
+ ch->t->intermediate_ccc_handle = handle;

- att_put_u16(val, atval);
- gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
- write_ccc_cb, msg);
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CHARAC_VALID_RANGE_UUID);
+ if (g_slist_length(ch->t->tadapter->iwatchers) == 0)
+ return;

- if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
- MEASUREMENT_INTERVAL_UUID) == 0) {
- gatt_read_char(ch->t->attrib, desc->handle, valid_range_desc_cb,
- desc);
+ val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+ msg = g_strdup("Enable Intermediate Temperature notification");
+ } else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
+ val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+ msg = g_strdup("Enable Measurement Interval indication");
+ } else {
return;
}

-done:
- bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
- DBG("Ignored descriptor %s in characteristic %s", uuidstr,
- ch->attr.uuid);
+ att_put_u16(val, atval);
+ gatt_write_char(ch->t->attrib, handle, atval, sizeof(atval),
+ write_ccc_cb, msg);
}

static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
@@ -630,24 +605,21 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
if (list == NULL)
return;

+ if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+ goto done;
+
for (i = 0; i < list->num; i++) {
- struct descriptor *desc;
uint8_t *value;
+ uint16_t handle, uuid;

value = list->data[i];
- desc = g_new0(struct descriptor, 1);
- desc->handle = att_get_u16(value);
- desc->ch = ch;
-
- if (format == ATT_FIND_INFO_RESP_FMT_16BIT)
- desc->uuid = att_get_uuid16(&value[2]);
- else
- desc->uuid = att_get_uuid128(&value[2]);
+ handle = att_get_u16(value);
+ uuid = att_get_u16(value + 2);

- ch->desc = g_slist_append(ch->desc, desc);
- process_thermometer_desc(desc);
+ process_thermometer_desc(ch, uuid, handle);
}

+done:
att_data_list_free(list);
}

--
1.8.0


2012-11-09 08:55:47

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 05/15] thermometer: Use dedicated handler for Temperature Measurement

This patch moves Temperature Measurement value indications handler into
separate callback registered for particular handle only.
---
profiles/thermometer/thermometer.c | 41 +++++++++++++++++++++++++++++++++++---
1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 5ed0553..c5fdb94 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -71,6 +71,8 @@ struct thermometer {
struct att_range *svc_range; /* Thermometer range */
guint attioid; /* Att watcher id */
guint attindid; /* Att incications id */
+ /* attio id for Temperature Measurement value indications */
+ guint attio_measurement_id;
/* attio id for Intermediate Temperature value notifications */
guint attio_intermediate_id;
GSList *chars; /* Characteristics */
@@ -180,6 +182,7 @@ static void destroy_thermometer(gpointer user_data)
if (t->attindid > 0)
g_attrib_unregister(t->attrib, t->attindid);

+ g_attrib_unregister(t->attrib, t->attio_measurement_id);
g_attrib_unregister(t->attrib, t->attio_intermediate_id);

if (t->attrib != NULL)
@@ -447,6 +450,29 @@ static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
g_free(m.type);
}

+
+static void measurement_ind_handler(const uint8_t *pdu, uint16_t len,
+ gpointer user_data)
+{
+ struct thermometer *t = user_data;
+ uint8_t *opdu;
+ uint16_t olen;
+ size_t plen;
+
+ if (len < 3) {
+ DBG("Bad pdu received");
+ return;
+ }
+
+ proc_measurement(t, pdu, len, TRUE);
+
+ opdu = g_attrib_get_buffer(t->attrib, &plen);
+ olen = enc_confirmation(opdu, plen);
+
+ if (olen > 0)
+ g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL);
+}
+
static void intermediate_notify_handler(const uint8_t *pdu, uint16_t len,
gpointer user_data)
{
@@ -679,6 +705,12 @@ static void process_thermometer_char(struct characteristic *ch)
t->attio_intermediate_id = g_attrib_register(t->attrib,
ATT_OP_HANDLE_NOTIFY, ch->attr.value_handle,
intermediate_notify_handler, t, NULL);
+ } else if (g_strcmp0(ch->attr.uuid,
+ TEMPERATURE_MEASUREMENT_UUID) == 0) {
+
+ t->attio_measurement_id = g_attrib_register(t->attrib,
+ ATT_OP_HANDLE_IND, ch->attr.value_handle,
+ measurement_ind_handler, t, NULL);
} else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0) {
gatt_read_char(ch->t->attrib, ch->attr.value_handle,
read_temp_type_cb, ch);
@@ -1140,9 +1172,7 @@ static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)

ch = l->data;

- if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0)
- proc_measurement(t, pdu, len, TRUE);
- else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+ if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
proc_measurement_interval(t, pdu, len);

opdu = g_attrib_get_buffer(t->attrib, &plen);
@@ -1176,6 +1206,11 @@ static void attio_disconnected_cb(gpointer user_data)
t->attindid = 0;
}

+ if (t->attio_measurement_id > 0) {
+ g_attrib_unregister(t->attrib, t->attio_measurement_id);
+ t->attio_measurement_id = 0;
+ }
+
if (t->attio_intermediate_id > 0) {
g_attrib_unregister(t->attrib, t->attio_intermediate_id);
t->attio_intermediate_id = 0;
--
1.8.0


2012-11-09 08:55:51

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 09/15] thermometer: Discover Measurement Interval descriptors only if needed

This patch will make descriptor discovery started only if Measurement
Interval characteristic properties are either write or indicate, otherwise
there are no known descriptors to be discovered.
---
profiles/thermometer/thermometer.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 63d9c1e..30f79b0 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -718,15 +718,24 @@ static void process_thermometer_char(struct thermometer *t,
gatt_read_char(t->attrib, c->value_handle,
read_temp_type_cb, t);
} else if (g_strcmp0(c->uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
+ bool need_desc = false;
+
gatt_read_char(t->attrib, c->value_handle, read_interval_cb, t);

- t->interval_val_handle = c->value_handle;
+ if (c->properties & ATT_CHAR_PROPER_WRITE) {
+ t->interval_val_handle = c->value_handle;
+ need_desc = true;
+ }

- t->attio_interval_id = g_attrib_register(t->attrib,
+ if (c->properties & ATT_CHAR_PROPER_INDICATE) {
+ t->attio_interval_id = g_attrib_register(t->attrib,
ATT_OP_HANDLE_IND, c->value_handle,
interval_ind_handler, t, NULL);
+ need_desc = true;
+ }

- discover_desc(t, c, c_next);
+ if (need_desc)
+ discover_desc(t, c, c_next);
}
}

--
1.8.0


2012-11-09 08:55:46

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 04/15] thermometer: Use dedicated handler for Intermediate Temperature

This patch replaces global notifications handler with one registered only
for Intermediate Temperature value notifications.
---
profiles/thermometer/thermometer.c | 345 ++++++++++++++++++-------------------
1 file changed, 168 insertions(+), 177 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index d65fc0d..5ed0553 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -71,7 +71,8 @@ struct thermometer {
struct att_range *svc_range; /* Thermometer range */
guint attioid; /* Att watcher id */
guint attindid; /* Att incications id */
- guint attnotid; /* Att notif id */
+ /* attio id for Intermediate Temperature value notifications */
+ guint attio_intermediate_id;
GSList *chars; /* Characteristics */
gboolean intermediate;
uint8_t type;
@@ -179,8 +180,7 @@ static void destroy_thermometer(gpointer user_data)
if (t->attindid > 0)
g_attrib_unregister(t->attrib, t->attindid);

- if (t->attnotid > 0)
- g_attrib_unregister(t->attrib, t->attnotid);
+ g_attrib_unregister(t->attrib, t->attio_intermediate_id);

if (t->attrib != NULL)
g_attrib_unref(t->attrib);
@@ -304,6 +304,162 @@ static void change_property(struct thermometer *t, const char *name,
}
}

+static void update_watcher(gpointer data, gpointer user_data)
+{
+ struct watcher *w = data;
+ struct measurement *m = user_data;
+ const gchar *path = device_get_path(m->t->dev);
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(w->srv, w->path,
+ THERMOMETER_WATCHER_INTERFACE,
+ "MeasurementReceived");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
+ dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
+ dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
+
+ if (m->suptime)
+ dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
+
+ dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
+ dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ dbus_message_set_no_reply(msg, TRUE);
+ g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void recv_measurement(struct thermometer *t, struct measurement *m)
+{
+ GSList *wlist;
+
+ m->t = t;
+
+ if (g_strcmp0(m->value, "intermediate") == 0)
+ wlist = t->tadapter->iwatchers;
+ else
+ wlist = t->tadapter->fwatchers;
+
+ g_slist_foreach(wlist, update_watcher, m);
+}
+
+static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
+ uint16_t len, gboolean final)
+{
+ struct measurement m;
+ const char *type = NULL;
+ uint8_t flags;
+ uint32_t raw;
+
+ /* skip opcode and handle */
+ pdu += 3;
+ len -= 3;
+
+ if (len < 1) {
+ DBG("Mandatory flags are not provided");
+ return;
+ }
+
+ memset(&m, 0, sizeof(m));
+
+ flags = *pdu;
+
+ if (flags & TEMP_UNITS)
+ m.unit = "fahrenheit";
+ else
+ m.unit = "celsius";
+
+ pdu++;
+ len--;
+
+ if (len < 4) {
+ DBG("Mandatory temperature measurement value is not provided");
+ return;
+ }
+
+ raw = att_get_u32(pdu);
+ m.mant = raw & 0x00FFFFFF;
+ m.exp = ((int32_t) raw) >> 24;
+
+ if (m.mant & 0x00800000) {
+ /* convert to C2 negative value */
+ m.mant = m.mant - FLOAT_MAX_MANTISSA;
+ }
+
+ pdu += 4;
+ len -= 4;
+
+ if (flags & TEMP_TIME_STAMP) {
+ struct tm ts;
+ time_t time;
+
+ if (len < 7) {
+ DBG("Time stamp is not provided");
+ return;
+ }
+
+ ts.tm_year = att_get_u16(pdu) - 1900;
+ ts.tm_mon = *(pdu + 2) - 1;
+ ts.tm_mday = *(pdu + 3);
+ ts.tm_hour = *(pdu + 4);
+ ts.tm_min = *(pdu + 5);
+ ts.tm_sec = *(pdu + 6);
+ ts.tm_isdst = -1;
+
+ time = mktime(&ts);
+ m.time = (uint64_t) time;
+ m.suptime = TRUE;
+
+ pdu += 7;
+ len -= 7;
+ }
+
+ if (flags & TEMP_TYPE) {
+ if (len < 1) {
+ DBG("Temperature type is not provided");
+ return;
+ }
+
+ type = temptype2str(*pdu);
+ } else if (t->has_type) {
+ type = temptype2str(t->type);
+ }
+
+ m.type = g_strdup(type);
+ m.value = final ? "final" : "intermediate";
+
+ recv_measurement(t, &m);
+ g_free(m.type);
+}
+
+static void intermediate_notify_handler(const uint8_t *pdu, uint16_t len,
+ gpointer user_data)
+{
+ struct thermometer *t = user_data;
+
+ if (len < 3) {
+ DBG("Bad pdu received");
+ return;
+ }
+
+ proc_measurement(t, pdu, len, FALSE);
+}
+
static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
@@ -514,10 +670,15 @@ static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,

static void process_thermometer_char(struct characteristic *ch)
{
+ struct thermometer *t = ch->t;
+
if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
gboolean intermediate = TRUE;
change_property(ch->t, "Intermediate", &intermediate);
- return;
+
+ t->attio_intermediate_id = g_attrib_register(t->attrib,
+ ATT_OP_HANDLE_NOTIFY, ch->attr.value_handle,
+ intermediate_notify_handler, t, NULL);
} else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0) {
gatt_read_char(ch->t->attrib, ch->attr.value_handle,
read_temp_type_cb, ch);
@@ -941,149 +1102,6 @@ static const GDBusSignalTable thermometer_signals[] = {
{ }
};

-static void update_watcher(gpointer data, gpointer user_data)
-{
- struct watcher *w = data;
- struct measurement *m = user_data;
- const gchar *path = device_get_path(m->t->dev);
- DBusMessageIter iter;
- DBusMessageIter dict;
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(w->srv, w->path,
- THERMOMETER_WATCHER_INTERFACE,
- "MeasurementReceived");
- if (msg == NULL)
- return;
-
- dbus_message_iter_init_append(msg, &iter);
-
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
- dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
- dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
- dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
-
- if (m->suptime)
- dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
-
- dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
- dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
-
- dbus_message_iter_close_container(&iter, &dict);
-
- dbus_message_set_no_reply(msg, TRUE);
- g_dbus_send_message(btd_get_dbus_connection(), msg);
-}
-
-static void recv_measurement(struct thermometer *t, struct measurement *m)
-{
- GSList *wlist;
-
- m->t = t;
-
- if (g_strcmp0(m->value, "intermediate") == 0)
- wlist = t->tadapter->iwatchers;
- else
- wlist = t->tadapter->fwatchers;
-
- g_slist_foreach(wlist, update_watcher, m);
-}
-
-static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
- uint16_t len, gboolean final)
-{
- struct measurement m;
- const char *type = NULL;
- uint8_t flags;
- uint32_t raw;
-
- /* skip opcode and handle */
- pdu += 3;
- len -= 3;
-
- if (len < 1) {
- DBG("Mandatory flags are not provided");
- return;
- }
-
- memset(&m, 0, sizeof(m));
-
- flags = *pdu;
-
- if (flags & TEMP_UNITS)
- m.unit = "fahrenheit";
- else
- m.unit = "celsius";
-
- pdu++;
- len--;
-
- if (len < 4) {
- DBG("Mandatory temperature measurement value is not provided");
- return;
- }
-
- raw = att_get_u32(pdu);
- m.mant = raw & 0x00FFFFFF;
- m.exp = ((int32_t) raw) >> 24;
-
- if (m.mant & 0x00800000) {
- /* convert to C2 negative value */
- m.mant = m.mant - FLOAT_MAX_MANTISSA;
- }
-
- pdu += 4;
- len -= 4;
-
- if (flags & TEMP_TIME_STAMP) {
- struct tm ts;
- time_t time;
-
- if (len < 7) {
- DBG("Time stamp is not provided");
- return;
- }
-
- ts.tm_year = att_get_u16(pdu) - 1900;
- ts.tm_mon = *(pdu + 2) - 1;
- ts.tm_mday = *(pdu + 3);
- ts.tm_hour = *(pdu + 4);
- ts.tm_min = *(pdu + 5);
- ts.tm_sec = *(pdu + 6);
- ts.tm_isdst = -1;
-
- time = mktime(&ts);
- m.time = (uint64_t) time;
- m.suptime = TRUE;
-
- pdu += 7;
- len -= 7;
- }
-
- if (flags & TEMP_TYPE) {
- if (len < 1) {
- DBG("Temperature type is not provided");
- return;
- }
-
- type = temptype2str(*pdu);
- } else if (t->has_type) {
- type = temptype2str(t->type);
- }
-
- m.type = g_strdup(type);
- m.value = final ? "final" : "intermediate";
-
- recv_measurement(t, &m);
- g_free(m.type);
-}
-
static void proc_measurement_interval(struct thermometer *t, const uint8_t *pdu,
uint16_t len)
{
@@ -1134,30 +1152,6 @@ static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL);
}

-static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
- struct thermometer *t = user_data;
- const struct characteristic *ch;
- uint16_t handle;
- GSList *l;
-
- if (len < 3) {
- DBG("Bad pdu received");
- return;
- }
-
- handle = att_get_u16(&pdu[1]);
- l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
- if (l == NULL) {
- DBG("Unexpected handle: 0x%04x", handle);
- return;
- }
-
- ch = l->data;
- if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0)
- proc_measurement(t, pdu, len, FALSE);
-}
-
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
{
struct thermometer *t = user_data;
@@ -1167,9 +1161,6 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
t->attindid = g_attrib_register(t->attrib, ATT_OP_HANDLE_IND,
GATTRIB_ALL_HANDLES,
ind_handler, t, NULL);
- t->attnotid = g_attrib_register(t->attrib, ATT_OP_HANDLE_NOTIFY,
- GATTRIB_ALL_HANDLES,
- notif_handler, t, NULL);
gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
NULL, configure_thermometer_cb, t);
}
@@ -1185,9 +1176,9 @@ static void attio_disconnected_cb(gpointer user_data)
t->attindid = 0;
}

- if (t->attnotid > 0) {
- g_attrib_unregister(t->attrib, t->attnotid);
- t->attnotid = 0;
+ if (t->attio_intermediate_id > 0) {
+ g_attrib_unregister(t->attrib, t->attio_intermediate_id);
+ t->attio_intermediate_id = 0;
}

g_attrib_unref(t->attrib);
--
1.8.0


2012-11-09 08:55:50

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 08/15] thermometer: Remove storage of all discovered characteristics

This patch removes structures used to keep all discovered characteristics
in thermometer structure. Useful values are already stored directly in
this structure.

characteristic structure is now only used as temporary user data when
discovering descriptors for particular characteristic.
---
profiles/thermometer/thermometer.c | 138 +++++++++++++++++--------------------
1 file changed, 65 insertions(+), 73 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 462173d..63d9c1e 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -76,7 +76,6 @@ struct thermometer {
guint attio_intermediate_id;
/* attio id for Measurement Interval value indications */
guint attio_interval_id;
- GSList *chars; /* Characteristics */
gboolean intermediate;
uint8_t type;
uint16_t interval;
@@ -91,8 +90,8 @@ struct thermometer {
};

struct characteristic {
- struct gatt_char attr; /* Characteristic */
struct thermometer *t; /* Thermometer where the char belongs */
+ char uuid[MAX_LEN_UUID_STR + 1];
};

struct watcher {
@@ -158,13 +157,6 @@ static void remove_watcher(gpointer user_data)
g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
}

-static void destroy_char(gpointer user_data)
-{
- struct characteristic *c = user_data;
-
- g_free(c);
-}
-
static void destroy_thermometer(gpointer user_data)
{
struct thermometer *t = user_data;
@@ -179,9 +171,6 @@ static void destroy_thermometer(gpointer user_data)
if (t->attrib != NULL)
g_attrib_unref(t->attrib);

- if (t->chars != NULL)
- g_slist_free_full(t->chars, destroy_char);
-
btd_device_unref(t->dev);
g_free(t->svc_range);
g_free(t);
@@ -549,7 +538,7 @@ static void process_thermometer_desc(struct characteristic *ch, uint16_t uuid,
char *msg;

if (uuid == GATT_CHARAC_VALID_RANGE_UUID) {
- if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+ if (g_strcmp0(ch->uuid, MEASUREMENT_INTERVAL_UUID) == 0)
gatt_read_char(ch->t->attrib, handle,
valid_range_desc_cb, ch->t);
return;
@@ -558,7 +547,7 @@ static void process_thermometer_desc(struct characteristic *ch, uint16_t uuid,
if (uuid != GATT_CLIENT_CHARAC_CFG_UUID)
return;

- if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) {
+ if (g_strcmp0(ch->uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) {
ch->t->measurement_ccc_handle = handle;

if (g_slist_length(ch->t->tadapter->fwatchers) == 0)
@@ -566,8 +555,7 @@ static void process_thermometer_desc(struct characteristic *ch, uint16_t uuid,

val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
msg = g_strdup("Enable Temperature Measurement indication");
- } else if (g_strcmp0(ch->attr.uuid,
- INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+ } else if (g_strcmp0(ch->uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
ch->t->intermediate_ccc_handle = handle;

if (g_slist_length(ch->t->tadapter->iwatchers) == 0)
@@ -575,7 +563,7 @@ static void process_thermometer_desc(struct characteristic *ch, uint16_t uuid,

val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
msg = g_strdup("Enable Intermediate Temperature notification");
- } else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
+ } else if (g_strcmp0(ch->uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
msg = g_strdup("Enable Measurement Interval indication");
} else {
@@ -591,19 +579,19 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
struct characteristic *ch = user_data;
- struct att_data_list *list;
+ struct att_data_list *list = NULL;
uint8_t format;
int i;

if (status != 0) {
error("Discover all characteristic descriptors failed [%s]: %s",
- ch->attr.uuid, att_ecode2str(status));
- return;
+ ch->uuid, att_ecode2str(status));
+ goto done;
}

list = dec_find_info_resp(pdu, len, &format);
if (list == NULL)
- return;
+ goto done;

if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
goto done;
@@ -620,14 +608,40 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
}

done:
- att_data_list_free(list);
+ if (list != NULL)
+ att_data_list_free(list);
+ g_free(ch);
+}
+
+static void discover_desc(struct thermometer *t, struct gatt_char *c,
+ struct gatt_char *c_next)
+{
+ struct characteristic *ch;
+ uint16_t start, end;
+
+ start = c->value_handle + 1;
+
+ if (c_next != NULL) {
+ if (start == c_next->handle)
+ return;
+ end = c_next->handle - 1;
+ } else if (c->value_handle != t->svc_range->end) {
+ end = t->svc_range->end;
+ } else {
+ return;
+ }
+
+ ch = g_new0(struct characteristic, 1);
+ ch->t = t;
+ memcpy(ch->uuid, c->uuid, sizeof(c->uuid));
+
+ gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
}

static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
- struct characteristic *ch = user_data;
- struct thermometer *t = ch->t;
+ struct thermometer *t = user_data;
uint8_t value[TEMPERATURE_TYPE_SIZE];
ssize_t vlen;

@@ -655,7 +669,7 @@ static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
- struct characteristic *ch = user_data;
+ struct thermometer *t = user_data;
uint8_t value[MEASUREMENT_INTERVAL_SIZE];
uint16_t interval;
ssize_t vlen;
@@ -678,38 +692,41 @@ static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
}

interval = att_get_u16(&value[0]);
- change_property(ch->t, "Interval", &interval);
+ change_property(t, "Interval", &interval);
}

-static void process_thermometer_char(struct characteristic *ch)
+static void process_thermometer_char(struct thermometer *t,
+ struct gatt_char *c, struct gatt_char *c_next)
{
- struct thermometer *t = ch->t;
-
- if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+ if (g_strcmp0(c->uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
gboolean intermediate = TRUE;
- change_property(ch->t, "Intermediate", &intermediate);
+ change_property(t, "Intermediate", &intermediate);

t->attio_intermediate_id = g_attrib_register(t->attrib,
- ATT_OP_HANDLE_NOTIFY, ch->attr.value_handle,
- intermediate_notify_handler, t, NULL);
- } else if (g_strcmp0(ch->attr.uuid,
- TEMPERATURE_MEASUREMENT_UUID) == 0) {
+ ATT_OP_HANDLE_NOTIFY, c->value_handle,
+ intermediate_notify_handler, t, NULL);
+
+ discover_desc(t, c, c_next);
+ } else if (g_strcmp0(c->uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) {

t->attio_measurement_id = g_attrib_register(t->attrib,
- ATT_OP_HANDLE_IND, ch->attr.value_handle,
- measurement_ind_handler, t, NULL);
- } else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0) {
- gatt_read_char(ch->t->attrib, ch->attr.value_handle,
- read_temp_type_cb, ch);
- } else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
- ch->t->interval_val_handle = ch->attr.value_handle;
+ ATT_OP_HANDLE_IND, c->value_handle,
+ measurement_ind_handler, t, NULL);

- gatt_read_char(ch->t->attrib, ch->attr.value_handle,
- read_interval_cb, ch);
+ discover_desc(t, c, c_next);
+ } else if (g_strcmp0(c->uuid, TEMPERATURE_TYPE_UUID) == 0) {
+ gatt_read_char(t->attrib, c->value_handle,
+ read_temp_type_cb, t);
+ } else if (g_strcmp0(c->uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
+ gatt_read_char(t->attrib, c->value_handle, read_interval_cb, t);
+
+ t->interval_val_handle = c->value_handle;

t->attio_interval_id = g_attrib_register(t->attrib,
- ATT_OP_HANDLE_IND, ch->attr.value_handle,
- interval_ind_handler, t, NULL);
+ ATT_OP_HANDLE_IND, c->value_handle,
+ interval_ind_handler, t, NULL);
+
+ discover_desc(t, c, c_next);
}
}

@@ -727,34 +744,9 @@ static void configure_thermometer_cb(GSList *characteristics, guint8 status,

for (l = characteristics; l; l = l->next) {
struct gatt_char *c = l->data;
- struct characteristic *ch;
- uint16_t start, end;
-
- ch = g_new0(struct characteristic, 1);
- ch->attr.handle = c->handle;
- ch->attr.properties = c->properties;
- ch->attr.value_handle = c->value_handle;
- memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
- ch->t = t;
-
- t->chars = g_slist_append(t->chars, ch);
-
- process_thermometer_char(ch);
-
- start = c->value_handle + 1;
-
- if (l->next != NULL) {
- struct gatt_char *c = l->next->data;
- if (start == c->handle)
- continue;
- end = c->handle - 1;
- } else if (c->value_handle != t->svc_range->end) {
- end = t->svc_range->end;
- } else {
- continue;
- }
+ struct gatt_char *c_next = (l->next ? l->next->data : NULL);

- gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
+ process_thermometer_char(t, c, c_next);
}
}

--
1.8.0


2012-11-09 08:55:48

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 06/15] thermometer: Use dedicated handler for Measurement Interval

This patch replaces global indications handler with one registered only
for Measurement Interval value indications.
---
profiles/thermometer/thermometer.c | 104 +++++++++++++------------------------
1 file changed, 36 insertions(+), 68 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index c5fdb94..b01ac7a 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -70,11 +70,12 @@ struct thermometer {
GAttrib *attrib; /* GATT connection */
struct att_range *svc_range; /* Thermometer range */
guint attioid; /* Att watcher id */
- guint attindid; /* Att incications id */
/* attio id for Temperature Measurement value indications */
guint attio_measurement_id;
/* attio id for Intermediate Temperature value notifications */
guint attio_intermediate_id;
+ /* attio id for Measurement Interval value indications */
+ guint attio_interval_id;
GSList *chars; /* Characteristics */
gboolean intermediate;
uint8_t type;
@@ -179,11 +180,9 @@ static void destroy_thermometer(gpointer user_data)
if (t->attioid > 0)
btd_device_remove_attio_callback(t->dev, t->attioid);

- if (t->attindid > 0)
- g_attrib_unregister(t->attrib, t->attindid);
-
g_attrib_unregister(t->attrib, t->attio_measurement_id);
g_attrib_unregister(t->attrib, t->attio_intermediate_id);
+ g_attrib_unregister(t->attrib, t->attio_interval_id);

if (t->attrib != NULL)
g_attrib_unref(t->attrib);
@@ -244,14 +243,6 @@ static gint cmp_watcher(gconstpointer a, gconstpointer b)
return g_strcmp0(watcher->path, match->path);
}

-static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
-{
- const struct characteristic *ch = a;
- const uint16_t *handle = b;
-
- return ch->attr.value_handle - *handle;
-}
-
static struct thermometer_adapter *
find_thermometer_adapter(struct btd_adapter *adapter)
{
@@ -486,6 +477,30 @@ static void intermediate_notify_handler(const uint8_t *pdu, uint16_t len,
proc_measurement(t, pdu, len, FALSE);
}

+static void interval_ind_handler(const uint8_t *pdu, uint16_t len,
+ gpointer user_data)
+{
+ struct thermometer *t = user_data;
+ uint16_t interval;
+ uint8_t *opdu;
+ uint16_t olen;
+ size_t plen;
+
+ if (len < 5) {
+ DBG("Bad pdu received");
+ return;
+ }
+
+ interval = att_get_u16(pdu + 3);
+ change_property(t, "Interval", &interval);
+
+ opdu = g_attrib_get_buffer(t->attrib, &plen);
+ olen = enc_confirmation(opdu, plen);
+
+ if (olen > 0)
+ g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL);
+}
+
static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
@@ -719,6 +734,10 @@ static void process_thermometer_char(struct characteristic *ch)

gatt_read_char(ch->t->attrib, ch->attr.value_handle,
read_interval_cb, ch);
+
+ t->attio_interval_id = g_attrib_register(t->attrib,
+ ATT_OP_HANDLE_IND, ch->attr.value_handle,
+ interval_ind_handler, t, NULL);
}
}

@@ -1134,63 +1153,12 @@ static const GDBusSignalTable thermometer_signals[] = {
{ }
};

-static void proc_measurement_interval(struct thermometer *t, const uint8_t *pdu,
- uint16_t len)
-{
- uint16_t interval;
-
- if (len < 5) {
- DBG("Measurement interval value is not provided");
- return;
- }
-
- interval = att_get_u16(&pdu[3]);
-
- change_property(t, "Interval", &interval);
-}
-
-static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
- struct thermometer *t = user_data;
- const struct characteristic *ch;
- uint8_t *opdu;
- uint16_t handle, olen;
- GSList *l;
- size_t plen;
-
- if (len < 3) {
- DBG("Bad pdu received");
- return;
- }
-
- handle = att_get_u16(&pdu[1]);
- l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
- if (l == NULL) {
- DBG("Unexpected handle: 0x%04x", handle);
- return;
- }
-
- ch = l->data;
-
- if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
- proc_measurement_interval(t, pdu, len);
-
- opdu = g_attrib_get_buffer(t->attrib, &plen);
- olen = enc_confirmation(opdu, plen);
-
- if (olen > 0)
- g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL);
-}
-
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
{
struct thermometer *t = user_data;

t->attrib = g_attrib_ref(attrib);

- t->attindid = g_attrib_register(t->attrib, ATT_OP_HANDLE_IND,
- GATTRIB_ALL_HANDLES,
- ind_handler, t, NULL);
gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
NULL, configure_thermometer_cb, t);
}
@@ -1201,11 +1169,6 @@ static void attio_disconnected_cb(gpointer user_data)

DBG("GATT Disconnected");

- if (t->attindid > 0) {
- g_attrib_unregister(t->attrib, t->attindid);
- t->attindid = 0;
- }
-
if (t->attio_measurement_id > 0) {
g_attrib_unregister(t->attrib, t->attio_measurement_id);
t->attio_measurement_id = 0;
@@ -1216,6 +1179,11 @@ static void attio_disconnected_cb(gpointer user_data)
t->attio_intermediate_id = 0;
}

+ if (t->attio_interval_id > 0) {
+ g_attrib_unregister(t->attrib, t->attio_interval_id);
+ t->attio_interval_id = 0;
+ }
+
g_attrib_unref(t->attrib);
t->attrib = NULL;
}
--
1.8.0


2012-11-09 08:55:45

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 03/15] thermometer: Store Measurement Interval value handle in struct

This patch adds Measurement Interval value handle directly into
thermometer struct. This way there's no need to traverse list
looking for value.

get_characteristic() function and related helpers are now unused
so can be removed.
---
profiles/thermometer/thermometer.c | 29 +++++------------------------
1 file changed, 5 insertions(+), 24 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index d836462..d65fc0d 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -83,6 +83,7 @@ struct thermometer {

uint16_t measurement_ccc_handle;
uint16_t intermediate_ccc_handle;
+ uint16_t interval_val_handle;
};

struct characteristic {
@@ -240,14 +241,6 @@ static gint cmp_watcher(gconstpointer a, gconstpointer b)
return g_strcmp0(watcher->path, match->path);
}

-static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
-{
- const struct characteristic *ch = a;
- const char *uuid = b;
-
- return g_strcmp0(ch->attr.uuid, uuid);
-}
-
static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
{
const struct characteristic *ch = a;
@@ -267,18 +260,6 @@ find_thermometer_adapter(struct btd_adapter *adapter)
return l->data;
}

-static struct characteristic *get_characteristic(struct thermometer *t,
- const char *uuid)
-{
- GSList *l;
-
- l = g_slist_find_custom(t->chars, uuid, cmp_char_uuid);
- if (l == NULL)
- return NULL;
-
- return l->data;
-}
-
static void change_property(struct thermometer *t, const char *name,
gpointer value) {
if (g_strcmp0(name, "Intermediate") == 0) {
@@ -541,6 +522,8 @@ static void process_thermometer_char(struct characteristic *ch)
gatt_read_char(ch->t->attrib, ch->attr.value_handle,
read_temp_type_cb, ch);
} else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
+ ch->t->interval_val_handle = ch->attr.value_handle;
+
gatt_read_char(ch->t->attrib, ch->attr.value_handle,
read_interval_cb, ch);
}
@@ -651,14 +634,12 @@ static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
uint16_t value)
{
struct tmp_interval_data *data;
- struct characteristic *ch;
uint8_t atval[2];

if (t->attrib == NULL)
return btd_error_not_connected(msg);

- ch = get_characteristic(t, MEASUREMENT_INTERVAL_UUID);
- if (ch == NULL)
+ if (t->interval_val_handle == 0)
return btd_error_not_available(msg);

if (value < t->min || value > t->max)
@@ -669,7 +650,7 @@ static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
data = g_new0(struct tmp_interval_data, 1);
data->thermometer = t;
data->interval = value;
- gatt_write_char(t->attrib, ch->attr.value_handle, atval, 2,
+ gatt_write_char(t->attrib, t->interval_val_handle, atval, 2,
write_interval_cb, data);

return dbus_message_new_method_return(msg);
--
1.8.0


2012-11-09 08:55:44

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 02/15] thermometer: Store Intermediate Temperature CCC handle in struct

This patch adds Intermediate Measurement CCC handle value directly into
thermometer struct. This way there's no need to traverse nested lists
looking for value.

write_ccc() function and related helpers are now unused so can be
removed.
---
profiles/thermometer/thermometer.c | 80 ++++++++++++--------------------------
1 file changed, 25 insertions(+), 55 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 3ea6e96..d836462 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -82,6 +82,7 @@ struct thermometer {
gboolean has_interval;

uint16_t measurement_ccc_handle;
+ uint16_t intermediate_ccc_handle;
};

struct characteristic {
@@ -255,14 +256,6 @@ static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
return ch->attr.value_handle - *handle;
}

-static gint cmp_descriptor(gconstpointer a, gconstpointer b)
-{
- const struct descriptor *desc = a;
- const bt_uuid_t *uuid = b;
-
- return bt_uuid_cmp(&desc->uuid, uuid);
-}
-
static struct thermometer_adapter *
find_thermometer_adapter(struct btd_adapter *adapter)
{
@@ -286,18 +279,6 @@ static struct characteristic *get_characteristic(struct thermometer *t,
return l->data;
}

-static struct descriptor *get_descriptor(struct characteristic *ch,
- const bt_uuid_t *uuid)
-{
- GSList *l;
-
- l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
- if (l == NULL)
- return NULL;
-
- return l->data;
-}
-
static void change_property(struct thermometer *t, const char *name,
gpointer value) {
if (g_strcmp0(name, "Intermediate") == 0) {
@@ -415,6 +396,8 @@ static void process_thermometer_desc(struct descriptor *desc)
"indication");
} else if (g_strcmp0(ch->attr.uuid,
INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+ desc->ch->t->intermediate_ccc_handle = desc->handle;
+
if (g_slist_length(ch->t->tadapter->iwatchers) == 0)
return;

@@ -728,38 +711,6 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
return write_attr_interval(t, msg, value);
}

-static void write_ccc(struct thermometer *t, const char *uuid, uint16_t value)
-{
- struct characteristic *ch;
- struct descriptor *desc;
- bt_uuid_t btuuid;
- uint8_t atval[2];
- char *msg;
-
- if (t->attrib == NULL)
- return;
-
- ch = get_characteristic(t, uuid);
- if (ch == NULL) {
- DBG("Characteristic %s not found", uuid);
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- desc = get_descriptor(ch, &btuuid);
- if (desc == NULL) {
- DBG("CCC descriptor for %s not found", uuid);
- return;
- }
-
- att_put_u16(value, atval);
-
- msg = g_strdup_printf("Write CCC: %04x for %s", value, uuid);
-
- gatt_write_char(t->attrib, desc->handle, atval, sizeof(atval),
- write_ccc_cb, msg);
-}
-
static void enable_final_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
@@ -780,9 +731,18 @@ static void enable_final_measurement(gpointer data, gpointer user_data)
static void enable_intermediate_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
+ uint16_t handle = t->intermediate_ccc_handle;
+ uint8_t value[2];
+ char *msg;
+
+ if (t->attrib == NULL || !handle)
+ return;
+
+ att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+ msg = g_strdup("Enable Intermediate Temperature notifications");

- write_ccc(t, INTERMEDIATE_TEMPERATURE_UUID,
- GATT_CLIENT_CHARAC_CFG_NOTIF_BIT);
+ gatt_write_char(t->attrib, handle, value, sizeof(value),
+ write_ccc_cb, msg);
}

static void disable_final_measurement(gpointer data, gpointer user_data)
@@ -805,8 +765,18 @@ static void disable_final_measurement(gpointer data, gpointer user_data)
static void disable_intermediate_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
+ uint16_t handle = t->intermediate_ccc_handle;
+ uint8_t value[2];
+ char *msg;

- write_ccc(t, INTERMEDIATE_TEMPERATURE_UUID, 0x0000);
+ if (t->attrib == NULL || !handle)
+ return;
+
+ att_put_u16(0x0000, value);
+ msg = g_strdup("Disable Intermediate Temperature notifications");
+
+ gatt_write_char(t->attrib, handle, value, sizeof(value),
+ write_ccc_cb, msg);
}

static void remove_int_watcher(struct thermometer_adapter *tadapter,
--
1.8.0


2012-11-09 08:55:43

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 01/15] thermometer: Store Temperature Measurement CCC handle in struct

This patch adds Temperature Measurement CCC handle value directly into
thermometer struct. This way there's no need to traverse nested lists
looking for value.
---
profiles/thermometer/thermometer.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 4d1df1d..3ea6e96 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -80,6 +80,8 @@ struct thermometer {
uint16_t min;
gboolean has_type;
gboolean has_interval;
+
+ uint16_t measurement_ccc_handle;
};

struct characteristic {
@@ -403,6 +405,8 @@ static void process_thermometer_desc(struct descriptor *desc)

if (g_strcmp0(ch->attr.uuid,
TEMPERATURE_MEASUREMENT_UUID) == 0) {
+ desc->ch->t->measurement_ccc_handle = desc->handle;
+
if (g_slist_length(ch->t->tadapter->fwatchers) == 0)
return;

@@ -759,9 +763,18 @@ static void write_ccc(struct thermometer *t, const char *uuid, uint16_t value)
static void enable_final_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
+ uint16_t handle = t->measurement_ccc_handle;
+ uint8_t value[2];
+ char *msg;
+
+ if (t->attrib == NULL || !handle)
+ return;
+
+ att_put_u16(GATT_CLIENT_CHARAC_CFG_IND_BIT, value);
+ msg = g_strdup("Enable Temperature Measurement indications");

- write_ccc(t, TEMPERATURE_MEASUREMENT_UUID,
- GATT_CLIENT_CHARAC_CFG_IND_BIT);
+ gatt_write_char(t->attrib, handle, value, sizeof(value),
+ write_ccc_cb, msg);
}

static void enable_intermediate_measurement(gpointer data, gpointer user_data)
@@ -775,8 +788,18 @@ static void enable_intermediate_measurement(gpointer data, gpointer user_data)
static void disable_final_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
+ uint16_t handle = t->measurement_ccc_handle;
+ uint8_t value[2];
+ char *msg;
+
+ if (t->attrib == NULL || !handle)
+ return;
+
+ att_put_u16(0x0000, value);
+ msg = g_strdup("Disable Temperature Measurement indications");

- write_ccc(t, TEMPERATURE_MEASUREMENT_UUID, 0x0000);
+ gatt_write_char(t->attrib, handle, value, sizeof(value),
+ write_ccc_cb, msg);
}

static void disable_intermediate_measurement(gpointer data, gpointer user_data)
--
1.8.0