4
votes

I am implementing a application on Android using BLE Api (SDK 18), and I have a issue that the transfer data process is delay very slow. This is my log.

03-12 16:20:05.121: D/BluetoothGatt(13578): writeCharacteristic() - uuid: ...

03-12 16:20:06.272: D/BluetoothGatt(13578): onCharacteristicWrite() - Device=... UUID=... Status=0

03-12 16:20:06.972: D/BluetoothGatt(13578): writeCharacteristic() - uuid: ...

03-12 16:20:08.254: D/BluetoothGatt(13578): onCharacteristicWrite() - Device=... UUID=... Status=0

03-12 16:20:10.055: D/BluetoothGatt(13578): writeCharacteristic() - uuid: ...

03-12 16:20:11.257: D/BluetoothGatt(13578): onCharacteristicWrite() - Device=... UUID=... Status=0

03-12 16:20:12.478: D/BluetoothGatt(13578): writeCharacteristic() - uuid: ...

03-12 16:20:14.250: D/BluetoothGatt(13578): onCharacteristicWrite() - Device=... UUID=... Status=0

03-12 16:20:14.960: D/BluetoothGatt(13578): writeCharacteristic() - uuid: ...

03-12 16:20:16.242: D/BluetoothGatt(13578): onCharacteristicWrite() - Device=... UUID=... Status=0

03-12 16:20:16.402: D/BluetoothGatt(13578): writeCharacteristic() - uuid: ...

03-12 16:20:20.225: D/BluetoothGatt(13578): onCharacteristicWrite() - Device=... UUID=... Status=0

03-12 16:20:20.526: D/BluetoothGatt(13578): writeCharacteristic() - uuid: ...

03-12 16:20:24.219: D/BluetoothGatt(13578): onCharacteristicWrite() - Device=... UUID=... Status=0

03-12 16:20:25.360: D/BluetoothGatt(13578): writeCharacteristic() - uuid: ...

03-12 16:20:27.222: D/BluetoothGatt(13578): onCharacteristicWrite() - Device=... UUID=... Status=0

For more information, I found that every Transfer Progress only completes when it has the onCharacteristicWrite callback, this means that all sending command before receive onCharacteristicWrite callback will be ignored.

Is this the flow of Android we have to following or there is any way to setup it skip the callback step to speed up the progress.

My code is:

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
......
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    mSending = false;
}
};

private void writeCharacteristic() {
    .....

    mGattCharacSetIntensity.setValue(data);
    mGattCharacSetIntensity.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
    mBluetoothGatt.writeCharacteristic(mGattCharacSetIntensity);
    return;
}

EDIT: I have a comparison with iPhone (a BLE transfer data app from AppStore), the BLE transfer data is very quick (less than 0.5 sec), so impressive. How can we work around to SPEED UP the Android BLE Transfer progress?.

EDIT: If I set WriteType of BluetoothGattCharacteristic to WRITE_TYPE_NO_RESPONSE, and when I send many command sequentially, the Android stores them on a queue and send to remote device one by one after receive writeCharacteristic CallBack, this leads to a issue, when you stop your sending lood, the Android Sending Progress still continue with the delay (Sometime more than 3 sec).

4
Is this the output of emulated bluetooth or real values from your device?Marco de Abreu
These are from real Nexus 7, version 2013, Android OS 4.3LongVo
Actually Android BLE stack works synchronously. So its works stack wise operations.user370305
Thank user370305, I agree with you, but there is not any document form Google Android to confirm about that. so I do not have any evidence. So sad. Can we decrease the delay interval?LongVo
Your writes should definitely not be taking so long. On a KitKat device my performance tests showed that I was able to write at more than 7KB/s and crossing 10 with responses turned off. Every write was done only after a response was received from the bluetooth device.Zomb

4 Answers

5
votes

Performance of a BLE link is highly dependent on the connection interval used, and if your connection interval is high, the performance you see may not be that unreasonable. By the Core Specification, the connection interval can be between 7.5 ms and 4 s, so there's quite some flexibility.

If it's possible for you, I'd recommend you to try changing the Peripheral you're talking to to use a shorter connection interval, which should improve performance. You may have use in taking a look at this page, explaining BLE throughput, and this page, explaining connection parameters.

4
votes

We had the same problem. It occurs after several writes and goes away when you reconnect the Gatt. What we do is measure the delay between writeCharacteristic() and onCharacteristicWrite(). If it is above a certain threshold (1500ms), we disconnect() and close() the gatt server and reconnect. After that it is usually fine for a while.

When doing this it might become necessary to disable the whole bluetooth adapter and reenable it. Otherwise the first reconnect to the gatt server fails and it takes about 15 seconds until it is reconnected. Sometimes it never reconnects.

When disabling the adapter you might run into the problem that service discovery does not return in onServicesDiscovered(). We have currently no solution for that.

1
votes

You'll have to implement you're own flow control, don't start a write until the OnCharacteristicWrite is sent for the previous write

1
votes

This seems to be a problem for me as well. If you delay the calls in the debugger you can confirm that there is a delay when writing to BLE radios. I will be implementing a queue in my application to handle the latency.

Here is what I do for queueing up commands:

public void sendWriteCommandToConnectedMachine(byte[] commandByte) {
    if(commandByte.length > 20)
        dissectAndSendCommandBytes(commandByte);
    else
        queueCommand(commandByte); //TODO - need to figure out if service is valid or not
}

private void queueCommand(byte[] command) {
    mCommandQueue.add(command);

    if(!mWaitingCommandResponse)
        dequeCommand();
}

Hereis what I do for dequeuing BLE commands

private void dequeCommand() {
    if(mCommandQueue.size() > 0) {
        byte[] command = mCommandQueue.get(0);
        mCommandQueue.remove(0);
        sendWriteCommand(command);
    }
}

here is my characteristic write method

@Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        if(status != BluetoothGatt.GATT_SUCCESS)
            logMachineResponse(characteristic, status);     

        mWaitingCommandResponse = false;
        dequeCommand();
    }