Максимальное количество пакетов в характеристике записи BLE - PullRequest
0 голосов
/ 06 июня 2019

Я пишу приложение 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 во время записи этой характеристики ... может ли это вызвать проблемы?

1 Ответ

1 голос
/ 06 июня 2019

Значение характеристики может быть только 512 байт в спецификации. Запись более длинного значения недопустима, даже если некоторые стеки, по-видимому, не применяют его. Когда вы записываете значение, превышающее то, которое умещается в MTU (по умолчанию 23 байта минус 3 для заголовка), стек Bluetooth отправителя разделяет его на несколько частей (Prepared Write) и затем отправляет запрос на выполнение для фиксации. Для каждого чанка у вас есть параметр смещения, чтобы вы знали, с каким смещением записать текущий чанк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...