DEV Community

HarmonyOS
HarmonyOS

Posted on

BLE Bluetooth setCharacteristicChangeNotification Interface Reports Errors 2900099 or 2900007

Read the original article:BLE Bluetooth setCharacteristicChangeNotification Interface Reports Errors 2900099 or 2900007

Problem Description

During BLE Bluetooth application development, calling the setCharacteristicChangeNotification interface may result in errors 2900099 or 2900007. This article analyzes the causes and provides solutions.

Background Knowledge

During BLE Bluetooth application development, calling the setCharacteristicChangeNotification interface results in errors 2900099 or 2900007. Key code as follows:

import { ble, constant } from '@kit.ConnectivityKit';
import { abilityAccessCtrl, common, PermissionRequestResult } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct setCharacteristicChangeNotification {
  @State gattClient: ble.GattClientDevice | undefined = undefined;
  // The server-side virtual MAC address needs to be modified according to the actual situation when in use.
  @State deviceMAC: string = 'XX:XX:XX:XX:XX:XX';
  // The server-side specifies the service UUID, which needs to be modified according to the actual situation when used.
  @State serviceUuid: string = '0000XXXX-0000-1000-8000-00805F9B34FB';
  uiContext = this.getUIContext();

  aboutToAppear(): void {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    atManager.requestPermissionsFromUser(this.uiContext?.getHostContext() as common.UIAbilityContext,
      ['ohos.permission.ACCESS_BLUETOOTH'], (err: BusinessError, data: PermissionRequestResult) => {
        if (err) {
          console.error(`requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
        } else {
          console.info(`data:${JSON.stringify(data)}`);
        }
      })
  }

  connect() {
    // Create a client-side instance
    this.gattClient = ble.createGattClientDevice(this.deviceMAC)
    // Subscribe to BLE Bluetooth connection status monitoring event
    this.onBLEConnectionStateChange()
    // Connect to the server-side BLE Bluetooth.
    this.gattClient.connect()
  }

  onBLEConnectionStateChange() {
    this.gattClient?.on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {
      if (state.state === constant.ProfileConnectionState.STATE_CONNECTED) {
        // After successful connection, proceed to retrieve all services from the server and negotiate the MTU.
        this.getServices()
      }
    })
  }

  getServices() {
    this.gattClient?.getServices().then((result: Array<ble.GattService>) => {
      result.filter(item => {
        // Select the specified feature value service and configure notification change capabilities.
        if (item.serviceUuid === this.serviceUuid) {
          // Negotiate MTU with the server
          this.gattClient?.setBLEMtuSize(128)
          let characteristic: ble.BLECharacteristic = item.characteristics[0];
          this.gattClient?.setCharacteristicChangeNotification(characteristic, true);
        }
      })
    });
  }

  build() {
    Column() {
      Button() {
        Text('Connect to BLE Bluetooth and initiate the request.')
      }
      .onClick(() => {
        // Connect to BLE Bluetooth and initiate a setCharacteristicChangeNotification request.
        this.connect();
      })
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • 2900007 indicates interface call timeout. When the client sends a request to the server but doesn’t receive a response within a certain time, the client displays this error code.
  • 2900099 indicates interface call operation failure. This error code generally appears when the interface call is blocked.

Troubleshooting Process

Analysis Conclusion

The error may be caused by incorrect characteristic parameters, which need to be confirmed through debugging or log printing to determine if the characteristic parameters are correct.
Before calling the setCharacteristicChangeNotification interface, the setBLEMtuSize interface is usually called first to negotiate the MTU data transfer size with the server. Then the getServices interface is called to obtain the server’s characteristic value services.
Therefore, the setCharacteristicChangeNotification interface should be called only after the setBLEMtuSize and getServices interfaces have been successfully called.

Solution

It is recommended to create the characteristic object by assigning values one by one, and then modify the calling logic of the setBLEMtuSize, getServices, and setCharacteristicChangeNotification interfaces.

Reference code as follows:

import { ble, constant } from '@kit.ConnectivityKit';
import { abilityAccessCtrl, common, PermissionRequestResult } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct setCharacteristicChangeNotification {
  @State gattClient: ble.GattClientDevice | undefined = undefined;
  // The server-side virtual MAC address needs to be modified according to the actual situation when in use.
  @State deviceMAC: string = 'XX:XX:XX:XX:XX:XX';
  // The server-side specifies the service UUID, which needs to be modified according to the actual situation when used.
  @State serviceUuid: string = '0000XXXX-0000-1000-8000-00805F9B34FB';
  uiContext = this.getUIContext();

  aboutToAppear(): void {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    atManager.requestPermissionsFromUser(this.uiContext?.getHostContext() as common.UIAbilityContext,
      ['ohos.permission.ACCESS_BLUETOOTH'], (err: BusinessError, data: PermissionRequestResult) => {
        if (err) {
          console.error(`requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
        } else {
          console.info(`data:${JSON.stringify(data)}`);
        }
      })
  }

  connect() {
    // Create a client-side instance
    this.gattClient = ble.createGattClientDevice(this.deviceMAC)
    // Subscribe to BLE Bluetooth connection status monitoring event
    this.onBLEConnectionStateChange()
    // Subscribe to MTU monitoring events
    this.BLEMtuChange()
    // Connect to the server-side BLE Bluetooth.
    this.gattClient.connect()
  }

  onBLEConnectionStateChange() {
    this.gattClient?.on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {
      if (state.state === constant.ProfileConnectionState.STATE_CONNECTED) {
        // Connection successful. First, negotiate the MTU with the server, with a parameter range of 23 to 517.
        this.gattClient?.setBLEMtuSize(128)
      }
    })
  }

  BLEMtuChange() {
    this.gattClient?.on('BLEMtuChange', (mtu: number) => {
      // MTU negotiation succeeded, and the getServices interface was called to retrieve the server service.
      console.info(`The negotiation was successful, and the MTU parameter is:${mtu}`);
      this.getServices()
    });
  }

  getServices() {
    this.gattClient?.getServices().then((result: Array<ble.GattService>) => {
      result.filter(item => {
        // Select the specified feature value service and configure notification change capabilities.
        if (item.serviceUuid === this.serviceUuid) {
          let descriptors: Array<ble.BLEDescriptor> = [];
          let arrayBuffer = new ArrayBuffer(8);
          let descV = new Uint8Array(arrayBuffer);
          descV[0] = 11;
          let arrayBufferC = new ArrayBuffer(8);
          let characteristic: ble.BLECharacteristic = {
            serviceUuid: item.serviceUuid,
            characteristicUuid: item.characteristics[0].characteristicUuid,
            characteristicValue: arrayBufferC,
            descriptors: descriptors
          };
          this.gattClient?.setCharacteristicChangeNotification(characteristic, true,(err: BusinessError) => {
            if (err) {
              console.error('notifyCharacteristicChanged callback failed');
            } else {
              console.info('notifyCharacteristicChanged callback successful');
            }
          });
        }
      })
    });
  }

  build() {
    Column() {
      Button() {
        Text('Connect to BLE Bluetooth and initiate the request.')
      }
      .onClick(() => {
        // Connect to BLE Bluetooth and initiate a setCharacteristicChangeNotification request.
        this.connect();
      })
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Add Bluetooth ACCESS_BLUETOOTH permission in the requestPermissions of module.json5.

Verification Result

kbs--60c03aba0aff4014b74319beaed6b70e-280c9.png

Constraints and Limitations

  • This example supports API Version 19 Release and above.
  • This example supports HarmonyOS 5.1.1 Release SDK and above.
  • This example requires DevEco Studio 5.1. 1 Release or above for compilation and execution.

Written by Taskhyn Maksim

Top comments (0)