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 json 6 7from autotest_lib.client.cros import constants 8from autotest_lib.server import autotest 9 10 11class BluetoothDevice(object): 12 """BluetoothDevice is a thin layer of logic over a remote DUT. 13 14 The Autotest host object representing the remote DUT, passed to this 15 class on initialization, can be accessed from its host property. 16 17 """ 18 19 XMLRPC_BRINGUP_TIMEOUT_SECONDS = 60 20 XMLRPC_LOG_PATH = '/var/log/bluetooth_xmlrpc_device.log' 21 22 def __init__(self, device_host): 23 """Construct a BluetoothDevice. 24 25 @param device_host: host object representing a remote host. 26 27 """ 28 self.host = device_host 29 # Make sure the client library is on the device so that the proxy code 30 # is there when we try to call it. 31 client_at = autotest.Autotest(self.host) 32 client_at.install() 33 # Start up the XML-RPC proxy on the client. 34 self._proxy = self.host.rpc_server_tracker.xmlrpc_connect( 35 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_COMMAND, 36 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT, 37 command_name= 38 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_CLEANUP_PATTERN, 39 ready_test_name= 40 constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_READY_METHOD, 41 timeout_seconds=self.XMLRPC_BRINGUP_TIMEOUT_SECONDS, 42 logfile=self.XMLRPC_LOG_PATH) 43 44 45 def reset_on(self): 46 """Reset the adapter and settings and power up the adapter. 47 48 @return True on success, False otherwise. 49 50 """ 51 return self._proxy.reset_on() 52 53 54 def reset_off(self): 55 """Reset the adapter and settings, leave the adapter powered off. 56 57 @return True on success, False otherwise. 58 59 """ 60 return self._proxy.reset_off() 61 62 63 def has_adapter(self): 64 """@return True if an adapter is present, False if not.""" 65 return self._proxy.has_adapter() 66 67 68 def set_powered(self, powered): 69 """Set the adapter power state. 70 71 @param powered: adapter power state to set (True or False). 72 73 @return True on success, False otherwise. 74 75 """ 76 return self._proxy.set_powered(powered) 77 78 79 def set_discoverable(self, discoverable): 80 """Set the adapter discoverable state. 81 82 @param discoverable: adapter discoverable state to set (True or False). 83 84 @return True on success, False otherwise. 85 86 """ 87 return self._proxy.set_discoverable(discoverable) 88 89 90 def set_pairable(self, pairable): 91 """Set the adapter pairable state. 92 93 @param pairable: adapter pairable state to set (True or False). 94 95 @return True on success, False otherwise. 96 97 """ 98 return self._proxy.set_pairable(pairable) 99 100 101 def get_adapter_properties(self): 102 """Read the adapter properties from the Bluetooth Daemon. 103 104 @return the properties as a dictionary on success, 105 the value False otherwise. 106 107 """ 108 return json.loads(self._proxy.get_adapter_properties()) 109 110 111 def read_version(self): 112 """Read the version of the management interface from the Kernel. 113 114 @return the version as a tuple of: 115 ( version, revision ) 116 117 """ 118 return json.loads(self._proxy.read_version()) 119 120 121 def read_supported_commands(self): 122 """Read the set of supported commands from the Kernel. 123 124 @return set of supported commands as arrays in a tuple of: 125 ( commands, events ) 126 127 """ 128 return json.loads(self._proxy.read_supported_commands()) 129 130 131 def read_index_list(self): 132 """Read the list of currently known controllers from the Kernel. 133 134 @return array of controller indexes. 135 136 """ 137 return json.loads(self._proxy.read_index_list()) 138 139 140 def read_info(self): 141 """Read the adapter information from the Kernel. 142 143 @return the information as a tuple of: 144 ( address, bluetooth_version, manufacturer_id, 145 supported_settings, current_settings, class_of_device, 146 name, short_name ) 147 148 """ 149 return json.loads(self._proxy.read_info()) 150 151 152 def add_device(self, address, address_type, action): 153 """Add a device to the Kernel action list. 154 155 @param address: Address of the device to add. 156 @param address_type: Type of device in @address. 157 @param action: Action to take. 158 159 @return tuple of ( address, address_type ) on success, 160 None on failure. 161 162 """ 163 return json.loads(self._proxy.add_device(address, address_type, action)) 164 165 166 def remove_device(self, address, address_type): 167 """Remove a device from the Kernel action list. 168 169 @param address: Address of the device to remove. 170 @param address_type: Type of device in @address. 171 172 @return tuple of ( address, address_type ) on success, 173 None on failure. 174 175 """ 176 return json.loads(self._proxy.remove_device(address, address_type)) 177 178 179 def get_devices(self): 180 """Read information about remote devices known to the adapter. 181 182 @return the properties of each device as an array of 183 dictionaries on success, the value False otherwise. 184 185 """ 186 return json.loads(self._proxy.get_devices()) 187 188 189 def start_discovery(self): 190 """Start discovery of remote devices. 191 192 Obtain the discovered device information using get_devices(), called 193 stop_discovery() when done. 194 195 @return True on success, False otherwise. 196 197 """ 198 return self._proxy.start_discovery() 199 200 201 def stop_discovery(self): 202 """Stop discovery of remote devices. 203 204 @return True on success, False otherwise. 205 206 """ 207 return self._proxy.stop_discovery() 208 209 210 def get_dev_info(self): 211 """Read raw HCI device information. 212 213 @return tuple of (index, name, address, flags, device_type, bus_type, 214 features, pkt_type, link_policy, link_mode, 215 acl_mtu, acl_pkts, sco_mtu, sco_pkts, 216 err_rx, err_tx, cmd_tx, evt_rx, acl_tx, acl_rx, 217 sco_tx, sco_rx, byte_rx, byte_tx) on success, 218 None on failure. 219 220 """ 221 return json.loads(self._proxy.get_dev_info()) 222 223 224 def register_profile(self, path, uuid, options): 225 """Register new profile (service). 226 227 @param path: Path to the profile object. 228 @param uuid: Service Class ID of the service as string. 229 @param options: Dictionary of options for the new service, compliant 230 with BlueZ D-Bus Profile API standard. 231 232 @return True on success, False otherwise. 233 234 """ 235 return self._proxy.register_profile(path, uuid, options) 236 237 238 def has_device(self, address): 239 """Checks if the device with a given address exists. 240 241 @param address: Address of the device. 242 243 @returns: True if there is a device with that address. 244 False otherwise. 245 246 """ 247 return self._proxy.has_device(address) 248 249 250 def pair_legacy_device(self, address, pin, timeout): 251 """Pairs a device with a given pin code. 252 253 Registers an agent who handles pin code request and 254 pairs a device with known pin code. 255 256 @param address: Address of the device to pair. 257 @param pin: The pin code of the device to pair. 258 @param timeout: The timeout in seconds for pairing. 259 260 @returns: True on success. False otherwise. 261 262 """ 263 return self._proxy.pair_legacy_device(address, pin, timeout) 264 265 266 def connect_device(self, address): 267 """Connects a device. 268 269 Connects a device if it is not connected. 270 271 @param address: Address of the device to connect. 272 273 @returns: True on success. False otherwise. 274 275 """ 276 return self._proxy.connect_device(address) 277 278 279 def device_is_connected(self, address): 280 """Checks if a device is connected. 281 282 @param address: Address of the device to check if it is connected. 283 284 @returns: True if device is connected. False otherwise. 285 286 """ 287 return self._proxy.device_is_connected(address) 288 289 290 def disconnect_device(self, address): 291 """Disconnects a device. 292 293 Disconnects a device if it is connected. 294 295 @param address: Address of the device to disconnect. 296 297 @returns: True on success. False otherwise. 298 299 """ 300 return self._proxy.disconnect_device(address) 301 302 303 def copy_logs(self, destination): 304 """Copy the logs generated by this device to a given location. 305 306 @param destination: destination directory for the logs. 307 308 """ 309 self.host.collect_logs(self.XMLRPC_LOG_PATH, destination) 310 311 312 def close(self): 313 """Tear down state associated with the client.""" 314 # Turn off the discoverable flag since it may affect future tests. 315 self._proxy.set_discoverable(False) 316 # Leave the adapter powered off, but don't do a full reset. 317 self._proxy.set_powered(False) 318 # This kills the RPC server. 319 self.host.close() 320