Summary of Android BLE development issues

Keywords: Android

The connection of a device is too slow.

1. The most effective method is:

Set the second parameter of the connectGATT() method to false. As shown below.

// The function of the second parameter is as follows: 
// Whether to directly connect to the remote device (false) or to
// automatically connect as soon as the remote device becomes available (true).

device.connectGatt(mContext,false,mGattCallback)

Two related callbacks.

Android BLE-related API callbacks are executed in threads that execute in the thread that sends the operation request.
So don't let the thread block, otherwise many callbacks will not be executed.

For example:

// Sending data and writing eigenvalues trigger Android's onCharacteristicWirte() callback method.
gatt.writeCharacteristic(characteristic)

// The callback method onCharacteristicWirte executes in the thread where the above code resides.
// So if there are blocking operations in the code. For example
while(true){
    // ...
}
// This will cause the onCharacteristicWirte callback method to be unable to execute. It will cause various abnormal phenomena.

Three Android data transmission issues.

1. Send length.

Before Android 5.0, the maximum length of data sent/received once was 20 bytes.
Therefore, data with large amount of data need to be sent and processed by subcontracting. In particular, it should be noted that if BLE peripherals
Android can only receive the first 20 bytes of data.
Later data will be lost.

2. Subcontracting

Packet sending should be careful not to block the current thread. Otherwise, unpredictable situations will occur. And it is necessary to do a second write operation when the last send data is successfully written (onCharacteristicWrite() callback execution). Otherwise, the second write operation will fail.

3. Subcontract sending example.

// Send data interface. 
private int sendData2DeviceInner2(final byte[] data){
    LogUtils.e(TAG,"Setting send parameters : " + FunctionTools.byte2HexString(data));
    mSendDataPackage.initSendTask(Arrays.copyOf(data,data.length));
    // Send data once.
    new Thread(sendDataPackageTask).start();
    return RES_BLE_SUCCESS;
}
 // Write data.
private boolean sendDataInner(byte[] data){
    LogUtils.e(TAG,"sendDataInner Current thread : " + Thread.currentThread().getId());
    mService = mCurBluetoothGatt.getService(SERVICE_UUID);
    if (!isObjectNull(mBlxService)) {
        mWriteCharacteristic = mBlxService.getCharacteristic(CHARACTERISTIC_WRITE_UUID);
    }
    if (!isObjectNull(mWriteCharacteristic)) {
        mWriteCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
        boolean res = mWriteCharacteristic.setValue(data);
        boolean res1 = mCurBluetoothGatt.writeCharacteristic(mWriteCharacteristic);
        if (res&res1)
            startDevComTimer();
        return res & res1;
    }else{
        LogUtils.e(TAG,"Write the eigenvalue empty");
        return false;
    }
}
// Data cache class to be sent.
private sendDataPackage mSendDataPackage = new sendDataPackage();
private class sendDataPackage {
        // send data
        int sendTotalLen = 0;
        int sendIndex = 0;
        byte[] sendBuffer = new byte[0];
        public void clearSendFlags(){
            sendTotalLen = 0;
            sendIndex = 0;
            sendBuffer = new byte[0];
        }
        public void initSendTask(final byte[] data){
            sendTotalLen = data.length;
            sendIndex = 0;
            sendBuffer = data;
        }
        public byte[] getOnceBuffer(){
            if (sendBuffer.length == 0)
                return new byte[0];
            int len = MAX_SEND_BYTES_COUNT;
            if (sendTotalLen - sendIndex < MAX_SEND_BYTES_COUNT)
                len = sendTotalLen - sendIndex;
            // Update Index
            sendIndex += len;

            return Arrays.copyOfRange(sendBuffer,sendIndex - len,sendIndex);
        }
        public boolean needSend(){
            if (sendBuffer.length == 0 || sendTotalLen == 0)
                return false;
            if (sendTotalLen == sendIndex )
                return false;
            return true;
        }
}
// Send data tasks.    
private Runnable sendDataPackageTask = new Runnable() {
        @Override
        public void run() {
            LogUtils.d(TAG,">>>>>>>>>> send data");
            if (mSendDataPackage.needSend()){
                if (!sendDataInner(mSendDataPackage.getOnceBuffer())){
                    // Failed to send data
                    // TODO.... Clean up the marker
                }
            }
        }
};
// Write Data Callback Implementation Code
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    super.onCharacteristicWrite(gatt, characteristic, status);
    if (status == BluetoothGatt.GATT_SUCCESS) {
        // Write success
        if (mSendDataPackage.needSend())
            new Thread(sendDataPackageTask).start();
        }
        else
            // Writing failure...
}

Solution to Re-connect BLE in Four Android s and Return the Device to STATE_DISCONNECTED

Problem description

if(gatt==null) is used to determine whether a GATT has been created, and if it has been created, the connection is re-established using gatt.connect(), but in this case the result of the test is that it takes a long time to reconnect.

Solution

The solution is through gatt = device.connectGatt(this, false, gattCallback);
Establishing a new connection object is obviously much faster than the previous method.

Problem description

However, the direct result of creating gatt connection objects many times is that after more than six gatts have been created, no device can be connected again. The reason should be that BLE in android limits the number of simultaneous connections to six.

Solution

gatt.close() is executed once for each reconnection, closing the previous connection. Some people say why not add a gatt.close(); because if gatt.close() is executed immediately, GATT Callback will not receive STATE_DISCONNECTED status. Of course, the best way is to execute gatt.close() after gattCallback receives STATE_DISCONNECTED; this will be more logical.

Reference resources:

Links: http://bbs.eeworld.com.cn/thread-438571-1-1.html

Five sub-packages send data error problem.

Question:

Some Bluetooth chips have the problem of TX data coverage when they receive a number of data. This results in errors in individual bytes of the received data. Because there is a need to interval between two frames of data in the Bluetooth core.

Solution:

  1. Delay operation can be added at the Android end when sending packets (100ms is better).
  2. Increase delay operation in COS program (recommended method).

Posted by craigerjs on Fri, 05 Apr 2019 17:27:30 -0700