blob: be213bccc83abb7c3e10d9a3f55eb50cc6fe5ee7 [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 Rakhov275ecaf2015-01-07 17:46:14 -0800153 return json.loads(
154 self._proxy.service_search_request(
155 uuids, max_rec_cnt, preferred_size, forced_pdu_size,
156 invalid_request)
157 )
Artem Rakhov448d52c2013-12-03 16:38:36 -0800158
159
Artem Rakhovaf4e4a62014-06-11 20:33:50 -0700160 def service_attribute_request(self, handle, max_attr_byte_count, attr_ids,
161 forced_pdu_size=None, invalid_request=None):
Artem Rakhovebf3df32014-04-01 14:52:25 -0700162 """Send a Service Attribute Request
163
164 @param handle: service record from which attribute values are to be
165 retrieved.
166 @param max_attr_byte_count: maximum number of bytes of attribute data to
167 be returned in the response to this request.
168 @param attr_ids: a list, where each element is either an attribute ID
169 or a range of attribute IDs.
Artem Rakhovaf4e4a62014-06-11 20:33:50 -0700170 @param forced_pdu_size: Use certain PDU size parameter instead of
171 calculating actual length of sequence.
172 @param invalid_request: Whether to send request with intentionally
173 invalid syntax for testing purposes (string with raw request).
Artem Rakhovebf3df32014-04-01 14:52:25 -0700174
175 @return list of found attributes IDs and their values or Error Code
176
177 """
Artem Rakhov275ecaf2015-01-07 17:46:14 -0800178 return json.loads(
179 self._proxy.service_attribute_request(
180 handle, max_attr_byte_count, attr_ids, forced_pdu_size,
181 invalid_request)
182 )
Artem Rakhovebf3df32014-04-01 14:52:25 -0700183
184
Artem Rakhovf53eeec2014-09-24 21:15:58 -0700185 def service_search_attribute_request(self, uuids, max_attr_byte_count,
Artem Rakhovef5a4582014-10-29 16:02:55 -0700186 attr_ids, preferred_size=32,
187 forced_pdu_size=None,
188 invalid_request=None):
Artem Rakhovf53eeec2014-09-24 21:15:58 -0700189 """Send a Service Search Attribute Request
190
191 @param uuids: list of UUIDs (as integers) to look for.
192 @param max_attr_byte_count: maximum number of bytes of attribute data to
193 be returned in the response to this request.
194 @param attr_ids: a list, where each element is either an attribute ID
195 or a range of attribute IDs.
196 @param preferred_size: Preffered size of UUIDs in bits (16, 32, or 128).
Artem Rakhovef5a4582014-10-29 16:02:55 -0700197 @param forced_pdu_size: Use certain PDU size parameter instead of
198 calculating actual length of sequence.
199 @param invalid_request: Whether to send request with intentionally
200 invalid syntax for testing purposes (string to be prepended
201 to correct request).
Artem Rakhovf53eeec2014-09-24 21:15:58 -0700202
203 @return list of found attributes IDs and their values or Error Code
204
205 """
Artem Rakhov275ecaf2015-01-07 17:46:14 -0800206 return json.loads(
207 self._proxy.service_search_attribute_request(
208 uuids, max_attr_byte_count, attr_ids, preferred_size,
209 forced_pdu_size, invalid_request)
210 )
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)