如何解决蓝牙/星闪协商MTU参数失败的问题
=====================

#### 问题现象

在蓝牙/星闪功能开发过程中，协商MTU时，有时会出现[2900099](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/errorcode-bluetoothmanager#section2900099)/[1009700099](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/errorcode-nearlink#section1009700099)错误的问题，该如何解决？

#### 背景知识

*   BLE蓝牙提供了[setBLEMtuSize](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-bluetooth-ble#setblemtusize)接口用于client端同server端协商MTU（最大传输单元，取值范围23~517）大小。
*   星闪提供了[requestMtuSize](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/nearlink-ssap#requestmtusize)接口用于client端同server端协商MTU（最大传输单元，取值范围22~512）大小。
*   蓝牙/星闪同server端协商MTU前，需要保证client端同server端处于连接的状态。

#### 问题定位

*   排查在协商MTU前，蓝牙/星闪client端同server端是否断开了连接。
*   检查协商的MTU参数范围是否合理。

#### 分析结论

*   结论一：setBLEMtuSize/requestMtuSize接口调用时机不对，需要在蓝牙/星闪client端和server端连接成功后，才能调用setBLEMtuSize/requestMtuSize接口协商MTU参数。
*   结论二：协商的MTU参数设置不在取值范围内。

#### 修改建议

协商MTU前，需保证client端同server端处于连接的状态，且协商的MTU参数需要设置在取值范围内。蓝牙/星闪端代码参考如下：

import { ble, constant } from '@kit.ConnectivityKit';
import { ssap } from '@kit.NearLinkKit';

@Entry
@Component
struct BleAndSsapSetMtu {
  @State gattClient: ble.GattClientDevice | undefined = undefined;
  @State ssapClient: ssap.Client | undefined = undefined;

  _// 设置ble端mtu_
  setBleMtu() {
    _// 创建client端实例，bleMac为server端虚拟mac地址，需要提前获取_
    this.gattClient = ble.createGattClientDevice('bleMac');
    _// 订阅ble蓝牙连接状态监听事件_
    this.onBLEConnectionStateChange();
    _// 订阅MTU协商结果监听事件_
    this.BLEMtuChange();
    _// 连接server端ble蓝牙_
    this.gattClient.connect();
  }

  onBLEConnectionStateChange() {
    this.gattClient?.on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {
      _// state.state返回结果为2时，表示client端同server端成功建立了连接。_
      if (state.state === constant.ProfileConnectionState.STATE\_CONNECTED) {
        _// 调用setBLEMtuSize接口，同server端协商MTU，参数取值范围23~517。_
        this.gattClient?.setBLEMtuSize(128);
      }
    });
  }

  BLEMtuChange() {
    this.gattClient?.on('BLEMtuChange', (mtu: number) => {
      _// MTU协商结果监听回调，回调触发，表示协商成功。_
      console.info(\`BLEMtuChange, mtu: ${mtu}\`);
    });
  }

  _// 设置星闪端mtu_
  setSsapMtu() {
    _// 创建client端实例，ssapMac为server端虚拟mac地址，需要提前获取_
    this.ssapClient = ssap.createClient('ssapMac');
    _// 订阅ble蓝牙连接状态监听事件_
    this.onConnectionStateChange();
    _// 订阅MTU协商结果监听事件_
    this.ssapMtuChange();
    _// 连接server端ble蓝牙_
    this.ssapClient.connect();
  }

  onConnectionStateChange() {
    this.ssapClient?.on('connectionStateChange', (state: ssap.ConnectionChangeState) => {
      _// state.state返回结果为1时，表示client端同server端成功建立了连接。_
      if (state.state === 1) {
        _// 调用requestMtuSize接口，同server端协商MTU，参数取值范围22~512，默认值为256字节。_
        this.ssapClient?.requestMtuSize(128);
      }
    });
  }

  ssapMtuChange() {
    this.ssapClient?.on('mtuChange', (mtu: number) => {
      _// MTU协商结果监听回调，回调触发，表示协商成功。_
      console.info(\`mtuChange, mtu:  ${mtu}\`);
    });
  }

  build() {
    Column() {
      Button('连接ble蓝牙，并协商MTU').onClick(() => {
        _// 连接ble蓝牙，并协商MTU_
        this.setBleMtu();
      }).margin(15);

      Button('连接星闪，并协商MTU').onClick(() => {
        _// 连接星闪，并协商MTU_
        this.setSsapMtu();
      });
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.SpaceAround);
  }
}

#### 常见FAQ

Q：在BLE蓝牙开发流程中，setBLEMtuSize()接口在什么时候调用最合适？

A：setBLEMtuSize()方法只能在调用[connect()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-bluetooth-ble#connect)接口成功连接上蓝牙之后调用。建议在调用[getServices()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-bluetooth-ble#getservices)接口获取server端支持的所有服务能力之前调用。