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 29STATE_CHANGE_TIMEOUT = 20 30 31 32class LteState(Enum): 33 """LTE ON and OFF""" 34 LTE_ON = 'ON' 35 LTE_OFF = 'OFF' 36 37 38class BtsNumber(Enum): 39 """Base station Identifiers.""" 40 BTS1 = 'PCC' 41 BTS2 = 'SCC1' 42 BTS3 = 'SCC2' 43 BTS4 = 'SCC3' 44 BTS5 = 'SCC4' 45 BTS6 = 'SCC6' 46 BTS7 = 'SCC7' 47 48 49class LteBandwidth(Enum): 50 """Supported LTE bandwidths.""" 51 BANDWIDTH_1MHz = 'B014' 52 BANDWIDTH_3MHz = 'B030' 53 BANDWIDTH_5MHz = 'B050' 54 BANDWIDTH_10MHz = 'B100' 55 BANDWIDTH_15MHz = 'B150' 56 BANDWIDTH_20MHz = 'B200' 57 58 59class DuplexMode(Enum): 60 """Duplex Modes""" 61 FDD = 'FDD' 62 TDD = 'TDD' 63 64 65class SchedulingMode(Enum): 66 """Supported scheduling modes.""" 67 RMC = 'RMC' 68 USERDEFINEDCH = 'UDCHannels' 69 70 71class TransmissionModes(Enum): 72 """Supported transmission modes.""" 73 TM1 = 'TM1' 74 TM2 = 'TM2' 75 TM3 = 'TM3' 76 TM4 = 'TM4' 77 TM7 = 'TM7' 78 TM8 = 'TM8' 79 TM9 = 'TM9' 80 81 82class UseCarrierSpecific(Enum): 83 """Enable or disable carrier specific.""" 84 UCS_ON = 'ON' 85 UCS_OFF = 'OFF' 86 87 88class RbPosition(Enum): 89 """Supported RB postions.""" 90 LOW = 'LOW' 91 HIGH = 'HIGH' 92 P5 = 'P5' 93 P10 = 'P10' 94 P23 = 'P23' 95 P35 = 'P35' 96 P48 = 'P48' 97 98 99class ModulationType(Enum): 100 """Supported Modulation Types.""" 101 QPSK = 'QPSK' 102 Q16 = 'Q16' 103 Q64 = 'Q64' 104 Q256 = 'Q256' 105 106 107class DciFormat(Enum): 108 """Support DCI Formats for MIMOs""" 109 D1 = 'D1' 110 D1A = 'D1A' 111 D1B = 'D1B' 112 D2 = 'D2' 113 D2A = 'D2A' 114 D2B = 'D2B' 115 D2C = 'D2C' 116 117 118class MimoModes(Enum): 119 """MIMO Modes dl antennas""" 120 MIMO1x1 = 'ONE' 121 MIMO2x2 = 'TWO' 122 MIMO4x4 = 'FOUR' 123 124 125class MimoScenario(Enum): 126 """Supportted mimo scenarios""" 127 SCEN1x1 = 'SCELl:FLEXible SUA1,RF1C,RX1,RF1C,TX1' 128 SCEN2x2 = 'TRO:FLEXible SUA1,RF1C,RX1,RF1C,TX1,RF3C,TX2' 129 SCEN4x4 = 'FRO FLEXible SUA1,RF1C,RX1,RF1C,TX1,RF3C,TX2,RF2C,TX3,RF4C,TX4' 130 131 132class RrcState(Enum): 133 """States to enable/disable rrc.""" 134 RRC_ON = 'ON' 135 RRC_OFF = 'OFF' 136 137 138class MacPadding(Enum): 139 """Enables/Disables Mac Padding.""" 140 ON = 'ON' 141 OFF = 'OFF' 142 143 144class ConnectionType(Enum): 145 """Supported Connection Types.""" 146 TEST = 'TESTmode' 147 DAU = 'DAPPlication' 148 149 150class RepetitionMode(Enum): 151 """Specifies LTE Measurement Repetition Mode.""" 152 SINGLESHOT = 'SINGleshot' 153 CONTINUOUS = 'CONTinuous' 154 155 156class TpcPowerControl(Enum): 157 """Specifies Up Link power control types.""" 158 MIN_POWER = 'MINPower' 159 MAX_POWER = 'MAXPower' 160 CONSTANT = 'CONStant' 161 SINGLE = 'SINGle' 162 UDSINGLE = 'UDSingle' 163 UDCONTINUOUS = 'UDContinuous' 164 ALTERNATE = 'ALT0' 165 CLOSED_LOOP = 'CLOop' 166 RP_CONTROL = 'RPControl' 167 FLEX_POWER = 'FULPower' 168 169 170class ReducedPdcch(Enum): 171 """Enables/disables the reduction of PDCCH resources.""" 172 ON = 'ON' 173 OFF = 'OFF' 174 175 176class Cmw500(abstract_inst.SocketInstrument): 177 178 def __init__(self, ip_addr, port): 179 """Init method to setup variables for controllers. 180 181 Args: 182 ip_addr: Controller's ip address. 183 port: Port 184 """ 185 super(Cmw500, self).__init__(ip_addr, port) 186 self._connect_socket() 187 self._send('*CLS') 188 self._send('*ESE 0;*SRE 0') 189 self._send('*CLS') 190 self._send('*ESE 1;*SRE 4') 191 self._send('SYST:DISP:UPD ON') 192 193 def switch_lte_signalling(self, state): 194 """ Turns LTE signalling ON/OFF. 195 196 Args: 197 state: an instance of LteState indicating the state to which LTE 198 signal has to be set. 199 """ 200 if not isinstance(state, LteState): 201 raise ValueError('state should be the instance of LteState.') 202 203 state = state.value 204 205 cmd = 'SOURce:LTE:SIGN:CELL:STATe {}'.format(state) 206 self.send_and_recv(cmd) 207 208 time_elapsed = 0 209 while time_elapsed < STATE_CHANGE_TIMEOUT: 210 response = self.send_and_recv('SOURce:LTE:SIGN:CELL:STATe:ALL?') 211 212 if response == state + ',ADJ': 213 self._logger.info('LTE signalling is now {}.'.format(state)) 214 break 215 216 # Wait for a second and increase time count by one 217 time.sleep(1) 218 time_elapsed += 1 219 else: 220 raise CmwError('Failed to turn {} LTE signalling.'.format(state)) 221 222 def enable_packet_switching(self): 223 """Enable packet switching in call box.""" 224 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion CONNect') 225 self.wait_for_pswitched_state() 226 227 def disable_packet_switching(self): 228 """Disable packet switching in call box.""" 229 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion DISConnect') 230 self.wait_for_pswitched_state() 231 232 @property 233 def use_carrier_specific(self): 234 """Gets current status of carrier specific duplex configuration.""" 235 return self.send_and_recv('CONFigure:LTE:SIGN:DMODe:UCSPECific?') 236 237 @use_carrier_specific.setter 238 def use_carrier_specific(self, state): 239 """Sets the carrier specific duplex configuration. 240 241 Args: 242 state: ON/OFF UCS configuration. 243 """ 244 cmd = 'CONFigure:LTE:SIGN:DMODe:UCSPECific {}'.format(state) 245 self.send_and_recv(cmd) 246 247 def send_and_recv(self, cmd): 248 """Send and recv the status of the command. 249 250 Args: 251 cmd: Command to send. 252 253 Returns: 254 status: returns the status of the command sent. 255 """ 256 257 self._send(cmd) 258 if '?' in cmd: 259 status = self._recv() 260 return status 261 262 def configure_mimo_settings(self, mimo): 263 """Sets the mimo scenario for the test. 264 265 Args: 266 mimo: mimo scenario to set. 267 """ 268 cmd = 'ROUTe:LTE:SIGN:SCENario:{}'.format(mimo.value) 269 self.send_and_recv(cmd) 270 271 def wait_for_pswitched_state(self, timeout=10): 272 """Wait until pswitched state. 273 274 Args: 275 timeout: timeout for lte pswitched state. 276 277 Raises: 278 CmwError on timeout. 279 """ 280 while timeout > 0: 281 state = self.send_and_recv('FETCh:LTE:SIGN:PSWitched:STATe?') 282 if state == LTE_PSWITCHED_ON_RESP: 283 self._logger.debug('Connection to setup initiated.') 284 break 285 elif state == LTE_PSWITCHED_OFF_RESP: 286 self._logger.debug('Connection to setup detached.') 287 break 288 289 # Wait for a second and decrease count by one 290 time.sleep(1) 291 timeout -= 1 292 else: 293 raise CmwError('Failure in setting up/detaching connection') 294 295 def wait_for_attached_state(self, timeout=120): 296 """Attach the controller with device. 297 298 Args: 299 timeout: timeout for phone to get attached. 300 301 Raises: 302 CmwError on time out. 303 """ 304 while timeout > 0: 305 state = self.send_and_recv('FETCh:LTE:SIGN:PSWitched:STATe?') 306 307 if state == LTE_ATTACH_RESP: 308 self._logger.debug('Call box attached with device') 309 break 310 311 # Wait for a second and decrease count by one 312 time.sleep(1) 313 timeout -= 1 314 else: 315 raise CmwError('Device could not be attached') 316 317 def wait_for_rrc_state(self, state, timeout=120): 318 """ Waits until a certain RRC state is set. 319 320 Args: 321 state: the RRC state that is being waited for. 322 timeout: timeout for phone to be in connnected state. 323 324 Raises: 325 CmwError on time out. 326 """ 327 if state not in [LTE_CONN_RESP, LTE_IDLE_RESP]: 328 raise ValueError( 329 'The allowed values for state are {} and {}.'.format( 330 LTE_CONN_RESP, LTE_IDLE_RESP)) 331 332 while timeout > 0: 333 new_state = self.send_and_recv('SENSe:LTE:SIGN:RRCState?') 334 335 if new_state == state: 336 self._logger.debug('The RRC state is {}.'.format(new_state)) 337 break 338 339 # Wait for a second and decrease count by one 340 time.sleep(1) 341 timeout -= 1 342 else: 343 raise CmwError('Timeout before RRC state was {}.'.format(state)) 344 345 def reset(self): 346 """System level reset""" 347 self.send_and_recv('*RST; *OPC') 348 349 @property 350 def get_instrument_id(self): 351 """Gets instrument identification number""" 352 return self.send_and_recv('*IDN?') 353 354 def disconnect(self): 355 """Disconnect controller from device and switch to local mode.""" 356 self.switch_lte_signalling(LteState.LTE_OFF) 357 self.close_remote_mode() 358 self._close_socket() 359 360 def close_remote_mode(self): 361 """Exits remote mode to local mode.""" 362 self.send_and_recv('>L') 363 364 def detach(self): 365 """Detach callbox and controller.""" 366 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion DETach') 367 368 @property 369 def rrc_connection(self): 370 """Gets the RRC connection state.""" 371 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:KRRC?') 372 373 @rrc_connection.setter 374 def rrc_connection(self, state): 375 """Selects whether the RRC connection is kept or released after attach. 376 377 Args: 378 mode: RRC State ON/OFF. 379 """ 380 if not isinstance(state, RrcState): 381 raise ValueError('state should be the instance of RrcState.') 382 383 cmd = 'CONFigure:LTE:SIGN:CONNection:KRRC {}'.format(state.value) 384 self.send_and_recv(cmd) 385 386 @property 387 def rrc_connection_timer(self): 388 """Gets the inactivity timeout for disabled rrc connection.""" 389 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:RITimer?') 390 391 @rrc_connection_timer.setter 392 def rrc_connection_timer(self, time_in_secs): 393 """Sets the inactivity timeout for disabled rrc connection. By default 394 the timeout is set to 5. 395 396 Args: 397 time_in_secs: timeout of inactivity in rrc connection. 398 """ 399 cmd = 'CONFigure:LTE:SIGN:CONNection:RITimer {}'.format(time_in_secs) 400 self.send_and_recv(cmd) 401 402 @property 403 def dl_mac_padding(self): 404 """Gets the state of mac padding.""" 405 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:DLPadding?') 406 407 @dl_mac_padding.setter 408 def dl_mac_padding(self, state): 409 """Enables/Disables downlink padding at the mac layer. 410 411 Args: 412 state: ON/OFF 413 """ 414 cmd = 'CONFigure:LTE:SIGN:CONNection:DLPadding {}'.format(state.value) 415 self.send_and_recv(cmd) 416 417 @property 418 def connection_type(self): 419 """Gets the connection type applied in callbox.""" 420 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:CTYPe?') 421 422 @connection_type.setter 423 def connection_type(self, ctype): 424 """Sets the connection type to be applied. 425 426 Args: 427 ctype: Connection type. 428 """ 429 cmd = 'CONFigure:LTE:SIGN:CONNection:CTYPe {}'.format(ctype.value) 430 self.send_and_recv(cmd) 431 432 def get_base_station(self, bts_num=BtsNumber.BTS1): 433 """Gets the base station object based on bts num. By default 434 bts_num set to PCC 435 436 Args: 437 bts_num: base station identifier 438 439 Returns: 440 base station object. 441 """ 442 return BaseStation(self, bts_num) 443 444 def init_lte_measurement(self): 445 """Gets the class object for lte measurement which can be used to 446 initiate measurements. 447 448 Returns: 449 lte measurement object. 450 """ 451 return LteMeasurement(self) 452 453 454class BaseStation(object): 455 """Class to interact with different base stations""" 456 457 def __init__(self, cmw, bts_num): 458 if not isinstance(bts_num, BtsNumber): 459 raise ValueError('bts_num should be an instance of BtsNumber.') 460 self._bts = bts_num.value 461 self._cmw = cmw 462 463 @property 464 def duplex_mode(self): 465 """Gets current duplex of cell.""" 466 cmd = 'CONFigure:LTE:SIGN:{}:DMODe?'.format(self._bts) 467 return self._cmw.send_and_recv(cmd) 468 469 @duplex_mode.setter 470 def duplex_mode(self, mode): 471 """Sets the Duplex mode of cell. 472 473 Args: 474 mode: String indicating FDD or TDD. 475 """ 476 if not isinstance(mode, DuplexMode): 477 raise ValueError('mode should be an instance of DuplexMode.') 478 479 cmd = 'CONFigure:LTE:SIGN:{}:DMODe {}'.format(self._bts, mode.value) 480 self._cmw.send_and_recv(cmd) 481 482 @property 483 def band(self): 484 """Gets the current band of cell.""" 485 cmd = 'CONFigure:LTE:SIGN:{}:BAND?'.format(self._bts) 486 return self._cmw.send_and_recv(cmd) 487 488 @band.setter 489 def band(self, band): 490 """Sets the Band of cell. 491 492 Args: 493 band: band of cell. 494 """ 495 cmd = 'CONFigure:LTE:SIGN:{}:BAND {}'.format(self._bts, band) 496 self._cmw.send_and_recv(cmd) 497 498 @property 499 def dl_channel(self): 500 """Gets the downlink channel of cell.""" 501 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:DL?'.format(self._bts) 502 return self._cmw.send_and_recv(cmd) 503 504 @dl_channel.setter 505 def dl_channel(self, channel): 506 """Sets the downlink channel number of cell. 507 508 Args: 509 channel: downlink channel number of cell. 510 """ 511 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:DL {}'.format( 512 self._bts, channel) 513 self._cmw.send_and_recv(cmd) 514 515 @property 516 def ul_channel(self): 517 """Gets the uplink channel of cell.""" 518 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:UL?'.format(self._bts) 519 return self._cmw.send_and_recv(cmd) 520 521 @ul_channel.setter 522 def ul_channel(self, channel): 523 """Sets the up link channel number of cell. 524 525 Args: 526 channel: up link channel number of cell. 527 """ 528 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:UL {}'.format( 529 self._bts, channel) 530 self._cmw.send_and_recv(cmd) 531 532 @property 533 def bandwidth(self): 534 """Get the channel bandwidth of the cell.""" 535 cmd = 'CONFigure:LTE:SIGN:CELL:BANDwidth:{}:DL?'.format(self._bts) 536 return self._cmw.send_and_recv(cmd) 537 538 @bandwidth.setter 539 def bandwidth(self, bandwidth): 540 """Sets the channel bandwidth of the cell. 541 542 Args: 543 bandwidth: channel bandwidth of cell. 544 """ 545 if not isinstance(bandwidth, LteBandwidth): 546 raise ValueError('bandwidth should be an instance of ' 547 'LteBandwidth.') 548 cmd = 'CONFigure:LTE:SIGN:CELL:BANDwidth:{}:DL {}'.format( 549 self._bts, bandwidth.value) 550 self._cmw.send_and_recv(cmd) 551 552 @property 553 def ul_frequency(self): 554 """Get the uplink frequency of the cell.""" 555 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:UL? MHZ'.format( 556 self._bts) 557 return self._cmw.send_and_recv(cmd) 558 559 @ul_frequency.setter 560 def ul_frequency(self, freq): 561 """Get the uplink frequency of the cell. 562 563 Args: 564 freq: uplink frequency of the cell. 565 """ 566 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:UL {} MHZ'.format( 567 self._bts, freq) 568 self._cmw.send_and_recv(cmd) 569 570 @property 571 def dl_frequency(self): 572 """Get the downlink frequency of the cell""" 573 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:DL? MHZ'.format( 574 self._bts) 575 return self._cmw.send_and_recv(cmd) 576 577 @dl_frequency.setter 578 def dl_frequency(self, freq): 579 """Get the downlink frequency of the cell. 580 581 Args: 582 freq: downlink frequency of the cell. 583 """ 584 cmd = 'CONFigure:LTE:SIGN:RFSettings:{}:CHANnel:DL {} MHZ'.format( 585 self._bts, freq) 586 self._cmw.send_and_recv(cmd) 587 588 @property 589 def transmode(self): 590 """Gets the TM of cell.""" 591 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:TRANsmission?'.format( 592 self._bts) 593 return self._cmw.send_and_recv(cmd) 594 595 @transmode.setter 596 def transmode(self, tm_mode): 597 """Sets the TM of cell. 598 599 Args: 600 tm_mode: TM of cell. 601 """ 602 if not isinstance(tm_mode, TransmissionModes): 603 raise ValueError('tm_mode should be an instance of ' 604 'Transmission modes.') 605 606 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:TRANsmission {}'.format( 607 self._bts, tm_mode.value) 608 self._cmw.send_and_recv(cmd) 609 610 @property 611 def downlink_power_level(self): 612 """Gets RSPRE level.""" 613 cmd = 'CONFigure:LTE:SIGN:DL:{}:RSEPre:LEVel?'.format(self._bts) 614 return self._cmw.send_and_recv(cmd) 615 616 @downlink_power_level.setter 617 def downlink_power_level(self, pwlevel): 618 """Modifies RSPRE level. 619 620 Args: 621 pwlevel: power level in dBm. 622 """ 623 cmd = 'CONFigure:LTE:SIGN:DL:{}:RSEPre:LEVel {}'.format( 624 self._bts, pwlevel) 625 self._cmw.send_and_recv(cmd) 626 627 @property 628 def uplink_power_control(self): 629 """Gets open loop nominal power directly.""" 630 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:OLNPower?'.format(self._bts) 631 return self._cmw.send_and_recv(cmd) 632 633 @uplink_power_control.setter 634 def uplink_power_control(self, ul_power): 635 """Sets open loop nominal power directly. 636 637 Args: 638 ul_power: uplink power level. 639 """ 640 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:OLNPower {}'.format( 641 self._bts, ul_power) 642 self._cmw.send_and_recv(cmd) 643 644 @property 645 def uldl_configuration(self): 646 """Gets uldl configuration of the cell.""" 647 cmd = 'CONFigure:LTE:SIGN:CELL:{}:ULDL?'.format(self._bts) 648 return self._cmw.send_and_recv(cmd) 649 650 @uldl_configuration.setter 651 def uldl_configuration(self, uldl): 652 """Sets the ul-dl configuration. 653 654 Args: 655 uldl: Configuration value ranging from 0 to 6. 656 """ 657 if uldl not in range(0, 7): 658 raise ValueError('uldl configuration value should be between' 659 ' 0 and 6 inclusive.') 660 661 cmd = 'CONFigure:LTE:SIGN:CELL:{}:ULDL {}'.format(self._bts, uldl) 662 self._cmw.send_and_recv(cmd) 663 664 @property 665 def tdd_special_subframe(self): 666 """Gets special subframe of the cell.""" 667 cmd = 'CONFigure:LTE:SIGN:CELL:{}:SSUBframe?'.format(self._bts) 668 return self._cmw.send_and_recv(cmd) 669 670 @tdd_special_subframe.setter 671 def tdd_special_subframe(self, sframe): 672 """Sets the tdd special subframe of the cell. 673 674 Args: 675 sframe: Integer value ranging from 1 to 9. 676 """ 677 if sframe not in range(0, 10): 678 raise ValueError('tdd special subframe should be between 0 and 9' 679 ' inclusive.') 680 681 cmd = 'CONFigure:LTE:SIGN:CELL:{}:SSUBframe {}'.format( 682 self._bts, sframe) 683 self._cmw.send_and_recv(cmd) 684 685 @property 686 def scheduling_mode(self): 687 """Gets the current scheduling mode.""" 688 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:STYPe?'.format(self._bts) 689 return self._cmw.send_and_recv(cmd) 690 691 @scheduling_mode.setter 692 def scheduling_mode(self, mode): 693 """Sets the scheduling type for the cell. 694 695 Args: 696 mode: Selects the channel mode to be scheduled. 697 """ 698 if not isinstance(mode, SchedulingMode): 699 raise ValueError('mode should be the instance of scheduling mode.') 700 701 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:STYPe {}'.format( 702 self._bts, mode.value) 703 self._cmw.send_and_recv(cmd) 704 705 @property 706 def rb_configuration_dl(self): 707 """Gets rmc's rb configuration for down link. This function returns 708 Number of Resource blocks, Resource block position and Modulation type. 709 """ 710 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:{}:DL?'.format( 711 self._bts, self.scheduling_mode) 712 return self._cmw.send_and_recv(cmd) 713 714 @rb_configuration_dl.setter 715 def rb_configuration_dl(self, rb_config): 716 """Sets the rb configuration for down link for scheduling type. 717 718 Args: 719 rb_config: Tuple containing Number of resource blocks, resource 720 block position and modulation type. 721 722 Raises: 723 ValueError: If tuple unpacking fails. 724 """ 725 if self.scheduling_mode == 'RMC': 726 rb, rb_pos, modulation = rb_config 727 728 cmd = ('CONFigure:LTE:SIGN:CONNection:{}:RMC:DL {},{},' 729 '{}'.format(self._bts, rb, rb_pos, modulation)) 730 self._cmw.send_and_recv(cmd) 731 732 elif self.scheduling_mode == 'UDCH': 733 rb, start_rb, modulation, tbs = rb_config 734 735 self.validate_rb(rb) 736 737 if not isinstance(modulation, ModulationType): 738 raise ValueError('Modulation should be of type ' 739 'ModulationType.') 740 741 cmd = ('CONFigure:LTE:SIGN:CONNection:{}:UDCHannels:DL {},{},' 742 '{},{}'.format(self._bts, rb, start_rb, modulation.value, 743 tbs)) 744 self._cmw.send_and_recv(cmd) 745 746 @property 747 def rb_configuration_ul(self): 748 """Gets rb configuration for up link. This function returns 749 Number of Resource blocks, Resource block position and Modulation type. 750 """ 751 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:{}:UL?'.format( 752 self._bts, self.scheduling_mode) 753 return self._cmw.send_and_recv(cmd) 754 755 @rb_configuration_ul.setter 756 def rb_configuration_ul(self, rb_config): 757 """Sets the rb configuration for down link for scheduling mode. 758 759 Args: 760 rb_config: Tuple containing Number of resource blocks, resource 761 block position and modulation type. 762 763 Raises: 764 ValueError: If tuple unpacking fails. 765 """ 766 if self.scheduling_mode == 'RMC': 767 rb, rb_pos, modulation = rb_config 768 769 cmd = ('CONFigure:LTE:SIGN:CONNection:{}:RMC:UL {},{},' 770 '{}'.format(self._bts, rb, rb_pos, modulation)) 771 self._cmw.send_and_recv(cmd) 772 773 elif self.scheduling_mode == 'UDCH': 774 rb, start_rb, modulation, tbs = rb_config 775 776 self.validate_rb(rb) 777 778 if not isinstance(modulation, ModulationType): 779 raise ValueError('Modulation should be of type ' 780 'ModulationType.') 781 cmd = ('CONFigure:LTE:SIGN:CONNection:{}:UDCHannels:UL {},{},' 782 '{},{}'.format(self._bts, rb, start_rb, modulation.value, 783 tbs)) 784 self._cmw.send_and_recv(cmd) 785 786 def validate_rb(self, rb): 787 """Validates if rb is within the limits for bandwidth set. 788 789 Args: 790 rb: No. of resource blocks. 791 792 Raises: 793 ValueError if rb out of range. 794 """ 795 bandwidth = self.bandwidth 796 797 if bandwidth == LteBandwidth.BANDWIDTH_1MHz.value: 798 if not 0 <= rb <= 6: 799 raise ValueError('RB should be between 0 to 6 inclusive' 800 ' for 1.4Mhz.') 801 elif bandwidth == LteBandwidth.BANDWIDTH_3MHz.value: 802 if not 0 <= rb <= 10: 803 raise ValueError('RB should be between 0 to 10 inclusive' 804 ' for 3 Mhz.') 805 elif bandwidth == LteBandwidth.BANDWIDTH_5MHz.value: 806 if not 0 <= rb <= 25: 807 raise ValueError('RB should be between 0 to 25 inclusive' 808 ' for 5 Mhz.') 809 elif bandwidth == LteBandwidth.BANDWIDTH_10MHz.value: 810 if not 0 <= rb <= 50: 811 raise ValueError('RB should be between 0 to 50 inclusive' 812 ' for 10 Mhz.') 813 elif bandwidth == LteBandwidth.BANDWIDTH_15MHz.value: 814 if not 0 <= rb <= 75: 815 raise ValueError('RB should be between 0 to 75 inclusive' 816 ' for 15 Mhz.') 817 elif bandwidth == LteBandwidth.BANDWIDTH_20MHz.value: 818 if not 0 <= rb <= 100: 819 raise ValueError('RB should be between 0 to 100 inclusive' 820 ' for 20 Mhz.') 821 822 @property 823 def rb_position_dl(self): 824 """Gets the position of the allocated down link resource blocks within 825 the channel band-width. 826 """ 827 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:RMC:RBPosition:DL?'.format( 828 self._bts) 829 return self._cmw.send_and_recv(cmd) 830 831 @rb_position_dl.setter 832 def rb_position_dl(self, rbpos): 833 """Selects the position of the allocated down link resource blocks 834 within the channel band-width 835 836 Args: 837 rbpos: position of resource blocks. 838 """ 839 if not isinstance(rbpos, RbPosition): 840 raise ValueError('rbpos should be the instance of RbPosition.') 841 842 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:RMC:RBPosition:DL {}'.format( 843 self._bts, rbpos.value) 844 self._cmw.send_and_recv(cmd) 845 846 @property 847 def rb_position_ul(self): 848 """Gets the position of the allocated up link resource blocks within 849 the channel band-width. 850 """ 851 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:RMC:RBPosition:UL?'.format( 852 self._bts) 853 return self._cmw.send_and_recv(cmd) 854 855 @rb_position_ul.setter 856 def rb_position_ul(self, rbpos): 857 """Selects the position of the allocated up link resource blocks 858 within the channel band-width. 859 860 Args: 861 rbpos: position of resource blocks. 862 """ 863 if not isinstance(rbpos, RbPosition): 864 raise ValueError('rbpos should be the instance of RbPosition.') 865 866 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:RMC:RBPosition:UL {}'.format( 867 self._bts, rbpos.value) 868 self._cmw.send_and_recv(cmd) 869 870 @property 871 def dci_format(self): 872 """Gets the downlink control information (DCI) format.""" 873 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:DCIFormat?'.format(self._bts) 874 return self._cmw.send_and_recv(cmd) 875 876 @dci_format.setter 877 def dci_format(self, dci_format): 878 """Selects the downlink control information (DCI) format. 879 880 Args: 881 dci_format: supported dci. 882 """ 883 if not isinstance(dci_format, DciFormat): 884 raise ValueError('dci_format should be the instance of DciFormat.') 885 886 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:DCIFormat {}'.format( 887 self._bts, dci_format) 888 self._cmw.send_and_recv(cmd) 889 890 @property 891 def dl_antenna(self): 892 """Gets dl antenna count of cell.""" 893 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:NENBantennas?'.format(self._bts) 894 return self._cmw.send_and_recv(cmd) 895 896 @dl_antenna.setter 897 def dl_antenna(self, num_antenna): 898 """Sets the dl antenna count of cell. 899 900 Args: 901 num_antenna: Count of number of dl antennas to use. 902 """ 903 if not isinstance(num_antenna, MimoModes): 904 raise ValueError('num_antenna should be an instance of MimoModes.') 905 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:NENBantennas {}'.format( 906 self._bts, num_antenna) 907 self._cmw.send_and_recv(cmd) 908 909 @property 910 def reduced_pdcch(self): 911 """Gets the reduction of PDCCH resources state.""" 912 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:PDCCh:RPDCch?'.format( 913 self._bts) 914 return self._cmw.send_and_recv(cmd) 915 916 @reduced_pdcch.setter 917 def reduced_pdcch(self, state): 918 """Sets the reduction of PDCCH resources state. 919 920 Args: 921 state: ON/OFF. 922 """ 923 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:PDCCh:RPDCch {}'.format( 924 self._bts, state.value) 925 self._cmw.send_and_recv(cmd) 926 927 def tpc_power_control(self, set_type): 928 """Set and execute the Up Link Power Control via TPC. 929 930 Args: 931 set_type: Type of tpc power control. 932 """ 933 934 if not isinstance(set_type, TpcPowerControl): 935 raise ValueError('set_type should be the instance of ' 936 'TpCPowerControl.') 937 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:SET {}'.format( 938 self._bts, set_type.value) 939 self._cmw.send_and_recv(cmd) 940 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:PEXecute'.format(self._bts) 941 self._cmw.send_and_recv(cmd) 942 943 @property 944 def tpc_closed_loop_target_power(self): 945 """Gets the target powers for power control with the TPC setup.""" 946 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:CLTPower?'.format(self._bts) 947 return self._cmw.send_and_recv(cmd) 948 949 @tpc_closed_loop_target_power.setter 950 def tpc_closed_loop_target_power(self, cltpower): 951 """Sets the target powers for power control with the TPC setup. 952 953 Args: 954 tpower: Target power. 955 """ 956 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:CLTPower {}'.format( 957 self._bts, cltpower) 958 self._cmw.send_and_recv(cmd) 959 960 @property 961 def drx_connected_mode(self): 962 """ Gets the Connected DRX LTE cell parameter 963 964 Args: 965 None 966 967 Returns: 968 DRX connected mode (OFF, AUTO, MANUAL) 969 """ 970 raise NotImplementedError() 971 972 @drx_connected_mode.setter 973 def drx_connected_mode(self, mode): 974 """ Sets the Connected DRX LTE cell parameter 975 976 Args: 977 mode: DRX Connected mode 978 979 Returns: 980 None 981 """ 982 raise NotImplementedError() 983 984 @property 985 def drx_on_duration_timer(self): 986 """ Gets the amount of PDCCH subframes to wait for data after 987 waking up from a DRX cycle 988 989 Args: 990 None 991 992 Returns: 993 DRX mode duration timer 994 """ 995 raise NotImplementedError() 996 997 @drx_on_duration_timer.setter 998 def drx_on_duration_timer(self, time): 999 """ Sets the amount of PDCCH subframes to wait for data after 1000 waking up from a DRX cycle 1001 1002 Args: 1003 timer: Length of interval to wait for user data to be transmitted 1004 1005 Returns: 1006 None 1007 """ 1008 raise NotImplementedError() 1009 1010 @property 1011 def drx_inactivity_timer(self): 1012 """ Gets the number of PDCCH subframes to wait before entering DRX mode 1013 1014 Args: 1015 None 1016 1017 Returns: 1018 DRX mode inactivity timer 1019 """ 1020 raise NotImplementedError() 1021 1022 @drx_inactivity_timer.setter 1023 def drx_inactivity_timer(self, time): 1024 """ Sets the number of PDCCH subframes to wait before entering DRX mode 1025 1026 Args: 1027 timer: Length of the interval to wait 1028 1029 Returns: 1030 None 1031 """ 1032 raise NotImplementedError() 1033 1034 @property 1035 def drx_retransmission_timer(self): 1036 """ Gets the number of consecutive PDCCH subframes to wait 1037 for retransmission 1038 1039 Args: 1040 None 1041 1042 Returns: 1043 Number of PDCCH subframes to wait for retransmission 1044 """ 1045 raise NotImplementedError() 1046 1047 @drx_retransmission_timer.setter 1048 def drx_retransmission_timer(self, time): 1049 """ Sets the number of consecutive PDCCH subframes to wait 1050 for retransmission 1051 1052 Args: 1053 time: Number of PDCCH subframes to wait 1054 for retransmission 1055 1056 Returns: 1057 None 1058 """ 1059 raise NotImplementedError() 1060 1061 @property 1062 def drx_long_cycle(self): 1063 """ Gets the amount of subframes representing a DRX long cycle 1064 1065 Args: 1066 None 1067 1068 Returns: 1069 The amount of subframes representing one long DRX cycle. 1070 One cycle consists of DRX sleep + DRX on duration 1071 """ 1072 raise NotImplementedError() 1073 1074 @drx_long_cycle.setter 1075 def drx_long_cycle(self, time): 1076 """ Sets the amount of subframes representing a DRX long cycle 1077 1078 Args: 1079 long_cycle: The amount of subframes representing one long DRX cycle. 1080 One cycle consists of DRX sleep + DRX on duration 1081 1082 Returns: 1083 None 1084 """ 1085 raise NotImplementedError() 1086 1087 @property 1088 def drx_long_cycle_offset(self): 1089 """ Gets the offset used to determine long cycle starting 1090 subframe 1091 1092 Args: 1093 None 1094 1095 Returns: 1096 Long cycle offset 1097 """ 1098 raise NotImplementedError() 1099 1100 @drx_long_cycle_offset.setter 1101 def drx_long_cycle_offset(self, offset): 1102 """ Sets the offset used to determine long cycle starting 1103 subframe 1104 1105 Args: 1106 offset: Number in range 0...(long cycle - 1) 1107 """ 1108 raise NotImplementedError() 1109 1110 1111 1112class LteMeasurement(object): 1113 1114 def __init__(self, cmw): 1115 self._cmw = cmw 1116 1117 def intitilize_measurement(self): 1118 """Initialize measurement modules.""" 1119 self._cmw.send_and_recv('INIT:LTE:MEAS:MEValuation') 1120 1121 @property 1122 def measurement_repetition(self): 1123 """Returns the measurement repetition mode that has been set.""" 1124 return self._cmw.send_and_recv( 1125 'CONFigure:LTE:MEAS:MEValuation:REPetition?') 1126 1127 @measurement_repetition.setter 1128 def measurement_repetition(self, mode): 1129 """Sets the mode for measuring power levels. 1130 1131 Args: 1132 mode: Single shot/continuous. 1133 """ 1134 if not isinstance(mode, RepetitionMode): 1135 raise ValueError('mode should be the instance of Repetition Mode') 1136 1137 cmd = 'CONFigure:LTE:MEAS:MEValuation:REPetition {}'.format(mode.value) 1138 self._cmw.send_and_recv(cmd) 1139 1140 @property 1141 def query_measurement_state(self): 1142 """Returns the states and sub states of measurement.""" 1143 return self._cmw.send_and_recv('FETCh:LTE:MEAS:MEValuation:STATe:ALL?') 1144 1145 @property 1146 def measure_tx_power(self): 1147 """Return the current Tx power measurement.""" 1148 return self._cmw.send_and_recv( 1149 'FETCh:LTE:MEAS:MEValuation:PMONitor:AVERage?') 1150 1151 def stop_measurement(self): 1152 """Stops the on-going measurement. 1153 This function call does not free up resources allocated for 1154 measurement. Instead it moves from RUN to RDY state. 1155 """ 1156 self._cmw.send_and_recv('STOP:LTE:MEAS:MEValuation') 1157 1158 def abort_measurement(self): 1159 """Aborts the measurement abruptly. 1160 This function call will free up the resources allocated for 1161 measurement and all the results will be wiped off. 1162 """ 1163 self._cmw.send_and_recv('ABORt:LTE:MEAS:MEValuation') 1164 1165 1166class CmwError(Exception): 1167 """Class to raise exceptions related to cmw.""" 1168