之前还以为BLE也就GATT那些东西嘛,没什么好说的了

其实

BLE或者说,蓝牙,的广播帧还是有很多很多奥秘的.还是有些东西可以拿来琢磨琢磨,学习学习

Context

至于为什么要突然学习这个东西,肯定是和新产品有关系的,具体的,可以等上市之后,买来一个试试看啊,哈哈哈哈哈哈

另一个原因,这个东西的官方文档真的很难找,至少在 www.bluetooth.com 上面我就没有看到讲述广播帧结构的文档,最后在TI的一个文档中,终于找到了相关的内容.

平时用BLE只要是在连接成功之后,搜索Service和Characteristc,后进行读写操作.这样的工作模式,只能一对一,不能做到一对多.但是利用了广播信息,可以做到一对多的发送消息…虽然这时候不能反过来写入.

Let’s go

我们先来上一张图片,看看Bluetooth到底广播了什么吧

AD

我是做上位机软件开发的,所以只关心应用层的东西,那么上面图片中,iOS和Android能被处理的数据是标红的那一段

一共31个字节,看起来好像不是很足够,但是由于协议是规定好了的,所以对应的位置表示对应的数据,还是够用的.

说说我们熟悉的一些广播信息吧:(iOS端CoreBluetooth的广播帧字典的Key)

1.LocalName (外设名称)
2.ServiceUUIDs (Service列表)
3.ManufacturerData (制造商数据)
4.IsConnectable (是否可连)

下面再给点儿我第一次知道的广播信息类型:

1.ServiceData (某个Service的广播数据)
2.TxPowerLevel (传输信号强度~.~,用来计算损耗用...好像暂时没啥用处,反正我也不会算)
3.OverflowServiceUUIDs (没懂他和ServiceUUIDs的区别~.~)
4.SolicitedServiceUUIDs (貌似和从设备没啥关系~.~)

说实话,平时用到的只有ServiceUUIDs,因为我们用这个来过滤出来我们需要的蓝牙外设,也用这个来区分不同的硬件.

LocalName的话iOS和Android都已经自动提取并封装成简单的接口了

上面是软件层面的东西,我们来看看硬件层面的呗~

一个广播帧会有很多类型的数据,每个类型有自己的type,上位机也是通过type字段来分辨数据是UUID还是Name或者其他的东西~

每一类数据都由3部分组成:

1.length of data (这个type的总长度)
2.type (定义type)
3.data (根据type的协议来填入数据)

这里简单的列举几个type:

0x02 不完整的16位UUID
0x04 不完整的32位UUID
0x06 不完整的128位UUID
0x08 设备全名
0x16 16位UUID的Service Data
0x20 32位UUID的Service Data
0x21 128位UUID的Service Data
0xFF 制造商自定义的数据

Example of Peripheral and Bluetooth Central

一台名叫VK的外设,公布了一个Service UUID 3344,5566;其中3344的Service Data是”0xAA,0xBB,0xCC”,制造商的自定义数据是”0x12,0x34,0x56,0x78”

那么他的广播数据是~

04 08 56 4B 05 02 44 33 66 55 06 16 44 33 cc bb aa 07 FF 00 00 78 56 34 12

拆分数据分析分析

04 08 56 4B
长度4 设备完整名称 V K

05 02 44 33 66 55
长度5 不完整的16位列表 3344 5566

06 16 44 33 cc bb aa
长度6 16位UUID的ServiceData UUID=3344 数据是 AA BB CC

07 FF 00 00 78 56 34 12
长度7 厂商自定义数据 厂商ID=0000 厂商自定义数据=12345678

如果有错误不要打我…

iOS端解析广播数据

-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
    // 名字的字符串
    NSLog(@"Name %@",advertisementData[CBAdvertisementDataLocalNameKey]);
    // CBUUID的NSArray
    NSLog(@"Service UUID %@",advertisementData[CBAdvertisementDataServiceUUIDsKey]);
    // Key为CBUUID,Value为NSData的NSDictionary
    NSLog(@"Service Data %@",advertisementData[CBAdvertisementDataServiceDataKey]);
    // 制造商的数据NSData
    NSLog(@"ManufacturerData %@",advertisementData[CBAdvertisementDataManufacturerDataKey]);
}

Android端解析

@Override
    public void onLeScan(final BluetoothDevice device, int rssi,
            byte[] scanRecord) {
        // scanRecord 就是所有的广播数据呗
   }

iOS端为了隐私保护,做了各种各样奇怪的限定,所以不像Android那么爽,可以直接把广播帧的字节流都提取出来,所以就只能好好阅读协议,才能让iOS的App获取到想要的数据

相同的,Android虽然数据很开放,下位机可以不按照BLE协议去设置广播数据,Android App依然可以读得出来数据,但是解析数据就很头疼的样子了.

嗯,各有各的好处~

BTW

其中一个type是

0x17  Public Target Address
目标Mac地址

官方定义是

The Public Target Address data type defines the address of one or more intended recipients of an advertisement when one or more devices were bonded using a public address. This data type is intended to be used to avoid a situation where a bonded device unnecessarily responds to an advertisement intended for another bonded device.

what are you 弄啥嘞…

我YY他的用处就是,这个BLE设备只能被指定Mac地址的主机连接.

好啦,这次又学到了一点儿蓝牙的知识,写个文章当笔记.