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 os 18import re 19import time 20 21from acts import asserts 22import acts_contrib.test_utils.bt.bt_test_utils as bt_utils 23from acts_contrib.test_utils.bt.BtSarBaseTest import BtSarBaseTest 24 25 26class BtSarSanityTest(BtSarBaseTest): 27 """Class to run sanity checks on BT SAR mechanisms. 28 29 This class defines sanity test cases on BT SAR. The tests include 30 a software state sanity check and a software power sanity check. 31 """ 32 33 def setup_class(self): 34 super().setup_class() 35 36 self.reg_domain_dict = { 37 'US': 'bluetooth_power_limits_US.csv', 38 'EU': 'bluetooth_power_limits_EU.csv', 39 'JP': 'bluetooth_power_limits_JP.csv' 40 } 41 42 #Backup BT SAR files on the device 43 for key in self.reg_domain_dict.keys(): 44 reg_file_path = os.path.join( 45 os.path.dirname(self.power_file_paths[0]), 46 self.reg_domain_dict[key]) 47 self.dut.adb.shell('cp {} {}.backup'.format( 48 reg_file_path, reg_file_path)) 49 50 self.log.info('Regulatory files backed up') 51 52 def setup_test(self): 53 54 #Reset SAR test result to 0 before every test 55 self.sar_test_result.metric_value = 0 56 57 # Starting BT on the master 58 self.dut.droid.bluetoothFactoryReset() 59 bt_utils.enable_bluetooth(self.dut.droid, self.dut.ed) 60 61 def teardown_class(self): 62 for key in self.reg_domain_dict.keys(): 63 reg_file_path = os.path.join( 64 os.path.dirname(self.power_file_paths[0]), 65 self.reg_domain_dict[key]) 66 self.dut.adb.shell('mv {}.backup {}'.format( 67 reg_file_path, reg_file_path)) 68 69 self.log.info('Regulatory files restored') 70 71 self.dut.reboot() #TODO: make this better 72 super().teardown_class() 73 74 def test_bt_sar_sanity_check_state(self): 75 """ Test for BT SAR State Sanity 76 77 BT SAR Software Sanity Test to ensure that the correct signal state 78 gets propagated to the firmware. This is done by comparing expected 79 device state with that read from device's logcat 80 """ 81 #Iterating through the BT SAR scenarios 82 for scenario in range(0, self.bt_sar_df.shape[0]): 83 # Reading BT SAR table row into dict 84 read_scenario = self.bt_sar_df.loc[scenario].to_dict() 85 86 start_time = self.dut.adb.shell('date +%s.%m') 87 time.sleep(1) 88 89 #Setting SAR state to the read BT SAR row 90 enforced_state = self.set_sar_state(self.dut, read_scenario, 91 self.country_code) 92 93 #Reading device state from logcat after forcing SAR State 94 device_state = self.get_current_device_state(self.dut, start_time) 95 96 #Comparing read device state to expected device state 97 for key in enforced_state.keys(): 98 key_regex = r'{}:\s*(\d)'.format(key) 99 try: 100 propagated_value = int( 101 re.findall(key_regex, device_state)[0]) 102 except IndexError: 103 propagated_value = 'NA' 104 105 if enforced_state[key] == propagated_value: 106 self.sar_test_result.metric_value = 1 107 self.log.info( 108 'scenario: {}, state : {}, forced_value: {}, value:{}'. 109 format(scenario, key, enforced_state[key], 110 propagated_value)) 111 else: 112 self.log.error( 113 'scenario:{}, state : {}, forced_value: {}, value:{}'. 114 format(scenario, key, enforced_state[key], 115 propagated_value)) 116 117 def test_bt_sar_sanity_check_power(self): 118 """ Test for BT SAR Power Cap Sanity 119 120 BT SAR Power Cap Sanity Test to ensure that the correct SAR power 121 cap corresponding to the forced SAR state gets propagated to the 122 firmware. This is done by comparing expected power cap read from 123 the BT SAR file to the power cap read from logcat 124 """ 125 126 power_cap_error = self.sweep_power_cap() 127 128 if power_cap_error: 129 asserts.fail("Power Caps didn't match powers in the SAR table") 130 else: 131 self.sar_test_result.metric_value = 1 132 asserts.explicit_pass('Power Caps were set according to the table') 133 134 def test_bt_sar_sanity_country_code(self): 135 """ Test for BT SAR Country Code Sanity 136 137 BT SAR Country Code Sanity Test to ensure that the correct SAR 138 regulatory domain corresponding to the forced SAR country code gets 139 propagated to the firmware. This is done by comparing forced regulatory 140 domain to regulatory domain read from logcat. 141 """ 142 143 error_flag = 0 144 for country_code_tuple in self.REG_DOMAIN_DICT.keys(): 145 for country_code in country_code_tuple: 146 start_time = self.dut.adb.shell('date +%s.%m') 147 148 time.sleep(1) 149 #Force country code using adb command 150 self.set_country_code(self.dut, country_code) 151 152 #Read regulatory code from logcat 153 set_regulatory_domain = self.get_country_code( 154 self.dut, start_time) 155 156 if set_regulatory_domain != self.REG_DOMAIN_DICT[country_code_tuple]: 157 error_flag = 1 158 self.log.error( 159 'Country Code: {} set to regulatory domain: {}'.format( 160 country_code, set_regulatory_domain)) 161 else: 162 self.log.info( 163 'Country Code: {} set to regulatory domain: {}'.format( 164 country_code, set_regulatory_domain)) 165 166 if error_flag: 167 asserts.fail( 168 'Regulatory domains not set according to country code') 169 else: 170 self.sar_test_result.metric_value = 1 171 asserts.explicit_pass( 172 'Regulatory domains set according to country code') 173 174 def test_bt_sar_sanity_reg_domain(self): 175 """ Test for BT SAR Regulatory Domain Sanity 176 177 BT SAR Regulatory Domain Sanity Test to ensure that the correct 178 SAR regulatory domain TX powers get propagated to the firmware. 179 This is done by measuring the TX power for different 180 regulatory domain files 181 """ 182 183 reg_domain_test_error_flag = True 184 reg_file_phone_path = os.path.dirname(self.sar_file_path) 185 186 #For different reg domain, sweep the sar table 187 for cc, reg_domain in self.REG_DOMAIN_DICT.items(): 188 self.country_code = cc[0] 189 for file in self.custom_files: 190 if 'bluetooth_power_limits_{}.csv'.format(reg_domain) in file: 191 custom_reg_file = file 192 reg_file_name = os.path.join( 193 reg_file_phone_path, 194 'bluetooth_power_limits_{}.csv'.format(reg_domain)) 195 break 196 else: 197 self.log.error( 198 'Regulatory file for {} missing'.format(reg_domain)) 199 200 self.push_table(self.dut, custom_reg_file, reg_file_name) 201 202 start_time = self.dut.adb.shell('date +%s.%m') 203 self.set_country_code(self.dut, cc[0]) 204 # Read regulatory code from logcat 205 read_reg_domain = self.get_country_code(self.dut, start_time) 206 self.log.info( 207 'Regulatory domain set to {}'.format(read_reg_domain)) 208 self.bt_sar_df = self.read_sar_table(self.dut, custom_reg_file) 209 210 reg_domain_error_flag = self.sweep_power_cap() 211 212 if not reg_domain_error_flag: 213 self.log.info( 214 'Regulatory Domain Sanity Test for {} passed'.format( 215 reg_domain)) 216 217 reg_domain_test_error_flag &= reg_domain_error_flag 218 219 if reg_domain_test_error_flag: 220 asserts.fail('Regulatory domain sanity tests failed') 221 else: 222 self.sar_test_result.metric_value = 1 223 asserts.explicit_pass('Regulatory domain sanity tests passed') 224