| #!/usr/bin/env python3 |
| # |
| # Copyright 2018 - The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the 'License'); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an 'AS IS' BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import ntpath |
| import time |
| |
| from acts.controllers.anritsu_lib import md8475_cellular_simulator as anritsusim |
| from acts.controllers.anritsu_lib.md8475a import BtsNumber |
| from acts.controllers.anritsu_lib.md8475a import BtsPacketRate |
| from acts.controllers.cellular_lib.BaseSimulation import BaseSimulation |
| from acts.controllers.cellular_lib import BaseCellularDut |
| |
| |
| class UmtsSimulation(BaseSimulation): |
| """ Single base station simulation. """ |
| |
| # Simulation config files in the callbox computer. |
| # These should be replaced in the future by setting up |
| # the same configuration manually. |
| |
| UMTS_BASIC_SIM_FILE = 'SIM_default_WCDMA.wnssp' |
| |
| UMTS_R99_CELL_FILE = 'CELL_WCDMA_R99_config.wnscp' |
| |
| UMTS_R7_CELL_FILE = 'CELL_WCDMA_R7_config.wnscp' |
| |
| UMTS_R8_CELL_FILE = 'CELL_WCDMA_R8_config.wnscp' |
| |
| # Configuration dictionary keys |
| PARAM_RELEASE_VERSION = "r" |
| PARAM_RELEASE_VERSION_99 = "99" |
| PARAM_RELEASE_VERSION_8 = "8" |
| PARAM_RELEASE_VERSION_7 = "7" |
| PARAM_BAND = "band" |
| PARAM_RRC_STATUS_CHANGE_TIMER = "rrcstatuschangetimer" |
| |
| # Units in which signal level is defined in DOWNLINK_SIGNAL_LEVEL_DICTIONARY |
| DOWNLINK_SIGNAL_LEVEL_UNITS = "RSCP" |
| |
| # RSCP signal levels thresholds (as reported by Android). Units are dBm |
| # Using LTE thresholds + 24 dB to have equivalent SPD |
| # 24 dB comes from 10 * log10(3.84 MHz / 15 KHz) |
| |
| DOWNLINK_SIGNAL_LEVEL_DICTIONARY = { |
| 'excellent': -51, |
| 'high': -76, |
| 'medium': -86, |
| 'weak': -96 |
| } |
| |
| # Transmitted output power for the phone |
| # Stronger Tx power means that the signal received by the BTS is weaker |
| # Units are dBm |
| |
| UPLINK_SIGNAL_LEVEL_DICTIONARY = { |
| 'low': -20, |
| 'medium': 8, |
| 'high': 15, |
| 'max': 23 |
| } |
| |
| # Converts packet rate to the throughput that can be actually obtained in |
| # Mbits/s |
| |
| packet_rate_to_dl_throughput = { |
| BtsPacketRate.WCDMA_DL384K_UL64K: 0.362, |
| BtsPacketRate.WCDMA_DL21_6M_UL5_76M: 18.5, |
| BtsPacketRate.WCDMA_DL43_2M_UL5_76M: 36.9 |
| } |
| |
| packet_rate_to_ul_throughput = { |
| BtsPacketRate.WCDMA_DL384K_UL64K: 0.0601, |
| BtsPacketRate.WCDMA_DL21_6M_UL5_76M: 5.25, |
| BtsPacketRate.WCDMA_DL43_2M_UL5_76M: 5.25 |
| } |
| |
| def __init__(self, simulator, log, dut, test_config, calibration_table): |
| """ Initializes the cellular simulator for a UMTS simulation. |
| |
| Loads a simple UMTS simulation environment with 1 basestation. It also |
| creates the BTS handle so we can change the parameters as desired. |
| |
| Args: |
| simulator: a cellular simulator controller |
| log: a logger handle |
| dut: a device handler implementing BaseCellularDut |
| test_config: test configuration obtained from the config file |
| calibration_table: a dictionary containing path losses for |
| different bands. |
| |
| """ |
| # The UMTS simulation relies on the cellular simulator to be a MD8475 |
| if not isinstance(self.simulator, anritsusim.MD8475CellularSimulator): |
| raise ValueError('The UMTS simulation relies on the simulator to ' |
| 'be an Anritsu MD8475 A/B instrument.') |
| |
| # The Anritsu controller needs to be unwrapped before calling |
| # super().__init__ because setup_simulator() requires self.anritsu and |
| # will be called during the parent class initialization. |
| self.anritsu = self.simulator.anritsu |
| self.bts1 = self.anritsu.get_BTS(BtsNumber.BTS1) |
| |
| super().__init__(simulator, log, dut, test_config, calibration_table) |
| |
| self.dut.set_preferred_network_type( |
| BaseCellularDut.PreferredNetworkType.WCDMA_ONLY) |
| |
| self.release_version = None |
| self.packet_rate = None |
| |
| def setup_simulator(self): |
| """ Do initial configuration in the simulator. """ |
| |
| # Load callbox config files |
| callbox_config_path = self.CALLBOX_PATH_FORMAT_STR.format( |
| self.anritsu._md8475_version) |
| |
| self.anritsu.load_simulation_paramfile( |
| ntpath.join(callbox_config_path, self.UMTS_BASIC_SIM_FILE)) |
| |
| # Start simulation if it wasn't started |
| self.anritsu.start_simulation() |
| |
| def configure(self, parameters): |
| """ Configures simulation using a dictionary of parameters. |
| |
| Processes UMTS configuration parameters. |
| |
| Args: |
| parameters: a configuration dictionary |
| """ |
| super().configure(parameters) |
| |
| # Setup band |
| if self.PARAM_BAND not in parameters: |
| raise ValueError( |
| "The configuration dictionary must include a key '{}' with " |
| "the required band number.".format(self.PARAM_BAND)) |
| |
| self.set_band(self.bts1, parameters[self.PARAM_BAND]) |
| self.load_pathloss_if_required() |
| |
| # Setup release version |
| if (self.PARAM_RELEASE_VERSION not in parameters |
| or parameters[self.PARAM_RELEASE_VERSION] not in [ |
| self.PARAM_RELEASE_VERSION_7, self.PARAM_RELEASE_VERSION_8, |
| self.PARAM_RELEASE_VERSION_99 |
| ]): |
| raise ValueError( |
| "The configuration dictionary must include a key '{}' with a " |
| "valid release version.".format(self.PARAM_RELEASE_VERSION)) |
| |
| self.set_release_version(self.bts1, |
| parameters[self.PARAM_RELEASE_VERSION]) |
| |
| # Setup W-CDMA RRC status change and CELL_DCH timer for idle test case |
| if self.PARAM_RRC_STATUS_CHANGE_TIMER not in parameters: |
| self.log.info( |
| "The config dictionary does not include a '{}' key. Disabled " |
| "by default.".format(self.PARAM_RRC_STATUS_CHANGE_TIMER)) |
| self.anritsu.set_umts_rrc_status_change(False) |
| else: |
| self.rrc_sc_timer = int( |
| parameters[self.PARAM_RRC_STATUS_CHANGE_TIMER]) |
| self.anritsu.set_umts_rrc_status_change(True) |
| self.anritsu.set_umts_dch_stat_timer(self.rrc_sc_timer) |
| |
| def set_release_version(self, bts, release_version): |
| """ Sets the release version. |
| |
| Loads the cell parameter file matching the requested release version. |
| Does nothing is release version is already the one requested. |
| |
| """ |
| |
| if release_version == self.release_version: |
| self.log.info( |
| "Release version is already {}.".format(release_version)) |
| return |
| if release_version == self.PARAM_RELEASE_VERSION_99: |
| |
| cell_parameter_file = self.UMTS_R99_CELL_FILE |
| self.packet_rate = BtsPacketRate.WCDMA_DL384K_UL64K |
| |
| elif release_version == self.PARAM_RELEASE_VERSION_7: |
| |
| cell_parameter_file = self.UMTS_R7_CELL_FILE |
| self.packet_rate = BtsPacketRate.WCDMA_DL21_6M_UL5_76M |
| |
| elif release_version == self.PARAM_RELEASE_VERSION_8: |
| |
| cell_parameter_file = self.UMTS_R8_CELL_FILE |
| self.packet_rate = BtsPacketRate.WCDMA_DL43_2M_UL5_76M |
| |
| else: |
| raise ValueError("Invalid UMTS release version number.") |
| |
| self.anritsu.load_cell_paramfile( |
| ntpath.join(self.callbox_config_path, cell_parameter_file)) |
| |
| self.release_version = release_version |
| |
| # Loading a cell parameter file stops the simulation |
| self.start() |
| |
| bts.packet_rate = self.packet_rate |
| |
| def maximum_downlink_throughput(self): |
| """ Calculates maximum achievable downlink throughput in the current |
| simulation state. |
| |
| Returns: |
| Maximum throughput in mbps. |
| |
| """ |
| |
| if self.packet_rate not in self.packet_rate_to_dl_throughput: |
| raise NotImplementedError("Packet rate not contained in the " |
| "throughput dictionary.") |
| return self.packet_rate_to_dl_throughput[self.packet_rate] |
| |
| def maximum_uplink_throughput(self): |
| """ Calculates maximum achievable uplink throughput in the current |
| simulation state. |
| |
| Returns: |
| Maximum throughput in mbps. |
| |
| """ |
| |
| if self.packet_rate not in self.packet_rate_to_ul_throughput: |
| raise NotImplementedError("Packet rate not contained in the " |
| "throughput dictionary.") |
| return self.packet_rate_to_ul_throughput[self.packet_rate] |
| |
| def set_downlink_rx_power(self, bts, signal_level): |
| """ Starts IP data traffic while setting downlink power. |
| |
| This is only necessary for UMTS for unclear reasons. b/139026916 """ |
| |
| # Starts IP traffic while changing this setting to force the UE to be |
| # in Communication state, as UL power cannot be set in Idle state |
| self.start_traffic_for_calibration() |
| |
| # Wait until it goes to communication state |
| self.anritsu.wait_for_communication_state() |
| |
| super().set_downlink_rx_power(bts, signal_level) |
| |
| # Stop IP traffic after setting the signal level |
| self.stop_traffic_for_calibration() |
| |
| def set_band(self, bts, band): |
| """ Sets the band used for communication. |
| |
| Args: |
| bts: basestation handle |
| band: desired band |
| """ |
| |
| bts.band = band |
| time.sleep(5) # It takes some time to propagate the new band |