blob: 6ac05522d8bc8479eff96a75b7540a16ad71152a [file] [log] [blame]
Scott James Remnant4dcd73f2013-07-22 15:00:24 -07001# 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
Scott James Remnantda9f43c2013-08-07 17:53:14 -07005import base64
6import json
7
Scott James Remnant4dcd73f2013-07-22 15:00:24 -07008from autotest_lib.client.cros import constants
Christopher Wiley6b1d9e72014-12-13 18:07:41 -08009from autotest_lib.server import autotest
10from autotest_lib.server import hosts
11from autotest_lib.server.cros import dnsname_mangler
Scott James Remnant4dcd73f2013-07-22 15:00:24 -070012
13
14class BluetoothTester(object):
Scott James Remnant1c72d7a2013-07-29 15:00:04 -070015 """BluetoothTester is a thin layer of logic over a remote tester.
16
17 The Autotest host object representing the remote tester, passed to this
18 class on initialization, can be accessed from its host property.
19
20 """
21
Scott James Remnant4dcd73f2013-07-22 15:00:24 -070022
23 XMLRPC_BRINGUP_TIMEOUT_SECONDS = 60
24
Scott James Remnant4dcd73f2013-07-22 15:00:24 -070025 def __init__(self, tester_host):
26 """Construct a BluetoothTester.
27
Scott James Remnant1c72d7a2013-07-29 15:00:04 -070028 @param tester_host: host object representing a remote host.
Scott James Remnant4dcd73f2013-07-22 15:00:24 -070029
30 """
Scott James Remnant1c72d7a2013-07-29 15:00:04 -070031 self.host = tester_host
Scott James Remnant4dcd73f2013-07-22 15:00:24 -070032 # Make sure the client library is on the device so that the proxy code
33 # is there when we try to call it.
34 client_at = autotest.Autotest(self.host)
35 client_at.install()
36 # Start up the XML-RPC proxy on the tester.
37 self._proxy = self.host.xmlrpc_connect(
38 constants.BLUETOOTH_TESTER_XMLRPC_SERVER_COMMAND,
39 constants.BLUETOOTH_TESTER_XMLRPC_SERVER_PORT,
40 command_name=
41 constants.BLUETOOTH_TESTER_XMLRPC_SERVER_CLEANUP_PATTERN,
42 ready_test_name=
43 constants.BLUETOOTH_TESTER_XMLRPC_SERVER_READY_METHOD,
44 timeout_seconds=self.XMLRPC_BRINGUP_TIMEOUT_SECONDS)
45
Scott James Remnant1c72d7a2013-07-29 15:00:04 -070046
Scott James Remnantda9f43c2013-08-07 17:53:14 -070047 def setup(self, profile):
48 """Set up the tester with the given profile.
49
50 @param profile: Profile to use for this test, valid values are:
51 computer - a standard computer profile
52
53 @return True on success, False otherwise.
54
55 """
56 return self._proxy.setup(profile)
57
58
Scott James Remnantaec4edd2013-08-26 18:47:11 -070059 def set_discoverable(self, discoverable, timeout=0):
60 """Set the discoverable state of the controller.
61
62 @param discoverable: Whether controller should be discoverable.
63 @param timeout: Timeout in seconds before disabling discovery again,
64 ignored when discoverable is False, must not be zero when
65 discoverable is True.
66
67 @return True on success, False otherwise.
68
69 """
70 return self._proxy.set_discoverable(discoverable, timeout)
71
72
73 def read_info(self):
74 """Read the adapter information from the Kernel.
75
76 @return the information as a JSON-encoded tuple of:
77 ( address, bluetooth_version, manufacturer_id,
78 supported_settings, current_settings, class_of_device,
79 name, short_name )
80
81 """
82 return json.loads(self._proxy.read_info())
83
84
Scott James Remnante686dcc2014-12-05 17:14:08 -080085 def set_advertising(self, advertising):
86 """Set the whether the controller is advertising via LE.
87
88 @param advertising: Whether controller should advertise via LE.
89
90 @return True on success, False otherwise.
91
92 """
93 return self._proxy.set_advertising(advertising)
94
95
Scott James Remnantda9f43c2013-08-07 17:53:14 -070096 def discover_devices(self, br_edr=True, le_public=True, le_random=True):
97 """Discover remote devices.
98
99 Activates device discovery and collects the set of devices found,
100 returning them as a list.
101
102 @param br_edr: Whether to detect BR/EDR devices.
103 @param le_public: Whether to detect LE Public Address devices.
104 @param le_random: Whether to detect LE Random Address devices.
105
106 @return List of devices found as tuples with the format
107 (address, address_type, rssi, flags, base64-encoded eirdata),
108 or False if discovery could not be started.
109
110 """
111 devices = self._proxy.discover_devices(br_edr, le_public, le_random)
112 if devices == False:
113 return False
114
115 return (
116 (address, address_type, rssi, flags,
117 base64.decodestring(eirdata))
118 for address, address_type, rssi, flags, eirdata
119 in json.loads(devices)
120 )
121
122
Scott James Remnant4dcd73f2013-07-22 15:00:24 -0700123 def close(self):
124 """Tear down state associated with the client."""
125 # This kills the RPC server.
Scott James Remnant1c72d7a2013-07-29 15:00:04 -0700126 self.host.close()
Scott James Remnant1ca2e0e2013-07-31 16:49:07 -0700127
128
Artem Rakhov448d52c2013-12-03 16:38:36 -0800129 def connect(self, address):
130 """Connect to device with the given address
131
132 @param address: Bluetooth address.
133
134 """
135 self._proxy.connect(address)
136
137
Artem Rakhovba130382014-02-26 17:39:57 -0800138 def service_search_request(self, uuids, max_rec_cnt, preferred_size=32,
Artem Rakhovf42dc832014-03-03 12:19:13 -0800139 forced_pdu_size=None, invalid_request=False):
Artem Rakhov448d52c2013-12-03 16:38:36 -0800140 """Send a Service Search Request
141
Artem Rakhovba130382014-02-26 17:39:57 -0800142 @param uuids: List of UUIDs (as integers) to look for.
Artem Rakhov448d52c2013-12-03 16:38:36 -0800143 @param max_rec_cnt: Maximum count of returned service records.
Artem Rakhovca443b52014-01-10 17:18:24 -0800144 @param preferred_size: Preffered size of UUIDs in bits (16, 32, or 128).
Artem Rakhovba130382014-02-26 17:39:57 -0800145 @param forced_pdu_size: Use certain PDU size parameter instead of
146 calculating actual length of sequence.
Artem Rakhovf42dc832014-03-03 12:19:13 -0800147 @param invalid_request: Whether to send request with intentionally
148 invalid syntax for testing purposes (bool flag).
Artem Rakhov448d52c2013-12-03 16:38:36 -0800149
Artem Rakhovba130382014-02-26 17:39:57 -0800150 @return list of found services' service record handles or Error Code
Artem Rakhov448d52c2013-12-03 16:38:36 -0800151
152 """
Artem Rakhovca443b52014-01-10 17:18:24 -0800153 return self._proxy.service_search_request(uuids, max_rec_cnt,
Artem Rakhovba130382014-02-26 17:39:57 -0800154 preferred_size,
Artem Rakhovf42dc832014-03-03 12:19:13 -0800155 forced_pdu_size,
156 invalid_request)
Artem Rakhov448d52c2013-12-03 16:38:36 -0800157
158
Artem Rakhovaf4e4a62014-06-11 20:33:50 -0700159 def service_attribute_request(self, handle, max_attr_byte_count, attr_ids,
160 forced_pdu_size=None, invalid_request=None):
Artem Rakhovebf3df32014-04-01 14:52:25 -0700161 """Send a Service Attribute Request
162
163 @param handle: service record from which attribute values are to be
164 retrieved.
165 @param max_attr_byte_count: maximum number of bytes of attribute data to
166 be returned in the response to this request.
167 @param attr_ids: a list, where each element is either an attribute ID
168 or a range of attribute IDs.
Artem Rakhovaf4e4a62014-06-11 20:33:50 -0700169 @param forced_pdu_size: Use certain PDU size parameter instead of
170 calculating actual length of sequence.
171 @param invalid_request: Whether to send request with intentionally
172 invalid syntax for testing purposes (string with raw request).
Artem Rakhovebf3df32014-04-01 14:52:25 -0700173
174 @return list of found attributes IDs and their values or Error Code
175
176 """
177 return self._proxy.service_attribute_request(handle,
178 max_attr_byte_count,
Artem Rakhovaf4e4a62014-06-11 20:33:50 -0700179 attr_ids,
180 forced_pdu_size,
181 invalid_request)
Artem Rakhovebf3df32014-04-01 14:52:25 -0700182
183
Artem Rakhovf53eeec2014-09-24 21:15:58 -0700184 def service_search_attribute_request(self, uuids, max_attr_byte_count,
Artem Rakhovef5a4582014-10-29 16:02:55 -0700185 attr_ids, preferred_size=32,
186 forced_pdu_size=None,
187 invalid_request=None):
Artem Rakhovf53eeec2014-09-24 21:15:58 -0700188 """Send a Service Search Attribute Request
189
190 @param uuids: list of UUIDs (as integers) to look for.
191 @param max_attr_byte_count: maximum number of bytes of attribute data to
192 be returned in the response to this request.
193 @param attr_ids: a list, where each element is either an attribute ID
194 or a range of attribute IDs.
195 @param preferred_size: Preffered size of UUIDs in bits (16, 32, or 128).
Artem Rakhovef5a4582014-10-29 16:02:55 -0700196 @param forced_pdu_size: Use certain PDU size parameter instead of
197 calculating actual length of sequence.
198 @param invalid_request: Whether to send request with intentionally
199 invalid syntax for testing purposes (string to be prepended
200 to correct request).
Artem Rakhovf53eeec2014-09-24 21:15:58 -0700201
202 @return list of found attributes IDs and their values or Error Code
203
204 """
205 return self._proxy.service_search_attribute_request(uuids,
206 max_attr_byte_count,
207 attr_ids,
Artem Rakhovef5a4582014-10-29 16:02:55 -0700208 preferred_size,
209 forced_pdu_size,
210 invalid_request)
Artem Rakhovf53eeec2014-09-24 21:15:58 -0700211
212
Scott James Remnant25622042014-12-05 11:20:37 -0800213def create_host_from(device_host, args=None):
Scott James Remnant1ca2e0e2013-07-31 16:49:07 -0700214 """Creates a host object for the Tester associated with a DUT.
215
Scott James Remnant25622042014-12-05 11:20:37 -0800216 The IP address or the hostname can be specified in the 'tester' member of
217 the argument dictionary. When not present it is derived from the hostname
218 of the DUT by appending '-router' to the first part.
219
220 Will raise an exception if there isn't a tester for the DUT, or if the DUT
221 is specified as an IP address and thus the hostname cannot be derived.
Scott James Remnant1ca2e0e2013-07-31 16:49:07 -0700222
Scott James Remnant8d2cbf32013-11-12 11:00:25 -0800223 @param device_host: Autotest host object for the DUT.
Scott James Remnant25622042014-12-05 11:20:37 -0800224 @param args: Dictionary of arguments passed to the test.
Scott James Remnant1ca2e0e2013-07-31 16:49:07 -0700225
226 @return Autotest host object for the Tester.
227
228 """
Christopher Wiley6b1d9e72014-12-13 18:07:41 -0800229 cmdline_override = args.get('tester', None)
230 hostname = dnsname_mangler.get_tester_addr(
231 device_host.hostname,
232 cmdline_override=cmdline_override)
233 return hosts.create_host(hostname)