• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""
15This module has the class for controlling Mini-Circuits RCDAT series
16attenuators over Telnet.
17
18See http://www.minicircuits.com/softwaredownload/Prog_Manual-6-Programmable_Attenuator.pdf
19"""
20
21from mobly.controllers import attenuator
22from mobly.controllers.attenuator_lib import telnet_scpi_client
23
24
25class AttenuatorDevice:
26  """This provides a specific telnet-controlled implementation of
27    AttenuatorDevice for Mini-Circuits RC-DAT attenuators.
28
29    Attributes:
30        path_count: The number of signal attenuation path this device has.
31    """
32
33  def __init__(self, path_count=1):
34    self.path_count = path_count
35    # The telnet client used to communicate with the attenuator device.
36    self._telnet_client = telnet_scpi_client.TelnetScpiClient(
37        tx_cmd_separator="\r\n", rx_cmd_separator="\r\n", prompt="")
38
39  @property
40  def is_open(self):
41    """This function returns the state of the telnet connection to the
42        underlying AttenuatorDevice.
43
44        Returns:
45            True if there is a successfully open connection to the
46            AttenuatorDevice.
47        """
48    return bool(self._telnet_client.is_open)
49
50  def open(self, host, port=23):
51    """Opens a telnet connection to the desired AttenuatorDevice and
52        queries basic information.
53
54        Args:
55            host: A valid hostname (IP address or DNS-resolvable name) to an
56                MC-DAT attenuator instrument.
57            port: An optional port number (defaults to telnet default 23)
58        """
59    self._telnet_client.open(host, port)
60    config_str = self._telnet_client.cmd("MN?")
61    if config_str.startswith("MN="):
62      config_str = config_str[len("MN="):]
63    self.properties = dict(
64        zip(['model', 'max_freq', 'max_atten'], config_str.split("-", 2)))
65    self.max_atten = float(self.properties['max_atten'])
66
67  def close(self):
68    """Closes a telnet connection to the desired attenuator device.
69
70        This should be called as part of any teardown procedure prior to the
71        attenuator instrument leaving scope.
72        """
73    if self.is_open:
74      self._telnet_client.close()
75
76  def set_atten(self, idx, value):
77    """Sets the attenuation value for a particular signal path.
78
79        Args:
80            idx: Zero-based index int which is the identifier for a particular
81                signal path in an instrument. For instruments that only has one
82                channel, this is ignored by the device.
83            value: A float that is the attenuation value to set.
84
85        Raises:
86            Error: The underlying telnet connection to the instrument is not
87                open.
88            IndexError: The index of the attenuator is greater than the maximum
89                index of the underlying instrument.
90            ValueError: The requested set value is greater than the maximum
91                attenuation value.
92        """
93    if not self.is_open:
94      raise attenuator.Error("Connection to attenuator at %s is not open!" %
95                             self._telnet_client.host)
96    if idx + 1 > self.path_count:
97      raise IndexError("Attenuator index out of range!", self.path_count, idx)
98    if value > self.max_atten:
99      raise ValueError("Attenuator value out of range!", self.max_atten, value)
100    # The actual device uses one-based index for channel numbers.
101    self._telnet_client.cmd("CHAN:%s:SETATT:%s" % (idx + 1, value))
102
103  def get_atten(self, idx=0):
104    """This function returns the current attenuation from an attenuator at a
105        given index in the instrument.
106
107        Args:
108            idx: This zero-based index is the identifier for a particular
109                attenuator in an instrument.
110
111        Raises:
112            Error: The underlying telnet connection to the instrument is not
113                open.
114
115        Returns:
116            A float that is the current attenuation value.
117        """
118    if not self.is_open:
119      raise attenuator.Error("Connection to attenuator at %s is not open!" %
120                             self._telnet_client.host)
121    if idx + 1 > self.path_count or idx < 0:
122      raise IndexError("Attenuator index out of range!", self.path_count, idx)
123    telnet_cmd = ":ATT?" if self.path_count == 1 else "CHAN:%s:ATT?" % (idx + 1)
124    atten_val_str = self._telnet_client.cmd(telnet_cmd)
125    atten_val = float(atten_val_str)
126    return atten_val
127