Android Ble 通讯数据分包

背景:为什么Android 蓝牙通讯数据包默认情况下最多20个字节?

参考资料:Core_v4.2.pdf
MTU is not a negotiated value, it is an informational parameter that each device can specify independently. It indicates to the remote device that the local device can receive, in this channel, an MTU larger than the minimum required. All L2CAP implementations shall support a minimum MTU of 48 octets over the ACL- U logical link and 23 octets over the LE-U logical link; however, some protocols and profiles explicitly require support for a larger MTU. The minimum MTU for a channel is the larger of the L2CAP minimum 48 octet MTU and any MTU explicitly required by the protocols and profiles using that channel. (Note: the MTU is only affected by the profile directly using the channel. For example, if a service discovery transaction is initiated by a non service discovery profile, that profile does not affect the MTU of the L2CAP channel used for service discovery).

同一个局域网

core spec里面定义了ATT的默认MTU为23个bytes, 除去ATT的opcode一个字节以及ATT的handle 2个字节之后,剩下的20个字节便是留给GATT的
  • 关于自定义MTU

    • BluetoothGatt源码中,有可自定义MTU的方法,但是由于国内各个OEM厂商百花齐放,实际在自定义MTU时,效果不一,要么无法设置,要么设置成功不生效,都是坑
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public final class BluetoothGatt implements BluetoothProfile {

    ...

    /**
    * Request an MTU size used for a given connection.
    *
    * <p>When performing a write request operation (write without response),
    * the data sent is truncated to the MTU size. This function may be used
    * to request a larger MTU size to be able to send more data at once.
    *
    * <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate
    * whether this operation was successful.
    *
    * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
    *
    * @return true, if the new MTU value has been requested successfully
    */
    public boolean requestMtu(int mtu) {
    if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
    + " mtu: " + mtu);
    if (mService == null || mClientIf == 0) return false;

    try {
    mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
    } catch (RemoteException e) {
    Log.e(TAG,"",e);
    return false;
    }

    return true;
    }

    ...

    }

分析:

so:蓝牙通讯时,往往有些指令/数据会超过20个字节,此时需要分包处理。

  1. 无论怎么分,每包不能大于20个字节
  2. 考虑性能问题
  3. 考虑业务逻辑问题

示例:

  • 分包说白了就是一套通讯协议
    假设:一包数据的格式 -> 协议头 + 总包号 + 当前包号 + 命令号 + 内容 + 协议尾
协议 内容 长度(byte) 类型 示例
协议头 s 1 字符
总包号 1 16进制 2
当前包号 1 16进制 1
命令号 2 16进制 T0
内容 14 字符 12345678901234
协议尾 e 1 字符

如果按照上述方式,那么每包数据内实际有效的内容只有14个字节。

  • 现在向蓝牙设备发送一条指令(时区+时间):UTC+8 2019-04-24 16:50:26

    • 我们把这条指令命名为 T0

    用刚才的定义的协议进行分包:
    第一包:s21T0 UTC+8 2019-04e
    第二包:s22T0-24 16:50:26e

  • 反之,蓝牙设备向手机发送数据也可以用同一套协议,
    现在蓝牙设备向手机通知一条数据(电量|温度|湿度|时间|经度|纬度):95|27.5|49|2019-04-24 16:50:26|123.456789|123.456789
    我们把这条数据命名为 D0

    第一包:s41D095|27.5|49|201e
    第一包:s42D09-04-24 16:50:e
    第一包:s43D026|123.456789|e
    第一包:s44D0123.456789e

    • 手机在处理的时候,需要先判断当前指令的命令号

当然实际业务中通讯协议没有这么简单,可能把数据处理成16进制、2进制,或者通讯数据加密之类的。


系列文章:
Android Ble 广播数据分包:https://mecono.cn/2985357922.html

--- 青山不改 绿水长流,日后江湖相见,自当杯酒言欢,咱们就此别过。---

本文标题:Android Ble 通讯数据分包

文章作者:mecono

发布时间:2019年04月24日 - 15:04

最后更新:2019年12月19日 - 09:12

原始链接:https://mecono.cn/2485615358.html

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-ND 4.0许可协议。转载请注明出处!