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