| # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from __future__ import absolute_import |
| |
| import base64 |
| import functools |
| import json |
| import logging |
| import threading |
| from datetime import datetime |
| |
| import common |
| from autotest_lib.client.bin import utils |
| from autotest_lib.client.cros import constants |
| from autotest_lib.server import autotest |
| |
| def proxy_thread_safe(method): |
| """A decorator enabling thread-safe XmlRpc calls""" |
| |
| @functools.wraps(method) |
| def wrapper(self, *args, **kwargs): |
| """A wrapper of the decorated method""" |
| with self._proxy_lock: |
| return method(self, *args, **kwargs) |
| |
| return wrapper |
| |
| |
| class BluetoothDevice(object): |
| """BluetoothDevice is a thin layer of logic over a remote DUT. |
| |
| The Autotest host object representing the remote DUT, passed to this |
| class on initialization, can be accessed from its host property. |
| |
| """ |
| |
| XMLRPC_BRINGUP_TIMEOUT_SECONDS = 60 |
| XMLRPC_LOG_PATH = '/var/log/bluetooth_xmlrpc_device.log' |
| XMLRPC_REQUEST_TIMEOUT_SECONDS = 180 |
| |
| # We currently get dates back in string format due to some inconsistencies |
| # between python2 and python3. This is the standard date format we use. |
| NATIVE_DATE_FORMAT = '%Y-%m-%d %H:%M:%S.%f' |
| |
| def __init__(self, device_host, remote_facade_proxy=None): |
| """Construct a BluetoothDevice. |
| |
| @param device_host: host object representing a remote host. |
| |
| """ |
| self.host = device_host |
| self._remote_proxy = remote_facade_proxy |
| |
| # Make sure the client library is on the device so that the proxy code |
| # is there when we try to call it. |
| client_at = autotest.Autotest(self.host) |
| client_at.install() |
| self._proxy_lock = threading.Lock() |
| |
| # If remote facade wasn't already created, connect directly here |
| if not self._remote_proxy: |
| self._connect_xmlrpc_directly() |
| |
| # Get some static information about the bluetooth adapter. |
| properties = self.get_adapter_properties() |
| self.bluez_version = properties.get('Name') |
| self.address = properties.get('Address') |
| self.bluetooth_class = properties.get('Class') |
| self.UUIDs = properties.get('UUIDs') |
| |
| def _connect_xmlrpc_directly(self): |
| """Connects to the bluetooth native facade directly via xmlrpc.""" |
| proxy = self.host.rpc_server_tracker.xmlrpc_connect( |
| constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_COMMAND, |
| constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT, |
| command_name=constants. |
| BLUETOOTH_DEVICE_XMLRPC_SERVER_CLEANUP_PATTERN, |
| ready_test_name=constants. |
| BLUETOOTH_DEVICE_XMLRPC_SERVER_READY_METHOD, |
| timeout_seconds=self.XMLRPC_BRINGUP_TIMEOUT_SECONDS, |
| logfile=self.XMLRPC_LOG_PATH, |
| request_timeout_seconds=self.XMLRPC_REQUEST_TIMEOUT_SECONDS) |
| |
| self._bt_direct_proxy = proxy |
| return proxy |
| |
| @property |
| def _proxy(self): |
| """Gets the proxy to the DUT bluetooth facade. |
| |
| @return XML RPC proxy to DUT bluetooth facade. |
| |
| """ |
| # When the xmlrpc server is already created (using the |
| # RemoteFacadeFactory), we will use the BluetoothNativeFacade inside the |
| # remote proxy. Otherwise, we will use the xmlrpc server started from |
| # this class. Currently, there are a few users outside of the Bluetooth |
| # autotests that use this and this can be removed once those users |
| # migrate to using the RemoteFacadeFactory to generate the xmlrpc |
| # connection. |
| if self._remote_proxy: |
| return self._remote_proxy.bluetooth |
| else: |
| return self._bt_direct_proxy |
| |
| @proxy_thread_safe |
| def set_debug_log_levels(self, dispatcher_vb, newblue_vb, bluez_vb, |
| kernel_vb): |
| """Enable or disable the debug logs of bluetooth |
| |
| @param dispatcher_vb: verbosity of btdispatcher debug log, either 0 or 1 |
| @param newblue_vb: verbosity of newblued debug log, either 0 or 1 |
| @param bluez_vb: verbosity of bluez debug log, either 0 or 1 |
| @param kernel_vb: verbosity of kernel debug log, either 0 or 1 |
| |
| """ |
| return self._proxy.set_debug_log_levels(dispatcher_vb, newblue_vb, |
| bluez_vb, kernel_vb) |
| |
| @proxy_thread_safe |
| def log_message(self, msg, dut=True, peer=True): |
| """ Log a message in DUT log and peer logs with timestamp. |
| |
| @param msg: message to be logged. |
| @param dut: log message on DUT |
| @param peer: log message on peer devices |
| """ |
| try: |
| # TODO(b/146671469) Implement logging to tester |
| |
| date = datetime.strftime(datetime.now(),"%Y:%m:%d %H:%M:%S:%f") |
| msg = "bluetooth autotest --- %s : %s ---" % (date, msg) |
| logging.debug("Broadcasting '%s'",msg) |
| |
| if dut: |
| self._proxy.log_message(msg) |
| |
| if peer: |
| for btpeer in self.host.btpeer_list: |
| btpeer.log_message(msg) |
| except Exception as e: |
| logging.error("Exception '%s' in log_message '%s'", str(e), msg) |
| |
| |
| @proxy_thread_safe |
| def is_wrt_supported(self): |
| """ Check if Bluetooth adapter support WRT logs. |
| |
| Intel adapter support WRT (except of WP2 and StP2) |
| |
| @returns: True if adapter support WRT logs |
| """ |
| return self._proxy.is_wrt_supported() |
| |
| |
| @proxy_thread_safe |
| def enable_wrt_logs(self): |
| """Enable wrt logs on Intel adapters.""" |
| return self._proxy.enable_wrt_logs() |
| |
| |
| @proxy_thread_safe |
| def collect_wrt_logs(self): |
| """Collect wrt logs on Intel adapters.""" |
| return self._proxy.collect_wrt_logs() |
| |
| |
| @proxy_thread_safe |
| def start_bluetoothd(self): |
| """start bluetoothd. |
| |
| @returns: True if bluetoothd is started correctly. |
| False otherwise. |
| |
| """ |
| return self._proxy.start_bluetoothd() |
| |
| |
| @proxy_thread_safe |
| def stop_bluetoothd(self): |
| """stop bluetoothd. |
| |
| @returns: True if bluetoothd is stopped correctly. |
| False otherwise. |
| |
| """ |
| return self._proxy.stop_bluetoothd() |
| |
| |
| @proxy_thread_safe |
| def is_bluetoothd_running(self): |
| """Is bluetoothd running? |
| |
| @returns: True if bluetoothd is running |
| |
| """ |
| return self._proxy.is_bluetoothd_running() |
| |
| |
| @proxy_thread_safe |
| def is_bluetoothd_valid(self): |
| """Checks whether the current bluetoothd session is ok. |
| |
| Returns: |
| True if the current bluetoothd session is ok. False if bluetoothd is |
| not running or it is a new session. |
| """ |
| return self._proxy.is_bluetoothd_proxy_valid() |
| |
| |
| @proxy_thread_safe |
| def reset_on(self): |
| """Reset the adapter and settings and power up the adapter. |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.reset_on() |
| |
| |
| @proxy_thread_safe |
| def reset_off(self): |
| """Reset the adapter and settings, leave the adapter powered off. |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.reset_off() |
| |
| |
| @proxy_thread_safe |
| def has_adapter(self): |
| """@return True if an adapter is present, False if not.""" |
| return self._proxy.has_adapter() |
| |
| |
| @proxy_thread_safe |
| def is_wake_enabled(self): |
| """@return True if adapter is wake enabled, False if not.""" |
| return self._proxy.is_wake_enabled() |
| |
| |
| @proxy_thread_safe |
| def set_wake_enabled(self, value): |
| """ Sets the power/wakeup value for the adapter. |
| |
| Args: |
| value: Whether the adapter can wake from suspend |
| |
| @return True if able to set it to value, False if not.""" |
| return self._proxy.set_wake_enabled(value) |
| |
| |
| @proxy_thread_safe |
| def set_powered(self, powered): |
| """Set the adapter power state. |
| |
| @param powered: adapter power state to set (True or False). |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.set_powered(powered) |
| |
| |
| def is_powered_on(self): |
| """Is the adapter powered on? |
| |
| @returns: True if the adapter is powered on |
| |
| """ |
| properties = self.get_adapter_properties() |
| return bool(properties.get(u'Powered')) |
| |
| |
| def get_hci(self): |
| """Get hci of the adapter; normally, it is 'hci0'. |
| |
| @returns: the hci name of the adapter. |
| |
| """ |
| dev_info = self.get_dev_info() |
| hci = (dev_info[1] if isinstance(dev_info, list) and |
| len(dev_info) > 1 else None) |
| return hci |
| |
| |
| def get_address(self): |
| """Get the bluetooth address of the adapter. |
| |
| An example of the bluetooth address of the adapter: '6C:29:95:1A:D4:6F' |
| |
| @returns: the bluetooth address of the adapter. |
| |
| """ |
| return self.address |
| |
| |
| def get_bluez_version(self): |
| """Get bluez version. |
| |
| An exmaple of bluez version: 'BlueZ 5.39' |
| |
| @returns: the bluez version |
| |
| """ |
| return self.bluez_version |
| |
| |
| def get_bluetooth_class(self): |
| """Get the bluetooth class of the adapter. |
| |
| An example of the bluetooth class of a chromebook: 4718852 |
| |
| @returns: the bluetooth class. |
| |
| """ |
| return self.bluetooth_class |
| |
| |
| def get_UUIDs(self): |
| """Get the UUIDs. |
| |
| An example of UUIDs: |
| [u'00001112-0000-1000-8000-00805f9b34fb', |
| u'00001801-0000-1000-8000-00805f9b34fb', |
| u'0000110a-0000-1000-8000-00805f9b34fb', |
| u'0000111f-0000-1000-8000-00805f9b34fb', |
| u'00001200-0000-1000-8000-00805f9b34fb', |
| u'00001800-0000-1000-8000-00805f9b34fb'] |
| |
| @returns: the list of the UUIDs. |
| |
| """ |
| return self.UUIDs |
| |
| |
| @proxy_thread_safe |
| def set_discoverable(self, discoverable): |
| """Set the adapter discoverable state. |
| |
| @param discoverable: adapter discoverable state to set (True or False). |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.set_discoverable(discoverable) |
| |
| |
| def is_discoverable(self): |
| """Is the adapter in the discoverable state? |
| |
| @return True if discoverable. False otherwise. |
| |
| """ |
| properties = self.get_adapter_properties() |
| return properties.get('Discoverable') == 1 |
| |
| |
| @proxy_thread_safe |
| def set_discoverable_timeout(self, discoverable_timeout): |
| """Set the adapter DiscoverableTimeout. |
| |
| @param discoverable_timeout: adapter DiscoverableTimeout |
| value to set in seconds (Integer). |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.set_discoverable_timeout(discoverable_timeout) |
| |
| |
| @proxy_thread_safe |
| def get_discoverable_timeout(self): |
| """Get the adapter DiscoverableTimeout. |
| |
| @return Value of property DiscoverableTimeout in seconds (Integer). |
| |
| """ |
| return self._proxy.get_discoverable_timeout() |
| |
| |
| @proxy_thread_safe |
| def set_pairable_timeout(self, pairable_timeout): |
| """Set the adapter PairableTimeout. |
| |
| @param pairable_timeout: adapter PairableTimeout |
| value to set in seconds (Integer). |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.set_pairable_timeout(pairable_timeout) |
| |
| |
| @proxy_thread_safe |
| def get_pairable_timeout(self): |
| """Get the adapter PairableTimeout. |
| |
| @return Value of property PairableTimeout in seconds (Integer). |
| |
| """ |
| return self._proxy.get_pairable_timeout() |
| |
| |
| @proxy_thread_safe |
| def set_pairable(self, pairable): |
| """Set the adapter pairable state. |
| |
| @param pairable: adapter pairable state to set (True or False). |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.set_pairable(pairable) |
| |
| |
| def is_pairable(self): |
| """Is the adapter in the pairable state? |
| |
| @return True if pairable. False otherwise. |
| |
| """ |
| properties = self.get_adapter_properties() |
| return properties.get('Pairable') == 1 |
| |
| @proxy_thread_safe |
| def set_adapter_alias(self, alias): |
| """Set the adapter alias. |
| |
| A note on Alias property - providing an empty string ('') will reset the |
| Alias property to the system default |
| |
| @param alias: adapter alias to set with type String |
| |
| @return True on success, False otherwise. |
| """ |
| |
| return self._proxy.set_adapter_alias(alias) |
| |
| @proxy_thread_safe |
| def get_adapter_properties(self): |
| """Read the adapter properties from the Bluetooth Daemon. |
| |
| An example of the adapter properties looks like |
| {u'Name': u'BlueZ 5.35', |
| u'Alias': u'Chromebook', |
| u'Modalias': u'bluetooth:v00E0p2436d0400', |
| u'Powered': 1, |
| u'DiscoverableTimeout': 180, |
| u'PairableTimeout': 0, |
| u'Discoverable': 0, |
| u'Address': u'6C:29:95:1A:D4:6F', |
| u'Discovering': 0, |
| u'Pairable': 1, |
| u'Class': 4718852, |
| u'UUIDs': [u'00001112-0000-1000-8000-00805f9b34fb', |
| u'00001801-0000-1000-8000-00805f9b34fb', |
| u'0000110a-0000-1000-8000-00805f9b34fb', |
| u'0000111f-0000-1000-8000-00805f9b34fb', |
| u'00001200-0000-1000-8000-00805f9b34fb', |
| u'00001800-0000-1000-8000-00805f9b34fb']} |
| |
| @return the properties as a dictionary on success, |
| the value False otherwise. |
| |
| """ |
| return json.loads(self._proxy.get_adapter_properties()) |
| |
| |
| @proxy_thread_safe |
| def read_version(self): |
| """Read the version of the management interface from the Kernel. |
| |
| @return the version as a tuple of: |
| ( version, revision ) |
| |
| """ |
| return json.loads(self._proxy.read_version()) |
| |
| |
| @proxy_thread_safe |
| def read_supported_commands(self): |
| """Read the set of supported commands from the Kernel. |
| |
| @return set of supported commands as arrays in a tuple of: |
| ( commands, events ) |
| |
| """ |
| return json.loads(self._proxy.read_supported_commands()) |
| |
| |
| @proxy_thread_safe |
| def read_index_list(self): |
| """Read the list of currently known controllers from the Kernel. |
| |
| @return array of controller indexes. |
| |
| """ |
| return json.loads(self._proxy.read_index_list()) |
| |
| |
| @proxy_thread_safe |
| def read_info(self): |
| """Read the adapter information from the Kernel. |
| |
| An example of the adapter information looks like |
| [u'6C:29:95:1A:D4:6F', 6, 2, 65535, 2769, 4718852, u'Chromebook', u''] |
| |
| @return the information as a tuple of: |
| ( address, bluetooth_version, manufacturer_id, |
| supported_settings, current_settings, class_of_device, |
| name, short_name ) |
| |
| """ |
| return json.loads(self._proxy.read_info()) |
| |
| |
| @proxy_thread_safe |
| def add_device(self, address, address_type, action): |
| """Add a device to the Kernel action list. |
| |
| @param address: Address of the device to add. |
| @param address_type: Type of device in @address. |
| @param action: Action to take. |
| |
| @return tuple of ( address, address_type ) on success, |
| None on failure. |
| |
| """ |
| return json.loads(self._proxy.add_device(address, address_type, action)) |
| |
| |
| @proxy_thread_safe |
| def remove_device(self, address, address_type): |
| """Remove a device from the Kernel action list. |
| |
| @param address: Address of the device to remove. |
| @param address_type: Type of device in @address. |
| |
| @return tuple of ( address, address_type ) on success, |
| None on failure. |
| |
| """ |
| return json.loads(self._proxy.remove_device(address, address_type)) |
| |
| def _decode_json_base64(self, data): |
| """Load serialized JSON and then base64 decode it |
| |
| Required to handle non-ascii data |
| @param data: data to be JSON and base64 decode |
| |
| @return : JSON and base64 decoded date |
| |
| |
| """ |
| logging.debug("_decode_json_base64 raw data is %s", data) |
| json_encoded = json.loads(data) |
| logging.debug("JSON encoded data is %s", json_encoded) |
| base64_decoded = utils.base64_recursive_decode(json_encoded) |
| logging.debug("base64 decoded data is %s", base64_decoded) |
| return base64_decoded |
| |
| |
| @proxy_thread_safe |
| def get_devices(self): |
| """Read information about remote devices known to the adapter. |
| |
| An example of the device information of RN-42 looks like |
| [{u'Name': u'RNBT-A96F', |
| u'Alias': u'RNBT-A96F', |
| u'Adapter': u'/org/bluez/hci0', |
| u'LegacyPairing': 0, |
| u'Paired': 1, |
| u'Connected': 0, |
| u'UUIDs': [u'00001124-0000-1000-8000-00805f9b34fb'], |
| u'Address': u'00:06:66:75:A9:6F', |
| u'Icon': u'input-mouse', |
| u'Class': 1408, |
| u'Trusted': 1, |
| u'Blocked': 0}] |
| |
| @return the properties of each device as an array of |
| dictionaries on success, the value False otherwise. |
| |
| """ |
| encoded_devices = self._proxy.get_devices() |
| return self._decode_json_base64(encoded_devices) |
| |
| |
| @proxy_thread_safe |
| def get_device_property(self, address, prop_name): |
| """Read a property of BT device by directly querying device dbus object |
| |
| @param address: Address of the device to query |
| @param prop_name: Property to be queried |
| |
| @return The property if device is found and has property, None otherwise |
| """ |
| |
| prop_val = self._proxy.get_device_property(address, prop_name) |
| |
| # Handle dbus error case returned by xmlrpc_server.dbus_safe decorator |
| if prop_val is None: |
| return prop_val |
| |
| # Decode and return property value |
| return self._decode_json_base64(prop_val) |
| |
| |
| @proxy_thread_safe |
| def get_battery_property(self, address, prop_name): |
| """Read a property of battery by directly querying the dbus object |
| |
| @param address: Address of the device to query |
| @param prop_name: Property to be queried |
| |
| @return The property if battery is found and has property, |
| None otherwise |
| """ |
| |
| return self._proxy.get_battery_property(address, prop_name) |
| |
| @proxy_thread_safe |
| def start_discovery(self): |
| """Start discovery of remote devices. |
| |
| Obtain the discovered device information using get_devices(), called |
| stop_discovery() when done. |
| |
| @return (True, None) on success, (False, <error>) otherwise. |
| |
| """ |
| return self._proxy.start_discovery() |
| |
| |
| @proxy_thread_safe |
| def stop_discovery(self): |
| """Stop discovery of remote devices. |
| |
| @return (True, None) on success, (False, <error>) otherwise. |
| |
| """ |
| return self._proxy.stop_discovery() |
| |
| |
| def is_discovering(self): |
| """Is it discovering? |
| |
| @return True if it is discovering. False otherwise. |
| |
| """ |
| return self.get_adapter_properties().get('Discovering') == 1 |
| |
| |
| @proxy_thread_safe |
| def get_dev_info(self): |
| """Read raw HCI device information. |
| |
| An example of the device information looks like: |
| [0, u'hci0', u'6C:29:95:1A:D4:6F', 13, 0, 1, 581900950526, 52472, 7, |
| 32768, 1021, 5, 96, 6, 0, 0, 151, 151, 0, 0, 0, 0, 1968, 12507] |
| |
| @return tuple of (index, name, address, flags, device_type, bus_type, |
| features, pkt_type, link_policy, link_mode, |
| acl_mtu, acl_pkts, sco_mtu, sco_pkts, |
| err_rx, err_tx, cmd_tx, evt_rx, acl_tx, acl_rx, |
| sco_tx, sco_rx, byte_rx, byte_tx) on success, |
| None on failure. |
| |
| """ |
| return json.loads(self._proxy.get_dev_info()) |
| |
| |
| @proxy_thread_safe |
| def get_supported_capabilities(self): |
| """ Get the supported_capabilities of the adapter |
| @returns (capabilities,None) on success (None, <error>) on failure |
| """ |
| capabilities, error = self._proxy.get_supported_capabilities() |
| return (json.loads(capabilities), error) |
| |
| |
| @proxy_thread_safe |
| def register_profile(self, path, uuid, options): |
| """Register new profile (service). |
| |
| @param path: Path to the profile object. |
| @param uuid: Service Class ID of the service as string. |
| @param options: Dictionary of options for the new service, compliant |
| with BlueZ D-Bus Profile API standard. |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.register_profile(path, uuid, options) |
| |
| |
| @proxy_thread_safe |
| def has_device(self, address): |
| """Checks if the device with a given address exists. |
| |
| @param address: Address of the device. |
| |
| @returns: True if there is a device with that address. |
| False otherwise. |
| |
| """ |
| return self._proxy.has_device(address) |
| |
| |
| @proxy_thread_safe |
| def device_is_paired(self, address): |
| """Checks if a device is paired. |
| |
| @param address: address of the device. |
| |
| @returns: True if device is paired. False otherwise. |
| |
| """ |
| return self._proxy.device_is_paired(address) |
| |
| |
| @proxy_thread_safe |
| def device_services_resolved(self, address): |
| """Checks if services are resolved for a device. |
| |
| @param address: address of the device. |
| |
| @returns: True if services are resolved. False otherwise. |
| |
| """ |
| return self._proxy.device_services_resolved(address) |
| |
| |
| @proxy_thread_safe |
| def set_trusted(self, address, trusted=True): |
| """Set the device trusted. |
| |
| @param address: The bluetooth address of the device. |
| @param trusted: True or False indicating whether to set trusted or not. |
| |
| @returns: True if successful. False otherwise. |
| |
| """ |
| return self._proxy.set_trusted(address, trusted) |
| |
| |
| @proxy_thread_safe |
| def pair_legacy_device(self, address, pin, trusted, timeout): |
| """Pairs a device with a given pin code. |
| |
| Registers an agent who handles pin code request and |
| pairs a device with known pin code. |
| |
| @param address: Address of the device to pair. |
| @param pin: The pin code of the device to pair. |
| @param trusted: indicating whether to set the device trusted. |
| @param timeout: The timeout in seconds for pairing. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.pair_legacy_device(address, pin, trusted, timeout) |
| |
| |
| @proxy_thread_safe |
| def remove_device_object(self, address): |
| """Removes a device object and the pairing information. |
| |
| Calls RemoveDevice method to remove remote device |
| object and the pairing information. |
| |
| @param address: address of the device to unpair. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.remove_device_object(address) |
| |
| |
| @proxy_thread_safe |
| def connect_device(self, address): |
| """Connects a device. |
| |
| Connects a device if it is not connected. |
| |
| @param address: Address of the device to connect. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.connect_device(address) |
| |
| |
| @proxy_thread_safe |
| def device_is_connected(self, address): |
| """Checks if a device is connected. |
| |
| @param address: Address of the device to check if it is connected. |
| |
| @returns: True if device is connected. False otherwise. |
| |
| """ |
| return self._proxy.device_is_connected(address) |
| |
| |
| @proxy_thread_safe |
| def disconnect_device(self, address): |
| """Disconnects a device. |
| |
| Disconnects a device if it is connected. |
| |
| @param address: Address of the device to disconnect. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.disconnect_device(address) |
| |
| |
| @proxy_thread_safe |
| def btmon_start(self): |
| """Start btmon monitoring.""" |
| self._proxy.btmon_start() |
| |
| |
| @proxy_thread_safe |
| def btmon_stop(self): |
| """Stop btmon monitoring.""" |
| self._proxy.btmon_stop() |
| |
| |
| @proxy_thread_safe |
| def btmon_get(self, search_str='', start_str=''): |
| """Get btmon output contents. |
| |
| @param search_str: only lines with search_str would be kept. |
| @param start_str: all lines before the occurrence of start_str would be |
| filtered. |
| |
| @returns: the recorded btmon output. |
| |
| """ |
| return self._proxy.btmon_get(search_str, start_str) |
| |
| |
| @proxy_thread_safe |
| def btmon_find(self, pattern_str): |
| """Find if a pattern string exists in btmon output. |
| |
| @param pattern_str: the pattern string to find. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.btmon_find(pattern_str) |
| |
| |
| @proxy_thread_safe |
| def advmon_check_manager_interface_exist(self): |
| """Check if AdvertisementMonitorManager1 interface is available. |
| |
| @returns: True if Manager interface is available, False otherwise. |
| |
| """ |
| return self._proxy.advmon_check_manager_interface_exist() |
| |
| |
| @proxy_thread_safe |
| def advmon_read_supported_types(self): |
| """Read the Advertisement Monitor supported monitor types. |
| |
| @returns: List of supported advertisement monitor types. |
| |
| """ |
| return self._proxy.advmon_read_supported_types() |
| |
| |
| @proxy_thread_safe |
| def advmon_read_supported_features(self): |
| """Read the Advertisement Monitor supported features. |
| |
| @returns: List of supported advertisement monitor features. |
| |
| """ |
| return self._proxy.advmon_read_supported_features() |
| |
| |
| @proxy_thread_safe |
| def advmon_create_app(self): |
| """Create an advertisement monitor app. |
| |
| @returns: app id, once the app is created. |
| |
| """ |
| return self._proxy.advmon_create_app() |
| |
| |
| @proxy_thread_safe |
| def advmon_exit_app(self, app_id): |
| """Exit an advertisement monitor app. |
| |
| @param app_id: the app id. |
| |
| @returns: True on success, False otherwise. |
| |
| """ |
| return self._proxy.advmon_exit_app(app_id) |
| |
| |
| @proxy_thread_safe |
| def advmon_kill_app(self, app_id): |
| """Kill an advertisement monitor app by sending SIGKILL. |
| |
| @param app_id: the app id. |
| |
| @returns: True on success, False otherwise. |
| |
| """ |
| return self._proxy.advmon_kill_app(app_id) |
| |
| |
| @proxy_thread_safe |
| def advmon_register_app(self, app_id): |
| """Register an advertisement monitor app. |
| |
| @param app_id: the app id. |
| |
| @returns: True on success, False otherwise. |
| |
| """ |
| return self._proxy.advmon_register_app(app_id) |
| |
| |
| @proxy_thread_safe |
| def advmon_unregister_app(self, app_id): |
| """Unregister an advertisement monitor app. |
| |
| @param app_id: the app id. |
| |
| @returns: True on success, False otherwise. |
| |
| """ |
| return self._proxy.advmon_unregister_app(app_id) |
| |
| |
| @proxy_thread_safe |
| def advmon_add_monitor(self, app_id, monitor_data): |
| """Create an Advertisement Monitor object. |
| |
| @param app_id: the app id. |
| @param monitor_data: the list containing monitor type, RSSI filter |
| values and patterns. |
| |
| @returns: monitor id, once the monitor is created, None otherwise. |
| |
| """ |
| return self._proxy.advmon_add_monitor(app_id, monitor_data) |
| |
| |
| @proxy_thread_safe |
| def advmon_remove_monitor(self, app_id, monitor_id): |
| """Remove the Advertisement Monitor object. |
| |
| @param app_id: the app id. |
| @param monitor_id: the monitor id. |
| |
| @returns: True on success, False otherwise. |
| |
| """ |
| return self._proxy.advmon_remove_monitor(app_id, monitor_id) |
| |
| |
| @proxy_thread_safe |
| def advmon_get_event_count(self, app_id, monitor_id, event): |
| """Read the count of a particular event on the given monitor. |
| |
| @param app_id: the app id. |
| @param monitor_id: the monitor id. |
| @param event: name of the specific event or 'All' for all events. |
| |
| @returns: count of the specific event or dict of counts of all events. |
| |
| """ |
| return self._proxy.advmon_get_event_count(app_id, monitor_id, event) |
| |
| |
| @proxy_thread_safe |
| def advmon_reset_event_count(self, app_id, monitor_id, event): |
| """Reset the count of a particular event on the given monitor. |
| |
| @param app_id: the app id. |
| @param monitor_id: the monitor id. |
| @param event: name of the specific event or 'All' for all events. |
| |
| @returns: True on success, False otherwise. |
| |
| """ |
| return self._proxy.advmon_reset_event_count(app_id, monitor_id, event) |
| |
| @proxy_thread_safe |
| def advmon_interleave_scan_logger_start(self): |
| """ Start interleave logger recording |
| """ |
| self._proxy.advmon_interleave_scan_logger_start() |
| |
| @proxy_thread_safe |
| def advmon_interleave_scan_logger_stop(self): |
| """ Stop interleave logger recording |
| |
| @returns: True if logs were successfully collected, |
| False otherwise. |
| |
| """ |
| return self._proxy.advmon_interleave_scan_logger_stop() |
| |
| @proxy_thread_safe |
| def advmon_interleave_scan_logger_get_records(self): |
| """ Get records in previous log collections |
| |
| @returns: a list of records, where each item is a record of |
| interleave |state| and the |time| the state starts. |
| |state| could be {'no filter', 'allowlist'} |
| |time| is system time in sec |
| |
| """ |
| return self._proxy.advmon_interleave_scan_logger_get_records() |
| |
| @proxy_thread_safe |
| def advmon_interleave_scan_logger_get_cancel_events(self): |
| """ Get cancel events in previous log collections |
| |
| @returns: a list of cancel |time| when a interleave cancel event log |
| was found. |
| |time| is system time in sec |
| |
| """ |
| return self._proxy.advmon_interleave_scan_logger_get_cancel_events() |
| |
| @proxy_thread_safe |
| def messages_start(self): |
| """Start messages monitoring.""" |
| self._proxy.messages_start() |
| |
| @proxy_thread_safe |
| def messages_stop(self): |
| """Stop messages monitoring. |
| |
| @returns: True if logs were successfully gathered since logging started, |
| else False |
| """ |
| return self._proxy.messages_stop() |
| |
| @proxy_thread_safe |
| def messages_find(self, pattern_str): |
| """Find if a pattern string exists in messages output. |
| |
| @param pattern_str: the pattern string to find. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.messages_find(pattern_str) |
| |
| @proxy_thread_safe |
| def register_advertisement(self, advertisement_data): |
| """Register an advertisement. |
| |
| Note that rpc supports only conformable types. Hence, a |
| dict about the advertisement is passed as a parameter such |
| that the advertisement object could be contructed on the host. |
| |
| @param advertisement_data: a dict of the advertisement for |
| the adapter to register. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.register_advertisement(advertisement_data) |
| |
| |
| @proxy_thread_safe |
| def unregister_advertisement(self, advertisement_data): |
| """Unregister an advertisement. |
| |
| @param advertisement_data: a dict of the advertisement to unregister. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.unregister_advertisement(advertisement_data) |
| |
| |
| @proxy_thread_safe |
| def set_advertising_intervals(self, min_adv_interval_ms, |
| max_adv_interval_ms): |
| """Set advertising intervals. |
| |
| @param min_adv_interval_ms: the min advertising interval in ms. |
| @param max_adv_interval_ms: the max advertising interval in ms. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.set_advertising_intervals(min_adv_interval_ms, |
| max_adv_interval_ms) |
| |
| |
| @proxy_thread_safe |
| def reset_advertising(self): |
| """Reset advertising. |
| |
| This includes unregister all advertisements, reset advertising |
| intervals, and disable advertising. |
| |
| @returns: True on success. False otherwise. |
| |
| """ |
| return self._proxy.reset_advertising() |
| |
| |
| @proxy_thread_safe |
| def create_audio_record_directory(self, audio_record_dir): |
| """Create the audio recording directory. |
| |
| @param audio_record_dir: the audio recording directory |
| |
| @returns: True on success. False otherwise. |
| """ |
| return self._proxy.create_audio_record_directory(audio_record_dir) |
| |
| |
| @proxy_thread_safe |
| def start_capturing_audio_subprocess(self, audio_data, recording_device): |
| """Start capturing audio in a subprocess. |
| |
| @param audio_data: the audio test data |
| @param recording_device: which device recorded the audio, |
| possible values are 'recorded_by_dut' or 'recorded_by_peer' |
| |
| @returns: True on success. False otherwise. |
| """ |
| return self._proxy.start_capturing_audio_subprocess( |
| json.dumps(audio_data), recording_device) |
| |
| |
| @proxy_thread_safe |
| def stop_capturing_audio_subprocess(self): |
| """Stop capturing audio. |
| |
| @returns: True on success. False otherwise. |
| """ |
| return self._proxy.stop_capturing_audio_subprocess() |
| |
| |
| @proxy_thread_safe |
| def start_playing_audio_subprocess(self, audio_data): |
| """Start playing audio in a subprocess. |
| |
| @param audio_data: the audio test data |
| |
| @returns: True on success. False otherwise. |
| """ |
| audio_data = json.dumps(audio_data) |
| return self._proxy.start_playing_audio_subprocess(audio_data) |
| |
| |
| @proxy_thread_safe |
| def stop_playing_audio_subprocess(self): |
| """Stop playing audio in the subprocess. |
| |
| @returns: True on success. False otherwise. |
| """ |
| return self._proxy.stop_playing_audio_subprocess() |
| |
| |
| @proxy_thread_safe |
| def play_audio(self, audio_data): |
| """Play audio. |
| |
| It blocks until it has completed playing back the audio. |
| |
| @param audio_data: the audio test data |
| |
| @returns: True on success. False otherwise. |
| """ |
| return self._proxy.play_audio(json.dumps(audio_data)) |
| |
| |
| @proxy_thread_safe |
| def check_audio_frames_legitimacy(self, audio_test_data, recording_device, |
| recorded_file): |
| """Get the number of frames in the recorded audio file. |
| @param audio_test_data: the audio test data |
| @param recording_device: which device recorded the audio, |
| possible values are 'recorded_by_dut' or 'recorded_by_peer' |
| @param recorded_file: the recorded file name |
| |
| @returns: True if audio frames are legitimate. |
| """ |
| return self._proxy.check_audio_frames_legitimacy( |
| json.dumps(audio_test_data), recording_device, recorded_file) |
| |
| |
| @proxy_thread_safe |
| def convert_audio_sample_rate(self, input_file, out_file, test_data, |
| new_rate): |
| """Convert audio file to new sample rate. |
| |
| @param input_file: Path to file to upsample. |
| @param out_file: Path to create upsampled file. |
| @param test_data: Dictionary with information about file. |
| @param new_rate: New rate to upsample file to. |
| |
| @returns: True if upsampling succeeded, False otherwise. |
| """ |
| return self._proxy.convert_audio_sample_rate(input_file, out_file, |
| json.dumps(test_data), |
| new_rate) |
| |
| |
| @proxy_thread_safe |
| def trim_wav_file(self, in_file, out_file, new_duration, test_data, |
| tolerance=0.1): |
| """Trim long file to desired length. |
| |
| Trims audio file to length by cutting out silence from beginning and |
| end. |
| |
| @param in_file: Path to audio file to be trimmed. |
| @param out_file: Path to trimmed audio file to create. |
| @param new_duration: A float representing the desired duration of |
| the resulting trimmed file. |
| @param test_data: Dictionary containing information about the test file. |
| @param tolerance: (optional) A float representing the allowable |
| difference between trimmed file length and desired duration |
| |
| @returns: True if file was trimmed successfully, False otherwise. |
| """ |
| return self._proxy.trim_wav_file(in_file, out_file, new_duration, |
| json.dumps(test_data), tolerance) |
| |
| |
| @proxy_thread_safe |
| def unzip_audio_test_data(self, tar_path, data_dir): |
| """Unzip audio test data files. |
| |
| @param tar_path: Path to audio test data tarball on DUT. |
| @oaram data_dir: Path to directory where to extract test data directory. |
| |
| @returns: True if audio test data folder exists, False otherwise. |
| """ |
| return self._proxy.unzip_audio_test_data(tar_path, data_dir) |
| |
| |
| @proxy_thread_safe |
| def convert_raw_to_wav(self, input_file, output_file, test_data): |
| """Convert raw audio file to wav file. |
| |
| @oaram input_file: The location of the raw file. |
| @param output_file: The location to place the resulting wav file. |
| @param test_data: The data for the file being converted. |
| |
| @returns: True if conversion was successful, otherwise false. |
| """ |
| return self._proxy.convert_raw_to_wav(input_file, output_file, |
| json.dumps(test_data)) |
| |
| |
| @proxy_thread_safe |
| def get_primary_frequencies(self, audio_test_data, recording_device, |
| recorded_file): |
| """Get primary frequencies of the audio test file. |
| |
| @param audio_test_data: the audio test data |
| @param recording_device: which device recorded the audio, |
| possible values are 'recorded_by_dut' or 'recorded_by_peer' |
| @param recorded_file: the recorded file name |
| |
| @returns: a list of primary frequencies of channels in the audio file |
| """ |
| return self._proxy.get_primary_frequencies( |
| json.dumps(audio_test_data), recording_device, recorded_file) |
| |
| |
| @proxy_thread_safe |
| def enable_wbs(self, value): |
| """Enable or disable wideband speech (wbs) per the value. |
| |
| @param value: True to enable wbs. |
| |
| @returns: True if the operation succeeds. |
| """ |
| logging.debug('%s wbs', 'enable' if value else 'disable') |
| return self._proxy.enable_wbs(value) |
| |
| |
| @proxy_thread_safe |
| def set_player_playback_status(self, status): |
| """Set playback status for the registered media player. |
| |
| @param status: playback status in string. |
| |
| """ |
| logging.debug('Set media player playback status to %s', status) |
| return self._proxy.set_player_playback_status(status) |
| |
| |
| @proxy_thread_safe |
| def set_player_position(self, position): |
| """Set media position for the registered media player. |
| |
| @param position: position in micro seconds. |
| |
| """ |
| logging.debug('Set media player position to %d', position) |
| return self._proxy.set_player_position(position) |
| |
| |
| @proxy_thread_safe |
| def set_player_metadata(self, metadata): |
| """Set metadata for the registered media player. |
| |
| @param metadata: dictionary of media metadata. |
| |
| """ |
| logging.debug('Set media player album:%s artist:%s title:%s', |
| metadata.get("album"), metadata.get("artist"), |
| metadata.get("title")) |
| return self._proxy.set_player_metadata(metadata) |
| |
| |
| @proxy_thread_safe |
| def set_player_length(self, length): |
| """Set media length for the registered media player. |
| |
| @param length: length in micro seconds. |
| |
| """ |
| logging.debug('Set media player length to %d', length) |
| return self._proxy.set_player_length(length) |
| |
| |
| @proxy_thread_safe |
| def select_input_device(self, device_name): |
| """Select the audio input device. |
| |
| @param device_name: the name of the Bluetooth peer device |
| |
| @returns: True if the operation succeeds. |
| """ |
| return self._proxy.select_input_device(device_name) |
| |
| |
| @proxy_thread_safe |
| def select_output_node(self, node_type): |
| """Select the audio output node. |
| |
| @param node_type: the node type of the Bluetooth peer device |
| |
| @returns: True if the operation succeeds. |
| """ |
| return self._proxy.select_output_node(node_type) |
| |
| |
| @proxy_thread_safe |
| def get_selected_output_device_type(self): |
| """Get the selected audio output node type. |
| |
| @returns: the node type of the selected output device. |
| """ |
| return self._proxy.get_selected_output_device_type() |
| |
| |
| @proxy_thread_safe |
| def read_characteristic(self, uuid, address): |
| """Reads the value of a gatt characteristic. |
| |
| Reads the current value of a gatt characteristic. |
| |
| @param uuid: The uuid of the characteristic to read, as a string. |
| @param address: The MAC address of the remote device. |
| |
| @returns: A byte array containing the value of the if the uuid/address |
| was found in the object tree. |
| None if the uuid/address was not found in the object tree, or |
| if a DBus exception was raised by the read operation. |
| |
| """ |
| value = self._proxy.read_characteristic(uuid, address) |
| if value is None: |
| return None |
| return bytearray(base64.standard_b64decode(value)) |
| |
| |
| @proxy_thread_safe |
| def write_characteristic(self, uuid, address, bytes_to_write): |
| """Performs a write operation on a gatt characteristic. |
| |
| Writes to a GATT characteristic on a remote device. |
| |
| @param uuid: The uuid of the characteristic to write to, as a string. |
| @param address: The MAC address of the remote device, as a string. |
| @param bytes_to_write: A byte array containing the data to write. |
| |
| @returns: True if the write operation does not raise an exception. |
| None if the uuid/address was not found in the object tree, or |
| if a DBus exception was raised by the write operation. |
| |
| """ |
| return self._proxy.write_characteristic( |
| uuid, address, base64.standard_b64encode(bytes_to_write)) |
| |
| |
| @proxy_thread_safe |
| def exchange_messages(self, tx_object_path, rx_object_path, bytes_to_write): |
| """Performs a write operation on a gatt characteristic and wait for |
| the response on another characteristic. |
| |
| @param tx_object_path: the object path of the characteristic to write. |
| @param rx_object_path: the object path of the characteristic to read. |
| @param value: A byte array containing the data to write. |
| |
| @returns: The value of the characteristic to read from. |
| None if the uuid/address was not found in the object tree, or |
| if a DBus exception was raised by the write operation. |
| |
| """ |
| return self._proxy.exchange_messages( |
| tx_object_path, rx_object_path, |
| base64.standard_b64encode(bytes_to_write)) |
| |
| |
| @proxy_thread_safe |
| def start_notify(self, object_path, cccd_value): |
| """Starts the notification session on the gatt characteristic. |
| |
| @param object_path: the object path of the characteristic. |
| @param cccd_value: Possible CCCD values include |
| 0x00 - inferred from the remote characteristic's properties |
| 0x01 - notification |
| 0x02 - indication |
| |
| @returns: True if the operation succeeds. |
| False if the characteristic is not found, or |
| if a DBus exception was raised by the operation. |
| |
| """ |
| return self._proxy.start_notify(object_path, cccd_value) |
| |
| |
| @proxy_thread_safe |
| def stop_notify(self, object_path): |
| """Stops the notification session on the gatt characteristic. |
| |
| @param object_path: the object path of the characteristic. |
| |
| @returns: True if the operation succeeds. |
| False if the characteristic is not found, or |
| if a DBus exception was raised by the operation. |
| |
| """ |
| return self._proxy.stop_notify(object_path) |
| |
| |
| @proxy_thread_safe |
| def is_notifying(self, object_path): |
| """Is the GATT characteristic in a notifying session? |
| |
| @param object_path: the object path of the characteristic. |
| |
| @return True if it is in a notification session. False otherwise. |
| |
| """ |
| return self._proxy.is_notifying(object_path) |
| |
| |
| @proxy_thread_safe |
| def is_characteristic_path_resolved(self, uuid, address): |
| """Checks whether a characteristic is in the object tree. |
| |
| Checks whether a characteristic is curently found in the object tree. |
| |
| @param uuid: The uuid of the characteristic to search for. |
| @param address: The MAC address of the device on which to search for |
| the characteristic. |
| |
| @returns: True if the characteristic is found, False otherwise. |
| |
| """ |
| return self._proxy.is_characteristic_path_resolved(uuid, address) |
| |
| |
| @proxy_thread_safe |
| def get_gatt_attributes_map(self, address): |
| """Return a JSON formated string of the GATT attributes of a device, |
| keyed by UUID |
| @param address: a string of the MAC address of the device |
| |
| @return: JSON formated string, stored the nested structure of the |
| attributes. Each attribute has 'path' and ['chrcs' | 'descs'], which |
| store their object path and children respectively. |
| """ |
| return self._proxy.get_gatt_attributes_map(address) |
| |
| |
| @proxy_thread_safe |
| def get_gatt_service_property(self, object_path, property_name): |
| """Get property from a service attribute |
| @param object_path: a string of the object path of the service |
| @param property_name: a string of a property, ex: 'Value', 'UUID' |
| |
| @return: the property if success, |
| None otherwise |
| """ |
| return self._proxy.get_gatt_service_property(object_path, property_name) |
| |
| |
| @proxy_thread_safe |
| def get_gatt_characteristic_property(self, object_path, property_name): |
| """Get property from a characteristic attribute |
| @param object_path: a string of the object path of the characteristic |
| @param property_name: a string of a property, ex: 'Value', 'UUID' |
| |
| @return: the property if success, |
| None otherwise |
| """ |
| return self._proxy.get_gatt_characteristic_property(object_path, |
| property_name) |
| |
| |
| @proxy_thread_safe |
| def get_gatt_descriptor_property(self, object_path, property_name): |
| """Get property from a descriptor attribute |
| @param object_path: a string of the object path of the descriptor |
| @param property_name: a string of a property, ex: 'Value', 'UUID' |
| |
| @return: the property if success, |
| None otherwise |
| """ |
| return self._proxy.get_gatt_descriptor_property(object_path, |
| property_name) |
| |
| |
| @proxy_thread_safe |
| def gatt_characteristic_read_value(self, uuid, object_path): |
| """Perform method ReadValue on a characteristic attribute |
| @param uuid: a string of uuid |
| @param object_path: a string of the object path of the characteristic |
| |
| @return: base64 string of dbus bytearray |
| """ |
| return self._proxy.gatt_characteristic_read_value(uuid, object_path) |
| |
| |
| @proxy_thread_safe |
| def gatt_descriptor_read_value(self, uuid, object_path): |
| """Perform method ReadValue on a descriptor attribute |
| @param uuid: a string of uuid |
| @param object_path: a string of the object path of the descriptor |
| |
| @return: base64 string of dbus bytearray |
| """ |
| return self._proxy.gatt_descriptor_read_value(uuid, object_path) |
| |
| |
| @proxy_thread_safe |
| def get_gatt_object_path(self, address, uuid): |
| """Get property from a characteristic attribute |
| |
| @param address: The MAC address of the remote device. |
| @param uuid: The uuid of the attribute. |
| |
| @return: the object path of the attribute if success, |
| none otherwise |
| |
| """ |
| return self._proxy.get_gatt_object_path(address, uuid) |
| |
| |
| def copy_logs(self, destination): |
| """Copy the logs generated by this device to a given location. |
| |
| @param destination: destination directory for the logs. |
| |
| """ |
| self.host.collect_logs(self.XMLRPC_LOG_PATH, destination) |
| |
| |
| @proxy_thread_safe |
| def get_connection_info(self, address): |
| """Get device connection info. |
| |
| @param address: The MAC address of the device. |
| |
| @returns: On success, a tuple of: |
| ( RSSI, transmit_power, max_transmit_power ) |
| None otherwise. |
| |
| """ |
| return self._proxy.get_connection_info(address) |
| |
| |
| @proxy_thread_safe |
| def set_discovery_filter(self, filter): |
| """Set the discovery filter. |
| |
| @param filter: The discovery filter to set. |
| |
| @return True on success, False otherwise. |
| |
| """ |
| return self._proxy.set_discovery_filter(filter) |
| |
| |
| @proxy_thread_safe |
| def set_le_connection_parameters(self, address, parameters): |
| """Set the LE connection parameters. |
| |
| @param address: The MAC address of the device. |
| @param parameters: The LE connection parameters to set. |
| |
| @return: True on success. False otherwise. |
| |
| """ |
| return self._proxy.set_le_connection_parameters(address, parameters) |
| |
| |
| @proxy_thread_safe |
| def wait_for_hid_device(self, device_address): |
| """Wait for hid device with given device address. |
| |
| Args: |
| device_address: Peripheral Address |
| |
| Returns: |
| True if hid device is found. |
| """ |
| return self._proxy.wait_for_hid_device(device_address) |
| |
| |
| @proxy_thread_safe |
| def bt_caused_last_resume(self): |
| """Checks if last resume from suspend was caused by bluetooth |
| |
| @return: True if BT wake path was cause of resume, False otherwise |
| """ |
| |
| return self._proxy.bt_caused_last_resume() |
| |
| @proxy_thread_safe |
| def find_last_suspend_via_powerd_logs(self): |
| """Finds the last suspend attempt via powerd logs. |
| |
| @return: Tuple (suspend start time, suspend end time, suspend result) or |
| None |
| """ |
| info = self._proxy.find_last_suspend_via_powerd_logs() |
| |
| # Currently, we get the date back in string format due to python2/3 |
| # inconsistencies. We can get rid of this once everything is running |
| # python3 (hopefully) |
| # TODO - Revisit converting date to string and back in this method |
| if info: |
| start_date = datetime.strptime(info[0], self.NATIVE_DATE_FORMAT) |
| end_date = datetime.strptime(info[1], self.NATIVE_DATE_FORMAT) |
| ret = info[2] |
| |
| return (start_date, end_date, ret) |
| |
| return None |
| |
| @proxy_thread_safe |
| def do_suspend(self, seconds, expect_bt_wake): |
| """Suspend DUT using the power manager. |
| |
| @param seconds: The number of seconds to suspend the device. |
| @param expect_bt_wake: Whether we expect bluetooth to wake us from |
| suspend. If true, we expect this resume will occur early |
| """ |
| |
| # Do not retry this RPC if it fails or times out |
| return self._proxy.do_suspend(seconds, expect_bt_wake, __no_retry=True) |
| |
| |
| @proxy_thread_safe |
| def get_wlan_vid_pid(self): |
| """ Return vendor id and product id of the wlan chip on BT/WiFi module |
| |
| @returns: (vid,pid) on success; (None,None) on failure |
| """ |
| return self._proxy.get_wlan_vid_pid() |
| |
| @proxy_thread_safe |
| def get_bt_module_name(self): |
| """ Return bluetooth module name for non-USB devices |
| |
| @returns: Name of the Bluetooth module (or string read from device on |
| success); '' on failure |
| """ |
| return self._proxy.get_bt_module_name() |
| |
| @proxy_thread_safe |
| def get_device_time(self): |
| """ Get the current device time. """ |
| return datetime.strptime(self._proxy.get_device_time(), |
| self.NATIVE_DATE_FORMAT) |
| |
| @proxy_thread_safe |
| def close(self, close_host=True): |
| """Tear down state associated with the client. |
| |
| @param close_host: If True, shut down the xml rpc server by closing the |
| underlying host object (which also shuts down all other xml rpc |
| servers running on the DUT). Otherwise, only shut down the |
| bluetooth device xml rpc server, which can be desirable if the host |
| object and/or other xml rpc servers need to be used afterwards. |
| """ |
| # Turn off the discoverable flag since it may affect future tests. |
| self._proxy.set_discoverable(False) |
| # Reset the adapter and leave it on. |
| self._proxy.reset_on() |
| # This kills the RPC server. |
| if close_host: |
| self.host.close() |
| elif self._bt_direct_proxy: |
| self.host.rpc_server_tracker.disconnect( |
| constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT) |