Android 4.3: BLE: поведение фильтра startLeScan()

Я работаю над сенсорным устройством BluetoothLE, для которого мне нужно сформировать широковещательную передачу данных "один ко многим". Согласно спецификации, периферийные устройства могут иметь только один мастер, и из-за ограничений чипа и стека, которые я проектирую, мастер может иметь только три подчиненных устройства. Из того, что я понимаю, Android не может стать ведомым BLE в любом случае, поэтому наличие моего устройства в качестве мастера не является вариантом.

В спецификации BT4 и документации производителя говорится о другом режиме работы, называемом широковещательным режимом. В широковещательном режиме соединение никогда не выполняется, а данные приложения передаются как часть рекламного пакета. Это точно соответствует моим потребностям, так как многие телефоны Android/iOS могут одновременно сканировать каждый пакет. Рекламный пакет передается несколько раз в пакетах, поэтому я подозреваю, что получение данных будет в основном надежным. Если пакет потерян здесь и там, его можно терпеть.

Когда это становится интересным, я хочу, чтобы эти пакеты несли данные датчиков в реальном времени, которые обновляются со скоростью 10-20 Гц. Из примеров, которые я нашел в Интернете, BLE в этом режиме в основном используется для реализаций типа iBeacon, где они передают статические данные. Я не могу найти никакой информации о том, как пакеты рекламы отфильтровываются в стеке Android. Возможно, они возвращают один результат на аппаратный адрес Bluetooth, или это может быть уникальная комбинация адресов и данных. Второй вариант будет работать для этого приложения. Если запуск и остановка сканирования сбрасывает фильтр, я могу заставить что-то работать.

В документации на Android ничего не говорится о том, как работает фильтрация устройств в методе сканирования. Я смог найти одно сообщение в сети, пытающееся решить эту же проблему, которая имеет нерешенный ответ: BLE: множественное обнаружение того же периферийного устройства во время сканирования. В iOS мой коллега сообщает мне, что есть параметр, который может быть передан функции сканирования, что делает это возможным.

Я попытался отследить код из вызова startLeScan() в источнике Android, но код довольно сложный, и использование абстракции затруднило определение реализации объекта, который его содержит. Самое дальнее, что я получил, - это объект IBluetoothGatt, возвращенный из метода класса BluetoothManagerService getBluetoothGatt(). Этот объект получает запрос на запуск сканирования. Он создается в строке 790 BluetoothManagerService.java в текущей версии live on github. Объект отбрасывается из результата сообщения, поэтому я подозреваю, что в результате возникает конкретный телефон/драйвер. Я не знаю, как это сделать.

Еще один вопрос, который я хотел бы решить, - это то, как быстро сканирование можно включать и выключать. Сканирование - это интенсивная работа, но передача данных будет происходить периодически на довольно точном таймере реального времени. В результате было бы большой оптимизацией, если сканирование можно включить и выключить, чтобы синхронизация и сканирование синхронизировались, а сканер отключил остальные 90% + времени. Вероятно, это необходимо будет испытать экспериментально.

Я все еще занимаюсь технико-экономическим исследованием, чтобы узнать, возможно ли это для нашего аксессуара для Android. Мой нынешний телефон еще не может запустить версию 4.3, поэтому у меня нет возможности проверить/взломать это экспериментально.

Ответ 1

С Android 4.3 и 4.4 до сих пор это кажется беспорядочным: некоторые устройства вызывают onLeScan (устройство BluetoothDevice, int rssi, byte [] scanRecord) несколько раз для одного устройства в одном сканере, а некоторые нет. Невозможно настроить фильтрацию, как в iOS (см. Ответ Arkadiusz Konior). Итак, теперь я начинаю список, потому что я не могу задать своим пользователям такой вопрос об их устройстве.

Тем не менее, перезапуск сканирования также не представляет проблемы на устройствах, не фильтрующих. Итак, я перезапускаю сканирование на каждом устройстве сейчас.

Не фильтровать (Постоянно вызывать onLeScan())

  • Samsung Galaxy S4 с 4.2.2 с использованием Samsung BLE sdk (мне принадлежало это устройство)
  • Nexus 5 с 4.4 (добавлено [vegarwe]. Устройство будет непрерывно сканировать записи для ближайших устройств во время сканирования)
  • Samsung Galaxy S3 с 4.3 (JSS15J.I9300XXUGMK6, я тестировал на этом устройстве)
  • Samsung Galaxy S4 с 4.3 и 4.4.2 с использованием Android SDK (добавлено arnaud.b, без сборки)
  • HTC One с 4.4.2 (добавлено arnaud.b, номер сборки не указан)

Фильтрующие устройства (относится к стандарту)

  • Nexus 4 с 4.3, 4.4 (у меня есть это устройство)
  • Nexus 7 2013 4G с 4.4.2 (KOT49H, я тестировал на этом устройстве)
  • Samsung Galaxy S4 mini с 4.2.2 (я тестировал на этом устройстве)
  • Motorola Moto X (добавлено user1603602, информация о версии для Android не указана)
  • Motorola Moto G с 4.3 (falcon_umts, мое тестовое устройство)
  • Sony Xperia Tablet Z Wifi с Android 4.3 (Build 10.4.B.0.577, модель SGP311, мое тестовое устройство)
  • OnePlus One с 5.0.1 и 5.1.1 (Cyanogen 12.1)

Неизвестное поведение фильтрации (Пожалуйста, помогите связать устройство с определенной группой)

Ответ 2

Текст на страницах 2535-2536 в спецификации Bluetooth (Core_v4.1.pdf) о дублирующих рекламных отчетах несколько неясен. Однако текст на стр. 1258 понятен. Он указывает параметр Filter_Duplicates на команду HCI_LE_Set_Scan_Enable. В Android версии 4.4 (Kitkat) этот параметр равен 0x00 (Duplicate filtering disabled).

Существует простой способ выяснить, выполнена ли какая-либо фильтрация в чипе Bluetooth от Android версии 4.4 (Kitkat). Сделайте телефон для телефона разработчика, введите параметры разработчика и установите флажок "Включить протокол Bluetooth HCI snoop". Затем разведите Bluetooth OFF и ON один раз, чтобы укусить настройки. С этого момента все пакеты HCI между прикладным процессором и чипом Bluetooth будут храниться на телефоне в файле, который вытягивается с помощью adb pull storage/emulated/legacy/btsnoop_hci.log. Это не текстовый файл, и вам нужна программа из http://www.fte.com/products/default.aspx или wirehark для просмотра btsnoop_hci.log. Для wirehark вам нужна довольно новая версия, потому что более старые версии не поддерживают BLE. Мой опыт в том, что в чипе Bluetooth никогда не происходит фильтрации, то есть событие HCI "Событие для публикации рекламы LE" отправляется для каждого ADV_IND  и ADV_NONCONN_IND  что чип Bluetooth получает. Это касается телефонов с чипами Bluetooth Qualcomm/Atheros WCN 3680 и Broadcom BCM 4339.

Коррекция: путь к btsnoop_hci.log может отличаться в зависимости от производителя телефона. Вы можете найти правильный путь с помощью adb shell cat etc/bluetooth/bt_stack.conf | grep BtSnoopFileName

Ответ 3

Я разрабатываю приложение для Android 4.3 (Nexus 4 и 7) с помощью BLE, и из моих наблюдений сканирование возвращает одно и то же устройство несколько раз, если не было ответа SCAN REQUEST обратно на периферию.

Устройство может рекламировать двумя способами: пассивным и активным. В пассивном режиме периферийное устройство просто рекламирует все данные и не слушает после отправки периодического пакета. Это просто отправка, сон, отправка, спящий... В активном режиме датчик также рекламирует, но сообщение как можно короче. После его отправки он переключается на прослушивание в течение очень короткого времени. При сканировании обнаруживает короткое сообщение, оно немедленно отправляет команду SCAN REQUEST в периферийное устройство и получает ответ с более подробной информацией. Насколько я вижу, Android не отправляет SCAN REQUEST несколько раз во время одного сканирования.

Предположим, что у нас есть 2 устройства в радиусе действия. Один из них - это f.e. Nordic nRF Temp sensor (пассивная реклама) и еще одно подключаемое устройство. Я получил следующий ответ на сканирование:

11-10 21:32:54.281: D/BluetoothAdapter(13468): startLeScan(): null
11-10 21:32:54.281: D/BluetoothAdapter(13468): onClientRegistered() - status=0 clientIf=4
11-10 21:32:54.321: D/BluetoothAdapter(13468): onScanResult() - Device=CD:61:1A:A8:BC:BE RSSI=-94
11-10 21:32:55.122: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-61
11-10 21:32:56.414: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-62
11-10 21:32:57.715: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-61
11-10 21:32:59.016: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:01.609: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:02.901: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:04.212: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-62
11-10 21:33:04.282: D/BluetoothAdapter(13468): stopLeScan()

Как видно, подключаемое устройство появилось только один раз, а другой - 7 раз.

Еще один вопрос, который я хотел бы решить, - это то, как быстро сканирование можно включать и выключать. Сканирование - это интенсивная работа, но передача данных будет происходить периодически на довольно точном таймере реального времени. В результате было бы большой оптимизацией, если сканирование можно включить и выключить, чтобы синхронизация и сканирование синхронизировались, а сканер отключил остальные 90% + времени. Вероятно, это необходимо будет испытать экспериментально.

Частота сканирования зависит от устройства. Кроме того, реклама обычно выполняется по 3 каналам: 37, 38 и 39 для увеличения вероятности обнаружения. Однако, может быть, неплохо было бы получать рекламные пакеты из "активных" устройств несколько раз.

Ответ 4

Фактическая спецификация bluetooth говорит:

Дублировать рекламные отчеты не требуется для отправки на хост.Дубликат рекламного отчета - это рекламный отчет для того же адрес устройства, в то время как уровень ссылки остается в состоянии сканирования. рекламные данные могут измениться; рекламные данные или данные ответа сканирования не считается существенным при определении дублирующейся рекламы отчеты.

В соответствии со спецификацией это применяется в течение периода сканирования, что предполагает, что правильный путь вокруг этого заключается в том, чтобы остановить и перезапустить сканирование каждый раз, когда вы получаете рекламу.

Основываясь на моем опыте работы с BLE, кажется, что отправка переменных данных в рекламе - это не очень хорошая идея. Почти все предполагает, что данные из рекламы не меняются. Если вы хотите действительно отправлять переменные данные (например, показания термометра), гораздо лучше фактически подключиться к устройству и сделать это через характеристику. Он более надежный и использует гораздо меньшую мощность. Недостатком является то, что вы можете подключаться только к 8 устройствам одновременно.

Объявления предназначены для обнаружения присутствия устройств и их идентификации.

Ответ 5

В iOS этот флаг называется CBCentralManagerScanOptionAllowDuplicatesKey. Передача его функции сканирования вызывает уведомление для каждого рекламного пакета. Я не мог найти аналогичный флаг в Android.