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