1 #!/usr/bin/env python3.4 2 3 # Copyright 2016- The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 """ 18 Class for Telnet control of Mini-Circuits RCDAT series attenuators 19 20 This class provides a wrapper to the MC-RCDAT attenuator modules for purposes 21 of simplifying and abstracting control down to the basic necessities. It is 22 not the intention of the module to expose all functionality, but to allow 23 interchangeable HW to be used. 24 25 See http://www.minicircuits.com/softwaredownload/Prog_Manual-6-Programmable_Attenuator.pdf 26 """ 27 28 from acts.controllers import attenuator 29 from acts.controllers.attenuator_lib import _tnhelper 30 31 32 class AttenuatorInstrument(attenuator.AttenuatorInstrument): 33 r"""This provides a specific telnet-controlled implementation of AttenuatorInstrument for 34 Mini-Circuits RC-DAT attenuators. 35 36 With the exception of telnet-specific commands, all functionality is defined by the 37 AttenuatorInstrument class. Because telnet is a stateful protocol, the functionality of 38 AttenuatorInstrument is contingent upon a telnet connection being established. 39 """ 40 41 def __init__(self, num_atten=0): 42 super(AttenuatorInstrument, self).__init__(num_atten) 43 self._tnhelper = _tnhelper._TNHelper(tx_cmd_separator="\r\n", 44 rx_cmd_separator="\r\n", 45 prompt="") 46 47 def __del__(self): 48 if self.is_open(): 49 self.close() 50 51 def open(self, host, port=23): 52 r"""Opens a telnet connection to the desired AttenuatorInstrument and queries basic 53 information. 54 55 Parameters 56 ---------- 57 host : A valid hostname (IP address or DNS-resolvable name) to an MC-DAT attenuator 58 instrument. 59 port : An optional port number (defaults to telnet default 23) 60 """ 61 62 self._tnhelper.open(host, port) 63 64 if self.num_atten == 0: 65 self.num_atten = 1 66 67 config_str = self._tnhelper.cmd("MN?") 68 69 if config_str.startswith("MN="): 70 config_str = config_str[len("MN="):] 71 72 self.properties = dict(zip(['model', 'max_freq', 'max_atten'], config_str.split("-", 2))) 73 self.max_atten = float(self.properties['max_atten']) 74 75 def is_open(self): 76 r"""This function returns the state of the telnet connection to the underlying 77 AttenuatorInstrument. 78 79 Returns 80 ------- 81 Bool 82 True if there is a successfully open connection to the AttenuatorInstrument 83 """ 84 85 return bool(self._tnhelper.is_open()) 86 87 def close(self): 88 r"""Closes a telnet connection to the desired AttenuatorInstrument. 89 90 This should be called as part of any teardown procedure prior to the attenuator 91 instrument leaving scope. 92 """ 93 94 self._tnhelper.close() 95 96 def set_atten(self, idx, value): 97 r"""This function sets the attenuation of an attenuator given its index in the instrument. 98 99 Parameters 100 ---------- 101 idx : This zero-based index is the identifier for a particular attenuator in an 102 instrument. For instruments that only has one channel, this is ignored by the device. 103 value : This is a floating point value for nominal attenuation to be set. 104 105 Raises 106 ------ 107 InvalidOperationError 108 This error occurs if the underlying telnet connection to the instrument is not open. 109 IndexError 110 If the index of the attenuator is greater than the maximum index of the underlying 111 instrument, this error will be thrown. Do not count on this check programmatically. 112 ValueError 113 If the requested set value is greater than the maximum attenuation value, this error 114 will be thrown. Do not count on this check programmatically. 115 """ 116 117 if not self.is_open(): 118 raise attenuator.InvalidOperationError("Connection not open!") 119 120 if idx >= self.num_atten: 121 raise IndexError("Attenuator index out of range!", self.num_atten, idx) 122 123 if value > self.max_atten: 124 raise ValueError("Attenuator value out of range!", self.max_atten, value) 125 # The actual device uses one-based index for channel numbers. 126 self._tnhelper.cmd("CHAN:%s:SETATT:%s" % (idx + 1, value)) 127 128 def get_atten(self, idx): 129 r"""This function returns the current attenuation from an attenuator at a given index in 130 the instrument. 131 132 Parameters 133 ---------- 134 idx : This zero-based index is the identifier for a particular attenuator in an instrument. 135 136 Raises 137 ------ 138 InvalidOperationError 139 This error occurs if the underlying telnet connection to the instrument is not open. 140 141 Returns 142 ------- 143 float 144 Returns a the current attenuation value 145 """ 146 147 if not self.is_open(): 148 raise attenuator.InvalidOperationError("Connection not open!") 149 150 if idx >= self.num_atten or idx < 0: 151 raise IndexError("Attenuator index out of range!", self.num_atten, idx) 152 153 atten_val_str = self._tnhelper.cmd("CHAN:%s:ATT?" % (idx + 1)) 154 atten_val = float(atten_val_str) 155 return atten_val