BLE写入特征中的最大数据包数



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

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]);
}

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

这两种设备都在BLE上不断做广告和扫描,同时写入此特性...这会导致问题吗?

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