Hi,
Changes since v1:
- fixed inconsistencies and issues in API document formatting
- changed string properties to lower-case (new patch)
Andrzej Kaczmarek (15):
thermometer: Store thermometer devices per-adapter
thermometer: Register ThermometerManager interface on adapter path
thermometer: Move watcher logic to adapter interface
thermometer: Include remote device information in MeasurementReceived
thermometer: Update API document
thermometer: Update test script
thermometer: Reformat MeasurementReceived description
thermometer: Change string properties to lower-case
thermometer: Update driver naming style
thermometer: Add constant definition for watcher interface name
thermometer: Add common function to write characteristics CCC
thermometer: Refactor processing of measurement characteristic value
thermometer: Fix whitespace
thermometer: Fix indentation
thermometer: Fix missing braces
doc/thermometer-api.txt | 127 ++++-----
profiles/thermometer/manager.c | 24 +-
profiles/thermometer/thermometer.c | 512 +++++++++++++++++++++----------------
profiles/thermometer/thermometer.h | 2 +
test/test-thermometer | 16 +-
5 files changed, 386 insertions(+), 295 deletions(-)
--
1.7.11.3
Hi Andrzej,
2012/10/2 Andrzej Kaczmarek <[email protected]>:
> Hi Santiago,
>
>
> On 10/01/2012 02:08 PM, Santiago Carot wrote:
>>>>
>>>> Mantissa values must not always be 2^23-1 on special cases.
>>>> Information provided here is required for upper profiles which are
>>>> implementing an 11073-20601 protocol layer because they have to
>>>> differentiate among these values. In my opinion, documentation about
>>>> passible values for the mantissa should remain as they are.
>>>
>>>
>>>
>>> HTS specification states (see quote below) that measurement value field
>>> may
>>> be NaN in case sensor is not able to provide valid measurement. So I
>>> assume
>>> here that either it has valid data or NaN otherwise and thus there's no
>>> need
>>> to specify other special values as they should not be received here.
>>>
>>> <quote>
>>> The Temperature Measurement Value field may contain special float value
>>> NaN
>>> (0x007FFFFF) defined in IEEE 11073-20601 [4] to report an invalid result
>>> from a computation step or missing data due to the hardware?s inability
>>> to
>>> provide a valid measurement.
>>> </quote>
>>>
>>
>> IMHO that doesn't justify you to force all mantisse values to be
>> 2^23-1, first of all because the value type for this characteristic is
>> a FLOAT type, so any value that a thermometer could send, it does it
>> using the format defined for FLOAT types which is explained in
>> IEEE-11073-20601,
>> [http://developer.bluetooth.org/gatt/Pages/FormatTypes.aspx]
>>
>> On the other hand, I understand from this quote that thermometers MAY
>> set NaN in case sensor is not able to provide valid measuremen due to
>> an invalid result or missing data, but it doesn't say anything about
>> other values that a FLOAT types can take, so you are forcing to be NaN
>> other special cases that are defined for this kind of type.
>>
>> If you had a look to that spec you could see wich other special values
>> a FLOAT type could take, if not, you could at least have a look to one
>> of the whitepapers defined in bluetooth sig for transcoders.
>
>
> Just to be clear here: I do not force mantissa values to any particular
> value. Whatever is received from remote device is still dispatched to
> application as-is. I just modified description so it mentions what HTS
> specification says about this value and that's all and since it was just
> done "by the way" when reformatting description I won't push for it.
>
> But perhaps it's worth just adding note that exponent and mantissa are as in
> IEEE-11073-20601. This clearly states that apps working in IEEE-11073-20601
> ecosystem can pack both values directly into float and there's no need to
> specify all special values.
>
I strongly agree with you, that's the reason we agreed in the past to
add the note for special FLOAT values in the API in order not to
redirect developers to the IEEE standard which, in addition, isn't
free.
Regards.
Hi Santiago,
On 10/01/2012 02:08 PM, Santiago Carot wrote:
>>> Mantissa values must not always be 2^23-1 on special cases.
>>> Information provided here is required for upper profiles which are
>>> implementing an 11073-20601 protocol layer because they have to
>>> differentiate among these values. In my opinion, documentation about
>>> passible values for the mantissa should remain as they are.
>>
>>
>> HTS specification states (see quote below) that measurement value field may
>> be NaN in case sensor is not able to provide valid measurement. So I assume
>> here that either it has valid data or NaN otherwise and thus there's no need
>> to specify other special values as they should not be received here.
>>
>> <quote>
>> The Temperature Measurement Value field may contain special float value NaN
>> (0x007FFFFF) defined in IEEE 11073-20601 [4] to report an invalid result
>> from a computation step or missing data due to the hardware?s inability to
>> provide a valid measurement.
>> </quote>
>>
>
> IMHO that doesn't justify you to force all mantisse values to be
> 2^23-1, first of all because the value type for this characteristic is
> a FLOAT type, so any value that a thermometer could send, it does it
> using the format defined for FLOAT types which is explained in
> IEEE-11073-20601,
> [http://developer.bluetooth.org/gatt/Pages/FormatTypes.aspx]
>
> On the other hand, I understand from this quote that thermometers MAY
> set NaN in case sensor is not able to provide valid measuremen due to
> an invalid result or missing data, but it doesn't say anything about
> other values that a FLOAT types can take, so you are forcing to be NaN
> other special cases that are defined for this kind of type.
>
> If you had a look to that spec you could see wich other special values
> a FLOAT type could take, if not, you could at least have a look to one
> of the whitepapers defined in bluetooth sig for transcoders.
Just to be clear here: I do not force mantissa values to any particular
value. Whatever is received from remote device is still dispatched to
application as-is. I just modified description so it mentions what HTS
specification says about this value and that's all and since it was just
done "by the way" when reformatting description I won't push for it.
But perhaps it's worth just adding note that exponent and mantissa are
as in IEEE-11073-20601. This clearly states that apps working in
IEEE-11073-20601 ecosystem can pack both values directly into float and
there's no need to specify all special values.
BR,
Andrzej
Hi Andrzej
>>
>> Mantissa values must not always be 2^23-1 on special cases.
>> Information provided here is required for upper profiles which are
>> implementing an 11073-20601 protocol layer because they have to
>> differentiate among these values. In my opinion, documentation about
>> passible values for the mantissa should remain as they are.
>
>
> HTS specification states (see quote below) that measurement value field may
> be NaN in case sensor is not able to provide valid measurement. So I assume
> here that either it has valid data or NaN otherwise and thus there's no need
> to specify other special values as they should not be received here.
>
> <quote>
> The Temperature Measurement Value field may contain special float value NaN
> (0x007FFFFF) defined in IEEE 11073-20601 [4] to report an invalid result
> from a computation step or missing data due to the hardware?s inability to
> provide a valid measurement.
> </quote>
>
IMHO that doesn't justify you to force all mantisse values to be
2^23-1, first of all because the value type for this characteristic is
a FLOAT type, so any value that a thermometer could send, it does it
using the format defined for FLOAT types which is explained in
IEEE-11073-20601,
[http://developer.bluetooth.org/gatt/Pages/FormatTypes.aspx]
On the other hand, I understand from this quote that thermometers MAY
set NaN in case sensor is not able to provide valid measuremen due to
an invalid result or missing data, but it doesn't say anything about
other values that a FLOAT types can take, so you are forcing to be NaN
other special cases that are defined for this kind of type.
If you had a look to that spec you could see wich other special values
a FLOAT type could take, if not, you could at least have a look to one
of the whitepapers defined in bluetooth sig for transcoders.
Regards
Hi Santiago,
On 10/01/2012 11:43 AM, Santiago Carot wrote:
> Hi Andrzej
>
> 2012/10/1 Andrzej Kaczmarek <[email protected]>:
>> MeasurementReceived method description is reformatted to be more
>> readable and consistent with other API documents.
>>
>> Special values for Exponent and Mantissa fields specify now only NaN
>> value as this is only special value defined by HTS specification for
>> measurement.
>> ---
>> doc/thermometer-api.txt | 67 +++++++++++++++++++++++++++----------------------
>> 1 file changed, 37 insertions(+), 30 deletions(-)
>>
>> diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt
>> index 1828811..0fb28f5 100644
>> --- a/doc/thermometer-api.txt
>> +++ b/doc/thermometer-api.txt
>> @@ -97,33 +97,40 @@ Service unique name
>> Interface org.bluez.ThermometerWatcher
>> Object path freely definable
>>
>> -Methods void MeasurementReceived(dict measure)
>> -
>> - This callback gets called when a measure has been
>> - scanned in the thermometer. The Time entry in the dict
>> - will be only present if the device supports storing of
>> - data. The time value is expressed in seconds since epoch.
>> - The value represented is (mantissa) x (10**exponent)
>> - See foot note for special values when treating with
>> - health devices. The Type entry is only present if the
>> - measurement type is known. Otherwise, it is undefined.
>> -
>> - Dict is defined as below:
>> - {
>> - "Exponent" : int8,
>> - "Mantissa" : int32,
>> - "Unit" : ("Celsius" or "Fahrenheit"),
>> - "Time" : uint64,
>> - "Type" : ("Armpit", "Body", "Ear", "Finger",
>> - "Intestines", "Mouth", "Rectum", "Toe",
>> - "Tympanum"),
>> - "Measurement" : ("Final" or "Intermediate"),
>> - }
>> -
>> - For special cases, the exponent shall always be zero and
>> - the mantissa should be one of following values:
>> -
>> - NRes = -(2**23)
>> - NaN = +(2**23-1)
>> - INFINITY = (2**23-2)
>> - -INFINITY = -(2**23-2)
>> +Methods void MeasurementReceived(dict measurement)
>> +
>> + This callback gets called when a measurement has been
>> + scanned in the thermometer.
>> +
>> + Measurement:
>> +
>> + int16 Exponent:
>> + int32 Mantissa:
>> +
>> + Measurement value is calculated as
>> + (Mantissa) x (10^Exponent)
>> +
>> + In case of invalid or missing data,
>> + Exponent is set to 0 and Mantissa is
>> + set to 2^23-1 (0x7FFFFF hexadecimal).
>
> Mantissa values must not always be 2^23-1 on special cases.
> Information provided here is required for upper profiles which are
> implementing an 11073-20601 protocol layer because they have to
> differentiate among these values. In my opinion, documentation about
> passible values for the mantissa should remain as they are.
HTS specification states (see quote below) that measurement value field
may be NaN in case sensor is not able to provide valid measurement. So I
assume here that either it has valid data or NaN otherwise and thus
there's no need to specify other special values as they should not be
received here.
<quote>
The Temperature Measurement Value field may contain special float value
NaN (0x007FFFFF) defined in IEEE 11073-20601 [4] to report an invalid
result from a computation step or missing data due to the hardware?s
inability to provide a valid measurement.
</quote>
BR,
Andrzej
Hi Andrzej
2012/10/1 Andrzej Kaczmarek <[email protected]>:
> MeasurementReceived method description is reformatted to be more
> readable and consistent with other API documents.
>
> Special values for Exponent and Mantissa fields specify now only NaN
> value as this is only special value defined by HTS specification for
> measurement.
> ---
> doc/thermometer-api.txt | 67 +++++++++++++++++++++++++++----------------------
> 1 file changed, 37 insertions(+), 30 deletions(-)
>
> diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt
> index 1828811..0fb28f5 100644
> --- a/doc/thermometer-api.txt
> +++ b/doc/thermometer-api.txt
> @@ -97,33 +97,40 @@ Service unique name
> Interface org.bluez.ThermometerWatcher
> Object path freely definable
>
> -Methods void MeasurementReceived(dict measure)
> -
> - This callback gets called when a measure has been
> - scanned in the thermometer. The Time entry in the dict
> - will be only present if the device supports storing of
> - data. The time value is expressed in seconds since epoch.
> - The value represented is (mantissa) x (10**exponent)
> - See foot note for special values when treating with
> - health devices. The Type entry is only present if the
> - measurement type is known. Otherwise, it is undefined.
> -
> - Dict is defined as below:
> - {
> - "Exponent" : int8,
> - "Mantissa" : int32,
> - "Unit" : ("Celsius" or "Fahrenheit"),
> - "Time" : uint64,
> - "Type" : ("Armpit", "Body", "Ear", "Finger",
> - "Intestines", "Mouth", "Rectum", "Toe",
> - "Tympanum"),
> - "Measurement" : ("Final" or "Intermediate"),
> - }
> -
> - For special cases, the exponent shall always be zero and
> - the mantissa should be one of following values:
> -
> - NRes = -(2**23)
> - NaN = +(2**23-1)
> - INFINITY = (2**23-2)
> - -INFINITY = -(2**23-2)
> +Methods void MeasurementReceived(dict measurement)
> +
> + This callback gets called when a measurement has been
> + scanned in the thermometer.
> +
> + Measurement:
> +
> + int16 Exponent:
> + int32 Mantissa:
> +
> + Measurement value is calculated as
> + (Mantissa) x (10^Exponent)
> +
> + In case of invalid or missing data,
> + Exponent is set to 0 and Mantissa is
> + set to 2^23-1 (0x7FFFFF hexadecimal).
Mantissa values must not always be 2^23-1 on special cases.
Information provided here is required for upper profiles which are
implementing an 11073-20601 protocol layer because they have to
differentiate among these values. In my opinion, documentation about
passible values for the mantissa should remain as they are.
Regards
---
profiles/thermometer/thermometer.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 9028fa1..edcd42d 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -335,8 +335,9 @@ static void change_property(struct thermometer *t, const char *name,
emit_property_changed(device_get_path(t->dev),
THERMOMETER_INTERFACE, name,
DBUS_TYPE_UINT16, &t->min);
- } else
+ } else {
DBG("%s is not a thermometer property", name);
+ }
}
static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
@@ -421,8 +422,9 @@ static void process_thermometer_desc(struct descriptor *desc)
val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
msg = g_strdup("Enable Measurement Interval "
"indication");
- } else
+ } else {
goto done;
+ }
att_put_u16(val, atval);
gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
@@ -548,12 +550,13 @@ static void process_thermometer_char(struct characteristic *ch)
gboolean intermediate = TRUE;
change_property(ch->t, "Intermediate", &intermediate);
return;
- } else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0)
+ } else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0) {
gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
read_temp_type_cb, ch);
- else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+ } else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
read_interval_cb, ch);
+ }
}
static void configure_thermometer_cb(GSList *characteristics, guint8 status,
@@ -591,10 +594,11 @@ static void configure_thermometer_cb(GSList *characteristics, guint8 status,
if (start == c->handle)
continue;
end = c->handle - 1;
- } else if (c->value_handle != t->svc_range->end)
+ } else if (c->value_handle != t->svc_range->end) {
end = t->svc_range->end;
- else
+ } else {
continue;
+ }
gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
}
--
1.7.11.3
---
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 71c6567..9028fa1 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -83,7 +83,7 @@ struct thermometer {
};
struct characteristic {
- struct gatt_char attr; /* Characteristic */
+ struct gatt_char attr; /* Characteristic */
GSList *desc; /* Descriptors */
struct thermometer *t; /* Thermometer where the char belongs */
};
--
1.7.11.3
---
profiles/thermometer/thermometer.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index c8a6826..f2568c9 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -42,7 +42,8 @@
#include "gatt.h"
#include "thermometer.h"
-#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
+#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
+#define THERMOMETER_MANAGER_INTERFACE "org.bluez.ThermometerManager"
/* Temperature measurement flag fields */
#define TEMP_UNITS 0x01
@@ -189,6 +190,16 @@ static void destroy_thermometer(gpointer user_data)
g_free(t);
}
+static void destroy_thermometer_adapter(gpointer user_data)
+{
+ struct thermometer_adapter *tadapter = user_data;
+
+ if (tadapter->devices != NULL)
+ g_slist_free_full(tadapter->devices, destroy_thermometer);
+
+ g_free(tadapter);
+}
+
static gint cmp_adapter(gconstpointer a, gconstpointer b)
{
const struct thermometer_adapter *tadapter = a;
@@ -1321,6 +1332,10 @@ void thermometer_unregister(struct btd_device *device)
device_get_path(t->dev), THERMOMETER_INTERFACE);
}
+static const GDBusMethodTable thermometer_manager_methods[] = {
+ { }
+};
+
int thermometer_adapter_register(struct btd_adapter *adapter)
{
struct thermometer_adapter *tadapter;
@@ -1328,6 +1343,18 @@ int thermometer_adapter_register(struct btd_adapter *adapter)
tadapter = g_new0(struct thermometer_adapter, 1);
tadapter->adapter = adapter;
+ if (!g_dbus_register_interface(btd_get_dbus_connection(),
+ adapter_get_path(adapter),
+ THERMOMETER_MANAGER_INTERFACE,
+ thermometer_manager_methods,
+ NULL, NULL, tadapter,
+ destroy_thermometer_adapter)) {
+ error("D-Bus failed to register %s interface",
+ THERMOMETER_MANAGER_INTERFACE);
+ destroy_thermometer_adapter(tadapter);
+ return -EIO;
+ }
+
thermometer_adapters = g_slist_prepend(thermometer_adapters, tadapter);
return 0;
@@ -1342,4 +1369,8 @@ void thermometer_adapter_unregister(struct btd_adapter *adapter)
return;
thermometer_adapters = g_slist_remove(thermometer_adapters, tadapter);
+
+ g_dbus_unregister_interface(btd_get_dbus_connection(),
+ adapter_get_path(tadapter->adapter),
+ THERMOMETER_MANAGER_INTERFACE);
}
--
1.7.11.3
Data buffer is read by simply moving buffer pointer instead of calculating
indexes of consecutive fields. This makes function flow easier to follow
as there's no need to care about presence of fields prior to current when
reading data.
---
profiles/thermometer/thermometer.c | 66 +++++++++++++++++++++-----------------
1 file changed, 37 insertions(+), 29 deletions(-)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 43c14b0..3ec413b 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -1021,27 +1021,37 @@ static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
uint16_t len, gboolean final)
{
struct measurement m;
- const char *type;
+ const char *type = NULL;
uint8_t flags;
uint32_t raw;
- if (len < 4) {
+ /* skip opcode and handle */
+ pdu += 3;
+ len -= 3;
+
+ if (len < 1) {
DBG("Mandatory flags are not provided");
return;
}
- flags = pdu[3];
+ flags = *pdu;
+
if (flags & TEMP_UNITS)
m.unit = "fahrenheit";
else
m.unit = "celsius";
- if (len < 8) {
- DBG("Temperature measurement value is not provided");
+ pdu++;
+ len--;
+
+ if (len < 4) {
+ DBG("Mandatory temperature measurement value is not provided");
return;
}
- raw = att_get_u32(&pdu[4]);
+ memset(&m, 0, sizeof(m));
+
+ raw = att_get_u32(pdu);
m.mant = raw & 0x00FFFFFF;
m.exp = ((int32_t) raw) >> 24;
@@ -1050,48 +1060,46 @@ static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
m.mant = m.mant - FLOAT_MAX_MANTISSA;
}
+ pdu += 4;
+ len -= 4;
+
if (flags & TEMP_TIME_STAMP) {
struct tm ts;
time_t time;
- if (len < 15) {
- DBG("Can't get time stamp value");
+ if (len < 7) {
+ DBG("Time stamp is not provided");
return;
}
- ts.tm_year = att_get_u16(&pdu[8]) - 1900;
- ts.tm_mon = pdu[10] - 1;
- ts.tm_mday = pdu[11];
- ts.tm_hour = pdu[12];
- ts.tm_min = pdu[13];
- ts.tm_sec = pdu[14];
+ 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;
- } else
- m.suptime = FALSE;
+
+ pdu += 7;
+ len -= 7;
+ }
if (flags & TEMP_TYPE) {
- uint8_t index;
-
- if (m.suptime && len >= 16)
- index = 15;
- else if (!m.suptime && len >= 9)
- index = 9;
- else {
- DBG("Can't get temperature type");
+ if (len < 1) {
+ DBG("Temperature type is not provided");
return;
}
- type = temptype2str(pdu[index]);
- } else if (t->has_type)
+ type = temptype2str(*pdu);
+ } else if (t->has_type) {
type = temptype2str(t->type);
- else
- type = NULL;
+ }
- m.type = type ? g_strdup(type) : NULL;
+ m.type = g_strdup(type);
m.value = final ? "final" : "intermediate";
recv_measurement(t, &m);
--
1.7.11.3
---
profiles/thermometer/thermometer.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 6b5faa2..27effc3 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -44,6 +44,7 @@
#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
#define THERMOMETER_MANAGER_INTERFACE "org.bluez.ThermometerManager"
+#define THERMOMETER_WATCHER_INTERFACE "org.bluez.ThermometerWatcher"
/* Temperature measurement flag fields */
#define TEMP_UNITS 0x01
@@ -1034,7 +1035,7 @@ static void update_watcher(gpointer data, gpointer user_data)
DBusMessage *msg;
msg = dbus_message_new_method_call(w->srv, w->path,
- "org.bluez.ThermometerWatcher",
+ THERMOMETER_WATCHER_INTERFACE,
"MeasurementReceived");
if (msg == NULL)
return;
--
1.7.11.3
There are now few separate functions to write CCC for measurement
characteristics which looks similar. This patch adds common function
to write given value into CCC for given characteristics and leaves
dedicated functions to act only as simple wrappers.
---
profiles/thermometer/thermometer.c | 108 ++++++++-----------------------------
1 file changed, 23 insertions(+), 85 deletions(-)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 27effc3..43c14b0 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -376,7 +376,7 @@ static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
change_property(desc->ch->t, "Minimum", &min);
}
-static void measurement_cb(guint8 status, const guint8 *pdu,
+static void write_ccc_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
char *msg = user_data;
@@ -426,7 +426,7 @@ static void process_thermometer_desc(struct descriptor *desc)
att_put_u16(val, atval);
gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
- measurement_cb, msg);
+ write_ccc_cb, msg);
return;
}
@@ -720,9 +720,8 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
return write_attr_interval(t, msg, value);
}
-static void enable_final_measurement(gpointer data, gpointer user_data)
+static void write_ccc(struct thermometer *t, const char *uuid, uint16_t value)
{
- struct thermometer *t = data;
struct characteristic *ch;
struct descriptor *desc;
bt_uuid_t btuuid;
@@ -732,116 +731,55 @@ static void enable_final_measurement(gpointer data, gpointer user_data)
if (t->attrib == NULL)
return;
- ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
+ ch = get_characteristic(t, uuid);
if (ch == NULL) {
- DBG("Temperature measurement characteristic not found");
+ 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("Client characteristic configuration descriptor not found");
+ DBG("CCC descriptor for %s not found", uuid);
return;
}
- atval[0] = 0x02;
- atval[1] = 0x00;
- msg = g_strdup("Enable final measurement");
- gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+ 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_intermediate_measurement(gpointer data, gpointer user_data)
+static void enable_final_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
- struct characteristic *ch;
- struct descriptor *desc;
- bt_uuid_t btuuid;
- uint8_t atval[2];
- char *msg;
-
- if (t->attrib == NULL || !t->intermediate)
- return;
- ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
- if (ch == NULL) {
- DBG("Intermediate measurement characteristic not found");
- return;
- }
+ write_ccc(t, TEMPERATURE_MEASUREMENT_UUID,
+ GATT_CLIENT_CHARAC_CFG_IND_BIT);
+}
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- desc = get_descriptor(ch, &btuuid);
- if (desc == NULL) {
- DBG("Client characteristic configuration descriptor not found");
- return;
- }
+static void enable_intermediate_measurement(gpointer data, gpointer user_data)
+{
+ struct thermometer *t = data;
- atval[0] = 0x01;
- atval[1] = 0x00;
- msg = g_strdup("Enable intermediate measurement");
- gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+ write_ccc(t, INTERMEDIATE_TEMPERATURE_UUID,
+ GATT_CLIENT_CHARAC_CFG_NOTIF_BIT);
}
static void disable_final_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
- 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, TEMPERATURE_MEASUREMENT_UUID);
- if (ch == NULL) {
- DBG("Temperature measurement characteristic not found");
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- desc = get_descriptor(ch, &btuuid);
- if (desc == NULL) {
- DBG("Client characteristic configuration descriptor not found");
- return;
- }
-
- atval[0] = 0x00;
- atval[1] = 0x00;
- msg = g_strdup("Disable final measurement");
- gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+ write_ccc(t, TEMPERATURE_MEASUREMENT_UUID, 0x0000);
}
static void disable_intermediate_measurement(gpointer data, gpointer user_data)
{
struct thermometer *t = data;
- 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, INTERMEDIATE_TEMPERATURE_UUID);
- if (ch == NULL) {
- DBG("Intermediate measurement characteristic not found");
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- desc = get_descriptor(ch, &btuuid);
- if (desc == NULL) {
- DBG("Client characteristic configuration descriptor not found");
- return;
- }
- atval[0] = 0x00;
- atval[1] = 0x00;
- msg = g_strdup("Disable intermediate measurement");
- gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+ write_ccc(t, INTERMEDIATE_TEMPERATURE_UUID, 0x0000);
}
static void remove_int_watcher(struct thermometer_adapter *tadapter,
--
1.7.11.3
MeasurementReceived method description is reformatted to be more
readable and consistent with other API documents.
Special values for Exponent and Mantissa fields specify now only NaN
value as this is only special value defined by HTS specification for
measurement.
---
doc/thermometer-api.txt | 67 +++++++++++++++++++++++++++----------------------
1 file changed, 37 insertions(+), 30 deletions(-)
diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt
index 1828811..0fb28f5 100644
--- a/doc/thermometer-api.txt
+++ b/doc/thermometer-api.txt
@@ -97,33 +97,40 @@ Service unique name
Interface org.bluez.ThermometerWatcher
Object path freely definable
-Methods void MeasurementReceived(dict measure)
-
- This callback gets called when a measure has been
- scanned in the thermometer. The Time entry in the dict
- will be only present if the device supports storing of
- data. The time value is expressed in seconds since epoch.
- The value represented is (mantissa) x (10**exponent)
- See foot note for special values when treating with
- health devices. The Type entry is only present if the
- measurement type is known. Otherwise, it is undefined.
-
- Dict is defined as below:
- {
- "Exponent" : int8,
- "Mantissa" : int32,
- "Unit" : ("Celsius" or "Fahrenheit"),
- "Time" : uint64,
- "Type" : ("Armpit", "Body", "Ear", "Finger",
- "Intestines", "Mouth", "Rectum", "Toe",
- "Tympanum"),
- "Measurement" : ("Final" or "Intermediate"),
- }
-
- For special cases, the exponent shall always be zero and
- the mantissa should be one of following values:
-
- NRes = -(2**23)
- NaN = +(2**23-1)
- INFINITY = (2**23-2)
- -INFINITY = -(2**23-2)
+Methods void MeasurementReceived(dict measurement)
+
+ This callback gets called when a measurement has been
+ scanned in the thermometer.
+
+ Measurement:
+
+ int16 Exponent:
+ int32 Mantissa:
+
+ Measurement value is calculated as
+ (Mantissa) x (10^Exponent)
+
+ In case of invalid or missing data,
+ Exponent is set to 0 and Mantissa is
+ set to 2^23-1 (0x7FFFFF hexadecimal).
+
+ string Unit:
+
+ Possible values: "Celsius" or "Fahrenheit"
+
+ uint64 Time (optional):
+
+ Time of measurement, if supported by device.
+ Expressed in seconds since epoch.
+
+ string Type (optional):
+
+ Only present if measurement type is known.
+
+ Possible values: "Armpit", "Body", "Ear",
+ "Finger", "Intestines", "Mouth",
+ "Rectum", "Toe", "Tympanum"
+
+ string Measurement:
+
+ Possible values: "Final" or "Intermediate"
--
1.7.11.3
Since watchers are now registered per-adapter it's necessary to include
remote device information in MeasurementReceived callback.
This patch adds parameter to MeasurementReceived method which is an
object path to remote device object.
---
profiles/thermometer/thermometer.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 4eb67a7..f0c1d67 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -101,13 +101,14 @@ struct watcher {
};
struct measurement {
- int16_t exp;
- int32_t mant;
- uint64_t time;
- gboolean suptime;
- char *unit;
- char *type;
- char *value;
+ struct thermometer *t;
+ int16_t exp;
+ int32_t mant;
+ uint64_t time;
+ gboolean suptime;
+ char *unit;
+ char *type;
+ char *value;
};
struct tmp_interval_data {
@@ -1027,6 +1028,7 @@ 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;
@@ -1039,6 +1041,8 @@ static void update_watcher(gpointer data, gpointer user_data)
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
@@ -1064,6 +1068,8 @@ 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
--
1.7.11.3
---
doc/thermometer-api.txt | 10 +++++-----
profiles/thermometer/thermometer.c | 26 +++++++++++++-------------
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt
index 0fb28f5..7ae161c 100644
--- a/doc/thermometer-api.txt
+++ b/doc/thermometer-api.txt
@@ -116,7 +116,7 @@ Methods void MeasurementReceived(dict measurement)
string Unit:
- Possible values: "Celsius" or "Fahrenheit"
+ Possible values: "celsius" or "fahrenheit"
uint64 Time (optional):
@@ -127,10 +127,10 @@ Methods void MeasurementReceived(dict measurement)
Only present if measurement type is known.
- Possible values: "Armpit", "Body", "Ear",
- "Finger", "Intestines", "Mouth",
- "Rectum", "Toe", "Tympanum"
+ Possible values: "armpit", "body", "ear",
+ "finger", "intestines", "mouth",
+ "rectum", "toe", "tympanum"
string Measurement:
- Possible values: "Final" or "Intermediate"
+ Possible values: "final" or "intermediate"
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index f0c1d67..6b5faa2 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -120,15 +120,15 @@ static GSList *thermometer_adapters = NULL;
const char *temp_type[] = {
"<reserved>",
- "Armpit",
- "Body",
- "Ear",
- "Finger",
- "Intestines",
- "Mouth",
- "Rectum",
- "Toe",
- "Tympanum"
+ "armpit",
+ "body",
+ "ear",
+ "finger",
+ "intestines",
+ "mouth",
+ "rectum",
+ "toe",
+ "tympanum"
};
static const gchar *temptype2str(uint8_t value)
@@ -1070,7 +1070,7 @@ static void recv_measurement(struct thermometer *t, struct measurement *m)
m->t = t;
- if (g_strcmp0(m->value, "Intermediate") == 0)
+ if (g_strcmp0(m->value, "intermediate") == 0)
wlist = t->tadapter->iwatchers;
else
wlist = t->tadapter->fwatchers;
@@ -1093,9 +1093,9 @@ static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
flags = pdu[3];
if (flags & TEMP_UNITS)
- m.unit = "Fahrenheit";
+ m.unit = "fahrenheit";
else
- m.unit = "Celsius";
+ m.unit = "celsius";
if (len < 8) {
DBG("Temperature measurement value is not provided");
@@ -1153,7 +1153,7 @@ static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
type = NULL;
m.type = type ? g_strdup(type) : NULL;
- m.value = final ? "Final" : "Intermediate";
+ m.value = final ? "final" : "intermediate";
recv_measurement(t, &m);
g_free(m.type);
--
1.7.11.3
---
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 3ec413b..71c6567 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -634,7 +634,7 @@ static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
return reply;
}
-static void write_interval_cb (guint8 status, const guint8 *pdu, guint16 len,
+static void write_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
struct tmp_interval_data *data = user_data;
--
1.7.11.3
---
test/test-thermometer | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/test/test-thermometer b/test/test-thermometer
index 9216264..2ca260f 100755
--- a/test/test-thermometer
+++ b/test/test-thermometer
@@ -16,9 +16,9 @@ from optparse import OptionParser, make_option
class Watcher(dbus.service.Object):
@dbus.service.method("org.bluez.ThermometerWatcher",
- in_signature="a{sv}", out_signature="")
- def MeasurementReceived(self, measure):
- print(measure["Measurement"], " measurement received")
+ in_signature="oa{sv}", out_signature="")
+ def MeasurementReceived(self, device, measure):
+ print("%s measurement received from %s" % (measure["Measurement"], device))
print("Exponent: ", measure["Exponent"])
print("Mantissa: ", measure["Mantissa"])
print("Unit: ", measure["Unit"])
@@ -66,23 +66,23 @@ if __name__ == "__main__":
adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
"org.bluez.Adapter")
+ thermometer_manager = dbus.Interface(bus.get_object("org.bluez",
+ adapter_path), "org.bluez.ThermometerManager")
+
device_path = adapter.FindDevice(options.address)
bus.add_signal_receiver(property_changed, bus_name="org.bluez",
dbus_interface="org.bluez.Thermometer",
signal_name="PropertyChanged")
- thermometer = dbus.Interface(bus.get_object("org.bluez",
- device_path), "org.bluez.Thermometer")
-
path = "/test/watcher"
watcher = Watcher(bus, path)
- thermometer.RegisterWatcher(path)
+ thermometer_manager.RegisterWatcher(path)
if len(args) > 0:
if args[0] == "EnableIntermediateMeasurement":
- thermometer.EnableIntermediateMeasurement(path)
+ thermometer_manager.EnableIntermediateMeasurement(path)
else:
print("unknown command")
sys.exit(1)
--
1.7.11.3
This patch changes device probe and remove functions name to include
'device' rather than 'driver' name as it better describes what both
do.
Also profile driver name is changed to better describe that it's now
profile driver rather than device driver only.
---
profiles/thermometer/manager.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/profiles/thermometer/manager.c b/profiles/thermometer/manager.c
index 86e3a0f..6057633 100644
--- a/profiles/thermometer/manager.c
+++ b/profiles/thermometer/manager.c
@@ -41,7 +41,7 @@ static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
return g_strcmp0(prim->uuid, uuid);
}
-static int thermometer_driver_probe(struct btd_profile *p,
+static int thermometer_device_probe(struct btd_profile *p,
struct btd_device *device,
GSList *uuids)
{
@@ -60,7 +60,7 @@ static int thermometer_driver_probe(struct btd_profile *p,
return thermometer_register(device, tattr);
}
-static void thermometer_driver_remove(struct btd_profile *p,
+static void thermometer_device_remove(struct btd_profile *p,
struct btd_device *device)
{
thermometer_unregister(device);
@@ -79,10 +79,10 @@ static void thermometer_adapter_remove(struct btd_profile *p,
}
static struct btd_profile thermometer_profile = {
- .name = "thermometer-device-driver",
+ .name = "Health Thermometer GATT driver",
.remote_uuids = BTD_UUIDS(HEALTH_THERMOMETER_UUID),
- .device_probe = thermometer_driver_probe,
- .device_remove = thermometer_driver_remove,
+ .device_probe = thermometer_device_probe,
+ .device_remove = thermometer_device_remove,
.adapter_probe = thermometer_adapter_probe,
.adapter_remove = thermometer_adapter_remove
};
--
1.7.11.3
This patch moves watcher related methods to ThermometerManager interface
so watchers can be registered per-adapter instead of per-device.
Final measurement notifications are now enabled on all devices connected
to given adapter when first watcher is registered and disabled when last
watcher is unregistered.
Intermediate measurement notifications are enabled for all devices
connected to given adapter which support this feature.
---
profiles/thermometer/thermometer.c | 134 +++++++++++++++++++------------------
1 file changed, 70 insertions(+), 64 deletions(-)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index f2568c9..4eb67a7 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -59,6 +59,8 @@
struct thermometer_adapter {
struct btd_adapter *adapter;
GSList *devices;
+ GSList *fwatchers; /* Final measurements */
+ GSList *iwatchers; /* Intermediate measurements */
};
struct thermometer {
@@ -70,8 +72,6 @@ struct thermometer {
guint attindid; /* Att incications id */
guint attnotid; /* Att notif id */
GSList *chars; /* Characteristics */
- GSList *fwatchers; /* Final measurements */
- GSList *iwatchers; /* Intermediate meas */
gboolean intermediate;
uint8_t type;
uint16_t interval;
@@ -94,10 +94,10 @@ struct descriptor {
};
struct watcher {
- struct thermometer *t;
- guint id;
- char *srv;
- char *path;
+ struct thermometer_adapter *tadapter;
+ guint id;
+ char *srv;
+ char *path;
};
struct measurement {
@@ -182,9 +182,6 @@ static void destroy_thermometer(gpointer user_data)
if (t->chars != NULL)
g_slist_free_full(t->chars, destroy_char);
- if (t->fwatchers != NULL)
- g_slist_free_full(t->fwatchers, remove_watcher);
-
btd_device_unref(t->dev);
g_free(t->svc_range);
g_free(t);
@@ -197,6 +194,9 @@ static void destroy_thermometer_adapter(gpointer user_data)
if (tadapter->devices != NULL)
g_slist_free_full(tadapter->devices, destroy_thermometer);
+ if (tadapter->fwatchers != NULL)
+ g_slist_free_full(tadapter->fwatchers, remove_watcher);
+
g_free(tadapter);
}
@@ -400,7 +400,7 @@ static void process_thermometer_desc(struct descriptor *desc)
if (g_strcmp0(ch->attr.uuid,
TEMPERATURE_MEASUREMENT_UUID) == 0) {
- if (g_slist_length(ch->t->fwatchers) == 0)
+ if (g_slist_length(ch->t->tadapter->fwatchers) == 0)
return;
val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
@@ -408,7 +408,7 @@ static void process_thermometer_desc(struct descriptor *desc)
"indication");
} else if (g_strcmp0(ch->attr.uuid,
INTERMEDIATE_TEMPERATURE_UUID) == 0) {
- if (g_slist_length(ch->t->iwatchers) == 0)
+ if (g_slist_length(ch->t->tadapter->iwatchers) == 0)
return;
val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
@@ -718,8 +718,9 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
return write_attr_interval(t, msg, value);
}
-static void enable_final_measurement(struct thermometer *t)
+static void enable_final_measurement(gpointer data, gpointer user_data)
{
+ struct thermometer *t = data;
struct characteristic *ch;
struct descriptor *desc;
bt_uuid_t btuuid;
@@ -748,15 +749,16 @@ static void enable_final_measurement(struct thermometer *t)
gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
}
-static void enable_intermediate_measurement(struct thermometer *t)
+static void enable_intermediate_measurement(gpointer data, gpointer user_data)
{
+ struct thermometer *t = data;
struct characteristic *ch;
struct descriptor *desc;
bt_uuid_t btuuid;
uint8_t atval[2];
char *msg;
- if (t->attrib == NULL)
+ if (t->attrib == NULL || !t->intermediate)
return;
ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
@@ -778,8 +780,9 @@ static void enable_intermediate_measurement(struct thermometer *t)
gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
}
-static void disable_final_measurement(struct thermometer *t)
+static void disable_final_measurement(gpointer data, gpointer user_data)
{
+ struct thermometer *t = data;
struct characteristic *ch;
struct descriptor *desc;
bt_uuid_t btuuid;
@@ -808,8 +811,9 @@ static void disable_final_measurement(struct thermometer *t)
gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
}
-static void disable_intermediate_measurement(struct thermometer *t)
+static void disable_intermediate_measurement(gpointer data, gpointer user_data)
{
+ struct thermometer *t = data;
struct characteristic *ch;
struct descriptor *desc;
bt_uuid_t btuuid;
@@ -838,31 +842,34 @@ static void disable_intermediate_measurement(struct thermometer *t)
gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
}
-static void remove_int_watcher(struct thermometer *t, struct watcher *w)
+static void remove_int_watcher(struct thermometer_adapter *tadapter,
+ struct watcher *w)
{
- if (!g_slist_find(t->iwatchers, w))
+ if (!g_slist_find(tadapter->iwatchers, w))
return;
- t->iwatchers = g_slist_remove(t->iwatchers, w);
+ tadapter->iwatchers = g_slist_remove(tadapter->iwatchers, w);
- if (g_slist_length(t->iwatchers) == 0)
- disable_intermediate_measurement(t);
+ if (g_slist_length(tadapter->iwatchers) == 0)
+ g_slist_foreach(tadapter->devices,
+ disable_intermediate_measurement, 0);
}
static void watcher_exit(DBusConnection *conn, void *user_data)
{
struct watcher *watcher = user_data;
- struct thermometer *t = watcher->t;
+ struct thermometer_adapter *tadapter = watcher->tadapter;
DBG("Thermometer watcher %s disconnected", watcher->path);
- remove_int_watcher(t, watcher);
+ remove_int_watcher(tadapter, watcher);
- t->fwatchers = g_slist_remove(t->fwatchers, watcher);
+ tadapter->fwatchers = g_slist_remove(tadapter->fwatchers, watcher);
g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
- if (g_slist_length(t->fwatchers) == 0)
- disable_final_measurement(t);
+ if (g_slist_length(tadapter->fwatchers) == 0)
+ g_slist_foreach(tadapter->devices,
+ disable_final_measurement, 0);
}
static struct watcher *find_watcher(GSList *list, const char *sender,
@@ -888,7 +895,7 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
void *data)
{
const char *sender = dbus_message_get_sender(msg);
- struct thermometer *t = data;
+ struct thermometer_adapter *tadapter = data;
struct watcher *watcher;
char *path;
@@ -896,7 +903,7 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
- watcher = find_watcher(t->fwatchers, sender, path);
+ watcher = find_watcher(tadapter->fwatchers, sender, path);
if (watcher != NULL)
return btd_error_already_exists(msg);
@@ -905,14 +912,14 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
watcher = g_new0(struct watcher, 1);
watcher->srv = g_strdup(sender);
watcher->path = g_strdup(path);
- watcher->t = t;
+ watcher->tadapter = tadapter;
watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
watcher, destroy_watcher);
- if (g_slist_length(t->fwatchers) == 0)
- enable_final_measurement(t);
+ if (g_slist_length(tadapter->fwatchers) == 0)
+ g_slist_foreach(tadapter->devices, enable_final_measurement, 0);
- t->fwatchers = g_slist_prepend(t->fwatchers, watcher);
+ tadapter->fwatchers = g_slist_prepend(tadapter->fwatchers, watcher);
return dbus_message_new_method_return(msg);
}
@@ -921,7 +928,7 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
void *data)
{
const char *sender = dbus_message_get_sender(msg);
- struct thermometer *t = data;
+ struct thermometer_adapter *tadapter = data;
struct watcher *watcher;
char *path;
@@ -929,19 +936,20 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
- watcher = find_watcher(t->fwatchers, sender, path);
+ watcher = find_watcher(tadapter->fwatchers, sender, path);
if (watcher == NULL)
return btd_error_does_not_exist(msg);
DBG("Thermometer watcher %s unregistered", path);
- remove_int_watcher(t, watcher);
+ remove_int_watcher(tadapter, watcher);
- t->fwatchers = g_slist_remove(t->fwatchers, watcher);
+ tadapter->fwatchers = g_slist_remove(tadapter->fwatchers, watcher);
g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
- if (g_slist_length(t->fwatchers) == 0)
- disable_final_measurement(t);
+ if (g_slist_length(tadapter->fwatchers) == 0)
+ g_slist_foreach(tadapter->devices,
+ disable_final_measurement, 0);
return dbus_message_new_method_return(msg);
}
@@ -950,30 +958,28 @@ static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg,
void *data)
{
const char *sender = dbus_message_get_sender(msg);
- struct thermometer *t = data;
+ struct thermometer_adapter *ta = data;
struct watcher *watcher;
char *path;
- if (!t->intermediate)
- return btd_error_not_supported(msg);
-
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
- watcher = find_watcher(t->fwatchers, sender, path);
+ watcher = find_watcher(ta->fwatchers, sender, path);
if (watcher == NULL)
return btd_error_does_not_exist(msg);
- if (find_watcher(t->iwatchers, sender, path))
+ if (find_watcher(ta->iwatchers, sender, path))
return btd_error_already_exists(msg);
DBG("Intermediate measurement watcher %s registered", path);
- if (g_slist_length(t->iwatchers) == 0)
- enable_intermediate_measurement(t);
+ if (g_slist_length(ta->iwatchers) == 0)
+ g_slist_foreach(ta->devices,
+ enable_intermediate_measurement, 0);
- t->iwatchers = g_slist_prepend(t->iwatchers, watcher);
+ ta->iwatchers = g_slist_prepend(ta->iwatchers, watcher);
return dbus_message_new_method_return(msg);
}
@@ -982,7 +988,7 @@ static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
void *data)
{
const char *sender = dbus_message_get_sender(msg);
- struct thermometer *t = data;
+ struct thermometer_adapter *ta = data;
struct watcher *watcher;
char *path;
@@ -990,13 +996,13 @@ static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
- watcher = find_watcher(t->iwatchers, sender, path);
+ watcher = find_watcher(ta->iwatchers, sender, path);
if (watcher == NULL)
return btd_error_does_not_exist(msg);
DBG("Intermediate measurement %s unregistered", path);
- remove_int_watcher(t, watcher);
+ remove_int_watcher(ta, watcher);
return dbus_message_new_method_return(msg);
}
@@ -1008,18 +1014,6 @@ static const GDBusMethodTable thermometer_methods[] = {
{ GDBUS_ASYNC_METHOD("SetProperty",
GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
set_property) },
- { GDBUS_METHOD("RegisterWatcher",
- GDBUS_ARGS({ "agent", "o" }), NULL,
- register_watcher) },
- { GDBUS_METHOD("UnregisterWatcher",
- GDBUS_ARGS({ "agent", "o" }), NULL,
- unregister_watcher) },
- { GDBUS_METHOD("EnableIntermediateMeasurement",
- GDBUS_ARGS({ "agent", "o" }), NULL,
- enable_intermediate) },
- { GDBUS_METHOD("DisableIntermediateMeasurement",
- GDBUS_ARGS({ "agent", "o" }), NULL,
- disable_intermediate) },
{ }
};
@@ -1071,9 +1065,9 @@ static void recv_measurement(struct thermometer *t, struct measurement *m)
GSList *wlist;
if (g_strcmp0(m->value, "Intermediate") == 0)
- wlist = t->iwatchers;
+ wlist = t->tadapter->iwatchers;
else
- wlist = t->fwatchers;
+ wlist = t->tadapter->fwatchers;
g_slist_foreach(wlist, update_watcher, m);
}
@@ -1333,6 +1327,18 @@ void thermometer_unregister(struct btd_device *device)
}
static const GDBusMethodTable thermometer_manager_methods[] = {
+ { GDBUS_METHOD("RegisterWatcher",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ register_watcher) },
+ { GDBUS_METHOD("UnregisterWatcher",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ unregister_watcher) },
+ { GDBUS_METHOD("EnableIntermediateMeasurement",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ enable_intermediate) },
+ { GDBUS_METHOD("DisableIntermediateMeasurement",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ disable_intermediate) },
{ }
};
--
1.7.11.3
This patch updates Thermometer API document to reflect changes in
Thermometer interface and introduction of ThermometerManager
interface and fixes minor formatiing inconsistencies.
---
doc/thermometer-api.txt | 60 +++++++++++++++++++++++++------------------------
1 file changed, 31 insertions(+), 29 deletions(-)
diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt
index 2271270..1828811 100644
--- a/doc/thermometer-api.txt
+++ b/doc/thermometer-api.txt
@@ -1,30 +1,16 @@
BlueZ D-Bus Thermometer API description
-****************************************
+***************************************
Santiago Carot-Nemesio <[email protected]>
-Health Thermometer Profile hierarchy
-=====================================
+Health Thermometer Manager hierarchy
+====================================
Service org.bluez
-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.
+Interface org.bluez.ThermometerManager
+Object path [variable prefix]/{hci0,hci1,...}
- Possible Errors: org.bluez.Error.InvalidArguments
-
- dict GetProperties()
-
- Returns all properties for the interface. See the
- Properties section for the available properties.
-
- RegisterWatcher(object agent)
+Methods RegisterWatcher(object agent)
Registers a watcher to monitor scanned measurements.
This agent will be notified about final temperature
@@ -36,30 +22,45 @@ Methods void SetProperty(string name, variant value)
Unregisters a watcher.
- Final and intermediate temperatures won't be notified to
- this agent any more.
-
- Possible Errors: org.bluez.Error.InvalidArguments
- org.bluez.Error.NotFound
-
EnableIntermediateMeasurement(object agent)
Enables intermediate measurement notifications for this
- agent if the thermometer supports it.
+ agent. Intermediate measurements will be enabled only
+ for thermometers which support it.
Possible Errors: org.bluez.Error.InvalidArguments
- org.bluez.Error.NotSupported
DisableIntermediateMeasurement(object agent)
Disables intermediate measurement notifications for this
- agent. It will disable notifications in the thermometer
+ agent. It will disable notifications in thermometers
when the last agent removes the watcher for intermediate
measurements.
Possible Errors: org.bluez.Error.InvalidArguments
org.bluez.Error.NotFound
+Health Thermometer Profile hierarchy
+====================================
+
+Service org.bluez
+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
@@ -91,6 +92,7 @@ Properties boolean Intermediate [readonly]
Health Thermometer Watcher hierarchy
====================================
+
Service unique name
Interface org.bluez.ThermometerWatcher
Object path freely definable
--
1.7.11.3
This patch replaces global list of thermometer devices with per-adapter
lists.
---
profiles/thermometer/manager.c | 16 +++++-
profiles/thermometer/thermometer.c | 114 ++++++++++++++++++++++++++++++-------
profiles/thermometer/thermometer.h | 2 +
3 files changed, 110 insertions(+), 22 deletions(-)
diff --git a/profiles/thermometer/manager.c b/profiles/thermometer/manager.c
index d965976..86e3a0f 100644
--- a/profiles/thermometer/manager.c
+++ b/profiles/thermometer/manager.c
@@ -66,11 +66,25 @@ static void thermometer_driver_remove(struct btd_profile *p,
thermometer_unregister(device);
}
+static int thermometer_adapter_probe(struct btd_profile *p,
+ struct btd_adapter *adapter)
+{
+ return thermometer_adapter_register(adapter);
+}
+
+static void thermometer_adapter_remove(struct btd_profile *p,
+ struct btd_adapter *adapter)
+{
+ thermometer_adapter_unregister(adapter);
+}
+
static struct btd_profile thermometer_profile = {
.name = "thermometer-device-driver",
.remote_uuids = BTD_UUIDS(HEALTH_THERMOMETER_UUID),
.device_probe = thermometer_driver_probe,
- .device_remove = thermometer_driver_remove
+ .device_remove = thermometer_driver_remove,
+ .adapter_probe = thermometer_adapter_probe,
+ .adapter_remove = thermometer_adapter_remove
};
int thermometer_manager_init(void)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 77dcb26..c8a6826 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -55,23 +55,29 @@
#define TEMPERATURE_TYPE_SIZE 1
#define MEASUREMENT_INTERVAL_SIZE 2
+struct thermometer_adapter {
+ struct btd_adapter *adapter;
+ GSList *devices;
+};
+
struct thermometer {
- struct btd_device *dev; /* Device reference */
- GAttrib *attrib; /* GATT connection */
- struct att_range *svc_range; /* Thermometer range */
- guint attioid; /* Att watcher id */
- guint attindid; /* Att incications id */
- guint attnotid; /* Att notifications id */
- GSList *chars; /* Characteristics */
- GSList *fwatchers; /* Final measurements */
- GSList *iwatchers; /* Intermediate measurements */
- gboolean intermediate;
- uint8_t type;
- uint16_t interval;
- uint16_t max;
- uint16_t min;
- gboolean has_type;
- gboolean has_interval;
+ struct btd_device *dev; /* Device reference */
+ struct thermometer_adapter *tadapter;
+ GAttrib *attrib; /* GATT connection */
+ struct att_range *svc_range; /* Thermometer range */
+ guint attioid; /* Att watcher id */
+ guint attindid; /* Att incications id */
+ guint attnotid; /* Att notif id */
+ GSList *chars; /* Characteristics */
+ GSList *fwatchers; /* Final measurements */
+ GSList *iwatchers; /* Intermediate meas */
+ gboolean intermediate;
+ uint8_t type;
+ uint16_t interval;
+ uint16_t max;
+ uint16_t min;
+ gboolean has_type;
+ gboolean has_interval;
};
struct characteristic {
@@ -108,7 +114,7 @@ struct tmp_interval_data {
uint16_t interval;
};
-static GSList *thermometers = NULL;
+static GSList *thermometer_adapters = NULL;
const char *temp_type[] = {
"<reserved>",
@@ -183,6 +189,17 @@ static void destroy_thermometer(gpointer user_data)
g_free(t);
}
+static gint cmp_adapter(gconstpointer a, gconstpointer b)
+{
+ const struct thermometer_adapter *tadapter = a;
+ const struct btd_adapter *adapter = b;
+
+ if (adapter == tadapter->adapter)
+ return 0;
+
+ return -1;
+}
+
static gint cmp_device(gconstpointer a, gconstpointer b)
{
const struct thermometer *t = a;
@@ -231,6 +248,17 @@ static gint cmp_descriptor(gconstpointer a, gconstpointer b)
return bt_uuid_cmp(&desc->uuid, uuid);
}
+static struct thermometer_adapter *
+find_thermometer_adapter(struct btd_adapter *adapter)
+{
+ GSList *l = g_slist_find_custom(thermometer_adapters, adapter,
+ cmp_adapter);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
static struct characteristic *get_characteristic(struct thermometer *t,
const char *uuid)
{
@@ -1233,13 +1261,25 @@ int thermometer_register(struct btd_device *device, struct gatt_primary *tattr)
{
const gchar *path = device_get_path(device);
struct thermometer *t;
+ struct btd_adapter *adapter;
+ struct thermometer_adapter *tadapter;
+
+ adapter = device_get_adapter(device);
+
+ tadapter = find_thermometer_adapter(adapter);
+
+ if (tadapter == NULL)
+ return -1;
t = g_new0(struct thermometer, 1);
t->dev = btd_device_ref(device);
+ t->tadapter = tadapter;
t->svc_range = g_new0(struct att_range, 1);
t->svc_range->start = tattr->range.start;
t->svc_range->end = tattr->range.end;
+ tadapter->devices = g_slist_prepend(tadapter->devices, t);
+
if (!g_dbus_register_interface(btd_get_dbus_connection(),
path, THERMOMETER_INTERFACE,
thermometer_methods, thermometer_signals,
@@ -1250,8 +1290,6 @@ int thermometer_register(struct btd_device *device, struct gatt_primary *tattr)
return -EIO;
}
- thermometers = g_slist_prepend(thermometers, t);
-
t->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
attio_disconnected_cb, t);
return 0;
@@ -1260,14 +1298,48 @@ int thermometer_register(struct btd_device *device, struct gatt_primary *tattr)
void thermometer_unregister(struct btd_device *device)
{
struct thermometer *t;
+ struct btd_adapter *adapter;
+ struct thermometer_adapter *tadapter;
GSList *l;
- l = g_slist_find_custom(thermometers, device, cmp_device);
+ adapter = device_get_adapter(device);
+
+ tadapter = find_thermometer_adapter(adapter);
+
+ if (tadapter == NULL)
+ return;
+
+ l = g_slist_find_custom(tadapter->devices, device, cmp_device);
if (l == NULL)
return;
t = l->data;
- thermometers = g_slist_remove(thermometers, t);
+
+ tadapter->devices = g_slist_remove(tadapter->devices, t);
+
g_dbus_unregister_interface(btd_get_dbus_connection(),
device_get_path(t->dev), THERMOMETER_INTERFACE);
}
+
+int thermometer_adapter_register(struct btd_adapter *adapter)
+{
+ struct thermometer_adapter *tadapter;
+
+ tadapter = g_new0(struct thermometer_adapter, 1);
+ tadapter->adapter = adapter;
+
+ thermometer_adapters = g_slist_prepend(thermometer_adapters, tadapter);
+
+ return 0;
+}
+
+void thermometer_adapter_unregister(struct btd_adapter *adapter)
+{
+ struct thermometer_adapter *tadapter;
+
+ tadapter = find_thermometer_adapter(adapter);
+ if (tadapter == NULL)
+ return;
+
+ thermometer_adapters = g_slist_remove(thermometer_adapters, tadapter);
+}
diff --git a/profiles/thermometer/thermometer.h b/profiles/thermometer/thermometer.h
index 2744ed6..ca83c31 100644
--- a/profiles/thermometer/thermometer.h
+++ b/profiles/thermometer/thermometer.h
@@ -22,3 +22,5 @@
int thermometer_register(struct btd_device *device, struct gatt_primary *tattr);
void thermometer_unregister(struct btd_device *device);
+int thermometer_adapter_register(struct btd_adapter *adapter);
+void thermometer_adapter_unregister(struct btd_adapter *adapter);
--
1.7.11.3