我决定我最好的做法是尝试在 VM 中使用 Linux,因为有更多可用的文档,并且访问源代码有望保证我能找到解决方案。对于同样面临此问题的任何人,以下是如何在 OS X 上发出连接参数更新请求(有点)。
步骤1
安装 Linux 虚拟机。我将 Virtual Box 与 Linux Mint 15(64 位 Cinnamon)一起使用。
第2步
允许在您的 VM 中使用 OS X 蓝牙设备。尝试将蓝牙 USB 控制器转发到您的 VM 将给出错误消息。为此,您需要停止使用控制器的所有内容。在我的机器上,这包括从命令行发出以下命令:
sudo launchctl unload /System/Library/LaunchDaemons/com.apple.blued.plist
这将杀死 OS X 蓝牙守护进程。尝试从活动监视器中杀死 blued 只会导致它自动重新启动。
sudo kextunload -b com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
在我的 MacBook 上,我有一个 Broadcom 控制器,这是 OS X 用于它的内核模块。不要担心发出这些命令。要撤消更改,您可以关闭并重新启动机器(注意,在某些情况下,当使用 BT 控制器并进入错误状态时,我实际上必须让机器关闭大约 10 秒钟,然后重新启动以清除易失性存储器)。
如果运行这两个命令后仍然无法挂载蓝牙控制器,您可以运行kextstat | grep Bluetooth
并查看其他与蓝牙相关的内核模块,然后尝试卸载它们。我有一些不需要卸载的名为 IOBluetoothFamily 和 IOBluetoothSerialManager。
第 3 步
启动您的 VM 并获取您的 Linux BT 堆栈。我从这里查看了 bluez Git repo 。我特别抓住了 5.14 发布标签,git checkout tags/5.14
只是为了确保它至少是一个带标签的版本并且不太可能被破坏。5.14 是撰写此答案时的最新标签。
第4步
构建蓝兹。这是使用引导程序完成的,然后是配置,然后是 make 和 make install。我--prefix=/opt/bluez
在配置上使用了标志来防止覆盖安装蓝牙堆栈。--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 或更高版本都将包含您需要的详细信息。阅读以下部分。
- 见卷。2,E 部分,4.1 主机到控制器 HCI 流程。
- 见卷。2,E 部分,5.4.2 用于 HCI ACL 数据包格式。
- 见卷。3,A部分,4为信令包格式。
- 见卷。3,A 部分,4.20 用于连接参数更新请求格式。
您基本上需要编写代码来格式化数据包,然后将它们写入 hci 设备。HCI ACL 数据包标头将包含 4 个字节。接下来是 4 个字节,用于信令命令的长度和通道 ID。然后是您的信号有效负载,在我的情况下为 12 个字节(用于连接参数更新请求)。
然后,您可以将它们写入类似于hci_send_cmd
in的设备bluez/lib/hci.c
。我将每个数据包标头作为它自己的结构进行处理,并将它们分别作为iovec
s 写入设备。我将新函数放在 hci.c 文件中,并在 .c 文件中使用函数原型公开它bluez/lib/hci_lib.h
。然后我进行了修改bluez/tools/hcitool.c
以允许我从命令行调用此方法。就我而言,我这样做是为了使该命令与 lecup 命令几乎相同,因为它需要相同的参数(不能使用 lecup,因为它应该在主端调用,而不是从属端)。
重新编译所有这些,然后,瞧,我可以在 hcitool 上使用我的新命令将参数发送到蓝牙控制器。发送我的命令后,它会按预期与 iOS 设备重新协商。
注释
这个过程不适合胆小的人。希望将此或其他设置连接参数的方法添加到 bluez 以简化此过程。理想情况下,Apple 将允许在某个时候通过 CoreBluetooth 或 IOBluetooth 来实现这一点(这可能是可能的,但没有文档记录/很难做到,我放弃了 Apple 库)。我已经走过了兔子洞,了解了更多关于蓝牙规范的知识,然后我认为我必须简单地更改 MacBook 和 iPhone 之间的连接参数。希望这会在某些时候对某人有所帮助(即使是我回头检查我是如何做到的)。
我知道我在此省略了很多细节,以使其保持简短(即在 bluez 工具上的用法)。如果有不清楚的地方,请发表评论。