1#!/usr/bin/env python3
2#
3#   Copyright 2019 - 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 csv
18import itertools
19import os
20import re
21import time
22
23from collections import OrderedDict
24from functools import partial
25
26import acts.base_test
27import acts.controllers.rohdeschwarz_lib.cmw500 as cmw500
28from acts.test_utils.coex.hotspot_utils import band_channel_map
29from acts.test_utils.coex.hotspot_utils import supported_lte_bands
30from acts.test_utils.coex.hotspot_utils import tdd_band_list
31from acts.test_utils.coex.hotspot_utils import wifi_channel_map
32from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
33from acts.test_utils.wifi.wifi_test_utils import reset_wifi
34from acts.test_utils.wifi.wifi_test_utils import start_wifi_tethering
35from acts.test_utils.wifi.wifi_test_utils import stop_wifi_tethering
36from acts.test_utils.wifi.wifi_test_utils import wifi_connect
37from acts.test_utils.wifi.wifi_test_utils import WifiEnums
38
39BANDWIDTH_2G = 20
40CNSS_LOG_PATH = '/data/vendor/wifi/wlan_logs'
41CNSS_CMD = 'cnss_diag -f -s'
42
43
44class HotspotWiFiChannelTest(acts.base_test.BaseTestClass):
45    """Idea behind this test is to check which wifi channel gets picked with
46    different lte bands(low, mid and high frequencies) when connected via
47    hotspot from secondary device. As of now there is no failure condition
48    to check the channel picked for the particular lte band.
49    """
50    def __init__(self, controllers):
51        super().__init__(controllers)
52        req_params = ['callbox_params', 'network', 'lte_bands', 'hotspot_mode']
53        self.unpack_userparams(req_params)
54        self.tests = self.generate_test_cases()
55
56    def setup_class(self):
57        self.pri_ad = self.android_devices[0]
58        self.sec_ad = self.android_devices[1]
59        self.cmw = cmw500.Cmw500(self.callbox_params['host'],
60                                 self.callbox_params['port'])
61        # Get basestation object.
62        self.bts = self.cmw.get_base_station()
63        csv_header = ('Hotspot Mode', 'lte_band', 'LTE_dl_channel',
64                      'LTE_ul_freq', 'LTE_dl_freq', 'wifi_channel',
65                      'wifi_bandwidth')
66        self.write_data_to_csv(csv_header)
67
68    def setup_test(self):
69        self.pri_ad.adb.shell_nb(CNSS_CMD)
70
71    def teardown_test(self):
72        self.pri_ad.adb.shell('killall cnss_diag')
73        stop_wifi_tethering(self.pri_ad)
74        reset_wifi(self.sec_ad)
75        cnss_path = os.path.join(self.log_path, 'wlan_logs')
76        os.makedirs(cnss_path, exist_ok=True)
77        self.pri_ad.pull_files([CNSS_LOG_PATH], os.path.join(
78            cnss_path, self.current_test_name))
79        self.pri_ad.adb.shell('rm -rf {}'.format(CNSS_LOG_PATH))
80
81    def teardown_class(self):
82        self.cmw.disconnect()
83
84    def write_data_to_csv(self, data):
85        """Writes the data to csv file
86
87        Args:
88            data: data to be written into csv.
89        """
90        with open('{}/test_data.csv'.format(self.log_path), 'a',
91                  newline="") as cf:
92            csv_writer = csv.writer(cf, delimiter=',')
93            csv_writer.writerow(data)
94            cf.close()
95
96    def generate_test_cases(self):
97        # find and run only the supported bands.
98        lte_band = list(set(self.lte_bands).intersection(supported_lte_bands))
99
100        if len(lte_band) == 0:
101            # if lte_band in config is empty run all bands.
102            lte_band = supported_lte_bands
103
104        test_cases = []
105        for hmode, lband in itertools.product(self.hotspot_mode, lte_band):
106            for channel in band_channel_map.get(lband):
107                test_case_name = ('test_hotspot_lte_band_{}_channel_{}_wifi'
108                                  '_band_{}'.format(lband, channel, hmode))
109                test_params = OrderedDict(
110                    lte_band=lband,
111                    LTE_dl_channel=channel,
112                    hotspot_mode=hmode,
113                )
114                setattr(self, test_case_name, partial(self.set_hotspot_params,
115                                                      test_params))
116                test_cases.append(test_case_name)
117
118        return test_cases
119
120    def set_hotspot_params(self, test_params):
121        """Set up hot spot parameters.
122
123        Args:
124            test_params: Contains band and frequency of current test.
125        """
126        self.setup_lte_and_attach(test_params['lte_band'],
127                                  test_params['LTE_dl_channel'])
128        band = test_params['hotspot_mode'].lower()
129        self.initiate_wifi_tethering_and_connect(band)
130        test_params['LTE_ul_freq'] = self.bts.ul_frequency
131        test_params['LTE_dl_freq'] = self.bts.dl_frequency
132        test_params['wifi_channel'] = self.get_wifi_channel(self.sec_ad)
133        test_params['wifi_bandwidth'] = self.get_wifi_bandwidth(self.sec_ad)
134        data = (test_params['hotspot_mode'], test_params['lte_band'],
135                test_params['LTE_dl_channel'], test_params['LTE_ul_freq'],
136                test_params['LTE_dl_freq'], test_params['wifi_channel'],
137                test_params['wifi_bandwidth'])
138
139        self.write_data_to_csv(data)
140
141    def setup_lte_and_attach(self, band, channel):
142        """Setup callbox and attaches the device.
143
144        Args:
145            band: lte band to configure.
146            channel: channel to set for band.
147        """
148        toggle_airplane_mode(self.log, self.pri_ad, True)
149
150        # Reset system
151        self.cmw.reset()
152
153        if band in tdd_band_list:
154            self.bts.duplex_mode = cmw500.DuplexMode.TDD
155
156        # Turn ON LTE signalling
157        self.cmw.switch_lte_signalling(cmw500.LteState.LTE_ON)
158
159        # Set Signalling params
160        self.cmw.enable_packet_switching()
161        self.bts.downlink_power_level = '-59.8'
162
163        self.bts.band = band
164        self.bts.bandwidth = cmw500.LteBandwidth.BANDWIDTH_5MHz
165        self.bts.dl_channel = channel
166        time.sleep(1)
167        self.log.info('Callbox settings: band: {}, bandwidth: {}, '
168                      'dl_channel: {}, '.format(self.bts.band,
169                                                self.bts.bandwidth,
170                                                self.bts.dl_channel
171                                                ))
172
173        toggle_airplane_mode(self.log, self.pri_ad, False)
174        self.log.info('Waiting for device to attach.')
175        self.cmw.wait_for_attached_state()
176        self.log.info('Device attached with callbox.')
177        self.log.debug('Waiting for connected state.')
178        self.cmw.wait_for_rrc_state(cmw500.LTE_CONN_RESP)
179        self.log.info('Device connected with callbox')
180
181    def initiate_wifi_tethering_and_connect(self, wifi_band=None):
182        """Initiates wifi tethering and connects wifi.
183
184        Args:
185            wifi_band: Hotspot mode to set.
186        """
187        if wifi_band == '2g':
188            wband = WifiEnums.WIFI_CONFIG_APBAND_2G
189        elif wifi_band == '5g':
190            wutils.set_wifi_country_code(self.pri_ad, WifiEnums.CountryCode.US)
191            wutils.set_wifi_country_code(self.sec_ad, WifiEnums.CountryCode.US)
192            wband = WifiEnums.WIFI_CONFIG_APBAND_5G
193        elif wifi_band == 'auto':
194            wband = WifiEnums.WIFI_CONFIG_APBAND_AUTO
195        else:
196            raise ValueError('Invalid hotspot mode.')
197
198        start_wifi_tethering(self.pri_ad, self.network['SSID'],
199                             self.network['password'], band=wband)
200
201        wifi_connect(self.sec_ad, self.network, check_connectivity=False)
202
203    def get_wifi_channel(self, ad):
204        """Get the Wifi Channel for the SSID connected.
205
206        Args:
207            ad: Android device to get channel.
208
209        Returns:
210            wifi_channel: WiFi channel of connected device,
211
212        Raises:
213            Value Error on Failure.
214        """
215        out = ad.adb.shell('wpa_cli status')
216        match = re.search('freq=.*', out)
217        if match:
218            freq = match.group(0).split('=')[1]
219            wifi_channel = wifi_channel_map[int(freq)]
220            self.log.info('Channel Chosen: {}'.format(wifi_channel))
221            return wifi_channel
222        else:
223            raise ValueError('Wifi connection inactive.')
224
225    def get_wifi_bandwidth(self, ad):
226        """Gets the Wifi Bandwidth for the SSID connected.
227
228        Args:
229            ad: Android device to get bandwidth.
230
231        Returns:
232            bandwidth: if connected wifi is 5GHz.
233            2G_BANDWIDTH: if connected wifi is 2GHz,
234        """
235        out = ad.adb.shell('iw wlan0 link')
236        match = re.search(r'[0-9.]+MHz', out)
237        if match:
238            bandwidth = match.group(0).strip('MHz')
239            return bandwidth
240        else:
241            return BANDWIDTH_2G
242