| # Copyright 2022 - 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. |
| |
| from acts.controllers.cellular_lib.BaseSimulation import BaseSimulation |
| from acts.controllers.cellular_lib import BaseCellularDut |
| |
| |
| class PresetSimulation(BaseSimulation): |
| """5G preset simulation. |
| |
| The simulation will be configed by importing SCPI config file |
| instead of individually set params. |
| """ |
| |
| # Keys to obtain settings from the test_config dictionary. |
| KEY_CELL_INFO = "cell_info" |
| KEY_SCPI_FILE_NAME = "scpi_file" |
| |
| NETWORK_BIT_MASK = { |
| 'nr_lte': '11000001000000000000' |
| } |
| ADB_CMD_LOCK_NETWORK = 'cmd phone set-allowed-network-types-for-users -s 0 {network_bit_mask}' |
| NR_LTE_BIT_MASK_KEY = 'nr_lte' |
| |
| def __init__(self, |
| simulator, |
| log, |
| dut, |
| test_config, |
| calibration_table, |
| nr_mode=None): |
| """Initializes the simulator for 5G preset simulation. |
| |
| 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. |
| """ |
| |
| super().__init__(simulator, log, dut, test_config, calibration_table, |
| nr_mode) |
| # require param for idle test case |
| self.rrc_sc_timer = 0 |
| |
| # Set to KeySight APN |
| log.info('Configuring APN.') |
| self.dut.set_apn('Keysight', 'Keysight') |
| self.num_carriers = None |
| |
| # Enable roaming on the phone |
| self.dut.toggle_data_roaming(True) |
| |
| def setup_simulator(self): |
| """Do initial configuration in the simulator. """ |
| self.log.info('This simulation does not require initial setup.') |
| |
| def configure(self, parameters): |
| """Configures simulation by importing scpi file. |
| |
| A pre-made SCPI file include all the essential configuration |
| for the simulation is imported by send SCPI import command |
| to the callbox. |
| |
| Args: |
| parameters: a configuration dictionary which includes scpi file path |
| if there is only one carrier, a list if there are multiple cells. |
| """ |
| scpi_file = parameters[0][self.KEY_SCPI_FILE_NAME] |
| cell_infos = parameters[0][self.KEY_CELL_INFO] |
| |
| self.log.info('Configure test scenario with\n' + |
| f' SCPI config file: {scpi_file}\n' + |
| f' cell info: {cell_infos}') |
| |
| self.simulator.import_configuration(scpi_file) |
| self.simulator.set_cell_info(cell_infos) |
| |
| def start(self): |
| """Start simulation. |
| |
| Waiting for the DUT to connect to the callbox. |
| |
| Raise: |
| RuntimeError: simulation fail to start |
| due to unable to connect dut and cells. |
| """ |
| self.attach() |
| |
| def attach(self): |
| """Attach UE to the callbox. |
| |
| Toggle airplane mode on-off and wait for a specified timeout, |
| repeat until the UE connect to the callbox. |
| |
| Raise: |
| RuntimeError: attaching fail |
| due to unable to connect dut and cells. |
| """ |
| try: |
| self.simulator.wait_until_attached(self.dut, self.attach_timeout, |
| self.attach_retries) |
| except Exception as exc: |
| raise RuntimeError('Could not attach to base station.') from exc |
| |
| def calibrated_downlink_rx_power(self, bts_config, rsrp): |
| """Convert RSRP to total signal power from the basestation. |
| |
| Args: |
| bts_config: the current configuration at the base station |
| rsrp: desired rsrp, contained in a key value pair |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def downlink_calibration(self, rat=None, power_units_conversion_func=None): |
| """Computes downlink path loss and returns the calibration value. |
| |
| See base class implementation for details. |
| |
| Args: |
| rat: ignored, replaced by 'lteRsrp'. |
| power_units_conversion_func: ignored, replaced by |
| self.rsrp_to_signal_power. |
| |
| Returns: |
| Downlink calibration value and measured DL power. Note that the |
| phone only reports RSRP of the primary chain |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def rsrp_to_signal_power(self, rsrp, bts_config): |
| """Converts rsrp to total band signal power |
| |
| RSRP is measured per subcarrier, so total band power needs to be |
| multiplied by the number of subcarriers being used. |
| |
| Args: |
| rsrp: desired rsrp in dBm. |
| bts_config: a base station configuration object. |
| |
| Returns: |
| Total band signal power in dBm |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def maximum_downlink_throughput(self): |
| """Calculates maximum achievable downlink throughput in. |
| |
| The calculation is based on the current simulation state |
| Returns: |
| Maximum throughput in mbps. |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def bts_maximum_downlink_throughtput(self, bts_config): |
| """Calculates maximum achievable downlink throughput for a single |
| |
| base station from its configuration object. |
| |
| Args: |
| bts_config: a base station configuration object. |
| |
| Returns: |
| Maximum throughput in mbps. |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def maximum_uplink_throughput(self): |
| """Calculates maximum achievable uplink throughput. |
| |
| Returns: |
| Maximum throughput in mbps. |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def bts_maximum_uplink_throughtput(self, bts_config): |
| """Calculates maximum achievable uplink throughput |
| |
| The calculation is for selected basestation |
| from its configuration object. |
| Args: |
| bts_config: an LTE base station configuration object. |
| |
| Returns: |
| Maximum throughput in mbps. |
| |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def calibrate(self, band): |
| """Calculates UL and DL path loss if it wasn't done before |
| |
| Before running the base class implementation, configure the base station |
| to only use one downlink antenna with maximum bandwidth. |
| |
| Args: |
| band: the band that is currently being calibrated. |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def start_traffic_for_calibration(self): |
| """If MAC padding is enabled, there is no need to start IP traffic. """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def stop_traffic_for_calibration(self): |
| """If MAC padding is enabled, IP traffic wasn't started. """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |
| |
| def get_measured_ul_power(self, samples=5, wait_after_sample=3): |
| """Calculates UL power. |
| |
| The calculation is based on measurements from the callbox |
| and the calibration data. |
| Args: |
| samples: the numble of samples to average |
| wait_after_sample: time in seconds to wait in between samples |
| |
| Returns: |
| the ul power at the UE antenna ports in dBs |
| """ |
| raise NotImplementedError( |
| 'This simulation mode does not support this configuration option') |