在 iOS 中向外部蓝牙设备写入 >20 个字节

Posted

技术标签:

【中文标题】在 iOS 中向外部蓝牙设备写入 >20 个字节【英文标题】:Writing >20 bytes to an external Bluetooth device in iOS 【发布时间】:2014-04-10 17:43:07 【问题描述】:

我有一个通过蓝牙与支持iOS6+iPhone应用程序通信的外部设备。

问题是我需要向一个特征写入超过 20 个字节,而根据我所阅读和尝试的内容,使用 BLE 是不可能的。 p>

这是我的方法的基本结构:

NSData * payload = ... //53 bytes, last 2 bytes CRC
[peripheral writeValue:payload forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];

发送 >20 个字节时出现的错误是 CBErrorOperationCancelled(代码 5)和 CBErrorConnectionTimeout(代码 6)。我相信这是正常的。

我把数据分成20字节的块(这里的例子:https://github.com/RedBearLab/ios/issues/8),数据在设备上写得不好:

NSData * chunk1 = ... //first 20 bytes
NSData * chunk2 = ... //next 20 bytes
...
NSData * chunkN = ... //remaining bytes + CRC from whole data

[peripheral writeValue:chunk1 forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
[peripheral writeValue:chunk2 forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
...
[peripheral writeValue:chunkN forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];

我认为外部设备处理的是每个字节数组,而不是整个数据。

此外,我尝试将有效负载数据拆分为 18 个字节的块,并将 CRC 附加到我发送的每个字节块中。这得到了与将 CRC 附加到最后一块数据相同的结果。

在应用程序的Android版本中,整个数据被发送,所以我知道设备可以通过单个命令读取>20字节

我的问题是:

    是否可以将整个数据分块发送到外部 无需修改外围硬件/软件的设备?

    第一个数据块中是否有标志/信号字节通知 设备整条消息的长度?

    我读到在 iOS 7 中可以发送更大的字节数组。如果 我支持 iOS 7+ 会解决我的问题吗?

    我有哪些替代 CB 的方法?

任何帮助将不胜感激。非常感谢!

编辑

当我尝试像BTLE sample 那样以块的形式发送数据时,我得到以下响应:

// NSLog - data that is written on the peripheral
// Chunk 1 : <2047d001 0f002000 315b0011 b4425543 41524553>
// Chunk 2 : <54202020 20202020 20202020 20202020 20202020>
// Chunk 3 : <20202020 2009059b 56210988 b9b50408 02c7123d>

// Write to peripheral
[self.twCurrentPeripheral writeValue:chunk1 forCharacteristic:self.twCharacteristic type:CBCharacteristicWriteWithoutResponse];
[self.twCurrentPeripheral writeValue:chunk2 forCharacteristic:self.twCharacteristic type:CBCharacteristicWriteWithoutResponse];
[self.twCurrentPeripheral writeValue:chunk3 forCharacteristic:self.twCharacteristic type:CBCharacteristicWriteWithResponse];

// NSLog - Response from peripheral
// Data update char : <20470000 04d00101 00ab42>
// Data update char : <204700>
// Data update char : <0004d001 0100ab42>
// Data update char : <204700>
// Data update char : <0504d001 032c6bcf>

正确的响应应该是(就像在 android 版本中一样):

// Response <20470000 04d00101 00ab42>
// Response <20470000 04d00105 006786>

【问题讨论】:

您可以将消息分成多个部分。我不做 iOS 的东西,但假设它真的只是 >20 字节是不开心的,你可以通过简单的数据分段来解决它。 @NathanielWaggoner 设备将每个数据块视为命令,它不会等待最后一段。我不知道是否需要指示每个数据包或整个消息的长度以及在何处附加此字节标志。 查看BTLETransfer sample,它完全符合您的要求。 @allprog 请查看更新后的问题。 当然,这样不行。进一步分析 BTLE 示例。你会看到在你的应用程序中必须实现更多的传输控制,简单地按顺序发送写请求很可能会失败。另外,查看其他相关的 SO 问题,我们已经多次回答这些问题。核心蓝牙编程指南也包含有用的信息。 【参考方案1】:

您需要以 20 字节的方式发送数据。每个数据包的大小应为 20 字节。另一端(BLE 中心)应该接受数据包并保存它们,直到他得到他正在等待的所有数据包。为此,您必须创建某种协议: 发送消息的类型,然后是消息的长度(以字节为单位),并且中心应该读取此标头,然后将他正在等待的“长度”字节保存在此消息中,然后解析整个数据。

请注意,当有很多数据包要发送非常快时,IOS可能会发送一些数据包失败,所以在调用时

 success = [self.peripheral updateValue:chunk forCharacteristic:myChar onSubscribedCentrals:nil];

success 会告诉你发送是否成功,如果不是你需要重新发送这个数据包。 在这种情况下,您应该实现 IOS BLE 协议CBPeripheralManagerDelegate

peripheralManagerIsReadyToUpdateSubscribers 方法中,您应该再次尝试发送相同的数据包。

【讨论】:

我正在编写运行在 iOS 设备上的 BLE Central,而不是外围设备【参考方案2】:

您需要将数据分块为 20 字节长度的片段,这部分是正确的。如果您使用“写响应”方法,那么在发送下一条数据之前,您应该等待在您的外围委托上发生peripheral:didWriteValueForCharacteristic:error: 回调,然后再发送下一条。在“无响应写入”的情况下,您应该在发送下一个块之前等待。您在 writeValue 调用中添加的内容将被缓冲。如果缓冲区已满,您的通话将被挂断。

【讨论】:

"如果是“写无响应”,您应该等待再发送下一个块。" - 你应该等多久,为什么? writeValue:(...) 在返回之前没有完成写入吗?没有缓冲或队列吗? @DarrenBlack 请查看我回答中的最后两句话。使用无响应写入时,您不会在发生或根本发生时收到通知。

以上是关于在 iOS 中向外部蓝牙设备写入 >20 个字节的主要内容,如果未能解决你的问题,请参考以下文章

ios 核心蓝牙与外部 BLE 设备配对

iOS 蓝牙

IOS蓝牙设备数据回调的坑

iOS之CoreBluetooth

iOS-蓝牙设备的唯一标识问题

如何通过外部附件框架使用蓝牙 PAN 配置文件