Android BLE - Peripheral | onCharacteristicRead return wrong value or part of it (but repeated)

血红的双手。 提交于 2019-12-04 18:49:10

Ok, i got it so i'll leave my response to help someone else will be in my situation.

The correct solution is

@Override
        public void onCharacteristicReadRequest(BluetoothDevice device,
                                                int requestId,
                                                int offset,
                                                BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
            Log.i(TAG, "onCharacteristicReadRequest " + characteristic.getUuid().toString());

            byte[] fullValue = getStoredValue();

            //check
            if (offset > fullValue.length) {
                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, new byte[]{0} );
                return;

            }


            int size = fullValue.length - offset;
            byte[] response = new byte[size];

            for (int i = offset; i < fullValue.length; i++) {
                response[i - offset] = fullValue[i];
            }



            if (MYBluetoothManager.UUID_READ_CHARACTERISTIC.equals(characteristic.getUuid())) {
                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, response);
                return;
            }



            mGattServer.sendResponse(device,
                    requestId,
                    BluetoothGatt.GATT_FAILURE,
                    0,
                    null);
        }

    };

The callback is called repeatedly with an offset, and this was clear. What was not clear it's i am supposed to respond with an array that contains all the data starting from that offset.

So i start with preparing an array with all the data. If the offset requested exceed the length of the data, i just return an array of 0 byte.

If it is not so, i prepare a portion of the original array starting from the offset requested by the callback till i have some information. So is not important if the array contains to much informations, on the second, third callback i know where to start to return the data.

sorry if it's not clear, but enable logging and you will understand what i mean.

good luck to everyone

hope you are still in for this one, because I havn't found any answers on the web on this and had to 'dig the dirt' myself.

So i`ll try to break it down:

Assuming we have made connection between two android BLE devices(central and peripheral),

  1. When BLE central device, issue characterRead(...) request for a given characteristic, the onReadCharacteristic(...) callback is called in the peripheral device with the relevant characteristic as parameter. The right way is to issue sendResponse(...) method with the value as the wanted value for the central to read(what you as peripheral want to answer actually). So as I see you quite right on that approach and all is well.

  2. The MTU size for the give link, is the default - 20 bytes.(Actually 23, but for the GATT protocol we need 3 bytes) Therefor, any buffer larger than 20 bytes will be split to chunks(fragmented) by android. You have couple of options here:

    2.1. Learn to work with the given android mechanism and send your chunks accordingly to the offset.

    2.2. Change the MTU size of the link using requestMtu(...) API from the central so it can support bigger messages.

    2.3. Know the MTU of the link, and build a fragmentation mechanism yourself(will leave the offset at 0 constantly with each call).

So to conclude, android has a fragmentation mechanism you were not aware of.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!