blob: 1e6081362c2c7d674801198757098fad29edc5c7 [file] [log] [blame]
#!/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