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 = int(monsoon_config['serial_num'])
66        self.monsoon_voltage = float(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            if 'subkibble_params' in kibble:
148                user_defined_kibble_config = kibble['subkibble_params']
149                kibble_config = copy.deepcopy(user_defined_kibble_config)
150            else:
151                kibble_config = copy.deepcopy(DEFAULT_KIBBLE_CONFIG)
152            board = kibble['board']
153            connector = kibble['connector']
154            serial = kibble['serial']
155            if board not in self.boards_configs:
156                self.boards_configs[board] = copy.deepcopy(
157                    DEFAULT_KIBBLES_BOARD_CONFIG)
158                self.boards_configs[board][
159                    'board_file'] = kibble_board_file
160                self.boards_configs[board]['kibble_py'] = kibble_bin
161            kibble_config['connector'] = connector
162            self.boards_configs[board]['attached_kibbles'][
163                serial] = kibble_config
164
165
166DEFAULT_SERVICE_CONFIG_DICT = {
167    'devices': {
168        'default_device': {
169            'enabled': 1,
170            'collectors': {}
171        }
172    }
173}
174
175
176class BitsServiceConfig(object):
177    """Helper object to construct a bits_service config from a bits controller
178    config and required additional resources, such as paths to executables.
179
180    The format for bits_service's configuration is explained in:
181    go/pixel-bits/user-guide/service/configuration.md
182
183    Attributes:
184        config_dic: A bits_service configuration as a python dictionary.
185    """
186
187    def __init__(self, controller_config, lvpm_monsoon_bin=None,
188                 hvpm_monsoon_bin=None, kibble_bin=None,
189                 kibble_board_file=None, virtual_metrics_file=None):
190        """Creates a BitsServiceConfig.
191
192        Args:
193            controller_config: The config as defined in the ACTS  BiTS
194                controller config. Expected format is:
195                {
196                    // optional
197                    'Monsoon':   {
198                        'serial_num': <serial number:int>,
199                        'monsoon_voltage': <voltage:double>
200                    }
201                    // optional
202                    'Kibble': [
203                        {
204                            'board': 'BoardName1',
205                            'connector': 'A',
206                            'serial': 'serial_1'
207                        },
208                        {
209                            'board': 'BoardName2',
210                            'connector': 'D',
211                            'serial': 'serial_2'
212                        }
213                    ]
214                }
215            lvpm_monsoon_bin: Binary file to interact with low voltage monsoons.
216                Needed if the monsoon is a lvpm monsoon (serial number lower
217                than 20000).
218            hvpm_monsoon_bin: Binary file to interact with high voltage
219                monsoons. Needed if the monsoon is a hvpm monsoon (serial number
220                greater than 20000).
221            kibble_bin: Binary file to interact with kibbles.
222            kibble_board_file: File describing the distribution of rails on a
223                kibble. go/kibble#setting-up-bits-board-files
224            virtual_metrics_file: A list of virtual metrics files to add
225                data aggregates on top of regular channel aggregates.
226                go/pixel-bits/user-guide/virtual-metrics
227        """
228        self.config_dic = copy.deepcopy(DEFAULT_SERVICE_CONFIG_DICT)
229        self.has_monsoon = False
230        self.has_kibbles = False
231        self.has_virtual_metrics_file = False
232        self.monsoon_config = None
233        self.kibbles_config = None
234        if 'Monsoon' in controller_config:
235            self.has_monsoon = True
236            self.monsoon_config = _BitsMonsoonConfig(
237                controller_config['Monsoon'],
238                lvpm_monsoon_bin,
239                hvpm_monsoon_bin)
240            self.config_dic['devices']['default_device']['collectors'][
241                'Monsoon'] = self.monsoon_config.config_dic
242        if 'Kibbles' in controller_config:
243            self.has_kibbles = True
244            self.kibbles_config = _BitsKibblesConfig(
245                controller_config['Kibbles'],
246                kibble_bin, kibble_board_file)
247            self.config_dic['devices']['default_device']['collectors'].update(
248                self.kibbles_config.boards_configs)
249            if virtual_metrics_file is not None:
250                self.config_dic['devices']['default_device'][
251                    'vm_files'] = [virtual_metrics_file]
252                self.has_virtual_metrics_file = True
253