2015-05-28 20:44:47

by Jakub Pawlowski

[permalink] [raw]
Subject: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Currently, calling org.bluez.Device1.Connect() on a new, never
connected before device, would cause automatic discovery of all
services.

This is bad in some cases, because discovering all available services
might take a long time. Additionally some devices, i.e. iPhone have
built-in 0.5s delay between each "Find Information Response" packet,
which make discovery even longer.


I would like to propose following change:

1. Calling org.bluez.Device1.Connect() would work just like now,
except no "Find Information Request" would be issued (that means no
call to "device_browse_gatt").

2. Add two new methods: org.bluez.Device1.DiscoverServices(), and
org.bluez.Device1.DiscoverServiceByUUID(uuid). First one would just
call device_browse_gatt and make "Find Information Request" , the
second one would issue "Find By Type Value Request" to find just one
service.


2015-05-31 02:55:05

by Johan Hedberg

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi Jakub,

On Thu, May 28, 2015, Jakub Pawlowski wrote:
> > 1. Instead of just 1 method there is at least 2, but Connect depends
> > on what has been discovered first so you are adding a D-Bus round
> > trips.
>
> Yes, I'm probably adding one round trip. It might hovewer be avoided.
> To avoid additional roundtrip there should be two methods:
> Connect() that just works right now, and ConnectToUUID(uuid) that
> would connect, and then do "Find By Type Value Request". I think that
> this solution wouldn't be that clean, and would be problematic to
> discover rest of services.

We already have this "ConnectToUUID" method in the form of
Device1.ConnectProfile, don't we? It was originally designed for BR/EDR,
but seems to have at least some code for LE as well. If it's not working
as desired for LE it's probably something worth fixing.

Johan

2015-05-29 08:35:51

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi Jakub,

On Fri, May 29, 2015 at 1:25 AM, Jakub Pawlowski <[email protected]> wrote:
> Hi Luiz,
>
> On Thu, May 28, 2015 at 2:32 PM, Luiz Augusto von Dentz
> <[email protected]> wrote:
>> Hi Jakub,
>>
>> On Thu, May 28, 2015 at 11:44 PM, Jakub Pawlowski <[email protected]> wrote:
>>> Currently, calling org.bluez.Device1.Connect() on a new, never
>>> connected before device, would cause automatic discovery of all
>>> services.
>>>
>>> This is bad in some cases, because discovering all available services
>>> might take a long time. Additionally some devices, i.e. iPhone have
>>> built-in 0.5s delay between each "Find Information Response" packet,
>>> which make discovery even longer.
>>>
>>>
>>> I would like to propose following change:
>>>
>>> 1. Calling org.bluez.Device1.Connect() would work just like now,
>>> except no "Find Information Request" would be issued (that means no
>>> call to "device_browse_gatt").
>>>
>>> 2. Add two new methods: org.bluez.Device1.DiscoverServices(), and
>>> org.bluez.Device1.DiscoverServiceByUUID(uuid). First one would just
>>> call device_browse_gatt and make "Find Information Request" , the
>>> second one would issue "Find By Type Value Request" to find just one
>>> service.
>>
>> You are just changing one problem to another, or actually many other problems:
>>
>
> Example use case to make things clearer:
> there's device advertising it contains service with UUID "abcd", and
> my app wants to use only this one. It connects to device, and asks
> only for this service. If it's not there I disconnect. If it's there,
> it read/writes and disconnect.
> Everything took ~1.5 second.
>
> If I can't do "Find By Type Value Request" I'm stuck discovering
> services for 6, or 10, or more seconds, depending of number of
> services on device.
>
>
>> 1. Instead of just 1 method there is at least 2, but Connect depends
>> on what has been discovered first so you are adding a D-Bus round
>> trips.
>
> Yes, I'm probably adding one round trip. It might hovewer be avoided.
> To avoid additional roundtrip there should be two methods:
> Connect() that just works right now, and ConnectToUUID(uuid) that
> would connect, and then do "Find By Type Value Request". I think that
> this solution wouldn't be that clean, and would be problematic to
> discover rest of services.
>
> One round trip per connection isn't that bad issue, is it ?
>
>> 2. DiscoverServiceByUUID can only discover primary services if I
>> remember correct, what about included? And if an application, or many,
>
> It can discovery Primary or Secondary services, but it is used for
> Primary only right now as far as I know.
>
>> decide to discovery one by one every single UUID defined in the spec,
>> how many more request that would be compared to Read by Group Type
>> Request?
>
> If application want to use only one service, and it cares about speed
> it should use this new method (I think that's the reason Bluetooth
> have "Find By Type Value Request").
> If application doesn't know what it wants, it should find all services for sure.
> If application want more than one service, or included service, it
> should probably discover all at once.
> If application wants to discover included service, it can do Read by
> Group Type with handle range that's included in "included service"
> attribute (would need new API method if we want that, or use discover
> all service).
>
>
>> 3. We can't take advance of Service Changed Characteristic if
>> DiscoverServiceByUUID, so at that point one would have to start
>> polling if the remote server has capability to change its database.
>>
>> I guess the problem number 3 is actually what you did not consider,
>> the whole point is that we discover only once and then let the server
>> tell us what has changed, so reconnection should happens very fast
>> because we already have the device database in cache.
>
> Right, I haven't conseidered number 3, but:
> - app might decide to later discover rest of services, or
> - just service I discovered might be still cached, or
> - service I need might be re-discovered because it's only one and
> it's fast in comparison to discovering all
> - maybe if device get paired, full service discovery will be required
> ? otherwise it'll change MAC in 15 minutes and be forgotten anyway.
>
> I'll figure out how to deal nicely with cache.
>
> I think that discovering one service should be a option in modern BLE
> API (and I know few projects that need it).
> Please note that i.e. MAC API have that. For other reasons why that's
> good idea see "Explore a Peripheral’s Data Wisely" at
> https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/BestPracticesForInteractingWithARemotePeripheralDevice/BestPracticesForInteractingWithARemotePeripheralDevice.html#//apple_ref/doc/uid/TP40013257-CH6-SW6
>
> I think it's more "how to do it right" than "whether to do it".

I realize you probably don't know how we discover the attributes, the
process is like this:

1. Read by Group Type Request: First we discover primary/secondary
range, the number of attempts depend in the MTU so this may actually
return all services in one operation:

> ACL Data RX: Handle 3585 flags 0x02 dlen 11
ATT: Read By Group Type Request (0x10) len 6
Handle range: 0x0001-0xffff
Attribute group type: Primary Service (0x2800)
< ACL Data TX: Handle 3585 flags 0x00 dlen 24
ATT: Read By Group Type Response (0x11) len 19
Attribute data length: 6
Attribute group list: 3 entries
Handle range: 0x0001-0x0005
UUID: Generic Access Profile (0x1800)
Handle range: 0x0006-0x000d
UUID: Heart Rate (0x180d)
Handle range: 0x000e-0x0011
UUID: Battery Service (0x180f)

2. Read By Type Request: Then we discover the characteristics within
each service, again this request can pack more than one entry:

> ACL Data RX: Handle 3585 flags 0x02 dlen 11
ATT: Read By Type Request (0x08) len 6
Handle range: 0x0001-0x0005
Attribute type: Characteristic (0x2803)
< ACL Data TX: Handle 3585 flags 0x00 dlen 13
ATT: Read By Type Response (0x09) len 8
Attribute data length: 7
Attribute data list: 1 entry
Handle: 0x0004
Value: 020500012a

3. Find Information Request: Last we discover the descriptors in the
characteristic range:

> ACL Data RX: Handle 3585 flags 0x02 dlen 9
ATT: Find Information Request (0x04) len 4
Handle range: 0x0009-0x0009
< ACL Data TX: Handle 3585 flags 0x00 dlen 10
ATT: Find Information Response (0x05) len 5
Format: UUID-16 (0x01)
Handle: 0x0009
UUID: Client Characteristic Configuration (0x2902)

Note that 2 and 3 are valid with Find by Type request, which btw is
documented in the core spec (see 4.4 PRIMARY SERVICE DISCOVERY), so if
we talk about efficiency we should compare Find by Type vs Read by
Group Type, the former can only group services of the same type, so if
you have a n number of UUID you will have to do n number of requests
which in practice means that once you have n > 1 Read by Group Type
will probably start to be more efficient. Given the fact that we want
to discover GAP, GATT and DIS normally, or at least GAP and GATT
Services, I think Read by Group Type will usually outperform Find by
Type in terms of speed in with that setup, with the only exception
being if the database is really huge or/and the MTU is small.

We could in theory optimize the process after 1 to only discovery
characteristics for the services which have a driver or a external
client registered, but this would mean splinting the ready logic
bt_gatt_client has so we are able to detect what drivers would be
probed and then continue from there, or provide the UUID list upfront
to bt_gatt_client do the filtering. Personally I don't think it is
worth changing this logic because the database are normally quite
small with just a few services, but if you find real case where this
is not true then we may have discuss this again.

--
Luiz Augusto von Dentz

2015-05-28 22:25:54

by Jakub Pawlowski

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi Luiz,

On Thu, May 28, 2015 at 2:32 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Jakub,
>
> On Thu, May 28, 2015 at 11:44 PM, Jakub Pawlowski <[email protected]> wrote:
>> Currently, calling org.bluez.Device1.Connect() on a new, never
>> connected before device, would cause automatic discovery of all
>> services.
>>
>> This is bad in some cases, because discovering all available services
>> might take a long time. Additionally some devices, i.e. iPhone have
>> built-in 0.5s delay between each "Find Information Response" packet,
>> which make discovery even longer.
>>
>>
>> I would like to propose following change:
>>
>> 1. Calling org.bluez.Device1.Connect() would work just like now,
>> except no "Find Information Request" would be issued (that means no
>> call to "device_browse_gatt").
>>
>> 2. Add two new methods: org.bluez.Device1.DiscoverServices(), and
>> org.bluez.Device1.DiscoverServiceByUUID(uuid). First one would just
>> call device_browse_gatt and make "Find Information Request" , the
>> second one would issue "Find By Type Value Request" to find just one
>> service.
>
> You are just changing one problem to another, or actually many other problems:
>

Example use case to make things clearer:
there's device advertising it contains service with UUID "abcd", and
my app wants to use only this one. It connects to device, and asks
only for this service. If it's not there I disconnect. If it's there,
it read/writes and disconnect.
Everything took ~1.5 second.

If I can't do "Find By Type Value Request" I'm stuck discovering
services for 6, or 10, or more seconds, depending of number of
services on device.


> 1. Instead of just 1 method there is at least 2, but Connect depends
> on what has been discovered first so you are adding a D-Bus round
> trips.

Yes, I'm probably adding one round trip. It might hovewer be avoided.
To avoid additional roundtrip there should be two methods:
Connect() that just works right now, and ConnectToUUID(uuid) that
would connect, and then do "Find By Type Value Request". I think that
this solution wouldn't be that clean, and would be problematic to
discover rest of services.

One round trip per connection isn't that bad issue, is it ?

> 2. DiscoverServiceByUUID can only discover primary services if I
> remember correct, what about included? And if an application, or many,

It can discovery Primary or Secondary services, but it is used for
Primary only right now as far as I know.

> decide to discovery one by one every single UUID defined in the spec,
> how many more request that would be compared to Read by Group Type
> Request?

If application want to use only one service, and it cares about speed
it should use this new method (I think that's the reason Bluetooth
have "Find By Type Value Request").
If application doesn't know what it wants, it should find all services for sure.
If application want more than one service, or included service, it
should probably discover all at once.
If application wants to discover included service, it can do Read by
Group Type with handle range that's included in "included service"
attribute (would need new API method if we want that, or use discover
all service).


> 3. We can't take advance of Service Changed Characteristic if
> DiscoverServiceByUUID, so at that point one would have to start
> polling if the remote server has capability to change its database.
>
> I guess the problem number 3 is actually what you did not consider,
> the whole point is that we discover only once and then let the server
> tell us what has changed, so reconnection should happens very fast
> because we already have the device database in cache.

Right, I haven't conseidered number 3, but:
- app might decide to later discover rest of services, or
- just service I discovered might be still cached, or
- service I need might be re-discovered because it's only one and
it's fast in comparison to discovering all
- maybe if device get paired, full service discovery will be required
? otherwise it'll change MAC in 15 minutes and be forgotten anyway.

I'll figure out how to deal nicely with cache.

I think that discovering one service should be a option in modern BLE
API (and I know few projects that need it).
Please note that i.e. MAC API have that. For other reasons why that's
good idea see "Explore a Peripheral’s Data Wisely" at
https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/BestPracticesForInteractingWithARemotePeripheralDevice/BestPracticesForInteractingWithARemotePeripheralDevice.html#//apple_ref/doc/uid/TP40013257-CH6-SW6

I think it's more "how to do it right" than "whether to do it".

Thanks,
Jakub.

>
>
> --
> Luiz Augusto von Dentz

2015-05-28 21:32:07

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi Jakub,

On Thu, May 28, 2015 at 11:44 PM, Jakub Pawlowski <[email protected]> wrote:
> Currently, calling org.bluez.Device1.Connect() on a new, never
> connected before device, would cause automatic discovery of all
> services.
>
> This is bad in some cases, because discovering all available services
> might take a long time. Additionally some devices, i.e. iPhone have
> built-in 0.5s delay between each "Find Information Response" packet,
> which make discovery even longer.
>
>
> I would like to propose following change:
>
> 1. Calling org.bluez.Device1.Connect() would work just like now,
> except no "Find Information Request" would be issued (that means no
> call to "device_browse_gatt").
>
> 2. Add two new methods: org.bluez.Device1.DiscoverServices(), and
> org.bluez.Device1.DiscoverServiceByUUID(uuid). First one would just
> call device_browse_gatt and make "Find Information Request" , the
> second one would issue "Find By Type Value Request" to find just one
> service.

You are just changing one problem to another, or actually many other problems:

1. Instead of just 1 method there is at least 2, but Connect depends
on what has been discovered first so you are adding a D-Bus round
trips.
2. DiscoverServiceByUUID can only discover primary services if I
remember correct, what about included? And if an application, or many,
decide to discovery one by one every single UUID defined in the spec,
how many more request that would be compared to Read by Group Type
Request?
3. We can't take advance of Service Changed Characteristic if
DiscoverServiceByUUID, so at that point one would have to start
polling if the remote server has capability to change its database.

I guess the problem number 3 is actually what you did not consider,
the whole point is that we discover only once and then let the server
tell us what has changed, so reconnection should happens very fast
because we already have the device database in cache.


--
Luiz Augusto von Dentz

2015-06-09 10:48:07

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi Arman, Jakub,

On Tue, Jun 2, 2015 at 5:51 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Arman,
>
> On Tue, Jun 2, 2015 at 12:42 AM, Arman Uguray <[email protected]> wrote:
>>> Service changed, the lower is your requirement to reconnect the more
>>> it will be required, but you got to pair to make it persistent across
>>> reconnections but the first time you connect is always going to be
>>> time consuming since you got to discover so it does not matter much if
>>> the first time takes 9.7s to discover all services since the next time
>>> it would not spend any time doing it again, that is the only reason
>>> HoG can reconnect very fast.
>>>
>>> --
>>> Luiz Augusto von Dentz
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>>> the body of a message to [email protected]
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>> I'm late to the discussion, but wasn't this kind of functionality the
>> whole point behind adding the org.bluez.GattProfile1 interface defined
>> in doc/gatt-api.txt? Can't we do this through that?
>
> Yes, that was my suggestion to give a list of UUID of interested so
> bt_gatt_client instance can skip discovery of characteristics and
> descriptor not in the list, but it is not so simple when this is
> dynamic as it is applications may come and go so we would have to
> cache not only the database but also what was discovered which
> complicate things.
>
> Btw, the spec says the following about the service changed:
>
> C1: Mandatory if service definitions on the server can be added,
> changed or removed;
> otherwise optional
>
> So the following code should be optimized to return without clearing
> the database if service changed is not supported.
>
> if (device->le_state.bonded)
> return;
>
> gatt_db_clear(device->db);
> device->gatt_cache_used = false;
>
> Futhermore Im not sure we need to clear the database like that, we
> could check if the service range match that probably means the service
> has not changed since the last connection as is very unlikely that
> service characteristics and descriptors would change even if the
> service was removed and added again in the exact same place.

Any chance that you guys give some feedback to the patch-set Ive sent
yesterday? Im assuming it does take care of connecting to a single
UUID since in most cases only Read by Group Type is necessary.


--
Luiz Augusto von Dentz

2015-06-02 14:51:01

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi Arman,

On Tue, Jun 2, 2015 at 12:42 AM, Arman Uguray <[email protected]> wrote:
>> Service changed, the lower is your requirement to reconnect the more
>> it will be required, but you got to pair to make it persistent across
>> reconnections but the first time you connect is always going to be
>> time consuming since you got to discover so it does not matter much if
>> the first time takes 9.7s to discover all services since the next time
>> it would not spend any time doing it again, that is the only reason
>> HoG can reconnect very fast.
>>
>> --
>> Luiz Augusto von Dentz
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> I'm late to the discussion, but wasn't this kind of functionality the
> whole point behind adding the org.bluez.GattProfile1 interface defined
> in doc/gatt-api.txt? Can't we do this through that?

Yes, that was my suggestion to give a list of UUID of interested so
bt_gatt_client instance can skip discovery of characteristics and
descriptor not in the list, but it is not so simple when this is
dynamic as it is applications may come and go so we would have to
cache not only the database but also what was discovered which
complicate things.

Btw, the spec says the following about the service changed:

C1: Mandatory if service definitions on the server can be added,
changed or removed;
otherwise optional

So the following code should be optimized to return without clearing
the database if service changed is not supported.

if (device->le_state.bonded)
return;

gatt_db_clear(device->db);
device->gatt_cache_used = false;

Futhermore Im not sure we need to clear the database like that, we
could check if the service range match that probably means the service
has not changed since the last connection as is very unlikely that
service characteristics and descriptors would change even if the
service was removed and added again in the exact same place.

--
Luiz Augusto von Dentz

2015-06-01 21:42:31

by Arman Uguray

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi,

> On Mon, Jun 1, 2015 at 11:22 AM, Luiz Augusto von Dentz <[email protected]> wrote:
> Hi Jakub,
>
> On Mon, Jun 1, 2015 at 8:25 PM, Jakub Pawlowski <[email protected]> wrote:
>> Hi Johan, Luiz
>>
>> On Sat, May 30, 2015 at 7:55 PM, Johan Hedberg <[email protected]> wrote:
>>> Hi Jakub,
>>>
>>> On Thu, May 28, 2015, Jakub Pawlowski wrote:
>>>> > 1. Instead of just 1 method there is at least 2, but Connect depends
>>>> > on what has been discovered first so you are adding a D-Bus round
>>>> > trips.
>>>>
>>>> Yes, I'm probably adding one round trip. It might hovewer be avoided.
>>>> To avoid additional roundtrip there should be two methods:
>>>> Connect() that just works right now, and ConnectToUUID(uuid) that
>>>> would connect, and then do "Find By Type Value Request". I think that
>>>> this solution wouldn't be that clean, and would be problematic to
>>>> discover rest of services.
>>>
>>> We already have this "ConnectToUUID" method in the form of
>>> Device1.ConnectProfile, don't we? It was originally designed for BR/EDR,
>>> but seems to have at least some code for LE as well. If it's not working
>>> as desired for LE it's probably something worth fixing.
>>>
>>
>> "ConnectToUUID" method is what I was looking for. It doesn't work for
>> LE devices as far as I tested, so I'll fix it. It creates connection,
>> but then stops (no MTU exchange, or service discovery).
>>
>> Here's merged (to show time order) output of btmon and bluetoothd
>> together when calling ConnectToUUID right now:
>> http://pastebin.com/s76bT3jx
>>
>> When I looked into source, it looks like it still want to do full
>> service discvery, not just one service. Can I modify it to do ""Find
>> By Type Value Request" for LE devices ?
>>
>>
>> I modified bluez a little bit to test timing, and show why I want to
>> have "Find By Type Value Request":
>>
>> Right after connecting and negotiating MTU, instead of doing Primary
>> and Secondary Service Discovery, I made BlueZ do "Find By Type Value
>> Request" for service with UUID "babe", and then auto discover it's
>> included services, characteristics, descriptors.
>>
>> First I tested against Android phone with three Primary Services
>> (GATT, GAP, and one with UUID "babe"), and total of 4 characteristic,
>> one in "babe" service. MTU=517.
>> Doing regular discovery took 2.38s from "Read By Group Type Request"
>> to last request, http://pastebin.com/pgrfAJM9
>> Doing just one service discovery took 0,84s from "Find By Type Value
>> Request" to last request, http://pastebin.com/V1WZERfw
>
> They are not doing the same thing, you are not looking for GAP, GATT
> and DIS services for example, so the device will not have any of these
> discovered, so no long names, no appearance, no service changed and no
> device information. Also Im not sure you got my point about the
> ConnectUUID, let say it is just discover the UUID requested, you will
> have to do it every single time you connnect because it cannot be
> cached without service changed, also this is per UUID, if the
> peripheral just have one being advertised that might work in favor of
> this but there could be many as well then doing ConnectUUID separately
> don't make any sense.
>
>> Then I tested against iPhone with 5 services and total of 12
>> characteristics (one with UUID "babe", having one characteristic).
>> MTU=158. Sample iPhone app I used for tests started automatically
>> discovering services on the laptop, which also impacted discovery
>> time.
>> Doing regular discovery took 9.7s from "Read By Group Type Request" to
>> last request, http://pastebin.com/aycMWZ4w
>> Doing just one service discovery took 2s from "Find By Type Value
>> Request" to last request, http://pastebin.com/C9Jp28WM
>>
>> My use case is to quickly connect, and use one service, then
>> disconnect. 2.3s vs 0.8s is big gain for me, not talking about 9.7 vs
>> 2s. Some controllers designed for coin-battery scenarios have MTU
>> fixed on 23, which should also make all service discovery slow, and
>> yield big difference.
>
> Service changed, the lower is your requirement to reconnect the more
> it will be required, but you got to pair to make it persistent across
> reconnections but the first time you connect is always going to be
> time consuming since you got to discover so it does not matter much if
> the first time takes 9.7s to discover all services since the next time
> it would not spend any time doing it again, that is the only reason
> HoG can reconnect very fast.
>
> --
> Luiz Augusto von Dentz
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

I'm late to the discussion, but wasn't this kind of functionality the
whole point behind adding the org.bluez.GattProfile1 interface defined
in doc/gatt-api.txt? Can't we do this through that?

-Arman

2015-06-01 18:22:32

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi Jakub,

On Mon, Jun 1, 2015 at 8:25 PM, Jakub Pawlowski <[email protected]> wrote:
> Hi Johan, Luiz
>
> On Sat, May 30, 2015 at 7:55 PM, Johan Hedberg <[email protected]> wrote:
>> Hi Jakub,
>>
>> On Thu, May 28, 2015, Jakub Pawlowski wrote:
>>> > 1. Instead of just 1 method there is at least 2, but Connect depends
>>> > on what has been discovered first so you are adding a D-Bus round
>>> > trips.
>>>
>>> Yes, I'm probably adding one round trip. It might hovewer be avoided.
>>> To avoid additional roundtrip there should be two methods:
>>> Connect() that just works right now, and ConnectToUUID(uuid) that
>>> would connect, and then do "Find By Type Value Request". I think that
>>> this solution wouldn't be that clean, and would be problematic to
>>> discover rest of services.
>>
>> We already have this "ConnectToUUID" method in the form of
>> Device1.ConnectProfile, don't we? It was originally designed for BR/EDR,
>> but seems to have at least some code for LE as well. If it's not working
>> as desired for LE it's probably something worth fixing.
>>
>
> "ConnectToUUID" method is what I was looking for. It doesn't work for
> LE devices as far as I tested, so I'll fix it. It creates connection,
> but then stops (no MTU exchange, or service discovery).
>
> Here's merged (to show time order) output of btmon and bluetoothd
> together when calling ConnectToUUID right now:
> http://pastebin.com/s76bT3jx
>
> When I looked into source, it looks like it still want to do full
> service discvery, not just one service. Can I modify it to do ""Find
> By Type Value Request" for LE devices ?
>
>
> I modified bluez a little bit to test timing, and show why I want to
> have "Find By Type Value Request":
>
> Right after connecting and negotiating MTU, instead of doing Primary
> and Secondary Service Discovery, I made BlueZ do "Find By Type Value
> Request" for service with UUID "babe", and then auto discover it's
> included services, characteristics, descriptors.
>
> First I tested against Android phone with three Primary Services
> (GATT, GAP, and one with UUID "babe"), and total of 4 characteristic,
> one in "babe" service. MTU=517.
> Doing regular discovery took 2.38s from "Read By Group Type Request"
> to last request, http://pastebin.com/pgrfAJM9
> Doing just one service discovery took 0,84s from "Find By Type Value
> Request" to last request, http://pastebin.com/V1WZERfw

They are not doing the same thing, you are not looking for GAP, GATT
and DIS services for example, so the device will not have any of these
discovered, so no long names, no appearance, no service changed and no
device information. Also Im not sure you got my point about the
ConnectUUID, let say it is just discover the UUID requested, you will
have to do it every single time you connnect because it cannot be
cached without service changed, also this is per UUID, if the
peripheral just have one being advertised that might work in favor of
this but there could be many as well then doing ConnectUUID separately
don't make any sense.

> Then I tested against iPhone with 5 services and total of 12
> characteristics (one with UUID "babe", having one characteristic).
> MTU=158. Sample iPhone app I used for tests started automatically
> discovering services on the laptop, which also impacted discovery
> time.
> Doing regular discovery took 9.7s from "Read By Group Type Request" to
> last request, http://pastebin.com/aycMWZ4w
> Doing just one service discovery took 2s from "Find By Type Value
> Request" to last request, http://pastebin.com/C9Jp28WM
>
> My use case is to quickly connect, and use one service, then
> disconnect. 2.3s vs 0.8s is big gain for me, not talking about 9.7 vs
> 2s. Some controllers designed for coin-battery scenarios have MTU
> fixed on 23, which should also make all service discovery slow, and
> yield big difference.

Service changed, the lower is your requirement to reconnect the more
it will be required, but you got to pair to make it persistent across
reconnections but the first time you connect is always going to be
time consuming since you got to discover so it does not matter much if
the first time takes 9.7s to discover all services since the next time
it would not spend any time doing it again, that is the only reason
HoG can reconnect very fast.

--
Luiz Augusto von Dentz

2015-06-01 17:25:09

by Jakub Pawlowski

[permalink] [raw]
Subject: Re: [RFC] Add new method to DBus API: DiscoverServiceByUUID

Hi Johan, Luiz

On Sat, May 30, 2015 at 7:55 PM, Johan Hedberg <[email protected]> wrote:
> Hi Jakub,
>
> On Thu, May 28, 2015, Jakub Pawlowski wrote:
>> > 1. Instead of just 1 method there is at least 2, but Connect depends
>> > on what has been discovered first so you are adding a D-Bus round
>> > trips.
>>
>> Yes, I'm probably adding one round trip. It might hovewer be avoided.
>> To avoid additional roundtrip there should be two methods:
>> Connect() that just works right now, and ConnectToUUID(uuid) that
>> would connect, and then do "Find By Type Value Request". I think that
>> this solution wouldn't be that clean, and would be problematic to
>> discover rest of services.
>
> We already have this "ConnectToUUID" method in the form of
> Device1.ConnectProfile, don't we? It was originally designed for BR/EDR,
> but seems to have at least some code for LE as well. If it's not working
> as desired for LE it's probably something worth fixing.
>

"ConnectToUUID" method is what I was looking for. It doesn't work for
LE devices as far as I tested, so I'll fix it. It creates connection,
but then stops (no MTU exchange, or service discovery).

Here's merged (to show time order) output of btmon and bluetoothd
together when calling ConnectToUUID right now:
http://pastebin.com/s76bT3jx

When I looked into source, it looks like it still want to do full
service discvery, not just one service. Can I modify it to do ""Find
By Type Value Request" for LE devices ?


I modified bluez a little bit to test timing, and show why I want to
have "Find By Type Value Request":

Right after connecting and negotiating MTU, instead of doing Primary
and Secondary Service Discovery, I made BlueZ do "Find By Type Value
Request" for service with UUID "babe", and then auto discover it's
included services, characteristics, descriptors.

First I tested against Android phone with three Primary Services
(GATT, GAP, and one with UUID "babe"), and total of 4 characteristic,
one in "babe" service. MTU=517.
Doing regular discovery took 2.38s from "Read By Group Type Request"
to last request, http://pastebin.com/pgrfAJM9
Doing just one service discovery took 0,84s from "Find By Type Value
Request" to last request, http://pastebin.com/V1WZERfw

Then I tested against iPhone with 5 services and total of 12
characteristics (one with UUID "babe", having one characteristic).
MTU=158. Sample iPhone app I used for tests started automatically
discovering services on the laptop, which also impacted discovery
time.
Doing regular discovery took 9.7s from "Read By Group Type Request" to
last request, http://pastebin.com/aycMWZ4w
Doing just one service discovery took 2s from "Find By Type Value
Request" to last request, http://pastebin.com/C9Jp28WM

My use case is to quickly connect, and use one service, then
disconnect. 2.3s vs 0.8s is big gain for me, not talking about 9.7 vs
2s. Some controllers designed for coin-battery scenarios have MTU
fixed on 23, which should also make all service discovery slow, and
yield big difference.



> Johan