Много пустых PDU в ESP32 Обновление через BLE

Я выполняю обновление прошивки периферийного устройства BLE на основе ESP32 из центра Android. Файл прошивки отправляется частями по 512 байт. Устройство ESP32 (сервер GATT) отправляет уведомление центральному устройству (клиенту GATT), а центральное устройство отправляет следующую часть, за которой следует команда записи на периферийное устройство. Затем отправляется следующее уведомление и так далее.

Обновление работает, однако занимает много времени (~ 10-12 минут для файла размером 600 КБ). Понюхал трафик с помощью Wireshark и оказалось, что между отправкой каждого уведомления периферией и началом отправки части центральным проходит 15-20 пустых PDU. Я искал, в чем может быть проблема на стороне сервера, но не смог найти ничего подходящего.

Может быть, что-то происходит в центре Android, что задерживает процесс отправки? Или, может быть, я что-то упускаю с ESP32? Вот захват Wireshark (я подчеркнул красным, где должна начинаться отправка):

Обновлено: я не добавил дополнительный сон на сервер, и если бы я это сделал, не было бы пустых серверных PDU, верно?

Я попробовал то, что вы предложили, чтобы использовать только внутренний механизм Android для подтверждения, и загрузка теперь примерно в 3 раза быстрее. Спасибо! Однако в захватах есть некоторые странные (для меня) вещи вроде множества 26-байтных ответных пакетов от сервера к мастеру (захваты ниже). Почему так и можно ли их объединить в 3 пакета, как они были отправлены от мастера?

Кроме того, об объяснении в ссылке, которую вы дали:

Контроллер Bluetooth отправляет событие «количество пакетов завершено» обратно в стек Bluetooth Android через HCI, что указывает на то, что канальный уровень удаленного устройства подтвердил получение пакета.

Я не совсем понял. Если это Write_No_Response от мастера, как удаленное устройство подтверждает получение пакета? И является ли этот механизм управления потоком Android возможным объяснением моей первоначальной проблемы с пустыми пакетами?

Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
0
0
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, устройство Android работает недостаточно быстро, или вы добавили дополнительный спящий режим.

Предполагая, что периферийное устройство может обрабатывать данные, вы можете достаточно надежно отправлять команды записи без использования схемы подтверждения уведомления. См. onCharacteristicWrite и onNotificationSent вызываются слишком быстро — как получить реальную скорость исходящего трафика?. По сути, просто дождитесь onCharacteristicWrite, прежде чем отправлять следующий.

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

peter_s 23.11.2022 08:54

Похоже, вы больше не используете тип записи «Запись без ответа», судя по подготовке запросов на запись? Пустые PDU всегда отправляются в качестве ответа на каждое событие соединения, если периферийному устройству нечего отправлять. Канальный уровень (который является более низким уровнем, чем ATT) подтверждает все виды пакетов, вы можете видеть это в «следующем ожидаемом порядковом номере» в заголовке.

Emil 23.11.2022 16:45

Да, я использую Write Request with Write Response, потому что, насколько я понимаю, это единственный способ, которым стек Android может получить подтверждение, верно? Я знаю о пустых пакетах, но у меня вопрос, почему сервер теперь отправляет клиенту столько 26-байтных ответных пакетов L2CAP, а не объединяет их в несколько больших?

peter_s 23.11.2022 20:39

Кроме того, я помню, как смотрел некоторые захваты wireshark, где у сервера была установлена ​​​​задержка, а в захвате во время задержки были только основные пакеты, поэтому я предположил, что сервер ничего не отправляет во время сна.

peter_s 23.11.2022 20:47

Пожалуйста, попробуйте написать без ответа. Подтверждений канального уровня достаточно для управления потоком. Подождите onCharacteristicWrite, прежде чем отправлять следующий пакет, и все будет в порядке. Подготовить запросы на запись действительно глупо и неэффективно, поскольку они возвращают данные обратно, а центр просто отбрасывает их. Убедитесь, что MTU достаточно велик для ваших пакетов.

Emil 23.11.2022 20:54

Спасибо, теперь намного быстрее.

peter_s 29.11.2022 15:33

Другие вопросы по теме