1#!/usr/bin/python3.4 2# 3# Copyright 2017 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import queue 18import time 19 20from acts import asserts 21from acts.test_decorators import test_tracker_info 22from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G 23from acts.test_utils.wifi import wifi_test_utils as wutils 24from acts.test_utils.wifi.rtt import rtt_const as rconsts 25from acts.test_utils.wifi.rtt import rtt_test_utils as rutils 26from acts.test_utils.wifi.rtt.RttBaseTest import RttBaseTest 27 28 29class RangeApSupporting11McTest(RttBaseTest): 30 """Test class for RTT ranging to Access Points which support IEEE 802.11mc""" 31 32 # Number of RTT iterations 33 NUM_ITER = 10 34 35 # Time gap (in seconds) between iterations 36 TIME_BETWEEN_ITERATIONS = 0 37 38 # Soft AP SSID 39 SOFT_AP_SSID = "RTT_TEST_SSID" 40 41 # Soft AP Password (irrelevant) 42 SOFT_AP_PASSWORD = "ABCDEFGH" 43 44 # Time to wait before configuration changes 45 WAIT_FOR_CONFIG_CHANGES_SEC = 1 46 47 def run_test_rtt_80211mc_supporting_aps(self, dut, accuracy_evaluation=False): 48 """Scan for APs and perform RTT only to those which support 802.11mc 49 Args: 50 dut: test device 51 accuracy_evaluation: False - only evaluate success rate. 52 True - evaluate both success rate and accuracy 53 default is False. 54 """ 55 rtt_supporting_aps = rutils.select_best_scan_results( 56 rutils.scan_with_rtt_support_constraint(dut, True, repeat=10), 57 select_count=2) 58 dut.log.debug("RTT Supporting APs=%s", rtt_supporting_aps) 59 events = rutils.run_ranging(dut, rtt_supporting_aps, self.NUM_ITER, 60 self.TIME_BETWEEN_ITERATIONS) 61 stats = rutils.analyze_results(events, self.rtt_reference_distance_mm, 62 self.rtt_reference_distance_margin_mm, 63 self.rtt_min_expected_rssi_dbm, 64 self.lci_reference, self.lcr_reference) 65 dut.log.debug("Stats=%s", stats) 66 67 for bssid, stat in stats.items(): 68 asserts.assert_true( 69 stat['num_no_results'] == 0, 70 "Missing (timed-out) results", 71 extras=stats) 72 asserts.assert_false( 73 stat['any_lci_mismatch'], "LCI mismatch", extras=stats) 74 asserts.assert_false( 75 stat['any_lcr_mismatch'], "LCR mismatch", extras=stats) 76 asserts.assert_false( 77 stat['invalid_num_attempted'], 78 "Invalid (0) number of attempts", 79 extras=stats) 80 asserts.assert_false( 81 stat['invalid_num_successful'], 82 "Invalid (0) number of successes", 83 extras=stats) 84 asserts.assert_equal( 85 stat['num_invalid_rssi'], 0, "Invalid RSSI", extras=stats) 86 asserts.assert_true( 87 stat['num_failures'] <= 88 self.rtt_max_failure_rate_two_sided_rtt_percentage * 89 stat['num_results'] / 100, 90 "Failure rate is too high", 91 extras=stats) 92 if accuracy_evaluation: 93 asserts.assert_true( 94 stat['num_range_out_of_margin'] <= 95 self.rtt_max_margin_exceeded_rate_two_sided_rtt_percentage * 96 stat['num_success_results'] / 100, 97 "Results exceeding error margin rate is too high", 98 extras=stats) 99 asserts.explicit_pass("RTT test done", extras=stats) 100 101 @test_tracker_info(uuid="6705270f-924b-4bef-b50a-0f0a7eb9ce52") 102 def test_rtt_80211mc_supporting_aps(self): 103 """Scan for APs and perform RTT only to those which support 802.11mc, 104 Functionality test: Only evaluate success rate.""" 105 dut = self.android_devices[0] 106 self.run_test_rtt_80211mc_supporting_aps(dut) 107 108 @test_tracker_info(uuid="56a8ca4c-b69d-436e-aa80-e86adb6f57d8") 109 def test_rtt_80211mc_supporting_aps_with_accuracy_evaluation(self): 110 """Scan for APs and perform RTT only to those which support 802.11mc, 111 Performance test: evaluate success rate and accuracy.""" 112 dut = self.android_devices[0] 113 self.run_test_rtt_80211mc_supporting_aps(dut, accuracy_evaluation=True) 114 115 @test_tracker_info(uuid="eb3fc9f5-ae15-47f5-8468-697bb9aa9ddf") 116 def test_rtt_in_and_after_softap_mode(self): 117 """Verify behavior when a SoftAP is enabled and then disabled on the 118 device: 119 120 - SAP Enabled: depending on device characteristics RTT may succeed or 121 fail. 122 - SAP Disabled: RTT must now succeed. 123 """ 124 supp_required_params = ("dbs_supported_models", ) 125 self.unpack_userparams(supp_required_params) 126 127 dut = self.android_devices[0] 128 129 rtt_supporting_aps = rutils.select_best_scan_results( 130 rutils.scan_with_rtt_support_constraint(dut, True, repeat=10), 131 select_count=1) 132 dut.log.debug("RTT Supporting APs=%s", rtt_supporting_aps) 133 134 # phase 1 (pre-SAP) 135 events = rutils.run_ranging(dut, rtt_supporting_aps, self.NUM_ITER, 136 self.TIME_BETWEEN_ITERATIONS) 137 stats = rutils.analyze_results(events, self.rtt_reference_distance_mm, 138 self.rtt_reference_distance_margin_mm, 139 self.rtt_min_expected_rssi_dbm, 140 self.lci_reference, self.lcr_reference) 141 dut.log.debug("Stats Phase 1 (pre-SAP)=%s", stats) 142 143 for bssid, stat in stats.items(): 144 asserts.assert_true( 145 stat['num_no_results'] == 0, 146 "Phase 1 (pre-SAP) missing (timed-out) results", 147 extras=stats) 148 149 # phase 2 (SAP) 150 wutils.start_wifi_tethering( 151 dut, 152 self.SOFT_AP_SSID, 153 self.SOFT_AP_PASSWORD, 154 band=WIFI_CONFIG_APBAND_5G, 155 hidden=False) 156 time.sleep(self.WAIT_FOR_CONFIG_CHANGES_SEC) 157 158 if dut.model not in self.dbs_supported_models: 159 rutils.wait_for_event(dut, rconsts.BROADCAST_WIFI_RTT_NOT_AVAILABLE) 160 asserts.assert_false(dut.droid.wifiIsRttAvailable(), 161 "RTT is available") 162 163 events = rutils.run_ranging(dut, rtt_supporting_aps, self.NUM_ITER, 164 self.TIME_BETWEEN_ITERATIONS) 165 stats = rutils.analyze_results(events, self.rtt_reference_distance_mm, 166 self.rtt_reference_distance_margin_mm, 167 self.rtt_min_expected_rssi_dbm, 168 self.lci_reference, self.lcr_reference) 169 dut.log.debug("Stats Phase 2 (SAP)=%s", stats) 170 171 for bssid, stat in stats.items(): 172 if dut.model in self.dbs_supported_models: 173 asserts.assert_true( 174 stat['num_no_results'] == 0, 175 "Phase 2 (SAP) missing (timed-out) results", 176 extras=stats) 177 else: 178 asserts.assert_true( 179 stat['num_success_results'] == 0, 180 "Phase 2 (SAP) valid results - but unexpected in SAP!?", 181 extras=stats) 182 183 # phase 3 (post-SAP) 184 185 # enabling Wi-Fi first: on some devices this will also disable SAP 186 # (that's the scenario we're primarily testing). Additionally, 187 # explicitly disable SAP (which may be a NOP on some devices). 188 wutils.wifi_toggle_state(dut, True) 189 time.sleep(self.WAIT_FOR_CONFIG_CHANGES_SEC) 190 wutils.stop_wifi_tethering(dut) 191 192 if dut.model not in self.dbs_supported_models: 193 rutils.wait_for_event(dut, rconsts.BROADCAST_WIFI_RTT_AVAILABLE) 194 asserts.assert_true(dut.droid.wifiIsRttAvailable(), 195 "RTT is not available") 196 197 events = rutils.run_ranging(dut, rtt_supporting_aps, self.NUM_ITER, 198 self.TIME_BETWEEN_ITERATIONS) 199 stats = rutils.analyze_results(events, self.rtt_reference_distance_mm, 200 self.rtt_reference_distance_margin_mm, 201 self.rtt_min_expected_rssi_dbm, 202 self.lci_reference, self.lcr_reference) 203 dut.log.debug("Stats Phase 3 (post-SAP)=%s", stats) 204 205 for bssid, stat in stats.items(): 206 asserts.assert_true( 207 stat['num_no_results'] == 0, 208 "Phase 3 (post-SAP) missing (timed-out) results", 209 extras=stats) 210 211 ######################################################################### 212 # 213 # LEGACY API test code 214 # 215 ######################################################################### 216 217 @test_tracker_info(uuid="18be9737-2f03-4e35-9a23-f722dea7b82d") 218 def test_legacy_rtt_80211mc_supporting_aps(self): 219 """Scan for APs and perform RTT only to those which support 802.11mc - using 220 the LEGACY API! 221 """ 222 dut = self.android_devices[0] 223 rtt_supporting_aps = rutils.select_best_scan_results( 224 rutils.scan_with_rtt_support_constraint(dut, True, repeat=10), 225 select_count=2) 226 dut.log.debug("RTT Supporting APs=%s", rtt_supporting_aps) 227 228 rtt_configs = [] 229 for ap in rtt_supporting_aps: 230 rtt_configs.append(self.rtt_config_from_scan_result(ap)) 231 dut.log.debug("RTT configs=%s", rtt_configs) 232 233 results = [] 234 num_missing = 0 235 num_failed_aborted = 0 236 for i in range(self.NUM_ITER): 237 idx = dut.droid.wifiRttStartRanging(rtt_configs) 238 event = None 239 try: 240 events = dut.ed.pop_events("WifiRttRanging%d" % idx, 30) 241 dut.log.debug("Event=%s", events) 242 for event in events: 243 if rconsts.EVENT_CB_RANGING_KEY_RESULTS in event["data"]: 244 results.append(event["data"][ 245 rconsts.EVENT_CB_RANGING_KEY_RESULTS]) 246 else: 247 self.log.info("RTT failed/aborted - %s", event) 248 results.append([]) 249 num_failed_aborted = num_failed_aborted + 1 250 except queue.Empty: 251 self.log.debug("Waiting for RTT event timed out.") 252 results.append([]) 253 num_missing = num_missing + 1 254 255 # basic error checking: 256 # 1. no missing 257 # 2. no full failed/aborted (i.e. operation not even tried) 258 # 3. overall (all BSSIDs) success rate > threshold 259 asserts.assert_equal( 260 num_missing, 261 0, 262 "Missing results (timeout waiting for event)", 263 extras={"data": results}) 264 asserts.assert_equal( 265 num_failed_aborted, 266 0, 267 "Failed or aborted operations (not tried)", 268 extras={"data": results}) 269 270 num_results = 0 271 num_errors = 0 272 for result_group in results: 273 num_results = num_results + len(result_group) 274 for result in result_group: 275 if result["status"] != 0: 276 num_errors = num_errors + 1 277 278 extras = [ 279 results, { 280 "num_results": num_results, 281 "num_errors": num_errors 282 } 283 ] 284 asserts.assert_true( 285 num_errors <= self.rtt_max_failure_rate_two_sided_rtt_percentage * 286 num_results / 100, 287 "Failure rate is too high", 288 extras={"data": extras}) 289 asserts.explicit_pass("RTT test done", extras={"data": extras}) 290 291 def rtt_config_from_scan_result(self, scan_result): 292 """Creates an Rtt configuration based on the scan result of a network. 293 """ 294 WifiEnums = wutils.WifiEnums 295 ScanResult = WifiEnums.ScanResult 296 RttParam = WifiEnums.RttParam 297 RttBW = WifiEnums.RttBW 298 RttPreamble = WifiEnums.RttPreamble 299 RttType = WifiEnums.RttType 300 301 scan_result_channel_width_to_rtt = { 302 ScanResult.CHANNEL_WIDTH_20MHZ: RttBW.BW_20_SUPPORT, 303 ScanResult.CHANNEL_WIDTH_40MHZ: RttBW.BW_40_SUPPORT, 304 ScanResult.CHANNEL_WIDTH_80MHZ: RttBW.BW_80_SUPPORT, 305 ScanResult.CHANNEL_WIDTH_160MHZ: RttBW.BW_160_SUPPORT, 306 ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: RttBW.BW_160_SUPPORT 307 } 308 p = {} 309 freq = scan_result[RttParam.frequency] 310 p[RttParam.frequency] = freq 311 p[RttParam.BSSID] = scan_result[WifiEnums.BSSID_KEY] 312 if freq > 5000: 313 p[RttParam.preamble] = RttPreamble.PREAMBLE_VHT 314 else: 315 p[RttParam.preamble] = RttPreamble.PREAMBLE_HT 316 cf0 = scan_result[RttParam.center_freq0] 317 if cf0 > 0: 318 p[RttParam.center_freq0] = cf0 319 cf1 = scan_result[RttParam.center_freq1] 320 if cf1 > 0: 321 p[RttParam.center_freq1] = cf1 322 cw = scan_result["channelWidth"] 323 p[RttParam.channel_width] = cw 324 p[RttParam.bandwidth] = scan_result_channel_width_to_rtt[cw] 325 if scan_result["is80211McRTTResponder"]: 326 p[RttParam.request_type] = RttType.TYPE_TWO_SIDED 327 else: 328 p[RttParam.request_type] = RttType.TYPE_ONE_SIDED 329 return p 330