1# Copyright 2023 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Client Class to access the Floss GATT client interface.""" 15 16import logging 17 18from floss.pandora.floss import floss_enums 19from floss.pandora.floss import observer_base 20from floss.pandora.floss import utils 21 22 23class GattClientCallbacks: 24 """Callbacks for the GATT client interface. 25 26 Implement this to observe these callbacks when exporting callbacks via register_client. 27 """ 28 29 def on_client_registered(self, status, scanner_id): 30 """Called when GATT client registered. 31 32 Args: 33 status: floss_enums.GattStatus. 34 scanner_id: Bluetooth GATT scanner id. 35 """ 36 pass 37 38 def on_client_connection_state(self, status, client_id, connected, addr): 39 """Called when GATT client connection state changed. 40 41 Args: 42 status: floss_enums.GattStatus. 43 client_id: Bluetooth GATT client id. 44 connected: A boolean value representing whether the device is connected. 45 addr: Remote device MAC address. 46 """ 47 pass 48 49 def on_phy_update(self, addr, tx_phy, rx_phy, status): 50 """Called when GATT physical type is updated. 51 52 Args: 53 addr: Remote device MAC address. 54 tx_phy: Transmit physical type. 55 rx_phy: Receive physical type. 56 status: floss_enums.GattStatus. 57 """ 58 pass 59 60 def on_phy_read(self, addr, tx_phy, rx_phy, status): 61 """Called when GATT physical type is read. 62 63 Args: 64 addr: Remote device MAC address. 65 tx_phy: Transmit physical type. 66 rx_phy: Receive physical type. 67 status: floss_enums.GattStatus. 68 """ 69 pass 70 71 def on_search_complete(self, addr, services, status): 72 """Called when search completed. 73 74 Args: 75 addr: Remote device MAC address. 76 services: Bluetooth GATT services as list. 77 status: floss_enums.GattStatus. 78 """ 79 pass 80 81 def on_characteristic_read(self, addr, status, handle, value): 82 """Called when characteristic is read. 83 84 Args: 85 addr: Remote device MAC address. 86 status: floss_enums.GattStatus. 87 handle: Characteristic handle id. 88 value: Characteristic value. 89 """ 90 pass 91 92 def on_characteristic_write(self, addr, status, handle): 93 """Called when characteristic is written. 94 95 Args: 96 addr: Remote device MAC address. 97 status: floss_enums.GattStatus. 98 handle: Characteristic handle id. 99 """ 100 pass 101 102 def on_execute_write(self, addr, status): 103 """Called when execute write. 104 105 Args: 106 addr: Remote device MAC address. 107 status: floss_enums.GattStatus. 108 """ 109 pass 110 111 def on_descriptor_read(self, addr, status, handle, value): 112 """Called when descriptor is read. 113 114 Args: 115 addr: Remote device MAC address. 116 status: floss_enums.GattStatus. 117 handle: Descriptor handle id. 118 value: Descriptor value. 119 """ 120 pass 121 122 def on_descriptor_write(self, addr, status, handle): 123 """Called when descriptor is written. 124 125 Args: 126 addr: Remote device MAC address. 127 status: floss_enums.GattStatus. 128 handle: Descriptor handle id. 129 """ 130 pass 131 132 def on_notify(self, addr, handle, value): 133 """Called when notified. 134 135 Args: 136 addr: Remote device MAC address. 137 handle: Characteristic handle id. 138 value: Characteristic value. 139 """ 140 pass 141 142 def on_read_remote_rssi(self, addr, rssi, status): 143 """Called when remote RSSI is read. 144 145 Args: 146 addr: Remote device MAC address. 147 rssi: RSSI value. 148 status: floss_enums.GattStatus. 149 """ 150 pass 151 152 def on_configure_mtu(self, addr, mtu, status): 153 """Called when MTU is configured. 154 155 Args: 156 addr: Remote device MAC address. 157 mtu: MTU value. 158 status: floss_enums.GattStatus. 159 """ 160 pass 161 162 def on_connection_updated(self, addr, interval, latency, timeout, status): 163 """Called when connection updated. 164 165 Args: 166 addr: Remote device MAC address. 167 interval: Interval in ms. 168 latency: Latency in ms. 169 timeout: Timeout in ms. 170 status: floss_enums.GattStatus. 171 """ 172 pass 173 174 def on_service_changed(self, addr): 175 """Called when service changed. 176 177 Args: 178 addr: Remote device MAC address. 179 """ 180 pass 181 182 183class FlossGattClient(GattClientCallbacks): 184 """Handles method calls and callbacks from the GATT client interface.""" 185 186 ADAPTER_SERVICE = 'org.chromium.bluetooth' 187 GATT_CLIENT_INTERFACE = 'org.chromium.bluetooth.BluetoothGatt' 188 GATT_OBJECT_PATTERN = '/org/chromium/bluetooth/hci{}/gatt' 189 GATT_CB_OBJ_NAME = 'test_gatt_client' 190 CB_EXPORTED_INTF = 'org.chromium.bluetooth.BluetoothGattCallback' 191 FLOSS_RESPONSE_LATENCY_SECS = 3 192 193 class ExportedGattClientCallbacks(observer_base.ObserverBase): 194 """ 195 <node> 196 <interface name="org.chromium.bluetooth.BluetoothGattCallback"> 197 <method name="OnClientRegistered"> 198 <arg type="u" name="status" direction="in" /> 199 <arg type="i" name="scanner_id" direction="in" /> 200 </method> 201 <method name="OnClientConnectionState"> 202 <arg type="u" name="status" direction="in" /> 203 <arg type="i" name="client_id" direction="in" /> 204 <arg type="b" name="connected" direction="in" /> 205 <arg type="s" name="addr" direction="in" /> 206 </method> 207 <method name="OnPhyUpdate"> 208 <arg type="s" name="addr" direction="in" /> 209 <arg type="u" name="tx_phy" direction="in" /> 210 <arg type="u" name="rx_phy" direction="in" /> 211 <arg type="u" name="status" direction="in" /> 212 </method> 213 <method name="OnPhyRead"> 214 <arg type="s" name="addr" direction="in" /> 215 <arg type="u" name="tx_phy" direction="in" /> 216 <arg type="u" name="rx_phy" direction="in" /> 217 <arg type="u" name="status" direction="in" /> 218 </method> 219 <method name="OnSearchComplete"> 220 <arg type="s" name="addr" direction="in" /> 221 <arg type="aa{sv}" name="services" direction="in" /> 222 <arg type="u" name="status" direction="in" /> 223 </method> 224 <method name="OnCharacteristicRead"> 225 <arg type="s" name="addr" direction="in" /> 226 <arg type="u" name="status" direction="in" /> 227 <arg type="i" name="handle" direction="in" /> 228 <arg type="ay" name="value" direction="in" /> 229 </method> 230 <method name="OnCharacteristicWrite"> 231 <arg type="s" name="addr" direction="in" /> 232 <arg type="u" name="status" direction="in" /> 233 <arg type="i" name="handle" direction="in" /> 234 </method> 235 <method name="OnExecuteWrite"> 236 <arg type="s" name="addr" direction="in" /> 237 <arg type="u" name="status" direction="in" /> 238 </method> 239 <method name="OnDescriptorRead"> 240 <arg type="s" name="addr" direction="in" /> 241 <arg type="u" name="status" direction="in" /> 242 <arg type="i" name="handle" direction="in" /> 243 <arg type="ay" name="value" direction="in" /> 244 </method> 245 <method name="OnDescriptorWrite"> 246 <arg type="s" name="addr" direction="in" /> 247 <arg type="u" name="status" direction="in" /> 248 <arg type="i" name="handle" direction="in" /> 249 </method> 250 <method name="OnNotify"> 251 <arg type="s" name="addr" direction="in" /> 252 <arg type="i" name="handle" direction="in" /> 253 <arg type="ay" name="value" direction="in" /> 254 </method> 255 <method name="OnReadRemoteRssi"> 256 <arg type="s" name="addr" direction="in" /> 257 <arg type="i" name="rssi" direction="in" /> 258 <arg type="u" name="status" direction="in" /> 259 </method> 260 <method name="OnConfigureMtu"> 261 <arg type="s" name="addr" direction="in" /> 262 <arg type="i" name="mtu" direction="in" /> 263 <arg type="u" name="status" direction="in" /> 264 </method> 265 <method name="OnConnectionUpdated"> 266 <arg type="s" name="addr" direction="in" /> 267 <arg type="i" name="interval" direction="in" /> 268 <arg type="i" name="latency" direction="in" /> 269 <arg type="i" name="timeout" direction="in" /> 270 <arg type="u" name="status" direction="in" /> 271 </method> 272 <method name="OnServiceChanged"> 273 <arg type="s" name="addr" direction="in" /> 274 </method> 275 276 </interface> 277 </node> 278 """ 279 280 def __init__(self): 281 """Constructs exported callbacks object.""" 282 observer_base.ObserverBase.__init__(self) 283 284 def OnClientRegistered(self, status, scanner_id): 285 """Handles client registration callback. 286 287 Args: 288 status: floss_enums.GattStatus. 289 scanner_id: Bluetooth GATT scanner id. 290 """ 291 for observer in self.observers.values(): 292 observer.on_client_registered(status, scanner_id) 293 294 def OnClientConnectionState(self, status, client_id, connected, addr): 295 """Handles client connection state callback. 296 297 Args: 298 status: floss_enums.GattStatus. 299 client_id: Bluetooth GATT client id. 300 connected: A boolean value representing whether the device is connected. 301 addr: Remote device MAC address. 302 """ 303 for observer in self.observers.values(): 304 observer.on_client_connection_state(status, client_id, connected, addr) 305 306 def OnPhyUpdate(self, addr, tx_phy, rx_phy, status): 307 """Handles GATT physical type update callback. 308 309 Args: 310 addr: Remote device MAC address. 311 tx_phy: Transmit physical type. 312 rx_phy: Receive physical type. 313 status: floss_enums.GattStatus. 314 """ 315 for observer in self.observers.values(): 316 observer.on_phy_update(addr, tx_phy, rx_phy, status) 317 318 def OnPhyRead(self, addr, tx_phy, rx_phy, status): 319 """Handles GATT physical type read callback. 320 321 Args: 322 addr: Remote device MAC address. 323 tx_phy: Transmit physical type. 324 rx_phy: Receive physical type. 325 status: floss_enums.GattStatus. 326 """ 327 for observer in self.observers.values(): 328 observer.on_phy_read(addr, tx_phy, rx_phy, status) 329 330 def OnSearchComplete(self, addr, services, status): 331 """Handles search complete callback. 332 333 Args: 334 addr: Remote device MAC address. 335 services: Bluetooth GATT services as list. 336 status: floss_enums.GattStatus. 337 """ 338 for observer in self.observers.values(): 339 observer.on_search_complete(addr, services, status) 340 341 def OnCharacteristicRead(self, addr, status, handle, value): 342 """Handles characteristic read callback. 343 344 Args: 345 addr: Remote device MAC address. 346 status: floss_enums.GattStatus. 347 handle: Characteristic handle id. 348 value: Characteristic value. 349 """ 350 for observer in self.observers.values(): 351 observer.on_characteristic_read(addr, status, handle, value) 352 353 def OnCharacteristicWrite(self, addr, status, handle): 354 """Handles characteristic write callback. 355 356 Args: 357 addr: Remote device MAC address. 358 status: floss_enums.GattStatus. 359 handle: Characteristic handle id. 360 """ 361 for observer in self.observers.values(): 362 observer.on_characteristic_write(addr, status, handle) 363 364 def OnExecuteWrite(self, addr, status): 365 """Handles write execution callbacks. 366 367 Args: 368 addr: Remote device MAC address. 369 status: floss_enums.GattStatus. 370 """ 371 for observer in self.observers.values(): 372 observer.on_execute_write(addr, status) 373 374 def OnDescriptorRead(self, addr, status, handle, value): 375 """Handles descriptor read callback. 376 377 Args: 378 addr: Remote device MAC address. 379 status: floss_enums.GattStatus. 380 handle: Descriptor handle id. 381 value: Descriptor value. 382 """ 383 for observer in self.observers.values(): 384 observer.on_descriptor_read(addr, status, handle, value) 385 386 def OnDescriptorWrite(self, addr, status, handle): 387 """Handles descriptor write callback. 388 389 Args: 390 addr: Remote device MAC address. 391 status: floss_enums.GattStatus. 392 handle: Descriptor handle id. 393 """ 394 for observer in self.observers.values(): 395 observer.on_descriptor_write(addr, status, handle) 396 397 def OnNotify(self, addr, handle, value): 398 """Handles notification callback. 399 400 Args: 401 addr: Remote device MAC address. 402 handle: Characteristic handle id. 403 value: Characteristic value. 404 """ 405 for observer in self.observers.values(): 406 observer.on_notify(addr, handle, value) 407 408 def OnReadRemoteRssi(self, addr, rssi, status): 409 """Handles remote RSSI value read callback. 410 411 Args: 412 addr: Remote device MAC address. 413 rssi: RSSI value. 414 status: floss_enums.GattStatus. 415 """ 416 for observer in self.observers.values(): 417 observer.on_read_remote_rssi(addr, rssi, status) 418 419 def OnConfigureMtu(self, addr, mtu, status): 420 """Handles MTU configuration callback. 421 422 Args: 423 addr: Remote device MAC address. 424 mtu: MTU value. 425 status: floss_enums.GattStatus. 426 """ 427 for observer in self.observers.values(): 428 observer.on_configure_mtu(addr, mtu, status) 429 430 def OnConnectionUpdated(self, addr, interval, latency, timeout, status): 431 """Handles connection update callback. 432 433 Args: 434 addr: Remote device MAC address. 435 interval: Interval in ms. 436 latency: Latency in ms. 437 timeout: Timeout in ms. 438 status: floss_enums.GattStatus. 439 """ 440 for observer in self.observers.values(): 441 observer.on_connection_updated(addr, interval, latency, timeout, status) 442 443 def OnServiceChanged(self, addr): 444 """Handles service changed callback. 445 446 Args: 447 addr: Remote device MAC address. 448 """ 449 for observer in self.observers.values(): 450 observer.on_service_changed(addr) 451 452 def __init__(self, bus, hci): 453 """Constructs the client. 454 455 Args: 456 bus: D-Bus bus over which we'll establish connections. 457 hci: HCI adapter index. Get this value from `get_default_adapter` on FlossManagerClient. 458 """ 459 460 self.bus = bus 461 self.hci = hci 462 self.callbacks = None 463 self.callback_id = None 464 self.objpath = self.GATT_OBJECT_PATTERN.format(hci) 465 self.client_id = None 466 self.gatt_services = {} 467 self.connected_clients = {} 468 469 def __del__(self): 470 """Destructor.""" 471 del self.callbacks 472 473 @utils.glib_callback() 474 def on_client_registered(self, status, scanner_id): 475 """Handles client registration callback. 476 477 Args: 478 status: floss_enums.GattStatus. 479 scanner_id: Bluetooth GATT scanner id. 480 """ 481 logging.debug('on_client_registered: status: %s, scanner_id: %s', status, scanner_id) 482 483 if status != floss_enums.GattStatus.SUCCESS: 484 logging.error('Failed to register client with id: %s, status = %s', scanner_id, status) 485 return 486 self.client_id = scanner_id 487 488 @utils.glib_callback() 489 def on_client_connection_state(self, status, client_id, connected, addr): 490 """Handles client connection state callback. 491 492 Args: 493 status: floss_enums.GattStatus. 494 client_id: Bluetooth GATT client id. 495 connected: A boolean value representing whether the device is connected. 496 addr: Remote device MAC address. 497 """ 498 logging.debug('on_client_connection_state: status: %s, client_id: %s, ' 499 'connected: %s, addr: %s', status, client_id, connected, addr) 500 if status != floss_enums.GattStatus.SUCCESS: 501 return 502 self.connected_clients[addr] = connected 503 504 @utils.glib_callback() 505 def on_phy_update(self, addr, tx_phy, rx_phy, status): 506 """Handles physical type update callback. 507 508 Args: 509 addr: Remote device MAC address. 510 tx_phy: Transmit physical type. 511 rx_phy: Receive physical type. 512 status: floss_enums.GattStatus. 513 """ 514 logging.debug('on_phy_update: addr: %s, tx_phy: %s, rx_phy: %s, status: %s', addr, tx_phy, rx_phy, status) 515 516 @utils.glib_callback() 517 def on_phy_read(self, addr, tx_phy, rx_phy, status): 518 """Handles physical type read callback. 519 520 Args: 521 addr: Remote device MAC address. 522 tx_phy: Transmit physical type. 523 rx_phy: Receive physical type. 524 status: floss_enums.GattStatus. 525 """ 526 logging.debug('on_phy_read: addr: %s, tx_phy: %s, rx_phy: %s, status: %s', addr, tx_phy, rx_phy, status) 527 528 @utils.glib_callback() 529 def on_search_complete(self, addr, services, status): 530 """Handles search complete callback. 531 532 Args: 533 addr: Remote device MAC address. 534 services: Bluetooth GATT services as list. 535 status: floss_enums.GattStatus. 536 """ 537 logging.debug('on_search_complete: addr: %s, services: %s, status: %s', addr, services, status) 538 if status != floss_enums.GattStatus.SUCCESS: 539 logging.error('Failed to complete search') 540 return 541 self.gatt_services[addr] = services 542 543 @utils.glib_callback() 544 def on_characteristic_read(self, addr, status, handle, value): 545 """Handles characteristic read callback. 546 547 Args: 548 addr: Remote device MAC address. 549 status: floss_enums.GattStatus. 550 handle: Characteristic handle id. 551 value: Characteristic value. 552 """ 553 logging.debug('on_characteristic_read: addr: %s, status: %s, handle: %s, ' 554 'value: %s', addr, status, handle, value) 555 556 @utils.glib_callback() 557 def on_characteristic_write(self, addr, status, handle): 558 """Handles characteristic write callback. 559 560 Args: 561 addr: Remote device MAC address. 562 status: floss_enums.GattStatus. 563 handle: Characteristic handle id. 564 """ 565 logging.debug('on_characteristic_write: addr: %s, status: %s, handle: %s', addr, status, handle) 566 567 @utils.glib_callback() 568 def on_execute_write(self, addr, status): 569 """Handles write execution callbacks. 570 571 Args: 572 addr: Remote device MAC address. 573 status: floss_enums.GattStatus. 574 """ 575 logging.debug('on_execute_write: addr: %s, status: %s', addr, status) 576 577 @utils.glib_callback() 578 def on_descriptor_read(self, addr, status, handle, value): 579 """Handles descriptor read callback. 580 581 Args: 582 addr: Remote device MAC address. 583 status: floss_enums.GattStatus. 584 handle: Descriptor handle id. 585 value: Descriptor value. 586 """ 587 logging.debug('on_descriptor_read: addr: %s, status: %s, handle: %s, value: %s', addr, status, handle, value) 588 589 @utils.glib_callback() 590 def on_descriptor_write(self, addr, status, handle): 591 """Handles descriptor write callback. 592 593 Args: 594 addr: Remote device MAC address. 595 status: floss_enums.GattStatus. 596 handle: Descriptor handle id. 597 """ 598 logging.debug('on_descriptor_write: addr: %s, status: %s, handle: %s', addr, status, handle) 599 600 @utils.glib_callback() 601 def on_notify(self, addr, handle, value): 602 """Handles notification callback. 603 604 Args: 605 addr: Remote device MAC address. 606 handle: Characteristic handle id. 607 value: Characteristic value. 608 """ 609 logging.debug('on_notify: addr: %s, handle: %s, value: %s', addr, handle, value) 610 611 @utils.glib_callback() 612 def on_read_remote_rssi(self, addr, rssi, status): 613 """Handles remote RSSI value read callback. 614 615 Args: 616 addr: Remote device MAC address. 617 rssi: RSSI value. 618 status: floss_enums.GattStatus. 619 """ 620 logging.debug('on_read_remote_rssi: addr: %s, rssi: %s, status: %s', addr, rssi, status) 621 622 @utils.glib_callback() 623 def on_configure_mtu(self, addr, mtu, status): 624 """Handles MTU configuration callback. 625 626 Args: 627 addr: Remote device MAC address. 628 mtu: MTU value. 629 status: floss_enums.GattStatus. 630 """ 631 logging.debug('on_configure_mtu: addr: %s, mtu: %s, status: %s', addr, mtu, status) 632 633 @utils.glib_callback() 634 def on_connection_updated(self, addr, interval, latency, timeout, status): 635 """Handles connection update callback. 636 637 Args: 638 addr: Remote device MAC address. 639 interval: Interval in ms. 640 latency: Latency in ms. 641 timeout: Timeout in ms. 642 status: floss_enums.GattStatus. 643 """ 644 logging.debug('on_connection_updated: addr: %s, interval: %s, latency: %s, ' 645 'timeout: %s, status: %s', addr, interval, latency, timeout, status) 646 647 @utils.glib_callback() 648 def on_service_changed(self, addr): 649 """Handles service changed callback. 650 651 Args: 652 addr: Remote device MAC address. 653 """ 654 logging.debug('on_service_changed: addr: %s', addr) 655 656 @utils.glib_call(False) 657 def has_proxy(self): 658 """Checks whether GATT Client can be acquired.""" 659 return bool(self.proxy()) 660 661 def proxy(self): 662 """Gets proxy object to GATT Client interface for method calls.""" 663 return self.bus.get(self.ADAPTER_SERVICE, self.objpath)[self.GATT_CLIENT_INTERFACE] 664 665 @utils.glib_call(False) 666 def register_client(self, app_uuid, eatt_support): 667 """Registers GATT client callbacks if one doesn't already exist. 668 669 Args: 670 app_uuid: GATT application uuid. 671 eatt_support: A boolean value that indicates whether eatt is supported. 672 673 Returns: 674 True on success, False otherwise. 675 """ 676 # Callbacks already registered 677 if self.callbacks: 678 return True 679 # Create and publish callbacks 680 self.callbacks = self.ExportedGattClientCallbacks() 681 self.callbacks.add_observer('gatt_testing_client', self) 682 objpath = utils.generate_dbus_cb_objpath(self.GATT_CB_OBJ_NAME, self.hci) 683 self.bus.register_object(objpath, self.callbacks, None) 684 # Register published callbacks with adapter daemon 685 self.callback_id = self.proxy().RegisterClient(app_uuid, objpath, eatt_support) 686 return True 687 688 @utils.glib_call(False) 689 def unregister_client(self): 690 """Unregisters GATT client. 691 692 Returns: 693 True on success, False otherwise. 694 """ 695 self.proxy().UnregisterClient(self.client_id) 696 return True 697 698 def register_callback_observer(self, name, observer): 699 """Add an observer for all callbacks. 700 701 Args: 702 name: Name of the observer. 703 observer: Observer that implements all callback classes. 704 """ 705 if isinstance(observer, GattClientCallbacks): 706 self.callbacks.add_observer(name, observer) 707 708 def unregister_callback_observer(self, name, observer): 709 """Remove an observer for all callbacks. 710 711 Args: 712 name: Name of the observer. 713 observer: Observer that implements all callback classes. 714 """ 715 if isinstance(observer, GattClientCallbacks): 716 self.callbacks.remove_observer(name, observer) 717 718 @utils.glib_call(False) 719 def connect_client(self, 720 address, 721 is_direct=False, 722 transport=floss_enums.BtTransport.LE, 723 opportunistic=False, 724 phy=floss_enums.LePhy.PHY1M): 725 """Connects GATT client. 726 727 Args: 728 address: Remote device MAC address. 729 is_direct: A boolean value represent direct status. 730 transport: floss_enums.BtTransport type. 731 opportunistic: A boolean value represent opportunistic status. 732 phy: floss_enums.LePhy type. 733 734 Returns: 735 True on success, False otherwise. 736 """ 737 self.proxy().ClientConnect(self.client_id, address, is_direct, transport, opportunistic, phy) 738 return True 739 740 @utils.glib_call(False) 741 def disconnect_client(self, address): 742 """Disconnects GATT client. 743 744 Args: 745 address: Remote device MAC address. 746 747 Returns: 748 True on success, False otherwise. 749 """ 750 self.proxy().ClientDisconnect(self.client_id, address) 751 return True 752 753 @utils.glib_call(False) 754 def refresh_device(self, address): 755 """Refreshes device. 756 757 Args: 758 address: Remote device MAC address. 759 760 Returns: 761 True on success, False otherwise. 762 """ 763 self.proxy().RefreshDevice(self.client_id, address) 764 return True 765 766 @utils.glib_call(False) 767 def discover_services(self, address): 768 """Discovers remote device GATT services. 769 770 Args: 771 address: Remote device MAC address. 772 773 Returns: 774 True on success, False otherwise. 775 """ 776 self.proxy().DiscoverServices(self.client_id, address) 777 return True 778 779 @utils.glib_call(False) 780 def discover_service_by_uuid(self, address, uuid): 781 """Discovers remote device GATT services by UUID. 782 783 Args: 784 address: Remote device MAC address. 785 uuid: The service UUID as a string. 786 787 Returns: 788 True on success, False otherwise. 789 """ 790 self.proxy().DiscoverServiceByUuid(self.client_id, address, uuid) 791 return True 792 793 @utils.glib_call(False) 794 def btif_gattc_discover_service_by_uuid(self, address, uuid): 795 """Discovers remote device GATT services by UUID from btif layer. 796 797 Args: 798 address: Remote device MAC address. 799 uuid: The service UUID as a string. 800 801 Returns: 802 True on success, False otherwise. 803 """ 804 self.proxy().BtifGattcDiscoverServiceByUuid(self.client_id, address, uuid) 805 return True 806 807 @utils.glib_call(False) 808 def read_characteristic(self, address, handle, auth_req): 809 """Reads GATT characteristic. 810 811 Args: 812 address: Remote device MAC address. 813 handle: Characteristic handle id. 814 auth_req: Authentication requirements value. 815 816 Returns: 817 True on success, False otherwise. 818 """ 819 self.proxy().ReadCharacteristic(self.client_id, address, handle, auth_req) 820 return True 821 822 @utils.glib_call(False) 823 def read_using_characteristic_uuid(self, address, uuid, start_handle, end_handle, auth_req): 824 """Reads remote device GATT characteristic by UUID. 825 826 Args: 827 address: Remote device MAC address. 828 uuid: The characteristic UUID as a string. 829 start_handle: Characteristic start handle id. 830 end_handle: Characteristic end handle id. 831 auth_req: Authentication requirements value. 832 833 Returns: 834 True on success, False otherwise. 835 """ 836 self.proxy().ReadUsingCharacteristicUuid(self.client_id, address, uuid, start_handle, end_handle, auth_req) 837 return True 838 839 @utils.glib_call(False) 840 def read_descriptor(self, address, handle, auth_req): 841 """Reads remote device GATT descriptor. 842 843 Args: 844 address: Remote device MAC address. 845 handle: Descriptor handle id. 846 auth_req: Authentication requirements value. 847 848 Returns: 849 True on success, False otherwise. 850 """ 851 self.proxy().ReadDescriptor(self.client_id, address, handle, auth_req) 852 return True 853 854 @utils.glib_call(False) 855 def write_descriptor(self, address, handle, auth_req, value): 856 """Writes remote device GATT descriptor. 857 858 Args: 859 address: Remote device MAC address. 860 handle: Descriptor handle id. 861 auth_req: Authentication requirements value. 862 value: Descriptor value to write. 863 864 Returns: 865 True on success, False otherwise. 866 """ 867 self.proxy().WriteDescriptor(self.client_id, address, handle, auth_req, value) 868 return True 869 870 @utils.glib_call(None) 871 def write_characteristic(self, address, handle, write_type, auth_req, value): 872 """Writes remote device GATT characteristic. 873 874 Args: 875 address: Remote device MAC address. 876 handle: Characteristic handle id. 877 write_type: Characteristic write type. 878 auth_req: Authentication requirements value. 879 value: Characteristic value to write. 880 881 Returns: 882 GattWriteRequestStatus on success, None otherwise. 883 """ 884 return self.proxy().WriteCharacteristic(self.client_id, address, handle, write_type, auth_req, value) 885 886 @utils.glib_call(False) 887 def register_for_notification(self, address, handle, enable): 888 """Registers for notification. 889 890 Args: 891 address: Remote device MAC address. 892 handle: Characteristic handle id. 893 enable: Boolean value represents enabling or disabling notify. 894 895 Returns: 896 True on success, False otherwise. 897 """ 898 self.proxy().RegisterForNotification(self.client_id, address, handle, enable) 899 return True 900 901 @utils.glib_call(False) 902 def begin_reliable_write(self, address): 903 """Begins a reliable write transaction. 904 905 Args: 906 address: Remote device MAC address. 907 908 Returns: 909 True on success, False otherwise. 910 """ 911 self.proxy().BeginReliableWrite(self.client_id, address) 912 return True 913 914 @utils.glib_call(False) 915 def end_reliable_write(self, address, execute): 916 """Ends the reliable write transaction. 917 918 Args: 919 address: Remote device MAC address. 920 execute: Boolean to execute or not. 921 922 Returns: 923 True on success, False otherwise. 924 """ 925 self.proxy().EndReliableWrite(self.client_id, address, execute) 926 return True 927 928 @utils.glib_call(False) 929 def read_remote_rssi(self, address): 930 """Reads remote device RSSI. 931 932 Args: 933 address: Remote device MAC address. 934 935 Returns: 936 True on success, False otherwise. 937 """ 938 self.proxy().ReadRemoteRssi(self.client_id, address) 939 return True 940 941 @utils.glib_call(False) 942 def configure_mtu(self, address, mtu): 943 """Configures MTU value. 944 945 Args: 946 address: Remote device MAC address. 947 mtu: MTU value. 948 949 Returns: 950 True on success, False otherwise. 951 """ 952 self.proxy().ConfigureMtu(self.client_id, address, mtu) 953 return True 954 955 @utils.glib_call(False) 956 def update_connection_parameter(self, address, min_interval, max_interval, latency, timeout, min_ce_len, 957 max_ce_len): 958 """Updates connection parameters. 959 960 Args: 961 address: Remote device MAC address. 962 min_interval: Minimum interval in ms. 963 max_interval: Maximum interval in ms. 964 latency: Latency interval in ms. 965 timeout: Timeout interval in ms. 966 min_ce_len: Connection event minimum length in ms. 967 max_ce_len: Connection event maximum length in ms. 968 969 Returns: 970 True on success, False otherwise. 971 """ 972 self.proxy().ConnectionParameterUpdate(self.client_id, address, min_interval, max_interval, latency, timeout, 973 min_ce_len, max_ce_len) 974 return True 975 976 @utils.glib_call(False) 977 def set_preferred_phy(self, address, tx_phy, rx_phy, phy_options): 978 """Sets remote device preferred physical options. 979 980 Args: 981 address: Remote device MAC address. 982 tx_phy: Transmit physical type. 983 rx_phy: Receive physical type. 984 phy_options: Physical options to use for connection. 985 986 Returns: 987 True on success, False otherwise. 988 """ 989 self.proxy().ClientSetPreferredPhy(self.client_id, address, tx_phy, rx_phy, phy_options) 990 return True 991 992 @utils.glib_call(False) 993 def read_phy(self, address): 994 """Reads remote device physical setting. 995 996 Args: 997 address: Remote device MAC address. 998 999 Returns: 1000 True on success, False otherwise. 1001 """ 1002 self.proxy().ClientReadPhy(self.client_id, address) 1003 return True 1004 1005 def wait_for_client_connected(self, address): 1006 """Waits for GATT client to be connected. 1007 1008 Args: 1009 address: Remote device MAC address. 1010 1011 Returns: 1012 True on success, False otherwise. 1013 """ 1014 try: 1015 utils.poll_for_condition(condition=lambda: self.connected_clients.get(address), 1016 timeout=self.FLOSS_RESPONSE_LATENCY_SECS) 1017 return True 1018 1019 except utils.TimeoutError: 1020 logging.error('on_client_connection_state not called') 1021 return False 1022 1023 def wait_for_search_complete(self, address): 1024 """Waits for GATT search to be completed. 1025 1026 Args: 1027 address: Remote device MAC address. 1028 1029 Returns: 1030 True on success, False otherwise. 1031 """ 1032 try: 1033 utils.poll_for_condition(condition=lambda: address in self.gatt_services, 1034 timeout=self.FLOSS_RESPONSE_LATENCY_SECS) 1035 return True 1036 1037 except utils.TimeoutError: 1038 logging.error('on_search_complete not called') 1039 return False 1040 1041 def connect_client_sync(self, address): 1042 """Connects GATT client. 1043 1044 Args: 1045 address: Remote device MAC address. 1046 1047 Returns: 1048 Client id on success, None otherwise. 1049 """ 1050 self.connect_client(address=address) 1051 if not self.wait_for_client_connected(address): 1052 return None 1053 return self.connected_clients[address] 1054 1055 def discover_services_sync(self, address): 1056 """Discovers remote device GATT services. 1057 1058 Args: 1059 address: Remote device MAC address. 1060 1061 Returns: 1062 Remote device GATT services as a list on success, None otherwise. 1063 """ 1064 self.discover_services(address) 1065 if not self.wait_for_search_complete(address): 1066 return None 1067 return self.gatt_services[address] 1068 1069 def register_callback_observer(self, name, observer): 1070 """Adds an observer for all callbacks. 1071 1072 Args: 1073 name: Name of the observer. 1074 observer: Observer that implements all callback classes. 1075 """ 1076 if isinstance(observer, GattClientCallbacks): 1077 self.callbacks.add_observer(name, observer) 1078 1079 def unregister_callback_observer(self, name, observer): 1080 """Removes an observer for all callbacks. 1081 1082 Args: 1083 name: Name of the observer. 1084 observer: Observer that implements all callback classes. 1085 """ 1086 if isinstance(observer, GattClientCallbacks): 1087 self.callbacks.remove_observer(name, observer) 1088