前言 笔者在上文中记录了蓝牙的基本使用主要记录了1-4的内容。
笔者在本文中会继续记录5-7的内容及一小部分拆包组包的思路。
- 创建蓝牙中心管理者;
- 扫描发现外围设备;
- 连接设备;
- 发现服务,发现特征值;
- 给指定外设的特征添加监听
- 给已连接设备发送数据
- 外设给中心设备通知数据时,监听过指定外设特征值的方法回调。 在本文中会继续补充完后续内容。
给指定外设的特征添加监听
给指定外设的特征添加监听可以使用如下代码。
[peripheral setNotifyValue:YES forCharacteristic:subCharacter];
给已连接设备发送数据
给已连接设备发送数据,其实就是App 向设备端写入数据,写入数据时可以使用如下代码。来给指定外设指定特征值写入指定类型的数据,最后的写数据CBCharacteristicWriteWithResponse参数用于控制,当App向指定特征写数据成功时,会收到回调,如果我们使用CBCharacteristicWriteWithoutResponse,那么我们就不会收到数据是否写成功的回调。
[_blePeripheral writeValue:absoluteData forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithResponse];
当App端成功向设备端写入数据时,会回调如下设备端更新特征值成功的回调方法。当外设成功收到App端写入的数据并且给App以响应时,会回调如下代理方法。下边的这个代理方法可以用于我们判断我们是否写成功了一个数据包,或许判断是否写完整了多个拆分好的数据包。如下代理方法中还有error字段,我们可以判断这个error是否为空来判断设备收成功数据与否。
//! 设备端告知App端是否收数据成功
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
}
当App端写数据成功时,会回调如下代理方法。下边的这个代理方法可以用于如果我们向设备写入的数据量比较大时,需要把数据包进行拆分,拆包之后,再进行数据发送。通过如下方法我们可以知道App是否写数据成功。用于控制我们是否要继续发送后续拆分的下一个数据包。
// Tells the delegate that the peripheral successfully set a value for the characteristic.
//! 写成功时,App端立即得到响应的回调
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
QiLog(@"error:%@", error);
}
拆包思路
最后我们简单聊一下拆包的思路。
简单来说,一般一个数据包分为报头和后边传输的内容。像报头的话一般字节数是固定的。我们主要判断要发送的数据的字节数是否超过了一个数据包所能包含的数据内容的字节数,如果没有超过一个包所能传输的数据。那么就不用拆包。否则就要进行拆包处理。当然拆包的话,我们肯定会有相应的比特位控制是否是第一个包,是否是最后一个数据包。会有指定的比特为指定数据包所属的消息。
有拆包就会有组包。组包就是对拆包的逆向操作。
组包和拆包会用到比较多的或运算、与运算等操作。我们通过位运算可以得到指定字节或起来的结果,通过与运算可以得到指定范围比特的值。笔者还记得是在大学的电工学、离散数学、及计算机网络、计算机组成原理课程中都有学到过相关的知识,没想到在拆包、组包部分就会有一个好的应用。
另外聊一下,我们的数据包的二进制内容,有的是知道要传入字节的值的像这种情况,可以使用如下代码。这里笔者就先举个小例子。
Byte bytes[] = {0x10, 0x11, 0x12, 0x13};
NSData *data = [[NSData alloc] initWithBytes:bytes length:sizeof(bytes)];
像更多的数据内容的拼接,有的是字符串转二进制、有的是字典转二进制、或其他方式。
关于蓝牙的数据包的组包、拆包、组装二进制数据的更多的内容,笔者会在之后的文章中进行记录。谢谢大家。
参考学习网址
Core Bluetooth Programming Guide
蓝牙
蓝牙低功耗
深入浅出讲解低功耗蓝牙(BLE)协议栈