1a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu# Copyright (c) 2017 The Chromium OS Authors. All rights reserved.
2a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu# Use of this source code is governed by a BSD-style license that can be
3a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu# found in the LICENSE file.
4a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
5a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu"""Interface to control RF Switch.
6a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
7a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj VeluHelper module to control RF Switch. Common commands to control the relays
8a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Veluare made available as methods that can be called.
9a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
10a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj VeluPlease refer go/rf-switch for more info on the switch.
11a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu"""
12a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Veluimport contextlib
13a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Veluimport logging
14a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
15a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velufrom autotest_lib.server.cros.network.rf_switch import scpi
16a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
17a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
18a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Veluclass RfSwitchException(Exception):
19a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    """Exception for RfSwitch Errors."""
20a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
21a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
22a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Veluclass RfSwitch(scpi.Scpi):
23a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    """RF Switch Controller."""
24a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
25a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _ALL_AP_RELAYS = 'k1_1:k1_24'  # Each AP uses 6 relays
26a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _ALL_CLIENT_RELAYS = 'k1_25:k1_48'  # Each client uses 6 relays
27a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _MIN_ENCLOSURE = 1  # Starting enclosure number
28a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _MAX_ENCLOSURE = 4  # Last enclosure number
29a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _ALL_ENCLOSURE = 0  # All the enclosures
30a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _RELAYS_PER_ENCLOSURE = 6  # Number of relays in an enclosure
31a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
32a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    # Each AP enclosure uses 6 relays and a R relay to set attenuation
33a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _AP_ATTENUATOR_RELAYS = {
34a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        1: ['k1_49', 'k1_50', 'k1_51', 'k1_52', 'k1_53', 'k1_54', 'R1_9'],
35a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        2: ['k1_55', 'k1_56', 'k1_57', 'k1_58', 'k1_59', 'k1_60', 'R1_10'],
36a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        3: ['k1_61', 'k1_62', 'k1_63', 'k1_64', 'k1_65', 'k1_66', 'R1_11'],
37a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        4: ['k1_67', 'k1_68', 'k1_69', 'k1_70', 'k1_71', 'k1_72', 'R1_12'],
38a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    }
39a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    # Shorter version
40a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _AP_ATTENUATOR_RELAYS_SHORT = {
41a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        1: 'k1_49:k1_54,R1_9',
42a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        2: 'k1_55:k1_60,R1_10',
43a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        3: 'k1_61:k1_66,R1_11',
44a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        4: 'k1_67:k1_72,R1_12',
45a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    }
46a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
47a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_CLOSE_RELAYS = 'ROUT:CLOS'
48a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_CHECK_RELAYS_CLOSED = 'ROUT:CLOS?'
49a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_OPEN_RELAYS = 'ROUT:OPEN'
50a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_OPEN_ALL_RELAYS = 'ROUT:OPEN:ALL'
51a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_SET_VERIFY = 'ROUT:CHAN:VER'
52a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_GET_VERIFY = 'ROUT:CHAN:VER?'
53a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_SET_VERIFY_INVERTED = 'ROUT:CHAN:VER:POL'
54a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_GET_VERIFY_INVERTED = 'ROUT:CHAN:VER:POL?'
55a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_GET_VERIFY_STATE = 'ROUT:CHAN:VER:POS:STAT?'
56a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_CHECK_BUSY = 'ROUT:MOD:BUSY?'
57a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    _CMD_WAIT = 'ROUT:MOD:WAIT'
58a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
59a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def __init__(self, host, port=scpi.Scpi.SCPI_PORT):
60a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Controller for RF Switch.
61a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
62a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param host: Hostname or IP address of RF Switch
63a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param port: Int SCPI port number (default 5025)
64a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
65a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
66a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        scpi.Scpi.__init__(self, host, port)
67a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
68a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def send_cmd_check_error(self, cmd):
69a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Send command to switch and check for any error.
70a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
71a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param cmd: string cmd to send to switch
72a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
73a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
74a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.write(cmd)
75a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        code, error = self.error_query()
76a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        if code:
77a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            raise RfSwitchException('Error on command: "%s" - code: %s,'
78a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                                    ' message: %s', cmd, code, error)
79a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.wait()
80a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
81a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def close_relays(self, relays):
82a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Close relays.
83a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
84a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param relays: relays to close (, to separate and : for range)
85a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
86a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
87a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.send_cmd_check_error('%s (@%s)\n'
88a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                                  % (self._CMD_CLOSE_RELAYS, relays))
89a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
90a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def relays_closed(self, relays):
91a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Get open/closed status of relays.
92a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
93a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param relays: relays to check (, to separate and : for range)
94a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
95a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns tuple of relay status, status is true if a relay is closed.
96a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
97a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
98a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
99a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        status = self.query('%s (@%s)\n' % (self._CMD_CHECK_RELAYS_CLOSED,
100a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                                            relays)).strip().split(',')
101a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        return tuple(bool(int(x)) for x in status)
102a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
103a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def open_relays(self, relays):
104a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Open relays.
105a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
106a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param relays: string relays to close (, to separate and : for range)
107a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
108a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
109a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.send_cmd_check_error('%s (@%s)\n' % (
110a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                self._CMD_OPEN_RELAYS, relays))
111a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
112a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def open_all_relays(self):
113a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Open all relays.
114a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
115a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        This will open all relays including the attenuator, which will set it
116a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        to Max. Please remember to set your attenuation to right level after
117a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        this call.
118a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
119a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
120a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.send_cmd_check_error('%s\n' % self._CMD_OPEN_ALL_RELAYS)
121a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
122a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def set_verify(self, relays, on):
123a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Configure Close? to return indicator state instead of driven state.
124a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
125a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param relays: relays to verify (, to separate and : for range)
126a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param on: string state to verify (on(True)/off(False))
127a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
128a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
129a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.send_cmd_check_error('%s %s,(@%s)\n' % (
130a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            self._CMD_SET_VERIFY, int(bool(on)), relays))
131a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
132a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def get_verify(self, relays):
133a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Get the verify mode of relays.
134a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
135a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param relays: relays to verify (, to separate and : for range)
136a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns tuple of verify mode for relays
137a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
138a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
139a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        status = self.query('%s (@%s)\n' % (
140a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            self._CMD_GET_VERIFY, relays)).strip().split(',')
141a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        return tuple(bool(int(x)) for x in status)
142a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
143a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def set_verify_inverted(self, relays, inverted):
144a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Set the polarity confidence of relay to be inverted.
145a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
146a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param relays: relays to set (, to separate and : for range)
147a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param inverted: Boolean True if INV, False for NORM
148a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
149a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
150a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.send_cmd_check_error('%s %s,(@%s)\n' % (
151a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                self._CMD_SET_VERIFY_INVERTED,
152a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                'INV' if inverted else 'NORM', relays))
153a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
154a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def get_verify_inverted(self, relays):
155a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Get the confidence polarity. 1 is inverted, 0 is value as-is.
156a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
157a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param relays: relays to get (, to separate and : for range)
158a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns tuple of status where 1 in inverted and 0 for value as-is
159a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
160a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
161a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        status = self.query('%s (@%s)\n' % (self._CMD_GET_VERIFY_INVERTED,
162a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                                            relays)).strip().split(',')
163a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        return tuple(bool(int(x)) for x in status)
164a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
165a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def get_verify_state(self, relays):
166a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """If verify set get driven state, else confidence state.
167a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
168a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param relays: relays to get (, to separate and : for range)
169a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
170a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns tuple of verify status for given relays
171a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
172a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
173a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        status = self.query('%s (@%s)\n' % (self._CMD_GET_VERIFY_STATE,
174a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                                            relays)).strip().split(',')
175a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        return tuple(bool(int(x)) for x in status)
176a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
177a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    @property
178a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def busy(self):
179a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Check relays are still settling.
180a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
181a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns Boolean True if relays are settling, False if not.
182a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
183a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
184a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        return bool(int(self.query('%s\n' % self._CMD_CHECK_BUSY).strip()))
185a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
186a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def wait(self):
187a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Wait for relays to debounce."""
188a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.write('%s\n' % self._CMD_WAIT)
189a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
190a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def get_attenuation(self, ap_enclosure):
191a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Get Attenuation for an AP enclosure.
192a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
193a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        Attenuation is set by turning on/off the relays.  Each relay specifies
194a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        a bit in the binary value of attenuation.  Find the relay status and
195a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        build the binary value, then find the decimal value from it.
196a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
197a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param ap_enclosure: Int 1/2/3/4 (AP enclosure index)
198a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
199a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns attenuation value in int
200a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
201a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @raises ValueError: on bad ap_enclosure value
202a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
203a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
204a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        if (ap_enclosure < self._MIN_ENCLOSURE or
205a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                ap_enclosure > self._MAX_ENCLOSURE):
206a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            raise ValueError('Invalid AP enclosure number: %s.', ap_enclosure)
207a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        else:
208a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            a_status = self.relays_closed(
209a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                self._AP_ATTENUATOR_RELAYS_SHORT[ap_enclosure])
210a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            status = a_status[::-1]  # reverse for Endian transform
211a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            logging.debug('attenuator status: %s', status)
212a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
213a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            # build the binary value
214a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            binary = ''.join(['0' if x else '1' for x in status])
215a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            return int(binary, 2)
216a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
217a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def get_all_attenuation(self):
218a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Get attenuation value for all AP enclosures.
219a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
220a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns tuple of attenuation value for each enclosure
221a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
222a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
223a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        attenuations = []
224a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        for x in xrange(self._MIN_ENCLOSURE, self._MAX_ENCLOSURE + 1):
225a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            attenuations.append(self.get_attenuation(x))
226a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        return tuple(attenuations)
227a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
228a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def set_attenuation(self, ap_enclosure, attenuation):
229a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Set attenuation for an AP enclosure.
230a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
231a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param ap_enclosure: Int 0,1,2,3,4 AP enclosure number. 0 for all
232a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param attenuation: Int Attenuation value to set
233a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
234a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @raises ValueError: on bad ap_enclosure value
235a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
236a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
237a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        if ap_enclosure == self._ALL_ENCLOSURE:
238a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            # set attenuation on all
239a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            for x in xrange(self._MIN_ENCLOSURE, self._MAX_ENCLOSURE + 1):
240a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                self.set_attenuation(x, attenuation)
241a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        elif (ap_enclosure < self._MIN_ENCLOSURE or
242a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu              ap_enclosure > self._MAX_ENCLOSURE):
243a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            raise ValueError('Bad AP enclosure value: %s' % ap_enclosure)
244a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        else:
245a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            # convert attenuation decimal value to binary
246a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            bin_array = [int(x) for x in list('{0:07b}'.format(attenuation))]
247a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            # For endian
248a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            reverse_bits = self._AP_ATTENUATOR_RELAYS[ap_enclosure][:: -1]
249a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
250a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            # determine which bits should be set
251a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            relays_to_close = [
252a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                reverse_bits[i] for i, j in enumerate(bin_array) if not j
253a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            ]
254a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
255a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            # open all relay for attenuator & then close the ones we need
256a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            relays = ','.join(self._AP_ATTENUATOR_RELAYS[ap_enclosure])
257a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            self.open_relays(relays)
258a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            logging.debug('Attenuator relays opened: %s', relays)
259a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            relays = ','.join(relays_to_close)
260a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            self.close_relays(relays)
261a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            logging.debug('Attenuator relays closed: %s', relays)
262a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
263a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def get_ap_connections(self):
264a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Get a list of AP to client connections.
265a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
266a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns tuple of dict of connections ({'AP': 1, 'Client': 1}, ...)
267a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
268a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
269a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        # Get the closed status for relays connected to AP enclosures.
270a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        ap_connections = self.relays_closed(self._ALL_AP_RELAYS)
271a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
272a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        # Find out the connections
273a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        connections = []
274a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        for index, relay_num in enumerate(ap_connections):
275a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            # if the relay is closed, there is a connection
276a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            if relay_num:
277a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                connection = {
278a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                    'AP': (index / self._RELAYS_PER_ENCLOSURE) + 1,
279a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                    'Client': (index % self._RELAYS_PER_ENCLOSURE) + 1
280a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                }
281a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                connections.append(connection)
282a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        return tuple(connections)
283a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
284a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def get_client_connections(self):
285a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Get a list of AP to client connections.
286a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
287a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @returns tuple of dict of connections ({'AP': 1, 'Client': 1}, ...)
288a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
289a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
290a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        # Get the closed status for relays connected to client enclosures.
291a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        c_connections = self.relays_closed(self._ALL_CLIENT_RELAYS)
292a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
293a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        # Find out the connections
294a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        connections = []
295a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        for index, relay_num in enumerate(c_connections):
296a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            # if the relay is closed, there is a connection
297a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            if relay_num:
298a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                connection = {
299a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                    'AP': (index % self._RELAYS_PER_ENCLOSURE) + 1,
300a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                    'Client': (index / self._RELAYS_PER_ENCLOSURE) + 1
301a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                }
302a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                connections.append(connection)
303a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        return tuple(connections)
304a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
305a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    def connect_ap_client(self, ap, client):
306a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """Connect AP and a Client enclosure.
307a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
308a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param ap: Int 1/2/3/4 AP enclosure index
309a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @param client: Int 1/2/3/4 Client enclosure index
310a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
311a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        @raises ValueError: when ap / client value is not 1/2/3/4
312a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
313a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        """
314a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        if (ap < self._MIN_ENCLOSURE or ap > self._MAX_ENCLOSURE):
315a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            raise ValueError(
316a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                'AP enclosure should be 1/2/3/4. Given: %s' % ap)
317a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        if (client < self._MIN_ENCLOSURE or
318a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                client > self._MAX_ENCLOSURE):
319a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            raise ValueError('Client enclosure should be 1/2/3/4. Given: %s' %
320a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu                             client)
321a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
322a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        # Relay index start from 0 so subtract 1 for index
323a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        relays = 'k1_%s,k1_%s' % (
324a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            ((int(ap) - 1) * self._RELAYS_PER_ENCLOSURE) + int(client),
325a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu            (((int(client) - 1) + self._MAX_ENCLOSURE) *
326a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu             self._RELAYS_PER_ENCLOSURE) + int(ap))
327a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        logging.debug('Relays to close: %s', relays)
328a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        self.close_relays(relays)
329a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
330a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
331a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu@contextlib.contextmanager
332a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Veludef RfSwitchSession(host, port=scpi.Scpi.SCPI_PORT):
333a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    """Start a RF Switch session and close it when done.
334a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
335a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    @param host: Hostname or IP address of RF Switch
336a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    @param port: Int SCPI port number (default 5025)
337a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu
338a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    @yields: an instance of InteractiveSsh
339a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    """
340a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    session = RfSwitch(host, port)
341a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    try:
342a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        yield session
343a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu    finally:
344a6c1bff74027ad7698a174298c19dd3674adfef7Kamesh Raj Velu        session.close()
345