如何写大量文字写出特色

Dar*_*ius 7 android xamarin.android bluetooth-lowenergy

我正在使用 Xamarin.Android 编写一个 Android 应用程序,但是本机 Android 中的答案也将受到赞赏。在我的 Android 应用程序中,我有一个设备可以写入的 BLE 写入特性。它可以工作,但我无法发送超过 20 个字节,其余的会被切断。我用于创建和添加服务/特性的代码:

BluetoothGattService service = new BluetoothGattService(Java.Util.UUID.FromString(MyServiceUuid), GattServiceType.Primary);

// write characteristic (write-only, supports subscriptions)
BluetoothGattCharacteristic writeCharacteristic = new BluetoothGattCharacteristic(Java.Util.UUID.FromString(MyCharacteristicUuid), GattProperty.WriteNoResponse | GattProperty.Notify, GattPermission.Write);

service.AddCharacteristic(writeCharacteristic);

_bluetoothGattServer.AddService(service);
Run Code Online (Sandbox Code Playgroud)

我在写入特征的一侧的代码:

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

    characteristic = gatt.GetService(Java.Util.UUID.FromString(MyServiceUuid))
                         .GetCharacteristic(Java.Util.UUID.FromString(MyCharacteristicUuid));

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

        characteristic.SetValue(MyVeryLongString);
        characteristic.WriteType = GattWriteType.NoResponse;
        gatt.WriteCharacteristic(characteristic);
    }
}
Run Code Online (Sandbox Code Playgroud)

在接受写入请求的一侧:

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

    if(responseNeeded)
    {
        BluetoothGattServer.SendResponse(device, requestId, GattStatus.Success, 0, Encoding.ASCII.GetBytes("ok"));
    }
}
Run Code Online (Sandbox Code Playgroud)

我看到有一个offset,但这个函数只被调用一次。我一定是在一侧遗漏了一些东西?

有趣的是,当我用我的应用程序的 iOS 版本测试这个 Android 应用程序时,我没有遇到这个问题。仅当两台设备都是 Android 时我才会遇到此问题。

编辑

我的新实现OnCharacteristicWriteRequest

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

    Guid characteristicId = new Guid(characteristic.Uuid.ToString());
    var record = _writeCharacteristicsReceived.FirstOrDefault(c => c.DeviceAddress == device.Address && c.CharacteristicId == 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)
    {
        _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, offset, value);
    }
}
Run Code Online (Sandbox Code Playgroud)

Emi*_*mil 6

原因是您使用 GattProperty.WriteNoResponse 而不是 GattProperty.Write。对于无响应属性变体,客户端只能使用“无响应写入”ATT 命令,该命令受 MTU 限制。使用正常的写入属性变体,客户端可以使用“带响应写入”ATT 请求以及执行写入(也称为“长写入”)的多个准备写入序列。对于长写入,客户端(自动)将写入分成带有偏移量的不同块。请注意,由于需要多次往返,长写入比仅增加 MTU 花费的时间要多得多。

  • 通过查看 https://developer.android.com/reference/android/bluetooth/BluetoothGattServerCallback.html#onExecuteWrite(android.bluetooth.BluetoothDevice,%20int,%20boolean) 上的文档,我认为您还需要重写该方法OnExecuteWrite 并在那里调用 SendResponse,因为执行数据包对应于客户端作为“完成”标记发送的最后一个 ATT 数据包,并且客户端期望响应来知道服务器已接受写入。 (2认同)