1
2#   Copyright 2016- The Android Open Source Project
3#
4#   Licensed under the Apache License, Version 2.0 (the "License");
5#   you may not use this file except in compliance with the License.
6#   You may obtain a copy of the License at
7#
8#       http://www.apache.org/licenses/LICENSE-2.0
9#
10#   Unless required by applicable law or agreed to in writing, software
11#   distributed under the License is distributed on an "AS IS" BASIS,
12#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13#   See the License for the specific language governing permissions and
14#   limitations under the License.
15"""
16Class for Telnet control of Aeroflex 832X and 833X Series Attenuator Modules
17
18This class provides a wrapper to the Aeroflex attenuator modules for purposes
19of simplifying and abstracting control down to the basic necessities. It is
20not the intention of the module to expose all functionality, but to allow
21interchangeable HW to be used.
22
23See http://www.aeroflex.com/ams/weinschel/PDFILES/IM-608-Models-8320-&-8321-preliminary.pdf
24"""
25
26from vts.utils.python.controllers import attenuator
27from vts.utils.python.controllers.attenuator_lib import _tnhelper
28
29
30class AttenuatorInstrument(attenuator.AttenuatorInstrument):
31    def __init__(self, num_atten=0):
32        super().__init__(num_atten)
33
34        self._tnhelper = _tnhelper._TNHelper(tx_cmd_separator="\r\n",
35                                             rx_cmd_separator="\r\n",
36                                             prompt=">")
37        self.properties = None
38
39    def open(self, host, port=23):
40        r"""Opens a telnet connection to the desired AttenuatorInstrument and queries basic
41        information.
42
43        Parameters
44        ----------
45        host : A valid hostname (IP address or DNS-resolvable name) to an MC-DAT attenuator
46        instrument.
47        port : An optional port number (defaults to telnet default 23)
48        """
49        self._tnhelper.open(host, port)
50
51        # work around a bug in IO, but this is a good thing to do anyway
52        self._tnhelper.cmd("*CLS", False)
53
54        if self.num_atten == 0:
55            self.num_atten = int(self._tnhelper.cmd("RFCONFIG? CHAN"))
56
57        configstr = self._tnhelper.cmd("RFCONFIG? ATTN 1")
58
59        self.properties = dict(zip(
60            ['model', 'max_atten', 'min_step', 'unknown', 'unknown2', 'cfg_str'
61             ], configstr.split(", ", 5)))
62
63        self.max_atten = float(self.properties['max_atten'])
64
65    def is_open(self):
66        r"""This function returns the state of the telnet connection to the underlying
67        AttenuatorInstrument.
68
69        Returns
70        -------
71        Bool
72            True if there is a successfully open connection to the AttenuatorInstrument
73        """
74
75        return bool(self._tnhelper.is_open())
76
77    def close(self):
78        r"""Closes a telnet connection to the desired AttenuatorInstrument.
79
80        This should be called as part of any teardown procedure prior to the attenuator
81        instrument leaving scope.
82        """
83
84        self._tnhelper.close()
85
86    def set_atten(self, idx, value):
87        r"""This function sets the attenuation of an attenuator given its index in the instrument.
88
89        Parameters
90        ----------
91        idx : This zero-based index is the identifier for a particular attenuator in an
92        instrument.
93        value : This is a floating point value for nominal attenuation to be set.
94
95        Raises
96        ------
97        InvalidOperationError
98            This error occurs if the underlying telnet connection to the instrument is not open.
99        IndexError
100            If the index of the attenuator is greater than the maximum index of the underlying
101            instrument, this error will be thrown. Do not count on this check programmatically.
102        ValueError
103            If the requested set value is greater than the maximum attenuation value, this error
104            will be thrown. Do not count on this check programmatically.
105        """
106
107        if not self.is_open():
108            raise attenuator.InvalidOperationError("Connection not open!")
109
110        if idx >= self.num_atten:
111            raise IndexError("Attenuator index out of range!", self.num_atten,
112                             idx)
113
114        if value > self.max_atten:
115            raise ValueError("Attenuator value out of range!", self.max_atten,
116                             value)
117
118        self._tnhelper.cmd("ATTN " + str(idx + 1) + " " + str(value), False)
119
120    def get_atten(self, idx):
121        r"""This function returns the current attenuation from an attenuator at a given index in
122        the instrument.
123
124        Parameters
125        ----------
126        idx : This zero-based index is the identifier for a particular attenuator in an instrument.
127
128        Raises
129        ------
130        InvalidOperationError
131            This error occurs if the underlying telnet connection to the instrument is not open.
132
133        Returns
134        -------
135        float
136            Returns a the current attenuation value
137        """
138        if not self.is_open():
139            raise attenuator.InvalidOperationError("Connection not open!")
140
141#       Potentially redundant safety check removed for the moment
142#       if idx >= self.num_atten:
143#           raise IndexError("Attenuator index out of range!", self.num_atten, idx)
144
145        atten_val = self._tnhelper.cmd("ATTN? " + str(idx + 1))
146
147        return float(atten_val)
148