1#!/usr/bin/env python3.4 2# 3# Copyright 2016 - 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""" 17Controller interface for Anritsu Signal Generator MG3710A. 18""" 19 20import time 21import socket 22from enum import Enum 23from enum import IntEnum 24 25from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError 26from acts.controllers.anritsu_lib._anritsu_utils import NO_ERROR 27from acts.controllers.anritsu_lib._anritsu_utils import OPERATION_COMPLETE 28 29TERMINATOR = "\n" 30 31 32def create(configs, logger): 33 objs = [] 34 for c in configs: 35 ip_address = c["ip_address"] 36 objs.append(MG3710A(ip_address, logger)) 37 return objs 38 39 40def destroy(objs): 41 return 42 43 44class MG3710A(object): 45 """Class to communicate with Anritsu Signal Generator MG3710A. 46 This uses GPIB command to interface with Anritsu MG3710A """ 47 48 def __init__(self, ip_address, log_handle): 49 self._ipaddr = ip_address 50 self.log = log_handle 51 52 # Open socket connection to Signaling Tester 53 self.log.info("Opening Socket Connection with " 54 "Signal Generator MG3710A ({}) ".format(self._ipaddr)) 55 try: 56 self._sock = socket.create_connection( 57 (self._ipaddr, 49158), timeout=30) 58 self.send_query("*IDN?", 60) 59 self.log.info("Communication Signal Generator MG3710A OK.") 60 self.log.info("Opened Socket connection to ({})" 61 "with handle ({})".format(self._ipaddr, self._sock)) 62 except socket.timeout: 63 raise AnritsuError("Timeout happened while conencting to" 64 " Anritsu MG3710A") 65 except socket.error: 66 raise AnritsuError("Socket creation error") 67 68 def disconnect(self): 69 """ Disconnect Signal Generator MG3710A 70 71 Args: 72 None 73 74 Returns: 75 None 76 """ 77 self.send_command(":SYST:COMM:GTL", opc=False) 78 self._sock.close() 79 80 def send_query(self, query, sock_timeout=10): 81 """ Sends a Query message to Anritsu MG3710A and return response 82 83 Args: 84 query - Query string 85 86 Returns: 87 query response 88 """ 89 self.log.info("--> {}".format(query)) 90 querytoSend = (query + TERMINATOR).encode('utf-8') 91 self._sock.settimeout(sock_timeout) 92 try: 93 self._sock.send(querytoSend) 94 result = self._sock.recv(256).rstrip(TERMINATOR.encode('utf-8')) 95 response = result.decode('utf-8') 96 self.log.info('<-- {}'.format(response)) 97 return response 98 except socket.timeout: 99 raise AnritsuError("Timeout: Response from Anritsu") 100 except socket.error: 101 raise AnritsuError("Socket Error") 102 103 def send_command(self, command, sock_timeout=30, opc=True): 104 """ Sends a Command message to Anritsu MG3710A 105 106 Args: 107 command - command string 108 109 Returns: 110 None 111 """ 112 self.log.info("--> {}".format(command)) 113 cmdToSend = (command + TERMINATOR).encode('utf-8') 114 self._sock.settimeout(sock_timeout) 115 try: 116 self._sock.send(cmdToSend) 117 if opc: 118 # check operation status 119 status = self.send_query("*OPC?") 120 if int(status) != OPERATION_COMPLETE: 121 raise AnritsuError("Operation not completed") 122 except socket.timeout: 123 raise AnritsuError("Timeout for Command Response from Anritsu") 124 except socket.error: 125 raise AnritsuError("Socket Error for Anritsu command") 126 return 127 128 @property 129 def sg(self): 130 """ Gets current selected signal generator(SG) 131 132 Args: 133 None 134 135 Returns: 136 selected signal generatr number 137 """ 138 return self.send_query("PORT?") 139 140 @sg.setter 141 def sg(self, sg_number): 142 """ Selects the signal generator to be controlled 143 144 Args: 145 sg_number: sg number 1 | 2 146 147 Returns: 148 None 149 """ 150 cmd = "PORT {}".format(sg_number) 151 self.send_command(cmd) 152 153 def get_modulation_state(self, sg=1): 154 """ Gets the RF signal modulation state (ON/OFF) of signal generator 155 156 Args: 157 sg: signal generator number. 158 Default is 1 159 160 Returns: 161 modulation state . 0 (OFF) | 1(ON) 162 """ 163 return self.send_query("OUTP{}:MOD?".format(sg)) 164 165 def set_modulation_state(self, state, sg=1): 166 """ Sets the RF signal modulation state 167 168 Args: 169 sg: signal generator number. 170 Default is 1 171 state : ON/OFF 172 173 Returns: 174 None 175 """ 176 cmd = "OUTP{}:MOD {}".format(sg, state) 177 self.send_command(cmd) 178 179 def get_rf_output_state(self, sg=1): 180 """ Gets RF signal output state (ON/OFF) of signal generator 181 182 Args: 183 sg: signal generator number. 184 Default is 1 185 186 Returns: 187 RF signal output state . 0 (OFF) | 1(ON) 188 """ 189 return self.send_query("OUTP{}?".format(sg)) 190 191 def set_rf_output_state(self, state, sg=1): 192 """ Sets the RF signal output state 193 194 Args: 195 sg: signal generator number. 196 Default is 1 197 state : ON/OFF 198 199 Returns: 200 None 201 """ 202 cmd = "OUTP{} {}".format(sg, state) 203 self.send_command(cmd) 204 205 def get_frequency(self, sg=1): 206 """ Gets the selected frequency of signal generator 207 208 Args: 209 sg: signal generator number. 210 Default is 1 211 212 Returns: 213 selected frequency 214 """ 215 return self.send_query("SOUR{}:FREQ?".format(sg)) 216 217 def set_frequency(self, freq, sg=1): 218 """ Sets the frequency of signal generator 219 220 Args: 221 sg: signal generator number. 222 Default is 1 223 freq : frequency 224 225 Returns: 226 None 227 """ 228 cmd = "SOUR{}:FREQ {}".format(sg, freq) 229 self.send_command(cmd) 230 231 def get_frequency_offset_state(self, sg=1): 232 """ Gets the Frequency Offset enable state (ON/OFF) of signal generator 233 234 Args: 235 sg: signal generator number. 236 Default is 1 237 238 Returns: 239 Frequency Offset enable state . 0 (OFF) | 1(ON) 240 """ 241 return self.send_query("SOUR{}:FREQ:OFFS:STAT?".format(sg)) 242 243 def set_frequency_offset_state(self, state, sg=1): 244 """ Sets the Frequency Offset enable state 245 246 Args: 247 sg: signal generator number. 248 Default is 1 249 state : enable state, ON/OFF 250 251 Returns: 252 None 253 """ 254 cmd = "SOUR{}:FREQ:OFFS:STAT {}".format(sg, state) 255 self.send_command(cmd) 256 257 def get_frequency_offset(self, sg=1): 258 """ Gets the current frequency offset value 259 260 Args: 261 sg: signal generator number. 262 Default is 1 263 264 Returns: 265 current frequency offset value 266 """ 267 return self.send_query("SOUR{}:FREQ:OFFS?".format(sg)) 268 269 def set_frequency_offset(self, offset, sg=1): 270 """ Sets the frequency offset value 271 272 Args: 273 sg: signal generator number. 274 Default is 1 275 offset : frequency offset value 276 277 Returns: 278 None 279 """ 280 cmd = "SOUR{}:FREQ:OFFS {}".format(sg, offset) 281 self.send_command(cmd) 282 283 def get_frequency_offset_multiplier_state(self, sg=1): 284 """ Gets the Frequency Offset multiplier enable state (ON/OFF) of 285 signal generator 286 287 Args: 288 sg: signal generator number. 289 Default is 1 290 291 Returns: 292 Frequency Offset multiplier enable state . 0 (OFF) | 1(ON) 293 """ 294 return self.send_query("SOUR{}:FREQ:MULT:STAT?".format(sg)) 295 296 def set_frequency_offset_multiplier_state(self, state, sg=1): 297 """ Sets the Frequency Offset multiplier enable state 298 299 Args: 300 sg: signal generator number. 301 Default is 1 302 state : enable state, ON/OFF 303 304 Returns: 305 None 306 """ 307 cmd = "SOUR{}:FREQ:MULT:STAT {}".format(sg, state) 308 self.send_command(cmd) 309 310 def get_frequency_offset_multiplier(self, sg=1): 311 """ Gets the current frequency offset multiplier value 312 313 Args: 314 sg: signal generator number. 315 Default is 1 316 317 Returns: 318 frequency offset multiplier value 319 """ 320 return self.send_query("SOUR{}:FREQ:MULT?".format(sg)) 321 322 def set_frequency_offset_multiplier(self, multiplier, sg=1): 323 """ Sets the frequency offset multiplier value 324 325 Args: 326 sg: signal generator number. 327 Default is 1 328 multiplier : frequency offset multiplier value 329 330 Returns: 331 None 332 """ 333 cmd = "SOUR{}:FREQ:MULT {}".format(sg, multiplier) 334 self.send_command(cmd) 335 336 def get_channel(self, sg=1): 337 """ Gets the current channel number 338 339 Args: 340 sg: signal generator number. 341 Default is 1 342 343 Returns: 344 current channel number 345 """ 346 return self.send_query("SOUR{}:FREQ:CHAN:NUMB?".format(sg)) 347 348 def set_channel(self, channel, sg=1): 349 """ Sets the channel number 350 351 Args: 352 sg: signal generator number. 353 Default is 1 354 channel : channel number 355 356 Returns: 357 None 358 """ 359 cmd = "SOUR{}:FREQ:CHAN:NUMB {}".format(sg, channel) 360 self.send_command(cmd) 361 362 def get_channel_group(self, sg=1): 363 """ Gets the current channel group number 364 365 Args: 366 sg: signal generator number. 367 Default is 1 368 369 Returns: 370 current channel group number 371 """ 372 return self.send_query("SOUR{}:FREQ:CHAN:GRO?".format(sg)) 373 374 def set_channel_group(self, group, sg=1): 375 """ Sets the channel group number 376 377 Args: 378 sg: signal generator number. 379 Default is 1 380 group : channel group number 381 382 Returns: 383 None 384 """ 385 cmd = "SOUR{}:FREQ:CHAN:GRO {}".format(sg, group) 386 self.send_command(cmd) 387 388 def get_rf_output_level(self, sg=1): 389 """ Gets the current RF output level 390 391 Args: 392 sg: signal generator number. 393 Default is 1 394 395 Returns: 396 current RF output level 397 """ 398 return self.send_query("SOUR{}:POW:CURR?".format(sg)) 399 400 def get_output_level_unit(self, sg=1): 401 """ Gets the current RF output level unit 402 403 Args: 404 sg: signal generator number. 405 Default is 1 406 407 Returns: 408 current RF output level unit 409 """ 410 return self.send_query("UNIT{}:POW?".format(sg)) 411 412 def set_output_level_unit(self, unit, sg=1): 413 """ Sets the RF output level unit 414 415 Args: 416 sg: signal generator number. 417 Default is 1 418 unit : Output level unit 419 420 Returns: 421 None 422 """ 423 cmd = "UNIT{}:POW {}".format(sg, unit) 424 self.send_command(cmd) 425 426 def get_output_level(self, sg=1): 427 """ Gets the Output level 428 429 Args: 430 sg: signal generator number. 431 Default is 1 432 433 Returns: 434 Output level 435 """ 436 return self.send_query("SOUR{}:POW?".format(sg)) 437 438 def set_output_level(self, level, sg=1): 439 """ Sets the Output level 440 441 Args: 442 sg: signal generator number. 443 Default is 1 444 level : Output level 445 446 Returns: 447 None 448 """ 449 cmd = "SOUR{}:POW {}".format(sg, level) 450 self.send_command(cmd) 451 452 def get_arb_state(self, sg=1): 453 """ Gets the ARB function state 454 455 Args: 456 sg: signal generator number. 457 Default is 1 458 459 Returns: 460 ARB function state . 0 (OFF) | 1(ON) 461 """ 462 return self.send_query("SOUR{}:RAD:ARB?".format(sg)) 463 464 def set_arb_state(self, state, sg=1): 465 """ Sets the ARB function state 466 467 Args: 468 sg: signal generator number. 469 Default is 1 470 state : enable state (ON/OFF) 471 472 Returns: 473 None 474 """ 475 cmd = "SOUR{}:RAD:ARB {}".format(sg, state) 476 self.send_command(cmd) 477 478 def restart_arb_waveform_pattern(self, sg=1): 479 """ playback the waveform pattern from the beginning. 480 481 Args: 482 sg: signal generator number. 483 Default is 1 484 485 Returns: 486 None 487 """ 488 cmd = "SOUR{}:RAD:ARB:WAV:REST".format(sg) 489 self.send_command(cmd) 490 491 def load_waveform(self, package_name, pattern_name, memory, sg=1): 492 """ loads the waveform from HDD to specified memory 493 494 Args: 495 sg: signal generator number. 496 Default is 1 497 package_name : Package name of signal 498 pattern_name : Pattern name of signal 499 memory: memory for the signal - "A" or "B" 500 501 Returns: 502 None 503 """ 504 cmd = "MMEM{}:LOAD:WAV:WM{} '{}','{}'".format(sg, memory, package_name, 505 pattern_name) 506 self.send_command(cmd) 507 508 def select_waveform(self, package_name, pattern_name, memory, sg=1): 509 """ Selects the waveform to output on specified memory 510 511 Args: 512 sg: signal generator number. 513 Default is 1 514 package_name : Package name of signal 515 pattern_name : Pattern name of signal 516 memory: memory for the signal - "A" or "B" 517 518 Returns: 519 None 520 """ 521 cmd = "SOUR{}:RAD:ARB:WM{}:WAV '{}','{}'".format( 522 sg, memory, package_name, pattern_name) 523 self.send_command(cmd) 524 525 def get_freq_relative_display_status(self, sg=1): 526 """ Gets the frequency relative display status 527 528 Args: 529 sg: signal generator number. 530 Default is 1 531 532 Returns: 533 frequency relative display status. 0 (OFF) | 1(ON) 534 """ 535 return self.send_query("SOUR{}:FREQ:REF:STAT?".format(sg)) 536 537 def set_freq_relative_display_status(self, enable, sg=1): 538 """ Sets frequency relative display status 539 540 Args: 541 sg: signal generator number. 542 Default is 1 543 enable : enable type (ON/OFF) 544 545 Returns: 546 None 547 """ 548 cmd = "SOUR{}:FREQ:REF:STAT {}".format(sg, enable) 549 self.send_command(cmd) 550 551 def get_freq_channel_display_type(self, sg=1): 552 """ Gets the selected type(frequency/channel) for input display 553 554 Args: 555 sg: signal generator number. 556 Default is 1 557 558 Returns: 559 selected type(frequecy/channel) for input display 560 """ 561 return self.send_query("SOUR{}:FREQ:TYPE?".format(sg)) 562 563 def set_freq_channel_display_type(self, freq_channel, sg=1): 564 """ Sets thes type(frequency/channel) for input display 565 566 Args: 567 sg: signal generator number. 568 Default is 1 569 freq_channel : display type (frequency/channel) 570 571 Returns: 572 None 573 """ 574 cmd = "SOUR{}:FREQ:TYPE {}".format(sg, freq_channel) 575 self.send_command(cmd) 576 577 def get_arb_combination_mode(self, sg=1): 578 """ Gets the current mode to generate the pattern 579 580 Args: 581 sg: signal generator number. 582 Default is 1 583 584 Returns: 585 current mode to generate the pattern 586 """ 587 return self.send_query("SOUR{}:RAD:ARB:PCOM?".format(sg)) 588 589 def set_arb_combination_mode(self, mode, sg=1): 590 """ Sets the mode to generate the pattern 591 592 Args: 593 sg: signal generator number. 594 Default is 1 595 mode : pattern generation mode 596 597 Returns: 598 None 599 """ 600 cmd = "SOUR{}:RAD:ARB:PCOM {}".format(sg, mode) 601 self.send_command(cmd) 602 603 def get_arb_pattern_aorb_state(self, a_or_b, sg=1): 604 """ Gets the Pattern A/B output state 605 606 Args: 607 sg: signal generator number. 608 Default is 1 609 a_or_b : Patten A or Pattern B( "A" or "B") 610 611 Returns: 612 Pattern A/B output state . 0(OFF) | 1(ON) 613 """ 614 return self.send_query("SOUR{}:RAD:ARB:WM{}:OUTP?".format(a_or_b, sg)) 615 616 def set_arb_pattern_aorb_state(self, a_or_b, state, sg=1): 617 """ Sets the Pattern A/B output state 618 619 Args: 620 sg: signal generator number. 621 Default is 1 622 a_or_b : Patten A or Pattern B( "A" or "B") 623 state : output state 624 625 Returns: 626 None 627 """ 628 cmd = "SOUR{}:RAD:ARB:WM{}:OUTP {}".format(sg, a_or_b, state) 629 self.send_command(cmd) 630 631 def get_arb_level_aorb(self, a_or_b, sg=1): 632 """ Gets the Pattern A/B output level 633 634 Args: 635 sg: signal generator number. 636 Default is 1 637 a_or_b : Patten A or Pattern B( "A" or "B") 638 639 Returns: 640 Pattern A/B output level 641 """ 642 return self.send_query("SOUR{}:RAD:ARB:WM{}:POW?".format(sg, a_or_b)) 643 644 def set_arb_level_aorb(self, a_or_b, level, sg=1): 645 """ Sets the Pattern A/B output level 646 647 Args: 648 sg: signal generator number. 649 Default is 1 650 a_or_b : Patten A or Pattern B( "A" or "B") 651 level : output level 652 653 Returns: 654 None 655 """ 656 cmd = "SOUR{}:RAD:ARB:WM{}:POW {}".format(sg, a_or_b, level) 657 self.send_command(cmd) 658 659 def get_arb_freq_offset(self, sg=1): 660 """ Gets the frequency offset between Pattern A and Patten B 661 when CenterSignal is A or B. 662 663 Args: 664 sg: signal generator number. 665 Default is 1 666 667 Returns: 668 frequency offset between Pattern A and Patten B 669 """ 670 return self.send_query("SOUR{}:RAD:ARB:FREQ:OFFS?".format(sg)) 671 672 def set_arb_freq_offset(self, offset, sg=1): 673 """ Sets the frequency offset between Pattern A and Patten B when 674 CenterSignal is A or B. 675 676 Args: 677 sg: signal generator number. 678 Default is 1 679 offset : frequency offset 680 681 Returns: 682 None 683 """ 684 cmd = "SOUR{}:RAD:ARB:FREQ:OFFS {}".format(sg, offset) 685 self.send_command(cmd) 686 687 def get_arb_freq_offset_aorb(self, sg=1): 688 """ Gets the frequency offset of Pattern A/Pattern B based on Baseband 689 center frequency 690 691 Args: 692 sg: signal generator number. 693 Default is 1 694 695 Returns: 696 frequency offset 697 """ 698 return self.send_query( 699 "SOUR{}:RAD:ARB:WM{}:FREQ:OFFS?".format(sg, a_or_b)) 700 701 def set_arb_freq_offset_aorb(self, a_or_b, offset, sg=1): 702 """ Sets the frequency offset of Pattern A/Pattern B based on Baseband 703 center frequency 704 705 Args: 706 sg: signal generator number. 707 Default is 1 708 a_or_b : Patten A or Pattern B( "A" or "B") 709 offset : frequency offset 710 711 Returns: 712 None 713 """ 714 cmd = "SOUR{}:RAD:ARB:WM{}:FREQ:OFFS {}".format(sg, a_or_b, offset) 715 self.send_command(cmd) 716