• 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"""Controller module for attenuators.
15
16Sample Config:
17
18.. code-block:: python
19
20    "Attenuator": [
21        {
22            "address": "192.168.1.12",
23            "port": 23,
24            "model": "minicircuits",
25            "paths": ["AP1-2G", "AP1-5G", "AP2-2G", "AP2-5G"]
26        },
27        {
28            "address": "192.168.1.14",
29            "port": 23,
30            "model": "minicircuits",
31            "paths": ["AP-DUT"]
32        }
33    ]
34"""
35import importlib
36import logging
37
38MOBLY_CONTROLLER_CONFIG_NAME = "Attenuator"
39# Keys used inside a config dict for attenuator.
40# Keys for making the connection to the attenuator device. Right now we only
41# use telnet lib. This can be refactored when the need for a different
42# communication protocol arises.
43KEY_ADDRESS = "address"
44KEY_PORT = "port"
45# A string that is the model of the attenuator used. This is essentially the
46# module name for the underlying driver for the attenuator hardware.
47KEY_MODEL = "model"
48# A list of strings, each describing what's the connected to this attenuation
49# path
50KEY_PATHS = "paths"
51
52PACKAGE_PATH_TEMPLATE = "mobly.controllers.attenuator_lib.%s"
53
54
55def create(configs):
56  objs = []
57  for config in configs:
58    _validate_config(config)
59    attenuator_model = config[KEY_MODEL]
60    # Import the correct driver module for the attenuator device
61    module_name = PACKAGE_PATH_TEMPLATE % attenuator_model
62    module = importlib.import_module(module_name)
63    # Create each
64    attenuation_device = module.AttenuatorDevice(
65        path_count=len(config[KEY_PATHS]))
66    attenuation_device.model = attenuator_model
67    instances = attenuation_device.open(config[KEY_ADDRESS], config[KEY_PORT])
68    for idx, path_name in enumerate(config[KEY_PATHS]):
69      path = AttenuatorPath(attenuation_device, idx=idx, name=path_name)
70      objs.append(path)
71  return objs
72
73
74def destroy(objs):
75  for attenuation_path in objs:
76    attenuation_path.attenuation_device.close()
77
78
79class Error(Exception):
80  """This is the Exception class defined for all errors generated by
81    Attenuator-related modules.
82    """
83
84
85def _validate_config(config):
86  """Verifies that a config dict for an attenuator device is valid.
87
88    Args:
89        config: A dict that is the configuration for an attenuator device.
90
91    Raises:
92        attenuator.Error: A config is not valid.
93    """
94  required_keys = [KEY_ADDRESS, KEY_MODEL, KEY_PORT, KEY_PATHS]
95  for key in required_keys:
96    if key not in config:
97      raise Error("Required key %s missing from config %s", (key, config))
98
99
100class AttenuatorPath:
101  """A convenience class that allows users to control each attenuator path
102    separately as different objects, as opposed to passing in an index number
103    to the functions of an attenuator device object.
104
105    This decouples the test code from the actual attenuator device used in the
106    physical test bed.
107
108    For example, if a test needs to attenuate four signal paths, this allows the
109    test to do:
110
111    .. code-block:: python
112
113        self.attenuation_paths[0].set_atten(50)
114        self.attenuation_paths[1].set_atten(40)
115
116    instead of:
117
118    .. code-block:: python
119
120        self.attenuators[0].set_atten(0, 50)
121        self.attenuators[0].set_atten(1, 40)
122
123    The benefit the former is that the physical test bed can use either four
124    single-channel attenuators, or one four-channel attenuators. Whereas the
125    latter forces the test bed to use a four-channel attenuator.
126    """
127
128  def __init__(self, attenuation_device, idx=0, name=None):
129    self.model = attenuation_device.model
130    self.attenuation_device = attenuation_device
131    self.idx = idx
132    if (self.idx >= attenuation_device.path_count):
133      raise IndexError("Attenuator index out of range!")
134
135  def set_atten(self, value):
136    """This function sets the attenuation of Attenuator.
137
138        Args:
139            value: This is a floating point value for nominal attenuation to be
140                set. Unit is db.
141        """
142    self.attenuation_device.set_atten(self.idx, value)
143
144  def get_atten(self):
145    """Gets the current attenuation setting of Attenuator.
146
147        Returns:
148            A float that is the current attenuation value. Unit is db.
149        """
150
151    return self.attenuation_device.get_atten(self.idx)
152
153  def get_max_atten(self):
154    """Gets the max attenuation supported by the Attenuator.
155
156        Returns:
157            A float that is the max attenuation value.
158        """
159    return self.attenuation_device.max_atten
160