BLE: как определить последний пакет для больших данных в BLE Write и уведомить в Win10

#c# #android #windows #uwp #bluetooth-lowenergy

#c# #Android #Windows #uwp #bluetooth-низкое энергопотребление

Вопрос:

У меня есть библиотека классов Windows, которая использует API-интерфейсы UWP BLE. Настройка такова: хост BLE: ноутбук Win 10 Периферийное устройство BLE: ноутбук Win 10 или Android

Мне нужно отправить большой файл (от нескольких K до нескольких M) на периферийное устройство и обратно (используя Write / WriteWithoutResponse и Notify), используя пользовательский сервис и характеристики.

Для беспроигрышной ситуации все, кажется, обрабатывается ОС. Хост просто вызывает это один раз

 writeResult = await characteristic.WriteValueAsync(buffer, GattWriteOption.WriteWithResponse);
 

с большими данными и ОС, похоже, автоматически согласует максимальный MTU (517 байт на Android), разделит данные на меньшие фрагменты и отправит.
Однако на принимающей стороне,

  private async void Characteristic_WriteRequestedAsync(GattLocalCharacteristic sender, GattWriteRequestedEventArgs args)        {

            var deferral = args.GetDeferral();
            using (deferral)
            {
                GattWriteRequest request = await args.GetRequestAsync();
                if (request == null)
                {
                    Log(LOG_ERR, $"No access allowed to the device");
                    return;
                }
                var reader = DataReader.FromBuffer(request.Value);
                string mystring = reader.ReadString(request.Value.Length);
                Log(LOG_VERBOSE, $"Receiving data value length: {request.Value.Length}");
                Log(LOG_VERBOSE, $"Receiving data write offset: {request.Offset}");
                Log(LOG_VERBOSE, $"Receiving data write state: {request.State}");

                
                if (request.Option == GattWriteOption.WriteWithResponse)
                {
                    request.Respond();
                }
                deferral.Complete();
            }
        }
 

Приемник будет иметь несколько обратных вызовов, но в каждом обратном вызове он имеет только информацию о значении, смещении и состоянии. Как получатель узнает, какой пакет является последним, и может начать обработку данных?
Я не думаю, что проверка длины значения <максимальный размер PDU — хороший способ. И периферийные устройства Android и Windows, похоже, получают разный размер данных на пакет. (Android 517, Windows 522)

То же самое для уведомления на хосте Win, в нем практически нет ничего, что могло бы определить, является ли это последним пакетом всего сообщения.

 private void NotifyCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
  Log(LOG_VERBOSE, $"Receiving value length from Notify: {args.CharacteristicValue.Length}");
}
 

Я думаю, что это очень простое требование и должно быть реализовано Windows. Я что-то здесь упускаю? Если нет собственной реализации Windows, мне нужно реализовать свой собственный механизм. Используя символ-терминатор в конце фактических данных? Есть предложения?

Спасибо, Анжела

Комментарии:

1. Отправьте количество байтов в начале первого сообщения, а затем читайте, пока не получите количество байтов.

2. Правильный поток — сначала отметить значения и смещения. Затем отправитель должен отправить «Выполнить запись» на уровне ATT для фиксации ранее отправленных записей, и в это время получатель должен атомарно обновить значение новым полным значением. Пока не уверен, как последний шаг должен обрабатываться в стеке Microsoft… С уведомлениями нет такого понятия, как «полное сообщение», поскольку уведомления отправляются только в одном пакете, усеченном для соответствия MTU.