1#!/usr/bin/env python3.4 2# 3# Copyright 2018 - 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 collections 18import json 19import logging 20import math 21import os 22import statistics 23from acts import asserts 24from acts import base_test 25from acts import utils 26from acts.controllers import iperf_server as ipf 27from acts.metrics.loggers.blackbox import BlackboxMetricLogger 28from acts.test_decorators import test_tracker_info 29from acts.test_utils.wifi import wifi_performance_test_utils as wputils 30from acts.test_utils.wifi import wifi_retail_ap as retail_ap 31from acts.test_utils.wifi import wifi_test_utils as wutils 32from concurrent.futures import ThreadPoolExecutor 33 34SHORT_SLEEP = 1 35MED_SLEEP = 6 36CONST_3dB = 3.01029995664 37RSSI_ERROR_VAL = float("nan") 38 39 40class WifiRssiTest(base_test.BaseTestClass): 41 """Class to test WiFi RSSI reporting. 42 43 This class tests RSSI reporting on android devices. The class tests RSSI 44 accuracy by checking RSSI over a large attenuation range, checks for RSSI 45 stability over time when attenuation is fixed, and checks that RSSI quickly 46 and reacts to changes attenuation by checking RSSI trajectories over 47 configurable attenuation waveforms.For an example config file to run this 48 test class see example_connectivity_performance_ap_sta.json. 49 """ 50 51 def __init__(self, controllers): 52 base_test.BaseTestClass.__init__(self, controllers) 53 test_metrics = [ 54 "signal_poll_rssi_shift", "signal_poll_avg_rssi_shift", 55 "scan_rssi_shift", "chain_0_rssi_shift", "chain_1_rssi_shift", 56 "signal_poll_rssi_error", "signal_poll_avg_rssi_error", 57 "scan_rssi_error", "chain_0_rssi_error", "chain_1_rssi_error", 58 "signal_poll_rssi_stdev", "chain_0_rssi_stdev", 59 "chain_1_rssi_stdev" 60 ] 61 for metric in test_metrics: 62 setattr( 63 self, 64 "{}_metric".format(metric), 65 BlackboxMetricLogger.for_test_case(metric_name=metric)) 66 67 def setup_class(self): 68 self.dut = self.android_devices[0] 69 req_params = [ 70 "RemoteServer", "RetailAccessPoints", "rssi_test_params", 71 "main_network", "testbed_params" 72 ] 73 self.unpack_userparams(req_params) 74 self.test_params = self.rssi_test_params 75 self.num_atten = self.attenuators[0].instrument.num_atten 76 self.iperf_server = self.iperf_servers[0] 77 self.iperf_client = self.iperf_clients[0] 78 self.access_point = retail_ap.create(self.RetailAccessPoints)[0] 79 self.log_path = os.path.join(logging.log_path, "results") 80 utils.create_dir(self.log_path) 81 self.log.info("Access Point Configuration: {}".format( 82 self.access_point.ap_settings)) 83 self.testclass_results = [] 84 85 def teardown_test(self): 86 self.iperf_server.stop() 87 88 def pass_fail_check_rssi_stability(self, postprocessed_results): 89 """Check the test result and decide if it passed or failed. 90 91 Checks the RSSI test result and fails the test if the standard 92 deviation of signal_poll_rssi is beyond the threshold defined in the 93 config file. 94 95 Args: 96 postprocessed_results: compiled arrays of RSSI measurements 97 """ 98 # Set Blackbox metric values 99 self.signal_poll_rssi_stdev_metric.metric_value = max( 100 postprocessed_results["signal_poll_rssi"]["stdev"]) 101 self.chain_0_rssi_stdev_metric.metric_value = max( 102 postprocessed_results["chain_0_rssi"]["stdev"]) 103 self.chain_1_rssi_stdev_metric.metric_value = max( 104 postprocessed_results["chain_1_rssi"]["stdev"]) 105 # Evaluate test pass/fail 106 test_failed = any([ 107 stdev > self.test_params["stdev_tolerance"] 108 for stdev in postprocessed_results["signal_poll_rssi"]["stdev"] 109 ]) 110 test_message = ( 111 "RSSI stability {0}. Standard deviation was {1} dB " 112 "(limit {2}), per chain standard deviation [{3}, {4}] dB".format( 113 "failed" * test_failed + "passed" * (not test_failed), [ 114 float("{:.2f}".format(x)) 115 for x in postprocessed_results["signal_poll_rssi"]["stdev"] 116 ], self.test_params["stdev_tolerance"], [ 117 float("{:.2f}".format(x)) 118 for x in postprocessed_results["chain_0_rssi"]["stdev"] 119 ], [ 120 float("{:.2f}".format(x)) 121 for x in postprocessed_results["chain_1_rssi"]["stdev"] 122 ])) 123 if test_failed: 124 asserts.fail(test_message) 125 asserts.explicit_pass(test_message) 126 127 def pass_fail_check_rssi_accuracy(self, postprocessed_results, 128 rssi_under_test, absolute_accuracy): 129 """Check the test result and decide if it passed or failed. 130 131 Checks the RSSI test result and compares and compute its deviation from 132 the predicted RSSI. This computation is done for all reported RSSI 133 values. The test fails if any of the RSSI values specified in 134 rssi_under_test have an average error beyond what is specified in the 135 configuration file. 136 137 Args: 138 postprocessed_results: compiled arrays of RSSI measurements 139 rssi_under_test: list of RSSIs under test, i.e., can cause test to 140 fail 141 absolute_accuracy: boolean indicating whether to look at absolute 142 RSSI accuracy, or centered RSSI accuracy. Centered accuracy is 143 computed after systematic RSSI shifts are removed. 144 """ 145 test_failed = False 146 test_message = "" 147 if absolute_accuracy: 148 error_type = "absolute" 149 else: 150 error_type = "centered" 151 152 for key, val in postprocessed_results.items(): 153 # Compute the error metrics ignoring invalid RSSI readings 154 # If all readings invalid, set error to RSSI_ERROR_VAL 155 if "rssi" in key and "predicted" not in key: 156 filtered_error = [x for x in val["error"] if not math.isnan(x)] 157 if filtered_error: 158 avg_shift = statistics.mean(filtered_error) 159 if absolute_accuracy: 160 avg_error = statistics.mean( 161 [abs(x) for x in filtered_error]) 162 else: 163 avg_error = statistics.mean( 164 [abs(x - avg_shift) for x in filtered_error]) 165 else: 166 avg_error = RSSI_ERROR_VAL 167 avg_shift = RSSI_ERROR_VAL 168 # Set Blackbox metric values 169 setattr( 170 getattr(self, "{}_error_metric".format(key)), 171 "metric_value", avg_error) 172 setattr( 173 getattr(self, "{}_shift_metric".format(key)), 174 "metric_value", avg_shift) 175 # Evaluate test pass/fail 176 rssi_failure = (avg_error > self.test_params["abs_tolerance"] 177 ) or math.isnan(avg_error) 178 if rssi_failure and key in rssi_under_test: 179 test_message = test_message + ( 180 "{} failed ({} error = {:.2f} dB, " 181 "shift = {:.2f} dB)\n").format(key, error_type, 182 avg_error, avg_shift) 183 test_failed = True 184 elif rssi_failure: 185 test_message = test_message + ( 186 "{} failed (ignored) ({} error = {:.2f} dB, " 187 "shift = {:.2f} dB)\n").format(key, error_type, 188 avg_error, avg_shift) 189 else: 190 test_message = test_message + ( 191 "{} passed ({} error = {:.2f} dB, " 192 "shift = {:.2f} dB)\n").format(key, error_type, 193 avg_error, avg_shift) 194 if test_failed: 195 asserts.fail(test_message) 196 asserts.explicit_pass(test_message) 197 198 def post_process_rssi_sweep(self, rssi_result): 199 """Postprocesses and saves JSON formatted results. 200 201 Args: 202 rssi_result: dict containing attenuation, rssi and other meta 203 data 204 Returns: 205 postprocessed_results: compiled arrays of RSSI data used in 206 pass/fail check 207 """ 208 # Save output as text file 209 results_file_path = "{}/{}.json".format(self.log_path, 210 self.current_test_name) 211 with open(results_file_path, 'w') as results_file: 212 json.dump(rssi_result, results_file, indent=4) 213 # Compile results into arrays of RSSIs suitable for plotting 214 # yapf: disable 215 postprocessed_results = collections.OrderedDict( 216 [("signal_poll_rssi", {}), 217 ("signal_poll_avg_rssi", {}), 218 ("scan_rssi", {}), 219 ("chain_0_rssi", {}), 220 ("chain_1_rssi", {}), 221 ("total_attenuation", []), 222 ("predicted_rssi", [])]) 223 # yapf: enable 224 for key, val in postprocessed_results.items(): 225 if "scan_rssi" in key: 226 postprocessed_results[key]["data"] = [ 227 x for data_point in rssi_result["rssi_result"] for x in 228 data_point[key][rssi_result["connected_bssid"]]["data"] 229 ] 230 postprocessed_results[key]["mean"] = [ 231 x[key][rssi_result["connected_bssid"]]["mean"] 232 for x in rssi_result["rssi_result"] 233 ] 234 postprocessed_results[key]["stdev"] = [ 235 x[key][rssi_result["connected_bssid"]]["stdev"] 236 for x in rssi_result["rssi_result"] 237 ] 238 elif "predicted_rssi" in key: 239 postprocessed_results["total_attenuation"] = [ 240 att + rssi_result["fixed_attenuation"] + 241 rssi_result["dut_front_end_loss"] 242 for att in rssi_result["attenuation"] 243 ] 244 postprocessed_results["predicted_rssi"] = [ 245 rssi_result["ap_tx_power"] - att 246 for att in postprocessed_results["total_attenuation"] 247 ] 248 elif "rssi" in key: 249 postprocessed_results[key]["data"] = [ 250 x for data_point in rssi_result["rssi_result"] 251 for x in data_point[key]["data"] 252 ] 253 postprocessed_results[key]["mean"] = [ 254 x[key]["mean"] for x in rssi_result["rssi_result"] 255 ] 256 postprocessed_results[key]["stdev"] = [ 257 x[key]["stdev"] for x in rssi_result["rssi_result"] 258 ] 259 # Compute RSSI errors 260 for key, val in postprocessed_results.items(): 261 if "chain" in key: 262 postprocessed_results[key]["error"] = [ 263 postprocessed_results[key]["mean"][idx] + CONST_3dB - 264 postprocessed_results["predicted_rssi"][idx] 265 for idx in range( 266 len(postprocessed_results["predicted_rssi"])) 267 ] 268 elif "rssi" in key and "predicted" not in key: 269 postprocessed_results[key]["error"] = [ 270 postprocessed_results[key]["mean"][idx] - 271 postprocessed_results["predicted_rssi"][idx] 272 for idx in range( 273 len(postprocessed_results["predicted_rssi"])) 274 ] 275 return postprocessed_results 276 277 def plot_rssi_vs_attenuation(self, postprocessed_results): 278 """Function to plot RSSI vs attenuation sweeps 279 280 Args: 281 postprocessed_results: compiled arrays of RSSI data. 282 """ 283 data_sets = [[ 284 postprocessed_results["total_attenuation"], 285 postprocessed_results["total_attenuation"], 286 postprocessed_results["total_attenuation"], 287 postprocessed_results["total_attenuation"], 288 postprocessed_results["total_attenuation"], 289 postprocessed_results["total_attenuation"] 290 ], [ 291 postprocessed_results["signal_poll_rssi"]["mean"], 292 postprocessed_results["signal_poll_avg_rssi"]["mean"], 293 postprocessed_results["scan_rssi"]["mean"], 294 postprocessed_results["chain_0_rssi"]["mean"], 295 postprocessed_results["chain_1_rssi"]["mean"], 296 postprocessed_results["predicted_rssi"] 297 ]] 298 legends = [ 299 "Signal Poll RSSI", "Signal Poll AVG_RSSI", "Scan RSSI", 300 "Chain 0 RSSI", "Chain 1 RSSI", "Predicted RSSI" 301 ] 302 fig_property = { 303 "title": self.current_test_name, 304 "x_label": 'Attenuation (dB)', 305 "y_label": 'RSSI (dBm)', 306 "linewidth": 3, 307 "markersize": 10 308 } 309 output_file_path = "{}/{}.html".format(self.log_path, 310 self.current_test_name) 311 wputils.bokeh_plot( 312 data_sets, 313 legends, 314 fig_property, 315 shaded_region=None, 316 output_file_path=output_file_path) 317 318 def plot_rssi_vs_time(self, rssi_result, postprocessed_results, 319 center_curves): 320 """Function to plot RSSI vs time. 321 322 Args: 323 rssi_result: dict containing raw RSSI data 324 postprocessed_results: compiled arrays of RSSI data 325 center_curvers: boolean indicating whether to shift curves to align 326 them with predicted RSSIs 327 """ 328 x_data = [] 329 y_data = [] 330 legends = [] 331 # yapf: disable 332 rssi_time_series = collections.OrderedDict( 333 [("signal_poll_rssi", []), 334 ("signal_poll_avg_rssi", []), 335 ("scan_rssi", []), 336 ("chain_0_rssi", []), 337 ("chain_1_rssi", []), 338 ("predicted_rssi", [])]) 339 # yapf: enable 340 for key, val in rssi_time_series.items(): 341 if "predicted_rssi" in key: 342 rssi_time_series[key] = [ 343 x for x in postprocessed_results[key] for copies in range( 344 len(rssi_result["rssi_result"][0]["signal_poll_rssi"][ 345 "data"])) 346 ] 347 elif "rssi" in key: 348 if center_curves: 349 filtered_error = [ 350 x for x in postprocessed_results[key]["error"] 351 if not math.isnan(x) 352 ] 353 if filtered_error: 354 avg_shift = statistics.mean(filtered_error) 355 else: 356 avg_shift = 0 357 rssi_time_series[key] = [ 358 x - avg_shift 359 for x in postprocessed_results[key]["data"] 360 ] 361 else: 362 rssi_time_series[key] = postprocessed_results[key]["data"] 363 time_vec = [ 364 self.test_params["polling_frequency"] * x 365 for x in range(len(rssi_time_series[key])) 366 ] 367 if len(rssi_time_series[key]) > 0: 368 x_data.append(time_vec) 369 y_data.append(rssi_time_series[key]) 370 legends.append(key) 371 data_sets = [x_data, y_data] 372 fig_property = { 373 "title": self.current_test_name, 374 "x_label": 'Time (s)', 375 "y_label": center_curves * 'Centered' + 'RSSI (dBm)', 376 "linewidth": 3, 377 "markersize": 0 378 } 379 output_file_path = "{}/{}.html".format(self.log_path, 380 self.current_test_name) 381 wputils.bokeh_plot( 382 data_sets, 383 legends, 384 fig_property, 385 shaded_region=None, 386 output_file_path=output_file_path) 387 388 def rssi_test(self, iperf_traffic, connected_measurements, 389 scan_measurements, bssids, polling_frequency, 390 first_measurement_delay): 391 """Test function to run RSSI tests. 392 393 The function runs an RSSI test in the current device/AP configuration. 394 Function is called from another wrapper function that sets up the 395 testbed for the RvR test 396 397 Args: 398 iperf_traffic: boolean specifying whether or not to run traffic 399 during RSSI tests 400 connected_measurements: number of RSSI measurements to make for the 401 connected AP per attenuation point 402 scan_measurements: number of scans and scan RSSIs to make per 403 attenuation point 404 bssids: list of BSSIDs to monitor in scans 405 polling_frequency: time between connected AP measurements 406 Returns: 407 rssi_result: dict containing rssi_result and meta data 408 """ 409 self.log.info("Start running RSSI test.") 410 rssi_result = [] 411 # Start iperf traffic if required by test 412 if self.iperf_traffic: 413 self.iperf_server.start(tag=0) 414 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb): 415 iperf_server_address = self.dut_ip 416 else: 417 iperf_server_address = self.testbed_params[ 418 "iperf_server_address"] 419 executor = ThreadPoolExecutor(max_workers=1) 420 thread_future = executor.submit( 421 self.iperf_client.start, iperf_server_address, self.iperf_args, 422 0, self.iperf_timeout + SHORT_SLEEP) 423 executor.shutdown(wait=False) 424 for atten in self.rssi_atten_range: 425 # Set Attenuation 426 self.log.info("Setting attenuation to {} dB".format(atten)) 427 for attenuator in self.attenuators: 428 attenuator.set_atten(atten) 429 current_rssi = collections.OrderedDict() 430 current_rssi = wputils.get_connected_rssi( 431 self.dut, connected_measurements, polling_frequency, 432 first_measurement_delay) 433 current_rssi["scan_rssi"] = wputils.get_scan_rssi( 434 self.dut, bssids, scan_measurements) 435 rssi_result.append(current_rssi) 436 self.log.info("Connected RSSI at {0:.2f} dB is {1:.2f} dB".format( 437 atten, current_rssi["signal_poll_rssi"]["mean"])) 438 # Stop iperf traffic if needed 439 for attenuator in self.attenuators: 440 attenuator.set_atten(0) 441 if self.iperf_traffic: 442 thread_future.result() 443 self.iperf_server.stop() 444 return rssi_result 445 446 def setup_ap(self): 447 """Function that gets devices ready for the test.""" 448 band = self.access_point.band_lookup_by_channel(self.channel) 449 if "2G" in band: 450 frequency = wutils.WifiEnums.channel_2G_to_freq[self.channel] 451 else: 452 frequency = wutils.WifiEnums.channel_5G_to_freq[self.channel] 453 if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES: 454 self.access_point.set_region(self.testbed_params["DFS_region"]) 455 else: 456 self.access_point.set_region(self.testbed_params["default_region"]) 457 self.access_point.set_channel(band, self.channel) 458 self.access_point.set_bandwidth(band, self.mode) 459 self.log.info("Access Point Configuration: {}".format( 460 self.access_point.ap_settings)) 461 462 def setup_dut(self): 463 """Sets up the DUT in the configuration required by the test.""" 464 band = self.access_point.band_lookup_by_channel(self.channel) 465 wutils.wifi_toggle_state(self.dut, True) 466 wutils.reset_wifi(self.dut) 467 self.main_network[band]["channel"] = self.channel 468 self.dut.droid.wifiSetCountryCode(self.test_params["country_code"]) 469 wutils.wifi_connect(self.dut, self.main_network[band], num_of_tries=5) 470 self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0] 471 472 def rssi_test_func(self, iperf_traffic, connected_measurements, 473 scan_measurements, bssids, polling_frequency, 474 first_measurement_delay): 475 """Main function to test RSSI. 476 477 The function sets up the AP in the correct channel and mode 478 configuration and called rssi_test to sweep attenuation and measure 479 RSSI 480 481 Returns: 482 rssi_result: dict containing rssi_results and meta data 483 """ 484 #Initialize test settings 485 rssi_result = collections.OrderedDict() 486 # Configure AP 487 self.setup_ap() 488 # Initialize attenuators 489 for attenuator in self.attenuators: 490 attenuator.set_atten(self.rssi_atten_range[0]) 491 # Connect DUT to Network 492 self.setup_dut() 493 # Run test and log result 494 band = self.access_point.band_lookup_by_channel(self.channel) 495 rssi_result["test_name"] = self.current_test_name 496 rssi_result["ap_settings"] = self.access_point.ap_settings.copy() 497 rssi_result["attenuation"] = list(self.rssi_atten_range) 498 rssi_result["connected_bssid"] = self.main_network[band]["BSSID"] 499 if "{}_{}".format(str(self.channel), 500 self.mode) in self.testbed_params["ap_tx_power"]: 501 rssi_result["ap_tx_power"] = self.testbed_params["ap_tx_power"][ 502 "{}_{}".format(str(self.channel), self.mode)] 503 else: 504 rssi_result["ap_tx_power"] = self.testbed_params["ap_tx_power"][ 505 str(self.channel)] 506 rssi_result["fixed_attenuation"] = self.testbed_params[ 507 "fixed_attenuation"][str(self.channel)] 508 rssi_result["dut_front_end_loss"] = self.testbed_params[ 509 "dut_front_end_loss"][str(self.channel)] 510 rssi_result["rssi_result"] = self.rssi_test( 511 iperf_traffic, connected_measurements, scan_measurements, bssids, 512 polling_frequency, first_measurement_delay) 513 self.testclass_results.append(rssi_result) 514 return rssi_result 515 516 def get_iperf_timeout(self, atten_range, connected_measurements, 517 polling_frequency, first_measurement_delay, 518 scan_measurements): 519 """Function to comput iperf session length required in RSSI test. 520 521 Args: 522 atten_range: array of attenuations 523 connected_measurements: number of measurements per atten step 524 polling_frequency: interval between RSSI measurements 525 first_measurement_delay: delay before first measurements 526 scan_measurements: number of scan RSSI measurements per atten step 527 Returns: 528 iperf_timeout: length of iperf session required in rssi test 529 """ 530 atten_step_duration = first_measurement_delay + ( 531 connected_measurements * 532 polling_frequency) + scan_measurements * MED_SLEEP 533 iperf_timeout = len(atten_range) * atten_step_duration + MED_SLEEP 534 self.log.info("iperf timeout is {}".format(iperf_timeout)) 535 return iperf_timeout 536 537 def _test_rssi_vs_atten(self): 538 """ Function that gets called for each test case of rssi_vs_atten 539 540 The function gets called in each rssi test case. The function 541 customizes the test based on the test name of the test that called it 542 """ 543 test_params = self.current_test_name.split("_") 544 self.channel = int(test_params[4][2:]) 545 self.mode = test_params[5] 546 self.iperf_traffic = "ActiveTraffic" in test_params[6] 547 band = self.access_point.band_lookup_by_channel(self.channel) 548 num_atten_steps = int((self.test_params["rssi_vs_atten_stop"] - 549 self.test_params["rssi_vs_atten_start"]) / 550 self.test_params["rssi_vs_atten_step"]) 551 self.rssi_atten_range = [ 552 self.test_params["rssi_vs_atten_start"] + 553 x * self.test_params["rssi_vs_atten_step"] 554 for x in range(0, num_atten_steps) 555 ] 556 self.iperf_timeout = self.get_iperf_timeout( 557 self.rssi_atten_range, 558 self.test_params["rssi_vs_atten_connected_measurements"], 559 self.test_params["polling_frequency"], MED_SLEEP, 560 self.test_params["rssi_vs_atten_scan_measurements"]) 561 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb): 562 self.iperf_args = '-i 1 -t {} -J'.format(self.iperf_timeout) 563 else: 564 self.iperf_args = '-i 1 -t {} -J -R'.format(self.iperf_timeout) 565 rssi_result = self.rssi_test_func( 566 self.iperf_traffic, 567 self.test_params["rssi_vs_atten_connected_measurements"], 568 self.test_params["rssi_vs_atten_scan_measurements"], 569 [self.main_network[band]["BSSID"]], 570 self.test_params["polling_frequency"], MED_SLEEP) 571 postprocessed_results = self.post_process_rssi_sweep(rssi_result) 572 self.plot_rssi_vs_attenuation(postprocessed_results) 573 self.pass_fail_check_rssi_accuracy( 574 postprocessed_results, self.test_params["rssi_vs_atten_metrics"], 575 1) 576 577 def _test_rssi_stability(self): 578 """ Function that gets called for each test case of rssi_stability 579 580 The function gets called in each stability test case. The function 581 customizes test based on the test name of the test that called it 582 """ 583 test_params = self.current_test_name.split("_") 584 self.channel = int(test_params[3][2:]) 585 self.mode = test_params[4] 586 self.iperf_traffic = "ActiveTraffic" in test_params[5] 587 band = self.access_point.band_lookup_by_channel(self.channel) 588 self.rssi_atten_range = self.test_params["rssi_stability_atten"] 589 connected_measurements = int( 590 self.test_params["rssi_stability_duration"] / 591 self.test_params["polling_frequency"]) 592 self.iperf_timeout = self.get_iperf_timeout( 593 self.rssi_atten_range, connected_measurements, 594 self.test_params["polling_frequency"], MED_SLEEP, 0) 595 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb): 596 self.iperf_args = '-i 1 -t {} -J'.format(self.iperf_timeout) 597 else: 598 self.iperf_args = '-i 1 -t {} -J -R'.format(self.iperf_timeout) 599 rssi_result = self.rssi_test_func( 600 self.iperf_traffic, connected_measurements, 0, 601 [self.main_network[band]["BSSID"]], 602 self.test_params["polling_frequency"], MED_SLEEP) 603 postprocessed_results = self.post_process_rssi_sweep(rssi_result) 604 self.plot_rssi_vs_time(rssi_result, postprocessed_results, 1) 605 self.pass_fail_check_rssi_stability(postprocessed_results) 606 607 def _test_rssi_tracking(self): 608 """ Function that gets called for each test case of rssi_tracking 609 610 The function gets called in each rssi test case. The function 611 customizes the test based on the test name of the test that called it 612 """ 613 test_params = self.current_test_name.split("_") 614 self.channel = int(test_params[3][2:]) 615 self.mode = test_params[4] 616 self.iperf_traffic = "ActiveTraffic" in test_params[5] 617 band = self.access_point.band_lookup_by_channel(self.channel) 618 self.rssi_atten_range = [] 619 for waveform in self.test_params["rssi_tracking_waveforms"]: 620 waveform_vector = [] 621 for section in range(len(waveform["atten_levels"]) - 1): 622 section_limits = waveform["atten_levels"][section:section + 2] 623 up_down = (1 - 2 * (section_limits[1] < section_limits[0])) 624 temp_section = list( 625 range(section_limits[0], section_limits[1] + up_down, 626 up_down * waveform["step_size"])) 627 temp_section = [ 628 temp_section[idx] for idx in range(len(temp_section)) 629 for n in range(waveform["step_duration"]) 630 ] 631 waveform_vector += temp_section 632 waveform_vector = waveform_vector * waveform["repetitions"] 633 self.rssi_atten_range = self.rssi_atten_range + waveform_vector 634 connected_measurements = int(1 / self.test_params["polling_frequency"]) 635 self.iperf_timeout = self.get_iperf_timeout( 636 self.rssi_atten_range, connected_measurements, 637 self.test_params["polling_frequency"], 0, 0) 638 if isinstance(self.iperf_server, ipf.IPerfServerOverAdb): 639 self.iperf_args = '-i 1 -t {} -J'.format(self.iperf_timeout) 640 else: 641 self.iperf_args = '-i 1 -t {} -J -R'.format(self.iperf_timeout) 642 rssi_result = self.rssi_test_func( 643 self.iperf_traffic, connected_measurements, 0, 644 [self.main_network[band]["BSSID"]], 645 self.test_params["polling_frequency"], 0) 646 postprocessed_results = self.post_process_rssi_sweep(rssi_result) 647 self.plot_rssi_vs_time(rssi_result, postprocessed_results, 1) 648 self.pass_fail_check_rssi_accuracy(postprocessed_results, 649 ["signal_poll_rssi"], 0) 650 651 @test_tracker_info(uuid='519689b8-0a3c-4fd9-9227-fd7962d0f1a0') 652 def test_rssi_stability_ch1_VHT20_ActiveTraffic(self): 653 self._test_rssi_stability() 654 655 @test_tracker_info(uuid='23eca2ab-d0b4-4730-9f32-ec2d901ae493') 656 def test_rssi_stability_ch2_VHT20_ActiveTraffic(self): 657 self._test_rssi_stability() 658 659 @test_tracker_info(uuid='63d340c0-dcf9-4e14-87bd-a068a59836b2') 660 def test_rssi_stability_ch3_VHT20_ActiveTraffic(self): 661 self._test_rssi_stability() 662 663 @test_tracker_info(uuid='ddbe88d8-be20-40eb-8f29-55049e3fef28') 664 def test_rssi_stability_ch4_VHT20_ActiveTraffic(self): 665 self._test_rssi_stability() 666 667 @test_tracker_info(uuid='9c06304e-2b60-4619-8fb3-73fd2cb4b854') 668 def test_rssi_stability_ch5_VHT20_ActiveTraffic(self): 669 self._test_rssi_stability() 670 671 @test_tracker_info(uuid='74b656ca-132e-4d66-9584-560287081607') 672 def test_rssi_stability_ch6_VHT20_ActiveTraffic(self): 673 self._test_rssi_stability() 674 675 @test_tracker_info(uuid='23b5f19a-539b-4908-a197-06ce505d3d23') 676 def test_rssi_stability_ch7_VHT20_ActiveTraffic(self): 677 self._test_rssi_stability() 678 679 @test_tracker_info(uuid='e7b85167-f4c4-4adb-a111-04d8a5f10e1a') 680 def test_rssi_stability_ch8_VHT20_ActiveTraffic(self): 681 self._test_rssi_stability() 682 683 @test_tracker_info(uuid='2a0a9393-4b68-4c08-8787-3f35d1a8458b') 684 def test_rssi_stability_ch9_VHT20_ActiveTraffic(self): 685 self._test_rssi_stability() 686 687 @test_tracker_info(uuid='069c7acf-3e7e-4298-91cb-d292c6025ae1') 688 def test_rssi_stability_ch10_VHT20_ActiveTraffic(self): 689 self._test_rssi_stability() 690 691 @test_tracker_info(uuid='95c5a27c-1dea-47a4-a1c5-edf955545f12') 692 def test_rssi_stability_ch11_VHT20_ActiveTraffic(self): 693 self._test_rssi_stability() 694 695 @test_tracker_info(uuid='8aeab023-a096-4fbe-80dd-fd01466f9fac') 696 def test_rssi_stability_ch36_VHT20_ActiveTraffic(self): 697 self._test_rssi_stability() 698 699 @test_tracker_info(uuid='872fed9f-d0bb-4a7b-a2a7-bf8df7740b2d') 700 def test_rssi_stability_ch36_VHT40_ActiveTraffic(self): 701 self._test_rssi_stability() 702 703 @test_tracker_info(uuid='27395fd1-e286-473a-b98e-5a50db2a598a') 704 def test_rssi_stability_ch36_VHT80_ActiveTraffic(self): 705 self._test_rssi_stability() 706 707 @test_tracker_info(uuid='6f6b25e3-1a1e-4a61-930a-1d0aa25ba900') 708 def test_rssi_stability_ch40_VHT20_ActiveTraffic(self): 709 self._test_rssi_stability() 710 711 @test_tracker_info(uuid='c6717da7-855c-4c6e-a6e2-ee42b8feaaab') 712 def test_rssi_stability_ch44_VHT20_ActiveTraffic(self): 713 self._test_rssi_stability() 714 715 @test_tracker_info(uuid='2e34f735-079c-4619-9e74-b96dc8d0597f') 716 def test_rssi_stability_ch44_VHT40_ActiveTraffic(self): 717 self._test_rssi_stability() 718 719 @test_tracker_info(uuid='d543c019-1ff5-41d4-9b37-ccdc593f3edd') 720 def test_rssi_stability_ch48_VHT20_ActiveTraffic(self): 721 self._test_rssi_stability() 722 723 @test_tracker_info(uuid='2bb08914-36b2-4f58-9b3e-c3f3f4fac8ab') 724 def test_rssi_stability_ch149_VHT20_ActiveTraffic(self): 725 self._test_rssi_stability() 726 727 @test_tracker_info(uuid='e2f585f5-7811-4570-b987-23da301eb75d') 728 def test_rssi_stability_ch149_VHT40_ActiveTraffic(self): 729 self._test_rssi_stability() 730 731 @test_tracker_info(uuid='f3e74d5b-73f6-4723-abf3-c9c147db08e3') 732 def test_rssi_stability_ch149_VHT80_ActiveTraffic(self): 733 self._test_rssi_stability() 734 735 @test_tracker_info(uuid='06503ed0-baf3-4cd1-ac5e-4124e3c7f52f') 736 def test_rssi_stability_ch153_VHT20_ActiveTraffic(self): 737 self._test_rssi_stability() 738 739 @test_tracker_info(uuid='0cf8286f-a919-4e29-a9f2-e7738a4afe8f') 740 def test_rssi_stability_ch157_VHT20_ActiveTraffic(self): 741 self._test_rssi_stability() 742 743 @test_tracker_info(uuid='f9a0165c-468b-4096-8f4b-cc80bae564a0') 744 def test_rssi_stability_ch157_VHT40_ActiveTraffic(self): 745 self._test_rssi_stability() 746 747 @test_tracker_info(uuid='4b74dd46-4190-4556-8ad8-c55808e9e847') 748 def test_rssi_stability_ch161_VHT20_ActiveTraffic(self): 749 self._test_rssi_stability() 750 751 @test_tracker_info(uuid='ae54b7cc-d76d-4460-8dcc-2c439265c7c9') 752 def test_rssi_vs_atten_ch1_VHT20_ActiveTraffic(self): 753 self._test_rssi_vs_atten() 754 755 @test_tracker_info(uuid='07fe7899-886d-45ba-9c1d-7daaf9844c9c') 756 def test_rssi_vs_atten_ch2_VHT20_ActiveTraffic(self): 757 self._test_rssi_vs_atten() 758 759 @test_tracker_info(uuid='9e86578b-a6cd-4de9-a79d-eabac5bd5f4e') 760 def test_rssi_vs_atten_ch3_VHT20_ActiveTraffic(self): 761 self._test_rssi_vs_atten() 762 763 @test_tracker_info(uuid='e9d258ca-8e70-408e-b704-782fce7a07c5') 764 def test_rssi_vs_atten_ch4_VHT20_ActiveTraffic(self): 765 self._test_rssi_vs_atten() 766 767 @test_tracker_info(uuid='1c5d71a0-7532-49e4-98a9-1c2d9d8d58d2') 768 def test_rssi_vs_atten_ch5_VHT20_ActiveTraffic(self): 769 self._test_rssi_vs_atten() 770 771 @test_tracker_info(uuid='107f01f3-b6b9-470b-9895-6345edfc9599') 772 def test_rssi_vs_atten_ch6_VHT20_ActiveTraffic(self): 773 self._test_rssi_vs_atten() 774 775 @test_tracker_info(uuid='88cb18b2-30bf-4c01-ac28-15451289e7cd') 776 def test_rssi_vs_atten_ch7_VHT20_ActiveTraffic(self): 777 self._test_rssi_vs_atten() 778 779 @test_tracker_info(uuid='c07a7442-bd1d-40c7-80ed-167e30b8cfaf') 780 def test_rssi_vs_atten_ch8_VHT20_ActiveTraffic(self): 781 self._test_rssi_vs_atten() 782 783 @test_tracker_info(uuid='b8946280-88d5-400d-a417-2bdc9d7e054a') 784 def test_rssi_vs_atten_ch9_VHT20_ActiveTraffic(self): 785 self._test_rssi_vs_atten() 786 787 @test_tracker_info(uuid='a05db91b-740d-4984-a447-79ab438034f0') 788 def test_rssi_vs_atten_ch10_VHT20_ActiveTraffic(self): 789 self._test_rssi_vs_atten() 790 791 @test_tracker_info(uuid='f4d565f8-f060-462c-9b3c-cd1f7d27b3ea') 792 def test_rssi_vs_atten_ch11_VHT20_ActiveTraffic(self): 793 self._test_rssi_vs_atten() 794 795 @test_tracker_info(uuid='a33a93ac-604a-414f-ae96-42dffbe59a93') 796 def test_rssi_vs_atten_ch36_VHT20_ActiveTraffic(self): 797 self._test_rssi_vs_atten() 798 799 @test_tracker_info(uuid='39875ab0-e0e9-464b-8a47-4dedd65f066e') 800 def test_rssi_vs_atten_ch36_VHT40_ActiveTraffic(self): 801 self._test_rssi_vs_atten() 802 803 @test_tracker_info(uuid='c6ff8768-f124-4190-baf2-bbf14b612de3') 804 def test_rssi_vs_atten_ch36_VHT80_ActiveTraffic(self): 805 self._test_rssi_vs_atten() 806 807 @test_tracker_info(uuid='ed4705af-e202-4737-b410-8bab0515e79f') 808 def test_rssi_vs_atten_ch40_VHT20_ActiveTraffic(self): 809 self._test_rssi_vs_atten() 810 811 @test_tracker_info(uuid='1388df99-ecbf-4412-9ded-d66552f37ec5') 812 def test_rssi_vs_atten_ch44_VHT20_ActiveTraffic(self): 813 self._test_rssi_vs_atten() 814 815 @test_tracker_info(uuid='06868677-ad3c-4f50-9b9e-ae8d9455ae4d') 816 def test_rssi_vs_atten_ch44_VHT40_ActiveTraffic(self): 817 self._test_rssi_vs_atten() 818 819 @test_tracker_info(uuid='9b6676de-c736-4603-a9b3-97670bea8f25') 820 def test_rssi_vs_atten_ch48_VHT20_ActiveTraffic(self): 821 self._test_rssi_vs_atten() 822 823 @test_tracker_info(uuid='2641c4b8-0092-4e29-9139-fdb3b3f04d05') 824 def test_rssi_vs_atten_ch149_VHT20_ActiveTraffic(self): 825 self._test_rssi_vs_atten() 826 827 @test_tracker_info(uuid='c8bc3f7d-b459-4e40-9c73-b0bf534c6c08') 828 def test_rssi_vs_atten_ch149_VHT40_ActiveTraffic(self): 829 self._test_rssi_vs_atten() 830 831 @test_tracker_info(uuid='3e08f5b6-9f3c-4905-8b10-82e1ca830cc9') 832 def test_rssi_vs_atten_ch149_VHT80_ActiveTraffic(self): 833 self._test_rssi_vs_atten() 834 835 @test_tracker_info(uuid='2343efe3-fdda-4180-add7-4786d35e29bb') 836 def test_rssi_vs_atten_ch153_VHT20_ActiveTraffic(self): 837 self._test_rssi_vs_atten() 838 839 @test_tracker_info(uuid='89a16974-2399-4356-b720-17b765ff1c3a') 840 def test_rssi_vs_atten_ch157_VHT20_ActiveTraffic(self): 841 self._test_rssi_vs_atten() 842 843 @test_tracker_info(uuid='c8e0e44a-b962-4e71-ba8f-068f268c8823') 844 def test_rssi_vs_atten_ch157_VHT40_ActiveTraffic(self): 845 self._test_rssi_vs_atten() 846 847 @test_tracker_info(uuid='581b5794-239e-4d1c-b0ce-7c6dc5bd373f') 848 def test_rssi_vs_atten_ch161_VHT20_ActiveTraffic(self): 849 self._test_rssi_vs_atten() 850 851 def test_rssi_tracking_ch6_VHT20_ActiveTraffic(self): 852 self._test_rssi_tracking() 853 854 def test_rssi_tracking_ch6_VHT20_NoTraffic(self): 855 self._test_rssi_tracking() 856 857 def test_rssi_tracking_ch36_VHT20_ActiveTraffic(self): 858 self._test_rssi_tracking() 859 860 def test_rssi_tracking_ch36_VHT20_NoTraffic(self): 861 self._test_rssi_tracking() 862 863 def test_rssi_tracking_ch36_VHT40_ActiveTraffic(self): 864 self._test_rssi_tracking() 865 866 def test_rssi_tracking_ch36_VHT40_NoTraffic(self): 867 self._test_rssi_tracking() 868 869 def test_rssi_tracking_ch36_VHT80_ActiveTraffic(self): 870 self._test_rssi_tracking() 871 872 def test_rssi_tracking_ch36_VHT80_NoTraffic(self): 873 self._test_rssi_tracking() 874 875 def test_rssi_tracking_ch149_VHT20_ActiveTraffic(self): 876 self._test_rssi_tracking() 877 878 def test_rssi_tracking_ch149_VHT20_NoTraffic(self): 879 self._test_rssi_tracking() 880 881 def test_rssi_tracking_ch149_VHT40_ActiveTraffic(self): 882 self._test_rssi_tracking() 883 884 def test_rssi_tracking_ch149_VHT40_NoTraffic(self): 885 self._test_rssi_tracking() 886 887 def test_rssi_tracking_ch149_VHT80_ActiveTraffic(self): 888 self._test_rssi_tracking() 889 890 def test_rssi_tracking_ch149_VHT80_NoTraffic(self): 891 self._test_rssi_tracking() 892 893 894class WifiRssi_2GHz_ActiveTraffic_Test(WifiRssiTest): 895 def __init__(self, controllers): 896 super().__init__(controllers) 897 self.tests = ("test_rssi_stability_ch1_VHT20_ActiveTraffic", 898 "test_rssi_vs_atten_ch1_VHT20_ActiveTraffic", 899 "test_rssi_stability_ch2_VHT20_ActiveTraffic", 900 "test_rssi_vs_atten_ch2_VHT20_ActiveTraffic", 901 "test_rssi_stability_ch6_VHT20_ActiveTraffic", 902 "test_rssi_vs_atten_ch6_VHT20_ActiveTraffic", 903 "test_rssi_stability_ch10_VHT20_ActiveTraffic", 904 "test_rssi_vs_atten_ch10_VHT20_ActiveTraffic", 905 "test_rssi_stability_ch11_VHT20_ActiveTraffic", 906 "test_rssi_vs_atten_ch11_VHT20_ActiveTraffic") 907 908 909class WifiRssi_5GHz_ActiveTraffic_Test(WifiRssiTest): 910 def __init__(self, controllers): 911 super().__init__(controllers) 912 self.tests = ("test_rssi_stability_ch36_VHT20_ActiveTraffic", 913 "test_rssi_vs_atten_ch36_VHT20_ActiveTraffic", 914 "test_rssi_stability_ch36_VHT40_ActiveTraffic", 915 "test_rssi_vs_atten_ch36_VHT40_ActiveTraffic", 916 "test_rssi_stability_ch36_VHT80_ActiveTraffic", 917 "test_rssi_vs_atten_ch36_VHT80_ActiveTraffic", 918 "test_rssi_stability_ch40_VHT20_ActiveTraffic", 919 "test_rssi_vs_atten_ch40_VHT20_ActiveTraffic", 920 "test_rssi_stability_ch44_VHT20_ActiveTraffic", 921 "test_rssi_vs_atten_ch44_VHT20_ActiveTraffic", 922 "test_rssi_stability_ch44_VHT40_ActiveTraffic", 923 "test_rssi_vs_atten_ch44_VHT40_ActiveTraffic", 924 "test_rssi_stability_ch48_VHT20_ActiveTraffic", 925 "test_rssi_vs_atten_ch48_VHT20_ActiveTraffic", 926 "test_rssi_stability_ch149_VHT20_ActiveTraffic", 927 "test_rssi_vs_atten_ch149_VHT20_ActiveTraffic", 928 "test_rssi_stability_ch149_VHT40_ActiveTraffic", 929 "test_rssi_vs_atten_ch149_VHT40_ActiveTraffic", 930 "test_rssi_stability_ch149_VHT80_ActiveTraffic", 931 "test_rssi_vs_atten_ch149_VHT80_ActiveTraffic", 932 "test_rssi_stability_ch153_VHT20_ActiveTraffic", 933 "test_rssi_vs_atten_ch153_VHT20_ActiveTraffic", 934 "test_rssi_stability_ch157_VHT20_ActiveTraffic", 935 "test_rssi_vs_atten_ch157_VHT20_ActiveTraffic", 936 "test_rssi_stability_ch157_VHT40_ActiveTraffic", 937 "test_rssi_vs_atten_ch157_VHT40_ActiveTraffic", 938 "test_rssi_stability_ch161_VHT20_ActiveTraffic", 939 "test_rssi_vs_atten_ch161_VHT20_ActiveTraffic") 940 941 942class WifiRssiTrackingTest(WifiRssiTest): 943 def __init__(self, controllers): 944 super().__init__(controllers) 945 self.tests = ("test_rssi_tracking_ch6_VHT20_ActiveTraffic", 946 "test_rssi_tracking_ch6_VHT20_NoTraffic", 947 "test_rssi_tracking_ch36_VHT20_ActiveTraffic", 948 "test_rssi_tracking_ch36_VHT20_NoTraffic", 949 "test_rssi_tracking_ch36_VHT40_ActiveTraffic", 950 "test_rssi_tracking_ch36_VHT40_NoTraffic", 951 "test_rssi_tracking_ch36_VHT80_ActiveTraffic", 952 "test_rssi_tracking_ch36_VHT80_NoTraffic", 953 "test_rssi_tracking_ch149_VHT20_ActiveTraffic", 954 "test_rssi_tracking_ch149_VHT20_NoTraffic", 955 "test_rssi_tracking_ch149_VHT40_ActiveTraffic", 956 "test_rssi_tracking_ch149_VHT40_NoTraffic", 957 "test_rssi_tracking_ch149_VHT80_ActiveTraffic", 958 "test_rssi_tracking_ch149_VHT80_NoTraffic") 959