28

我正在开发一个 BluetoothLE 传感器设备,为此我需要形成一对多的数据广播。根据规范,外围设备可能只有一个主设备,并且由于我正在设计的芯片和堆栈的限制,一个主设备只能有三个从设备。据我了解,Android 无论如何都不能成为 BLE 从属设备,因此不能让我的设备作为主设备。

BT4 规范和制造商文档都谈到了另一种操作模式,称为广播模式。在广播模式下,永远不会建立连接,并且应用程序数据作为广告数据包的一部分进行传输。这完全符合我的需求,因为许多 Android/iOS 手机可以同时扫描每个数据包。一个广告包以突发方式多次传输,所以我怀疑数据的接收大部分是可靠的。如果一个数据包在这里和那里丢失,它是可以容忍的。

有趣的是,我希望这些数据包能够携带实时传感器数据,这些数据以 10-20Hz 的速率更新。从我在网上找到的示例来看,这种模式下的 BLE 主要用于“iBeacon”类型的实现,它们在其中广播静态数据。我找不到有关如何在 Android 堆栈中过滤广告数据包的任何信息。它们可能是每个蓝牙硬件地址返回一个结果,也可能是地址和数据的唯一组合。第二个选项适用于此应用程序。如果开始和停止扫描会重置过滤器,我也可以做一些工作。

Android 文档没有提到扫描方法中的设备过滤是如何工作的。我已经能够在网上找到一篇试图解决同样问题的帖子,但回复未解决:BLE: Multiple discovery of the same peripheral during scan。在 iOS 中,我的同事告诉我,有一个参数可以传递给 scan 函数,使这成为可能。

我试图从 Android 源代码中的 startLeScan() 调用中追溯代码,但代码非常复杂,并且抽象的使用使得很难识别包含它的对象的实现。我得到的最远的是从 BluetoothManagerService 类方法 getBluetoothGatt() 返回的 IBluetoothGatt 对象。该对象接收开始扫描的请求。它在 github 上的当前修订版的 BluetoothManagerService.java 的第 790 行附近被实例化。该对象是从消息的结果中投射出来的,所以我怀疑结果可能是电话/驱动程序特定的。能够进一步追踪它超出了我的专业知识。

我想解决的另一个问题是打开和关闭扫描的速度有多快。扫描是一项耗电量大的操作,但数据的广播将在相当精确的实时计时器上定期发生。因此,如果可以打开和关闭扫描,这将是一个很好的优化,这样广播和扫描是同步的,而扫描仪在其他 90% 以上的时间里会关闭。这可能需要进行实验测试。

我还在做可行性研究,看看我们的 Android 配件是否可行。我现在的手机还不能运行 4.3 版,所以我无法通过实验测试/破解它。

4

5 回答 5

27

到目前为止,对于 Android 4.3 和 4.4,它似乎是一团糟:有些设备在一次扫描中为一台设备调用 onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)多次,有些则没有。无法像在 iOS 中那样配置过滤(参见 Arkadiusz Konior 的回答)。所以,我现在开始列出一个列表,因为我无法向我的用户询问有关他们设备的此类问题。

但是,在“未过滤”设备上重新启动扫描也没有问题。所以,我现在在每台设备上重新开始扫描。

不过滤(不断调用 onLeScan())

  • 使用三星 BLE sdk 的带有 4.2.2 的三星 Galaxy S4(我拥有该设备)
  • Nexus 5 with 4.4(由[vegarwe]添加。设备会在扫描时连续给附近设备的扫描记录)
  • 带有 4.3 的三星 Galaxy S3(JSS15J.I9300XXUGMK6,我正在该设备上进行测试)
  • 带有 4.3 和 4.4.2 的三星 Galaxy S4 使用 Android SDK(由arnaud.b添加,未提供构建)
  • HTC One 4.4.2(由arnaud.b添加,未提供内部版本号)

过滤装置(适用于标准)

  • 带有 4.3、4.4 的 Nexus 4(我拥有该设备)
  • Nexus 7 2013 4G 和 4.4.2(KOT49H,我在那个设备上测试)
  • 带有 4.2.2 的三星 Galaxy S4 mini(我正在此设备上进行测试)
  • 摩托罗拉 Moto X(由user1603602添加,未提供有关 android 版本的信息)
  • 带有 4.3 的摩托罗拉 Moto G(falcon_umts,我的测试设备)
  • Sony Xperia Tablet Z Wifi with Android 4.3 (Build 10.4.B.0.577, Model SGP311, my testing device)
  • 带有 5.0.1 和 5.1.1 (Cyanogen 12.1) 的 OnePlus One

未知过滤行为(请帮助将设备关联到某个组)

  • Nexus 7 2013 (不同的行为被报告在这里。但我已经阅读了更多的报告,它属于第一组。)
  • 其他 SAMSUNG、HTC、摩托罗拉、...、设备
于 2013-11-25T14:55:03.257 回答
15

蓝牙规范 (Core_v4.1.pdf) 第 2535-2536 页中关于重复广告报告的文本有些不清楚。但是,第 1258 页上的文字很清楚。它为 HCI_LE_Set_Scan_Enable 命令指定一个 Filter_Duplicates 参数。在 Android 版本 4.4 (Kitkat) 中,此参数为 0x00(禁用重复过滤)。

有一种简单的方法可以从 Android 版本 4.4 (Kitkat) 中找出是否在蓝牙芯片中进行了任何过滤。将手机设为开发者手机,进入开发者选项,勾选“启用蓝牙 HCI 监听日志”。然后关闭和打开蓝牙一次以使设置生效。从现在开始,应用处理器和蓝牙芯片之间的所有 HCI 数据包都将存储在手机上的一个文件中,该文件由 adb pull storage/emulated/legacy/btsnoop_hci.log 拉取。这不是文本文件,您需要来自http://www.fte.com/products/default.aspx的程序或使用wireshark 查看btsnoop_hci.log。对于wireshark,你需要一个相当新的版本,因为旧版本不支持BLE。我的经验是蓝牙芯片中从来没有任何过滤,即蓝牙芯片接收到的每个 ADV_IND 和 ADV_NONCONN_IND 都会发送 HCI 事件“LE Advertising Report Event”。这适用于带有蓝牙芯片 Qualcomm/Atheros WCN 3680 和 Broadcom BCM 4339 的手机。

更正:btsnoop_hci.log 的路径可能因手机制造商而异。您可以通过 adb shell cat etc/bluetooth/bt_stack.conf 找到正确的路径 | grep BtSnoopFileName

于 2014-04-25T10:14:47.233 回答
8

我正在使用 BLE 开发适用于 Android 4.3 (Nexus 4&7) 的应用程序,并且根据我的观察,如果没有 SCAN REQUEST 发送回外围设备,则扫描会多次返回同一设备。

设备可以通过两种方式做广告:被动和主动。在被动模式下,外围设备只是广播它的所有数据,并且在发送周期性数据包后不监听。它只是发送、休眠、发送、休眠......在活动模式下,传感器也会做广告,但消息尽可能短。发送后,它会切换到听很短的时间。当扫描检测到短消息时,它会立即向外围设备发送 SCAN REQUEST 命令,并获得更多详细信息的响应。据我所见,Android 在一次扫描期间不会多次发送 SCAN REQUEST 。

假设我们在范围内有 2 个设备。一种是 fe Nordic 的 nRF Temp 传感器(被动广告)和另一种可连接设备。我收到以下扫描回复:

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,以增加被发现的可能性。然而,这可能是从“活动”设备多次获取广告数据包的好主意。

于 2013-11-10T21:12:56.330 回答
6

实际的蓝牙规格说:

不需要将重复的广告报告发送给主机。 重复广告报告是在链路层处于扫描状态时针对同一设备地址的广告报告。广告数据可能会发生变化;在确定重复的广告报告时,广告数据或扫描响应数据被认为不重要。

根据规范,这适用于扫描期间,这表明解决此问题的正确方法是每次收到广告时停止并重新开始扫描。

根据我在 BLE 方面的经验,在广告中发送可变数据似乎不是一个好主意。几乎所有事情都假设来自广告的数据不会改变。如果您想实际发送可变数据(例如温度计读数),那么最好实际连接到设备并通过特性来完成。它更可靠并且使用更少的功率。缺点是您一次只能连接到 8 个设备。

广告旨在检测设备的存在并识别它们。

于 2014-04-21T01:01:03.227 回答
0

在 iOS 中,这个标志被命名为CBCentralManagerScanOptionAllowDuplicatesKey. 将其传递给扫描函数会导致通知每个广告数据包。我在 Android 中找不到类似的标志。

于 2013-11-07T11:10:42.637 回答