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 time 18 19from enum import Enum 20 21from acts.controllers import abstract_inst 22 23LTE_ATTACH_RESP = 'ATT' 24LTE_CONN_RESP = 'CONN' 25LTE_IDLE_RESP = 'IDLE' 26LTE_PSWITCHED_ON_RESP = 'ON' 27LTE_PSWITCHED_OFF_RESP = 'OFF' 28 29WCDMA_ATTACH_RESP = 'ATT' 30WCDMA_CESTABLISHED_RESP = 'CEST' 31WCDMA_PSWITCHED_ON_RESP = 'ON' 32 33STATE_CHANGE_TIMEOUT = 20 34 35 36class IPAddressType(Enum): 37 """ IP Address types""" 38 IPV4 = "IPV4" 39 IPV6 = "IPV6" 40 IPV4V6 = "IPV46" 41 42 43class SignallingState(Enum): 44 """Signalling states common to all RATs.""" 45 ON = 'ON' 46 OFF = 'OFF' 47 ReadyForHandover = 'RFH' 48 49 50class SccActivationMode(Enum): 51 """Activation mode to use for SCCs.""" 52 AUTO = 'AUTO' 53 MANUAL = 'MAN' 54 SEMI_AUTO = 'SEM' 55 56 57class SccState(Enum): 58 """Secondary component carrier states.""" 59 ON = 'ON' 60 OFF = 'OFF' 61 RRC = 'RRC' 62 MAC = 'MAC' 63 64 65class LteState(Enum): 66 """LTE ON and OFF""" 67 LTE_ON = 'ON' 68 LTE_OFF = 'OFF' 69 70 71class BtsNumber(Enum): 72 """Base station Identifiers.""" 73 BTS1 = 'PCC' 74 BTS2 = 'SCC1' 75 BTS3 = 'SCC2' 76 BTS4 = 'SCC3' 77 BTS5 = 'SCC4' 78 BTS6 = 'SCC6' 79 BTS7 = 'SCC7' 80 81 82class LteBandwidth(Enum): 83 """Supported LTE bandwidths.""" 84 BANDWIDTH_1MHz = 'B014' 85 BANDWIDTH_3MHz = 'B030' 86 BANDWIDTH_5MHz = 'B050' 87 BANDWIDTH_10MHz = 'B100' 88 BANDWIDTH_15MHz = 'B150' 89 BANDWIDTH_20MHz = 'B200' 90 91 92def BandwidthFromFloat(bw): 93 if bw == 20: 94 return LteBandwidth.BANDWIDTH_20MHz 95 elif bw == 15: 96 return LteBandwidth.BANDWIDTH_15MHz 97 elif bw == 10: 98 return LteBandwidth.BANDWIDTH_10MHz 99 elif bw == 5: 100 return LteBandwidth.BANDWIDTH_5MHz 101 elif bw == 3: 102 return LteBandwidth.BANDWIDTH_3MHz 103 elif bw == 1.4: 104 return LteBandwidth.BANDWIDTH_1MHz 105 106 raise ValueError('Bandwidth {} MHz is not valid for LTE'.format(bandwidth)) 107 108 109class DrxMode(Enum): 110 """DRX Modes.""" 111 DRXS = 'DRXS' 112 DRXL = 'DRXL' 113 USER_DEFINED = 'UDEF' 114 ON = 'ON' 115 OFF = 'OFF' 116 117 118class DuplexMode(Enum): 119 """Duplex Modes""" 120 FDD = 'FDD' 121 TDD = 'TDD' 122 123 124class SchedulingMode(Enum): 125 """Supported scheduling modes.""" 126 RMC = 'RMC' 127 USERDEFINEDCH = 'UDCHannels' 128 129 130class TransmissionModes(Enum): 131 """Supported transmission modes.""" 132 TM1 = 'TM1' 133 TM2 = 'TM2' 134 TM3 = 'TM3' 135 TM4 = 'TM4' 136 TM7 = 'TM7' 137 TM8 = 'TM8' 138 TM9 = 'TM9' 139 140 141class UseCarrierSpecific(Enum): 142 """Enable or disable carrier specific.""" 143 UCS_ON = 'ON' 144 UCS_OFF = 'OFF' 145 146 147class RbPosition(Enum): 148 """Supported RB positions.""" 149 LOW = 'LOW' 150 HIGH = 'HIGH' 151 P5 = 'P5' 152 P10 = 'P10' 153 P23 = 'P23' 154 P35 = 'P35' 155 P48 = 'P48' 156 157 158class ModulationType(Enum): 159 """Supported Modulation Types.""" 160 QPSK = 'QPSK' 161 Q16 = 'Q16' 162 Q64 = 'Q64' 163 Q256 = 'Q256' 164 165 166class DciFormat(Enum): 167 """Support DCI Formats for MIMOs""" 168 D1 = 'D1' 169 D1A = 'D1A' 170 D1B = 'D1B' 171 D2 = 'D2' 172 D2A = 'D2A' 173 D2B = 'D2B' 174 D2C = 'D2C' 175 176 177class MimoModes(Enum): 178 """MIMO Modes dl antennas""" 179 MIMO1x1 = 'ONE' 180 MIMO2x2 = 'TWO' 181 MIMO4x4 = 'FOUR' 182 183 184class MimoScenario(Enum): 185 """Supported mimo scenarios""" 186 SCEN1x1 = 'SCELl:FLEXible SUA1,RF1C,RX1,RF1C,TX1' 187 SCEN2x2 = 'TRO:FLEXible SUA1,RF1C,RX1,RF1C,TX1,RF3C,TX2' 188 SCEN4x4 = 'FRO FLEXible SUA1,RF1C,RX1,RF1C,TX1,RF3C,TX2,RF2C,TX3,RF4C,TX4' 189 190 191class RrcState(Enum): 192 """States to enable/disable rrc.""" 193 RRC_ON = 'ON' 194 RRC_OFF = 'OFF' 195 196 197class MacPadding(Enum): 198 """Enables/Disables Mac Padding.""" 199 ON = 'ON' 200 OFF = 'OFF' 201 202 203class ConnectionType(Enum): 204 """Supported Connection Types.""" 205 TEST = 'TESTmode' 206 DAU = 'DAPPlication' 207 208 209class RepetitionMode(Enum): 210 """Specifies LTE Measurement Repetition Mode.""" 211 SINGLESHOT = 'SINGleshot' 212 CONTINUOUS = 'CONTinuous' 213 214 215class TpcPowerControl(Enum): 216 """Specifies Up Link power control types.""" 217 MIN_POWER = 'MINPower' 218 MAX_POWER = 'MAXPower' 219 CONSTANT = 'CONStant' 220 SINGLE = 'SINGle' 221 UDSINGLE = 'UDSingle' 222 UDCONTINUOUS = 'UDContinuous' 223 ALTERNATE = 'ALT0' 224 CLOSED_LOOP = 'CLOop' 225 RP_CONTROL = 'RPControl' 226 FLEX_POWER = 'FULPower' 227 228 229class ReducedPdcch(Enum): 230 """Enables/disables the reduction of PDCCH resources.""" 231 ON = 'ON' 232 OFF = 'OFF' 233 234 235class Cmw500(abstract_inst.SocketInstrument): 236 def __init__(self, ip_addr, port): 237 """Init method to setup variables for controllers. 238 239 Args: 240 ip_addr: Controller's ip address. 241 port: Port 242 """ 243 super(Cmw500, self).__init__(ip_addr, port) 244 self._connect_socket() 245 self._send('*CLS') 246 self._send('*ESE 0;*SRE 0') 247 self._send('*CLS') 248 self._send('*ESE 1;*SRE 4') 249 self._send('SYST:DISP:UPD ON') 250 251 def switch_lte_signalling(self, state): 252 """ Turns LTE signalling ON/OFF. 253 254 Args: 255 state: an instance of LteState indicating the state to which LTE 256 signal has to be set. 257 """ 258 if not isinstance(state, LteState): 259 raise ValueError('state should be the instance of LteState.') 260 261 state = state.value 262 263 cmd = 'SOURce:LTE:SIGN:CELL:STATe {}'.format(state) 264 self.send_and_recv(cmd) 265 266 time_elapsed = 0 267 while time_elapsed < STATE_CHANGE_TIMEOUT: 268 response = self.send_and_recv('SOURce:LTE:SIGN:CELL:STATe:ALL?') 269 270 if response == state + ',ADJ': 271 self._logger.info('LTE signalling is now {}.'.format(state)) 272 break 273 274 # Wait for a second and increase time count by one 275 time.sleep(1) 276 time_elapsed += 1 277 else: 278 raise CmwError('Failed to turn {} LTE signalling.'.format(state)) 279 280 def switch_scc_state(self, scc_index, state): 281 """ Changes the SCC to the requested state. 282 283 Args: 284 scc_index: the SCC number to modify. 285 state: an instance of SccState indicating which SCC state to set. 286 """ 287 cmd = 'CALL:LTE:SIGN:SCC{}:ACTion {}'.format(scc_index, state.value) 288 self.send_and_recv(cmd) 289 self.wait_for_scc_state(scc_index, [state]) 290 291 def wait_for_scc_state(self, scc_index, allowed, timeout=120): 292 """ Polls for a SCC to reach the requested state. 293 294 Args: 295 scc_index: an integer defining the scc number. 296 allowed: a list of SccStates defining the allowed states. 297 timeout: the maximum amount of time to wait for the requested state. 298 """ 299 self.wait_for_response( 300 'FETCh:LTE:SIGN:SCC{}:STATe?'.format(scc_index), 301 [a.value for a in allowed], 302 timeout, 303 ) 304 305 def wait_for_response(self, cmd, allowed, timeout=120): 306 """Polls a specific query command until an allowed response is returned. 307 308 Args: 309 cmd: the query command string. 310 allowed: a collection of allowed string responses. 311 timeout: the maximum amount of time to wait for an allowed response. 312 """ 313 time_elapsed = 0 314 while time_elapsed < timeout: 315 response = self.send_and_recv(cmd) 316 317 if response in allowed: 318 return 319 320 time.sleep(1) 321 time_elapsed += 1 322 323 raise CmwError('Failed to wait for valid response.') 324 325 def enable_packet_switching(self): 326 """Enable packet switching in call box.""" 327 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion CONNect') 328 self.wait_for_pswitched_state() 329 330 def disable_packet_switching(self): 331 """Disable packet switching in call box.""" 332 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion DISConnect') 333 self.wait_for_pswitched_state() 334 335 @property 336 def use_carrier_specific(self): 337 """Gets current status of carrier specific duplex configuration.""" 338 return self.send_and_recv('CONFigure:LTE:SIGN:DMODe:UCSPECific?') 339 340 @use_carrier_specific.setter 341 def use_carrier_specific(self, state): 342 """Sets the carrier specific duplex configuration. 343 344 Args: 345 state: ON/OFF UCS configuration. 346 """ 347 cmd = 'CONFigure:LTE:SIGN:DMODe:UCSPECific {}'.format(state) 348 self.send_and_recv(cmd) 349 350 def send_and_recv(self, cmd): 351 """Send and recv the status of the command. 352 353 Args: 354 cmd: Command to send. 355 356 Returns: 357 status: returns the status of the command sent. 358 """ 359 360 self._send(cmd) 361 if '?' in cmd: 362 status = self._recv() 363 return status 364 365 def configure_mimo_settings(self, mimo): 366 """Sets the mimo scenario for the test. 367 368 Args: 369 mimo: mimo scenario to set. 370 """ 371 cmd = 'ROUTe:LTE:SIGN:SCENario:{}'.format(mimo.value) 372 self.send_and_recv(cmd) 373 374 def wait_for_pswitched_state(self, timeout=10): 375 """Wait until pswitched state. 376 377 Args: 378 timeout: timeout for lte pswitched state. 379 380 Raises: 381 CmwError on timeout. 382 """ 383 while timeout > 0: 384 state = self.send_and_recv('FETCh:LTE:SIGN:PSWitched:STATe?') 385 if state == LTE_PSWITCHED_ON_RESP: 386 self._logger.debug('Connection to setup initiated.') 387 break 388 elif state == LTE_PSWITCHED_OFF_RESP: 389 self._logger.debug('Connection to setup detached.') 390 break 391 392 # Wait for a second and decrease count by one 393 time.sleep(1) 394 timeout -= 1 395 else: 396 raise CmwError('Failure in setting up/detaching connection') 397 398 def wait_for_attached_state(self, timeout=120): 399 """Attach the controller with device. 400 401 Args: 402 timeout: timeout for phone to get attached. 403 404 Raises: 405 CmwError on time out. 406 """ 407 while timeout > 0: 408 state = self.send_and_recv('FETCh:LTE:SIGN:PSWitched:STATe?') 409 410 if state == LTE_ATTACH_RESP: 411 self._logger.debug('Call box attached with device') 412 break 413 414 # Wait for a second and decrease count by one 415 time.sleep(1) 416 timeout -= 1 417 else: 418 raise CmwError('Device could not be attached') 419 420 def wait_for_rrc_state(self, state, timeout=120): 421 """ Waits until a certain RRC state is set. 422 423 Args: 424 state: the RRC state that is being waited for. 425 timeout: timeout for phone to be in connected state. 426 427 Raises: 428 CmwError on time out. 429 """ 430 if state not in [LTE_CONN_RESP, LTE_IDLE_RESP]: 431 raise ValueError( 432 'The allowed values for state are {} and {}.'.format( 433 LTE_CONN_RESP, LTE_IDLE_RESP)) 434 435 while timeout > 0: 436 new_state = self.send_and_recv('SENSe:LTE:SIGN:RRCState?') 437 438 if new_state == state: 439 self._logger.debug('The RRC state is {}.'.format(new_state)) 440 break 441 442 # Wait for a second and decrease count by one 443 time.sleep(1) 444 timeout -= 1 445 else: 446 raise CmwError('Timeout before RRC state was {}.'.format(state)) 447 448 def stop_all_signalling(self): 449 """Turns off all signaling applications, generators, or measurements.""" 450 self.send_and_recv('SYSTem:SIGNaling:ALL:OFF') 451 self.wait_until_quiet() 452 453 def wait_until_quiet(self): 454 """Waits for all pending operations to stop on the callbox.""" 455 self.send_and_recv('*OPC?') 456 457 def reset(self): 458 """System level reset""" 459 self.send_and_recv('*RST; *OPC') 460 461 @property 462 def get_instrument_id(self): 463 """Gets instrument identification number""" 464 return self.send_and_recv('*IDN?') 465 466 def disconnect(self): 467 """Disconnect controller from device and switch to local mode.""" 468 self.switch_lte_signalling(LteState.LTE_OFF) 469 self.close_remote_mode() 470 self._close_socket() 471 472 def close_remote_mode(self): 473 """Exits remote mode to local mode.""" 474 self.send_and_recv('>L') 475 476 def detach(self): 477 """Detach callbox and controller.""" 478 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion DETach') 479 480 @property 481 def rrc_connection(self): 482 """Gets the RRC connection state.""" 483 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:KRRC?') 484 485 @rrc_connection.setter 486 def rrc_connection(self, state): 487 """Selects whether the RRC connection is kept or released after attach. 488 489 Args: 490 mode: RRC State ON/OFF. 491 """ 492 if not isinstance(state, RrcState): 493 raise ValueError('state should be the instance of RrcState.') 494 495 cmd = 'CONFigure:LTE:SIGN:CONNection:KRRC {}'.format(state.value) 496 self.send_and_recv(cmd) 497 498 @property 499 def rrc_connection_timer(self): 500 """Gets the inactivity timeout for disabled rrc connection.""" 501 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:RITimer?') 502 503 @rrc_connection_timer.setter 504 def rrc_connection_timer(self, time_in_secs): 505 """Sets the inactivity timeout for disabled rrc connection. By default 506 the timeout is set to 5. 507 508 Args: 509 time_in_secs: timeout of inactivity in rrc connection. 510 """ 511 cmd = 'CONFigure:LTE:SIGN:CONNection:RITimer {}'.format(time_in_secs) 512 self.send_and_recv(cmd) 513 514 @property 515 def scc_activation_mode(self): 516 """Gets the activation mode to use for SCCs when establishing a 517 connection. 518 """ 519 return self.send_and_recv('CONFigure:LTE:SIGN:SCC:AMODe?') 520 521 @scc_activation_mode.setter 522 def scc_activation_mode(self, activation_mode): 523 """Sets the activation mode to use with SCCs when establishing a 524 connection. 525 526 Args: 527 activation_mode: the scc activation mode to use. 528 """ 529 if not isinstance(activation_mode, SccActivationMode): 530 raise ValueError('state should be the instance of RrcState.') 531 532 cmd = 'CONFigure:LTE:SIGN:SCC:AMODe {}'.format(activation_mode.value) 533 self.send_and_recv(cmd) 534 535 @property 536 def dl_mac_padding(self): 537 """Gets the state of mac padding.""" 538 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:DLPadding?') 539 540 @dl_mac_padding.setter 541 def dl_mac_padding(self, state): 542 """Enables/Disables downlink padding at the mac layer. 543 544 Args: 545 state: ON/OFF 546 """ 547 cmd = 'CONFigure:LTE:SIGN:CONNection:DLPadding {}'.format(state.value) 548 self.send_and_recv(cmd) 549 550 @property 551 def connection_type(self): 552 """Gets the connection type applied in callbox.""" 553 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:CTYPe?') 554 555 @connection_type.setter 556 def connection_type(self, ctype): 557 """Sets the connection type to be applied. 558 559 Args: 560 ctype: Connection type. 561 """ 562 cmd = 'CONFigure:LTE:SIGN:CONNection:CTYPe {}'.format(ctype.value) 563 self.send_and_recv(cmd) 564 565 @property 566 def drx_connected_mode(self): 567 """ Gets the Connected DRX LTE cell parameter 568 569 Args: 570 None 571 572 Returns: 573 DRX connected mode (ON, OFF, USER_DEFINED, DRX_S, DRX_L) 574 """ 575 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:ENABle?' 576 return self.send_and_recv(cmd) 577 578 @drx_connected_mode.setter 579 def drx_connected_mode(self, mode): 580 """ Sets the Connected DRX LTE cell parameter 581 582 Args: 583 mode: DRX mode 584 585 Returns: 586 None 587 """ 588 if not isinstance(mode, DrxMode): 589 raise ValueError('state should be the instance of DrxMode.') 590 591 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:ENABle {}'.format(mode.value) 592 self.send_and_recv(cmd) 593 594 @property 595 def drx_on_duration_timer(self): 596 """ Gets the amount of PDCCH subframes to wait for data after 597 waking up from a DRX cycle 598 599 Args: 600 None 601 602 Returns: 603 DRX mode duration timer 604 """ 605 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:ODTimer?' 606 return self.send_and_recv(cmd) 607 608 @drx_on_duration_timer.setter 609 def drx_on_duration_timer(self, time): 610 """ Sets the amount of PDCCH subframes to wait for data after 611 waking up from a DRX cycle 612 613 Args: 614 timer: Length of interval to wait for user data to be transmitted 615 616 Returns: 617 None 618 """ 619 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:ODTimer {}'.format(time) 620 self.send_and_recv(cmd) 621 622 @property 623 def drx_inactivity_timer(self): 624 """ Gets the number of PDCCH subframes to wait before entering DRX mode 625 626 Args: 627 None 628 629 Returns: 630 DRX mode inactivity timer 631 """ 632 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:ITIMer?' 633 return self.send_and_recv(cmd) 634 635 @drx_inactivity_timer.setter 636 def drx_inactivity_timer(self, time): 637 """ Sets the number of PDCCH subframes to wait before entering DRX mode 638 639 Args: 640 timer: Length of the interval to wait 641 642 Returns: 643 None 644 """ 645 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:ITIMer {}'.format(time) 646 self.send_and_recv(cmd) 647 648 @property 649 def drx_retransmission_timer(self): 650 """ Gets the number of consecutive PDCCH subframes to wait 651 for retransmission 652 653 Args: 654 None 655 656 Returns: 657 Number of PDCCH subframes to wait for retransmission 658 """ 659 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:RTIMer?' 660 self.send_and_recv(cmd) 661 662 @drx_retransmission_timer.setter 663 def drx_retransmission_timer(self, time): 664 """ Sets the number of consecutive PDCCH subframes to wait 665 for retransmission 666 667 Args: 668 time: Number of PDCCH subframes to wait 669 for retransmission 670 671 Returns: 672 None 673 """ 674 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:RTIMer {}'.format(time) 675 self.send_and_recv(cmd) 676 677 @property 678 def drx_long_cycle(self): 679 """ Gets the amount of subframes representing a DRX long cycle 680 681 Args: 682 None 683 684 Returns: 685 The amount of subframes representing one long DRX cycle. 686 One cycle consists of DRX sleep + DRX on duration 687 """ 688 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:LDCYcle?' 689 return self.send_and_recv(cmd) 690 691 @drx_long_cycle.setter 692 def drx_long_cycle(self, long_cycle): 693 """ Sets the amount of subframes representing a DRX long cycle 694 695 Args: 696 long_cycle: The amount of subframes representing one long DRX cycle. 697 One cycle consists of DRX sleep + DRX on duration 698 699 Returns: 700 None 701 """ 702 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:LDCYcle {}'.format( 703 long_cycle) 704 self.send_and_recv(cmd) 705 706 @property 707 def drx_long_cycle_offset(self): 708 """ Gets the offset used to determine long cycle starting 709 subframe 710 711 Args: 712 None 713 714 Returns: 715 Long cycle offset 716 """ 717 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:SOFFset?' 718 return self.send_and_recv(cmd) 719 720 @drx_long_cycle_offset.setter 721 def drx_long_cycle_offset(self, offset): 722 """ Sets the offset used to determine long cycle starting 723 subframe 724 725 Args: 726 offset: Number in range 0...(long cycle - 1) 727 """ 728 cmd = 'CONFigure:LTE:SIGN:CONNection:CDRX:SOFFset {}'.format(offset) 729 self.send_and_recv(cmd) 730 731 @property 732 def apn(self): 733 """Gets the callbox network Access Point Name.""" 734 cmd = 'CONFigure:LTE:SIGNaling:CONNection:APN?' 735 return self.send_and_recv(cmd) 736 737 @apn.setter 738 def apn(self, apn): 739 """Sets the callbox network Access Point Name. 740 741 Args: 742 apn: the APN name 743 """ 744 cmd = 'CONFigure:LTE:SIGNaling:CONNection:APN {}'.format(apn) 745 self.send_and_recv(cmd) 746 747 @property 748 def ip_type(self): 749 """Gets the callbox network IP type.""" 750 cmd = 'CONFigure:LTE:SIGNaling:CONNection:IPVersion?' 751 return self.send_and_recv(cmd) 752 753 @ip_type.setter 754 def ip_type(self, ip_type): 755 """ Configures the callbox network IP type. 756 757 Args: 758 ip_type: the network type to use. 759 """ 760 if not isinstance(ip_type, IPAddressType): 761 raise ValueError('state should be the instance of IPAddressType.') 762 763 cmd = 'CONFigure:LTE:SIGNaling:CONNection:IPVersion {}'.format( 764 ip_type.value) 765 return self.send_and_recv(cmd) 766 767 @property 768 def mtu(self): 769 """Gets the callbox network Maximum Transmission Unit.""" 770 cmd = 'CONFigure:DATA:CONTrol:MTU?' 771 return self.send_and_recv(cmd) 772 773 @mtu.setter 774 def mtu(self, mtu): 775 """Sets the callbox network Maximum Transmission Unit. 776 777 Args: 778 mtu: the MTU size. 779 """ 780 cmd = 'CONFigure:DATA:CONTrol:MTU {}'.format(mtu) 781 self.send_and_recv(cmd) 782 783 def get_base_station(self, bts_num=BtsNumber.BTS1): 784 """Gets the base station object based on bts num. By default 785 bts_num set to PCC 786 787 Args: 788 bts_num: base station identifier 789 790 Returns: 791 base station object. 792 """ 793 return BaseStation(self, bts_num) 794 795 def init_lte_measurement(self): 796 """Gets the class object for lte measurement which can be used to 797 initiate measurements. 798 799 Returns: 800 lte measurement object. 801 """ 802 return LteMeasurement(self) 803 804 def set_sms(self, message): 805 """Sets the SMS message to be sent to the DUT. 806 807 Args: 808 message: the SMS message to send. 809 """ 810 cmd = 'CONFigure:LTE:SIGN:SMS:OUTGoing:INTernal "{}"'.format(message) 811 self.send_and_recv(cmd) 812 813 def send_sms(self): 814 """Sends the currently set SMS message.""" 815 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion SMS;*OPC?') 816 timeout = time.time() + STATE_CHANGE_TIMEOUT 817 while time.time() < timeout: 818 state = self.send_and_recv( 819 'SENSe:LTE:SIGN:SMS:OUTGoing:INFO:LMSent?') 820 if state == "SUCC": 821 return 822 time.sleep(1) 823 824 raise CmwError('Failed to send SMS message') 825 826 827class BaseStation(object): 828 """Class to interact with different base stations""" 829 def __init__(self, cmw, bts_num): 830 if not isinstance(bts_num, BtsNumber): 831 raise ValueError('bts_num should be an instance of BtsNumber.') 832 self._bts = bts_num.value 833 self._cmw = cmw 834 835 @property 836 def scc_state(self): 837 """Gets the scc state of cell.""" 838 cmd = 'FETCh:LTE:SIGN:{}:STATe?'.format(self._bts) 839 return self._cmw.send_and_recv(cmd) 840 841 @property 842 def duplex_mode(self): 843 """Gets current duplex of cell.""" 844 cmd = 'CONFigure:LTE:SIGN:{}:DMODe?'.format(self._bts) 845 return self._cmw.send_and_recv(cmd) 846 847 @duplex_mode.setter 848 def duplex_mode(self, mode): 849 """Sets the Duplex mode of cell. 850 851 Args: 852 mode: String indicating FDD or TDD. 853 """ 854 if not isinstance(mode, DuplexMode): 855 raise ValueError('mode should be an instance of DuplexMode.') 856 857 cmd = 'CONFigure:LTE:SIGN:{}:DMODe {}'.format(self._bts, mode.value) 858 self._cmw.send_and_recv(cmd) 859 860 @property 861 def band(self): 862 """Gets the current band of cell.""" 863 cmd = 'CONFigure:LTE:SIGN:{}:BAND?'.format(self._bts) 864 return self._cmw.send_and_recv(cmd) 865 866 @band.setter 867 def band(self, band): 868 """Sets the Band of cell. 869 870 Args: 871 band: band of cell. 872 """ 873 cmd = 'CONFigure:LTE:SIGN:{}:BAND {}'.format(self._bts, band) 874 self._cmw.send_and_recv(cmd) 875 876 @property 877 def dl_channel(self): 878 """Gets the downlink channel of cell.""" 879 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:DL?'.format(self._bts) 880 return self._cmw.send_and_recv(cmd) 881 882 @dl_channel.setter 883 def dl_channel(self, channel): 884 """Sets the downlink channel number of cell. 885 886 Args: 887 channel: downlink channel number of cell. 888 """ 889 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:DL {}'.format( 890 self._bts, channel) 891 self._cmw.send_and_recv(cmd) 892 893 @property 894 def ul_channel(self): 895 """Gets the uplink channel of cell.""" 896 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:UL?'.format(self._bts) 897 return self._cmw.send_and_recv(cmd) 898 899 @ul_channel.setter 900 def ul_channel(self, channel): 901 """Sets the up link channel number of cell. 902 903 Args: 904 channel: up link channel number of cell. 905 """ 906 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:UL {}'.format( 907 self._bts, channel) 908 self._cmw.send_and_recv(cmd) 909 910 @property 911 def bandwidth(self): 912 """Get the channel bandwidth of the cell.""" 913 cmd = 'CONFigure:LTE:SIGN:CELL:BANDwidth:{}:DL?'.format(self._bts) 914 return self._cmw.send_and_recv(cmd) 915 916 @bandwidth.setter 917 def bandwidth(self, bandwidth): 918 """Sets the channel bandwidth of the cell. 919 920 Args: 921 bandwidth: channel bandwidth of cell. 922 """ 923 if not isinstance(bandwidth, LteBandwidth): 924 raise ValueError('bandwidth should be an instance of ' 925 'LteBandwidth.') 926 cmd = 'CONFigure:LTE:SIGN:CELL:BANDwidth:{}:DL {}'.format( 927 self._bts, bandwidth.value) 928 self._cmw.send_and_recv(cmd) 929 930 @property 931 def ul_frequency(self): 932 """Get the uplink frequency of the cell.""" 933 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:UL? MHZ'.format( 934 self._bts) 935 return self._cmw.send_and_recv(cmd) 936 937 @ul_frequency.setter 938 def ul_frequency(self, freq): 939 """Get the uplink frequency of the cell. 940 941 Args: 942 freq: uplink frequency of the cell. 943 """ 944 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:UL {} MHZ'.format( 945 self._bts, freq) 946 self._cmw.send_and_recv(cmd) 947 948 @property 949 def dl_frequency(self): 950 """Get the downlink frequency of the cell""" 951 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:DL? MHZ'.format( 952 self._bts) 953 return self._cmw.send_and_recv(cmd) 954 955 @dl_frequency.setter 956 def dl_frequency(self, freq): 957 """Get the downlink frequency of the cell. 958 959 Args: 960 freq: downlink frequency of the cell. 961 """ 962 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:DL {} MHZ'.format( 963 self._bts, freq) 964 self._cmw.send_and_recv(cmd) 965 966 @property 967 def transmode(self): 968 """Gets the TM of cell.""" 969 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:TRANsmission?'.format( 970 self._bts) 971 return self._cmw.send_and_recv(cmd) 972 973 @transmode.setter 974 def transmode(self, tm_mode): 975 """Sets the TM of cell. 976 977 Args: 978 tm_mode: TM of cell. 979 """ 980 if not isinstance(tm_mode, TransmissionModes): 981 raise ValueError('tm_mode should be an instance of ' 982 'Transmission modes.') 983 984 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:TRANsmission {}'.format( 985 self._bts, tm_mode.value) 986 self._cmw.send_and_recv(cmd) 987 988 @property 989 def downlink_power_level(self): 990 """Gets RSPRE level.""" 991 cmd = 'CONFigure:LTE:SIGN:DL:{}:RSEPre:LEVel?'.format(self._bts) 992 return self._cmw.send_and_recv(cmd) 993 994 @downlink_power_level.setter 995 def downlink_power_level(self, pwlevel): 996 """Modifies RSPRE level. 997 998 Args: 999 pwlevel: power level in dBm. 1000 """ 1001 cmd = 'CONFigure:LTE:SIGN:DL:{}:RSEPre:LEVel {}'.format( 1002 self._bts, pwlevel) 1003 self._cmw.send_and_recv(cmd) 1004 1005 @property 1006 def uplink_power_control(self): 1007 """Gets open loop nominal power directly.""" 1008 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:OLNPower?'.format(self._bts) 1009 return self._cmw.send_and_recv(cmd) 1010 1011 @uplink_power_control.setter 1012 def uplink_power_control(self, ul_power): 1013 """Sets open loop nominal power directly. 1014 1015 Args: 1016 ul_power: uplink power level. 1017 """ 1018 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:OLNPower {}'.format( 1019 self._bts, ul_power) 1020 self._cmw.send_and_recv(cmd) 1021 1022 @property 1023 def uldl_configuration(self): 1024 """Gets uldl configuration of the cell.""" 1025 cmd = 'CONFigure:LTE:SIGN:CELL:{}:ULDL?'.format(self._bts) 1026 return self._cmw.send_and_recv(cmd) 1027 1028 @uldl_configuration.setter 1029 def uldl_configuration(self, uldl): 1030 """Sets the ul-dl configuration. 1031 1032 Args: 1033 uldl: Configuration value ranging from 0 to 6. 1034 """ 1035 if uldl not in range(0, 7): 1036 raise ValueError('uldl configuration value should be between' 1037 ' 0 and 6 inclusive.') 1038 1039 cmd = 'CONFigure:LTE:SIGN:CELL:{}:ULDL {}'.format(self._bts, uldl) 1040 self._cmw.send_and_recv(cmd) 1041 1042 @property 1043 def tdd_special_subframe(self): 1044 """Gets special subframe of the cell.""" 1045 cmd = 'CONFigure:LTE:SIGN:CELL:{}:SSUBframe?'.format(self._bts) 1046 return self._cmw.send_and_recv(cmd) 1047 1048 @tdd_special_subframe.setter 1049 def tdd_special_subframe(self, sframe): 1050 """Sets the tdd special subframe of the cell. 1051 1052 Args: 1053 sframe: Integer value ranging from 1 to 9. 1054 """ 1055 if sframe not in range(0, 10): 1056 raise ValueError('tdd special subframe should be between 0 and 9' 1057 ' inclusive.') 1058 1059 cmd = 'CONFigure:LTE:SIGN:CELL:{}:SSUBframe {}'.format( 1060 self._bts, sframe) 1061 self._cmw.send_and_recv(cmd) 1062 1063 @property 1064 def scheduling_mode(self): 1065 """Gets the current scheduling mode.""" 1066 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:STYPe?'.format(self._bts) 1067 return self._cmw.send_and_recv(cmd) 1068 1069 @scheduling_mode.setter 1070 def scheduling_mode(self, mode): 1071 """Sets the scheduling type for the cell. 1072 1073 Args: 1074 mode: Selects the channel mode to be scheduled. 1075 """ 1076 if not isinstance(mode, SchedulingMode): 1077 raise ValueError('mode should be the instance of scheduling mode.') 1078 1079 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:STYPe {}'.format( 1080 self._bts, mode.value) 1081 self._cmw.send_and_recv(cmd) 1082 1083 @property 1084 def rb_configuration_dl(self): 1085 """Gets rmc's rb configuration for down link. This function returns 1086 Number of Resource blocks, Resource block position and Modulation type. 1087 """ 1088 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:{}:DL?'.format( 1089 self._bts, self.scheduling_mode) 1090 return self._cmw.send_and_recv(cmd) 1091 1092 @rb_configuration_dl.setter 1093 def rb_configuration_dl(self, rb_config): 1094 """Sets the rb configuration for down link for scheduling type. 1095 1096 Args: 1097 rb_config: Tuple containing Number of resource blocks, resource 1098 block position and modulation type. 1099 1100 Raises: 1101 ValueError: If tuple unpacking fails. 1102 """ 1103 if self.scheduling_mode == 'RMC': 1104 rb, rb_pos, modulation = rb_config 1105 1106 cmd = ('CONFigure:LTE:SIGN:CONNection:{}:RMC:DL {},{},' 1107 '{}'.format(self._bts, rb, rb_pos, modulation)) 1108 self._cmw.send_and_recv(cmd) 1109 1110 elif self.scheduling_mode == 'UDCH': 1111 rb, start_rb, modulation, tbs = rb_config 1112 1113 self.validate_rb(rb) 1114 1115 if not isinstance(modulation, ModulationType): 1116 raise ValueError('Modulation should be of type ' 1117 'ModulationType.') 1118 1119 cmd = ('CONFigure:LTE:SIGN:CONNection:{}:UDCHannels:DL {},{},' 1120 '{},{}'.format(self._bts, rb, start_rb, modulation.value, 1121 tbs)) 1122 self._cmw.send_and_recv(cmd) 1123 1124 @property 1125 def rb_configuration_ul(self): 1126 """Gets rb configuration for up link. This function returns 1127 Number of Resource blocks, Resource block position and Modulation type. 1128 """ 1129 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:{}:UL?'.format( 1130 self._bts, self.scheduling_mode) 1131 return self._cmw.send_and_recv(cmd) 1132 1133 @rb_configuration_ul.setter 1134 def rb_configuration_ul(self, rb_config): 1135 """Sets the rb configuration for down link for scheduling mode. 1136 1137 Args: 1138 rb_config: Tuple containing Number of resource blocks, resource 1139 block position and modulation type. 1140 1141 Raises: 1142 ValueError: If tuple unpacking fails. 1143 """ 1144 if self.scheduling_mode == 'RMC': 1145 rb, rb_pos, modulation = rb_config 1146 1147 cmd = ('CONFigure:LTE:SIGN:CONNection:{}:RMC:UL {},{},' 1148 '{}'.format(self._bts, rb, rb_pos, modulation)) 1149 self._cmw.send_and_recv(cmd) 1150 1151 elif self.scheduling_mode == 'UDCH': 1152 rb, start_rb, modulation, tbs = rb_config 1153 1154 self.validate_rb(rb) 1155 1156 if not isinstance(modulation, ModulationType): 1157 raise ValueError('Modulation should be of type ' 1158 'ModulationType.') 1159 cmd = ('CONFigure:LTE:SIGN:CONNection:{}:UDCHannels:UL {},{},' 1160 '{},{}'.format(self._bts, rb, start_rb, modulation.value, 1161 tbs)) 1162 self._cmw.send_and_recv(cmd) 1163 1164 def validate_rb(self, rb): 1165 """Validates if rb is within the limits for bandwidth set. 1166 1167 Args: 1168 rb: No. of resource blocks. 1169 1170 Raises: 1171 ValueError if rb out of range. 1172 """ 1173 bandwidth = self.bandwidth 1174 1175 if bandwidth == LteBandwidth.BANDWIDTH_1MHz.value: 1176 if not 0 <= rb <= 6: 1177 raise ValueError('RB should be between 0 to 6 inclusive' 1178 ' for 1.4Mhz.') 1179 elif bandwidth == LteBandwidth.BANDWIDTH_3MHz.value: 1180 if not 0 <= rb <= 10: 1181 raise ValueError('RB should be between 0 to 10 inclusive' 1182 ' for 3 Mhz.') 1183 elif bandwidth == LteBandwidth.BANDWIDTH_5MHz.value: 1184 if not 0 <= rb <= 25: 1185 raise ValueError('RB should be between 0 to 25 inclusive' 1186 ' for 5 Mhz.') 1187 elif bandwidth == LteBandwidth.BANDWIDTH_10MHz.value: 1188 if not 0 <= rb <= 50: 1189 raise ValueError('RB should be between 0 to 50 inclusive' 1190 ' for 10 Mhz.') 1191 elif bandwidth == LteBandwidth.BANDWIDTH_15MHz.value: 1192 if not 0 <= rb <= 75: 1193 raise ValueError('RB should be between 0 to 75 inclusive' 1194 ' for 15 Mhz.') 1195 elif bandwidth == LteBandwidth.BANDWIDTH_20MHz.value: 1196 if not 0 <= rb <= 100: 1197 raise ValueError('RB should be between 0 to 100 inclusive' 1198 ' for 20 Mhz.') 1199 1200 @property 1201 def rb_position_dl(self): 1202 """Gets the position of the allocated down link resource blocks within 1203 the channel band-width. 1204 """ 1205 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:RMC:RBPosition:DL?'.format( 1206 self._bts) 1207 return self._cmw.send_and_recv(cmd) 1208 1209 @rb_position_dl.setter 1210 def rb_position_dl(self, rbpos): 1211 """Selects the position of the allocated down link resource blocks 1212 within the channel band-width 1213 1214 Args: 1215 rbpos: position of resource blocks. 1216 """ 1217 if not isinstance(rbpos, RbPosition): 1218 raise ValueError('rbpos should be the instance of RbPosition.') 1219 1220 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:RMC:RBPosition:DL {}'.format( 1221 self._bts, rbpos.value) 1222 self._cmw.send_and_recv(cmd) 1223 1224 @property 1225 def rb_position_ul(self): 1226 """Gets the position of the allocated up link resource blocks within 1227 the channel band-width. 1228 """ 1229 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:RMC:RBPosition:UL?'.format( 1230 self._bts) 1231 return self._cmw.send_and_recv(cmd) 1232 1233 @rb_position_ul.setter 1234 def rb_position_ul(self, rbpos): 1235 """Selects the position of the allocated up link resource blocks 1236 within the channel band-width. 1237 1238 Args: 1239 rbpos: position of resource blocks. 1240 """ 1241 if not isinstance(rbpos, RbPosition): 1242 raise ValueError('rbpos should be the instance of RbPosition.') 1243 1244 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:RMC:RBPosition:UL {}'.format( 1245 self._bts, rbpos.value) 1246 self._cmw.send_and_recv(cmd) 1247 1248 @property 1249 def dci_format(self): 1250 """Gets the downlink control information (DCI) format.""" 1251 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:DCIFormat?'.format(self._bts) 1252 return self._cmw.send_and_recv(cmd) 1253 1254 @dci_format.setter 1255 def dci_format(self, dci_format): 1256 """Selects the downlink control information (DCI) format. 1257 1258 Args: 1259 dci_format: supported dci. 1260 """ 1261 if not isinstance(dci_format, DciFormat): 1262 raise ValueError('dci_format should be the instance of DciFormat.') 1263 1264 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:DCIFormat {}'.format( 1265 self._bts, dci_format.value) 1266 self._cmw.send_and_recv(cmd) 1267 1268 @property 1269 def dl_antenna(self): 1270 """Gets dl antenna count of cell.""" 1271 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:NENBantennas?'.format( 1272 self._bts) 1273 return self._cmw.send_and_recv(cmd) 1274 1275 @dl_antenna.setter 1276 def dl_antenna(self, num_antenna): 1277 """Sets the dl antenna count of cell. 1278 1279 Args: 1280 num_antenna: Count of number of dl antennas to use. 1281 """ 1282 if not isinstance(num_antenna, MimoModes): 1283 raise ValueError('num_antenna should be an instance of MimoModes.') 1284 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:NENBantennas {}'.format( 1285 self._bts, num_antenna.value) 1286 self._cmw.send_and_recv(cmd) 1287 1288 @property 1289 def reduced_pdcch(self): 1290 """Gets the reduction of PDCCH resources state.""" 1291 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:PDCCh:RPDCch?'.format( 1292 self._bts) 1293 return self._cmw.send_and_recv(cmd) 1294 1295 @reduced_pdcch.setter 1296 def reduced_pdcch(self, state): 1297 """Sets the reduction of PDCCH resources state. 1298 1299 Args: 1300 state: ON/OFF. 1301 """ 1302 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:PDCCh:RPDCch {}'.format( 1303 self._bts, state.value) 1304 self._cmw.send_and_recv(cmd) 1305 1306 @property 1307 def tpc_power_control(self): 1308 """Gets the type of uplink power control used.""" 1309 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:SET?'.format(self._bts) 1310 return self._cmw.send_and_recv(cmd) 1311 1312 @tpc_power_control.setter 1313 def tpc_power_control(self, set_type): 1314 """Set and execute the Up Link Power Control via TPC. 1315 1316 Args: 1317 set_type: Type of tpc power control. 1318 """ 1319 1320 if not isinstance(set_type, TpcPowerControl): 1321 raise ValueError('set_type should be the instance of ' 1322 'TpCPowerControl.') 1323 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:SET {}'.format( 1324 self._bts, set_type.value) 1325 self._cmw.send_and_recv(cmd) 1326 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:PEXecute'.format(self._bts) 1327 self._cmw.send_and_recv(cmd) 1328 1329 @property 1330 def tpc_closed_loop_target_power(self): 1331 """Gets the target powers for power control with the TPC setup.""" 1332 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:CLTPower?'.format(self._bts) 1333 return self._cmw.send_and_recv(cmd) 1334 1335 @tpc_closed_loop_target_power.setter 1336 def tpc_closed_loop_target_power(self, cltpower): 1337 """Sets the target powers for power control with the TPC setup. 1338 1339 Args: 1340 tpower: Target power. 1341 """ 1342 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:CLTPower {}'.format( 1343 self._bts, cltpower) 1344 self._cmw.send_and_recv(cmd) 1345 1346 1347class LteMeasurementState(Enum): 1348 """Possible measurement states""" 1349 OFF = 'OFF' 1350 READY = 'RDY' 1351 RUN = 'RUN' 1352 1353 1354def _try_parse(s, fun): 1355 try: 1356 return fun(s) 1357 except ValueError: 1358 return None 1359 1360 1361class LteMeasurement(object): 1362 """ Class for measuring LTE performance """ 1363 1364 INDEX_TX = 17 1365 INDEX_TX_MIN = 17 1366 INDEX_TX_MAX = 18 1367 1368 def __init__(self, cmw): 1369 self._cmw = cmw 1370 1371 @property 1372 def sample_count(self): 1373 """Gets the number of samples to use when calculating results.""" 1374 cmd = 'CONFigure:LTE:MEAS:MEValuation:SCOunt:MODulation?' 1375 return self._cmw.send_and_recv(cmd) 1376 1377 @sample_count.setter 1378 def sample_count(self, sample_count): 1379 cmd = 'CONFigure:LTE:MEAS:MEValuation:SCOunt:MODulation {}'.format( 1380 sample_count) 1381 self._cmw.send_and_recv(cmd) 1382 1383 @property 1384 def average(self): 1385 """Gets the average values of the most recent measurement. 1386 Invalid measurements are set to None. 1387 """ 1388 values = self._cmw.send_and_recv( 1389 'FETch:LTE:MEAS:MEValuation:MODulation:AVERage?').split(',') 1390 for i in range(0, 2): 1391 values[i] = _try_parse(values[i], int) 1392 for i in range(2, len(values)): 1393 values[i] = _try_parse(values[i], float) 1394 return values 1395 1396 @property 1397 def extrema(self): 1398 """Gets the extrema values of the most recent measurement. 1399 Invalid measurements are set to None. 1400 """ 1401 values = self._cmw.send_and_recv( 1402 'FETch:LTE:MEAS:MEValuation:MODulation:EXTReme?').split(',') 1403 for i in range(0, 2): 1404 values[i] = _try_parse(values[i], int) 1405 for i in range(2, len(values)): 1406 values[i] = _try_parse(values[i], float) 1407 return values 1408 1409 @property 1410 def stdev(self): 1411 """Gets the standard deviation of the most recent measurement. 1412 Invalid measurements are set to None. 1413 """ 1414 values = self._cmw.send_and_recv( 1415 'FETch:LTE:MEAS:MEValuation:MODulation:SDEV?').split(',') 1416 for i in range(0, 2): 1417 values[i] = _try_parse(values[i], int) 1418 for i in range(2, len(values)): 1419 values[i] = _try_parse(values[i], float) 1420 return values 1421 1422 @property 1423 def tx_average(self): 1424 """Gets the measured average Tx power (in dBm).""" 1425 value = self.average[self.INDEX_TX] 1426 if value is None: 1427 raise ValueError("LteMeasurement has no value for tx_average") 1428 return value 1429 1430 @property 1431 def tx_min(self): 1432 """Gets the measured minimum Tx power (in dBm).""" 1433 value = self.extrema[self.INDEX_TX_MIN] 1434 if value is None: 1435 raise ValueError("LteMeasurement has no value for tx_min") 1436 return value 1437 1438 @property 1439 def tx_max(self): 1440 """Gets the measured maximum Tx power (in dBm).""" 1441 value = self.extrema[self.INDEX_TX_MAX] 1442 if value is None: 1443 raise ValueError("LteMeasurement has no value for tx_max") 1444 return value 1445 1446 @property 1447 def tx_stdev(self): 1448 """Gets the measured Tx power standard deviation (in dBm).""" 1449 value = self.stdev[self.INDEX_TX] 1450 if value is None: 1451 raise ValueError( 1452 "LteMeasurement has no value for standard_deviation") 1453 return value 1454 1455 @property 1456 def measurement_repetition(self): 1457 """Returns the measurement repetition mode that has been set.""" 1458 return self._cmw.send_and_recv( 1459 'CONFigure:LTE:MEAS:MEValuation:REPetition?') 1460 1461 @measurement_repetition.setter 1462 def measurement_repetition(self, mode): 1463 """Sets the mode for measuring power levels. 1464 1465 Args: 1466 mode: Single shot/continuous. 1467 """ 1468 if not isinstance(mode, RepetitionMode): 1469 raise ValueError('mode should be the instance of Repetition Mode') 1470 1471 cmd = 'CONFigure:LTE:MEAS:MEValuation:REPetition {}'.format(mode.value) 1472 self._cmw.send_and_recv(cmd) 1473 1474 @property 1475 def query_measurement_state(self): 1476 """Returns the states and sub states of measurement.""" 1477 return self._cmw.send_and_recv('FETCh:LTE:MEAS:MEValuation:STATe:ALL?') 1478 1479 @property 1480 def measure_tx_power(self): 1481 """Return the current Tx power measurement.""" 1482 return self._cmw.send_and_recv( 1483 'FETCh:LTE:MEAS:MEValuation:PMONitor:AVERage?') 1484 1485 @property 1486 def state(self): 1487 """Gets the state of the measurement.""" 1488 cmd = 'FETCh:LTE:MEAS:MEValuation:STATe?' 1489 return LteMeasurementState(self._cmw.send_and_recv(cmd)) 1490 1491 def initialize_measurement(self): 1492 """Initialize measurement modules.""" 1493 self._cmw.send_and_recv( 1494 'CONF:LTE:MEAS:MEV:RES:ALL ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON,ON') 1495 self._cmw.send_and_recv('ROUTe:LTE:MEAS:SCENario:CSPath "LTE Sig1"') 1496 self._cmw.send_and_recv('INIT:LTE:MEAS:MEValuation;*OPC?') 1497 self._wait_for_state({LteMeasurementState.RUN}) 1498 1499 def run_measurement(self): 1500 """Runs a single Tx multievaluation measurement to completion.""" 1501 self.stop_measurement() 1502 self.measurement_repetition = RepetitionMode.SINGLESHOT 1503 self.initialize_measurement() 1504 self._wait_for_state({LteMeasurementState.READY}, timeout=120) 1505 1506 def stop_measurement(self): 1507 """Stops the on-going measurement. 1508 This function call does not free up resources allocated for 1509 measurement. Instead it moves from RUN to RDY state. 1510 """ 1511 self._cmw.send_and_recv('STOP:LTE:MEAS:MEValuation') 1512 self._wait_for_state( 1513 {LteMeasurementState.OFF, LteMeasurementState.READY}) 1514 1515 def abort_measurement(self): 1516 """Aborts the measurement abruptly. 1517 This function call will free up the resources allocated for 1518 measurement and all the results will be wiped off. 1519 """ 1520 self._cmw.send_and_recv('ABORt:LTE:MEAS:MEValuation') 1521 self._wait_for_state({LteMeasurementState.OFF}) 1522 1523 def _wait_for_state(self, states, timeout=10): 1524 """Polls the measurement state until it reaches an allowable state 1525 1526 Args: 1527 states: the allowed states 1528 timeout: the maximum amount time to wait (in seconds) 1529 """ 1530 while timeout > 0: 1531 if self.state in states: 1532 return 1533 1534 time.sleep(1) 1535 timeout -= 1 1536 1537 raise CmwError( 1538 'Failed to wait for LTE measurement state: {}.'.format(states)) 1539 1540 1541class CmwError(Exception): 1542 """Class to raise exceptions related to cmw.""" 1543