• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# GATT Development
2
3## Introduction
4Generic Attribute Profile (GATT) provides profile discovery and description services for BLE protocol. It defines how ATT attributes are organized and exchanged over a BLE connection.
5
6A 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.
7
8## When to Use
9
10You can use the APIs provided by the **gatt** module to:
11- Connect to the server to read and write data.
12- Manage services on the server and respond to the requests from the client.
13
14## Available APIs
15
16For details about the APIs and sample code, see [@ohos.bluetooth.ble](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md).
17
18The following table describes the related APIs.
19
20| API                                     | Description                                                                                              |
21| ------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
22| connect()                                  | Connects the client to the remote BLE device.                                                                     |
23| disconnect()                               | Disconnects the client from the remote BLE device.                                                                 |
24| close()                                    | Closes this client to unregister it from the protocol stack. After this API is called, this **GattClientDevice** instance cannot be used any longer.|
25| getDeviceName()                            | Obtains the name of the remote BLE device for the client.                                                                         |
26| getServices()                              | Obtains all services of the remote BLE device for the client.                                                        |
27| readCharacteristicValue()                  | Reads a characteristic value of a service of the remote BLE device.                                                              |
28| readDescriptorValue()                      | Reads the descriptor contained in a characteristic of the remote BLE device.                                                        |
29| writeCharacteristicValue()                 | Writes a characteristic value to the remote BLE device.                                                                |
30| writeDescriptorValue()                     | Writes binary data to a descriptor of the remote BLE device.                                                       |
31| 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()**.|
32| 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()**.|
33| setCharacteristicChangeNotification()      | Sets the characteristic change notification. The client will be notified when the characteristic value of the remote BLE device changes.                                                                         |
34| setCharacteristicChangeIndication()        | Sets the characteristic change indication. The client will be indicated when the characteristic value of the remote BLE device changes.                                                                         |
35| 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.       |
36| off(type: 'BLECharacteristicChange')       | Unsubscribes from the BLE characteristic changes.                                                                    |
37| on(type: 'BLEConnectionStateChange')       | Subscribes to the BLE connection state changes for the client.                                                              |
38| off(type: 'BLEConnectionStateChange')      | Unsubscribes from the BLE connection state changes for the client.                                                                  |
39| on(type: 'BLEMtuChange')                   | Subscribes to MTU status changes for the client.                                                                               |
40| off(type: 'BLEMtuChange')                  | Unsubscribes from MTU status changes for the client.                                                                           |
41| addService()                               | Adds a service to this server.                                                                                          |
42| removeService()                            | Removes a service from this server.                                                                                          |
43| close()                                    | Closes this server to unregister it from the protocol stack. After this API is called, the **GattServer** instance cannot be used any longer.                            |
44| notifyCharacteristicChanged()              | Notifies a connected client device when a characteristic value changes.                                                          |
45| sendResponse()                             | Sends a response to a read or write request from the client.                                                                            |
46| on(type: 'characteristicRead')             | Subscribes to the characteristic read request event for the server.                                                                              |
47| off(type: 'characteristicRead')            | Unsubscribes from the characteristic read request event for the server.                                                                          |
48| on(type: 'characteristicWrite')            | Subscribes to the characteristic write request event for the server.                                                                              |
49| off(type: 'characteristicWrite')           | Unsubscribes from the characteristic write request event for the server.                                                                          |
50| on(type: 'descriptorRead')                 | Subscribes to the descriptor read request event for the server.                                                                              |
51| off(type: 'descriptorRead')                | Unsubscribes from the descriptor read request event for the server.                                                                          |
52| on(type: 'descriptorWrite')                | Subscribes to the descriptor write request event for the server.                                                                              |
53| off(type: 'descriptorWrite')               | Unsubscribes from the descriptor write request event for the server.                                                                          |
54| on(type: 'connectionStateChange')          | Subscribes to the BLE connection state changes for the server.                                                                           |
55| off(type: 'connectionStateChange')         | Unsubscribes from the BLE connection state changes for the server.                                                                       |
56| on(type: 'BLEMtuChange')                   | Subscribes to MTU status changes for the server.                                                                               |
57| off(type: 'BLEMtuChange')                  | Unsubscribes from MTU status changes for the server.                                                                           |
58
59## How to Develop
60
61### Reading and Writing Data on the Server
621. Import the **ble** module.
632. Create a **gattClient** instance.
643. Connect to the server.
654. Read characteristics and descriptors from the server.
665. Write characteristics and descriptors to the server.
676. Disconnect from the server and destroy the **gattClient** instance.
68Example:
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
356For 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. Create a **gattServer** object.
3623. Add services.
3634. Notify the client after a characteristic is written to the server.
3645. Remove services.
3656. Close the gattServer instance.
366Example:
367
368    ```ts
369    import { ble } from '@kit.ConnectivityKit';
370    import { constant } from '@kit.ConnectivityKit';
371    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
372
373    const TAG: string = 'GattServerManager';
374
375    export class GattServerManager {
376      gattServer: ble.GattServer | undefined = undefined;
377      connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;
378      myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';
379      myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';
380      myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; // 2902 is generally used for notification or indication.
381      mySecondDescriptorUuid: string = '00002903-0000-1000-8000-00805F9B34FB';
382
383      // Construct BLEDescriptor.
384      private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {
385        let descriptor: ble.BLEDescriptor = {
386          serviceUuid: this.myServiceUuid,
387          characteristicUuid: this.myCharacteristicUuid,
388          descriptorUuid: des,
389          descriptorValue: value
390        };
391        return descriptor;
392      }
393
394      // Construct BLECharacteristic.
395      private initCharacteristic(): ble.BLECharacteristic {
396        let descriptors: Array<ble.BLEDescriptor> = [];
397        let descBuffer = new ArrayBuffer(2);
398        let descValue = new Uint8Array(descBuffer);
399        descValue[0] = 31;
400        descValue[1] = 32;
401        descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, new ArrayBuffer(2));
402        descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
403        let charBuffer = new ArrayBuffer(2);
404        let charValue = new Uint8Array(charBuffer);
405        charValue[0] = 21;
406        charValue[1] = 22;
407        let characteristic: ble.BLECharacteristic = {
408          serviceUuid: this.myServiceUuid,
409          characteristicUuid: this.myCharacteristicUuid,
410          characteristicValue: charBuffer,
411          descriptors: descriptors
412        };
413        return characteristic;
414      }
415
416      // 1. Subscribe to the connection status change event.
417      public onGattServerStateChange() {
418        if (!this.gattServer) {
419          console.error(TAG, 'no gattServer');
420          return;
421        }
422        try {
423          this.gattServer.on('connectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
424            let state = '';
425            switch (stateInfo.state) {
426              case 0:
427                state = 'DISCONNECTED';
428                break;
429              case 1:
430                state = 'CONNECTING';
431                break;
432              case 2:
433                state = 'CONNECTED';
434                break;
435              case 3:
436                state = 'DISCONNECTING';
437                break;
438              default:
439                state = 'undefined';
440                break;
441            }
442            console.info(TAG, 'onGattServerStateChange: device=' + stateInfo.deviceId + ', state=' + state);
443          });
444        } catch (err) {
445          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
446        }
447      }
448
449      // 2. Register a service with the server.
450      public registerServer() {
451        let characteristics: Array<ble.BLECharacteristic> = [];
452        let characteristic = this.initCharacteristic();
453        characteristics.push(characteristic);
454        let gattService: ble.GattService = {
455          serviceUuid: this.myServiceUuid,
456          isPrimary: true,
457          characteristics: characteristics
458        };
459
460        console.info(TAG, 'registerServer ' + this.myServiceUuid);
461        try {
462          The this.gattServer = ble.createGattServer(); // 2.1 Create a gattServer instance, which is used in subsequent interactions.
463          this.onGattServerStateChange(); // 2.2 Subscribe to the connection status.
464          this.gattServer.addService(gattService);
465        } catch (err) {
466          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
467        }
468      }
469
470      // 3. Subscribe to the characteristic read requests from the gattClient.
471      public onCharacteristicRead() {
472        if (!this.gattServer) {
473          console.error(TAG, 'no gattServer');
474          return;
475        }
476
477        console.info(TAG, 'onCharacteristicRead');
478        try {
479          this.gattServer.on('characteristicRead', (charReq: ble.CharacteristicReadRequest) => {
480            let deviceId: string = charReq.deviceId;
481            let transId: number = charReq.transId;
482            let offset: number = charReq.offset;
483            console.info(TAG, 'receive characteristicRead');
484            let rspBuffer = new ArrayBuffer(2);
485            let rspValue = new Uint8Array(rspBuffer);
486            rspValue[0] = 21;
487            rspValue[1] = 22;
488            let serverResponse: ble.ServerResponse = {
489              deviceId: deviceId,
490              transId: transId,
491              status: 0, // The value 0 indicates the operation is successful.
492              offset: offset,
493              value: rspBuffer
494            };
495
496            try {
497              this.gattServer.sendResponse(serverResponse);
498            } catch (err) {
499              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
500            }
501          });
502        } catch (err) {
503          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
504        }
505      }
506
507      // 4. Subscribe to the characteristic write requests from the gattClient.
508      public onCharacteristicWrite() {
509        if (!this.gattServer) {
510          console.error(TAG, 'no gattServer');
511          return;
512        }
513
514        console.info(TAG, 'onCharacteristicWrite');
515        try {
516          this.gattServer.on('characteristicWrite', (charReq: ble.CharacteristicWriteRequest) => {
517            let deviceId: string = charReq.deviceId;
518            let transId: number = charReq.transId;
519            let offset: number = charReq.offset;
520            console.info(TAG, 'receive characteristicWrite: needRsp=' + charReq.needRsp);
521            if (!charReq.needRsp) {
522              return;
523            }
524            let rspBuffer = new ArrayBuffer(0);
525            let serverResponse: ble.ServerResponse = {
526              deviceId: deviceId,
527              transId: transId,
528              status: 0, // The value 0 indicates the operation is successful.
529              offset: offset,
530              value: rspBuffer
531            };
532
533            try {
534              this.gattServer.sendResponse(serverResponse);
535            } catch (err) {
536              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
537            }
538          });
539        } catch (err) {
540          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
541        }
542      }
543
544      // 5. Subscribe to the descriptor read requests from the gattClient.
545      public onDescriptorRead() {
546        if (!this.gattServer) {
547          console.error(TAG, 'no gattServer');
548          return;
549        }
550
551        console.info(TAG, 'onDescriptorRead');
552        try {
553          this.gattServer.on('descriptorRead', (desReq: ble.DescriptorReadRequest) => {
554            let deviceId: string = desReq.deviceId;
555            let transId: number = desReq.transId;
556            let offset: number = desReq.offset;
557            console.info(TAG, 'receive descriptorRead');
558            let rspBuffer = new ArrayBuffer(2);
559            let rspValue = new Uint8Array(rspBuffer);
560            rspValue[0] = 31;
561            rspValue[1] = 32;
562            let serverResponse: ble.ServerResponse = {
563              deviceId: deviceId,
564              transId: transId,
565              status: 0, // The value 0 indicates the operation is successful.
566              offset: offset,
567              value: rspBuffer
568            };
569
570            try {
571              this.gattServer.sendResponse(serverResponse);
572            } catch (err) {
573              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
574            }
575          });
576        } catch (err) {
577          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
578        }
579      }
580
581      // 6. Subscribe to the descriptor write requests from the gattClient.
582      public onDescriptorWrite() {
583        if (!this.gattServer) {
584          console.error(TAG, 'no gattServer');
585          return;
586        }
587
588        console.info(TAG, 'onDescriptorWrite');
589        try {
590          this.gattServer.on('descriptorWrite', (desReq: ble.DescriptorWriteRequest) => {
591            let deviceId: string = desReq.deviceId;
592            let transId: number = desReq.transId;
593            let offset: number = desReq.offset;
594            console.info(TAG, 'receive descriptorWrite: needRsp=' + desReq.needRsp);
595            if (!desReq.needRsp) {
596              return;
597            }
598            let rspBuffer = new ArrayBuffer(0);
599            let serverResponse: ble.ServerResponse = {
600              deviceId: deviceId,
601              transId: transId,
602              status: 0, // The value 0 indicates the operation is successful.
603              offset: offset,
604              value: rspBuffer
605            };
606
607            try {
608              this.gattServer.sendResponse(serverResponse);
609            } catch (err) {
610              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
611            }
612          });
613        } catch (err) {
614          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
615        }
616      }
617
618      // 7. Unregister the service that is not required from the server.
619      public unRegisterServer() {
620        if (!this.gattServer) {
621          console.error(TAG, 'no gattServer');
622          return;
623        }
624
625        console.info(TAG, 'unRegisterServer ' + this.myServiceUuid);
626        try {
627          this.gattServer.removeService (this.myServiceUuid); // 7.1 Remove the service.
628          this.gattServer.off('connectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => { // 7.2 Unsubscribe from the connection state changes.
629          });
630          this.gattServer.close() // 7.3 Close the gattServer if it is no longer required.
631        } catch (err) {
632          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
633        }
634      }
635    }
636
637    let gattServerManager = new GattServerManager();
638    export default gattServerManager as GattServerManager;
639    ```
640
641For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).
642