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 5 import cgi 6 import logging 7 8 from autotest_lib.client.bin import utils 9 from autotest_lib.client.common_lib import error 10 from autotest_lib.server.cros.bluetooth import bluetooth_test 11 12 13 class bluetooth_Sanity_LEDiscovery(bluetooth_test.BluetoothTest): 14 """ 15 Verify that the client can discover the tester. 16 """ 17 version = 1 18 19 # How long should the tester remain discoverable? 20 DISCOVERABLE_TIMEOUT=180 21 22 def find_device(self): 23 """Retrieve devices from client and look for tester. 24 25 @return True if device has been found, False otherwise. 26 27 """ 28 # Get the set of devices known to the DUT. 29 devices = self.device.get_devices() 30 if devices == False: 31 raise error.TestFail('Could not retrieve devices from DUT') 32 33 device_found = False 34 for device in devices: 35 if self.tester: 36 if self.address == device['Address']: 37 logging.info('Found tester with RSSI %d', 38 device.get('RSSI')) 39 # Check name as well; if the name and alias fields don't 40 # match, that means it hasn't been requested yet, so 41 # wait until next time. 42 if device.get('Name') != device['Alias']: 43 logging.info('Device name not yet received') 44 continue 45 if self.name != device['Alias']: 46 raise error.TestFail( 47 'Tester did not have expected name ' + 48 '"%s" != "%s"' % (device['Alias'], 49 self.name)) 50 # Found the device 51 device_found = True 52 # Write out the RSSI now we've found it. 53 self.write_perf_keyval({'rssi': int(device.get('RSSI', 0))}) 54 self.output_perf_value('rssi', int(device.get('RSSI', 0)), 55 'dBm') 56 57 if self.interactive: 58 item_name = device['Address'].replace(':', '') 59 html = '%s %s' % (cgi.escape(device['Address']), 60 cgi.escape(device['Alias'])) 61 62 if device['Address'] in self.devices_discovered: 63 self.interactive.replace_list_item(item_name, html) 64 else: 65 self.interactive.append_list_item('devices', item_name, 66 html) 67 self.devices_discovered.append(device['Address']) 68 69 result = self.interactive.check_for_button() 70 if result == 0: 71 device_found = True 72 elif result != -1: 73 raise error.TestFail('User indicated test failed') 74 75 return device_found 76 77 78 def run_once(self): 79 # Reset the adapter to the powered on state. 80 if not self.device.reset_on(): 81 raise error.TestFail('DUT could not be reset to initial state') 82 83 if self.tester: 84 # Setup the tester as a generic LE peripheral. 85 if not self.tester.setup('peripheral'): 86 raise error.TestFail('Tester could not be initialized') 87 # Enable general discoverable advertising on the tester 88 self.tester.set_discoverable(True) 89 self.tester.set_advertising(True) 90 # Read the tester information so we know what we're looking for. 91 ( address, bluetooth_version, manufacturer_id, 92 supported_settings, current_settings, class_of_device, 93 name, short_name ) = self.tester.read_info() 94 self.address = address 95 self.name = name 96 97 if self.interactive: 98 self.interactive.login() 99 100 if self.tester: 101 self.interactive.append_output( 102 '<p>The Tester is advertising as an LE peripheral. ' 103 '<p>The DUT is in the observer/discovery state. ' 104 '<p>Please verify that you can discover the tester ' + 105 ('<b>%s</b> with address <b>%s</b> from the device.' % 106 (cgi.escape(self.name), 107 cgi.escape(self.address)))) 108 else: 109 self.interactive.append_output( 110 '<p>The DUT is in the observer/discovery state. ' 111 '<p>Please verify that you can discover the device.') 112 113 self.interactive.append_output('<h2>Devices Found</h2>') 114 self.interactive.append_list('devices') 115 self.devices_discovered = [] 116 117 if self.tester: 118 self.interactive.append_buttons('Tester Found', 119 'Tester Not Found') 120 else: 121 self.interactive.append_buttons('Device Found', 122 'Device Not Found') 123 124 # Discover devices from the DUT. 125 for failed_attempts in range(0, 5): 126 if not self.device.start_discovery(): 127 raise error.TestFail('Could not start discovery on DUT') 128 try: 129 utils.poll_for_condition( 130 condition=self.find_device, 131 desc='Device discovered from DUT', 132 timeout=self.DISCOVERABLE_TIMEOUT) 133 # We only reach this if we find a device. Break out of the 134 # failed_attempts loop to bypass the "reached the end" 135 # condition. 136 break 137 except utils.TimeoutError: 138 # Capture the timeout error and try once more through the 139 # loop. 140 pass 141 finally: 142 if not self.device.stop_discovery(): 143 logging.warning('Failed to stop discovery on DUT') 144 else: 145 # We only reach this if we tried five times to find the device and 146 # failed. 147 raise error.TestFail('DUT could not discover device') 148 # Record how many attempts this took, hopefully we'll one day figure 149 # out a way to reduce this to zero and then the loop above can go 150 # away. 151 self.write_perf_keyval({'failed_attempts': failed_attempts }) 152 self.output_perf_value('failed_attempts', failed_attempts, 'attempts') 153 154 155 def cleanup(self): 156 """Set the tester back to not advertising.""" 157 if self.tester: 158 self.tester.set_advertising(False) 159 self.tester.set_discoverable(False) 160 161 super(bluetooth_Sanity_LEDiscovery, self).cleanup() 162