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.
68
69    Example:
70
71    ```ts
72    import { ble } from '@kit.ConnectivityKit';
73    import { constant } from '@kit.ConnectivityKit';
74    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
75
76    const TAG: string = 'GattClientManager';
77
78    export class GattClientManager {
79      device: string = undefined;
80      gattClient: ble.GattClientDevice = undefined;
81      connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;
82      myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';
83      myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';
84      myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; // 2902 is generally used for notification or indication.
85      mySecondDescriptorUuid: string = '00002903-0000-1000-8000-00805F9B34FB';
86      found: boolean = false;
87
88      // Construct BLEDescriptor.
89      private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {
90        let descriptor: ble.BLEDescriptor = {
91          serviceUuid: this.myServiceUuid,
92          characteristicUuid: this.myCharacteristicUuid,
93          descriptorUuid: des,
94          descriptorValue: value
95        };
96        return descriptor;
97      }
98
99      // Construct BLECharacteristic.
100      private initCharacteristic(): ble.BLECharacteristic {
101        let descriptors: Array<ble.BLEDescriptor> = [];
102        let descBuffer = new ArrayBuffer(2);
103        let descValue = new Uint8Array(descBuffer);
104        descValue[0] = 11;
105        descValue[1] = 12;
106        descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, new ArrayBuffer(2));
107        descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
108        let charBuffer = new ArrayBuffer(2);
109        let charValue = new Uint8Array(charBuffer);
110        charValue[0] = 1;
111        charValue[1] = 2;
112        let characteristic: ble.BLECharacteristic = {
113          serviceUuid: this.myServiceUuid,
114          characteristicUuid: this.myCharacteristicUuid,
115          characteristicValue: charBuffer,
116          descriptors: descriptors
117        };
118        return characteristic;
119      }
120
121      private logCharacteristic(char: ble.BLECharacteristic) {
122        let message = 'logCharacteristic uuid:' + char.characteristicUuid + '\n';
123        let value = new Uint8Array(char.characteristicValue);
124        message += 'logCharacteristic value: ';
125        for (let i = 0; i < char.characteristicValue.byteLength; i++) {
126          message += value[i] + ' ';
127        }
128        console.info(TAG, message);
129      }
130
131      private logDescriptor(des: ble.BLEDescriptor) {
132        let message = 'logDescriptor uuid:' + des.descriptorUuid + '\n';
133        let value = new Uint8Array(des.descriptorValue);
134        message += 'logDescriptor value: ';
135        for (let i = 0; i < des.descriptorValue.byteLength; i++) {
136          message += value[i] + ' ';
137        }
138        console.info(TAG, message);
139      }
140
141      private checkService(services: Array<ble.GattService>): boolean {
142        for (let i = 0; i < services.length; i++) {
143          if (services[i].serviceUuid != this.myServiceUuid) {
144            continue;
145          }
146          for (let j = 0; j < services[i].characteristics.length; j++) {
147            if (services[i].characteristics[j].characteristicUuid != this.myCharacteristicUuid) {
148              continue;
149            }
150            for (let k = 0; k < services[i].characteristics[j].descriptors.length; k++) {
151              if (services[i].characteristics[j].descriptors[k].descriptorUuid == this.myFirstDescriptorUuid) {
152                console.info(TAG, 'find expected service from server');
153                return true;
154              }
155            }
156          }
157        }
158        console.error(TAG, 'no expected service from server');
159        return false;
160      }
161
162      // 1. Subscribe to the connection status change event.
163      public onGattClientStateChange() {
164        if (!this.gattClient) {
165          console.error(TAG, 'no gattClient');
166          return;
167        }
168        try {
169          this.gattClient.on('BLEConnectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
170            let state = '';
171            switch (stateInfo.state) {
172              case 0:
173                state = 'DISCONNECTED';
174                break;
175              case 1:
176                state = 'CONNECTING';
177                break;
178              case 2:
179                state = 'CONNECTED';
180                break;
181              case 3:
182                state = 'DISCONNECTING';
183                break;
184              default:
185                state = 'undefined';
186                break;
187            }
188            console.info(TAG, 'onGattClientStateChange: device=' + stateInfo.deviceId + ', state=' + state);
189            if (stateInfo.deviceId == this.device) {
190              this.connectState = stateInfo.state;
191            }
192          });
193        } catch (err) {
194          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
195        }
196      }
197
198      // 2. Called when the client proactively connects to the server.
199      public startConnect(peerDevice: string) {// The peer device is generally discovered through BLE scan.
200        if (this.connectState != constant.ProfileConnectionState.STATE_DISCONNECTED) {
201          console.error(TAG, 'startConnect failed');
202          return;
203        }
204        console.info(TAG, 'startConnect ' + peerDevice);
205        this.device = peerDevice;
206        // 2.1 Use device to construct gattClient. This instance is used for subsequent interactions.
207        this.gattClient = ble.createGattClientDevice(peerDevice);
208        try {
209          this.onGattClientStateChange(); // 2.2 Subscribe to the connection status.
210          this.gattClient.connect(); // 2.3 Initiate a connection.
211        } catch (err) {
212          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
213        }
214      }
215
216      // 3. After the client is connected, start service discovery.
217      public discoverServices() {
218        if (!this.gattClient) {
219          console.info(TAG, 'no gattClient');
220          return;
221        }
222        console.info(TAG, 'discoverServices');
223        try {
224          this.gattClient.getServices().then((result: Array<ble.GattService>) => {
225            console.info(TAG, 'getServices success: ' + JSON.stringify(result));
226            this.found = this.checkService(result); // Ensure that the service required exists on the server.
227          });
228        } catch (err) {
229          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
230        }
231      }
232
233      // 4. Read a specific characteristic after obtaining the services on the server.
234      public readCharacteristicValue() {
235        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
236          console.error(TAG, 'no gattClient or not connected');
237          return;
238        }
239        if (!this.found) {// Ensure that the server has the corresponding characteristic.
240          console.error(TAG, 'no characteristic from server');
241          return;
242        }
243
244        let characteristic = this.initCharacteristic();
245        console.info(TAG, 'readCharacteristicValue');
246        try {
247          this.gattClient.readCharacteristicValue(characteristic).then((outData: ble.BLECharacteristic) => {
248            this.logCharacteristic(outData);
249          })
250        } catch (err) {
251          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
252        }
253      }
254
255      // 5. Write a characteristic value after obtaining the services on the server.
256      public writeCharacteristicValue() {
257        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
258          console.error(TAG, 'no gattClient or not connected');
259          return;
260        }
261        if (!this.found) {// Ensure that the server has the corresponding characteristic.
262          console.error(TAG, 'no characteristic from server');
263          return;
264        }
265
266        let characteristic = this.initCharacteristic();
267        console.info(TAG, 'writeCharacteristicValue');
268        try {
269          this.gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (err) => {
270            if (err) {
271              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
272              return;
273            }
274            console.info(TAG, 'writeCharacteristicValue success');
275          });
276        } catch (err) {
277          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
278        }
279      }
280
281      // 6. Read a specific service descriptor after obtaining the services on the server.
282      public readDescriptorValue() {
283        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
284          console.error(TAG, 'no gattClient or not connected');
285          return;
286        }
287        if (!this.found) {// Ensure that the server has the corresponding descriptor.
288          console.error(TAG, 'no descriptor from server');
289          return;
290        }
291
292        let descBuffer = new ArrayBuffer(0);
293        let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
294        console.info(TAG, 'readDescriptorValue');
295        try {
296          this.gattClient.readDescriptorValue(descriptor).then((outData: ble.BLEDescriptor) => {
297            this.logDescriptor(outData);
298          });
299        } catch (err) {
300          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
301        }
302      }
303
304      // 7. Write a service descriptor after obtaining the services on the server.
305      public writeDescriptorValue() {
306        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
307          console.error(TAG, 'no gattClient or not connected');
308          return;
309        }
310        if (!this.found) {// Ensure that the server has the corresponding descriptor.
311          console.error(TAG, 'no descriptor from server');
312          return;
313        }
314
315        let descBuffer = new ArrayBuffer(2);
316        let descValue = new Uint8Array(descBuffer);
317        descValue[0] = 11;
318        descValue[1] = 12;
319        let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
320        console.info(TAG, 'writeDescriptorValue');
321        try {
322          this.gattClient.writeDescriptorValue(descriptor, (err) => {
323            if (err) {
324              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
325              return;
326            }
327            console.info(TAG, 'writeDescriptorValue success');
328          });
329        } catch (err) {
330          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
331        }
332      }
333
334      // 8. The client proactively disconnects from the server.
335      public stopConnect() {
336        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
337          console.error(TAG, 'no gattClient or not connected');
338          return;
339        }
340
341        console.info(TAG, 'stopConnect ' + this.device);
342        try {
343          this.gattClient.disconnect (); // 8.1 Disconnect from the server.
344          this.gattClient.off('BLEConnectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
345          });
346          this.gattClient.close () // 8.2 Close this gattClient if it is no longer required.
347        } catch (err) {
348          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
349        }
350      }
351    }
352
353    let gattClientManager = new GattClientManager();
354    export default gattClientManager as GattClientManager;
355    ```
356
357    For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).
358
359
360### Managing Services on the Server and Notifying the Client
3611. Import the **ble** module.
3622. Create a **gattServer** object.
3633. Add services.
3644. Notify the client after a characteristic is written to the server.
3655. Remove services.
3666. Close the gattServer instance.
367
368    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;
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
643    For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).
644