Android BLE 开发指南二:广播数据解析

广播数据结构

BLE 外设开始工作时,会发出广播让中心设备发现,广播的数据包中带有外设的相关信息,比如设备的MAC地址,名字,Service 列表的 UUID 等等。

广播包的数据结构都是固定的,按照蓝牙相关规范规定好的。
每个包都是 31 字节,数据包中分为有效数据(significant)和无效数据(non-significant)两部分。

有效数据部分: 包含若干个广播数据单元 AD Structure。如图中所示,AD Structure 的组成是:第一个字节是长度值 Len,表示接下来的 Len 个字节是数据部分。数据部分的第一个字节表示数据的类型 AD Type,剩下的 Len - 1 个字节是真正的数据 AD data。其中 AD type 非常关键,决定了 AD Data 的数据代表的是什么,怎么解析。

无效数据部分: 因为广播包的长度必须是 31 个 byte,如果有效数据部分不到 31 自己,剩下的就用 0 补全。这部分的数据是无效的,解释的时候,忽略即可。
ble_ad_structure

AD Type 类型

AD Type 包括如下类型:

Flags: TYPE = 0x01 这个数据用来标识设备 LE 物理连接的功能。DATA 是 0 到多个字节的 Flag 值,每个 bit 上用 0 或者 1 来表示是否为 True。如果有任何一个 bit 不为 0,并且广播包是可连接的,就必须包含此数据。各 bit 的定义如下:

bit 0: LE 有限发现模式
bit 1: LE 普通发现模式
bit 2: 不支持 BR/EDR
bit 3: 对 Same Device Capable(Controller) 同时支持 BLE 和 BR/EDR
bit 4: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
bit 5..7: 预留

Service UUID 广播数据中一般都会把设备支持的 GATT Service 广播出来,用来告诉外面本设备所支持的 Service。有三种类型的 UUID:16 bit, 32bit, 128 bit。广播中,每种类型类型有有两个类别:完整和非完整的。这样就共有 6 种 AD Type。

非完整的 16 bit UUID 列表: TYPE = 0x02;
完整的 16 bit UUID 列表: TYPE = 0x03;
非完整的 32 bit UUID 列表: TYPE = 0x04;
完整的 32 bit UUID 列表: TYPE = 0x05;
非完整的 128 bit UUID 列表: TYPE = 0x06;
完整的 128 bit UUID 列表: TYPE = 0x07;

Local Name 设备名字 DATA 是名字的字符串。Local Name 可以是设备的全名,也可以是设备名字的缩写,其中缩写必须是全名的前面的若干字符。

设备全名: TYPE = 0x08
设备简称: TYPE = 0x09

TX Power Level: TYPE = 0x0A 表示设备发送广播包的信号强度。DATA 部分是一个字节,表示 -127 到 + 127 dBm。

带外安全管理(Security Manager Out of Band):TYPE = 0x11 :DATA 也是 Flag,每个 bit 表示一个功能:

bit 0: OOB Flag,0 表示没有 OOB 数据,1 表示有
bit 1: 支持 LE
bit 2: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
bit 3: 地址类型,0 表示公开地址,1 表示随机地址

外设(Slave)连接间隔范围:TYPE = 0x12 :数据中定义了 Slave 最大和最小连接间隔,数据包含 4 个字节:

前 2 字节:定义最小连接间隔,取值范围:0x0006 ~ 0x0C80,而 0xFFFF 表示未定义;
后 2 字节:定义最大连接间隔,同上,不过需要保证最大连接间隔大于或者等于最小连接间隔。

服务搜寻:外围设备可以要请中心设备提供相应的 Service。其数据定义和前面的 Service UUID 类似:

16 bit UUID 列表: TYPE = 0x14
32 bit UUID 列表: TYPE = 0x??
128 bit UUID 列表: TYPE = 0x15

Service Data: Service 对应的数据。

16 bit UUID Service: TYPE = 0x16, 前 2 字节是 UUID,后面是 Service 的数据;
32 bit UUID Service: TYPE = 0x??, 前 4 字节是 UUID,后面是 Service 的数据;
128 bit UUID Service: TYPE = 0x??, 前 16 字节是 UUID,后面是 Service 的数据;

公开目标地址:TYPE = 0x17,表示希望这个广播包被指定的目标设备处理,此设备绑定了公开地址,DATA 是目标地址列表,每个地址 6 字节。

随机目标地址:TYPE = 0x18,定义和前一个类似,表示希望这个广播包被指定的目标设备处理,此设备绑定了随机地址,DATA 是目标地址列表,每个地址 6 字节。

Appearance:TYPE = 0x19,DATA 是表示了设备的外观。

厂商自定义数据: TYPE = 0xFF: 厂商自定义的数据中,前两个字节表示厂商 ID,剩下的是厂商自己按照需求添加,里面的数据内容自己定义。

这里列举了部分常见的数据,还有一些其他的数据。

广播数据解析

在Android中,扫描蓝牙设备有两套api,一套是Android4.3上面的,扫描的广播数据需要自己解析;另一套是Android5.0上面的,扫描的广播数据,系统会帮我们解析好。
下面是Android4.3上面的开启扫描代码:

	//扫描结果回调
    val leScanCallback = object : BluetoothAdapter.LeScanCallback {
        override fun onLeScan(device: BluetoothDevice, rssi: Int, scanRecord: ByteArray) {
			//回调在子线程
			ParseBluetoothAdData.parse(scanRecord)//解析广播数据
        }
    }
	val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
	if (bluetoothAdapter.isEnabled) {//蓝牙为打开状态
	    bluetoothAdapter.startLeScan(leScanCallback)//开始扫描,传入回调接口
	}

下面是解析广播的代码,这里只解析了UUID,厂商数据和设备名字:

object ParseBluetoothAdData {
    fun parse(bytes: ByteArray): AdData {
        val baseUuid = "%08X-0000-1000-8000-00805F9B34FB"
        val uuidS = ArrayList<UUID>()
        var manufacturerByte: ByteArray? = null
        var name: String? = null
        val buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN)
        while (buffer.remaining() > 2) {
            var length = buffer.get().toInt() and 0xff
            if (length == 0) {
                break
            }
            val type = buffer.get().toInt() and 0xff
            length--
            when (type) {
                0x01 -> {
                    buffer.position(buffer.position() + length)
                }
                0x02, 0x03, 0x14 -> {
                    while (length >= 2) {
                        uuidS.add(UUID.fromString(String.format(baseUuid, buffer.short)))
                        length -= 2
                    }
                }
                0x04, 0x05 -> {
                    while (length >= 4) {
                        uuidS.add(UUID.fromString(String.format(baseUuid, buffer.int)))
                        length -= 4
                    }
                }
                0x06, 0x07, 0x15 -> {
                    while (length >= 16) {
                        val lsb = buffer.long
                        val msb = buffer.long
                        uuidS.add(UUID(msb, lsb))
                        length -= 16
                    }
                }
                0xff -> {//厂商自定义数据
                    manufacturerByte = ByteArray(length)
                    buffer.get(manufacturerByte, 0, length)
                }
                0x09, 0x08 -> {//全名,简短名
                    val byteArray = ByteArray(length)
                    buffer.get(byteArray)
                    name = String(byteArray)
                }
                else -> {
                    buffer.position(buffer.position() + length)
                }
            }
        }
        return AdData(uuidS, manufacturerByte, name)
    }

    class AdData(val UUIDs: ArrayList<UUID>, val manufacturerByte: ByteArray?, val name: String?)
}

以上内容摘自

BLE 广播数据解析

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您解答Android BLE广播过程中更新广播数据的问题。在Android BLE中,可以通过BluetoothLeAdvertiser对象的updateAdvertiseData()方法来更新BLE广播数据。以下是更新BLE广播数据的步骤: 1. 创建AdvertiseData对象:创建一个新的AdvertiseData对象,用于更新广播数据。 2. 调用updateAdvertiseData()方法:调用BluetoothLeAdvertiser对象的updateAdvertiseData()方法,传入新的AdvertiseData对象。 例如,以下代码演示了如何在BLE广播过程中更新广播数据: ``` private BluetoothLeAdvertiser mAdvertiser; private AdvertiseData mAdvertiseData; // 初始化广播数据 private void initAdvertiseData() { mAdvertiseData = new AdvertiseData.Builder() .setIncludeDeviceName(true) .addServiceUuid(new ParcelUuid(SERVICE_UUID)) .build(); } // 开始广播 private void startAdvertise() { mAdvertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser(); mAdvertiser.startAdvertising(settings, mAdvertiseData, null); } // 更新广播数据 private void updateAdvertiseData() { AdvertiseData newAdvertiseData = new AdvertiseData.Builder() .setIncludeDeviceName(true) .addServiceUuid(new ParcelUuid(SERVICE_UUID)) .addManufacturerData(MANUFACTURER_ID, new byte[]{0x01, 0x02, 0x03}) .build(); mAdvertiser.updateAdvertiseData(newAdvertiseData, null); } ``` 在上面的代码中,initAdvertiseData()方法用于初始化广播数据,startAdvertise()方法用于开始广播,updateAdvertiseData()方法用于更新广播数据。在updateAdvertiseData()方法中,创建一个新的AdvertiseData对象,并调用updateAdvertiseData()方法更新广播数据。 需要注意的是,更新BLE广播数据可能会影响广播性能和功耗。因此,需要谨慎使用,并根据具体需求进行优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值