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 Mini-Circuits RCDAT series attenuators
17
18This class provides a wrapper to the MC-RCDAT 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.minicircuits.com/softwaredownload/Prog_Manual-6-Programmable_Attenuator.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    r"""This provides a specific telnet-controlled implementation of AttenuatorInstrument for
32    Mini-Circuits RC-DAT attenuators.
33
34    With the exception of telnet-specific commands, all functionality is defined by the
35    AttenuatorInstrument class. Because telnet is a stateful protocol, the functionality of
36    AttenuatorInstrument is contingent upon a telnet connection being established.
37    """
38
39    def __init__(self, num_atten=0):
40        super().__init__(num_atten)
41        self._tnhelper = _tnhelper._TNHelper(tx_cmd_separator="\r\n",
42                                             rx_cmd_separator="\n\r",
43                                             prompt="")
44
45    def __del__(self):
46        if self.is_open():
47            self.close()
48
49    def open(self, host, port=23):
50        r"""Opens a telnet connection to the desired AttenuatorInstrument and queries basic
51        information.
52
53        Parameters
54        ----------
55        host : A valid hostname (IP address or DNS-resolvable name) to an MC-DAT attenuator
56        instrument.
57        port : An optional port number (defaults to telnet default 23)
58        """
59
60        self._tnhelper.open(host, port)
61
62        if self.num_atten == 0:
63            self.num_atten = 1
64
65        config_str = self._tnhelper.cmd("MN?")
66
67        if config_str.startswith("MN="):
68            config_str = config_str[len("MN="):]
69
70        self.properties = dict(zip(
71            ['model', 'max_freq', 'max_atten'], config_str.split("-", 2)))
72        self.max_atten = float(self.properties['max_atten'])
73
74    def is_open(self):
75        r"""This function returns the state of the telnet connection to the underlying
76        AttenuatorInstrument.
77
78        Returns
79        -------
80        Bool
81            True if there is a successfully open connection to the AttenuatorInstrument
82        """
83
84        return bool(self._tnhelper.is_open())
85
86    def close(self):
87        r"""Closes a telnet connection to the desired AttenuatorInstrument.
88
89        This should be called as part of any teardown procedure prior to the attenuator
90        instrument leaving scope.
91        """
92
93        self._tnhelper.close()
94
95    def set_atten(self, idx, value):
96        r"""This function sets the attenuation of an attenuator given its index in the instrument.
97
98        Parameters
99        ----------
100        idx : This zero-based index is the identifier for a particular attenuator in an
101        instrument.
102        value : This is a floating point value for nominal attenuation to be set.
103
104        Raises
105        ------
106        InvalidOperationError
107            This error occurs if the underlying telnet connection to the instrument is not open.
108        IndexError
109            If the index of the attenuator is greater than the maximum index of the underlying
110            instrument, this error will be thrown. Do not count on this check programmatically.
111        ValueError
112            If the requested set value is greater than the maximum attenuation value, this error
113            will be thrown. Do not count on this check programmatically.
114        """
115
116        if not self.is_open():
117            raise attenuator.InvalidOperationError("Connection not open!")
118
119        if idx >= self.num_atten:
120            raise IndexError("Attenuator index out of range!", self.num_atten,
121                             idx)
122
123        if value > self.max_atten:
124            raise ValueError("Attenuator value out of range!", self.max_atten,
125                             value)
126
127        self._tnhelper.cmd("SETATT=" + str(value))
128
129    def get_atten(self, idx):
130        r"""This function returns the current attenuation from an attenuator at a given index in
131        the instrument.
132
133        Parameters
134        ----------
135        idx : This zero-based index is the identifier for a particular attenuator in an instrument.
136
137        Raises
138        ------
139        InvalidOperationError
140            This error occurs if the underlying telnet connection to the instrument is not open.
141
142        Returns
143        -------
144        float
145            Returns a the current attenuation value
146        """
147
148        if not self.is_open():
149            raise attenuator.InvalidOperationError("Connection not open!")
150
151        atten_val = self._tnhelper.cmd("ATT?")
152
153        return float(atten_val)
154