BLE写特性中的最大包数

时间:2019-06-06 15:20:27

标签: android bluetooth-lowenergy

我正在编写Xamarin.Android应用程序,但该问题通常适用于本机Android和BLE。我有一个可以写入的写入特征,只要我发送的字符数不超过600个,它就可以工作。超过600个字符的内容都会被截断。查看我的日志,可以看到该文本被拆分为20个字符的数据包,每个数据包都被调用OnCharacteristicWriteRequest,但是在600个字符之后不再被调用。我正在测试2个Android平板电脑。我要编写的代码特征:

public override void OnServicesDiscovered(BluetoothGatt gatt, [GeneratedEnum] GattStatus status)
{
    base.OnServicesDiscovered(gatt, status);

    try
    {
        if (status != GattStatus.Success)
        {
            Log?.Invoke("discover services failed");
            return;
        }

        Log?.Invoke("services discovered");

        if(RequestForAddressExists(gatt.Device.Address))
        {
            lock (_requestsLocker)
            {
                Java.Util.UUID serviceUuid = GetRequestedServiceUuid(gatt.Device.Address);
                Java.Util.UUID characteristicUuid = GetRequestedCharacteristicUuid(gatt.Device.Address);

                BluetoothGattCharacteristic characteristic = gatt.GetService(serviceUuid).GetCharacteristic(characteristicUuid);

                Log?.Invoke("characterisitic found");

                var request = _requests.FirstOrDefault(r => r.DeviceAddress == gatt.Device.Address);

                if (characteristic.Properties.HasFlag(GattProperty.Write))
                {
                    Log?.Invoke("writing characteristic...");

                    string data = ((WriteCharacteristicRequest)request).Data;

                    characteristic.SetValue($"{data}{Constants.WriteCharacteristicEndDelimiter}");
                    characteristic.WriteType = GattWriteType.Default;
                    gatt.WriteCharacteristic(characteristic);
                }
                else
                {
                    Log?.Invoke("GattProperty not supported");
                    _requests.Remove(request);
                }
            }
        }
    }
    catch (Exception e)
    {
        Log?.Invoke(e.Message);
    }
}

public override void OnCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, [GeneratedEnum] GattStatus status)
{
    base.OnCharacteristicWrite(gatt, characteristic, status);

    if (status != GattStatus.Success)
    {
        Log?.Invoke($"OnCharacteristicWrite status not success: {status}");
    }
    else
    {
        Log?.Invoke("OnCharacteristicWrite success");
    }

    gatt.Disconnect();
    gatt.Close();

    lock (_requestsLocker)
    {
        var r = _requests.FirstOrDefault(x => x.DeviceAddress == gatt.Device.Address);

        if (r != null)
        {
            _requests.Remove(r);
        }
    }
}

我的代码接受写请求:

public override void OnCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, bool preparedWrite, bool responseNeeded, int offset, byte[] value)
{
    base.OnCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);

    Log?.Invoke("OnCharacteristicWriteRequest");

    string data = System.Text.Encoding.UTF8.GetString(value);

    Log?.Invoke(data);

    string characteristicId = new Guid(characteristic.Uuid.ToString()).ToString().ToUpperInvariant();
    var record = _writeCharacteristicsReceived.FirstOrDefault(c => c.DeviceAddress == device.Address && c.CharacteristicId.ToUpperInvariant() == characteristicId);

    if(record != null)
    {
        record.Data += data;
    }
    else
    {
        record = new CharacteristicWriteReceived()
        {
            CharacteristicId = characteristicId,
            DeviceAddress = device.Address,
            Data = data
        };

        _writeCharacteristicsReceived.Add(record);
    }

    if (record.Data.EndsWith(Constants.WriteCharacteristicEndDelimiter) == true)
    {
        Log?.Invoke("end found");

        _writeCharacteristicsReceived.Remove(record);
        record.Data = record.Data.Substring(0, record.Data.Length - Constants.WriteCharacteristicEndDelimiter.Length); // remove the end delimeter
        Log?.Invoke(record.Data);

        OnCharacteristicWriteReceived?.Invoke(record);
    }

    if (responseNeeded)
    {
        BluetoothGattServer.SendResponse(device, requestId, GattStatus.Success, 0, value);
    }
}

public override void OnExecuteWrite(BluetoothDevice device, int requestId, bool execute)
{
    // need to override OnExecuteWrite and call SendResponse here as well,
    // since the execute packet corresponds to the last ATT packet that the client sends as a "finish" marker,
    // and the client expects a response to know that the server accepted the writes

    base.OnExecuteWrite(device, requestId, execute);

    BluetoothGattServer.SendResponse(device, requestId, GattStatus.Success, 0, new byte[0]);
}

有趣的是,即使文本被截断,我的status == GattStatus.Success中仍然有OnCharacteristicWrite。为什么会被截断?是否可以发送最大数量的数据包?

两个设备都在写入BLE的同时不断在BLE上做广告和扫描...会引起问题吗?

1 个答案:

答案 0 :(得分:1)

每个规范的特征值只能是512个字节长。不允许写入更长的值,即使某些堆栈显然不强制执行它也是如此。 当您写入的值长于MTU的值时(默认23字节减去3的报头),发送方蓝牙堆栈会将其拆分为多个块(“准备写入”),然后发送执行请求以提交。对于每个块,您都有offset参数,因此您知道在哪个偏移量下写入当前块。