1# Copyright 2021 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5from enum import Enum 6import time 7 8from autotest_lib.server.cros.cellular import abstract_inst 9 10LTE_ATTACH_RESP = 'ATT' 11LTE_CONN_RESP = 'CONN' 12LTE_IDLE_RESP = 'IDLE' 13LTE_PSWITCHED_ON_RESP = 'ON' 14LTE_PSWITCHED_OFF_RESP = 'OFF' 15 16STATE_CHANGE_TIMEOUT = 20 17 18 19class LteState(Enum): 20 """LTE ON and OFF""" 21 LTE_ON = 'ON' 22 LTE_OFF = 'OFF' 23 24 25class BtsNumber(Enum): 26 """Base station Identifiers.""" 27 BTS1 = 'PCC' 28 BTS2 = 'SCC1' 29 BTS3 = 'SCC2' 30 BTS4 = 'SCC3' 31 BTS5 = 'SCC4' 32 BTS6 = 'SCC6' 33 BTS7 = 'SCC7' 34 35 36class LteBandwidth(Enum): 37 """Supported LTE bandwidths.""" 38 BANDWIDTH_1MHz = 'B014' 39 BANDWIDTH_3MHz = 'B030' 40 BANDWIDTH_5MHz = 'B050' 41 BANDWIDTH_10MHz = 'B100' 42 BANDWIDTH_15MHz = 'B150' 43 BANDWIDTH_20MHz = 'B200' 44 45 46class DuplexMode(Enum): 47 """Duplex Modes""" 48 FDD = 'FDD' 49 TDD = 'TDD' 50 51 52class SchedulingMode(Enum): 53 """Supported scheduling modes.""" 54 RMC = 'RMC' 55 USERDEFINEDCH = 'UDCHannels' 56 57 58class TransmissionModes(Enum): 59 """Supported transmission modes.""" 60 TM1 = 'TM1' 61 TM2 = 'TM2' 62 TM3 = 'TM3' 63 TM4 = 'TM4' 64 TM7 = 'TM7' 65 TM8 = 'TM8' 66 TM9 = 'TM9' 67 68 69class UseCarrierSpecific(Enum): 70 """Enable or disable carrier specific.""" 71 UCS_ON = 'ON' 72 UCS_OFF = 'OFF' 73 74 75class RbPosition(Enum): 76 """Supported RB positions.""" 77 LOW = 'LOW' 78 HIGH = 'HIGH' 79 P5 = 'P5' 80 P10 = 'P10' 81 P23 = 'P23' 82 P35 = 'P35' 83 P48 = 'P48' 84 85 86class ModulationType(Enum): 87 """Supported Modulation Types.""" 88 QPSK = 'QPSK' 89 Q16 = 'Q16' 90 Q64 = 'Q64' 91 Q256 = 'Q256' 92 93 94class DciFormat(Enum): 95 """Support DCI Formats for MIMOs""" 96 D1 = 'D1' 97 D1A = 'D1A' 98 D1B = 'D1B' 99 D2 = 'D2' 100 D2A = 'D2A' 101 D2B = 'D2B' 102 D2C = 'D2C' 103 104 105class MimoModes(Enum): 106 """MIMO Modes dl antennas""" 107 MIMO1x1 = 'ONE' 108 MIMO2x2 = 'TWO' 109 MIMO4x4 = 'FOUR' 110 111 112class MimoScenario(Enum): 113 """Supported mimo scenarios""" 114 SCEN1x1 = 'SCELl:FLEXible SUA1,RF1C,RX1,RF1C,TX1' 115 SCEN2x2 = 'TRO:FLEXible SUA1,RF1C,RX1,RF1C,TX1,RF3C,TX2' 116 SCEN4x4 = 'FRO FLEXible SUA1,RF1C,RX1,RF1C,TX1,RF3C,TX2,RF2C,TX3,RF4C,TX4' 117 118 119class RrcState(Enum): 120 """States to enable/disable rrc.""" 121 RRC_ON = 'ON' 122 RRC_OFF = 'OFF' 123 124 125class MacPadding(Enum): 126 """Enables/Disables Mac Padding.""" 127 ON = 'ON' 128 OFF = 'OFF' 129 130 131class ConnectionType(Enum): 132 """Supported Connection Types.""" 133 TEST = 'TESTmode' 134 DAU = 'DAPPlication' 135 136 137class RepetitionMode(Enum): 138 """Specifies LTE Measurement Repetition Mode.""" 139 SINGLESHOT = 'SINGleshot' 140 CONTINUOUS = 'CONTinuous' 141 142 143class TpcPowerControl(Enum): 144 """Specifies Up Link power control types.""" 145 MIN_POWER = 'MINPower' 146 MAX_POWER = 'MAXPower' 147 CONSTANT = 'CONStant' 148 SINGLE = 'SINGle' 149 UDSINGLE = 'UDSingle' 150 UDCONTINUOUS = 'UDContinuous' 151 ALTERNATE = 'ALT0' 152 CLOSED_LOOP = 'CLOop' 153 RP_CONTROL = 'RPControl' 154 FLEX_POWER = 'FULPower' 155 156 157class ReducedPdcch(Enum): 158 """Enables/disables the reduction of PDCCH resources.""" 159 ON = 'ON' 160 OFF = 'OFF' 161 162 163class Cmw500(abstract_inst.SocketInstrument): 164 """ Base class for interfacing with the CMW500 Callbox device """ 165 166 def __init__(self, ip_addr, port): 167 """Init method to setup variables for controllers. 168 169 Args: 170 ip_addr: Controller's ip address. 171 port: Port 172 """ 173 super(Cmw500, self).__init__(ip_addr, port) 174 self._connect_socket() 175 self._send('*CLS') 176 self._send('*ESE 0;*SRE 0') 177 self._send('*CLS') 178 self._send('*ESE 1;*SRE 4') 179 self._send('SYST:DISP:UPD ON') 180 181 def switch_lte_signalling(self, state): 182 """ Turns LTE signalling ON/OFF. 183 184 Args: 185 state: an instance of LteState indicating the state to which LTE 186 signal has to be set. 187 """ 188 if not isinstance(state, LteState): 189 raise ValueError('state should be the instance of LteState.') 190 191 state = state.value 192 193 cmd = 'SOURce:LTE:SIGN:CELL:STATe {}'.format(state) 194 self.send_and_recv(cmd) 195 196 time_elapsed = 0 197 while time_elapsed < STATE_CHANGE_TIMEOUT: 198 response = self.send_and_recv('SOURce:LTE:SIGN:CELL:STATe:ALL?') 199 200 if response == state + ',ADJ': 201 self._logger.info('LTE signalling is now {}.'.format(state)) 202 break 203 204 # Wait for a second and increase time count by one 205 time.sleep(1) 206 time_elapsed += 1 207 else: 208 raise CmwError('Failed to turn {} LTE signalling.'.format(state)) 209 210 def enable_packet_switching(self): 211 """Enable packet switching in call box.""" 212 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion CONNect') 213 self.wait_for_pswitched_state() 214 215 def disable_packet_switching(self): 216 """Disable packet switching in call box.""" 217 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion DISConnect') 218 self.wait_for_pswitched_state() 219 220 @property 221 def use_carrier_specific(self): 222 """Gets current status of carrier specific duplex configuration.""" 223 return self.send_and_recv('CONFigure:LTE:SIGN:DMODe:UCSPECific?') 224 225 @use_carrier_specific.setter 226 def use_carrier_specific(self, state): 227 """Sets the carrier specific duplex configuration. 228 229 Args: 230 state: ON/OFF UCS configuration. 231 """ 232 cmd = 'CONFigure:LTE:SIGN:DMODe:UCSPECific {}'.format(state) 233 self.send_and_recv(cmd) 234 235 def send_and_recv(self, cmd): 236 """Send and recv the status of the command. 237 238 Args: 239 cmd: Command to send. 240 241 Returns: 242 status: returns the status of the command sent. 243 """ 244 245 self._send(cmd) 246 if '?' in cmd: 247 status = self._recv() 248 return status 249 250 def configure_mimo_settings(self, mimo): 251 """Sets the mimo scenario for the test. 252 253 Args: 254 mimo: mimo scenario to set. 255 """ 256 cmd = 'ROUTe:LTE:SIGN:SCENario:{}'.format(mimo.value) 257 self.send_and_recv(cmd) 258 259 def wait_for_pswitched_state(self, timeout=10): 260 """Wait until pswitched state. 261 262 Args: 263 timeout: timeout for lte pswitched state. 264 265 Raises: 266 CmwError on timeout. 267 """ 268 while timeout > 0: 269 state = self.send_and_recv('FETCh:LTE:SIGN:PSWitched:STATe?') 270 if state == LTE_PSWITCHED_ON_RESP: 271 self._logger.debug('Connection to setup initiated.') 272 break 273 elif state == LTE_PSWITCHED_OFF_RESP: 274 self._logger.debug('Connection to setup detached.') 275 break 276 277 # Wait for a second and decrease count by one 278 time.sleep(1) 279 timeout -= 1 280 else: 281 raise CmwError('Failure in setting up/detaching connection') 282 283 def wait_for_attached_state(self, timeout=120): 284 """Attach the controller with device. 285 286 Args: 287 timeout: timeout for phone to get attached. 288 289 Raises: 290 CmwError on time out. 291 """ 292 while timeout > 0: 293 state = self.send_and_recv('FETCh:LTE:SIGN:PSWitched:STATe?') 294 295 if state == LTE_ATTACH_RESP: 296 self._logger.debug('Call box attached with device') 297 break 298 299 # Wait for a second and decrease count by one 300 time.sleep(1) 301 timeout -= 1 302 else: 303 raise CmwError('Device could not be attached') 304 305 def wait_for_rrc_state(self, state, timeout=120): 306 """ Waits until a certain RRC state is set. 307 308 Args: 309 state: the RRC state that is being waited for. 310 timeout: timeout for phone to be in connected state. 311 312 Raises: 313 CmwError on time out. 314 """ 315 if state not in [LTE_CONN_RESP, LTE_IDLE_RESP]: 316 raise ValueError( 317 'The allowed values for state are {} and {}.'.format( 318 LTE_CONN_RESP, LTE_IDLE_RESP)) 319 320 while timeout > 0: 321 new_state = self.send_and_recv('SENSe:LTE:SIGN:RRCState?') 322 if new_state == state: 323 self._logger.debug('The RRC state is {}.'.format(new_state)) 324 break 325 326 # Wait for a second and decrease count by one 327 time.sleep(1) 328 timeout -= 1 329 else: 330 raise CmwError('Timeout before RRC state was {}.'.format(state)) 331 332 def reset(self): 333 """System level reset""" 334 self.send_and_recv('*RST; *OPC') 335 336 @property 337 def get_instrument_id(self): 338 """Gets instrument identification number""" 339 return self.send_and_recv('*IDN?') 340 341 def disconnect(self): 342 """Disconnect controller from device and switch to local mode.""" 343 self.switch_lte_signalling(LteState.LTE_OFF) 344 self.close_remote_mode() 345 self._close_socket() 346 347 def close_remote_mode(self): 348 """Exits remote mode to local mode.""" 349 self.send_and_recv('>L') 350 351 def detach(self): 352 """Detach callbox and controller.""" 353 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion DETach') 354 355 @property 356 def rrc_connection(self): 357 """Gets the RRC connection state.""" 358 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:KRRC?') 359 360 @rrc_connection.setter 361 def rrc_connection(self, state): 362 """Selects whether the RRC connection is kept or released after attach. 363 364 Args: 365 mode: RRC State ON/OFF. 366 """ 367 if not isinstance(state, RrcState): 368 raise ValueError('state should be the instance of RrcState.') 369 370 cmd = 'CONFigure:LTE:SIGN:CONNection:KRRC {}'.format(state.value) 371 self.send_and_recv(cmd) 372 373 @property 374 def rrc_connection_timer(self): 375 """Gets the inactivity timeout for disabled rrc connection.""" 376 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:RITimer?') 377 378 @rrc_connection_timer.setter 379 def rrc_connection_timer(self, time_in_secs): 380 """Sets the inactivity timeout for disabled rrc connection. By default 381 the timeout is set to 5. 382 383 Args: 384 time_in_secs: timeout of inactivity in rrc connection. 385 """ 386 cmd = 'CONFigure:LTE:SIGN:CONNection:RITimer {}'.format(time_in_secs) 387 self.send_and_recv(cmd) 388 389 @property 390 def dl_mac_padding(self): 391 """Gets the state of mac padding.""" 392 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:DLPadding?') 393 394 @dl_mac_padding.setter 395 def dl_mac_padding(self, state): 396 """Enables/Disables downlink padding at the mac layer. 397 398 Args: 399 state: ON/OFF 400 """ 401 cmd = 'CONFigure:LTE:SIGN:CONNection:DLPadding {}'.format(state.value) 402 self.send_and_recv(cmd) 403 404 @property 405 def connection_type(self): 406 """Gets the connection type applied in callbox.""" 407 return self.send_and_recv('CONFigure:LTE:SIGN:CONNection:CTYPe?') 408 409 @connection_type.setter 410 def connection_type(self, ctype): 411 """Sets the connection type to be applied. 412 413 Args: 414 ctype: Connection type. 415 """ 416 cmd = 'CONFigure:LTE:SIGN:CONNection:CTYPe {}'.format(ctype.value) 417 self.send_and_recv(cmd) 418 419 def get_base_station(self, bts_num=BtsNumber.BTS1): 420 """Gets the base station object based on bts num. By default 421 bts_num set to PCC 422 423 Args: 424 bts_num: base station identifier 425 426 Returns: 427 base station object. 428 """ 429 return BaseStation(self, bts_num) 430 431 def init_lte_measurement(self): 432 """Gets the class object for lte measurement which can be used to 433 initiate measurements. 434 435 Returns: 436 lte measurement object. 437 """ 438 return LteMeasurement(self) 439 440 def set_sms(self, sms_message): 441 """Sets the SMS message to be sent by the callbox.""" 442 self.send_and_recv('CONFigure:LTE:SIGN:SMS:OUTGoing:INTernal "%s"' % sms_message) 443 444 def send_sms(self): 445 """Sends the SMS message.""" 446 self.send_and_recv('CALL:LTE:SIGN:PSWitched:ACTion SMS; *OPC?') 447 timeout = time.time() + STATE_CHANGE_TIMEOUT 448 while "SUCC" != self.send_and_recv('SENSe:LTE:SIGN:SMS:OUTGoing:INFO:LMSent?'): 449 if time.time() > timeout: 450 raise CmwError("SENSe:LTE:SIGN:SMS:OUTGoing:INFO:LMSent? never returns status 'SUCC' instead got (%s)" % self.send_and_recv('SENSe:LTE:SIGN:SMS:OUTGoing:INFO:LMSent?')) 451 time.sleep(2) 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( 894 self._bts) 895 return self._cmw.send_and_recv(cmd) 896 897 @dl_antenna.setter 898 def dl_antenna(self, num_antenna): 899 """Sets the dl antenna count of cell. 900 901 Args: 902 num_antenna: Count of number of dl antennas to use. 903 """ 904 if not isinstance(num_antenna, MimoModes): 905 raise ValueError('num_antenna should be an instance of MimoModes.') 906 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:NENBantennas {}'.format( 907 self._bts, num_antenna) 908 self._cmw.send_and_recv(cmd) 909 910 @property 911 def reduced_pdcch(self): 912 """Gets the reduction of PDCCH resources state.""" 913 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:PDCCh:RPDCch?'.format( 914 self._bts) 915 return self._cmw.send_and_recv(cmd) 916 917 @reduced_pdcch.setter 918 def reduced_pdcch(self, state): 919 """Sets the reduction of PDCCH resources state. 920 921 Args: 922 state: ON/OFF. 923 """ 924 cmd = 'CONFigure:LTE:SIGN:CONNection:{}:PDCCh:RPDCch {}'.format( 925 self._bts, state.value) 926 self._cmw.send_and_recv(cmd) 927 928 def tpc_power_control(self, set_type): 929 """Set and execute the Up Link Power Control via TPC. 930 931 Args: 932 set_type: Type of tpc power control. 933 """ 934 935 if not isinstance(set_type, TpcPowerControl): 936 raise ValueError('set_type should be the instance of ' 937 'TpCPowerControl.') 938 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:SET {}'.format( 939 self._bts, set_type.value) 940 self._cmw.send_and_recv(cmd) 941 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:PEXecute'.format(self._bts) 942 self._cmw.send_and_recv(cmd) 943 944 @property 945 def tpc_closed_loop_target_power(self): 946 """Gets the target powers for power control with the TPC setup.""" 947 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:CLTPower?'.format(self._bts) 948 return self._cmw.send_and_recv(cmd) 949 950 @tpc_closed_loop_target_power.setter 951 def tpc_closed_loop_target_power(self, cltpower): 952 """Sets the target powers for power control with the TPC setup. 953 954 Args: 955 tpower: Target power. 956 """ 957 cmd = 'CONFigure:LTE:SIGN:UL:{}:PUSCh:TPC:CLTPower {}'.format( 958 self._bts, cltpower) 959 self._cmw.send_and_recv(cmd) 960 961 @property 962 def drx_connected_mode(self): 963 """ Gets the Connected DRX LTE cell parameter 964 965 Args: 966 None 967 968 Returns: 969 DRX connected mode (OFF, AUTO, MANUAL) 970 """ 971 raise NotImplementedError() 972 973 @drx_connected_mode.setter 974 def drx_connected_mode(self, mode): 975 """ Sets the Connected DRX LTE cell parameter 976 977 Args: 978 mode: DRX Connected mode 979 980 Returns: 981 None 982 """ 983 raise NotImplementedError() 984 985 @property 986 def drx_on_duration_timer(self): 987 """ Gets the amount of PDCCH subframes to wait for data after 988 waking up from a DRX cycle 989 990 Args: 991 None 992 993 Returns: 994 DRX mode duration timer 995 """ 996 raise NotImplementedError() 997 998 @drx_on_duration_timer.setter 999 def drx_on_duration_timer(self, time): 1000 """ Sets the amount of PDCCH subframes to wait for data after 1001 waking up from a DRX cycle 1002 1003 Args: 1004 timer: Length of interval to wait for user data to be transmitted 1005 1006 Returns: 1007 None 1008 """ 1009 raise NotImplementedError() 1010 1011 @property 1012 def drx_inactivity_timer(self): 1013 """ Gets the number of PDCCH subframes to wait before entering DRX mode 1014 1015 Args: 1016 None 1017 1018 Returns: 1019 DRX mode inactivity timer 1020 """ 1021 raise NotImplementedError() 1022 1023 @drx_inactivity_timer.setter 1024 def drx_inactivity_timer(self, time): 1025 """ Sets the number of PDCCH subframes to wait before entering DRX mode 1026 1027 Args: 1028 timer: Length of the interval to wait 1029 1030 Returns: 1031 None 1032 """ 1033 raise NotImplementedError() 1034 1035 @property 1036 def drx_retransmission_timer(self): 1037 """ Gets the number of consecutive PDCCH subframes to wait 1038 for retransmission 1039 1040 Args: 1041 None 1042 1043 Returns: 1044 Number of PDCCH subframes to wait for retransmission 1045 """ 1046 raise NotImplementedError() 1047 1048 @drx_retransmission_timer.setter 1049 def drx_retransmission_timer(self, time): 1050 """ Sets the number of consecutive PDCCH subframes to wait 1051 for retransmission 1052 1053 Args: 1054 time: Number of PDCCH subframes to wait 1055 for retransmission 1056 1057 Returns: 1058 None 1059 """ 1060 raise NotImplementedError() 1061 1062 @property 1063 def drx_long_cycle(self): 1064 """ Gets the amount of subframes representing a DRX long cycle 1065 1066 Args: 1067 None 1068 1069 Returns: 1070 The amount of subframes representing one long DRX cycle. 1071 One cycle consists of DRX sleep + DRX on duration 1072 """ 1073 raise NotImplementedError() 1074 1075 @drx_long_cycle.setter 1076 def drx_long_cycle(self, time): 1077 """ Sets the amount of subframes representing a DRX long cycle 1078 1079 Args: 1080 long_cycle: The amount of subframes representing one long DRX cycle. 1081 One cycle consists of DRX sleep + DRX on duration 1082 1083 Returns: 1084 None 1085 """ 1086 raise NotImplementedError() 1087 1088 @property 1089 def drx_long_cycle_offset(self): 1090 """ Gets the offset used to determine long cycle starting 1091 subframe 1092 1093 Args: 1094 None 1095 1096 Returns: 1097 Long cycle offset 1098 """ 1099 raise NotImplementedError() 1100 1101 @drx_long_cycle_offset.setter 1102 def drx_long_cycle_offset(self, offset): 1103 """ Sets the offset used to determine long cycle starting 1104 subframe 1105 1106 Args: 1107 offset: Number in range 0...(long cycle - 1) 1108 """ 1109 raise NotImplementedError() 1110 1111 1112class LteMeasurement(object): 1113 """ Class for measuring LTE performance """ 1114 1115 def __init__(self, cmw): 1116 self._cmw = cmw 1117 1118 def intitilize_measurement(self): 1119 """Initialize measurement modules.""" 1120 self._cmw.send_and_recv('INIT:LTE:MEAS:MEValuation') 1121 1122 @property 1123 def measurement_repetition(self): 1124 """Returns the measurement repetition mode that has been set.""" 1125 return self._cmw.send_and_recv( 1126 'CONFigure:LTE:MEAS:MEValuation:REPetition?') 1127 1128 @measurement_repetition.setter 1129 def measurement_repetition(self, mode): 1130 """Sets the mode for measuring power levels. 1131 1132 Args: 1133 mode: Single shot/continuous. 1134 """ 1135 if not isinstance(mode, RepetitionMode): 1136 raise ValueError('mode should be the instance of Repetition Mode') 1137 1138 cmd = 'CONFigure:LTE:MEAS:MEValuation:REPetition {}'.format(mode.value) 1139 self._cmw.send_and_recv(cmd) 1140 1141 @property 1142 def query_measurement_state(self): 1143 """Returns the states and sub states of measurement.""" 1144 return self._cmw.send_and_recv('FETCh:LTE:MEAS:MEValuation:STATe:ALL?') 1145 1146 @property 1147 def measure_tx_power(self): 1148 """Return the current Tx power measurement.""" 1149 return self._cmw.send_and_recv( 1150 'FETCh:LTE:MEAS:MEValuation:PMONitor:AVERage?') 1151 1152 def stop_measurement(self): 1153 """Stops the on-going measurement. 1154 This function call does not free up resources allocated for 1155 measurement. Instead it moves from RUN to RDY state. 1156 """ 1157 self._cmw.send_and_recv('STOP:LTE:MEAS:MEValuation') 1158 1159 def abort_measurement(self): 1160 """Aborts the measurement abruptly. 1161 This function call will free up the resources allocated for 1162 measurement and all the results will be wiped off. 1163 """ 1164 self._cmw.send_and_recv('ABORt:LTE:MEAS:MEValuation') 1165 1166 1167class CmwError(Exception): 1168 """Class to raise exceptions related to cmw.""" 1169