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 math 18import ntpath 19import time 20import acts.controllers.cellular_simulator as cc 21from acts.controllers.cellular_lib import LteSimulation 22from acts.controllers.anritsu_lib import md8475a 23from acts.controllers.anritsu_lib import _anritsu_utils as anritsu 24 25 26class MD8475CellularSimulator(cc.AbstractCellularSimulator): 27 28 MD8475_VERSION = 'A' 29 30 # Indicates if it is able to use 256 QAM as the downlink modulation for LTE 31 LTE_SUPPORTS_DL_256QAM = False 32 33 # Indicates if it is able to use 64 QAM as the uplink modulation for LTE 34 LTE_SUPPORTS_UL_64QAM = False 35 36 # Indicates if 4x4 MIMO is supported for LTE 37 LTE_SUPPORTS_4X4_MIMO = False 38 39 # The maximum number of carriers that this simulator can support for LTE 40 LTE_MAX_CARRIERS = 2 41 42 # The maximum power that the equipment is able to transmit 43 MAX_DL_POWER = -10 44 45 # Simulation config files in the callbox computer. 46 # These should be replaced in the future by setting up 47 # the same configuration manually. 48 LTE_BASIC_SIM_FILE = 'SIM_default_LTE.wnssp' 49 LTE_BASIC_CELL_FILE = 'CELL_LTE_config.wnscp' 50 LTE_CA_BASIC_SIM_FILE = 'SIM_LTE_CA.wnssp' 51 LTE_CA_BASIC_CELL_FILE = 'CELL_LTE_CA_config.wnscp' 52 53 # Filepath to the config files stored in the Anritsu callbox. Needs to be 54 # formatted to replace {} with either A or B depending on the model. 55 CALLBOX_CONFIG_PATH = 'C:\\Users\\MD8475A\\Documents\\DAN_configs\\' 56 57 def __init__(self, ip_address): 58 """ Initializes the cellular simulator. 59 60 Args: 61 ip_address: the ip address of the MD8475 instrument 62 """ 63 super().__init__() 64 65 try: 66 self.anritsu = md8475a.MD8475A(ip_address, 67 md8475_version=self.MD8475_VERSION) 68 except anritsu.AnritsuError: 69 raise cc.CellularSimulatorError('Could not connect to MD8475.') 70 71 self.bts = None 72 73 def destroy(self): 74 """ Sends finalization commands to the cellular equipment and closes 75 the connection. """ 76 self.anritsu.stop_simulation() 77 self.anritsu.disconnect() 78 79 def setup_lte_scenario(self): 80 """ Configures the equipment for an LTE simulation. """ 81 cell_file_name = self.LTE_BASIC_CELL_FILE 82 sim_file_name = self.LTE_BASIC_SIM_FILE 83 84 cell_file_path = ntpath.join(self.CALLBOX_CONFIG_PATH, cell_file_name) 85 sim_file_path = ntpath.join(self.CALLBOX_CONFIG_PATH, sim_file_name) 86 87 self.anritsu.load_simulation_paramfile(sim_file_path) 88 self.anritsu.load_cell_paramfile(cell_file_path) 89 90 # MD4875A supports only 2 carriers. The MD4875B class adds other cells. 91 self.bts = [ 92 self.anritsu.get_BTS(md8475a.BtsNumber.BTS1), 93 self.anritsu.get_BTS(md8475a.BtsNumber.BTS2) 94 ] 95 96 def set_band_combination(self, bands, mimo_modes): 97 """ Prepares the test equipment for the indicated band combination. 98 99 The reason why this is implemented in a separate method and not calling 100 LteSimulation.BtsConfig for each separate band is that configuring each 101 ssc cannot be done separately, as it is necessary to know which 102 carriers are on the same band in order to decide which RF outputs can 103 be shared in the test equipment. 104 105 Args: 106 bands: a list of bands represented as ints or strings 107 mimo_modes: a list of LteSimulation.MimoMode to use for each carrier 108 """ 109 self.num_carriers = len(bands) 110 111 # Validate the number of carriers. 112 if self.num_carriers > self.LTE_MAX_CARRIERS: 113 raise cc.CellularSimulatorError('The test equipment supports up ' 114 'to {} carriers.'.format( 115 self.LTE_MAX_CARRIERS)) 116 117 # Initialize the base stations in the test equipment 118 self.anritsu.set_simulation_model( 119 *[md8475a.BtsTechnology.LTE for _ in range(self.num_carriers)], 120 reset=False) 121 122 # If base stations use different bands, make sure that the RF cards are 123 # not being shared by setting the right maximum MIMO modes 124 if self.num_carriers == 2: 125 # RF cards are never shared when doing 2CA so 4X4 can be done in 126 # both base stations. 127 self.bts[0].mimo_support = md8475a.LteMimoMode.MIMO_4X4 128 self.bts[1].mimo_support = md8475a.LteMimoMode.MIMO_4X4 129 elif self.num_carriers == 3: 130 # 4X4 can only be done in the second base station if it is shared 131 # with the primary. If the RF cards cannot be shared, then at most 132 # 2X2 can be done. 133 self.bts[0].mimo_support = md8475a.LteMimoMode.MIMO_4X4 134 if bands[0] == bands[1]: 135 self.bts[1].mimo_support = md8475a.LteMimoMode.MIMO_4X4 136 else: 137 self.bts[1].mimo_support = md8475a.LteMimoMode.MIMO_2X2 138 self.bts[2].mimo_support = md8475a.LteMimoMode.MIMO_2X2 139 elif self.num_carriers > 3: 140 raise NotImplementedError('The controller doesn\'t implement more ' 141 'than 3 carriers for MD8475B yet.') 142 143 # Enable carrier aggregation if there is more than one carrier 144 if self.num_carriers > 1: 145 self.anritsu.set_carrier_aggregation_enabled() 146 147 # Restart the simulation as changing the simulation model will stop it. 148 self.anritsu.start_simulation() 149 150 def set_input_power(self, bts_index, input_power): 151 """ Sets the input power for the indicated base station. 152 153 Args: 154 bts_index: the base station number 155 input_power: the new input power 156 """ 157 nrb_ul = int(self.bts[bts_index].nrb_ul) 158 max_nrb_ul = self.bts[bts_index].max_nrb_ul 159 input_level = str( 160 round(input_power - 10 * math.log10(nrb_ul / max_nrb_ul), 1)) 161 if nrb_ul < max_nrb_ul: 162 self.log.info('Number of UL RBs ({}) is less than the maximum RB ' 163 'allocation ({}). Increasing UL reference power to ' 164 '{} dbm to compensate'.format( 165 nrb_ul, max_nrb_ul, input_level)) 166 self.bts[bts_index].input_level = input_level 167 168 def set_output_power(self, bts_index, output_power): 169 """ Sets the output power for the indicated base station. 170 171 Args: 172 bts_index: the base station number 173 output_power: the new output power 174 """ 175 self.bts[bts_index].output_level = output_power 176 177 def set_downlink_channel_number(self, bts_index, channel_number): 178 """ Sets the downlink channel number for the indicated base station. 179 180 Args: 181 bts_index: the base station number 182 channel_number: the new channel number 183 """ 184 # Temporarily adding this line to workaround a bug in the 185 # Anritsu callbox in which the channel number needs to be set 186 # to a different value before setting it to the final one. 187 self.bts[bts_index].dl_channel = str(int(channel_number + 1)) 188 time.sleep(8) 189 self.bts[bts_index].dl_channel = str(int(channel_number)) 190 191 def set_dl_256_qam_enabled(self, bts_index, enabled): 192 """ Determines what MCS table should be used for the downlink. 193 194 Args: 195 bts_index: the base station number 196 enabled: whether 256 QAM should be used 197 """ 198 if enabled and not self.LTE_SUPPORTS_DL_256QAM: 199 raise RuntimeError('256 QAM is not supported') 200 self.bts[bts_index].lte_dl_modulation_order = \ 201 md8475a.ModulationType.Q256 if enabled else md8475a.ModulationType.Q64 202 203 def set_ul_64_qam_enabled(self, bts_index, enabled): 204 """ Determines what MCS table should be used for the uplink. 205 206 Args: 207 bts_index: the base station number 208 enabled: whether 64 QAM should be used 209 """ 210 self.bts[bts_index].lte_ul_modulation_order = \ 211 md8475a.ModulationType.Q64 if enabled else md8475a.ModulationType.Q16 212 213 def set_mac_padding(self, bts_index, mac_padding): 214 """ Enables or disables MAC padding in the indicated base station. 215 216 Args: 217 bts_index: the base station number 218 mac_padding: the new MAC padding setting 219 """ 220 if mac_padding: 221 self.bts[bts_index].tbs_pattern = 'FULLALLOCATION' 222 else: 223 self.bts[bts_index].tbs_pattern = 'OFF' 224 225 def set_lte_rrc_state_change_timer(self, enabled, time=10): 226 """ Configures the LTE RRC state change timer. 227 228 Args: 229 enabled: a boolean indicating if the timer should be on or off. 230 time: time in seconds for the timer to expire 231 """ 232 self.anritsu.set_lte_rrc_status_change(enabled) 233 if enabled: 234 self.anritsu.set_lte_rrc_status_change_timer(time) 235 236 def set_cfi(self, bts_index, cfi): 237 """ Sets the Channel Format Indicator for the indicated base station. 238 239 Args: 240 bts_index: the base station number 241 cfi: the new CFI setting 242 """ 243 self.bts[bts_index].cfi = cfi 244 245 def set_paging_cycle(self, bts_index, cycle_duration): 246 """ Sets the paging cycle duration for the indicated base station. 247 248 Args: 249 bts_index: the base station number 250 cycle_duration: the new paging cycle duration in milliseconds 251 """ 252 # TODO (b/146068532): implement. 253 self.bts[bts_index].paging_duration = cycle_duration 254 255 def set_phich_resource(self, bts_index, phich): 256 """ Sets the PHICH Resource setting for the indicated base station. 257 258 Args: 259 bts_index: the base station number 260 phich: the new PHICH resource setting 261 """ 262 self.bts[bts_index].phich_resource = phich 263 264 def set_drx_connected_mode(self, bts_index, active): 265 """ Sets the DRX connected mode 266 267 Args: 268 bts_index: the base station number 269 active: Boolean indicating whether cDRX mode 270 is active 271 """ 272 mode = 'MANUAL' if active else 'OFF' 273 self.bts[bts_index].drx_connected_mode = mode 274 275 def set_drx_on_duration_timer(self, bts_index, timer): 276 """ Sets the amount of PDCCH subframes to wait for data after 277 waking up from a DRX cycle 278 279 Args: 280 bts_index: the base station number 281 timer: Number of PDCCH subframes to wait and check for user data 282 after waking from the DRX cycle 283 """ 284 self.bts[bts_index].drx_on_duration_timer = timer 285 286 def set_drx_inactivity_timer(self, bts_index, timer): 287 """ Sets the number of PDCCH subframes to wait before entering DRX mode 288 289 Args: 290 bts_index: the base station number 291 timer: The time interval to wait before entering DRX mode 292 """ 293 self.bts[bts_index].drx_inactivity_timer = timer 294 295 def set_drx_retransmission_timer(self, bts_index, timer): 296 """ Sets the number of consecutive PDCCH subframes to wait 297 for retransmission 298 299 Args: 300 bts_index: the base station number 301 timer: Number of PDCCH subframes to remain active 302 303 """ 304 self.bts[bts_index].drx_retransmission_timer = timer 305 306 def set_drx_long_cycle(self, bts_index, cycle): 307 """ Sets the amount of subframes representing a DRX long cycle. 308 309 Args: 310 bts_index: the base station number 311 cycle: The amount of subframes representing one long DRX cycle. 312 One cycle consists of DRX sleep + DRX on duration 313 """ 314 self.bts[bts_index].drx_long_cycle = cycle 315 316 def set_drx_long_cycle_offset(self, bts_index, offset): 317 """ Sets the offset used to determine the subframe number 318 to begin the long drx cycle 319 320 Args: 321 bts_index: the base station number 322 offset: Number in range 0 to (long cycle - 1) 323 """ 324 self.bts[bts_index].drx_long_cycle_offset = offset 325 326 def set_band(self, bts_index, band): 327 """ Sets the right duplex mode before switching to a new band. 328 329 Args: 330 bts_index: the base station number 331 band: desired band 332 """ 333 bts = self.bts[bts_index] 334 335 # The callbox won't restore the band-dependent default values if the 336 # request is to switch to the same band as the one the base station is 337 # currently using. To ensure that default values are restored, go to a 338 # different band before switching. 339 if int(bts.band) == band: 340 # Using bands 1 and 2 but it could be any others 341 bts.band = '1' if band != 1 else '2' 342 # Switching to config.band will be handled by the parent class 343 # implementation of this method. 344 345 bts.duplex_mode = self.get_duplex_mode(band).value 346 bts.band = band 347 time.sleep(5) # It takes some time to propagate the new band 348 349 def get_duplex_mode(self, band): 350 """ Determines if the band uses FDD or TDD duplex mode 351 352 Args: 353 band: a band number 354 Returns: 355 an variable of class DuplexMode indicating if band is FDD or TDD 356 """ 357 358 if 33 <= int(band) <= 46: 359 return LteSimulation.DuplexMode.TDD 360 else: 361 return LteSimulation.DuplexMode.FDD 362 363 def set_tdd_config(self, bts_index, config): 364 """ Sets the frame structure for TDD bands. 365 366 Args: 367 bts_index: the base station number 368 config: the desired frame structure. An int between 0 and 6. 369 """ 370 371 if not 0 <= config <= 6: 372 raise ValueError("The frame structure configuration has to be a " 373 "number between 0 and 6") 374 375 self.bts[bts_index].uldl_configuration = config 376 377 # Wait for the setting to propagate 378 time.sleep(5) 379 380 def set_ssf_config(self, bts_index, ssf_config): 381 """ Sets the Special Sub-Frame config number for the indicated 382 base station. 383 384 Args: 385 bts_index: the base station number 386 ssf_config: the new ssf config number 387 """ 388 # Cast to int in case it was passed as a string 389 ssf_config = int(ssf_config) 390 391 if not 0 <= ssf_config <= 9: 392 raise ValueError('The Special Sub-Frame configuration has to be a ' 393 'number between 0 and 9.') 394 395 self.bts[bts_index].tdd_special_subframe = ssf_config 396 397 def set_bandwidth(self, bts_index, bandwidth): 398 """ Sets the LTE channel bandwidth (MHz) 399 400 Args: 401 bts_index: the base station number 402 bandwidth: desired bandwidth (MHz) 403 """ 404 bts = self.bts[bts_index] 405 406 if bandwidth == 20: 407 bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_20MHz 408 elif bandwidth == 15: 409 bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_15MHz 410 elif bandwidth == 10: 411 bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_10MHz 412 elif bandwidth == 5: 413 bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_5MHz 414 elif bandwidth == 3: 415 bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_3MHz 416 elif bandwidth == 1.4: 417 bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_1dot4MHz 418 else: 419 msg = "Bandwidth = {} MHz is not valid for LTE".format(bandwidth) 420 self.log.error(msg) 421 raise ValueError(msg) 422 time.sleep(5) # It takes some time to propagate the new settings 423 424 def set_mimo_mode(self, bts_index, mimo): 425 """ Sets the number of DL antennas for the desired MIMO mode. 426 427 Args: 428 bts_index: the base station number 429 mimo: object of class MimoMode 430 """ 431 432 bts = self.bts[bts_index] 433 434 # If the requested mimo mode is not compatible with the current TM, 435 # warn the user before changing the value. 436 437 if mimo == LteSimulation.MimoMode.MIMO_1x1: 438 if bts.transmode not in [ 439 LteSimulation.TransmissionMode.TM1, 440 LteSimulation.TransmissionMode.TM7 441 ]: 442 self.log.warning( 443 "Using only 1 DL antennas is not allowed with " 444 "the current transmission mode. Changing the " 445 "number of DL antennas will override this " 446 "setting.") 447 bts.dl_antenna = 1 448 elif mimo == LteSimulation.MimoMode.MIMO_2x2: 449 if bts.transmode not in [ 450 LteSimulation.TransmissionMode.TM2, 451 LteSimulation.TransmissionMode.TM3, 452 LteSimulation.TransmissionMode.TM4, 453 LteSimulation.TransmissionMode.TM8, 454 LteSimulation.TransmissionMode.TM9 455 ]: 456 self.log.warning("Using two DL antennas is not allowed with " 457 "the current transmission mode. Changing the " 458 "number of DL antennas will override this " 459 "setting.") 460 bts.dl_antenna = 2 461 elif mimo == LteSimulation.MimoMode.MIMO_4x4 and \ 462 self.LTE_SUPPORTS_4X4_MIMO: 463 if bts.transmode not in [ 464 LteSimulation.TransmissionMode.TM2, 465 LteSimulation.TransmissionMode.TM3, 466 LteSimulation.TransmissionMode.TM4, 467 LteSimulation.TransmissionMode.TM9 468 ]: 469 self.log.warning("Using four DL antennas is not allowed with " 470 "the current transmission mode. Changing the " 471 "number of DL antennas will override this " 472 "setting.") 473 474 bts.dl_antenna = 4 475 else: 476 RuntimeError("The requested MIMO mode is not supported.") 477 478 def set_scheduling_mode(self, bts_index, scheduling, mcs_dl, mcs_ul, 479 nrb_dl, nrb_ul): 480 """ Sets the scheduling mode for LTE 481 482 Args: 483 bts_index: the base station number 484 scheduling: DYNAMIC or STATIC scheduling (Enum list) 485 mcs_dl: Downlink MCS (only for STATIC scheduling) 486 mcs_ul: Uplink MCS (only for STATIC scheduling) 487 nrb_dl: Number of RBs for downlink (only for STATIC scheduling) 488 nrb_ul: Number of RBs for uplink (only for STATIC scheduling) 489 """ 490 491 bts = self.bts[bts_index] 492 bts.lte_scheduling_mode = scheduling.value 493 494 if scheduling == LteSimulation.SchedulingMode.STATIC: 495 496 if not all([nrb_dl, nrb_ul, mcs_dl, mcs_ul]): 497 raise ValueError('When the scheduling mode is set to manual, ' 498 'the RB and MCS parameters are required.') 499 500 bts.packet_rate = md8475a.BtsPacketRate.LTE_MANUAL 501 bts.lte_mcs_dl = mcs_dl 502 bts.lte_mcs_ul = mcs_ul 503 bts.nrb_dl = nrb_dl 504 bts.nrb_ul = nrb_ul 505 506 time.sleep(5) # It takes some time to propagate the new settings 507 508 def lte_attach_secondary_carriers(self, ue_capability_enquiry): 509 """ Activates the secondary carriers for CA. Requires the DUT to be 510 attached to the primary carrier first. 511 512 Args: 513 ue_capability_enquiry: UE capability enquiry message to be sent to 514 the UE before starting carrier aggregation. 515 """ 516 517 # Trigger UE capability enquiry from network to get 518 # UE supported CA band combinations. Here freq_bands is a hex string. 519 self.anritsu.trigger_ue_capability_enquiry(ue_capability_enquiry) 520 521 testcase = self.anritsu.get_AnritsuTestCases() 522 # A bug in the instrument's software (b/139547391) requires the test 523 # procedure to be set to whatever was the previous configuration before 524 # setting it to MULTICELL. 525 testcase.procedure = md8475a.TestProcedure(testcase.procedure) 526 testcase.procedure = md8475a.TestProcedure.PROCEDURE_MULTICELL 527 testcase.power_control = md8475a.TestPowerControl.POWER_CONTROL_DISABLE 528 testcase.measurement_LTE = md8475a.TestMeasurement.MEASUREMENT_DISABLE 529 530 # Enable the secondary carrier base stations for CA 531 for bts_index in range(1, self.num_carriers): 532 self.bts[bts_index].dl_cc_enabled = True 533 534 self.anritsu.start_testcase() 535 536 retry_counter = 0 537 self.log.info("Waiting for the test case to start...") 538 time.sleep(5) 539 540 while self.anritsu.get_testcase_status() == "0": 541 retry_counter += 1 542 if retry_counter == 3: 543 raise RuntimeError( 544 "The test case failed to start after {} " 545 "retries. The connection between the phone " 546 "and the base station might be unstable.".format( 547 retry_counter)) 548 time.sleep(10) 549 550 def set_transmission_mode(self, bts_index, tmode): 551 """ Sets the transmission mode for the LTE basetation 552 553 Args: 554 bts_index: the base station number 555 tmode: Enum list from class 'TransmissionModeLTE' 556 """ 557 558 bts = self.bts[bts_index] 559 560 # If the selected transmission mode does not support the number of DL 561 # antennas, throw an exception. 562 if (tmode in [ 563 LteSimulation.TransmissionMode.TM1, 564 LteSimulation.TransmissionMode.TM7 565 ] and bts.dl_antenna != '1'): 566 # TM1 and TM7 only support 1 DL antenna 567 raise ValueError("{} allows only one DL antenna. Change the " 568 "number of DL antennas before setting the " 569 "transmission mode.".format(tmode.value)) 570 elif (tmode == LteSimulation.TransmissionMode.TM8 571 and bts.dl_antenna != '2'): 572 # TM8 requires 2 DL antennas 573 raise ValueError("TM2 requires two DL antennas. Change the " 574 "number of DL antennas before setting the " 575 "transmission mode.") 576 elif (tmode in [ 577 LteSimulation.TransmissionMode.TM2, 578 LteSimulation.TransmissionMode.TM3, 579 LteSimulation.TransmissionMode.TM4, 580 LteSimulation.TransmissionMode.TM9 581 ] and bts.dl_antenna == '1'): 582 # TM2, TM3, TM4 and TM9 require 2 or 4 DL antennas 583 raise ValueError("{} requires at least two DL atennas. Change the " 584 "number of DL antennas before setting the " 585 "transmission mode.".format(tmode.value)) 586 587 # The TM mode is allowed for the current number of DL antennas, so it 588 # is safe to change this setting now 589 bts.transmode = tmode.value 590 591 time.sleep(5) # It takes some time to propagate the new settings 592 593 def wait_until_attached(self, timeout=120): 594 """ Waits until the DUT is attached to the primary carrier. 595 596 Args: 597 timeout: after this amount of time the method will raise a 598 CellularSimulatorError exception. Default is 120 seconds. 599 """ 600 try: 601 self.anritsu.wait_for_registration_state(time_to_wait=timeout) 602 except anritsu.AnritsuError: 603 raise cc.CellularSimulatorError('The phone did not attach before ' 604 'the timeout period ended.') 605 606 def wait_until_communication_state(self, timeout=120): 607 """ Waits until the DUT is in Communication state. 608 609 Args: 610 timeout: after this amount of time the method will raise a 611 CellularSimulatorError exception. Default is 120 seconds. 612 """ 613 try: 614 self.anritsu.wait_for_communication_state(time_to_wait=timeout) 615 except anritsu.AnritsuError: 616 raise cc.CellularSimulatorError('The phone was not in ' 617 'Communication state before ' 618 'the timeout period ended.') 619 620 def wait_until_idle_state(self, timeout=120): 621 """ Waits until the DUT is in Idle state. 622 623 Args: 624 timeout: after this amount of time the method will raise a 625 CellularSimulatorError exception. Default is 120 seconds. 626 """ 627 try: 628 self.anritsu.wait_for_idle_state(time_to_wait=timeout) 629 except anritsu.AnritsuError: 630 raise cc.CellularSimulatorError('The phone was not in Idle state ' 631 'before the time the timeout ' 632 'period ended.') 633 634 def detach(self): 635 """ Turns off all the base stations so the DUT loose connection.""" 636 if self.anritsu.get_smartstudio_status() == \ 637 md8475a.ProcessingStatus.PROCESS_STATUS_NOTRUN.value: 638 self.log.info('Device cannot be detached because simulation is ' 639 'not running.') 640 return 641 self.anritsu.set_simulation_state_to_poweroff() 642 643 def stop(self): 644 """ Stops current simulation. After calling this method, the simulator 645 will need to be set up again. """ 646 self.anritsu.stop_simulation() 647 648 def start_data_traffic(self): 649 """ Starts transmitting data from the instrument to the DUT. """ 650 try: 651 self.anritsu.start_ip_traffic() 652 except md8475a.AnritsuError as inst: 653 # This typically happens when traffic is already running. 654 # TODO (b/141962691): continue only if traffic is running 655 self.log.warning(str(inst)) 656 time.sleep(4) 657 658 def stop_data_traffic(self): 659 """ Stops transmitting data from the instrument to the DUT. """ 660 try: 661 self.anritsu.stop_ip_traffic() 662 except md8475a.AnritsuError as inst: 663 # This typically happens when traffic has already been stopped 664 # TODO (b/141962691): continue only if traffic is stopped 665 self.log.warning(str(inst)) 666 time.sleep(2) 667 668 def get_measured_pusch_power(self): 669 """ Queries PUSCH power measured at the callbox. 670 671 Returns: 672 The PUSCH power in the primary input port. 673 """ 674 # Try three times before raising an exception. This is needed because 675 # the callbox sometimes reports an active chain as 'DEACTIVE'. 676 retries_left = 3 677 678 while retries_left > 0: 679 680 ul_pusch = self.anritsu.get_measured_pusch_power().split(',')[0] 681 682 if ul_pusch != 'DEACTIVE': 683 return float(ul_pusch) 684 685 time.sleep(3) 686 retries_left -= 1 687 self.log.info('Chain shows as inactive. %d retries left.' % 688 retries_left) 689 690 raise cc.CellularSimulatorError('Could not get measured PUSCH power.') 691 692 693class MD8475BCellularSimulator(MD8475CellularSimulator): 694 695 MD8475_VERSION = 'B' 696 697 # Indicates if it is able to use 256 QAM as the downlink modulation for LTE 698 LTE_SUPPORTS_DL_256QAM = True 699 700 # Indicates if it is able to use 64 QAM as the uplink modulation for LTE 701 LTE_SUPPORTS_UL_64QAM = True 702 703 # Indicates if 4x4 MIMO is supported for LTE 704 LTE_SUPPORTS_4X4_MIMO = True 705 706 # The maximum number of carriers that this simulator can support for LTE 707 LTE_MAX_CARRIERS = 4 708 709 # The maximum power that the equipment is able to transmit 710 MAX_DL_POWER = -10 711 712 # Simulation config files in the callbox computer. 713 # These should be replaced in the future by setting up 714 # the same configuration manually. 715 LTE_BASIC_SIM_FILE = 'SIM_default_LTE.wnssp2' 716 LTE_BASIC_CELL_FILE = 'CELL_LTE_config.wnscp2' 717 LTE_CA_BASIC_SIM_FILE = 'SIM_LTE_CA.wnssp2' 718 LTE_CA_BASIC_CELL_FILE = 'CELL_LTE_CA_config.wnscp2' 719 720 # Filepath to the config files stored in the Anritsu callbox. Needs to be 721 # formatted to replace {} with either A or B depending on the model. 722 CALLBOX_CONFIG_PATH = 'C:\\Users\\MD8475B\\Documents\\DAN_configs\\' 723 724 def setup_lte_scenario(self): 725 """ The B model can support up to five carriers. """ 726 727 super().setup_lte_scenario() 728 729 self.bts.extend([ 730 self.anritsu.get_BTS(md8475a.BtsNumber.BTS3), 731 self.anritsu.get_BTS(md8475a.BtsNumber.BTS4), 732 self.anritsu.get_BTS(md8475a.BtsNumber.BTS5) 733 ]) 734