1#!/usr/bin/env python3
2#
3#   Copyright 2020 - 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
17import copy
18
19DEFAULT_MONSOON_CONFIG_DICT = {
20    'enabled': 1,
21    'type': 'monsooncollector',
22    'monsoon_reset': 0,
23    # maximum monsoon sample rate that works best for both lvpm and hvpm
24    'sampling_rate': 1000,
25}
26
27
28class _BitsMonsoonConfig(object):
29    """Helper object to construct a bits_service config from a monsoon config as
30    defined for the bits controller config and required additional resources,
31    such as paths to executables.
32
33    The format for the bits_service's monsoon configuration is explained at:
34    http://go/pixel-bits/user-guide/service/collectors/monsoon
35
36    Attributes:
37        config_dic: A bits_service's monsoon configuration as a python
38        dictionary.
39    """
40
41    def __init__(self, monsoon_config, lvpm_monsoon_bin=None,
42                 hvpm_monsoon_bin=None):
43        """Constructs _BitsServiceMonsoonConfig.
44
45        Args:
46            monsoon_config: The monsoon config as defined in the
47                ACTS Bits controller config. Expected format is:
48                  { 'serial_num': <serial number:int>,
49                    'monsoon_voltage': <voltage:double> }
50            lvpm_monsoon_bin: Binary file to interact with low voltage monsoons.
51                Needed if the monsoon is a lvpm monsoon (serial number lower
52                than 20000).
53            hvpm_monsoon_bin: Binary file to interact with high voltage
54                monsoons. Needed if the monsoon is a hvpm monsoon (serial number
55                greater than 20000).
56        """
57        if 'serial_num' not in monsoon_config:
58            raise ValueError(
59                'Monsoon serial_num can not be undefined. Received '
60                'config was: %s' % monsoon_config)
61        if 'monsoon_voltage' not in monsoon_config:
62            raise ValueError('Monsoon voltage can not be undefined. Received '
63                             'config was: %s' % monsoon_config)
64
65        self.serial_num = monsoon_config['serial_num']
66        self.monsoon_voltage = monsoon_config['monsoon_voltage']
67
68        self.config_dic = copy.deepcopy(DEFAULT_MONSOON_CONFIG_DICT)
69        if float(self.serial_num) >= 20000:
70            self.config_dic['hv_monsoon'] = 1
71            if hvpm_monsoon_bin is None:
72                raise ValueError('hvpm_monsoon binary is needed but was None. '
73                                 'Received config was: %s' % monsoon_config)
74            self.monsoon_binary = hvpm_monsoon_bin
75        else:
76            self.config_dic['hv_monsoon'] = 0
77            if lvpm_monsoon_bin is None:
78                raise ValueError('lvpm_monsoon binary is needed but was None. '
79                                 'Received config was: %s' % monsoon_config)
80            self.monsoon_binary = lvpm_monsoon_bin
81
82        self.config_dic['monsoon_binary_path'] = self.monsoon_binary
83        self.config_dic['monsoon_voltage'] = self.monsoon_voltage
84        self.config_dic['serial_num'] = self.serial_num
85
86
87DEFAULT_KIBBLES_BOARD_CONFIG = {
88    'enabled': 1,
89    'type': 'kibblecollector',
90    'attached_kibbles': {}
91}
92
93DEFAULT_KIBBLE_CONFIG = {
94    'ultra_channels_current_hz': 976.5625,
95    'ultra_channels_voltage_hz': 976.5625,
96    'high_channels_current_hz': 976.5625,
97    'high_channels_voltage_hz': 976.5625
98}
99
100
101class _BitsKibblesConfig(object):
102    def __init__(self, kibbles_config, kibble_bin, kibble_board_file):
103        """Constructs _BitsKibblesConfig.
104
105        Args:
106            kibbles_config: A list of compacted kibble boards descriptions.
107                Expected format is:
108                    [{
109                        'board': 'BoardName1',
110                        'connector': 'A',
111                        'serial': 'serial_1'
112                     },
113                    {
114                        'board': 'BoardName2',
115                        'connector': 'D',
116                        'serial': 'serial_2'
117                    }]
118                More details can be found at go/acts-bits.
119            kibble_bin: Binary file to interact with kibbles.
120            kibble_board_file: File describing the distribution of rails on a
121                kibble. go/kibble#setting-up-bits-board-files
122        """
123
124        if not isinstance(kibbles_config, list):
125            raise ValueError(
126                'kibbles_config must be a list. Got %s.' % kibbles_config)
127
128        if kibble_bin is None:
129            raise ValueError('Kibbles were present in the config but no '
130                             'kibble_bin was provided')
131        if kibble_board_file is None:
132            raise ValueError('Kibbles were present in the config but no '
133                             'kibble_board_file was provided')
134
135        self.boards_configs = {}
136
137        for kibble in kibbles_config:
138            if 'board' not in kibble:
139                raise ValueError('An individual kibble config must have a '
140                                 'board')
141            if 'connector' not in kibble:
142                raise ValueError('An individual kibble config must have a '
143                                 'connector')
144            if 'serial' not in kibble:
145                raise ValueError('An individual kibble config must have a '
146                                 'serial')
147
148            board = kibble['board']
149            connector = kibble['connector']
150            serial = kibble['serial']
151            if board not in self.boards_configs:
152                self.boards_configs[board] = copy.deepcopy(
153                    DEFAULT_KIBBLES_BOARD_CONFIG)
154                self.boards_configs[board][
155                    'board_file'] = kibble_board_file
156                self.boards_configs[board]['kibble_py'] = kibble_bin
157            kibble_config = copy.deepcopy(DEFAULT_KIBBLE_CONFIG)
158            kibble_config['connector'] = connector
159            self.boards_configs[board]['attached_kibbles'][
160                serial] = kibble_config
161
162
163DEFAULT_SERVICE_CONFIG_DICT = {
164    'devices': {
165        'default_device': {
166            'enabled': 1,
167            'collectors': {}
168        }
169    }
170}
171
172
173class BitsServiceConfig(object):
174    """Helper object to construct a bits_service config from a bits controller
175    config and required additional resources, such as paths to executables.
176
177    The format for bits_service's configuration is explained in:
178    go/pixel-bits/user-guide/service/configuration.md
179
180    Attributes:
181        config_dic: A bits_service configuration as a python dictionary.
182    """
183
184    def __init__(self, controller_config, lvpm_monsoon_bin=None,
185                 hvpm_monsoon_bin=None, kibble_bin=None,
186                 kibble_board_file=None, virtual_metrics_file=None):
187        """Creates a BitsServiceConfig.
188
189        Args:
190            controller_config: The config as defined in the ACTS  BiTS
191                controller config. Expected format is:
192                {
193                    // optional
194                    'Monsoon':   {
195                        'serial_num': <serial number:int>,
196                        'monsoon_voltage': <voltage:double>
197                    }
198                    // optional
199                    'Kibble': [
200                        {
201                            'board': 'BoardName1',
202                            'connector': 'A',
203                            'serial': 'serial_1'
204                        },
205                        {
206                            'board': 'BoardName2',
207                            'connector': 'D',
208                            'serial': 'serial_2'
209                        }
210                    ]
211                }
212            lvpm_monsoon_bin: Binary file to interact with low voltage monsoons.
213                Needed if the monsoon is a lvpm monsoon (serial number lower
214                than 20000).
215            hvpm_monsoon_bin: Binary file to interact with high voltage
216                monsoons. Needed if the monsoon is a hvpm monsoon (serial number
217                greater than 20000).
218            kibble_bin: Binary file to interact with kibbles.
219            kibble_board_file: File describing the distribution of rails on a
220                kibble. go/kibble#setting-up-bits-board-files
221            virtual_metrics_file: A list of virtual metrics files to add
222                data aggregates on top of regular channel aggregates.
223                go/pixel-bits/user-guide/virtual-metrics
224        """
225        self.config_dic = copy.deepcopy(DEFAULT_SERVICE_CONFIG_DICT)
226        self.has_monsoon = False
227        self.has_kibbles = False
228        self.has_virtual_metrics_file = False
229        self.monsoon_config = None
230        self.kibbles_config = None
231        if 'Monsoon' in controller_config:
232            self.has_monsoon = True
233            self.monsoon_config = _BitsMonsoonConfig(
234                controller_config['Monsoon'],
235                lvpm_monsoon_bin,
236                hvpm_monsoon_bin)
237            self.config_dic['devices']['default_device']['collectors'][
238                'Monsoon'] = self.monsoon_config.config_dic
239        if 'Kibbles' in controller_config:
240            self.has_kibbles = True
241            self.kibbles_config = _BitsKibblesConfig(
242                controller_config['Kibbles'],
243                kibble_bin, kibble_board_file)
244            self.config_dic['devices']['default_device']['collectors'].update(
245                self.kibbles_config.boards_configs)
246            if virtual_metrics_file is not None:
247                self.config_dic['devices']['default_device'][
248                    'vm_files'] = [virtual_metrics_file]
249                self.has_virtual_metrics_file = True
250