14dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant#!/usr/bin/env python 24dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 34dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 44dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant# Use of this source code is governed by a BSD-style license that can be 54dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant# found in the LICENSE file. 64dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 7da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnantimport base64 8da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnantimport json 94dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnantimport logging 104dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnantimport logging.handlers 114dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 124dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnantimport common 13448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhovfrom autotest_lib.client.common_lib.cros.bluetooth import bluetooth_sdp_socket 146946f948018ca7ce9263e9a9b5ff0eee676c1f68Christopher Wileyfrom autotest_lib.client.common_lib.cros.bluetooth import bluetooth_socket 15e0b08e6170b57f90262726eb7f04e059cb47419cHsinyu Chaofrom autotest_lib.client.cros import constants 16ec0b71daa4d20f466724523821e4f4908d7e7d5aChristopher Wileyfrom autotest_lib.client.cros import xmlrpc_server 174dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 184dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 194dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnantclass BluetoothTesterXmlRpcDelegate(xmlrpc_server.XmlRpcDelegate): 20448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov """Exposes Tester methods called remotely during Bluetooth autotests. 214dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 224dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant All instance methods of this object without a preceding '_' are exposed via 234dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant an XML-RPC server. This is not a stateless handler object, which means that 24aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant if you store state inside the delegate, that state will remain around for 254dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant future calls. 264dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant """ 274dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 28da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant BR_EDR_LE_PROFILE = ( 29da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant bluetooth_socket.MGMT_SETTING_POWERED | 30da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant bluetooth_socket.MGMT_SETTING_CONNECTABLE | 31da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant bluetooth_socket.MGMT_SETTING_PAIRABLE | 32da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant bluetooth_socket.MGMT_SETTING_SSP | 33da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant bluetooth_socket.MGMT_SETTING_BREDR | 34da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant bluetooth_socket.MGMT_SETTING_LE) 35da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 36f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant LE_PROFILE = ( 37f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant bluetooth_socket.MGMT_SETTING_POWERED | 38f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant bluetooth_socket.MGMT_SETTING_CONNECTABLE | 39f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant bluetooth_socket.MGMT_SETTING_PAIRABLE | 40f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant bluetooth_socket.MGMT_SETTING_LE) 41f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant 42da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant PROFILE_SETTINGS = { 43da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 'computer': BR_EDR_LE_PROFILE, 44f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant 'peripheral': LE_PROFILE 45da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant } 46da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 47da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant PROFILE_CLASS = { 48da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 'computer': 0x000104, 49f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant 'peripheral': None 50da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant } 51da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 52da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant PROFILE_NAMES = { 53da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 'computer': ('ChromeOS Bluetooth Tester', 'Tester'), 54f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant 'peripheral': ('ChromeOS Bluetooth Tester', 'Tester') 55da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant } 56da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 57da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 584dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant def __init__(self): 59da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant super(BluetoothTesterXmlRpcDelegate, self).__init__() 60da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 61da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant # Open the Bluetooth Control socket to the kernel which provides us 62da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant # the needed raw management access to the Bluetooth Host Subsystem. 63da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant self._control = bluetooth_socket.BluetoothControlSocket() 64448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov # Open the Bluetooth SDP socket to the kernel which provides us the 65448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov # needed interface to use SDP commands. 66448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov self._sdp = bluetooth_sdp_socket.BluetoothSDPSocket() 67da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant # This is almost a constant, but it might not be forever. 68da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant self.index = 0 69da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 70da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 71da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant def setup(self, profile): 72da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant """Set up the tester with the given profile. 73da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 74da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant @param profile: Profile to use for this test, valid values are: 75da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant computer - a standard computer profile 76da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 77da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant @return True on success, False otherwise. 78da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 79da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant """ 80da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant profile_settings = self.PROFILE_SETTINGS[profile] 81c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant profile_class = self.PROFILE_CLASS[profile] 82c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant (profile_name, profile_short_name) = self.PROFILE_NAMES[profile] 83c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant 84e56271c1898aaae33231a206b1ea28c5e6afb529Scott James Remnant # Make sure the controller actually exists. 85e56271c1898aaae33231a206b1ea28c5e6afb529Scott James Remnant if self.index not in self._control.read_index_list(): 86e56271c1898aaae33231a206b1ea28c5e6afb529Scott James Remnant logging.warning('Bluetooth Controller missing on tester') 87e56271c1898aaae33231a206b1ea28c5e6afb529Scott James Remnant return False 88e56271c1898aaae33231a206b1ea28c5e6afb529Scott James Remnant 89da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant # Make sure all of the settings are supported by the controller. 90da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant ( address, bluetooth_version, manufacturer_id, 91da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant supported_settings, current_settings, class_of_device, 92da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant name, short_name ) = self._control.read_info(self.index) 93da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant if profile_settings & supported_settings != profile_settings: 94da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant logging.warning('Controller does not support requested settings') 95c026987fe3ef3f5d16f956176d4f52c464b46856Katherine Threlkeld logging.debug('Supported: %b; Requested: %b', supported_settings, 96c026987fe3ef3f5d16f956176d4f52c464b46856Katherine Threlkeld profile_settings) 97da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return False 98da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 99589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant # Before beginning, force the adapter power off, even if it's already 100589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant # off; this is enough to persuade an AP-mode Intel chip to accept 101589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant # settings. 102589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant if not self._control.set_powered(self.index, False): 103589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant logging.warning('Failed to power off adapter to accept settings') 104589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant return False 1058316318f409a01e1b7d1e96b447bb6942a2d7752Scott James Remnant 106f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # Set the controller up as either BR/EDR only, LE only or Dual Mode. 107f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # This is a bit tricky because it rejects commands outright unless 108f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # it's in dual mode, so we actually have to figure out what changes 109f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # we have to make, and we have to turn things on before we turn them 110f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # off. 111f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant turn_on = (current_settings ^ profile_settings) & profile_settings 112f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if turn_on & bluetooth_socket.MGMT_SETTING_BREDR: 113f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if self._control.set_bredr(self.index, True) is None: 114f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant logging.warning('Failed to enable BR/EDR') 115f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant return False 116f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if turn_on & bluetooth_socket.MGMT_SETTING_LE: 117f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if self._control.set_le(self.index, True) is None: 118f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant logging.warning('Failed to enable LE') 119f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant return False 120f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant 121f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant turn_off = (current_settings ^ profile_settings) & current_settings 122f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if turn_off & bluetooth_socket.MGMT_SETTING_BREDR: 123f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if self._control.set_bredr(self.index, False) is None: 124f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant logging.warning('Failed to disable BR/EDR') 125f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant return False 126f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if turn_off & bluetooth_socket.MGMT_SETTING_LE: 127f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if self._control.set_le(self.index, False) is None: 128f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant logging.warning('Failed to disable LE') 129f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant return False 130f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant 131f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # Adjust settings that are BR/EDR specific that we need to set before 132f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # powering on the adapter, and would be rejected otherwise. 133f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if profile_settings & bluetooth_socket.MGMT_SETTING_BREDR: 134f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if (self._control.set_link_security( 135f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant self.index, 136f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant (profile_settings & 137f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant bluetooth_socket.MGMT_SETTING_LINK_SECURITY)) 138f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant is None): 139f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant logging.warning('Failed to set link security setting') 140f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant return False 141f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if (self._control.set_ssp( 142f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant self.index, 143f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant profile_settings & bluetooth_socket.MGMT_SETTING_SSP) 144f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant is None): 145f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant logging.warning('Failed to set SSP setting') 146f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant return False 147f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if (self._control.set_hs( 148f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant self.index, 149f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant profile_settings & bluetooth_socket.MGMT_SETTING_HS) 150f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant is None): 151f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant logging.warning('Failed to set High Speed setting') 152f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant return False 153f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant 154c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant # Split our the major and minor class; it's listed as a kernel bug 155c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant # that we supply these to the kernel without shifting the bits over 156c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant # to take out the CoD format field, so this might have to change 157c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant # one day. 158c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant major_class = (profile_class & 0x00ff00) >> 8 159c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant minor_class = profile_class & 0x0000ff 160c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant if (self._control.set_device_class( 161c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant self.index, major_class, minor_class) 162c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant is None): 163c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant logging.warning('Failed to set device class') 164c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant return False 165c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant 166f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # Setup generic settings that apply to either BR/EDR, LE or dual-mode 167f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # that still require the power to be off. 168589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant if (self._control.set_connectable( 169da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant self.index, 170589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant profile_settings & bluetooth_socket.MGMT_SETTING_CONNECTABLE) 171da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant is None): 172589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant logging.warning('Failed to set connectable setting') 173da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return False 174589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant if (self._control.set_pairable( 175da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant self.index, 176589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant profile_settings & bluetooth_socket.MGMT_SETTING_PAIRABLE) 177da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant is None): 178589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant logging.warning('Failed to set pairable setting') 179da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return False 180589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant 181c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant if (self._control.set_local_name( 182c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant self.index, profile_name, profile_short_name) 183c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant is None): 184c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant logging.warning('Failed to set local name') 185c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant return False 186c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant 187589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant # Now the settings have been set, power up the adapter. 188589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant if not self._control.set_powered( 189da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant self.index, 190589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant profile_settings & bluetooth_socket.MGMT_SETTING_POWERED): 191589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant logging.warning('Failed to set powered setting') 192589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant return False 193589b7fff8391bc20acc748c2a5de63c773599077Scott James Remnant 194f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # Fast connectable can only be set once the controller is powered, 195f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant # and only when BR/EDR is enabled. 196f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if profile_settings & bluetooth_socket.MGMT_SETTING_BREDR: 197c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant # Wait for the device class set event, this happens after the 198c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant # power up "command complete" event when we've pre-set the class 199c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant # even though it's a side-effect of doing that. 200c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant self._control.wait_for_events( 201c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant self.index, 202c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant ( bluetooth_socket.MGMT_EV_CLASS_OF_DEV_CHANGED, )) 203c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant 204f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant if (self._control.set_fast_connectable( 205f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant self.index, 206f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant profile_settings & 207f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant bluetooth_socket.MGMT_SETTING_FAST_CONNECTABLE) 208f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant is None): 209f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant logging.warning('Failed to set fast connectable setting') 210f719e2d8dfc2610974c44186fac641cd215b7460Scott James Remnant return False 211da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 212da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant # Fetch the settings again and make sure they're all set correctly, 213da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant # including the BR/EDR flag. 214da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant ( address, bluetooth_version, manufacturer_id, 215da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant supported_settings, current_settings, class_of_device, 216da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant name, short_name ) = self._control.read_info(self.index) 2173988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov 2183988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov # Check generic settings. 219da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant if profile_settings != current_settings: 220da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant logging.warning('Controller settings did not match those set: ' 221da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant '%x != %x', current_settings, profile_settings) 222da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return False 223c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant if name != profile_name: 224da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant logging.warning('Local name did not match that set: "%s" != "%s"', 225c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant name, profile_name) 226da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return False 227c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant elif short_name != profile_short_name: 228da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant logging.warning('Short name did not match that set: "%s" != "%s"', 229c9864b65a425f8806d2400264e52899d2bcdad90Scott James Remnant short_name, profile_short_name) 230da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return False 231da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 2323988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov # Check BR/EDR specific settings. 2333988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov if profile_settings & bluetooth_socket.MGMT_SETTING_BREDR: 2343988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov if class_of_device != profile_class: 2353988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov if class_of_device & 0x00ffff == profile_class & 0x00ffff: 2363988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov logging.warning('Class of device matched that set, but ' 2373988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov 'Service Class field did not: %x != %x ' 2383988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov 'Reboot Tester? ', 2393988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov class_of_device, profile_class) 2403988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov else: 2413988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov logging.warning('Class of device did not match that set: ' 2423988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov '%x != %x', class_of_device, profile_class) 2433988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov return False 2443988665743edec3f0f709e9be7928120fdcf4a47Artem Rakhov 245da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return True 246da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 247da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 248aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant def set_discoverable(self, discoverable, timeout=0): 249aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant """Set the discoverable state of the controller. 250aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 251aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant @param discoverable: Whether controller should be discoverable. 252aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant @param timeout: Timeout in seconds before disabling discovery again, 253aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant ignored when discoverable is False, must not be zero when 254aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant discoverable is True. 255aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 256aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant @return True on success, False otherwise. 257aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 258aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant """ 259aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant settings = self._control.set_discoverable(self.index, 260aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant discoverable, timeout) 261aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant return settings & bluetooth_socket.MGMT_SETTING_DISCOVERABLE 262aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 263aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 264aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant def read_info(self): 265aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant """Read the adapter information from the Kernel. 266aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 267aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant @return the information as a JSON-encoded tuple of: 268aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant ( address, bluetooth_version, manufacturer_id, 269aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant supported_settings, current_settings, class_of_device, 270aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant name, short_name ) 271aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 272aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant """ 273aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant return json.dumps(self._control.read_info(self.index)) 274aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 275aec4edd340e914885cb1fe26e9b8766788009f2fScott James Remnant 276e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant def set_advertising(self, advertising): 277e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant """Set the whether the controller is advertising via LE. 278e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant 279e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant @param advertising: Whether controller should advertise via LE. 280e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant 281e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant @return True on success, False otherwise. 282e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant 283e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant """ 284e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant settings = self._control.set_advertising(self.index, advertising) 285e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant return settings & bluetooth_socket.MGMT_SETTING_ADVERTISING 286e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant 287e686dcc4914aaf44164ce0cb9bd5dd243477fa76Scott James Remnant 288da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant def discover_devices(self, br_edr=True, le_public=True, le_random=True): 289da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant """Discover remote devices. 290da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 291da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant Activates device discovery and collects the set of devices found, 292da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant returning them as a list. 293da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 294da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant @param br_edr: Whether to detect BR/EDR devices. 295da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant @param le_public: Whether to detect LE Public Address devices. 296da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant @param le_random: Whether to detect LE Random Address devices. 297da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 298da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant @return List of devices found as JSON-encoded tuples with the format 299da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant (address, address_type, rssi, flags, base64-encoded eirdata), 300da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant or False if discovery could not be started. 301da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 302da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant """ 303da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant address_type = 0 304da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant if br_edr: 305da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant address_type |= 0x1 306da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant if le_public: 307da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant address_type |= 0x2 308da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant if le_random: 309da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant address_type |= 0x4 310da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 311da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant set_type = self._control.start_discovery(self.index, address_type) 312da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant if set_type != address_type: 313da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant logging.warning('Discovery address type did not match that set: ' 314da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant '%x != %x', set_type, address_type) 315da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return False 316da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant 317da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant devices = self._control.get_discovered_devices(self.index) 318da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant return json.dumps([ 319da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant (address, address_type, rssi, flags, 320da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant base64.encodestring(eirdata)) 321da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant for address, address_type, rssi, flags, eirdata in devices 322da9f43cc5c84691d82b1dd9222fea37234cb9a0aScott James Remnant ]) 3234dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 3244dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 325448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov def connect(self, address): 326448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov """Connect to device with the given address 327448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 328448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov @param address: Bluetooth address. 329448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 330448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov """ 331448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov self._sdp.connect(address) 332448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov return True 333448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 334448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 335ba130384b49108dcfa91ad7751b825c0d0128963Artem Rakhov def service_search_request(self, uuids, max_rec_cnt, preferred_size=32, 336f42dc83292497e95cf4f41c6463f697b840826e2Artem Rakhov forced_pdu_size=None, invalid_request=False): 337448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov """Send a Service Search Request 338448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 339ba130384b49108dcfa91ad7751b825c0d0128963Artem Rakhov @param uuids: List of UUIDs (as integers) to look for. 340448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov @param max_rec_cnt: Maximum count of returned service records. 341ca443b518bfe8457c73d9a0cddadf8f6972a4c64Artem Rakhov @param preferred_size: Preffered size of UUIDs in bits (16, 32, or 128). 342ba130384b49108dcfa91ad7751b825c0d0128963Artem Rakhov @param forced_pdu_size: Use certain PDU size parameter instead of 343ba130384b49108dcfa91ad7751b825c0d0128963Artem Rakhov calculating actual length of sequence. 344f42dc83292497e95cf4f41c6463f697b840826e2Artem Rakhov @param invalid_request: Whether to send request with intentionally 345f42dc83292497e95cf4f41c6463f697b840826e2Artem Rakhov invalid syntax for testing purposes (bool flag). 346448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 347ba130384b49108dcfa91ad7751b825c0d0128963Artem Rakhov @return list of found services' service record handles or Error Code 348448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 349448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov """ 350275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov return json.dumps( 351275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov self._sdp.service_search_request( 352275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov uuids, max_rec_cnt, preferred_size, forced_pdu_size, 353275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov invalid_request) 354275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov ) 355448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 356448d52cd25de24ffd96a882a4445fc7c8326e413Artem Rakhov 357af4e4a6932ecbb6744e48f4f9e2dcc12f3ba9d50Artem Rakhov def service_attribute_request(self, handle, max_attr_byte_count, attr_ids, 358af4e4a6932ecbb6744e48f4f9e2dcc12f3ba9d50Artem Rakhov forced_pdu_size=None, invalid_request=None): 359ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov """Send a Service Attribute Request 360ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov 361ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov @param handle: service record from which attribute values are to be 362ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov retrieved. 363ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov @param max_attr_byte_count: maximum number of bytes of attribute data to 364ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov be returned in the response to this request. 365ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov @param attr_ids: a list, where each element is either an attribute ID 366ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov or a range of attribute IDs. 367af4e4a6932ecbb6744e48f4f9e2dcc12f3ba9d50Artem Rakhov @param forced_pdu_size: Use certain PDU size parameter instead of 368af4e4a6932ecbb6744e48f4f9e2dcc12f3ba9d50Artem Rakhov calculating actual length of sequence. 369af4e4a6932ecbb6744e48f4f9e2dcc12f3ba9d50Artem Rakhov @param invalid_request: Whether to send request with intentionally 370af4e4a6932ecbb6744e48f4f9e2dcc12f3ba9d50Artem Rakhov invalid syntax for testing purposes (string with raw request). 371ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov 372ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov @return list of found attributes IDs and their values or Error Code 373ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov 374ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov """ 375275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov return json.dumps( 376275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov self._sdp.service_attribute_request( 377275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov handle, max_attr_byte_count, attr_ids, forced_pdu_size, 378275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov invalid_request) 379275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov ) 380ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov 381ebf3df32a3bfa32782ffdc8e0ce5bf6d65734d5dArtem Rakhov 382f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov def service_search_attribute_request(self, uuids, max_attr_byte_count, 383ef5a458439a763afa1937837cdf5b6d7065be74dArtem Rakhov attr_ids, preferred_size=32, 384ef5a458439a763afa1937837cdf5b6d7065be74dArtem Rakhov forced_pdu_size=None, 385ef5a458439a763afa1937837cdf5b6d7065be74dArtem Rakhov invalid_request=None): 386f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov """Send a Service Search Attribute Request 387f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov 388f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov @param uuids: list of UUIDs (as integers) to look for. 389f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov @param max_attr_byte_count: maximum number of bytes of attribute data to 390f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov be returned in the response to this request. 391f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov @param attr_ids: a list, where each element is either an attribute ID 392f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov or a range of attribute IDs. 393f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov @param preferred_size: Preffered size of UUIDs in bits (16, 32, or 128). 394ef5a458439a763afa1937837cdf5b6d7065be74dArtem Rakhov @param forced_pdu_size: Use certain PDU size parameter instead of 395ef5a458439a763afa1937837cdf5b6d7065be74dArtem Rakhov calculating actual length of sequence. 396ef5a458439a763afa1937837cdf5b6d7065be74dArtem Rakhov @param invalid_request: Whether to send request with intentionally 397ef5a458439a763afa1937837cdf5b6d7065be74dArtem Rakhov invalid syntax for testing purposes (string to be prepended 398ef5a458439a763afa1937837cdf5b6d7065be74dArtem Rakhov to correct request). 399f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov 400f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov @return list of found attributes IDs and their values or Error Code 401f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov 402f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov """ 403275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov return json.dumps( 404275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov self._sdp.service_search_attribute_request( 405275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov uuids, max_attr_byte_count, attr_ids, preferred_size, 406275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov forced_pdu_size, invalid_request) 407275ecaf0baf905cf69b0c144aac1ae905857cd9cArtem Rakhov ) 408f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov 409f53eeec1740214b1838f577559ba0acd856e996cArtem Rakhov 4104dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnantif __name__ == '__main__': 4114dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant logging.basicConfig(level=logging.DEBUG) 4124dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant handler = logging.handlers.SysLogHandler(address = '/dev/log') 4139fd7f46552205dc17e1d888632658bdf1a97d603Christopher Wiley formatter = logging.Formatter( 4149fd7f46552205dc17e1d888632658bdf1a97d603Christopher Wiley 'bluetooth_tester_xmlrpc_server: [%(levelname)s] %(message)s') 4159fd7f46552205dc17e1d888632658bdf1a97d603Christopher Wiley handler.setFormatter(formatter) 4164dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant logging.getLogger().addHandler(handler) 4174dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant logging.debug('bluetooth_tester_xmlrpc_server main...') 4184dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant server = xmlrpc_server.XmlRpcServer( 4194dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant 'localhost', 4204dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant constants.BLUETOOTH_TESTER_XMLRPC_SERVER_PORT) 4214dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant server.register_delegate(BluetoothTesterXmlRpcDelegate()) 4224dcd73f7d38d89063911c74796db9aa68ff8b064Scott James Remnant server.run() 423