OSX蓝牙LE外设传输速率很慢

San*_*man 0 macos bluetooth iobluetooth ios

背景资料:

我已经为OSX实现了蓝牙LE外设,它暴露了两个特性(使用CoreBluetooth).一个是可读的,一个是可写的(两者都有指示).我在iOS上实现了一个Bluetooth LE Central,它将从可读特性中读取并写入可写特性.我已将其设置为每次读取特征值时,都会更新该值(以类似于此示例的方式).我通过这种设置获得的传输速率非常缓慢(以大约340 字节 /秒的测量持续速度进行补偿).此速度是实际数据,而不是包括数据包详细信息,ACK等的度量.

问题:

这种持续的速度太慢了.我考虑过两个解决方案:

  1. CoreBluetooth中有一些我错过的参数可以帮助我提高速度.
  2. 我需要使用IOBluetooth类而不是CoreBluetooth来实现自定义蓝牙LE服务.

我相信,我已经用尽了选项1.我没有看到任何其他可以调整的参数.我只限于每封邮件发送20个字节.还有其他任何东西,我在iOS设备上收到有关未知错误,不太可能错误或值"不长"的神秘错误.由于演示项目还指示了一个20字节的MTU,我会接受这可能是不可能的.

所以我留下了选项2.我试图以某种方式修改OSX上蓝牙LE的连接参数,希望能够提高传输速度(通过将最小和最大连接间隔分别设置为20ms和40ms - 如以及每个连接间隔发送多个BT数据包).看起来在IOBluetooth上提供我自己的SDP服务是在OSX上实现这一目标的唯一方法.这个问题是关于如何做到这一点的文档可以忽略不计.

告诉我如何实现我自己的服务(尽管使用deprecate API),但是,它没有解释注册SDP服务所需的参数.所以我想知道:

  1. 我在哪里可以找到这本词典所需的参数?
  2. 如何以提供蓝牙LE服务的方式定义这些参数?
  3. 有没有其他方法可以通过另一个框架(Python库?可以访问蓝牙堆栈的VM中的Linux?在OSX上提供蓝牙LE外设?我想完全避免这种情况.)

San*_*man 5

我决定我最好的做法是尝试在VM中使用Linux,因为有更多的文档可用,并且访问源代码有望保证我能找到解决方案.对于同样面临此问题的任何人,以下是如何在OS X上发布连接参数更新请求(排序).

步骤1

安装Linux VM.我使用Virtual Box和Linux Mint 15(64位Cinnamon).

第2步

允许在VM中使用OS X Bluetooth设备.尝试将蓝牙USB控制器转发到VM将显示错误消息.为此,您需要停止使用控制器的所有内容.在我的机器上,包括从命令行发出以下命令:

sudo launchctl unload /System/Library/LaunchDaemons/com.apple.blued.plist

这会杀死OS X蓝牙守护进程.尝试从活动监视器中杀死蓝色只会导致它自动重新启动.

sudo kextunload -b com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport

在我的MacBook上,我有一个Broadcom控制器,这是OS X用于它的内核模块.不要担心发出这些命令.要撤消更改,您可以关闭并重新启动计算机(请注意,在某些情况下,当使用BT控制器并且它处于不良状态时,我必须让机器断电约10秒才能重新启动以清除易变的记忆).

如果在运行这两个命令之后仍然无法安装BT控制器,您可以运行kextstat | grep Bluetooth并查看其他蓝牙相关的内核模块,然后尝试卸载它们.我有一个名为IOBluetoothFamily和IOBluetoothSerialManager的,不需要卸载.

第3步

启动VM并获取Linux BT堆栈.我从这里检查了bluez Git repo .我特意抓住5.14版本标签git checkout tags/5.14,以确保它至少是一个标记版本,不太可能被破坏.在写这个答案时,5.14是最新的标签.

第4步

建立bluez.这是使用bootstrap完成的,然后配置,然后make和make install.我--prefix=/opt/bluez在configure上使用了标志来防止覆盖安装蓝牙堆栈.另外,我使用--enable-maintainer-mode配置标志的原因在下一步中说明.您可能还需要使用--disable-systemd它来配置它.Bluez有许多工具和实用程序,可用于各种事情.要使用内置的蓝牙守护程序,您需要使用停止系统守护程序sudo service bluetooth stop.然后,您可以使用sudo /opt/bluez/libexec/bluetooth/bluetoothd -n -d(在具有调试输出的非守护程序模式下启动)启动构建的一个.

第5步

通过bluez运行您的LE服务.您可以查看bluez/plugins/gatt-example.c有关如何执行此操作的信息.我通过删除不必要的代码并使用电池服务代码作为我自己的服务和特性的模板直接修改了这个.您需要重新编译bluez才能将此代码添加到蓝牙守护程序中.有一点需要注意(这导致我在工作中遇到一两天的麻烦)是iOS缓存GATT服务列表,并且不会在每个连接上读取/刷新.如果您添加服务或特性或更改UUID,则需要在iOS设备上禁用蓝牙,然后重新启用它.这在Apples文档中没有记录,并且没有编程方法.

第6步

不幸的是,这是事情变得棘手的地方.Bluez没有内置支持使用其任何实用程序发出连接参数更新请求.我必须自己写.我目前正在看他们是否希望我的代码包含在bluez堆栈中.我目前无法发布代码,因为我需要先了解bluez开发人员是否对代码感兴趣,然后从我的工作场所获得批准以获得代码.但是,我现在可以解释我做了什么来启用支持.

第7步

使用蓝牙标准自己做好准备.任何4.0或更高版本都将具有您需要的详细信息.阅读以下部分.

  • 见Vol.2,部分E,4.1用于主机到控制器的HCI流程.
  • 见Vol.2,部分E,5.4.2用于HCI ACL数据包格式.
  • 见Vol.3,部分A,4用于信令分组格式.
  • 见Vol.3,A部分,4.20用于连接参数更新请求格式.

您基本上需要编写代码来格式化数据包,然后将它们写入hci设备.HCI ACL数据包报头将包含4个字节.接下来是4个字节,用于信令命令的长度和通道ID.然后是你的信号有效载荷,在我的例子中是12个字节(用于连接参数更新请求).

然后,您可以将它们写入类似装置hci_send_cmdbluez/lib/hci.c.我把每个数据包标题作为它自己的结构,然后将它们作为iovecs写入设备.我把我的新函数放在hci.c文件中并用函数原型公开它bluez/lib/hci_lib.h.然后我修改bluez/tools/hcitool.c了允许我从命令行调用此方法.在我的情况下,我做了这个命令几乎与lecup命令相同,因为它需要相同的参数(lecup不能用,因为它意味着要在主方面调用,而不是从属).

重新编译所有这些然后,瞧,我可以在hcitool上使用我的新命令将参数发送到蓝牙控制器.发送命令后,它会按预期与iOS设备重新协商.

评论

这个过程不适合胆小的人.希望将此设置或其他一些设置连接参数的方法添加到bluez以简化此过程.理想情况下,Apple也允许在某些时候通过CoreBluetooth或IOBluetooth这样做(这可能是可能的,但是没有记录/很难这样做,我放弃了Apple库).我已经沿着兔子洞走了下来,学到了更多关于蓝牙规格的知识,然后我想我只需要改变MacBook和iPhone之间的连接参数.希望这在某些方面对某人有帮助(即使是我检查我是如何做到的).

我知道我在这里省略了很多细节,以便保持简短(即使用bluez工具).如果不清楚,请评论.