Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Services with the same UUIDs #93

Closed
Shakenbeer opened this issue Apr 22, 2021 · 14 comments · Fixed by #238
Closed

Services with the same UUIDs #93

Shakenbeer opened this issue Apr 22, 2021 · 14 comments · Fixed by #238
Milestone

Comments

@Shakenbeer
Copy link

Thanks a lot for you work. The library is awesome.

I have BLE device with this strange firmware. There are two services with the same UUIDs and with identical sets of characteristics. The only difference is in one of descriptors. So, there are two services S1 and S2, they both have characteristic C, and value of a descriptor D differs. All uuids are the same.

S1.uuid == S2.uuid
S1.C.uuid == S2.C.uuid
S1.C.D.uuid == S2.C.D.uuid
S1.C.D.value != S1.C.D.value.

This way I should distinct those 2 services.

So after services are discovered I do a loop over them and for every service S1 and S2 I read that descriptor.
Unfortunately I always get the same value, as in both cases I read only descriptor of the service S1.
readDescriptor function searches for descriptor through all services and always return the first one found.
Is there a way to read identical descriptors (and characteristics) of two different services?

@twyatt
Copy link
Member

twyatt commented Apr 22, 2021

Android provides instanceId for characteristics. I think that should allow multiple characteristics with the same UUID to be identified as distinct.

I'll have to investigate if Core Bluetooth (e.g. iOS) and JavaScript offer a similar property (to keep behavior parity between the platforms). — this might be a good approach for Core Bluetooth.

@twyatt twyatt added this to the 0.6.0 milestone Apr 22, 2021
@twyatt
Copy link
Member

twyatt commented Apr 22, 2021

@Shakenbeer it looks like BluetoothGattService and BluetoothGattCharacteristic both have an instanceId, which would allow some form of API in Kable to allow you to interact with distinct items with the same UUID, but I don't see a similar property for BluetoothGattDescriptor.

Just to confirm: You don't have multiple descriptors (with the same UUID) on the same characteristic, do you?

@Shakenbeer
Copy link
Author

@twyatt There is mInstance in BluetoothGattDescriptor, but the method getInstanceId is hidden:

     * @hide
     */
    public int getInstanceId() {
        return mInstance;
    }

I did a quick fix for myself. Now I can read/write/observe characteristics and read/write descriptors for services with the same UUID. Peripheral.kt:

public suspend fun read(
        descriptor: Descriptor,
        serviceInstance: Int = 0
    ): ByteArray

and that serviceInstance goes down to Service.kt

internal fun <T : Service> List<T>.first(
    serviceUuid: Uuid,
    serviceInstance: Int = 0
): T = firstOrNull { it.serviceUuid == serviceUuid && (serviceInstance == 0 || it.instanceId == serviceInstance) }
    ?: throw NoSuchElementException("Service $serviceUuid not found")

@Shakenbeer
Copy link
Author

@twyatt Answering your question - no, I do not. I think, it's only possible for services. But I'm not sure, need to read some specs.

@twyatt
Copy link
Member

twyatt commented Apr 23, 2021

There is mInstance in BluetoothGattDescriptor, but the method getInstanceId is hidden

Aw, thanks for the tip.

I did a quick fix for myself. Now I can read/write/observe characteristics and read/write descriptors for services with the same UUID.

Do you know if Android always has the same instance ID for the characteristics (with the same UUID)? In other words, can you rely on the instanceId being consistent across connects? I'm wondering how it would do that, unless the BLE spec has some sort of way of communicating that to the client (Android in this case). — otherwise I'd think the ordering of your characteristics (and which one got which instance ID) would be non-deterministic?

Perhaps it is just based on the ordering that they are sent over during discover services? In which case it would be in the control of the Peripheral/server as to what the ordering would be. 🤔

@Shakenbeer
Copy link
Author

Shakenbeer commented Apr 23, 2021

Do you know if Android always has the same instance ID for the characteristics (with the same UUID)? In other words, can you rely on the instanceId being consistent across connects?

I checked instanceIds only for services so far. And those ids are the same after every connection. But I believe you would want some written confirmation in specs. So far I simply write those two services instanceIds to properties after services are discovered and use them.

Also, I'm not sure at all, how those ids are assigned. For example, I have 9 services and ids are 1, 9, 16, 35, 44, 75, 106, 137, 150.
And characteristics of interest S1.C and S2.C has the same instanceId. Makes sense, as their services differs.

@twyatt
Copy link
Member

twyatt commented Apr 23, 2021

I have 9 services and ids are 1, 9, 16, 35, 44, 75, 106, 137, 150.

Just when I thought BLE couldn't get any stranger. 😄

Thanks for the info!

I'll do some research when I have some time, but good to hear that at least you're observing that they are consistent across connects.

@twyatt
Copy link
Member

twyatt commented Jun 9, 2021

For the Core Bluetooth side, found this helpful recommendation:

I would say, trying to access or identify characteristics by their GATT handles is akin to accessing a member of an array by hardcoding its location index.

Although it may work for now, or maybe later, but eventually this would end in tears when something somewhere in the system, be it the peripheral firmware, be it the CoreBluetooth implementation, etc. is changed and the assumption on the location and order of your data breaks.

The proper way to identify two characteristics with identical UUIDs (if they must be like that) is to add a Descriptor to the Characteristics that will identify each of them uniquely. Descriptors are used to provide further information about a Characteristic's value.

The CBDescriptor Class Reference explains how to use and access them: https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBDescriptor_Class/index.html#//apple_ref/doc/uid/TP40011294

Differentiate between two CBCharacteristics with identical UUIDs?

It seems likely that in situations where multiple characteristics share a UUID, that Kable libraries consumers will need to iterate the service property to inspect which characteristic is which (i.e. differentiating based on associated descriptors). It is expected then that a reference to a characteristics will be held (DiscoveredCharacteristic) and will be used with I/O functions (e.g. write or read). It is likely DiscoveredCharacteristic will need to be updated to act more like a PlatformCharacteristic (with a reference to the underlying OS level characteristic object).

@twyatt
Copy link
Member

twyatt commented Sep 8, 2021

Apologies, I haven't had the time I had hoped to work on this. I do want to tackle this sooner than later, but it will have to be pushed back to a later version.

@twyatt twyatt removed this from the 0.10.0 milestone Sep 8, 2021
@Shakenbeer
Copy link
Author

There is nothing to apologize for. I was able to adjust your great code to my needs. Unfortunately I have no time to make this properly and create a pull request. I should apologize here.

@twyatt

This comment has been minimized.

@twyatt
Copy link
Member

twyatt commented Jan 6, 2022

@Shakenbeer when you have a chance, can you try the following version and see if it addresses this issue?:

repositories {
    maven("https://oss.sonatype.org/content/repositories/snapshots")
}

dependencies {
    implementation("com.juul.kable:core:0.10.4-issue-93-1-SNAPSHOT")
}

See #238 for more details.

@Shakenbeer
Copy link
Author

@twyatt thanks for your work. At this moment I can't verify it, as we closed the project and I have neither devices nor software infrastructure to simulate the state of interest. I'll try to find time on the weekend and verify it with some simulated devices. Sorry that I can't help more at this moment. If I still worked on that project, I would do it right away.

@twyatt
Copy link
Member

twyatt commented Jan 7, 2022

No worries at all. Other users had similar issues, so I'll be able to get feedback as needed. Thanks for following up!

@twyatt twyatt modified the milestones: 0.12.0, 0.13.0 Jan 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants