Android-BLE-Library icon indicating copy to clipboard operation
Android-BLE-Library copied to clipboard

Is there any way to decrease or bypass Service Discovery?

Open onatakduman opened this issue 2 years ago • 1 comments

Hi Android-Ble-Library developers,

I tried to illustrate the communication diagram between a BLE Device and an Android device when I tried to send the data (with my observations). And I have a question:
First of all, I am trying to make a connection as fast as possible but there is something wrong with this.
Service Discovery is taking too much time sometimes (5-8 seconds), and sometimes less (2-3 seconds)and it still is too much.

  • Is there any way to decrease or bypass Service Discovery?
  • Is there any way to cache Gatt Services?
  • If there are fewer services and characteristics, will it help reduce service discovery? like this:
Service Characteristic Size
Service 1 1

It might be because our services and characteristics sizes are big:

Service Characteristic Size
Service 1 4
Service 2 1
Service 3 1
Service 4 1
Service 5 5
Service 6 1

So I splited the services and charactersitics on BleManager classes and if I need a use some service I create by what I needed in BleManager.
With example 2 classes:

class Manager1(
    context: Context,
    private val scope: CoroutineScope
) : BleManager(context) {

    private var characteristic1: BluetoothGattCharacteristic? = null
    private var characteristic2: BluetoothGattCharacteristic? = null
    private var characteristic3: BluetoothGattCharacteristic? = null
    private var characteristic4: BluetoothGattCharacteristic? = null
    private var characteristic5: BluetoothGattCharacteristic? = null

    private val data: MutableStateFlow<CommunicationData> =
        MutableStateFlow(CommunicationData())
    val dataHolder = ConnectionObserverAdapter<CommunicationData>()

    init {
        connectionObserver = dataHolder
        data.onEach {
            dataHolder.setValue(it)
        }.launchIn(scope)
    }

    override fun getMinLogPriority(): Int = Log.VERBOSE

    override fun initialize() {
        requestMtu(500).enqueue()
        setNotificationCallback(characteristicOnOff).with(dataCallback)
        enableNotifications(characteristicOnOff).enqueue()
    }

    override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean {
        val service1: BluetoothGattService? =
            gatt.getService(SERVICE_1_UUID)

        if (service1!= null) {
            characteristic1 =
                service1.getCharacteristic(CHARACTERISTIC_UUID_1)
            characteristic2 =
                service1.getCharacteristic(CHARACTERISTIC_UUID_2)
            characteristic3 =
                service1.getCharacteristic(CHARACTERISTIC_UUID_3)
            characteristic4 =
                service1.getCharacteristic(CHARACTERISTIC_UUID_4)
        }

        val service6: BluetoothGattService? =
            gatt.getService(SERVICE_6_UUID)
        if (service6!= null) {
            characteristic5 =
                service6.getCharacteristic(CHARACTERISTIC_UUID_6)
        }

        return characteristis1 != null && characteristic2 = null...
    }

    override fun onServicesInvalidated() {
        characteristic1 = null
        characteristic2 = null
        characteristic3 = null
        characteristic4 = null
        characteristic5 = null
    }

    fun sendCommand(command: Boolean) {
        val commandData = if (command) Command.SOME else Command.SOME
        val request: WriteRequest =
            writeCharacteristic(
                characteristic,
                commandData.data,
                BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
            )
        request.with(dataCallback).enqueue()
    }
...
    private val dataCallback = ...

}
class Manager2(
    context: Context,
    private val scope: CoroutineScope
) : BleManager(context) {

    private var characteristic: BluetoothGattCharacteristic? = null

    private val data: MutableStateFlow<CommunicationData> =
        MutableStateFlow(CommunicationData())
    val dataHolder = ConnectionObserverAdapter<CommunicationData>()

    init {
        connectionObserver = dataHolder
        data.onEach {
            dataHolder.setValue(it)
        }.launchIn(scope)
    }

    override fun getMinLogPriority(): Int = Log.VERBOSE

    override fun initialize() {
        setNotificationCallback(characteristicOnOff).with(dataCallback)
        enableNotifications(characteristicOnOff).enqueue()
        sendCommand()
    }

    override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean {
        val service2: BluetoothGattService? =
            gatt.getService(SERVICE_2_UUID)

        if (service2!= null) {
            characteristic =
                service2.getCharacteristic(CHARACTERISTIC_UUID_2)
        }

        return characteristic != null
    }

    override fun onServicesInvalidated() {
        characteristic = null
    }

    fun sendCommand() {
        val data = byteArrayOf(
            1.convertByte(),
            0,
            0,
            0
        )
        val request: WriteRequest =
            writeCharacteristic(
                characteristic,
                data,
                BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
            )
        request.with(dataCallback).enqueue()
    }

    private val dataCallback = ...

}
sequenceDiagram

actor User
participant Android
participant Bluetooth Gatt
participant BLEDevice

User->>Android: userAction()

activate Android

Android-)Bluetooth Gatt: connect()
Android-)Bluetooth Gatt: sendData() when connect()

activate Bluetooth Gatt

Bluetooth Gatt->>BLEDevice: connect()

BLEDevice-->>Bluetooth Gatt: onConnectionUpdated()

loop
Bluetooth Gatt-->>Android: onDeviceConnecting()
BLEDevice-->>Bluetooth Gatt: onConnectionUpdated()
opt optional
BLEDevice-xAndroid:connectionFailed()
end
end

BLEDevice-->>Bluetooth Gatt: onDeviceConnected()
Bluetooth Gatt-->>Android: onDeviceConnected()
Bluetooth Gatt->>BLEDevice: discoverServices()
Note over Bluetooth Gatt, BLEDevice: Takes too much time
BLEDevice-->Bluetooth Gatt: Services Handshake
Bluetooth Gatt -->> Android: onSearchComplete()

deactivate Bluetooth Gatt
Bluetooth Gatt->>BLEDevice:setCharacteristicNotification()
Bluetooth Gatt->>BLEDevice:setCharacteristicNotification()
BLEDevice-->>Bluetooth Gatt: onConnectionUpdated()
Bluetooth Gatt-->>Android:onDeviceReady()

Bluetooth Gatt->>BLEDevice:sendData()
BLEDevice-->>Bluetooth Gatt:dataResponse()
Bluetooth Gatt-->>Android:dataResponse()
Android-->>User:notifiyAboutAction()

activate Android 
Android-->>Android:Wait User action for 5 seconds
Android->>Bluetooth Gatt: sendDisconnect()
deactivate Android

Bluetooth Gatt->>BLEDevice: sendDisconnect()

Bluetooth Gatt-->>Android:onDeviceDisconnecting()
BLEDevice-->Bluetooth Gatt: Disconnect Handshake


activate Bluetooth Gatt
Bluetooth Gatt-->>Android:onDeviceDisconnected()
deactivate Bluetooth Gatt


Example 1

15:27:50.489 selectedDevices       E  C8:F0:9E:A0:82:5A
15:27:50.789 BluetoothGatt         D  onClientConnectionState() - status=133 clientIf=9 device=C8:F0:9E:A0:82:5A
15:27:51.796 BluetoothGatt         D  close()
15:27:51.796 BluetoothGatt         D  unregisterApp() - mClientIf=9
15:27:52.003 BluetoothGatt         D  connect() - device: C8:F0:9E:A0:82:5A, auto: false
15:27:52.003 BluetoothGatt         D  registerApp()
15:27:52.004 BluetoothGatt         D  registerApp() - UUID=d0bc6014-4436-43c5-99a8-0073d2c2618d
15:27:52.010 BluetoothGatt         D  onClientRegistered() - status=0 clientIf=9
15:27:52.026 BLE-CONNECTION        D  onDeviceConnecting()
15:27:52.298 BluetoothGatt         D  onClientConnectionState() - status=133 clientIf=9 device=C8:F0:9E:A0:82:5A
15:27:53.318 BluetoothGatt         D  close()
15:27:53.319 BluetoothGatt         D  unregisterApp() - mClientIf=9
15:27:53.527 BluetoothGatt         D  connect() - device: C8:F0:9E:A0:82:5A, auto: false
15:27:53.527 BluetoothGatt         D  registerApp()
15:27:53.529 BluetoothGatt         D  registerApp() - UUID=102aee31-2fe8-4170-8163-abe0ee0ef581
15:27:53.539 BluetoothGatt         D  onClientRegistered() - status=0 clientIf=9
15:27:53.580 BLE-CONNECTION        D  onDeviceConnecting()
15:27:53.827 BluetoothGatt         D  onClientConnectionState() - status=133 clientIf=9 device=C8:F0:9E:A0:82:5A
15:27:54.855 BluetoothGatt         D  close()
15:27:54.855 BluetoothGatt         D  unregisterApp() - mClientIf=9
15:27:55.065 BluetoothGatt         D  connect() - device: C8:F0:9E:A0:82:5A, auto: false
15:27:55.066 BluetoothGatt         D  registerApp()
15:27:55.067 BluetoothGatt         D  registerApp() - UUID=da8be66d-7352-4c29-be54-2da42fd3310f
15:27:55.074 BluetoothGatt         D  onClientRegistered() - status=0 clientIf=9
15:27:55.078 BLE-CONNECTION        D  onDeviceConnecting()
15:27:55.248 BluetoothGatt         D  onClientConnectionState() - status=0 clientIf=9 device=C8:F0:9E:A0:82:5A
15:27:55.265 BLE-CONNECTION        D  onDeviceConnected()
15:27:55.566 BluetoothGatt         D  discoverServices() - device: C8:F0:9E:A0:82:5A
15:27:55.704 BluetoothGatt         D  onConnectionUpdated() - Device=C8:F0:9E:A0:82:5A interval=6 latency=0 timeout=500 status=0
15:27:56.530 BluetoothGatt         D  onSearchComplete() = Device=C8:F0:9E:A0:82:5A Status=0
15:27:56.540 BluetoothGatt         D  setCharacteristicNotification() - uuid: 47421404-f259-11ec-b939-0242ac120002 enable: true
15:27:56.571 BluetoothGatt         D  setCharacteristicNotification() - uuid: 47421402-f259-11ec-b939-0242ac120002 enable: true
15:27:56.591 BluetoothGatt         D  onConnectionUpdated() - Device=C8:F0:9E:A0:82:5A interval=30 latency=0 timeout=500 status=0
15:27:56.636 BLE-CONNECTION        D  onDeviceReady()
15:27:56.670 onDataSent            E  1B000000
... /*Disconnects after 7 seconds*/
15:28:01.908 BluetoothGatt         D  cancelOpen() - device: C8:F0:9E:A0:82:5A
15:28:01.916 BLE-CONNECTION        D  onDeviceDisconnecting()
15:28:01.928 BluetoothGatt         D  onClientConnectionState() - status=0 clientIf=9 device=C8:F0:9E:A0:82:5A
15:28:01.936 BluetoothGatt         D  refresh() - device: C8:F0:9E:A0:82:5A
15:28:01.942 BluetoothGatt         D  close()
15:28:01.942 BluetoothGatt         D  unregisterApp() - mClientIf=9
15:28:01.954 BLE-CONNECTION        D  onDeviceDisconnected(), reason: 0

Example 2

15:28:04.279 BLE-CONNECTION        D  onDeviceConnecting()
15:28:04.279 BluetoothGatt         D  connect() - device: C8:F0:9E:A0:82:5A, auto: false
15:28:04.279 BluetoothGatt         D  registerApp()
15:28:04.280 BluetoothGatt         D  registerApp() - UUID=ded3b352-53d5-42d7-8c1a-893afb323eff
15:28:04.284 BluetoothGatt         D  onClientRegistered() - status=0 clientIf=9
15:28:04.389 selectedDevices       E  C8:F0:9E:A0:82:5A
15:28:04.625 BluetoothGatt         D  onClientConnectionState() - status=133 clientIf=9 device=C8:F0:9E:A0:82:5A
15:28:05.639 BluetoothGatt         D  close()
15:28:05.640 BluetoothGatt         D  unregisterApp() - mClientIf=9
15:28:05.845 BluetoothGatt         D  connect() - device: C8:F0:9E:A0:82:5A, auto: false
15:28:05.845 BluetoothGatt         D  registerApp()
15:28:05.846 BluetoothGatt         D  registerApp() - UUID=b7ff9713-afbb-43b8-9693-ea25745d6b72
15:28:05.852 BluetoothGatt         D  onClientRegistered() - status=0 clientIf=9
15:28:05.854 BLE-CONNECTION        D  onDeviceConnecting()
15:28:06.103 BluetoothGatt         D  onClientConnectionState() - status=0 clientIf=9 device=C8:F0:9E:A0:82:5A
15:28:06.142 BLE-CONNECTION        D  onDeviceConnected()
15:28:06.435 BluetoothGatt         D  discoverServices() - device: C8:F0:9E:A0:82:5A
15:28:06.616 BluetoothGatt         D  onConnectionUpdated() - Device=C8:F0:9E:A0:82:5A interval=6 latency=0 timeout=500 status=0
15:28:07.550 BluetoothGatt         D  onSearchComplete() = Device=C8:F0:9E:A0:82:5A Status=0
15:28:07.561 BluetoothGatt         D  setCharacteristicNotification() - uuid: 47421404-f259-11ec-b939-0242ac120002 enable: true
15:28:07.592 BluetoothGatt         D  onConnectionUpdated() - Device=C8:F0:9E:A0:82:5A interval=30 latency=0 timeout=500 status=0
15:28:07.666 BluetoothGatt         D  setCharacteristicNotification() - uuid: 47421402-f259-11ec-b939-0242ac120002 enable: true
15:28:07.745 BLE-CONNECTION        D  onDeviceReady()
15:28:07.765 onDataSent            E  27000000
15:28:07.911 onDataReceived        E  0027AC2345
... /*Disconnects after 7 seconds*/
15:28:13.028 BluetoothGatt         D  cancelOpen() - device: C8:F0:9E:A0:82:5A
15:28:13.032 BluetoothGatt         D  onClientConnectionState() - status=19 clientIf=9 device=C8:F0:9E:A0:82:5A
15:28:13.036 BLE-CONNECTION        D  onDeviceDisconnecting()
15:28:13.067 BluetoothGatt         D  refresh() - device: C8:F0:9E:A0:82:5A
15:28:13.070 BluetoothGatt         D  close()
15:28:13.071 BluetoothGatt         D  unregisterApp() - mClientIf=9
15:28:13.081 BLE-CONNECTION        D  onDeviceDisconnected(), reason: 2

onatakduman avatar Jan 18 '23 10:01 onatakduman