1#!/usr/bin/env python3.4 2# 3# Copyright 2021 - 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 collections 18import itertools 19 20import pyvisa 21import time 22from acts import logger 23from acts import asserts as acts_asserts 24from acts_contrib.test_utils.cellular.performance import cellular_performance_test_utils as cputils 25 26SHORT_SLEEP = 1 27VERY_SHORT_SLEEP = 0.1 28MEDIUM_SLEEP = 5 29SUBFRAME_DURATION = 0.001 30VISA_QUERY_DELAY = 0.01 31 32 33class Keysight5GTestApp(object): 34 """Controller for the Keysight 5G NR Test Application. 35 36 This controller enables interacting with a Keysight Test Application 37 running on a remote test PC and implements many of the configuration 38 parameters supported in test app. 39 """ 40 41 VISA_LOCATION = '/opt/keysight/iolibs/libktvisa32.so' 42 43 def __init__(self, config): 44 self.config = config 45 self.test_app_settings = { 46 'lte_cell_count': 0, 47 'nr_cell_count': 0, 48 'lte_cell_configs': [], 49 'nr_cell_configs': [] 50 } 51 self.log = logger.create_tagged_trace_logger("{}{}".format( 52 self.config['brand'], self.config['model'])) 53 self.resource_manager = pyvisa.ResourceManager(self.VISA_LOCATION) 54 self.test_app = self.resource_manager.open_resource( 55 'TCPIP0::{}::{}::INSTR'.format(self.config['ip_address'], 56 self.config['hislip_interface'])) 57 self.test_app.timeout = 200000 58 self.test_app.write_termination = '\n' 59 self.test_app.read_termination = '\n' 60 self.test_app.query_delay = VISA_QUERY_DELAY 61 self.last_loaded_scpi = None 62 63 inst_id = self.send_cmd('*IDN?', 1) 64 if 'Keysight' not in inst_id[0]: 65 self.log.error( 66 'Failed to connect to Keysight Test App: {}'.format(inst_id)) 67 else: 68 self.log.info("Test App ID: {}".format(inst_id)) 69 70 self.test_app_settings['lte_cell_count'] = self.get_cell_count('LTE') 71 self.test_app_settings['nr_cell_count'] = self.get_cell_count('NR5G') 72 73 def destroy(self): 74 self.test_app.close() 75 76 ### Programming Utilities 77 @staticmethod 78 def _format_cells(cells): 79 "Helper function to format list of cells." 80 if isinstance(cells, int): 81 return 'CELL{}'.format(cells) 82 elif isinstance(cells, str): 83 return cells 84 elif isinstance(cells, list): 85 cell_list = [ 86 Keysight5GTestApp._format_cells(cell) for cell in cells 87 ] 88 cell_list = ','.join(cell_list) 89 return cell_list 90 91 @staticmethod 92 def _format_response(response): 93 "Helper function to format test app response." 94 95 def _format_response_entry(entry): 96 try: 97 formatted_entry = float(entry) 98 except: 99 formatted_entry = entry 100 return formatted_entry 101 102 if ',' not in response: 103 return _format_response_entry(response) 104 response = response.split(',') 105 formatted_response = [ 106 _format_response_entry(entry) for entry in response 107 ] 108 return formatted_response 109 110 def send_cmd(self, command, read_response=0, check_errors=1): 111 "Helper function to write to or query test app." 112 if read_response: 113 try: 114 response = Keysight5GTestApp._format_response( 115 self.test_app.query(command)) 116 time.sleep(VISA_QUERY_DELAY) 117 if check_errors: 118 error = self.test_app.query('SYSTem:ERRor?') 119 time.sleep(VISA_QUERY_DELAY) 120 if 'No error' not in error: 121 self.log.warning("Command: {}. Error: {}".format( 122 command, error)) 123 return response 124 except: 125 raise RuntimeError('Lost connection to test app.') 126 else: 127 try: 128 self.test_app.write(command) 129 time.sleep(VISA_QUERY_DELAY) 130 if check_errors: 131 error = self.test_app.query('SYSTem:ERRor?') 132 if 'No error' not in error: 133 self.log.warning("Command: {}. Error: {}".format( 134 command, error)) 135 self.send_cmd('*OPC?', 1, check_errors) 136 time.sleep(VISA_QUERY_DELAY) 137 except: 138 raise RuntimeError('Lost connection to test app.') 139 return None 140 141 def check_error(self): 142 error = self.test_app.query('SYSTem:ERRor?') 143 if 'No error' not in error: 144 self.log.warning("Error: {}".format(error)) 145 return True 146 else: 147 return False 148 149 def import_scpi_file(self, file_name, check_last_loaded=0): 150 """Function to import SCPI file specified in file_name. 151 152 Args: 153 file_name: name of SCPI file to run 154 check_last_loaded: flag to check last loaded scpi and 155 only load if different. 156 """ 157 if file_name == self.last_loaded_scpi and check_last_loaded: 158 self.log.info('Skipping SCPI import.') 159 self.send_cmd("SYSTem:SCPI:IMPort '{}'".format(file_name)) 160 while int(self.send_cmd('SYSTem:SCPI:IMPort:STATus?', 1)): 161 self.send_cmd('*OPC?', 1) 162 self.log.info('Done with SCPI import') 163 164 ### Configure Cells 165 def assert_cell_off_decorator(func): 166 "Decorator function that ensures cells or off when configuring them" 167 168 def inner(self, *args, **kwargs): 169 if "nr" in func.__name__: 170 cell_type = 'NR5G' 171 else: 172 cell_type = kwargs.get('cell_type', args[0]) 173 cell = kwargs.get('cell', args[1]) 174 cell_state = self.get_cell_state(cell_type, cell) 175 if cell_state: 176 self.log.error('Cell must be off when calling {}'.format( 177 func.__name__)) 178 return (func(self, *args, **kwargs)) 179 180 return inner 181 182 ### Configure Cells 183 def skip_config_if_none_decorator(func): 184 "Decorator function that skips the config function if any args are none" 185 186 def inner(self, *args, **kwargs): 187 none_arg = False 188 for arg in args: 189 if arg is None: 190 none_arg = True 191 for key, value in kwargs.items(): 192 if value is None: 193 none_arg = True 194 if none_arg: 195 self.log.warning( 196 'Skipping {}. Received incomplete arguments.'.format( 197 func.__name__)) 198 return 199 return (func(self, *args, **kwargs)) 200 201 return inner 202 203 def assert_cell_off(self, cell_type, cell): 204 cell_state = self.get_cell_state(cell_type, cell) 205 if cell_state: 206 self.log.error('Cell must be off') 207 208 def select_cell(self, cell_type, cell): 209 """Function to select active cell. 210 211 Args: 212 cell_type: LTE or NR5G cell 213 cell: cell/carrier number 214 """ 215 self.send_cmd('BSE:SELected:CELL {},{}'.format( 216 cell_type, Keysight5GTestApp._format_cells(cell))) 217 218 def select_display_tab(self, cell_type, cell, tab, subtab): 219 """Function to select display tab. 220 221 Args: 222 cell_type: LTE or NR5G cell 223 cell: cell/carrier number 224 tab: tab to display for the selected cell 225 """ 226 supported_tabs = { 227 'PHY': [ 228 'BWP', 'HARQ', 'PDSCH', 'PDCCH', 'PRACH', 'PUSCH', 'PUCCH', 229 'SRSC' 230 ], 231 'BTHR': ['SUMMARY', 'OTAGRAPH', 'ULOTA', 'DLOTA'], 232 'CSI': [] 233 } 234 if (tab not in supported_tabs) or (subtab not in supported_tabs[tab]): 235 return 236 self.select_cell(cell_type, cell) 237 self.send_cmd('DISPlay:{} {},{}'.format(cell_type, tab, subtab)) 238 239 def get_cell_count(self, cell_type): 240 """Function to get cell count 241 242 Args: 243 cell_type: LTE or NR5G cell 244 Returns: 245 cell_count: number of cells of cell_type supported. 246 """ 247 cell_count = int( 248 self.send_cmd('BSE:CONFig:{}:CELL:COUNt?'.format(cell_type), 1)) 249 return cell_count 250 251 def get_cell_state(self, cell_type, cell): 252 """Function to get cell on/off state. 253 254 Args: 255 cell_type: LTE or NR5G cell 256 cell: cell/carrier number 257 Returns: 258 cell_state: boolean. True if cell on 259 """ 260 cell_state = int( 261 self.send_cmd( 262 'BSE:CONFig:{}:{}:ACTive:STATe?'.format( 263 cell_type, Keysight5GTestApp._format_cells(cell)), 1)) 264 return cell_state 265 266 def wait_for_cell_status(self, 267 cell_type, 268 cell, 269 states, 270 timeout, 271 polling_interval=SHORT_SLEEP): 272 """Function to wait for a specific cell status 273 274 Args: 275 cell_type: LTE or NR5G cell 276 cell: cell/carrier number 277 states: list of acceptable states (ON, CONN, AGG, ACT, etc) 278 timeout: amount of time to wait for requested status 279 Returns: 280 True if one of the listed states is achieved 281 False if timed out waiting for acceptable state. 282 """ 283 states = [states] if isinstance(states, str) else states 284 for i in range(int(timeout / polling_interval)): 285 current_state = self.send_cmd( 286 'BSE:STATus:{}:{}?'.format( 287 cell_type, Keysight5GTestApp._format_cells(cell)), 1) 288 if current_state in states: 289 return True 290 time.sleep(polling_interval) 291 self.log.warning('Timeout waiting for {} {} {}'.format( 292 cell_type, Keysight5GTestApp._format_cells(cell), states)) 293 return False 294 295 def set_cell_state(self, cell_type, cell, state): 296 """Function to set cell state 297 298 Args: 299 cell_type: LTE or NR5G cell 300 cell: cell/carrier number 301 state: requested state 302 """ 303 self.send_cmd('BSE:CONFig:{}:{}:ACTive:STATe {}'.format( 304 cell_type, Keysight5GTestApp._format_cells(cell), state)) 305 306 def turn_all_cells_off(self): 307 for cell in range(self.test_app_settings['lte_cell_count']): 308 self.set_cell_state('LTE', cell + 1, 0) 309 for cell in range(self.test_app_settings['nr_cell_count']): 310 self.set_cell_state('NR5G', cell + 1, 0) 311 312 def set_nr_cell_type(self, cell_type, cell, nr_cell_type): 313 """Function to set cell duplex mode 314 315 Args: 316 cell_type: LTE or NR5G cell 317 cell: cell/carrier number 318 nr_cell_type: SA or NSA 319 """ 320 self.assert_cell_off(cell_type, cell) 321 self.send_cmd('BSE:CONFig:{}:{}:TYPE {}'.format( 322 cell_type, Keysight5GTestApp._format_cells(cell), nr_cell_type)) 323 324 def set_cell_duplex_mode(self, cell_type, cell, duplex_mode): 325 """Function to set cell duplex mode 326 327 Args: 328 cell_type: LTE or NR5G cell 329 cell: cell/carrier number 330 duplex_mode: TDD or FDD 331 """ 332 self.assert_cell_off(cell_type, cell) 333 self.send_cmd('BSE:CONFig:{}:{}:DUPLEX:MODe {}'.format( 334 cell_type, Keysight5GTestApp._format_cells(cell), duplex_mode)) 335 336 def set_cell_band(self, cell_type, cell, band): 337 """Function to set cell band 338 339 Args: 340 cell_type: LTE or NR5G cell 341 cell: cell/carrier number 342 band: LTE or NR band (e.g. 1,3,N260, N77) 343 """ 344 self.assert_cell_off(cell_type, cell) 345 self.send_cmd('BSE:CONFig:{}:{}:BAND {}'.format( 346 cell_type, Keysight5GTestApp._format_cells(cell), band)) 347 348 def set_cell_channel(self, cell_type, cell, channel, arfcn=1): 349 """Function to set cell frequency/channel 350 351 Args: 352 cell_type: LTE or NR5G cell 353 cell: cell/carrier number 354 channel: requested channel (ARFCN) or frequency in MHz 355 """ 356 self.assert_cell_off(cell_type, cell) 357 if cell_type == 'NR5G' and isinstance( 358 channel, str) and channel.lower() in ['low', 'mid', 'high']: 359 self.send_cmd('BSE:CONFig:{}:{}:TESTChanLoc {}'.format( 360 cell_type, Keysight5GTestApp._format_cells(cell), 361 channel.upper())) 362 elif arfcn == 1: 363 self.send_cmd('BSE:CONFig:{}:{}:DL:CHANnel {}'.format( 364 cell_type, Keysight5GTestApp._format_cells(cell), channel)) 365 else: 366 self.send_cmd('BSE:CONFig:{}:{}:DL:FREQuency:MAIN {}'.format( 367 cell_type, Keysight5GTestApp._format_cells(cell), 368 channel * 1e6)) 369 370 def toggle_contiguous_nr_channels(self, force_contiguous): 371 self.assert_cell_off('NR5G', 1) 372 self.log.warning( 373 'Forcing contiguous NR channels overrides channel config.') 374 self.send_cmd('BSE:CONFig:NR5G:PHY:OPTimize:CONTiguous:STATe 0') 375 if force_contiguous: 376 self.send_cmd('BSE:CONFig:NR5G:PHY:OPTimize:CONTiguous:STATe 1') 377 378 def configure_contiguous_nr_channels(self, cell, band, channel): 379 """Function to set cell frequency/channel 380 381 Args: 382 cell: cell/carrier number 383 band: band to set channel in (only required for preset) 384 channel_preset: frequency in MHz or preset in [low, mid, or high] 385 """ 386 self.assert_cell_off('NR5G', cell) 387 self.send_cmd('BSE:CONFig:NR5G:PHY:OPTimize:CONTiguous:STATe 0') 388 if channel.lower() in ['low', 'mid', 'high']: 389 pcc_arfcn = cputils.PCC_PRESET_MAPPING[band][channel] 390 self.set_cell_channel('NR5G', cell, pcc_arfcn, 1) 391 else: 392 self.set_cell_channel('NR5G', cell, channel, 0) 393 self.send_cmd('BSE:CONFig:NR5G:PHY:OPTimize:CONTiguous:STATe 1') 394 395 def configure_noncontiguous_nr_channels(self, cells, band, channels): 396 """Function to set cell frequency/channel 397 398 Args: 399 cell: cell/carrier number 400 band: band number 401 channel: frequency in MHz 402 """ 403 for cell in cells: 404 self.assert_cell_off('NR5G', cell) 405 self.send_cmd('BSE:CONFig:NR5G:PHY:OPTimize:CONTiguous:STATe 0') 406 for cell, channel in zip(cells, channels): 407 self.set_cell_channel('NR5G', cell, channel, arfcn=0) 408 409 def set_cell_bandwidth(self, cell_type, cell, bandwidth): 410 """Function to set cell bandwidth 411 412 Args: 413 cell_type: LTE or NR5G cell 414 cell: cell/carrier number 415 bandwidth: requested bandwidth 416 """ 417 self.assert_cell_off(cell_type, cell) 418 self.send_cmd('BSE:CONFig:{}:{}:DL:BW {}'.format( 419 cell_type, Keysight5GTestApp._format_cells(cell), bandwidth)) 420 421 def set_nr_subcarrier_spacing(self, cell, subcarrier_spacing): 422 """Function to set cell bandwidth 423 424 Args: 425 cell: cell/carrier number 426 subcarrier_spacing: requested SCS 427 """ 428 self.assert_cell_off('NR5G', cell) 429 self.send_cmd('BSE:CONFig:NR5G:{}:SUBCarrier:SPACing:COMMon {}'.format( 430 Keysight5GTestApp._format_cells(cell), subcarrier_spacing)) 431 432 def set_cell_mimo_config(self, cell_type, cell, link, mimo_config): 433 """Function to set cell mimo config. 434 435 Args: 436 cell_type: LTE or NR5G cell 437 cell: cell/carrier number 438 link: uplink or downlink 439 mimo_config: requested mimo configuration (refer to SCPI 440 documentation for allowed range of values) 441 """ 442 self.assert_cell_off(cell_type, cell) 443 if cell_type == 'NR5G': 444 self.send_cmd('BSE:CONFig:{}:{}:{}:MIMO:CONFig {}'.format( 445 cell_type, Keysight5GTestApp._format_cells(cell), link, 446 mimo_config)) 447 else: 448 self.send_cmd('BSE:CONFig:{}:{}:PHY:DL:ANTenna:CONFig {}'.format( 449 cell_type, Keysight5GTestApp._format_cells(cell), mimo_config)) 450 451 def set_lte_cell_transmission_mode(self, cell, transmission_mode): 452 """Function to set LTE cell transmission mode. 453 454 Args: 455 cell: cell/carrier number 456 transmission_mode: one of TM1, TM2, TM3, TM4 ... 457 """ 458 459 self.assert_cell_off('LTE', cell) 460 self.send_cmd('BSE:CONFig:LTE:{}:RRC:TMODe {}'.format( 461 Keysight5GTestApp._format_cells(cell), transmission_mode)) 462 463 @skip_config_if_none_decorator 464 def set_lte_cell_num_layers(self, cell, num_layers): 465 """Function to set LTE cell number of layers.""" 466 467 self.assert_cell_off('LTE', cell) 468 self.send_cmd('BSE:CONFig:LTE:{}:PHY:DL:NUMLayers {}'.format( 469 Keysight5GTestApp._format_cells(cell), num_layers)) 470 471 @skip_config_if_none_decorator 472 def set_lte_cell_num_codewords(self, cell, num_codewords): 473 """Function to set LTE number of codewords.""" 474 475 self.assert_cell_off('LTE', cell) 476 self.send_cmd('BSE:CONFig:LTE:{}:PHY:DL:NUMCodewords {}'.format( 477 Keysight5GTestApp._format_cells(cell), num_codewords)) 478 479 @skip_config_if_none_decorator 480 def set_lte_cell_dl_subframe_allocation(self, 481 cell, 482 dl_subframe_allocation=[1] * 10): 483 """Function to set LTE downlink subrframe allocation. 484 485 Args: 486 cell: cell/carrier number 487 dl_subframe_allocation: string or bool list indicating allocation 488 (1 enabled, 0 disabled) 489 """ 490 if isinstance(dl_subframe_allocation, list): 491 dl_subframe_allocation = str(dl_subframe_allocation)[1:-1].replace( 492 '\'', '') 493 self.assert_cell_off('LTE', cell) 494 self.send_cmd( 495 'BSE:CONFig:LTE:{}:PHY:DL:SFRame:ALLocation:ALL {}'.format( 496 Keysight5GTestApp._format_cells(cell), dl_subframe_allocation)) 497 498 def set_cell_dl_power(self, cell_type, cell, power, full_bw): 499 """Function to set cell power 500 501 Args: 502 cell_type: LTE or NR5G cell 503 cell: cell/carrier number 504 power: requested power 505 full_bw: boolean controlling if requested power is per channel 506 or subcarrier 507 """ 508 if full_bw: 509 self.send_cmd('BSE:CONFig:{}:{}:DL:POWer:CHANnel {}'.format( 510 cell_type, Keysight5GTestApp._format_cells(cell), power)) 511 else: 512 self.send_cmd('BSE:CONFig:{}:{}:DL:POWer:EPRE {}'.format( 513 cell_type, Keysight5GTestApp._format_cells(cell), power)) 514 time.sleep(VERY_SHORT_SLEEP) 515 self.send_cmd('BSE:CONFig:{}:APPLY'.format(cell_type)) 516 517 def set_cell_ul_power_control(self, cell_type, cell, mode, target_power=0): 518 """Function configure UL power control 519 520 Args: 521 cell_type: LTE or NR5G cell 522 cell: cell/carrier number 523 mode: UL power control mode. One of [TARget | MANual | UP | DOWN | DISabled] 524 target_power: target power for PUSCH 525 """ 526 self.send_cmd('BSE:CONFig:{}:{}:UL:PUSCh:CLPControl:MODE {}'.format( 527 cell_type, Keysight5GTestApp._format_cells(cell), mode)) 528 if cell_type == 'NR5G' and mode == 'TARget': 529 self.send_cmd( 530 'BSE:CONFig:{}:{}:UL:PUSCh:CLPControl:TARGet:POWer {}'.format( 531 cell_type, Keysight5GTestApp._format_cells(cell), 532 target_power)) 533 elif cell_type == 'LTE' and mode == 'TARget': 534 self.send_cmd( 535 'BSE:CONFig:{}:{}:UL:CLPControl:TARGet:POWer:PUSCH {}'.format( 536 cell_type, Keysight5GTestApp._format_cells(cell), 537 target_power)) 538 self.send_cmd('BSE:CONFig:{}:APPLY'.format(cell_type)) 539 540 def set_cell_input_power(self, cell_type, cell, power): 541 """Function to set cell input power 542 543 Args: 544 cell_type: LTE or NR5G cell 545 cell: cell/carrier number 546 power: expected input power 547 """ 548 if power == "AUTO" and cell_type == "LTE": 549 self.send_cmd('BSE:CONFig:{}:{}:CONTrol:POWer:AUTO ON'.format( 550 cell_type, Keysight5GTestApp._format_cells(cell))) 551 elif cell_type == "LTE": 552 self.send_cmd('BSE:CONFig:{}:{}:CONTrol:POWer:AUTO OFF'.format( 553 cell_type, Keysight5GTestApp._format_cells(cell))) 554 self.send_cmd('BSE:CONFig:{}:{}:MANual:POWer {}'.format( 555 cell_type, Keysight5GTestApp._format_cells(cell), power)) 556 if power == "AUTO" and cell_type == "NR5G": 557 self.send_cmd('BSE:CONFig:{}:UL:EIP:AUTO ON'.format(cell_type)) 558 elif cell_type == "NR5G": 559 self.send_cmd('BSE:CONFig:{}:UL:EIP:AUTO OFF'.format(cell_type)) 560 self.send_cmd('BSE:CONFig:{}:{}:MANual:POWer {}'.format( 561 cell_type, Keysight5GTestApp._format_cells(cell), power)) 562 self.send_cmd('BSE:CONFig:{}:APPLY'.format(cell_type)) 563 564 def set_cell_duplex_mode(self, cell_type, cell, duplex_mode): 565 """Function to set cell power 566 567 Args: 568 cell_type: LTE or NR5G cell 569 cell: cell/carrier number 570 duplex mode: TDD or FDD 571 """ 572 self.assert_cell_off(cell_type, cell) 573 self.send_cmd('BSE:CONFig:{}:{}:DUPLEX:MODe {}'.format( 574 cell_type, Keysight5GTestApp._format_cells(cell), duplex_mode)) 575 576 def set_dl_carriers(self, cells): 577 """Function to set aggregated DL NR5G carriers 578 579 Args: 580 cells: list of DL cells/carriers to aggregate with LTE (e.g. [1,2]) 581 """ 582 self.send_cmd('BSE:CONFig:NR5G:CELL1:CAGGregation:NRCC:DL {}'.format( 583 Keysight5GTestApp._format_cells(cells))) 584 585 def set_ul_carriers(self, cells): 586 """Function to set aggregated UL NR5G carriers 587 588 Args: 589 cells: list of DL cells/carriers to aggregate with LTE (e.g. [1,2]) 590 """ 591 self.send_cmd('BSE:CONFig:NR5G:CELL1:CAGGregation:NRCC:UL {}'.format( 592 Keysight5GTestApp._format_cells(cells))) 593 594 def set_nr_cell_schedule_scenario(self, cell, scenario): 595 """Function to set NR schedule to one of predefince quick configs. 596 597 Args: 598 cell: cell number to address. schedule will apply to all cells 599 scenario: one of the predefined test app schedlue quick configs 600 (e.g. FULL_TPUT, BASIC). 601 """ 602 self.assert_cell_off('NR5G', cell) 603 self.send_cmd( 604 'BSE:CONFig:NR5G:{}:SCHeduling:QCONFig:SCENario {}'.format( 605 Keysight5GTestApp._format_cells(cell), scenario)) 606 self.send_cmd('BSE:CONFig:NR5G:SCHeduling:QCONFig:APPLy:ALL') 607 608 def set_nr_schedule_slot_ratio(self, cell, slot_ratio): 609 """Function to set NR schedule to one of predefince quick configs. 610 611 Args: 612 cell: cell number to address. schedule will apply to all cells 613 slot_ratio: downlink slot ratio 614 """ 615 self.assert_cell_off('NR5G', cell) 616 self.send_cmd('BSE:CONFig:NR5G:{}:SCHeduling:QCONFig:RATIo {}'.format( 617 Keysight5GTestApp._format_cells(cell), slot_ratio)) 618 self.send_cmd('BSE:CONFig:NR5G:SCHeduling:QCONFig:APPLy:ALL') 619 620 def set_nr_schedule_tdd_pattern(self, cell, tdd_pattern): 621 """Function to set NR schedule to one of predefince quick configs. 622 623 Args: 624 cell: cell number to address. schedule will apply to all cells 625 tdd_pattern: 0 for disabled, 1/enabled, or current 626 """ 627 tdd_pattern_mapping = { 628 0: 'DISabled', 629 1: 'ENABled', 630 'current': 'CURRent' 631 } 632 self.assert_cell_off('NR5G', cell) 633 self.send_cmd( 634 'BSE:CONFig:NR5G:{}:SCHeduling:QCONFig:TDD:PATTern {}'.format( 635 Keysight5GTestApp._format_cells(cell), 636 tdd_pattern_mapping[tdd_pattern])) 637 self.send_cmd('BSE:CONFig:NR5G:SCHeduling:QCONFig:APPLy:ALL') 638 639 def set_nr_cell_mcs(self, cell, dl_mcs, ul_mcs): 640 """Function to set NR cell DL & UL MCS 641 642 Args: 643 cell: cell number to address. MCS will apply to all cells 644 dl_mcs: mcs index to use on DL 645 ul_mcs: mcs index to use on UL 646 """ 647 self.assert_cell_off('NR5G', cell) 648 frame_config_count = 5 649 slot_config_count = 8 650 if isinstance(dl_mcs, dict): 651 self.configure_nr_link_adaptation(cell, link_config=dl_mcs) 652 else: 653 for frame, slot in itertools.product(range(frame_config_count), 654 range(slot_config_count)): 655 self.send_cmd( 656 'BSE:CONFig:NR5G:{}:SCHeduling:BWP0:FC{}:SC{}:DL:RRESource:APOLicy FIXed' 657 .format(Keysight5GTestApp._format_cells(cell), frame, 658 slot)) 659 self.send_cmd( 660 'BSE:CONFig:NR5G:SCHeduling:SETParameter "CELLALL:BWPALL:FCALL:SCALL", "DL:IMCS", "{}"' 661 .format(dl_mcs)) 662 self.send_cmd( 663 'BSE:CONFig:NR5G:SCHeduling:SETParameter "CELLALL:BWPALL:FCALL:SCALL", "UL:IMCS", "{}"' 664 .format(ul_mcs)) 665 666 def configure_nr_link_adaptation(self, cell, link_config): 667 frame_config_count = 5 668 slot_config_count = 8 669 for frame, slot in itertools.product(range(frame_config_count), 670 range(slot_config_count)): 671 self.send_cmd( 672 'BSE:CONFig:NR5G:{}:SCHeduling:BWP0:FC{}:SC{}:DL:RRESource:APOLicy {}' 673 .format(Keysight5GTestApp._format_cells(cell), frame, slot, 674 link_config['link_policy'])) 675 self.send_cmd( 676 'BSE:CONFig:NR5G:{}:SCHeduling:BWP0:FC{}:SC{}:DL:IMCS {}'. 677 format(Keysight5GTestApp._format_cells(cell), frame, slot, 678 link_config['initial_mcs'])) 679 self.send_cmd( 680 'BSE:CONFig:NR5G:{}:SCHeduling:BWP0:FC{}:SC{}:DL:MAXimum:IMCS {}' 681 .format(Keysight5GTestApp._format_cells(cell), frame, slot, 682 link_config['maximum_mcs'])) 683 self.send_cmd( 684 'BSE:CONFig:NR5G:{}:MAC:LADaptation:NTX:BEValuation {}'.format( 685 Keysight5GTestApp._format_cells(cell), 686 link_config.get('adaptation_interval', 10000))) 687 self.send_cmd( 688 'BSE:CONFig:NR5G:{}:MAC:LADaptation:TARGet:NACK:COUNt {}'.format( 689 Keysight5GTestApp._format_cells(cell), 690 link_config.get('target_nack_count', 1000))) 691 self.send_cmd( 692 'BSE:CONFig:NR5G:{}:MAC:LADaptation:TARGet:NACK:MARGin {}'.format( 693 Keysight5GTestApp._format_cells(cell), 694 link_config.get('target_nack_margin', 100))) 695 self.send_cmd( 696 'BSE:CONFig:NR5G:{}:MAC:DL:LADaptation:MCS:INCRement {}'.format( 697 Keysight5GTestApp._format_cells(cell), 698 link_config.get('mcs_step', 1))) 699 700 def set_lte_cell_mcs( 701 self, 702 cell, 703 dl_mcs_table, 704 dl_mcs, 705 ul_mcs_table, 706 ul_mcs, 707 ): 708 """Function to set NR cell DL & UL MCS 709 710 Args: 711 cell: cell number to address. MCS will apply to all cells 712 dl_mcs: mcs index to use on DL 713 ul_mcs: mcs index to use on UL 714 """ 715 if dl_mcs_table == 'QAM256': 716 dl_mcs_table_formatted = 'ASUBframe' 717 elif dl_mcs_table == 'QAM1024': 718 dl_mcs_table_formatted = 'ASUB1024' 719 elif dl_mcs_table == 'QAM64': 720 dl_mcs_table_formatted = 'DISabled' 721 self.assert_cell_off('LTE', cell) 722 self.send_cmd( 723 'BSE:CONFig:LTE:SCHeduling:SETParameter "CELLALL", "DL:MCS:TABle", "{}"' 724 .format(dl_mcs_table_formatted)) 725 self.configure_lte_periodic_csi_reporting(cell, 1) 726 if dl_mcs == 'WCQI': 727 self.send_cmd('BSE:CONFig:LTE:{}:PHY:DL:IMCS:MODE WCQI'.format( 728 Keysight5GTestApp._format_cells(cell))) 729 else: 730 self.send_cmd('BSE:CONFig:LTE:{}:PHY:DL:IMCS:MODE EXPLicit'.format( 731 Keysight5GTestApp._format_cells(cell))) 732 self.send_cmd( 733 'BSE:CONFig:LTE:SCHeduling:SETParameter "CELLALL:SFALL:CWALL", "DL:IMCS", "{}"' 734 .format(dl_mcs)) 735 self.send_cmd( 736 'BSE:CONFig:LTE:SCHeduling:SETParameter "CELLALL", "UL:MCS:TABle", "{}"' 737 .format(ul_mcs_table)) 738 self.send_cmd( 739 'BSE:CONFig:LTE:SCHeduling:SETParameter "CELLALL:SFALL", "UL:IMCS", "{}"' 740 .format(ul_mcs)) 741 742 def configure_lte_periodic_csi_reporting(self, cell, enable): 743 """Function to enable/disable LTE CSI reporting.""" 744 745 self.send_cmd('BSE:CONFig:LTE:{}:PHY:CSI:PERiodic:STATe {}'.format( 746 Keysight5GTestApp._format_cells(cell), enable)) 747 748 def set_lte_control_region_size(self, cell, num_symbols): 749 self.assert_cell_off('LTE', cell) 750 self.send_cmd('BSE:CONFig:LTE:{}:PHY:PCFich:CFI {}'.format( 751 Keysight5GTestApp._format_cells(cell), num_symbols)) 752 753 def set_lte_ul_mac_padding(self, mac_padding): 754 self.assert_cell_off('LTE', 'CELL1') 755 padding_str = 'TRUE' if mac_padding else 'FALSE' 756 self.send_cmd( 757 'BSE:CONFig:LTE:SCHeduling:SETParameter "CELLALL", "UL:MAC:PADDING", "{}"' 758 .format(padding_str)) 759 760 def set_nr_ul_dft_precoding(self, cell, precoding): 761 """Function to configure DFT-precoding on uplink. 762 763 Args: 764 cell: cell number to address. MCS will apply to all cells 765 precoding: 0/1 to disable/enable precoding 766 """ 767 self.assert_cell_off('NR5G', cell) 768 precoding_str = "ENABled" if precoding else "DISabled" 769 self.send_cmd( 770 'BSE:CONFig:NR5G:{}:SCHeduling:QCONFig:UL:TRANsform:PRECoding {}'. 771 format(Keysight5GTestApp._format_cells(cell), precoding_str)) 772 precoding_str = "True" if precoding else "False" 773 self.send_cmd( 774 'BSE:CONFig:NR5G:SCHeduling:SETParameter "CELLALL:BWPALL", "UL:TPEnabled", "{}"' 775 .format(precoding_str)) 776 777 def configure_ul_clpc(self, channel, mode, target): 778 """Function to configure UL power control on all cells/carriers 779 780 Args: 781 channel: physical channel must be PUSCh or PUCCh 782 mode: mode supported by test app (all up/down bits, target, etc) 783 target: target power if mode is set to target 784 """ 785 self.send_cmd('BSE:CONFig:NR5G:UL:{}:CLPControl:MODE:ALL {}'.format( 786 channel, mode)) 787 if "tar" in mode.lower(): 788 self.send_cmd( 789 'BSE:CONFig:NR5G:UL:{}:CLPControl:TARGet:POWer:ALL {}'.format( 790 channel, target)) 791 792 def configure_channel_emulator(self, cell_type, cell, fading_model): 793 if cell_type == 'LTE': 794 self.send_cmd('BSE:CONFig:{}:{}:CMODel {}'.format( 795 cell_type, Keysight5GTestApp._format_cells(cell), 796 fading_model['channel_model'])) 797 self.send_cmd('BSE:CONFig:{}:{}:CMATrix {}'.format( 798 cell_type, Keysight5GTestApp._format_cells(cell), 799 fading_model['correlation_matrix'])) 800 self.send_cmd('BSE:CONFig:{}:{}:MDSHift {}'.format( 801 cell_type, Keysight5GTestApp._format_cells(cell), 802 fading_model['max_doppler'])) 803 elif cell_type == 'NR5G': 804 #TODO: check that this is FR1 805 self.send_cmd('BSE:CONFig:{}:{}:FRANge1:CMODel {}'.format( 806 cell_type, Keysight5GTestApp._format_cells(cell), 807 fading_model['channel_model'])) 808 self.send_cmd('BSE:CONFig:{}:{}:FRANge1:CMATrix {}'.format( 809 cell_type, Keysight5GTestApp._format_cells(cell), 810 fading_model['correlation_matrix'])) 811 self.send_cmd('BSE:CONFig:{}:{}:FRANge1:MDSHift {}'.format( 812 cell_type, Keysight5GTestApp._format_cells(cell), 813 fading_model['max_doppler'])) 814 815 def set_channel_emulator_state(self, state): 816 self.send_cmd('BSE:CONFig:FADing:ENABle {}'.format(int(state))) 817 818 def apply_lte_carrier_agg(self, cells): 819 """Function to start LTE carrier aggregation on already configured cells""" 820 if self.wait_for_cell_status('LTE', 'CELL1', 'CONN', 60): 821 self.send_cmd( 822 'BSE:CONFig:LTE:CELL1:CAGGregation:AGGRegate:SCC {}'.format( 823 Keysight5GTestApp._format_cells(cells))) 824 self.send_cmd( 825 'BSE:CONFig:LTE:CELL1:CAGGregation:ACTivate:SCC {}'.format( 826 Keysight5GTestApp._format_cells(cells))) 827 828 def apply_carrier_agg(self): 829 """Function to start carrier aggregation on already configured cells""" 830 if not self.wait_for_cell_status('LTE', 'CELL1', 'CONN', 60): 831 raise RuntimeError('LTE must be connected to start aggregation.') 832 # Continue if LTE connected 833 self.send_cmd('BSE:CONFig:LTE:CELL1:CAGGregation:AGGRegate:NRCC:APPly', 834 0, 0) 835 time.sleep(MEDIUM_SLEEP) 836 error = self.check_error() 837 if error: 838 acts_asserts.fail('Failed to apply NR carrier aggregation.') 839 840 def get_ip_throughput(self, cell_type): 841 """Function to query IP layer throughput on LTE or NR 842 843 Args: 844 cell_type: LTE or NR5G 845 Returns: 846 dict containing DL and UL IP-layer throughput 847 """ 848 #Tester reply format 849 #{ report-count, total-bytes, current transfer-rate, average transfer-rate, peak transfer-rate } 850 dl_tput = self.send_cmd( 851 'BSE:MEASure:{}:BTHRoughput:DL:THRoughput:IP?'.format(cell_type), 852 1) 853 ul_tput = self.send_cmd( 854 'BSE:MEASure:{}:BTHRoughput:UL:THRoughput:IP?'.format(cell_type), 855 1) 856 return {'dl_tput': dl_tput, 'ul_tput': ul_tput} 857 858 def _get_throughput(self, cell_type, link, cell): 859 """Helper function to get PHY layer throughput on single cell""" 860 if cell_type == 'LTE': 861 tput_response = self.send_cmd( 862 'BSE:MEASure:LTE:BTHRoughput:{}:THRoughput:OTA:{}?'.format( 863 link, Keysight5GTestApp._format_cells(cell)), 1) 864 elif cell_type == 'NR5G': 865 # Tester reply format 866 #progress-count, ack-count, ack-ratio, nack-count, nack-ratio, statdtx-count, statdtx-ratio, pdschBlerCount, pdschBlerRatio, pdschTputRatio. 867 tput_response = self.send_cmd( 868 'BSE:MEASure:NR5G:BTHRoughput:{}:THRoughput:OTA:{}?'.format( 869 link, Keysight5GTestApp._format_cells(cell)), 1) 870 tput_result = { 871 'frame_count': tput_response[0] / 1e6, 872 'current_tput': tput_response[1] / 1e6, 873 'min_tput': tput_response[2] / 1e6, 874 'max_tput': tput_response[3] / 1e6, 875 'average_tput': tput_response[4] / 1e6, 876 'theoretical_tput': tput_response[5] / 1e6, 877 } 878 return tput_result 879 880 def get_throughput(self, cell_type, dl_cells, ul_cells): 881 """Function to get PHY layer throughput on on or more cells 882 883 This function returns the throughput data on the requested cells 884 during the last BLER test run, i.e., throughpt data must be fetch at 885 the end/after a BLE test run on the Keysight Test App. 886 887 Args: 888 cell_type: LTE or NR5G 889 cells: list of cells to query for throughput data 890 Returns: 891 tput_result: dict containing all throughput statistics in Mbps 892 """ 893 if not isinstance(dl_cells, list): 894 dl_cells = [dl_cells] 895 if not isinstance(ul_cells, list): 896 ul_cells = [ul_cells] 897 tput_result = collections.OrderedDict() 898 for cell in dl_cells: 899 tput_result.setdefault(cell, {}) 900 tput_result[cell]['DL'] = self._get_throughput( 901 cell_type, 'DL', cell) 902 frame_count = tput_result[cell]['DL']['frame_count'] 903 for cell in ul_cells: 904 tput_result.setdefault(cell, {}) 905 tput_result[cell]['UL'] = self._get_throughput( 906 cell_type, 'UL', cell) 907 agg_tput = { 908 'DL': { 909 'frame_count': frame_count, 910 'current_tput': 0, 911 'min_tput': 0, 912 'max_tput': 0, 913 'average_tput': 0, 914 'theoretical_tput': 0 915 }, 916 'UL': { 917 'frame_count': frame_count, 918 'current_tput': 0, 919 'min_tput': 0, 920 'max_tput': 0, 921 'average_tput': 0, 922 'theoretical_tput': 0 923 } 924 } 925 for cell, cell_tput in tput_result.items(): 926 for link, link_tput in cell_tput.items(): 927 for key, value in link_tput.items(): 928 if 'tput' in key: 929 agg_tput[link][key] = agg_tput[link][key] + value 930 tput_result['total'] = agg_tput 931 return tput_result 932 933 def _clear_bler_measurement(self, cell_type): 934 """Helper function to clear BLER results.""" 935 if cell_type == 'LTE': 936 self.send_cmd('BSE:MEASure:LTE:CELL1:BTHRoughput:CLEar') 937 elif cell_type == 'NR5G': 938 self.send_cmd('BSE:MEASure:NR5G:BTHRoughput:CLEar') 939 940 def _configure_bler_measurement(self, cell_type, continuous, length): 941 """Helper function to configure BLER results.""" 942 if continuous: 943 if cell_type == 'LTE': 944 self.send_cmd('BSE:MEASure:LTE:CELL1:BTHRoughput:CONTinuous 1') 945 elif cell_type == 'NR5G': 946 self.send_cmd('BSE:MEASure:NR5G:BTHRoughput:CONTinuous 1') 947 elif length > 1: 948 if cell_type == 'LTE': 949 self.send_cmd( 950 'BSE:MEASure:LTE:CELL1:BTHRoughput:LENGth {}'.format( 951 length)) 952 self.send_cmd('BSE:MEASure:LTE:CELL1:BTHRoughput:CONTinuous 0') 953 elif cell_type == 'NR5G': 954 self.send_cmd( 955 'BSE:MEASure:NR5G:BTHRoughput:LENGth {}'.format(length)) 956 self.send_cmd('BSE:MEASure:NR5G:BTHRoughput:CONTinuous 0') 957 958 def _set_bler_measurement_state(self, cell_type, state): 959 """Helper function to start or stop BLER measurement.""" 960 if cell_type == 'LTE': 961 self.send_cmd( 962 'BSE:MEASure:LTE:CELL1:BTHRoughput:STATe {}'.format(state)) 963 elif cell_type == 'NR5G': 964 self.send_cmd( 965 'BSE:MEASure:NR5G:BTHRoughput:STATe {}'.format(state)) 966 967 def start_bler_measurement(self, cell_type, cells, length): 968 """Function to kick off a BLER measurement 969 970 Args: 971 cell_type: LTE or NR5G 972 length: integer length of BLER measurements in subframes 973 """ 974 self._clear_bler_measurement(cell_type) 975 self._set_bler_measurement_state(cell_type, 0) 976 self._configure_bler_measurement(cell_type, 0, length) 977 self._set_bler_measurement_state(cell_type, 1) 978 time.sleep(0.1) 979 #bler_check = self.get_bler_result(cell_type, cells, length, 0) 980 #if bler_check['total']['DL']['frame_count'] == 0: 981 # self.log.warning('BLER measurement did not start. Retrying') 982 # self.start_bler_measurement(cell_type, cells, length) 983 984 def _get_bler(self, cell_type, link, cell): 985 """Helper function to get single-cell BLER measurement results.""" 986 if cell_type == 'LTE': 987 bler_response = self.send_cmd( 988 'BSE:MEASure:LTE:BTHRoughput:{}:BLER:{}?'.format( 989 link, Keysight5GTestApp._format_cells(cell)), 1) 990 bler_items = [ 991 'frame_count', 'ack_count', 'ack_ratio', 'nack_count', 992 'nack_ratio', 'statDtx_count', 'statDtx_ratio', 993 'nackStatDtx_count', 'nackStatDtx_ratio', 'pdschBler_count', 994 'pdschBler_ratio', 'any_count', 'any_ratio' 995 ] 996 bler_result = { 997 bler_items[x]: bler_response[x] 998 for x in range(len(bler_response)) 999 } 1000 elif cell_type == 'NR5G': 1001 bler_response = self.send_cmd( 1002 'BSE:MEASure:NR5G:BTHRoughput:{}:BLER:{}?'.format( 1003 link, Keysight5GTestApp._format_cells(cell)), 1) 1004 bler_items = [ 1005 'frame_count', 'ack_count', 'ack_ratio', 'nack_count', 1006 'nack_ratio', 'statDtx_count', 'statDtx_ratio', 1007 'pdschBler_count', 'pdschBler_ratio', 'pdschTputRatio' 1008 ] 1009 1010 bler_result = { 1011 bler_items[x]: bler_response[x] 1012 for x in range(len(bler_response)) 1013 } 1014 return bler_result 1015 1016 def get_bler_result(self, 1017 cell_type, 1018 dl_cells, 1019 ul_cells, 1020 length, 1021 wait_for_length=1, 1022 polling_interval=SHORT_SLEEP): 1023 """Function to get BLER results. 1024 1025 This function gets the BLER measurements results on one or more 1026 requested cells. The function can either return BLER statistics 1027 immediately or wait until a certain number of subframes have been 1028 counted (e.g. if the BLER measurement is done) 1029 1030 Args: 1031 cell_type: LTE or NR5G 1032 cells: list of cells for which to get BLER 1033 length: number of subframes to wait for (typically set to the 1034 configured length of the BLER measurements) 1035 wait_for_length: boolean to block/wait till length subframes have 1036 been counted. 1037 Returns: 1038 bler_result: dict containing per-cell and aggregate BLER results 1039 """ 1040 if not isinstance(dl_cells, list): 1041 dl_cells = [dl_cells] 1042 if not isinstance(ul_cells, list): 1043 ul_cells = [ul_cells] 1044 while wait_for_length: 1045 dl_bler = self._get_bler(cell_type, 'DL', dl_cells[0]) 1046 if dl_bler['frame_count'] < length: 1047 time.sleep(polling_interval) 1048 else: 1049 break 1050 1051 bler_result = collections.OrderedDict() 1052 for cell in dl_cells: 1053 bler_result.setdefault(cell, {}) 1054 bler_result[cell]['DL'] = self._get_bler(cell_type, 'DL', cell) 1055 for cell in ul_cells: 1056 bler_result.setdefault(cell, {}) 1057 bler_result[cell]['UL'] = self._get_bler(cell_type, 'UL', cell) 1058 agg_bler = { 1059 'DL': { 1060 'frame_count': length, 1061 'ack_count': 0, 1062 'ack_ratio': 0, 1063 'nack_count': 0, 1064 'nack_ratio': 0 1065 }, 1066 'UL': { 1067 'frame_count': length, 1068 'ack_count': 0, 1069 'ack_ratio': 0, 1070 'nack_count': 0, 1071 'nack_ratio': 0 1072 } 1073 } 1074 for cell, cell_bler in bler_result.items(): 1075 for link, link_bler in cell_bler.items(): 1076 for key, value in link_bler.items(): 1077 if 'ack_count' in key: 1078 agg_bler[link][key] = agg_bler[link][key] + value 1079 dl_ack_nack = agg_bler['DL']['ack_count'] + agg_bler['DL']['nack_count'] 1080 ul_ack_nack = agg_bler['UL']['ack_count'] + agg_bler['UL']['nack_count'] 1081 try: 1082 agg_bler['DL'][ 1083 'ack_ratio'] = agg_bler['DL']['ack_count'] / dl_ack_nack 1084 agg_bler['DL'][ 1085 'nack_ratio'] = agg_bler['DL']['nack_count'] / dl_ack_nack 1086 agg_bler['UL'][ 1087 'ack_ratio'] = agg_bler['UL']['ack_count'] / ul_ack_nack 1088 agg_bler['UL'][ 1089 'nack_ratio'] = agg_bler['UL']['nack_count'] / ul_ack_nack 1090 except: 1091 self.log.debug(bler_result) 1092 agg_bler['DL']['ack_ratio'] = 0 1093 agg_bler['DL']['nack_ratio'] = 1 1094 agg_bler['UL']['ack_ratio'] = 0 1095 agg_bler['UL']['nack_ratio'] = 1 1096 bler_result['total'] = agg_bler 1097 return bler_result 1098 1099 def measure_bler(self, cell_type, cells, length): 1100 """Function to start and wait for BLER results. 1101 1102 This function starts a BLER test on a number of cells and waits for the 1103 test to complete before returning the BLER measurements. 1104 1105 Args: 1106 cell_type: LTE or NR5G 1107 cells: list of cells for which to get BLER 1108 length: number of subframes to wait for (typically set to the 1109 configured length of the BLER measurements) 1110 Returns: 1111 bler_result: dict containing per-cell and aggregate BLER results 1112 """ 1113 self.start_bler_measurement(cell_type, cells, length) 1114 time.sleep(length * SUBFRAME_DURATION) 1115 bler_result = self.get_bler_result(cell_type, cells, length, 1) 1116 return bler_result 1117 1118 def start_nr_rsrp_measurement(self, cells, length): 1119 """Function to start 5G NR RSRP measurement. 1120 1121 Args: 1122 cells: list of NR cells to get RSRP on 1123 length: length of RSRP measurement in milliseconds 1124 Returns: 1125 rsrp_result: dict containing per-cell and aggregate BLER results 1126 """ 1127 for cell in cells: 1128 self.send_cmd('BSE:MEASure:NR5G:{}:L1:RSRPower:STOP'.format( 1129 Keysight5GTestApp._format_cells(cell))) 1130 for cell in cells: 1131 self.send_cmd('BSE:MEASure:NR5G:{}:L1:RSRPower:LENGth {}'.format( 1132 Keysight5GTestApp._format_cells(cell), length)) 1133 for cell in cells: 1134 self.send_cmd('BSE:MEASure:NR5G:{}:L1:RSRPower:STARt'.format( 1135 Keysight5GTestApp._format_cells(cell))) 1136 1137 def get_nr_rsrp_measurement_state(self, cells): 1138 for cell in cells: 1139 self.log.info( 1140 self.send_cmd( 1141 'BSE:MEASure:NR5G:{}:L1:RSRPower:STATe?'.format( 1142 Keysight5GTestApp._format_cells(cell)), 1)) 1143 1144 def get_nr_rsrp_measurement_results(self, cells): 1145 for cell in cells: 1146 self.log.info( 1147 self.send_cmd( 1148 'BSE:MEASure:NR5G:{}:L1:RSRPower:REPorts:JSON?'.format( 1149 Keysight5GTestApp._format_cells(cell)), 1)) 1150 1151 def release_rrc_connection(self, cell_type, cell): 1152 if cell_type == 'LTE': 1153 self.send_cmd('BSE:FUNCtion:LTE:{}:RELease:SEND'.format( 1154 Keysight5GTestApp._format_cells(cell))) 1155 elif cell_type == 'NR5G': 1156 self.send_cmd( 1157 'BSE:CONFig:NR5G:{}:RCONtrol:RRC:STARt RRELease'.format( 1158 Keysight5GTestApp._format_cells(cell))) 1159 1160 def send_rrc_paging(self, cell_type, cell): 1161 if cell_type == 'LTE': 1162 self.send_cmd('BSE:FUNCtion:LTE:{}:PAGing:PAGE'.format( 1163 Keysight5GTestApp._format_cells(cell))) 1164 elif cell_type == 'NR5G': 1165 self.send_cmd( 1166 'BSE:CONFig:NR5G:{}:RCONtrol:RRC:STARt PAGing'.format( 1167 Keysight5GTestApp._format_cells(cell))) 1168 1169 def enable_rach(self, cell_type, cell, enabled): 1170 self.send_cmd('BSE:CONFig:{}:{}:MAC:RACH:IGNore {}'.format( 1171 cell_type, Keysight5GTestApp._format_cells(cell), int(enabled))) 1172 self.send_cmd('BSE:CONFig:{}:APPLY'.format(cell_type)) 1173 1174 def enable_preamble_report(self, cell_type, enable): 1175 self.send_cmd('BSE:CONFig:{}:PReamble:REPort:STATe {}'.format( 1176 cell_type, int(enable))) 1177 1178 def fetch_preamble_report(self, cell_type, cell, num_reports=10): 1179 report = self.send_cmd( 1180 'BSE:CONFig:{}:{}:PReamble:REPort:FETCh:JSON? {}'.format( 1181 cell_type, Keysight5GTestApp._format_cells(cell), num_reports), 1182 read_response=1) 1183 self.send_cmd('BSE:CONFig:{}:PReamble:REPort:CLEAr'.format(cell_type)) 1184 if 'No Data' in report: 1185 report = None 1186 return report 1187