【问题标题】:Android BLE: knowing MTU on the GattServer sideAndroid BLE:了解 GattServer 端的 MTU
【发布时间】:2016-08-10 18:02:16
【问题描述】:

我已经在 Android 上实现了 BLE 通信。我正在使用requestMtu 在客户端协商 MTU。这很有效,因为客户端在onMtuChanged 上获得了 MTU 更改。但是,我仍然没有办法知道服务器端的 MTU,只有客户端。我实现了自己的碎片/分段机制,因为有时我会发送合理数量的数据。我想根据 MTU 大小对数据进行分段以加快通信速度。我目前在服务器端一次发送 20 个字节,这可以工作但速度较慢。有没有办法在服务器上获取 MTU?

【问题讨论】:

    标签: android bluetooth bluetooth-lowenergy


    【解决方案1】:

    我完成这项工作的方式是等待连接,然后与通过onConnectionStateChange(...) 函数连接的设备创建连接。

    private final BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
      @Override
      public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
          if (newState == Bluetooth.STATE_CONNECTED)
            device.connectGatt(MainActivity.this, false, mGattCallback);
          super.onConnectionStateChange(device, status, newState);
    }
    

    这允许我在成功连接时请求Mtu()。

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
          if (newState == Bluetooth.STATE_CONNECTED) {
            gatt.requestMtu(512);
          }
          super.onConnectionStateChange(gatt, status, newState);
    
        }
      };
    

    【讨论】:

    • 非常感谢伙计。不过有一个疑问:MTU 更改请求是否必须从服务器发起才能正常工作,还是双方都必须从各自的一方请求 MTU 更改:有点握手,因为我所做的和工作的对我来说..?
    • 但是如果 BluetoothGattServerCallBack 在服务器端,而 BluetoothGattCallBack 在客户端......我如何调用方法 device.connectGatt(MainActivity.this, false, mGattCallBack);如果 mGattCallBack 必须在客户端一侧,则来自 BluetoothGattServerCallBack?
    【解决方案2】:

    requestMtu 调用将导致客户端和服务器之间的 Gatt MTU 交换。较小的 mtu 将是最后使用的。 如果想知道服务器端的mtu大小,只要给“requestMtu”调用一个足够大的参数,在“onMtuChanged”中得到结果。 或者,在平台上查看你的 btsnoop 文件,你会得到服务器上的 mtu 大小。

    【讨论】:

    • 但是服务端不存在onMtuChanged方法。如何获得 MTU?
    【解决方案3】:

    BluetoothGattServerCallback 有方法onMtuChanged 可以覆盖并在协商后直接获取MTU(在中心侧请求后):

    @Override
    public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
       super.onMtuChanged(gatt, mtu, status);
       this.mtu = mtu;
       Log.i(TAG, "New MTU: " + mtu + " , Status: " + status + " , Succeed: " + (status == BluetoothGatt.GATT_SUCCESS));
    }
    

    【讨论】:

    • 我的回调有不同的参数: onMtuChanged(BluetoothGatt gatt, int mtu, int status) { super.onMtuChanged(mBluetoothGatt,mtu, status); Log.i("BLEService", "新的 MTU 是 " + mtu); }
    【解决方案4】:

    根据 3.F 3.2.8 中的蓝牙核心规范文档:

    同时充当服务器和客户端的设备应使用 客户端 Rx MTU 和服务器 Rx MTU 的值相同。

    因此,使用您通过 GATT 客户端 API 获得的 MTU,它必须相同。

    【讨论】:

    • 我没有将设备同时用作服务器和客户端。还有别的吗?
    • Android 实现了客户端和服务器,所以它们都在这里,即使你没有明确地使用它们。即使您不使用客户端 API 中的任何其他机制,这也应该为您提供所需的值。
    • 嗯,是的,但我只是在网络上宣传该设备,而不是扫描。如果设备同时执行这两种操作,您的建议是有道理的,但我仍然不明白如何在不扫描的情况下获取服务器上的 MTU。
    • 您错过了属性协议是对称的事实,即使设备是外围设备,设备上总是有服务器。 Peripheral/Central 的区别只是谁在协议的较低级别发起连接的问题。
    • 你在哪里读到的?我能够在 Android 和 iOS 中将设备专门作为外围设备启动。但无论如何,问题仍然存在。如果设备没有扫描(哪些外围设备不应该因为它是电池密集型的)我无法知道 Android 上的 MTU。你的意思是我还是要扫描?
    【解决方案5】:

    BluetoothGattServerCallback 现在的正确签名是 onMtuChanged(BluetoothDevice device, int mtu)

    对于 C#,我使用了这个签名:

            public override void OnMtuChanged(BluetoothDevice gatt, int mtu)
            {
                System.Diagnostics.Debug.WriteLine("OnMtuChanged: mtu is {0}", mtu);
            }
    

    【讨论】:

      猜你喜欢
      • 2020-07-20
      • 1970-01-01
      • 1970-01-01
      • 2018-08-04
      • 1970-01-01
      • 1970-01-01
      • 2021-01-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多