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