Search code examples
androidbluetooth-lowenergymtu

Android BLE taking some delay after successful connection


I am working on Android app that connect to BLE device and do some process there.

I have total 5 steps:

After scanning and connectGatt()

In onConnectionStateChange(),

  1. requestMtu()

    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        switch (newState) {
            case BluetoothProfile.STATE_CONNECTED:
                gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
                Log.e("Connect", (System.currentTimeMillis() - startTime) + " ms");
                deviceConnected = true;
                gatt.requestMtu(185);
                break;
    

In onMtuChanged(),

  1. discoverServices()

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
        super.onMtuChanged(gatt, mtu, status);
        Log.e("Mtu Change", (System.currentTimeMillis() - startTime) + " ms");
        if (status == BluetoothGatt.GATT_SUCCESS) {
            gatt.discoverServices();
        }
    }
    

In onServicesDiscovered(),

  1. writeDescriptor()

        @Override
    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);
        Log.e("Service Discover", (System.currentTimeMillis() - startTime) + " ms");
        try {
            BluetoothGattService service = gatt.getService(UUID.fromString("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
    
            BluetoothGattCharacteristic notifyChar = gatt.getService(UUID.fromString("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
    
            if (notifyChar != null) {
                gatt.setCharacteristicNotification(notifyChar, true);
    
                BluetoothGattDescriptor descriptor = notifyChar.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
                descriptor.setValue(new byte[]{0x01, 0x00});
                gatt.writeDescriptor(descriptor);
                gatt.readCharacteristic(notifyChar);
            }
    
        } catch (Exception e) {
            showToast("Service Disc. EXCEPTION");
            e.printStackTrace();
        }
    }
    

In onDescriptorWrite(),

  1. writeCharacteristic()

        @Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        Log.e("Descriptor Write", (System.currentTimeMillis() - startTime) + " ms");
        if (status == 0) {
            BluetoothGattCharacteristic characteristic = gatt.getService(UUID.fromString("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
    
            characteristic.setValue(myVal);
            gatt.writeCharacteristic(characteristic);
            Log.e(TAG, "TagID Sent");
        } 
    }
    

In onCharacteristicWrite(),

  1. A small beep,

        @Override
    public void onCharacteristicWrite(BluetoothGatt gatt,
                                      BluetoothGattCharacteristic characteristic,
                                      final int status) {
        Log.e("Characteristic Write", (System.currentTimeMillis() - startTime) + " ms");
        if(status == 0){
            beep();
        }
    }
    

I have noted down time taken at each step, below are the readings(Average of 5 occurance),

  1. Connection success(i.e. onConnectionStateChange()): 500 to 525 ms
  2. MtuChange(i.e. onMtuChanged()): 1400 to 1450 ms
  3. Service Discovery(i.e. onServicesDiscovered()): 10 to 25 ms
  4. Descriptor Write(i.e. onDescriptorWrite()): 10 to 25 ms
  5. Characteritic write(i.e. onCharacteristicWrite): 10 to 25 ms

So, first I thought that setting mtu size is taking too much time, then I removed step 2 - requestMtu()) and directly called discoverService() method, surprisingly, service discovery(step 3)) took around 1400 ms time.

I did another experiment, called requestMtu method in step 2) again, now the second call took only 10 to 25 ms.

Finally, I got to understand that any first step after successful connection takes longer time.

I don't know the reason, can you please help me to understand and also, I want to reduce this time to make whole process faster.

Is there any possibility to do so?

Thanks in advance.


Solution

  • What actually takes time is the service discovery which is always done when the device has connected (even if you don't call discoverServices). Any command is delayed until that is complete. To speed it up, you should try to shrink the peripheral's GATT db. You could also try to send an MTU request from the peripheral directly after connection to make the service discovery use less packets.

    By the way, you can't read a characteristic immediately after you sent a write descriptor request. You always need to wait for a GATT operation to complete until you can send a new one.