1# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import base64 6import json 7import logging 8from datetime import datetime 9 10from autotest_lib.client.bin import utils 11from autotest_lib.client.cros import constants 12from autotest_lib.server import autotest 13 14 15class BluetoothDevice(object): 16 """BluetoothDevice is a thin layer of logic over a remote DUT. 17 18 The Autotest host object representing the remote DUT, passed to this 19 class on initialization, can be accessed from its host property. 20 21 """ 22 23 XMLRPC_BRINGUP_TIMEOUT_SECONDS = 60 24 XMLRPC_LOG_PATH = '/var/log/bluetooth_xmlrpc_device.log' 25 26 def __init__(self, device_host): 27 """Construct a BluetoothDevice. 28 29 @param device_host: host object representing a remote host. 30 31 """ 32 self.host = device_host 33 # Make sure the client library is on the device so that the proxy code 34 # is there when we try to call it. 35 client_at = autotest.Autotest(self.host) 36 client_at.install() 37 # Start up the XML-RPC proxy on the client. 38 self._proxy = self.host.rpc_server_tracker.xmlrpc_connect( 39 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_COMMAND, 40 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT, 41 command_name= 42 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_CLEANUP_PATTERN, 43 ready_test_name= 44 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_READY_METHOD, 45 timeout_seconds=self.XMLRPC_BRINGUP_TIMEOUT_SECONDS, 46 logfile=self.XMLRPC_LOG_PATH) 47 48 # Get some static information about the bluetooth adapter. 49 properties = self.get_adapter_properties() 50 self.bluez_version = properties.get('Name') 51 self.address = properties.get('Address') 52 self.bluetooth_class = properties.get('Class') 53 self.UUIDs = properties.get('UUIDs') 54 55 56 def set_debug_log_levels(self, dispatcher_vb, newblue_vb, bluez_vb, 57 kernel_vb): 58 """Enable or disable the debug logs of bluetooth 59 60 @param dispatcher_vb: verbosity of btdispatcher debug log, either 0 or 1 61 @param newblue_vb: verbosity of newblued debug log, either 0 or 1 62 @param bluez_vb: verbosity of bluez debug log, either 0 or 1 63 @param kernel_vb: verbosity of kernel debug log, either 0 or 1 64 65 """ 66 return self._proxy.set_debug_log_levels(dispatcher_vb, newblue_vb, 67 bluez_vb, kernel_vb) 68 69 def log_message(self, msg, dut=True, peer=True): 70 """ Log a message in DUT log and peer logs with timestamp. 71 72 @param msg: message to be logged. 73 @param dut: log message on DUT 74 @param peer: log message on peer devices 75 """ 76 try: 77 # TODO(b/146671469) Implement logging to tester 78 79 date = datetime.strftime(datetime.now(),"%Y:%m:%d %H:%M:%S:%f") 80 msg = "bluetooth autotest --- %s : %s ---" % (date, msg) 81 logging.debug("Broadcasting '%s'",msg) 82 83 if dut: 84 self._proxy.log_message(msg) 85 86 if peer: 87 for chameleon in self.host.chameleon_list: 88 chameleon.log_message(msg) 89 except Exception as e: 90 logging.error("Exception '%s' in log_message '%s'", str(e), msg) 91 92 93 94 def start_bluetoothd(self): 95 """start bluetoothd. 96 97 @returns: True if bluetoothd is started correctly. 98 False otherwise. 99 100 """ 101 return self._proxy.start_bluetoothd() 102 103 104 def stop_bluetoothd(self): 105 """stop bluetoothd. 106 107 @returns: True if bluetoothd is stopped correctly. 108 False otherwise. 109 110 """ 111 return self._proxy.stop_bluetoothd() 112 113 114 def is_bluetoothd_running(self): 115 """Is bluetoothd running? 116 117 @returns: True if bluetoothd is running 118 119 """ 120 return self._proxy.is_bluetoothd_running() 121 122 123 def reset_on(self): 124 """Reset the adapter and settings and power up the adapter. 125 126 @return True on success, False otherwise. 127 128 """ 129 return self._proxy.reset_on() 130 131 132 def reset_off(self): 133 """Reset the adapter and settings, leave the adapter powered off. 134 135 @return True on success, False otherwise. 136 137 """ 138 return self._proxy.reset_off() 139 140 141 def has_adapter(self): 142 """@return True if an adapter is present, False if not.""" 143 return self._proxy.has_adapter() 144 145 146 def set_powered(self, powered): 147 """Set the adapter power state. 148 149 @param powered: adapter power state to set (True or False). 150 151 @return True on success, False otherwise. 152 153 """ 154 return self._proxy.set_powered(powered) 155 156 157 def is_powered_on(self): 158 """Is the adapter powered on? 159 160 @returns: True if the adapter is powered on 161 162 """ 163 properties = self.get_adapter_properties() 164 return bool(properties.get(u'Powered')) 165 166 167 def get_hci(self): 168 """Get hci of the adapter; normally, it is 'hci0'. 169 170 @returns: the hci name of the adapter. 171 172 """ 173 dev_info = self.get_dev_info() 174 hci = (dev_info[1] if isinstance(dev_info, list) and 175 len(dev_info) > 1 else None) 176 return hci 177 178 179 def get_address(self): 180 """Get the bluetooth address of the adapter. 181 182 An example of the bluetooth address of the adapter: '6C:29:95:1A:D4:6F' 183 184 @returns: the bluetooth address of the adapter. 185 186 """ 187 return self.address 188 189 190 def get_bluez_version(self): 191 """Get bluez version. 192 193 An exmaple of bluez version: 'BlueZ 5.39' 194 195 @returns: the bluez version 196 197 """ 198 return self.bluez_version 199 200 201 def get_bluetooth_class(self): 202 """Get the bluetooth class of the adapter. 203 204 An example of the bluetooth class of a chromebook: 4718852 205 206 @returns: the bluetooth class. 207 208 """ 209 return self.bluetooth_class 210 211 212 def get_UUIDs(self): 213 """Get the UUIDs. 214 215 An example of UUIDs: 216 [u'00001112-0000-1000-8000-00805f9b34fb', 217 u'00001801-0000-1000-8000-00805f9b34fb', 218 u'0000110a-0000-1000-8000-00805f9b34fb', 219 u'0000111f-0000-1000-8000-00805f9b34fb', 220 u'00001200-0000-1000-8000-00805f9b34fb', 221 u'00001800-0000-1000-8000-00805f9b34fb'] 222 223 @returns: the list of the UUIDs. 224 225 """ 226 return self.UUIDs 227 228 229 def set_discoverable(self, discoverable): 230 """Set the adapter discoverable state. 231 232 @param discoverable: adapter discoverable state to set (True or False). 233 234 @return True on success, False otherwise. 235 236 """ 237 return self._proxy.set_discoverable(discoverable) 238 239 240 def is_discoverable(self): 241 """Is the adapter in the discoverable state? 242 243 @return True if discoverable. False otherwise. 244 245 """ 246 properties = self.get_adapter_properties() 247 return properties.get('Discoverable') == 1 248 249 250 def set_discoverable_timeout(self, discoverable_timeout): 251 """Set the adapter DiscoverableTimeout. 252 253 @param discoverable_timeout: adapter DiscoverableTimeout 254 value to set in seconds (Integer). 255 256 @return True on success, False otherwise. 257 258 """ 259 return self._proxy.set_discoverable_timeout(discoverable_timeout) 260 261 def get_discoverable_timeout(self): 262 """Get the adapter DiscoverableTimeout. 263 264 @return Value of property DiscoverableTimeout in seconds (Integer). 265 266 """ 267 return self._proxy.get_discoverable_timeout() 268 269 def set_pairable_timeout(self, pairable_timeout): 270 """Set the adapter PairableTimeout. 271 272 @param pairable_timeout: adapter PairableTimeout 273 value to set in seconds (Integer). 274 275 @return True on success, False otherwise. 276 277 """ 278 return self._proxy.set_pairable_timeout(pairable_timeout) 279 280 def get_pairable_timeout(self): 281 """Get the adapter PairableTimeout. 282 283 @return Value of property PairableTimeout in seconds (Integer). 284 285 """ 286 return self._proxy.get_pairable_timeout() 287 288 289 def set_pairable(self, pairable): 290 """Set the adapter pairable state. 291 292 @param pairable: adapter pairable state to set (True or False). 293 294 @return True on success, False otherwise. 295 296 """ 297 return self._proxy.set_pairable(pairable) 298 299 300 def is_pairable(self): 301 """Is the adapter in the pairable state? 302 303 @return True if pairable. False otherwise. 304 305 """ 306 properties = self.get_adapter_properties() 307 return properties.get('Pairable') == 1 308 309 310 def get_adapter_properties(self): 311 """Read the adapter properties from the Bluetooth Daemon. 312 313 An example of the adapter properties looks like 314 {u'Name': u'BlueZ 5.35', 315 u'Alias': u'Chromebook', 316 u'Modalias': u'bluetooth:v00E0p2436d0400', 317 u'Powered': 1, 318 u'DiscoverableTimeout': 180, 319 u'PairableTimeout': 0, 320 u'Discoverable': 0, 321 u'Address': u'6C:29:95:1A:D4:6F', 322 u'Discovering': 0, 323 u'Pairable': 1, 324 u'Class': 4718852, 325 u'UUIDs': [u'00001112-0000-1000-8000-00805f9b34fb', 326 u'00001801-0000-1000-8000-00805f9b34fb', 327 u'0000110a-0000-1000-8000-00805f9b34fb', 328 u'0000111f-0000-1000-8000-00805f9b34fb', 329 u'00001200-0000-1000-8000-00805f9b34fb', 330 u'00001800-0000-1000-8000-00805f9b34fb']} 331 332 @return the properties as a dictionary on success, 333 the value False otherwise. 334 335 """ 336 return json.loads(self._proxy.get_adapter_properties()) 337 338 339 def read_version(self): 340 """Read the version of the management interface from the Kernel. 341 342 @return the version as a tuple of: 343 ( version, revision ) 344 345 """ 346 return json.loads(self._proxy.read_version()) 347 348 349 def read_supported_commands(self): 350 """Read the set of supported commands from the Kernel. 351 352 @return set of supported commands as arrays in a tuple of: 353 ( commands, events ) 354 355 """ 356 return json.loads(self._proxy.read_supported_commands()) 357 358 359 def read_index_list(self): 360 """Read the list of currently known controllers from the Kernel. 361 362 @return array of controller indexes. 363 364 """ 365 return json.loads(self._proxy.read_index_list()) 366 367 368 def read_info(self): 369 """Read the adapter information from the Kernel. 370 371 An example of the adapter information looks like 372 [u'6C:29:95:1A:D4:6F', 6, 2, 65535, 2769, 4718852, u'Chromebook', u''] 373 374 @return the information as a tuple of: 375 ( address, bluetooth_version, manufacturer_id, 376 supported_settings, current_settings, class_of_device, 377 name, short_name ) 378 379 """ 380 return json.loads(self._proxy.read_info()) 381 382 383 def add_device(self, address, address_type, action): 384 """Add a device to the Kernel action list. 385 386 @param address: Address of the device to add. 387 @param address_type: Type of device in @address. 388 @param action: Action to take. 389 390 @return tuple of ( address, address_type ) on success, 391 None on failure. 392 393 """ 394 return json.loads(self._proxy.add_device(address, address_type, action)) 395 396 397 def remove_device(self, address, address_type): 398 """Remove a device from the Kernel action list. 399 400 @param address: Address of the device to remove. 401 @param address_type: Type of device in @address. 402 403 @return tuple of ( address, address_type ) on success, 404 None on failure. 405 406 """ 407 return json.loads(self._proxy.remove_device(address, address_type)) 408 409 def _decode_json_base64(self, data): 410 """Load serialized JSON and then base64 decode it 411 412 Required to handle non-ascii data 413 @param data: data to be JSON and base64 decode 414 415 @return : JSON and base64 decoded date 416 417 418 """ 419 logging.debug("_decode_json_base64 raw data is %s", data) 420 json_encoded = json.loads(data) 421 logging.debug("JSON encoded data is %s", json_encoded) 422 base64_decoded = utils.base64_recursive_decode(json_encoded) 423 logging.debug("base64 decoded data is %s", base64_decoded) 424 return base64_decoded 425 426 def get_devices(self): 427 """Read information about remote devices known to the adapter. 428 429 An example of the device information of RN-42 looks like 430 [{u'Name': u'RNBT-A96F', 431 u'Alias': u'RNBT-A96F', 432 u'Adapter': u'/org/bluez/hci0', 433 u'LegacyPairing': 0, 434 u'Paired': 1, 435 u'Connected': 0, 436 u'UUIDs': [u'00001124-0000-1000-8000-00805f9b34fb'], 437 u'Address': u'00:06:66:75:A9:6F', 438 u'Icon': u'input-mouse', 439 u'Class': 1408, 440 u'Trusted': 1, 441 u'Blocked': 0}] 442 443 @return the properties of each device as an array of 444 dictionaries on success, the value False otherwise. 445 446 """ 447 encoded_devices = self._proxy.get_devices() 448 return self._decode_json_base64(encoded_devices) 449 450 451 def get_device_property(self, address, prop_name): 452 """Read a property of BT device by directly querying device dbus object 453 454 @param address: Address of the device to query 455 @param prop_name: Property to be queried 456 457 @return The property if device is found and has property, None otherwise 458 """ 459 460 prop_val = self._proxy.get_device_property(address, prop_name) 461 462 # Handle dbus error case returned by xmlrpc_server.dbus_safe decorator 463 if prop_val is None: 464 return prop_val 465 466 # Decode and return property value 467 return self._decode_json_base64(prop_val) 468 469 470 def start_discovery(self): 471 """Start discovery of remote devices. 472 473 Obtain the discovered device information using get_devices(), called 474 stop_discovery() when done. 475 476 @return (True, None) on success, (False, <error>) otherwise. 477 478 """ 479 return self._proxy.start_discovery() 480 481 482 def stop_discovery(self): 483 """Stop discovery of remote devices. 484 485 @return (True, None) on success, (False, <error>) otherwise. 486 487 """ 488 return self._proxy.stop_discovery() 489 490 def pause_discovery(self, system_suspend_resume=False): 491 """ Pause discovery of remote devices 492 493 @params: boolean system_suspend_resume Is this request related to 494 system suspend resume. 495 496 @return (True, None) on success (False, <error>) otherwise 497 """ 498 return self._proxy.pause_discovery(system_suspend_resume) 499 500 def unpause_discovery(self, system_suspend_resume=False): 501 """ Unpause discovery of remote devices 502 503 @params: boolean system_suspend_resume Is this request related to 504 system suspend resume. 505 506 @return (True, None) on success (False, <error>) otherwise 507 """ 508 return self._proxy.unpause_discovery(system_suspend_resume) 509 510 511 def pause_discovery(self, system_suspend_resume=False): 512 """Pause discovery of remote devices. 513 514 This pauses all device discovery sessions. 515 516 @param system_suspend_resume: whether the 517 request is related to system suspend/resume. 518 519 @return True on success, False otherwise. 520 521 """ 522 return self._proxy.pause_discovery(system_suspend_resume) 523 524 525 def unpause_discovery(self, system_suspend_resume=False): 526 """Unpause discovery of remote devices. 527 528 This unpauses all device discovery sessions. 529 530 @param system_suspend_resume: whether the 531 request is related to system suspend/resume. 532 533 @return True on success, False otherwise. 534 535 """ 536 return self._proxy.unpause_discovery(system_suspend_resume) 537 538 539 def is_discovering(self): 540 """Is it discovering? 541 542 @return True if it is discovering. False otherwise. 543 544 """ 545 return self.get_adapter_properties().get('Discovering') == 1 546 547 548 def get_dev_info(self): 549 """Read raw HCI device information. 550 551 An example of the device information looks like: 552 [0, u'hci0', u'6C:29:95:1A:D4:6F', 13, 0, 1, 581900950526, 52472, 7, 553 32768, 1021, 5, 96, 6, 0, 0, 151, 151, 0, 0, 0, 0, 1968, 12507] 554 555 @return tuple of (index, name, address, flags, device_type, bus_type, 556 features, pkt_type, link_policy, link_mode, 557 acl_mtu, acl_pkts, sco_mtu, sco_pkts, 558 err_rx, err_tx, cmd_tx, evt_rx, acl_tx, acl_rx, 559 sco_tx, sco_rx, byte_rx, byte_tx) on success, 560 None on failure. 561 562 """ 563 return json.loads(self._proxy.get_dev_info()) 564 565 def get_supported_capabilities(self): 566 """ Get the supported_capabilities of the adapter 567 @returns (capabilities,None) on success (None, <error>) on failure 568 """ 569 return self._proxy.get_supported_capabilities() 570 571 def register_profile(self, path, uuid, options): 572 """Register new profile (service). 573 574 @param path: Path to the profile object. 575 @param uuid: Service Class ID of the service as string. 576 @param options: Dictionary of options for the new service, compliant 577 with BlueZ D-Bus Profile API standard. 578 579 @return True on success, False otherwise. 580 581 """ 582 return self._proxy.register_profile(path, uuid, options) 583 584 585 def has_device(self, address): 586 """Checks if the device with a given address exists. 587 588 @param address: Address of the device. 589 590 @returns: True if there is a device with that address. 591 False otherwise. 592 593 """ 594 return self._proxy.has_device(address) 595 596 597 def device_is_paired(self, address): 598 """Checks if a device is paired. 599 600 @param address: address of the device. 601 602 @returns: True if device is paired. False otherwise. 603 604 """ 605 return self._proxy.device_is_paired(address) 606 607 608 def device_services_resolved(self, address): 609 """Checks if services are resolved for a device. 610 611 @param address: address of the device. 612 613 @returns: True if services are resolved. False otherwise. 614 615 """ 616 return self._proxy.device_services_resolved(address) 617 618 619 def set_trusted(self, address, trusted=True): 620 """Set the device trusted. 621 622 @param address: The bluetooth address of the device. 623 @param trusted: True or False indicating whether to set trusted or not. 624 625 @returns: True if successful. False otherwise. 626 627 """ 628 return self._proxy.set_trusted(address, trusted) 629 630 631 def pair_legacy_device(self, address, pin, trusted, timeout): 632 """Pairs a device with a given pin code. 633 634 Registers an agent who handles pin code request and 635 pairs a device with known pin code. 636 637 @param address: Address of the device to pair. 638 @param pin: The pin code of the device to pair. 639 @param trusted: indicating whether to set the device trusted. 640 @param timeout: The timeout in seconds for pairing. 641 642 @returns: True on success. False otherwise. 643 644 """ 645 return self._proxy.pair_legacy_device(address, pin, trusted, timeout) 646 647 648 def remove_device_object(self, address): 649 """Removes a device object and the pairing information. 650 651 Calls RemoveDevice method to remove remote device 652 object and the pairing information. 653 654 @param address: address of the device to unpair. 655 656 @returns: True on success. False otherwise. 657 658 """ 659 return self._proxy.remove_device_object(address) 660 661 662 def connect_device(self, address): 663 """Connects a device. 664 665 Connects a device if it is not connected. 666 667 @param address: Address of the device to connect. 668 669 @returns: True on success. False otherwise. 670 671 """ 672 return self._proxy.connect_device(address) 673 674 675 def device_is_connected(self, address): 676 """Checks if a device is connected. 677 678 @param address: Address of the device to check if it is connected. 679 680 @returns: True if device is connected. False otherwise. 681 682 """ 683 return self._proxy.device_is_connected(address) 684 685 686 def disconnect_device(self, address): 687 """Disconnects a device. 688 689 Disconnects a device if it is connected. 690 691 @param address: Address of the device to disconnect. 692 693 @returns: True on success. False otherwise. 694 695 """ 696 return self._proxy.disconnect_device(address) 697 698 699 def btmon_start(self): 700 """Start btmon monitoring.""" 701 self._proxy.btmon_start() 702 703 704 def btmon_stop(self): 705 """Stop btmon monitoring.""" 706 self._proxy.btmon_stop() 707 708 709 def btmon_get(self, search_str='', start_str=''): 710 """Get btmon output contents. 711 712 @param search_str: only lines with search_str would be kept. 713 @param start_str: all lines before the occurrence of start_str would be 714 filtered. 715 716 @returns: the recorded btmon output. 717 718 """ 719 return self._proxy.btmon_get(search_str, start_str) 720 721 722 def btmon_find(self, pattern_str): 723 """Find if a pattern string exists in btmon output. 724 725 @param pattern_str: the pattern string to find. 726 727 @returns: True on success. False otherwise. 728 729 """ 730 return self._proxy.btmon_find(pattern_str) 731 732 733 def register_advertisement(self, advertisement_data): 734 """Register an advertisement. 735 736 Note that rpc supports only conformable types. Hence, a 737 dict about the advertisement is passed as a parameter such 738 that the advertisement object could be contructed on the host. 739 740 @param advertisement_data: a dict of the advertisement for 741 the adapter to register. 742 743 @returns: True on success. False otherwise. 744 745 """ 746 return self._proxy.register_advertisement(advertisement_data) 747 748 749 def unregister_advertisement(self, advertisement_data): 750 """Unregister an advertisement. 751 752 @param advertisement_data: a dict of the advertisement to unregister. 753 754 @returns: True on success. False otherwise. 755 756 """ 757 return self._proxy.unregister_advertisement(advertisement_data) 758 759 760 def set_advertising_intervals(self, min_adv_interval_ms, 761 max_adv_interval_ms): 762 """Set advertising intervals. 763 764 @param min_adv_interval_ms: the min advertising interval in ms. 765 @param max_adv_interval_ms: the max advertising interval in ms. 766 767 @returns: True on success. False otherwise. 768 769 """ 770 return self._proxy.set_advertising_intervals(min_adv_interval_ms, 771 max_adv_interval_ms) 772 773 774 def reset_advertising(self): 775 """Reset advertising. 776 777 This includes unregister all advertisements, reset advertising 778 intervals, and disable advertising. 779 780 @returns: True on success. False otherwise. 781 782 """ 783 return self._proxy.reset_advertising() 784 785 786 def read_characteristic(self, uuid, address): 787 """Reads the value of a gatt characteristic. 788 789 Reads the current value of a gatt characteristic. 790 791 @param uuid: The uuid of the characteristic to read, as a string. 792 @param address: The MAC address of the remote device. 793 794 @returns: A byte array containing the value of the if the uuid/address 795 was found in the object tree. 796 None if the uuid/address was not found in the object tree, or 797 if a DBus exception was raised by the read operation. 798 799 """ 800 value = self._proxy.read_characteristic(uuid, address) 801 if value is None: 802 return None 803 return bytearray(base64.standard_b64decode(value)) 804 805 806 def write_characteristic(self, uuid, address, bytes_to_write): 807 """Performs a write operation on a gatt characteristic. 808 809 Writes to a GATT characteristic on a remote device. 810 811 @param uuid: The uuid of the characteristic to write to, as a string. 812 @param address: The MAC address of the remote device, as a string. 813 @param bytes_to_write: A byte array containing the data to write. 814 815 @returns: True if the write operation does not raise an exception. 816 None if the uuid/address was not found in the object tree, or 817 if a DBus exception was raised by the write operation. 818 819 """ 820 return self._proxy.write_characteristic( 821 uuid, address, base64.standard_b64encode(bytes_to_write)) 822 823 824 def start_notify(self, address, uuid, cccd_value): 825 """Starts the notification session on the gatt characteristic. 826 827 @param address: The MAC address of the remote device. 828 @param uuid: The uuid of the characteristic. 829 @param cccd_value: Possible CCCD values include 830 0x00 - inferred from the remote characteristic's properties 831 0x01 - notification 832 0x02 - indication 833 834 @returns: True if the operation succeeds. 835 False if the characteristic is not found, or 836 if a DBus exception was raised by the operation. 837 838 """ 839 return self._proxy.start_notify(address, uuid, cccd_value) 840 841 842 def stop_notify(self, address, uuid): 843 """Stops the notification session on the gatt characteristic. 844 845 @param address: The MAC address of the remote device. 846 @param uuid: The uuid of the characteristic. 847 848 @returns: True if the operation succeeds. 849 False if the characteristic is not found, or 850 if a DBus exception was raised by the operation. 851 852 """ 853 return self._proxy.stop_notify(address, uuid) 854 855 856 def is_notifying(self, address, uuid): 857 """Is the GATT characteristic in a notifying session? 858 859 @param address: The MAC address of the remote device. 860 @param uuid: The uuid of the characteristic. 861 862 @return True if it is in a notification session. False otherwise. 863 864 """ 865 return self._proxy.is_notifying(address, uuid) 866 867 868 def is_characteristic_path_resolved(self, uuid, address): 869 """Checks whether a characteristic is in the object tree. 870 871 Checks whether a characteristic is curently found in the object tree. 872 873 @param uuid: The uuid of the characteristic to search for. 874 @param address: The MAC address of the device on which to search for 875 the characteristic. 876 877 @returns: True if the characteristic is found, False otherwise. 878 879 """ 880 return self._proxy.is_characteristic_path_resolved(uuid, address) 881 882 883 def get_gatt_attributes_map(self, address): 884 """Return a JSON formated string of the GATT attributes of a device, 885 keyed by UUID 886 @param address: a string of the MAC address of the device 887 888 @return: JSON formated string, stored the nested structure of the 889 attributes. Each attribute has 'path' and ['chrcs' | 'descs'], which 890 store their object path and children respectively. 891 """ 892 return self._proxy.get_gatt_attributes_map(address) 893 894 895 def get_gatt_service_property(self, object_path, property_name): 896 """Get property from a service attribute 897 @param object_path: a string of the object path of the service 898 @param property_name: a string of a property, ex: 'Value', 'UUID' 899 900 @return: the property if success, 901 None otherwise 902 """ 903 return self._proxy.get_gatt_service_property(object_path, property_name) 904 905 906 def get_gatt_characteristic_property(self, object_path, property_name): 907 """Get property from a characteristic attribute 908 @param object_path: a string of the object path of the characteristic 909 @param property_name: a string of a property, ex: 'Value', 'UUID' 910 911 @return: the property if success, 912 None otherwise 913 """ 914 return self._proxy.get_gatt_characteristic_property(object_path, 915 property_name) 916 917 918 def get_gatt_descriptor_property(self, object_path, property_name): 919 """Get property from a descriptor attribute 920 @param object_path: a string of the object path of the descriptor 921 @param property_name: a string of a property, ex: 'Value', 'UUID' 922 923 @return: the property if success, 924 None otherwise 925 """ 926 return self._proxy.get_gatt_descriptor_property(object_path, 927 property_name) 928 929 930 def gatt_characteristic_read_value(self, uuid, object_path): 931 """Perform method ReadValue on a characteristic attribute 932 @param uuid: a string of uuid 933 @param object_path: a string of the object path of the characteristic 934 935 @return: base64 string of dbus bytearray 936 """ 937 return self._proxy.gatt_characteristic_read_value(uuid, object_path) 938 939 940 def gatt_descriptor_read_value(self, uuid, object_path): 941 """Perform method ReadValue on a descriptor attribute 942 @param uuid: a string of uuid 943 @param object_path: a string of the object path of the descriptor 944 945 @return: base64 string of dbus bytearray 946 """ 947 return self._proxy.gatt_descriptor_read_value(uuid, object_path) 948 949 950 def copy_logs(self, destination): 951 """Copy the logs generated by this device to a given location. 952 953 @param destination: destination directory for the logs. 954 955 """ 956 self.host.collect_logs(self.XMLRPC_LOG_PATH, destination) 957 958 959 def get_connection_info(self, address): 960 """Get device connection info. 961 962 @param address: The MAC address of the device. 963 964 @returns: On success, a tuple of: 965 ( RSSI, transmit_power, max_transmit_power ) 966 None otherwise. 967 968 """ 969 return self._proxy.get_connection_info(address) 970 971 972 def set_discovery_filter(self, filter): 973 """Set the discovery filter. 974 975 @param filter: The discovery filter to set. 976 977 @return True on success, False otherwise. 978 979 """ 980 return self._proxy.set_discovery_filter(filter) 981 982 983 def set_le_connection_parameters(self, address, parameters): 984 """Set the LE connection parameters. 985 986 @param address: The MAC address of the device. 987 @param parameters: The LE connection parameters to set. 988 989 @return: True on success. False otherwise. 990 991 """ 992 return self._proxy.set_le_connection_parameters(address, parameters) 993 994 995 def close(self, close_host=True): 996 """Tear down state associated with the client. 997 998 @param close_host: If True, shut down the xml rpc server by closing the 999 underlying host object (which also shuts down all other xml rpc 1000 servers running on the DUT). Otherwise, only shut down the 1001 bluetooth device xml rpc server, which can be desirable if the host 1002 object and/or other xml rpc servers need to be used afterwards. 1003 """ 1004 # Turn off the discoverable flag since it may affect future tests. 1005 self._proxy.set_discoverable(False) 1006 # Reset the adapter and leave it on. 1007 self._proxy.reset_on() 1008 # This kills the RPC server. 1009 if close_host: 1010 self.host.close() 1011 else: 1012 self.host.rpc_server_tracker.disconnect( 1013 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT) 1014