• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# GATT-based BLE Connection and Data Transmission
2
3## Introduction
4Generic Attribute Profile (GATT) provides profile discovery and description services for the BLE protocol. It defines how ATT attributes are organized and exchanged over a BLE connection.<br>A GATT server (referred to as server in this topic) is a device that stores attribute data locally and provides data access to a remote GATT client paired via BLE. A GATT client (referred to as client in this topic) is a device that accesses data on the remote GATT server via read, write, notify, or indicate operations.
5
6## When to Use
7
8You can use the APIs provided by the **gatt** module to:
9- Connect to the server to read and write data.
10- Manage services on the server and respond to the requests from the client.
11
12## Available APIs
13
14For details about the APIs and sample code, see [@ohos.bluetooth.ble](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md).
15
16The following table describes the related APIs.
17
18| API                                     | Description                                                                                              |
19| ------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
20| connect()                                  | Connects the client to the remote BLE device.                                                                     |
21| disconnect()                               | Disconnects the client from the remote BLE device.                                                                 |
22| close()                                    | Closes this client to unregister it from the protocol stack. After this API is called, this **GattClientDevice** instance cannot be used any longer.|
23| getDeviceName()                            | Obtains the name of the remote BLE device for the client.                                                                         |
24| getServices()                              | Obtains all services of the remote BLE device for the client.                                                        |
25| readCharacteristicValue()                  | Reads a characteristic value of a service of the remote BLE device.                                                              |
26| readDescriptorValue()                      | Reads the descriptor contained in a characteristic of the remote BLE device.                                                        |
27| writeCharacteristicValue()                 | Writes a characteristic value to the remote BLE device.                                                                |
28| writeDescriptorValue()                     | Writes binary data to a descriptor of the remote BLE device.                                                       |
29| getRssiValue()                             | Obtains the received signal strength indication (RSSI) of the peer BLE device. This API can be used only after a connection is set up by **connect()**.|
30| setBLEMtuSize()                            | Sets the maximum transmission unit (MTU) that can be transmitted between the client and its peer BLE device. This API can be used only after a connection is set up by **connect()**.|
31| setCharacteristicChangeNotification()      | Sets the characteristic change notification. The client will be notified when the characteristic value of the remote BLE device changes.                                                                         |
32| setCharacteristicChangeIndication()        | Sets the characteristic change indication. The client will be indicated when the characteristic value of the remote BLE device changes.                                                                         |
33| on(type: 'BLECharacteristicChange')        | Subscribes to the BLE characteristic changes. The client can receive a notification from the server only after the **setNotifyCharacteristicChanged** method is called.       |
34| off(type: 'BLECharacteristicChange')       | Unsubscribes from the BLE characteristic changes.                                                                    |
35| on(type: 'BLEConnectionStateChange')       | Subscribes to the BLE connection state changes for the client.                                                              |
36| off(type: 'BLEConnectionStateChange')      | Unsubscribes from the BLE connection state changes for the client.                                                                  |
37| on(type: 'BLEMtuChange')                   | Subscribes to MTU status changes for the client.                                                                               |
38| off(type: 'BLEMtuChange')                  | Unsubscribes from MTU status changes for the client.                                                                           |
39| addService()                               | Adds a service to this server.                                                                                          |
40| removeService()                            | Removes a service from this server.                                                                                          |
41| close()                                    | Closes this server to unregister it from the protocol stack. After this API is called, the **GattServer** instance cannot be used any longer.                            |
42| notifyCharacteristicChanged()              | Notifies a connected client device when a characteristic value changes.                                                          |
43| sendResponse()                             | Sends a response to a read or write request from the client.                                                                            |
44| on(type: 'characteristicRead')             | Subscribes to the characteristic read request event for the server.                                                                              |
45| off(type: 'characteristicRead')            | Unsubscribes from the characteristic read request event for the server.                                                                          |
46| on(type: 'characteristicWrite')            | Subscribes to the characteristic write request event for the server.                                                                              |
47| off(type: 'characteristicWrite')           | Unsubscribes from the characteristic write request event for the server.                                                                          |
48| on(type: 'descriptorRead')                 | Subscribes to the descriptor read request event for the server.                                                                              |
49| off(type: 'descriptorRead')                | Unsubscribes from the descriptor read request event for the server.                                                                          |
50| on(type: 'descriptorWrite')                | Subscribes to the descriptor write request event for the server.                                                                              |
51| off(type: 'descriptorWrite')               | Unsubscribes from the descriptor write request event for the server.                                                                          |
52| on(type: 'connectionStateChange')          | Subscribes to the BLE connection state changes for the server.                                                                           |
53| off(type: 'connectionStateChange')         | Unsubscribes from the BLE connection state changes for the server.                                                                       |
54| on(type: 'BLEMtuChange')                   | Subscribes to MTU status changes for the server.                                                                               |
55| off(type: 'BLEMtuChange')                  | Unsubscribes from MTU status changes for the server.                                                                           |
56
57## How to Develop
58
59### Reading and Writing Data on the Server
601. Import the **ble** module.
612. Enable Bluetooth.
623. Apply for the **ohos.permission.ACCESS_BLUETOOTH** permission.
634. Create a **gattClient** instance.
645. Connect to the server.
656. Read characteristics and descriptors from the server.
667. Write characteristics and descriptors to the server.
678. Disconnect from the server and destroy the **gattClient** instance.
689. Example:
69
70    ```ts
71    import { ble } from '@kit.ConnectivityKit';
72    import { constant } from '@kit.ConnectivityKit';
73    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
74
75    const TAG: string = 'GattClientManager';
76
77    export class GattClientManager {
78      device: string | undefined = undefined;
79      gattClient: ble.GattClientDevice | undefined = undefined;
80      connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;
81      myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';
82      myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';
83      myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; // 2902 is generally used for notification or indication.
84      mySecondDescriptorUuid: string = '00002903-0000-1000-8000-00805F9B34FB';
85      found: boolean = false;
86
87      // Construct BLEDescriptor.
88      private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {
89        let descriptor: ble.BLEDescriptor = {
90          serviceUuid: this.myServiceUuid,
91          characteristicUuid: this.myCharacteristicUuid,
92          descriptorUuid: des,
93          descriptorValue: value
94        };
95        return descriptor;
96      }
97
98      // Construct BLECharacteristic.
99      private initCharacteristic(): ble.BLECharacteristic {
100        let descriptors: Array<ble.BLEDescriptor> = [];
101        let descBuffer = new ArrayBuffer(2);
102        let descValue = new Uint8Array(descBuffer);
103        descValue[0] = 11;
104        descValue[1] = 12;
105        descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, new ArrayBuffer(2));
106        descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
107        let charBuffer = new ArrayBuffer(2);
108        let charValue = new Uint8Array(charBuffer);
109        charValue[0] = 1;
110        charValue[1] = 2;
111        let characteristic: ble.BLECharacteristic = {
112          serviceUuid: this.myServiceUuid,
113          characteristicUuid: this.myCharacteristicUuid,
114          characteristicValue: charBuffer,
115          descriptors: descriptors
116        };
117        return characteristic;
118      }
119
120      private logCharacteristic(char: ble.BLECharacteristic) {
121        let message = 'logCharacteristic uuid:' + char.characteristicUuid + '\n';
122        let value = new Uint8Array(char.characteristicValue);
123        message += 'logCharacteristic value: ';
124        for (let i = 0; i < char.characteristicValue.byteLength; i++) {
125          message += value[i] + ' ';
126        }
127        console.info(TAG, message);
128      }
129
130      private logDescriptor(des: ble.BLEDescriptor) {
131        let message = 'logDescriptor uuid:' + des.descriptorUuid + '\n';
132        let value = new Uint8Array(des.descriptorValue);
133        message += 'logDescriptor value: ';
134        for (let i = 0; i < des.descriptorValue.byteLength; i++) {
135          message += value[i] + ' ';
136        }
137        console.info(TAG, message);
138      }
139
140      private checkService(services: Array<ble.GattService>): boolean {
141        for (let i = 0; i < services.length; i++) {
142          if (services[i].serviceUuid != this.myServiceUuid) {
143            continue;
144          }
145          for (let j = 0; j < services[i].characteristics.length; j++) {
146            if (services[i].characteristics[j].characteristicUuid != this.myCharacteristicUuid) {
147              continue;
148            }
149            for (let k = 0; k < services[i].characteristics[j].descriptors.length; k++) {
150              if (services[i].characteristics[j].descriptors[k].descriptorUuid == this.myFirstDescriptorUuid) {
151                console.info(TAG, 'find expected service from server');
152                return true;
153              }
154            }
155          }
156        }
157        console.error(TAG, 'no expected service from server');
158        return false;
159      }
160
161      // 1. Subscribe to the connection status change event.
162      public onGattClientStateChange() {
163        if (!this.gattClient) {
164          console.error(TAG, 'no gattClient');
165          return;
166        }
167        try {
168          this.gattClient.on('BLEConnectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
169            let state = '';
170            switch (stateInfo.state) {
171              case 0:
172                state = 'DISCONNECTED';
173                break;
174              case 1:
175                state = 'CONNECTING';
176                break;
177              case 2:
178                state = 'CONNECTED';
179                break;
180              case 3:
181                state = 'DISCONNECTING';
182                break;
183              default:
184                state = 'undefined';
185                break;
186            }
187            console.info(TAG, 'onGattClientStateChange: device=' + stateInfo.deviceId + ', state=' + state);
188            if (stateInfo.deviceId == this.device) {
189              this.connectState = stateInfo.state;
190            }
191          });
192        } catch (err) {
193          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
194        }
195      }
196
197      // 2. Called when the client proactively connects to the server.
198      public startConnect(peerDevice: string) {// The peer device is generally discovered through BLE scan.
199        if (this.connectState != constant.ProfileConnectionState.STATE_DISCONNECTED) {
200          console.error(TAG, 'startConnect failed');
201          return;
202        }
203        console.info(TAG, 'startConnect ' + peerDevice);
204        this.device = peerDevice;
205        // 2.1 Use device to construct gattClient. This instance is used for subsequent interactions.
206        this.gattClient = ble.createGattClientDevice(peerDevice);
207        try {
208          this.onGattClientStateChange(); // 2.2 Subscribe to the connection status.
209          this.gattClient.connect(); // 2.3 Initiate a connection.
210        } catch (err) {
211          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
212        }
213      }
214
215      // 3. After the client is connected, start service discovery.
216      public discoverServices() {
217        if (!this.gattClient) {
218          console.info(TAG, 'no gattClient');
219          return;
220        }
221        console.info(TAG, 'discoverServices');
222        try {
223          this.gattClient.getServices().then((result: Array<ble.GattService>) => {
224            console.info(TAG, 'getServices success: ' + JSON.stringify(result));
225            this.found = this.checkService(result); // Ensure that the service required exists on the server.
226          });
227        } catch (err) {
228          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
229        }
230      }
231
232      // 4. Read a specific characteristic after obtaining the services on the server.
233      public readCharacteristicValue() {
234        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
235          console.error(TAG, 'no gattClient or not connected');
236          return;
237        }
238        if (!this.found) {// Ensure that the server has the corresponding characteristic.
239          console.error(TAG, 'no characteristic from server');
240          return;
241        }
242
243        let characteristic = this.initCharacteristic();
244        console.info(TAG, 'readCharacteristicValue');
245        try {
246          this.gattClient.readCharacteristicValue(characteristic).then((outData: ble.BLECharacteristic) => {
247            this.logCharacteristic(outData);
248          })
249        } catch (err) {
250          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
251        }
252      }
253
254      // 5. Write a characteristic value after obtaining the services on the server.
255      public writeCharacteristicValue() {
256        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
257          console.error(TAG, 'no gattClient or not connected');
258          return;
259        }
260        if (!this.found) {// Ensure that the server has the corresponding characteristic.
261          console.error(TAG, 'no characteristic from server');
262          return;
263        }
264
265        let characteristic = this.initCharacteristic();
266        console.info(TAG, 'writeCharacteristicValue');
267        try {
268          this.gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (err) => {
269            if (err) {
270              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
271              return;
272            }
273            console.info(TAG, 'writeCharacteristicValue success');
274          });
275        } catch (err) {
276          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
277        }
278      }
279
280      // 6. Read a specific service descriptor after obtaining the services on the server.
281      public readDescriptorValue() {
282        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
283          console.error(TAG, 'no gattClient or not connected');
284          return;
285        }
286        if (!this.found) {// Ensure that the server has the corresponding descriptor.
287          console.error(TAG, 'no descriptor from server');
288          return;
289        }
290
291        let descBuffer = new ArrayBuffer(0);
292        let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
293        console.info(TAG, 'readDescriptorValue');
294        try {
295          this.gattClient.readDescriptorValue(descriptor).then((outData: ble.BLEDescriptor) => {
296            this.logDescriptor(outData);
297          });
298        } catch (err) {
299          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
300        }
301      }
302
303      // 7. Write a service descriptor after obtaining the services on the server.
304      public writeDescriptorValue() {
305        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
306          console.error(TAG, 'no gattClient or not connected');
307          return;
308        }
309        if (!this.found) {// Ensure that the server has the corresponding descriptor.
310          console.error(TAG, 'no descriptor from server');
311          return;
312        }
313
314        let descBuffer = new ArrayBuffer(2);
315        let descValue = new Uint8Array(descBuffer);
316        descValue[0] = 11;
317        descValue[1] = 12;
318        let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
319        console.info(TAG, 'writeDescriptorValue');
320        try {
321          this.gattClient.writeDescriptorValue(descriptor, (err) => {
322            if (err) {
323              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
324              return;
325            }
326            console.info(TAG, 'writeDescriptorValue success');
327          });
328        } catch (err) {
329          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
330        }
331      }
332
333      // 8. The client proactively disconnects from the server.
334      public stopConnect() {
335        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
336          console.error(TAG, 'no gattClient or not connected');
337          return;
338        }
339
340        console.info(TAG, 'stopConnect ' + this.device);
341        try {
342          this.gattClient.disconnect (); // 8.1 Disconnect from the server.
343          this.gattClient.off('BLEConnectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
344          });
345          this.gattClient.close () // 8.2 Close this gattClient if it is no longer required.
346        } catch (err) {
347          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
348        }
349      }
350    }
351
352    let gattClientManager = new GattClientManager();
353    export default gattClientManager as GattClientManager;
354    ```
355
3569. For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).
357
358
359### Managing Services on the Server and Notifying the Client
3601. Import the **ble** module.
3612. Enable Bluetooth.
3623. Apply for the **ohos.permission.ACCESS_BLUETOOTH** permission.
3634. Create a **gattServer** object.
3645. Add services.
3656. Notify the client after a characteristic is written to the server.
3667. Remove services.
3678. Close the gattServer instance.
3689. Example:
369
370    ```ts
371    import { ble } from '@kit.ConnectivityKit';
372    import { constant } from '@kit.ConnectivityKit';
373    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
374
375    const TAG: string = 'GattServerManager';
376
377    export class GattServerManager {
378      gattServer: ble.GattServer | undefined = undefined;
379      connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;
380      myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';
381      myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';
382      myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; // 2902 is generally used for notification or indication.
383      mySecondDescriptorUuid: string = '00002903-0000-1000-8000-00805F9B34FB';
384
385      // Construct BLEDescriptor.
386      private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {
387        let descriptor: ble.BLEDescriptor = {
388          serviceUuid: this.myServiceUuid,
389          characteristicUuid: this.myCharacteristicUuid,
390          descriptorUuid: des,
391          descriptorValue: value
392        };
393        return descriptor;
394      }
395
396      // Construct BLECharacteristic.
397      private initCharacteristic(): ble.BLECharacteristic {
398        let descriptors: Array<ble.BLEDescriptor> = [];
399        let descBuffer = new ArrayBuffer(2);
400        let descValue = new Uint8Array(descBuffer);
401        descValue[0] = 31;
402        descValue[1] = 32;
403        descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, new ArrayBuffer(2));
404        descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
405        let charBuffer = new ArrayBuffer(2);
406        let charValue = new Uint8Array(charBuffer);
407        charValue[0] = 21;
408        charValue[1] = 22;
409        let characteristic: ble.BLECharacteristic = {
410          serviceUuid: this.myServiceUuid,
411          characteristicUuid: this.myCharacteristicUuid,
412          characteristicValue: charBuffer,
413          descriptors: descriptors
414        };
415        return characteristic;
416      }
417
418      // 1. Subscribe to the connection status change event.
419      public onGattServerStateChange() {
420        if (!this.gattServer) {
421          console.error(TAG, 'no gattServer');
422          return;
423        }
424        try {
425          this.gattServer.on('connectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
426            let state = '';
427            switch (stateInfo.state) {
428              case 0:
429                state = 'DISCONNECTED';
430                break;
431              case 1:
432                state = 'CONNECTING';
433                break;
434              case 2:
435                state = 'CONNECTED';
436                break;
437              case 3:
438                state = 'DISCONNECTING';
439                break;
440              default:
441                state = 'undefined';
442                break;
443            }
444            console.info(TAG, 'onGattServerStateChange: device=' + stateInfo.deviceId + ', state=' + state);
445          });
446        } catch (err) {
447          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
448        }
449      }
450
451      // 2. Register a service with the server.
452      public registerServer() {
453        let characteristics: Array<ble.BLECharacteristic> = [];
454        let characteristic = this.initCharacteristic();
455        characteristics.push(characteristic);
456        let gattService: ble.GattService = {
457          serviceUuid: this.myServiceUuid,
458          isPrimary: true,
459          characteristics: characteristics
460        };
461
462        console.info(TAG, 'registerServer ' + this.myServiceUuid);
463        try {
464          The this.gattServer = ble.createGattServer(); // 2.1 Create a gattServer instance, which is used in subsequent interactions.
465          this.onGattServerStateChange(); // 2.2 Subscribe to the connection status.
466          this.gattServer.addService(gattService);
467        } catch (err) {
468          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
469        }
470      }
471
472      // 3. Subscribe to the characteristic read requests from the gattClient.
473      public onCharacteristicRead() {
474        if (!this.gattServer) {
475          console.error(TAG, 'no gattServer');
476          return;
477        }
478
479        console.info(TAG, 'onCharacteristicRead');
480        try {
481          this.gattServer.on('characteristicRead', (charReq: ble.CharacteristicReadRequest) => {
482            let deviceId: string = charReq.deviceId;
483            let transId: number = charReq.transId;
484            let offset: number = charReq.offset;
485            console.info(TAG, 'receive characteristicRead');
486            let rspBuffer = new ArrayBuffer(2);
487            let rspValue = new Uint8Array(rspBuffer);
488            rspValue[0] = 21;
489            rspValue[1] = 22;
490            let serverResponse: ble.ServerResponse = {
491              deviceId: deviceId,
492              transId: transId,
493              status: 0, // The value 0 indicates the operation is successful.
494              offset: offset,
495              value: rspBuffer
496            };
497
498            try {
499              this.gattServer.sendResponse(serverResponse);
500            } catch (err) {
501              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
502            }
503          });
504        } catch (err) {
505          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
506        }
507      }
508
509      // 4. Subscribe to the characteristic write requests from the gattClient.
510      public onCharacteristicWrite() {
511        if (!this.gattServer) {
512          console.error(TAG, 'no gattServer');
513          return;
514        }
515
516        console.info(TAG, 'onCharacteristicWrite');
517        try {
518          this.gattServer.on('characteristicWrite', (charReq: ble.CharacteristicWriteRequest) => {
519            let deviceId: string = charReq.deviceId;
520            let transId: number = charReq.transId;
521            let offset: number = charReq.offset;
522            console.info(TAG, 'receive characteristicWrite: needRsp=' + charReq.needRsp);
523            if (!charReq.needRsp) {
524              return;
525            }
526            let rspBuffer = new ArrayBuffer(0);
527            let serverResponse: ble.ServerResponse = {
528              deviceId: deviceId,
529              transId: transId,
530              status: 0, // The value 0 indicates the operation is successful.
531              offset: offset,
532              value: rspBuffer
533            };
534
535            try {
536              this.gattServer.sendResponse(serverResponse);
537            } catch (err) {
538              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
539            }
540          });
541        } catch (err) {
542          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
543        }
544      }
545
546      // 5. Subscribe to the descriptor read requests from the gattClient.
547      public onDescriptorRead() {
548        if (!this.gattServer) {
549          console.error(TAG, 'no gattServer');
550          return;
551        }
552
553        console.info(TAG, 'onDescriptorRead');
554        try {
555          this.gattServer.on('descriptorRead', (desReq: ble.DescriptorReadRequest) => {
556            let deviceId: string = desReq.deviceId;
557            let transId: number = desReq.transId;
558            let offset: number = desReq.offset;
559            console.info(TAG, 'receive descriptorRead');
560            let rspBuffer = new ArrayBuffer(2);
561            let rspValue = new Uint8Array(rspBuffer);
562            rspValue[0] = 31;
563            rspValue[1] = 32;
564            let serverResponse: ble.ServerResponse = {
565              deviceId: deviceId,
566              transId: transId,
567              status: 0, // The value 0 indicates the operation is successful.
568              offset: offset,
569              value: rspBuffer
570            };
571
572            try {
573              this.gattServer.sendResponse(serverResponse);
574            } catch (err) {
575              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
576            }
577          });
578        } catch (err) {
579          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
580        }
581      }
582
583      // 6. Subscribe to the descriptor write requests from the gattClient.
584      public onDescriptorWrite() {
585        if (!this.gattServer) {
586          console.error(TAG, 'no gattServer');
587          return;
588        }
589
590        console.info(TAG, 'onDescriptorWrite');
591        try {
592          this.gattServer.on('descriptorWrite', (desReq: ble.DescriptorWriteRequest) => {
593            let deviceId: string = desReq.deviceId;
594            let transId: number = desReq.transId;
595            let offset: number = desReq.offset;
596            console.info(TAG, 'receive descriptorWrite: needRsp=' + desReq.needRsp);
597            if (!desReq.needRsp) {
598              return;
599            }
600            let rspBuffer = new ArrayBuffer(0);
601            let serverResponse: ble.ServerResponse = {
602              deviceId: deviceId,
603              transId: transId,
604              status: 0, // The value 0 indicates the operation is successful.
605              offset: offset,
606              value: rspBuffer
607            };
608
609            try {
610              this.gattServer.sendResponse(serverResponse);
611            } catch (err) {
612              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
613            }
614          });
615        } catch (err) {
616          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
617        }
618      }
619
620      // 7. Unregister the service that is not required from the server.
621      public unRegisterServer() {
622        if (!this.gattServer) {
623          console.error(TAG, 'no gattServer');
624          return;
625        }
626
627        console.info(TAG, 'unRegisterServer ' + this.myServiceUuid);
628        try {
629          this.gattServer.removeService (this.myServiceUuid); // 7.1 Remove the service.
630          this.gattServer.off('connectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => { // 7.2 Unsubscribe from the connection state changes.
631          });
632          this.gattServer.close() // 7.3 Close the gattServer if it is no longer required.
633        } catch (err) {
634          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
635        }
636      }
637    }
638
639    let gattServerManager = new GattServerManager();
640    export default gattServerManager as GattServerManager;
641    ```
642
6438. For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).
644