xref: /aosp_15_r20/external/autotest/server/cros/network/attenuator.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6from autotest_lib.client.common_lib import error
7from autotest_lib.server.cros.network import telnet_helper
8
9
10class Attenuator(object):
11    """Represents a minicircuits telnet-controlled 4-channel variable
12    attenuator."""
13
14    def __init__(self, host, num_atten=0):
15        self._tnhelper = telnet_helper.TelnetHelper(
16                tx_cmd_separator="\r\n", rx_cmd_separator="\r\n", prompt="")
17        self.host = host
18        self.num_atten = num_atten
19        self.open(host)
20
21
22    def __del__(self):
23        if self.is_open():
24            self.close()
25
26    def open(self, host, port=22):
27        """Opens a telnet connection to the attenuator and queries basic
28        information.
29
30        @param host: Valid hostname
31        @param port: Optional port number, defaults to 22
32
33        """
34        self._tnhelper.open(host, port)
35
36        if self.num_atten == 0:
37            self.num_atten = 1
38
39        config_str = self._tnhelper.cmd("MN?")
40
41        if config_str.startswith("MN="):
42            config_str = config_str[len("MN="):]
43
44        self.properties = dict(list(zip(['model', 'max_freq', 'max_atten'],
45                                   config_str.split("-", 2))))
46        self.max_atten = float(self.properties['max_atten'])
47        self.min_atten = 0
48
49    def is_open(self):
50        """Returns true if telnet connection to attenuator is open."""
51        return bool(self._tnhelper.is_open())
52
53    def reopen(self, host, port=22):
54        """Close and reopen telnet connection to the attenuator."""
55        self._tnhelper.close()
56        self._tnhelper.open(host, port)
57
58    def close(self):
59        """Closes the telnet connection."""
60        self._tnhelper.close()
61
62    def set_atten(self, channel, value):
63        """Set attenuation of the attenuator for given channel (0-3).
64
65        @param channel: Zero-based attenuator channel to set attenuation (0-3)
66        @param value: Floating point value for attenuation to be set
67        """
68        if not self.is_open():
69            raise error.TestError("Connection not open!")
70
71        if channel >= self.num_atten:
72            raise error.TestError("Attenuator channel out of range! Requested "
73                                  "%d; max available %d" %
74                                  (channel, self.num_atten))
75
76        if not (self.min_atten <= value <= self.max_atten):
77            raise error.TestError("Requested attenuator value %d not in range "
78                                  "(%d - %d)" %
79                                  (value, self.min_atten, self.max_atten))
80        # The actual device uses one-based channel for channel numbers.
81        if (int(self._tnhelper.cmd("CHAN:%d:SETATT:%d" %
82                                  (channel + 1, value))) != 1):
83            raise error.TestError("Error while setting attenuation on %d" %
84                                  channel)
85
86    def get_atten(self, channel):
87        """Returns current attenuation of the attenuator for given channel.
88
89        @param channel: Attenuator channel
90        @returns the current attenuation value as a float
91        """
92        if not self.is_open():
93            raise error.TestError("Connection not open!")
94
95        if channel >= self.num_atten or channel < 0:
96            raise error.TestError("Attenuator channel out of range! Requested "
97                                  "%d; should be between 0 and max available "
98                                  "%d" % (channel, self.num_atten))
99
100        return float(self._tnhelper.cmd("CHAN:%d:ATT?" % (channel + 1)))
101