blob: 756f1fe547be6f300b4f0c08dcff42847b1fb7ce [file] [log] [blame]
Omar El Ayachb8808082018-03-04 01:05:39 +00001#!/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 json
18import logging
19import math
20import os
21import re
22import time
23from acts import asserts
24from acts import base_test
25from acts import utils
26from acts.test_decorators import test_tracker_info
27from acts.test_utils.wifi import wifi_power_test_utils as wputils
28from acts.test_utils.wifi import wifi_retail_ap as retail_ap
29from acts.test_utils.wifi import wifi_test_utils as wutils
30
31SHORT_SLEEP = 1
32MED_SLEEP = 6
33STATION_DUMP = "iw wlan0 station dump"
34SCAN = "wpa_cli scan"
35SCAN_RESULTS = "wpa_cli scan_results"
36SIGNAL_POLL = "wpa_cli signal_poll"
37CONST_3dB = 3.01029995664
38RSSI_ERROR_VAL = float("nan")
39
40
41class WifiRssiTest(base_test.BaseTestClass):
42 def __init__(self, controllers):
43 base_test.BaseTestClass.__init__(self, controllers)
44
45 def setup_class(self):
46 self.dut = self.android_devices[0]
47 req_params = ["test_params", "main_network"]
48 opt_params = ["RetailAccessPoints"]
49 self.unpack_userparams(req_params, opt_params)
50 self.num_atten = self.attenuators[0].instrument.num_atten
51 self.iperf_server = self.iperf_servers[0]
52 self.access_points = retail_ap.create(self.RetailAccessPoints)
53 self.access_point = self.access_points[0]
54 self.log_path = os.path.join(logging.log_path, "results")
55 utils.create_dir(self.log_path)
56 self.log.info("Access Point Configuration: {}".format(
57 self.access_point.ap_settings))
58 self.testclass_results = []
59
60 def teardown_test(self):
61 self.iperf_server.stop()
62
63 def pass_fail_check_rssi_vs_attenuation(self, postprocessed_results):
64 """Check the test result and decide if it passed or failed.
65
66 Checks the RSSI test result and compares and compute its deviation from
67 the predicted RSSI. This computation is done for all reported RSSI
68 values. The test fails if any of the RSSI values specified in
69 rssi_under_test have an average error beyond what is specified in the
70 configuration file.
71
72 Args:
73 result: dict containing attenuation, rssi, and other meta
74 data. This dict is the output of self.post_process_results
75 """
76
77 error_data = {
78 "signal_poll_rssi": [
79 postprocessed_results["mean_signal_poll_rssi"][idx] -
80 postprocessed_results["predicted_rssi"][idx]
81 for idx in range(len(postprocessed_results["predicted_rssi"]))
82 ],
83 "signal_poll_avg_rssi": [
84 postprocessed_results["mean_signal_poll_avg_rssi"][idx] -
85 postprocessed_results["predicted_rssi"][idx]
86 for idx in range(len(postprocessed_results["predicted_rssi"]))
87 ],
88 "scan_rssi": [
89 postprocessed_results["mean_scan_rssi"][idx] -
90 postprocessed_results["predicted_rssi"][idx]
91 for idx in range(len(postprocessed_results["predicted_rssi"]))
92 ],
93 "chain_0_rssi": [
94 postprocessed_results["mean_chain_0_rssi"][idx] + CONST_3dB -
95 postprocessed_results["predicted_rssi"][idx]
96 for idx in range(len(postprocessed_results["predicted_rssi"]))
97 ],
98 "chain_1_rssi": [
99 postprocessed_results["mean_chain_1_rssi"][idx] + CONST_3dB -
100 postprocessed_results["predicted_rssi"][idx]
101 for idx in range(len(postprocessed_results["predicted_rssi"]))
102 ]
103 }
104
105 test_failed = False
106 test_message = ""
107 for key, val in error_data.items():
108 # Compute the error metrics ignoring invalid RSSI readings
109 # If all readings invalid, set error to RSSI_ERROR_VAL
110 filtered_errors = [x for x in val if not math.isnan(x)]
111 if filtered_errors:
112 avg_error = sum([abs(x) for x in filtered_errors
113 ]) / len(filtered_errors)
114 avg_shift = sum(filtered_errors) / len(filtered_errors)
115 else:
116 avg_error = RSSI_ERROR_VAL
117 rssi_failure = (avg_error > self.test_params["abs_tolerance"]
118 ) or math.isnan(avg_error)
119 if rssi_failure and key in self.test_params["rssi_under_test"]:
120 test_message = test_message + (
121 "{} failed. Average error is {:.2f} dB. "
122 "Average shift is {:.2f} dB.\n").format(
123 key, avg_error, avg_shift)
124 test_failed = True
125 elif rssi_failure:
126 test_message = test_message + (
127 "{} failed (ignored). Average error is {:.2f} dB. "
128 "Average shift is {:.2f} dB.\n").format(
129 key, avg_error, avg_shift)
130 else:
131 test_message = test_message + (
132 "{} passed. Average error is {:.2f} dB. "
133 "Average shift is {:.2f} dB.\n").format(
134 key, avg_error, avg_shift)
135
136 if test_failed:
137 asserts.fail(test_message)
138 asserts.explicit_pass(test_message)
139
140 def post_process_results(self, rssi_result):
141 """Saves plots and JSON formatted results.
142
143 Args:
144 rssi_result: dict containing attenuation, rssi and other meta
145 data
146 Returns:
147 postprocessed_results: compiled arrays of RSSI measurements used in
148 pass/fail check
149 """
150 # Save output as text file
151 test_name = self.current_test_name
152 results_file_path = "{}/{}.json".format(self.log_path,
153 self.current_test_name)
154 with open(results_file_path, 'w') as results_file:
155 json.dump(rssi_result, results_file)
156 # Plot and save
157 total_attenuation = [
158 att + rssi_result["fixed_attenuation"]
159 for att in rssi_result["attenuation"]
160 ]
161 # Compile results into arrays of RSSIs suitable for plotting
162 postprocessed_results = {
163 "total_attenuation":
164 total_attenuation,
165 "mean_signal_poll_rssi": [
166 x["connected_rssi"]["mean_signal_poll_rssi"]
167 for x in rssi_result["rssi_result"]
168 ],
169 "mean_signal_poll_avg_rssi": [
170 x["connected_rssi"]["mean_signal_poll_avg_rssi"]
171 for x in rssi_result["rssi_result"]
172 ],
173 "mean_scan_rssi": [
174 x["scan_rssi"][rssi_result["connected_bssid"]]["avg_rssi"]
175 for x in rssi_result["rssi_result"]
176 ],
177 "mean_chain_0_rssi": [
178 x["connected_rssi"]["mean_chain_0_rssi"]
179 for x in rssi_result["rssi_result"]
180 ],
181 "mean_chain_1_rssi": [
182 x["connected_rssi"]["mean_chain_1_rssi"]
183 for x in rssi_result["rssi_result"]
184 ],
185 "predicted_rssi":
186 [rssi_result["ap_tx_power"] - att for att in total_attenuation]
187 }
188 data_sets = [[
189 total_attenuation, total_attenuation, total_attenuation,
190 total_attenuation, total_attenuation, total_attenuation
191 ], [
192 postprocessed_results["mean_signal_poll_rssi"],
193 postprocessed_results["mean_signal_poll_avg_rssi"],
194 postprocessed_results["mean_scan_rssi"],
195 postprocessed_results["mean_chain_0_rssi"],
196 postprocessed_results["mean_chain_1_rssi"],
197 postprocessed_results["predicted_rssi"]
198 ]]
199 legends = [
200 "Signal Poll RSSI", "Signal Poll AVG_RSSI", "Scan RSSI",
201 "Chain 0 RSSI", "Chain 1 RSSI", "Predicted RSSI"
202 ]
203 x_label = 'Attenuation (dB)'
204 y_label = 'RSSI (dBm)'
205 fig_property = {
206 "title": test_name,
207 "x_label": x_label,
208 "y_label": y_label,
209 "linewidth": 3,
210 "markersize": 10
211 }
212 output_file_path = "{}/{}.html".format(self.log_path, test_name)
213 wputils.bokeh_plot(
214 data_sets,
215 legends,
216 fig_property,
217 shaded_region=None,
218 output_file_path=output_file_path)
219 return postprocessed_results
220
221 def get_scan_rssi(self, tracked_bssids, num_measurements=1):
222 """Gets scan RSSI for specified BSSIDs.
223
224 Args:
225 tracked_bssids: array of BSSIDs to gather RSSI data for
226 num_measurements: number of scans done, and RSSIs collected
227 Returns:
228 scan_rssi: dict containing the measurement results as well as the
229 average scan RSSI for all BSSIDs in tracked_bssids
230 """
231 scan_rssi = {}
232 for bssid in tracked_bssids:
233 scan_rssi[bssid] = {"rssi": [], "avg_rssi": None}
234 for idx in range(num_measurements):
235 scan_output = self.dut.adb.shell(SCAN)
236 time.sleep(MED_SLEEP)
237 scan_output = self.dut.adb.shell(SCAN_RESULTS)
238 for bssid in tracked_bssids:
239 bssid_result = re.search(
240 bssid + ".*", scan_output, flags=re.IGNORECASE)
241 if bssid_result:
242 bssid_result = bssid_result.group(0).split("\t")
243 scan_rssi[bssid]["rssi"].append(int(bssid_result[2]))
244 else:
245 scan_rssi[bssid]["rssi"].append(RSSI_ERROR_VAL)
246 # Compute mean RSSIs. Only average valid readings.
247 # Output RSSI_ERROR_VAL if no readings found.
248 for key, val in scan_rssi.items():
249 filtered_rssi_values = [
250 x for x in val["rssi"] if not math.isnan(x)
251 ]
252 if filtered_rssi_values:
253 scan_rssi[key]["avg_rssi"] = sum(filtered_rssi_values) / len(
254 filtered_rssi_values)
255 else:
256 scan_rssi[key]["avg_rssi"] = RSSI_ERROR_VAL
257 return scan_rssi
258
259 def get_connected_rssi(self,
260 num_measurements=1,
261 polling_frequency=SHORT_SLEEP):
262 """Gets all RSSI values reported for the connected access point/BSSID.
263
264 Args:
265 num_measurements: number of scans done, and RSSIs collected
266 polling_frequency: time to wait between RSSI measurements
267 Returns:
268 connected_rssi: dict containing the measurements results for
269 all reported RSSI values (signal_poll, per chain, etc.) and their
270 averages
271 """
272 connected_rssi = {
273 "signal_poll_rssi": [],
274 "signal_poll_avg_rssi": [],
275 "chain_0_rssi": [],
276 "chain_1_rssi": []
277 }
278 for idx in range(num_measurements):
279 # Get signal poll RSSI
280 signal_poll_output = self.dut.adb.shell(SIGNAL_POLL)
281 match = re.search("RSSI=.*", signal_poll_output)
282 if match:
283 temp_rssi = int(match.group(0).split("=")[1])
284 if temp_rssi == -9999:
285 connected_rssi["signal_poll_rssi"].append(RSSI_ERROR_VAL)
286 else:
287 connected_rssi["signal_poll_rssi"].append(temp_rssi)
288 else:
289 connected_rssi["signal_poll_rssi"].append(RSSI_ERROR_VAL)
290 match = re.search("AVG_RSSI=.*", signal_poll_output)
291 if match:
292 connected_rssi["signal_poll_avg_rssi"].append(
293 int(match.group(0).split("=")[1]))
294 else:
295 connected_rssi["signal_poll_avg_rssi"].append(RSSI_ERROR_VAL)
296 # Get per chain RSSI
297 per_chain_rssi = self.dut.adb.shell(STATION_DUMP)
298 match = re.search(".*signal avg:.*", per_chain_rssi)
299 if match:
300 per_chain_rssi = per_chain_rssi[per_chain_rssi.find("[") + 1:
301 per_chain_rssi.find("]")]
302 per_chain_rssi = per_chain_rssi.split(", ")
303 connected_rssi["chain_0_rssi"].append(int(per_chain_rssi[0]))
304 connected_rssi["chain_1_rssi"].append(int(per_chain_rssi[1]))
305 else:
306 connected_rssi["chain_0_rssi"].append(RSSI_ERROR_VAL)
307 connected_rssi["chain_1_rssi"].append(RSSI_ERROR_VAL)
308 time.sleep(polling_frequency)
309 # Compute mean RSSIs. Only average valid readings.
310 # Output RSSI_ERROR_VAL if no valid connected readings found.
311 for key, val in connected_rssi.copy().items():
312 filtered_rssi_values = [x for x in val if not math.isnan(x)]
313 if filtered_rssi_values:
314 connected_rssi["mean_{}".format(key)] = sum(
315 filtered_rssi_values) / len(filtered_rssi_values)
316 else:
317 connected_rssi["mean_{}".format(key)] = RSSI_ERROR_VAL
318 return connected_rssi
319
320 def rssi_test(self, iperf_traffic, connected_measurements,
321 scan_measurements, bssids, polling_frequency):
322 """Test function to run RSSI tests.
323
324 The function runs an RSSI test in the current device/AP configuration.
325 Function is called from another wrapper function that sets up the
326 testbed for the RvR test
327
328 Args:
329 iperf_traffic: boolean specifying whether or not to run traffic
330 during RSSI tests
331 connected_measurements: number of RSSI measurements to make for the
332 connected AP per attenuation point
333 scan_measurements: number of scans and scan RSSIs to make per
334 attenuation point
335 bssids: list of BSSIDs to monitor in scans
336 polling_frequency: time between connected AP measurements
337 Returns:
338 rssi_result: dict containing rssi_result and meta data
339 """
340 self.log.info("Start running RSSI test.")
341 rssi_result = []
342 # Start iperf traffic if required by test
343 if self.iperf_traffic:
344 self.iperf_server.start(tag=0)
345 self.dut.run_iperf_client_nb(
346 self.test_params["iperf_server_address"],
347 self.iperf_args,
348 timeout=3600)
349 for atten in self.rssi_atten_range:
350 # Set Attenuation
351 self.log.info("Setting attenuation to {} dB".format(atten))
352 [
353 self.attenuators[i].set_atten(atten)
354 for i in range(self.num_atten)
355 ]
356 time.sleep(MED_SLEEP)
357 current_rssi = {}
358 current_rssi["connected_rssi"] = self.get_connected_rssi(
359 connected_measurements, polling_frequency)
360 current_rssi["scan_rssi"] = self.get_scan_rssi(
361 bssids, scan_measurements)
362 rssi_result.append(current_rssi)
363 self.log.info("Connected RSSI at {0:.2f} dB is {1:.2f} dB".format(
364 atten, current_rssi["connected_rssi"][
365 "mean_signal_poll_rssi"]))
366 # Stop iperf traffic if needed
367 if self.iperf_traffic:
368 self.iperf_server.stop()
369 self.dut.adb.shell("pkill iperf3")
370 [self.attenuators[i].set_atten(0) for i in range(self.num_atten)]
371 return rssi_result
372
373 def rssi_test_func(self):
374 """Main function to test RSSI.
375
376 The function sets up the AP in the correct channel and mode
377 configuration and called rssi_test to sweep attenuation and measure
378 RSSI
379
380 Returns:
381 rssi_result: dict containing rssi_results and meta data
382 """
383 #Initialize test parameters
384 num_atten_steps = int((self.test_params["rssi_atten_stop"] -
385 self.test_params["rssi_atten_start"]) /
386 self.test_params["rssi_atten_step"])
387 self.rssi_atten_range = [
388 self.test_params["rssi_atten_start"] +
389 x * self.test_params["rssi_atten_step"]
390 for x in range(0, num_atten_steps)
391 ]
392
393 rssi_result = {}
394 # Configure AP
395 band = self.access_point.band_lookup_by_channel(self.channel)
396 self.access_point.set_channel(band, self.channel)
397 self.access_point.set_bandwidth(band, self.mode)
398 self.log.info("Access Point Configuration: {}".format(
399 self.access_point.ap_settings))
400 # Set attenuator to starting attenuation
401 [
402 self.attenuators[i].set_atten(self.rssi_atten_range[0])
403 for i in range(self.num_atten)
404 ]
405 # Connect DUT to Network
406 wutils.wifi_toggle_state(self.dut, True)
407 wutils.reset_wifi(self.dut)
408 self.main_network[band]["channel"] = self.channel
409 wutils.wifi_connect(self.dut, self.main_network[band], num_of_tries=5)
410 time.sleep(5)
411 # Run RvR and log result
412 rssi_result["test_name"] = self.current_test_name
413 rssi_result["ap_settings"] = self.access_point.ap_settings.copy()
414 rssi_result["attenuation"] = list(self.rssi_atten_range)
415 rssi_result["connected_bssid"] = self.main_network[band]["BSSID"]
416 rssi_result["ap_tx_power"] = self.test_params["ap_tx_power"][str(
417 self.channel)]
418 rssi_result["fixed_attenuation"] = self.test_params[
419 "fixed_attenuation"][str(self.channel)]
420 rssi_result["rssi_result"] = self.rssi_test(
421 self.iperf_traffic, self.test_params["connected_measurements"],
422 self.test_params["scan_measurements"], [
423 self.main_network[band]["BSSID"]
424 ], self.test_params["polling_frequency"])
425 self.testclass_results.append(rssi_result)
426 return rssi_result
427
428 def _test_rssi_vs_atten(self):
429 """ Function that gets called for each test case of rssi_vs_atten
430
431 The function gets called in each rvr test case. The function customizes
432 the rvr test based on the test name of the test that called it
433 """
434 test_params = self.current_test_name.split("_")
435 self.channel = int(test_params[4][2:])
436 self.mode = test_params[5]
437 self.iperf_traffic = "ActiveTraffic" in test_params[6]
438 self.iperf_args = '-i 1 -t 3600 -J -R'
439 rssi_result = self.rssi_test_func()
440 postprocessed_results = self.post_process_results(rssi_result)
441 self.pass_fail_check_rssi_vs_attenuation(postprocessed_results)
442
443 def _test_rssi_stability(self):
444 #TODO: Implement test that looks at RSSI stability at fixed attenuation
445 pass
446
Omar El Ayach19a55672018-03-09 00:53:12 +0000447
448class WifiRssi_2GHz_ActiveTraffic_Test(WifiRssiTest):
449 def __init__(self, controllers):
450 base_test.BaseTestClass.__init__(self, controllers)
451
Omar El Ayachb8808082018-03-04 01:05:39 +0000452 @test_tracker_info(uuid='ae54b7cc-d76d-4460-8dcc-2c439265c7c9')
453 def test_rssi_vs_atten_ch1_VHT20_ActiveTraffic(self):
454 self._test_rssi_vs_atten()
455
456 @test_tracker_info(uuid='07fe7899-886d-45ba-9c1d-7daaf9844c9c')
457 def test_rssi_vs_atten_ch2_VHT20_ActiveTraffic(self):
458 self._test_rssi_vs_atten()
459
460 @test_tracker_info(uuid='9e86578b-a6cd-4de9-a79d-eabac5bd5f4e')
461 def test_rssi_vs_atten_ch3_VHT20_ActiveTraffic(self):
462 self._test_rssi_vs_atten()
463
464 @test_tracker_info(uuid='e9d258ca-8e70-408e-b704-782fce7a07c5')
465 def test_rssi_vs_atten_ch4_VHT20_ActiveTraffic(self):
466 self._test_rssi_vs_atten()
467
468 @test_tracker_info(uuid='1c5d71a0-7532-49e4-98a9-1c2d9d8d58d2')
469 def test_rssi_vs_atten_ch5_VHT20_ActiveTraffic(self):
470 self._test_rssi_vs_atten()
471
472 @test_tracker_info(uuid='107f01f3-b6b9-470b-9895-6345edfc9599')
473 def test_rssi_vs_atten_ch6_VHT20_ActiveTraffic(self):
474 self._test_rssi_vs_atten()
475
476 @test_tracker_info(uuid='88cb18b2-30bf-4c01-ac28-15451289e7cd')
477 def test_rssi_vs_atten_ch7_VHT20_ActiveTraffic(self):
478 self._test_rssi_vs_atten()
479
480 @test_tracker_info(uuid='c07a7442-bd1d-40c7-80ed-167e30b8cfaf')
481 def test_rssi_vs_atten_ch8_VHT20_ActiveTraffic(self):
482 self._test_rssi_vs_atten()
483
484 @test_tracker_info(uuid='b8946280-88d5-400d-a417-2bdc9d7e054a')
485 def test_rssi_vs_atten_ch9_VHT20_ActiveTraffic(self):
486 self._test_rssi_vs_atten()
487
488 @test_tracker_info(uuid='a05db91b-740d-4984-a447-79ab438034f0')
489 def test_rssi_vs_atten_ch10_VHT20_ActiveTraffic(self):
490 self._test_rssi_vs_atten()
491
492 @test_tracker_info(uuid='f4d565f8-f060-462c-9b3c-cd1f7d27b3ea')
493 def test_rssi_vs_atten_ch11_VHT20_ActiveTraffic(self):
494 self._test_rssi_vs_atten()
495
Omar El Ayach19a55672018-03-09 00:53:12 +0000496
497class WifiRssi_5GHz_ActiveTraffic_Test(WifiRssiTest):
498 def __init__(self, controllers):
499 base_test.BaseTestClass.__init__(self, controllers)
500
Omar El Ayachb8808082018-03-04 01:05:39 +0000501 @test_tracker_info(uuid='a33a93ac-604a-414f-ae96-42dffbe59a93')
502 def test_rssi_vs_atten_ch36_VHT20_ActiveTraffic(self):
503 self._test_rssi_vs_atten()
504
505 @test_tracker_info(uuid='39875ab0-e0e9-464b-8a47-4dedd65f066e')
506 def test_rssi_vs_atten_ch36_VHT40_ActiveTraffic(self):
507 self._test_rssi_vs_atten()
508
509 @test_tracker_info(uuid='c6ff8768-f124-4190-baf2-bbf14b612de3')
510 def test_rssi_vs_atten_ch36_VHT80_ActiveTraffic(self):
511 self._test_rssi_vs_atten()
512
513 @test_tracker_info(uuid='ed4705af-e202-4737-b410-8bab0515e79f')
514 def test_rssi_vs_atten_ch40_VHT20_ActiveTraffic(self):
515 self._test_rssi_vs_atten()
516
517 @test_tracker_info(uuid='1388df99-ecbf-4412-9ded-d66552f37ec5')
518 def test_rssi_vs_atten_ch44_VHT20_ActiveTraffic(self):
519 self._test_rssi_vs_atten()
520
521 @test_tracker_info(uuid='06868677-ad3c-4f50-9b9e-ae8d9455ae4d')
522 def test_rssi_vs_atten_ch44_VHT40_ActiveTraffic(self):
523 self._test_rssi_vs_atten()
524
525 @test_tracker_info(uuid='9b6676de-c736-4603-a9b3-97670bea8f25')
526 def test_rssi_vs_atten_ch48_VHT20_ActiveTraffic(self):
527 self._test_rssi_vs_atten()
528
529 @test_tracker_info(uuid='2641c4b8-0092-4e29-9139-fdb3b3f04d05')
530 def test_rssi_vs_atten_ch149_VHT20_ActiveTraffic(self):
531 self._test_rssi_vs_atten()
532
533 @test_tracker_info(uuid='c8bc3f7d-b459-4e40-9c73-b0bf534c6c08')
534 def test_rssi_vs_atten_ch149_VHT40_ActiveTraffic(self):
535 self._test_rssi_vs_atten()
536
537 @test_tracker_info(uuid='3e08f5b6-9f3c-4905-8b10-82e1ca830cc9')
538 def test_rssi_vs_atten_ch149_VHT80_ActiveTraffic(self):
539 self._test_rssi_vs_atten()
540
541 @test_tracker_info(uuid='2343efe3-fdda-4180-add7-4786d35e29bb')
542 def test_rssi_vs_atten_ch153_VHT20_ActiveTraffic(self):
543 self._test_rssi_vs_atten()
544
545 @test_tracker_info(uuid='89a16974-2399-4356-b720-17b765ff1c3a')
546 def test_rssi_vs_atten_ch157_VHT20_ActiveTraffic(self):
547 self._test_rssi_vs_atten()
548
549 @test_tracker_info(uuid='c8e0e44a-b962-4e71-ba8f-068f268c8823')
550 def test_rssi_vs_atten_ch157_VHT40_ActiveTraffic(self):
551 self._test_rssi_vs_atten()
552
553 @test_tracker_info(uuid='581b5794-239e-4d1c-b0ce-7c6dc5bd373f')
554 def test_rssi_vs_atten_ch161_VHT20_ActiveTraffic(self):
555 self._test_rssi_vs_atten()