blob: 762140a93ca43a7894ccb6fe9427ac89bfb9833b [file] [log] [blame]
David Burger7fd1dbe2020-03-26 09:26:55 -06001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright 2020 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""Transforms config from /config/proto/api proto format to platform JSON."""
7
Ren-Pei Zengce869dd2020-08-18 01:29:37 +08008# pylint: disable=too-many-lines
9
David Burger7fd1dbe2020-03-26 09:26:55 -060010import argparse
11import json
12import pprint
C Shapiro90fda252020-04-17 14:34:57 -050013import os
David Burger7fd1dbe2020-03-26 09:26:55 -060014import sys
C Shapiro90fda252020-04-17 14:34:57 -050015import re
David Burger7fd1dbe2020-03-26 09:26:55 -060016
Andrew Lamb319cc922020-06-15 10:45:46 -060017from typing import List
18
David Burger7fd1dbe2020-03-26 09:26:55 -060019from collections import namedtuple
20
Andrew Lambcd33f702020-06-11 10:45:16 -060021from google.protobuf import json_format
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080022from lxml import etree
Andrew Lambcd33f702020-06-11 10:45:16 -060023
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070024from chromiumos.config.api import device_brand_pb2
David Burger92609a32020-04-23 10:38:50 -060025from chromiumos.config.api import topology_pb2
C Shapiro5bf23a72020-04-24 11:40:17 -050026from chromiumos.config.payload import config_bundle_pb2
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070027from chromiumos.config.api.software import brand_config_pb2
David Burger7fd1dbe2020-03-26 09:26:55 -060028
Andrew Lamb2413c982020-05-29 12:15:36 -060029Config = namedtuple('Config', [
30 'program', 'hw_design', 'odm', 'hw_design_config', 'device_brand',
C Shapirod5545f12020-11-30 16:37:04 -060031 'device_signer_config', 'oem', 'sw_config', 'brand_config'
Andrew Lamb2413c982020-05-29 12:15:36 -060032])
David Burger7fd1dbe2020-03-26 09:26:55 -060033
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080034ConfigFiles = namedtuple('ConfigFiles', [
35 'arc_hw_features', 'arc_media_profiles', 'touch_fw', 'dptf_map',
36 'camera_map', 'wifi_sar_map'
37])
David Burger8ee9b4d2020-06-16 17:40:21 -060038
39CAMERA_CONFIG_DEST_PATH_TEMPLATE = '/etc/camera/camera_config_{}.json'
40CAMERA_CONFIG_SOURCE_PATH_TEMPLATE = (
41 'sw_build_config/platform/chromeos-config/camera/camera_config_{}.json')
C Shapiro5bf23a72020-04-24 11:40:17 -050042
David Burger52c9d322020-06-09 07:16:18 -060043DPTF_PATH = 'sw_build_config/platform/chromeos-config/thermal'
44DPTF_FILE = 'dptf.dv'
David Burger2f0d9522020-07-30 10:52:28 -060045
C Shapiro2b6d5332020-05-06 17:51:35 -050046TOUCH_PATH = 'sw_build_config/platform/chromeos-config/touch'
Andrew Lamb6c42efc2020-06-16 10:40:43 -060047WALLPAPER_BASE_PATH = '/usr/share/chromeos-assets/wallpaper'
David Burger7fd1dbe2020-03-26 09:26:55 -060048
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080049XML_DECLARATION = b'<?xml version="1.0" encoding="utf-8"?>\n'
50
Andrew Lamb2413c982020-05-29 12:15:36 -060051
Andrew Lambcd33f702020-06-11 10:45:16 -060052def parse_args(argv):
David Burger7fd1dbe2020-03-26 09:26:55 -060053 """Parse the available arguments.
54
55 Invalid arguments or -h cause this function to print a message and exit.
56
57 Args:
58 argv: List of string arguments (excluding program name / argv[0])
59
60 Returns:
61 argparse.Namespace object containing the attributes.
62 """
63 parser = argparse.ArgumentParser(
64 description='Converts source proto config into platform JSON config.')
65 parser.add_argument(
66 '-c',
67 '--project_configs',
68 nargs='+',
69 type=str,
70 help='Space delimited list of source protobinary project config files.')
71 parser.add_argument(
72 '-p',
73 '--program_config',
74 type=str,
75 help='Path to the source program-level protobinary file')
76 parser.add_argument(
Andrew Lamb2413c982020-05-29 12:15:36 -060077 '-o', '--output', type=str, help='Output file that will be generated')
David Burger7fd1dbe2020-03-26 09:26:55 -060078 return parser.parse_args(argv)
79
80
David Burger8ee9b4d2020-06-16 17:40:21 -060081def _upsert(field, target, target_name):
82 """Updates or inserts `field` within `target`.
83
84 If `target_name` already exists within `target` an update is performed,
85 otherwise, an insert is performed.
86 """
Sam McNally9a873f72020-06-05 19:47:22 +100087 if field or field == 0:
David Burger8ee9b4d2020-06-16 17:40:21 -060088 if target_name in target:
89 target[target_name].update(field)
90 else:
91 target[target_name] = field
David Burger7fd1dbe2020-03-26 09:26:55 -060092
93
Andrew Lambcd33f702020-06-11 10:45:16 -060094def _build_arc(config, config_files):
Andrew Lambcd33f702020-06-11 10:45:16 -060095 build_properties = {
C Shapirod5545f12020-11-30 16:37:04 -060096 # TODO(chromium:1126527) - Push this into the overlay itself.
97 # This isn't/can't be device specific and shouldn't be configured as such.
98 'device': "%s_cheets" % config.program.name.lower(),
99 'first-api-level': '28',
Andrew Lambcd33f702020-06-11 10:45:16 -0600100 'marketing-name': config.device_brand.brand_name,
101 'metrics-tag': config.hw_design.name.lower(),
C Shapirod5545f12020-11-30 16:37:04 -0600102 'product': config.program.name.lower(),
Andrew Lambcd33f702020-06-11 10:45:16 -0600103 }
104 if config.oem:
105 build_properties['oem'] = config.oem.name
106 result = {'build-properties': build_properties}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800107 config_id = _get_formatted_config_id(config.hw_design_config)
108 if config_id in config_files.arc_hw_features:
109 result['hardware-features'] = config_files.arc_hw_features[config_id]
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800110 if config_id in config_files.arc_media_profiles:
111 result['media-profiles'] = config_files.arc_media_profiles[config_id]
Andrew Lambcd33f702020-06-11 10:45:16 -0600112 topology = config.hw_design_config.hardware_topology
113 ppi = topology.screen.hardware_feature.screen.panel_properties.pixels_per_in
114 # Only set for high resolution displays
115 if ppi and ppi > 250:
116 result['scale'] = ppi
David Burger2f0d9522020-07-30 10:52:28 -0600117
Andrew Lambcd33f702020-06-11 10:45:16 -0600118 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600119
Andrew Lamb2413c982020-05-29 12:15:36 -0600120
Andrew Lamb319cc922020-06-15 10:45:46 -0600121def _build_ash_flags(config: Config) -> List[str]:
122 """Returns a list of Ash flags for config.
123
124 Ash is the window manager and system UI for ChromeOS, see
125 https://chromium.googlesource.com/chromium/src/+/refs/heads/master/ash/.
126 """
127 # A map from flag name -> value. Value may be None for boolean flags.
128 flags = {}
129
130 hw_features = config.hw_design_config.hardware_features
131 if hw_features.stylus.stylus == topology_pb2.HardwareFeatures.Stylus.INTERNAL:
Andrew Lamb2e641e22020-06-15 12:30:41 -0600132 flags['has-internal-stylus'] = None
Andrew Lamb319cc922020-06-15 10:45:46 -0600133
Andrew Lamb2e641e22020-06-15 12:30:41 -0600134 fp_loc = hw_features.fingerprint.location
135 if fp_loc and fp_loc != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
136 loc_name = topology_pb2.HardwareFeatures.Fingerprint.Location.Name(fp_loc)
137 flags['fingerprint-sensor-location'] = loc_name.lower().replace('_', '-')
138
Andrew Lamb6c42efc2020-06-16 10:40:43 -0600139 wallpaper = config.brand_config.wallpaper
140 # If a wallpaper is set, the 'default-wallpaper-is-oem' flag needs to be set.
141 # If a wallpaper is not set, the 'default_[large|small].jpg' wallpapers
142 # should still be set.
143 if wallpaper:
144 flags['default-wallpaper-is-oem'] = None
145 else:
146 wallpaper = 'default'
147
148 for size in ('small', 'large'):
149 flags[f'default-wallpaper-{size}'] = (
150 f'{WALLPAPER_BASE_PATH}/{wallpaper}_{size}.jpg')
151
152 # For each size, also install 'guest' and 'child' wallpapers.
153 for wallpaper_type in ('guest', 'child'):
154 flags[f'{wallpaper_type}-wallpaper-{size}'] = (
155 f'{WALLPAPER_BASE_PATH}/{wallpaper_type}_{size}.jpg')
156
C Shapiro2e97aad2020-11-16 11:58:10 -0600157 regulatory_label = config.brand_config.regulatory_label
158 if regulatory_label:
159 flags['regulatory-label-dir'] = (regulatory_label)
160
C Shapirod5545f12020-11-30 16:37:04 -0600161 flags['arc-build-properties'] = {
162 'device': "%s_cheets" % config.program.name.lower(),
163 'firstApiLevel': '28',
164 }
Andrew Lamb72d41362020-06-17 09:19:02 -0600165
Andrew Lamb90b168c2020-06-22 10:42:30 -0600166 power_button = hw_features.power_button
167 if power_button.edge:
168 flags['ash-power-button-position'] = json.dumps({
169 'edge':
170 topology_pb2.HardwareFeatures.Button.Edge.Name(power_button.edge
171 ).lower(),
172 # Starlark sometimes represents float literals strangely, e.g. changing
173 # 0.9 to 0.899999. Round to two digits here.
174 'position':
175 round(power_button.position, 2)
176 })
177
178 volume_button = hw_features.volume_button
179 if volume_button.edge:
180 flags['ash-side-volume-button-position'] = json.dumps({
181 'region':
182 topology_pb2.HardwareFeatures.Button.Region.Name(
183 volume_button.region).lower(),
Sam McNallye1f77422021-04-20 21:08:24 +1000184 'side':
Andrew Lamb90b168c2020-06-22 10:42:30 -0600185 topology_pb2.HardwareFeatures.Button.Edge.Name(volume_button.edge
186 ).lower(),
187 })
188
Nikolai Artemievda87d992020-12-04 15:09:00 +1100189 form_factor = hw_features.form_factor.form_factor
190 lid_accel = hw_features.accelerometer.lid_accelerometer
191 if (form_factor == topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE and
192 lid_accel == topology_pb2.HardwareFeatures.PRESENT):
Nikolai Artemiev03de0e02021-03-23 17:46:49 +1100193 flags['supports-clamshell-auto-rotation'] = None
Nikolai Artemievda87d992020-12-04 15:09:00 +1100194
Tim Sergeant7a022462021-04-07 20:23:32 +1000195 if config.sw_config.ui_config.extra_web_apps_dir:
196 flags['extra-web-apps-dir'] = config.sw_config.ui_config.extra_web_apps_dir
197
Andrew Lamb2e641e22020-06-15 12:30:41 -0600198 return sorted([f'--{k}={v}' if v else f'--{k}' for k, v in flags.items()])
Andrew Lamb319cc922020-06-15 10:45:46 -0600199
200
201def _build_ui(config: Config) -> dict:
202 """Builds the 'ui' property from cros_config_schema."""
203 return {'extra-ash-flags': _build_ash_flags(config)}
204
205
David Burger07af5242020-08-11 11:08:25 -0600206def _build_bluetooth(config):
C Shapiro90fda252020-04-17 14:34:57 -0500207 bt_flags = config.sw_config.bluetooth_config.flags
208 # Convert to native map (from proto wrapper)
209 bt_flags_map = dict(bt_flags)
210 result = {}
211 if bt_flags_map:
212 result['flags'] = bt_flags_map
C Shapiro90fda252020-04-17 14:34:57 -0500213 return result
214
David Burger7fd1dbe2020-03-26 09:26:55 -0600215
David Burgerceeb68a2020-09-03 11:31:10 -0600216def _build_ath10k_config(ath10k_config):
217 """Builds the wifi configuration for the ath10k driver.
218
219 Args:
220 ath10k_config: Ath10kConfig config.
221
222 Returns:
223 wifi configuration for the ath10k driver.
224 """
David Burgerec753912020-08-10 12:59:11 -0600225 result = {}
David Burgerec753912020-08-10 12:59:11 -0600226
David Burgerceeb68a2020-09-03 11:31:10 -0600227 def power_chain(power):
228 return {
229 'limit-2g': power.limit_2g,
230 'limit-5g': power.limit_5g,
231 }
David Burgerec753912020-08-10 12:59:11 -0600232
David Burgerceeb68a2020-09-03 11:31:10 -0600233 result['tablet-mode-power-table-ath10k'] = power_chain(
234 ath10k_config.tablet_mode_power_table)
235 result['non-tablet-mode-power-table-ath10k'] = power_chain(
236 ath10k_config.non_tablet_mode_power_table)
David Burgerec753912020-08-10 12:59:11 -0600237 return result
238
239
David Burgerceeb68a2020-09-03 11:31:10 -0600240def _build_rtw88_config(rtw88_config):
241 """Builds the wifi configuration for the rtw88 driver.
242
243 Args:
244 rtw88_config: Rtw88Config config.
245
246 Returns:
247 wifi configuration for the rtw88 driver.
248 """
249 result = {}
250
251 def power_chain(power):
252 return {
253 'limit-2g': power.limit_2g,
254 'limit-5g-1': power.limit_5g_1,
255 'limit-5g-3': power.limit_5g_3,
256 'limit-5g-4': power.limit_5g_4,
257 }
258
259 result['tablet-mode-power-table-rtw'] = power_chain(
260 rtw88_config.tablet_mode_power_table)
261 result['non-tablet-mode-power-table-rtw'] = power_chain(
262 rtw88_config.non_tablet_mode_power_table)
263
264 def offsets(offset):
265 return {
266 'offset-2g': offset.offset_2g,
267 'offset-5g': offset.offset_5g,
268 }
269
270 result['geo-offsets-fcc'] = offsets(rtw88_config.offset_fcc)
271 result['geo-offsets-eu'] = offsets(rtw88_config.offset_eu)
272 result['geo-offsets-rest-of-world'] = offsets(rtw88_config.offset_other)
273 return result
274
275
276def _build_intel_config(config, config_files):
277 """Builds the wifi configuration for the intel driver.
278
279 Args:
280 config: Config namedtuple
281 config_files: Map to look up the generated config files.
282
283 Returns:
284 wifi configuration for the intel driver.
285 """
286 design_name = config.hw_design.name.lower()
287 return config_files.wifi_sar_map.get(design_name)
288
289
290def _build_wifi(config, config_files):
291 """Builds the wifi configuration.
292
293 Args:
294 config: Config namedtuple
295 config_files: Map to look up the generated config files.
296
297 Returns:
298 wifi configuration.
299 """
300 config_field = config.sw_config.wifi_config.WhichOneof('wifi_config')
301 if config_field == 'ath10k_config':
302 return _build_ath10k_config(config.sw_config.wifi_config.ath10k_config)
303 if config_field == 'rtw88_config':
304 return _build_rtw88_config(config.sw_config.wifi_config.rtw88_config)
305 if config_field == 'intel_config':
306 return _build_intel_config(config, config_files)
307 return {}
308
309
Andrew Lambcd33f702020-06-11 10:45:16 -0600310def _build_fingerprint(hw_topology):
311 if not hw_topology.HasField('fingerprint'):
312 return None
313
314 fp = hw_topology.fingerprint.hardware_feature.fingerprint
315 result = {}
316 if fp.location != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
317 location = fp.Location.DESCRIPTOR.values_by_number[fp.location].name
318 result['sensor-location'] = location.lower().replace('_', '-')
319 if fp.board:
320 result['board'] = fp.board
Tom Hughesdfc35402020-06-29 16:02:09 -0700321 if fp.ro_version:
322 result['ro-version'] = fp.ro_version
323
Andrew Lambcd33f702020-06-11 10:45:16 -0600324 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600325
326
Trent Beginf067ccb2020-08-12 12:33:53 -0600327def _build_hardware_properties(hw_topology):
328 if not hw_topology.HasField('form_factor'):
329 return None
330
331 form_factor = hw_topology.form_factor.hardware_feature.form_factor.form_factor
332 result = {}
333 if form_factor in [
334 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
335 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE,
336 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
337 ]:
338 result['psu-type'] = "AC_only"
339 else:
340 result['psu-type'] = "battery"
341
342 result['has-backlight'] = form_factor not in [
343 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
344 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
345 ]
346
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100347 form_factor_names = {
Nikolai Artemievaf103a32021-02-15 14:37:16 +1100348 topology_pb2.HardwareFeatures.FormFactor.CLAMSHELL: "CHROMEBOOK",
349 topology_pb2.HardwareFeatures.FormFactor.CONVERTIBLE: "CHROMEBOOK",
350 topology_pb2.HardwareFeatures.FormFactor.DETACHABLE: "CHROMEBOOK",
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100351 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE: "CHROMEBASE",
Nikolai Artemievaf103a32021-02-15 14:37:16 +1100352 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX: "CHROMEBOX",
353 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT: "CHROMEBIT",
354 topology_pb2.HardwareFeatures.FormFactor.CHROMESLATE: "CHROMEBOOK",
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100355 }
356 if form_factor in form_factor_names:
357 result['form-factor'] = form_factor_names[form_factor]
358
Trent Beginf067ccb2020-08-12 12:33:53 -0600359 return result
360
361
Andrew Lambcd33f702020-06-11 10:45:16 -0600362def _fw_bcs_path(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600363 if payload and payload.firmware_image_name:
YH Lin873742a2021-03-02 07:02:31 -0800364 return 'bcs://%s.%d.%d.%d.tbz2' % (
365 payload.firmware_image_name, payload.version.major,
366 payload.version.minor, payload.version.patch)
David Burger7fd1dbe2020-03-26 09:26:55 -0600367
Andrew Lambcd33f702020-06-11 10:45:16 -0600368 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600369
Andrew Lambcd33f702020-06-11 10:45:16 -0600370
371def _fw_build_target(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600372 if payload:
373 return payload.build_target_name
374
Andrew Lambcd33f702020-06-11 10:45:16 -0600375 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600376
Andrew Lambcd33f702020-06-11 10:45:16 -0600377
378def _build_firmware(config):
David Burgerb70b6762020-05-21 12:14:59 -0600379 """Returns firmware config, or None if no build targets."""
Andrew Lamb3da156d2020-04-16 16:00:56 -0600380 fw_payload_config = config.sw_config.firmware
381 fw_build_config = config.sw_config.firmware_build_config
382 main_ro = fw_payload_config.main_ro_payload
383 main_rw = fw_payload_config.main_rw_payload
384 ec_ro = fw_payload_config.ec_ro_payload
385 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600386
387 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600388
David Burger8ee9b4d2020-06-16 17:40:21 -0600389 _upsert(fw_build_config.build_targets.depthcharge, build_targets,
390 'depthcharge')
391 _upsert(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
392 _upsert(fw_build_config.build_targets.ec, build_targets, 'ec')
393 _upsert(
Andrew Lambf8954ee2020-04-21 10:24:40 -0600394 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
David Burger8ee9b4d2020-06-16 17:40:21 -0600395 _upsert(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
YH Lind4809502021-04-06 13:46:40 -0700396 _upsert(fw_build_config.build_targets.zephyr_ec, build_targets, 'zephyr-ec')
David Burger7fd1dbe2020-03-26 09:26:55 -0600397
David Burgerb70b6762020-05-21 12:14:59 -0600398 if not build_targets:
399 return None
400
David Burger7fd1dbe2020-03-26 09:26:55 -0600401 result = {
C Shapirod5545f12020-11-30 16:37:04 -0600402 'bcs-overlay': 'overlay-%s-private' % config.program.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600403 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600404 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600405
David Burger8ee9b4d2020-06-16 17:40:21 -0600406 _upsert(main_ro.firmware_image_name.lower(), result, 'image-name')
Andrew Lamb883fa042020-04-06 11:37:22 -0600407
David Burger8ee9b4d2020-06-16 17:40:21 -0600408 _upsert(_fw_bcs_path(main_ro), result, 'main-ro-image')
409 _upsert(_fw_bcs_path(main_rw), result, 'main-rw-image')
410 _upsert(_fw_bcs_path(ec_ro), result, 'ec-ro-image')
411 _upsert(_fw_bcs_path(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600412
David Burger8ee9b4d2020-06-16 17:40:21 -0600413 _upsert(
Andrew Lambf39fbe82020-04-13 16:14:33 -0600414 config.hw_design_config.hardware_features.fw_config.value,
415 result,
416 'firmware-config',
417 )
418
David Burger7fd1dbe2020-03-26 09:26:55 -0600419 return result
420
421
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000422def _build_fw_signing(config, whitelabel):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500423 if config.sw_config.firmware and config.device_signer_config:
David Burger68e0d142020-05-15 17:29:33 -0600424 hw_design = config.hw_design.name.lower()
Sam McNally2fc807f2020-07-16 18:13:53 +1000425 brand_scan_config = config.brand_config.scan_config
426 if brand_scan_config and brand_scan_config.whitelabel_tag:
427 signature_id = '%s-%s' % (hw_design, brand_scan_config.whitelabel_tag)
428 else:
429 signature_id = hw_design
430
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000431 result = {
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500432 'key-id': config.device_signer_config.key_id,
Sam McNally2fc807f2020-07-16 18:13:53 +1000433 'signature-id': signature_id,
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500434 }
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000435 if whitelabel:
436 result['sig-id-in-customization-id'] = True
437 return result
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500438 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600439
440
Andrew Lambcd33f702020-06-11 10:45:16 -0600441def _file(source, destination):
Andrew Lamb2413c982020-05-29 12:15:36 -0600442 return {'destination': destination, 'source': source}
David Burger7fd1dbe2020-03-26 09:26:55 -0600443
444
David Burger40dfe3a2020-06-18 17:09:13 -0600445def _file_v2(build_path, system_path):
446 return {'build-path': build_path, 'system-path': system_path}
447
448
Andrew Lambcd33f702020-06-11 10:45:16 -0600449def _build_audio(config):
David Burger178f3ef2020-06-26 12:11:57 -0600450 if not config.sw_config.audio_configs:
451 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600452 alsa_path = '/usr/share/alsa/ucm'
453 cras_path = '/etc/cras'
Judy Hsiao1ae95122020-12-23 15:39:50 +0800454 sound_card_init_path = '/etc/sound_card_init'
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800455 design_name = config.hw_design.name.lower()
David Burger43250662020-05-07 11:21:50 -0600456 program_name = config.program.name.lower()
David Burger7fd1dbe2020-03-26 09:26:55 -0600457 files = []
David Burger178f3ef2020-06-26 12:11:57 -0600458 ucm_suffix = None
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800459 sound_card_init_conf = None
460
David Burger178f3ef2020-06-26 12:11:57 -0600461 for audio in config.sw_config.audio_configs:
462 card = audio.card_name
463 card_with_suffix = audio.card_name
464 if audio.ucm_suffix:
465 # TODO: last ucm_suffix wins.
466 ucm_suffix = audio.ucm_suffix
467 card_with_suffix += '.' + audio.ucm_suffix
468 if audio.ucm_file:
469 files.append(
470 _file(audio.ucm_file,
471 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
472 if audio.ucm_master_file:
473 files.append(
474 _file(
475 audio.ucm_master_file, '%s/%s/%s.conf' %
Andrew Lamb2413c982020-05-29 12:15:36 -0600476 (alsa_path, card_with_suffix, card_with_suffix)))
David Burger178f3ef2020-06-26 12:11:57 -0600477 if audio.card_config_file:
478 files.append(
479 _file(audio.card_config_file,
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800480 '%s/%s/%s' % (cras_path, design_name, card)))
David Burger178f3ef2020-06-26 12:11:57 -0600481 if audio.dsp_file:
482 files.append(
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800483 _file(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, design_name)))
David Burger178f3ef2020-06-26 12:11:57 -0600484 if audio.module_file:
485 files.append(
486 _file(audio.module_file,
487 '/etc/modprobe.d/alsa-%s.conf' % program_name))
488 if audio.board_file:
489 files.append(
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800490 _file(audio.board_file, '%s/%s/board.ini' % (cras_path, design_name)))
Judy Hsiao1ae95122020-12-23 15:39:50 +0800491 if audio.sound_card_init_file:
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800492 sound_card_init_conf = design_name + ".yaml"
Judy Hsiao1ae95122020-12-23 15:39:50 +0800493 files.append(
494 _file(audio.sound_card_init_file,
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800495 '%s/%s.yaml' % (sound_card_init_path, design_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600496
497 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600498 'main': {
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800499 'cras-config-dir': design_name,
David Burger7fd1dbe2020-03-26 09:26:55 -0600500 'files': files,
501 }
502 }
David Burger178f3ef2020-06-26 12:11:57 -0600503
504 if ucm_suffix:
505 result['main']['ucm-suffix'] = ucm_suffix
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800506 if sound_card_init_conf:
507 result['main']['sound-card-init-conf'] = sound_card_init_conf
David Burger599ff7b2020-04-06 16:29:31 -0600508
509 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600510
511
Andrew Lambcd33f702020-06-11 10:45:16 -0600512def _build_camera(hw_topology):
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800513 camera_pb = topology_pb2.HardwareFeatures.Camera
514 camera = hw_topology.camera.hardware_feature.camera
515 result = {'count': len(camera.devices)}
516 if camera.devices:
517 result['devices'] = []
518 for device in camera.devices:
519 interface = {
520 camera_pb.INTERFACE_USB: 'usb',
521 camera_pb.INTERFACE_MIPI: 'mipi',
522 }[device.interface]
523 facing = {
524 camera_pb.FACING_FRONT: 'front',
525 camera_pb.FACING_BACK: 'back',
526 }[device.facing]
527 orientation = {
528 camera_pb.ORIENTATION_0: 0,
529 camera_pb.ORIENTATION_90: 90,
530 camera_pb.ORIENTATION_180: 180,
531 camera_pb.ORIENTATION_270: 270,
532 }[device.orientation]
533 flags = {
534 'support-1080p':
535 bool(device.flags & camera_pb.FLAGS_SUPPORT_1080P),
536 'support-autofocus':
537 bool(device.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS),
538 }
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100539 dev = {
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800540 'interface': interface,
541 'facing': facing,
542 'orientation': orientation,
543 'flags': flags,
544 'ids': list(device.ids),
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100545 }
546 if device.privacy_switch != topology_pb2.HardwareFeatures.PRESENT_UNKNOWN:
547 dev['has-privacy-switch'] = device.privacy_switch == topology_pb2.HardwareFeatures.PRESENT
548 result['devices'].append(dev)
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800549 return result
David Burger8aa8fa32020-04-14 08:30:34 -0600550
Andrew Lambcd33f702020-06-11 10:45:16 -0600551
552def _build_identity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600553 identity = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600554 _upsert(hw_scan_config.firmware_sku, identity, 'sku-id')
555 _upsert(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600556 # 'platform-name' is needed to support 'mosys platform name'. Clients should
Sean McAllister0b757772020-11-13 12:22:36 -0700557 # no longer require platform name, but set it here for backwards compatibility.
558 if program.mosys_platform_name:
559 _upsert(program.mosys_platform_name, identity, 'platform-name')
560 else:
561 _upsert(program.name, identity, 'platform-name')
562
David Burger7fd1dbe2020-03-26 09:26:55 -0600563 # ARM architecture
David Burger8ee9b4d2020-06-16 17:40:21 -0600564 _upsert(hw_scan_config.device_tree_compatible_match, identity,
565 'device-tree-compatible-match')
David Burger7fd1dbe2020-03-26 09:26:55 -0600566
567 if brand_scan_config:
David Burger8ee9b4d2020-06-16 17:40:21 -0600568 _upsert(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
David Burger7fd1dbe2020-03-26 09:26:55 -0600569
570 return identity
571
572
Andrew Lambcd33f702020-06-11 10:45:16 -0600573def _lookup(id_value, id_map):
574 if not id_value.value:
575 return None
576
577 key = id_value.value
578 if key in id_map:
579 return id_map[id_value.value]
580 error = 'Failed to lookup %s with value: %s' % (
581 id_value.__class__.__name__.replace('Id', ''), key)
582 print(error)
583 print('Check the config contents provided:')
584 printer = pprint.PrettyPrinter(indent=4)
585 printer.pprint(id_map)
586 raise Exception(error)
David Burger7fd1dbe2020-03-26 09:26:55 -0600587
588
Andrew Lambcd33f702020-06-11 10:45:16 -0600589def _build_touch_file_config(config, project_name):
Sean McAllistereaf10b72020-08-03 13:41:06 -0600590 partners = {x.id.value: x for x in config.partner_list}
C Shapiro2b6d5332020-05-06 17:51:35 -0500591 files = []
592 for comp in config.components:
C Shapiro4813be62020-05-13 17:31:58 -0500593 touch = comp.touchscreen
594 # Everything is the same for Touch screen/pad, except different fields
595 if comp.HasField('touchpad'):
596 touch = comp.touchpad
597 if touch.product_id:
Andrew Lambcd33f702020-06-11 10:45:16 -0600598 vendor = _lookup(comp.manufacturer_id, partners)
C Shapiro2b6d5332020-05-06 17:51:35 -0500599 if not vendor:
Andrew Lamb2413c982020-05-29 12:15:36 -0600600 raise Exception("Manufacturer must be set for touch device %s" %
601 comp.id.value)
C Shapiro2b6d5332020-05-06 17:51:35 -0500602
C Shapiro4813be62020-05-13 17:31:58 -0500603 product_id = touch.product_id
604 fw_version = touch.fw_version
C Shapiro2b6d5332020-05-06 17:51:35 -0500605
C Shapiro2b6d5332020-05-06 17:51:35 -0500606 file_name = "%s_%s.bin" % (product_id, fw_version)
607 fw_file_path = os.path.join(TOUCH_PATH, vendor.name, file_name)
608
609 if not os.path.exists(fw_file_path):
Andrew Lamb2413c982020-05-29 12:15:36 -0600610 raise Exception("Touchscreen fw bin file doesn't exist at: %s" %
611 fw_file_path)
C Shapiro2b6d5332020-05-06 17:51:35 -0500612
C Shapiro303cece2020-07-22 07:15:21 -0500613 touch_vendor = vendor.touch_vendor
614 sym_link = touch_vendor.symlink_file_format.format(
615 vendor_name=vendor.name,
616 vendor_id=touch_vendor.vendor_id,
617 product_id=product_id,
618 fw_version=fw_version,
619 product_series=touch.product_series)
620
621 dest = "%s_%s" % (vendor.name, file_name)
622 if touch_vendor.destination_file_format:
623 dest = touch_vendor.destination_file_format.format(
624 vendor_name=vendor.name,
625 vendor_id=touch_vendor.vendor_id,
626 product_id=product_id,
627 fw_version=fw_version,
628 product_series=touch.product_series)
629
C Shapiro2b6d5332020-05-06 17:51:35 -0500630 files.append({
C Shapiro303cece2020-07-22 07:15:21 -0500631 "destination": os.path.join("/opt/google/touch/firmware", dest),
YH Lin9160fc52020-07-22 16:35:28 -0700632 "source": os.path.join(project_name, fw_file_path),
633 "symlink": os.path.join("/lib/firmware", sym_link),
C Shapiro2b6d5332020-05-06 17:51:35 -0500634 })
635
636 result = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600637 _upsert(files, result, 'files')
C Shapiro2b6d5332020-05-06 17:51:35 -0500638 return result
639
640
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000641def _build_modem(config):
642 """Returns the cellular modem configuration, or None if absent."""
643 hw_features = config.hw_design_config.hardware_features
644 lte_support = _any_present([hw_features.lte.present])
645 if not lte_support:
646 return None
Vincent Palatin0ebdfd32021-04-23 15:54:43 +0200647 firmware_variant = config.hw_design.name.lower()
648 if hw_features.lte.model:
649 firmware_variant += '_' + hw_features.lte.model.lower()
650 return {'firmware-variant': firmware_variant}
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000651
652
David Burgerceeb68a2020-09-03 11:31:10 -0600653def _sw_config(sw_configs, design_config_id):
654 """Returns the correct software config for `design_config_id`.
655
656 Returns the correct software config match for `design_config_id`. If no such
657 config or multiple such configs are found an exception is raised.
658 """
659 sw_config_matches = [
660 x for x in sw_configs if x.design_config_id.value == design_config_id
661 ]
662 if len(sw_config_matches) == 1:
663 return sw_config_matches[0]
664 if len(sw_config_matches) > 1:
665 raise ValueError('Multiple software configs found for: %s' %
666 design_config_id)
667 raise ValueError('Software config is required for: %s' % design_config_id)
668
669
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000670def _is_whitelabel(brand_configs, device_brands):
671 for device_brand in device_brands:
672 if device_brand.id.value in brand_configs:
673 brand_scan_config = brand_configs[device_brand.id.value].scan_config
674 if brand_scan_config and brand_scan_config.whitelabel_tag:
675 return True
676 return False
677
678
David Burgerceeb68a2020-09-03 11:31:10 -0600679def _transform_build_configs(config,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800680 config_files=ConfigFiles({}, {}, {}, {}, {}, {})):
Andrew Lambcd33f702020-06-11 10:45:16 -0600681 # pylint: disable=too-many-locals,too-many-branches
Sean McAllistereaf10b72020-08-03 13:41:06 -0600682 partners = {x.id.value: x for x in config.partner_list}
Sean McAllisterf38d1e92020-08-03 13:57:53 -0600683 programs = {x.id.value: x for x in config.program_list}
David Burger7fd1dbe2020-03-26 09:26:55 -0600684 sw_configs = list(config.software_configs)
Andrew Lambcd33f702020-06-11 10:45:16 -0600685 brand_configs = {x.brand_id.value: x for x in config.brand_configs}
David Burger7fd1dbe2020-03-26 09:26:55 -0600686
687 results = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600688 for hw_design in config.design_list:
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600689 if config.device_brand_list:
Andrew Lamb2413c982020-05-29 12:15:36 -0600690 device_brands = [
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600691 x for x in config.device_brand_list
Andrew Lamb2413c982020-05-29 12:15:36 -0600692 if x.design_id.value == hw_design.id.value
693 ]
David Burger7fd1dbe2020-03-26 09:26:55 -0600694 else:
695 device_brands = [device_brand_pb2.DeviceBrand()]
696
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000697 whitelabel = _is_whitelabel(brand_configs, device_brands)
698
David Burger7fd1dbe2020-03-26 09:26:55 -0600699 for device_brand in device_brands:
700 # Brand config can be empty since platform JSON config allows it
701 brand_config = brand_config_pb2.BrandConfig()
702 if device_brand.id.value in brand_configs:
703 brand_config = brand_configs[device_brand.id.value]
704
705 for hw_design_config in hw_design.configs:
David Burgerceeb68a2020-09-03 11:31:10 -0600706 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
Andrew Lambcd33f702020-06-11 10:45:16 -0600707 program = _lookup(hw_design.program_id, programs)
C Shapiroadefd7c2020-05-19 16:37:21 -0500708 signer_configs_by_design = {}
709 signer_configs_by_brand = {}
710 for signer_config in program.device_signer_configs:
711 design_id = signer_config.design_id.value
712 brand_id = signer_config.brand_id.value
713 if design_id:
714 signer_configs_by_design[design_id] = signer_config
715 elif brand_id:
716 signer_configs_by_brand[brand_id] = signer_config
717 else:
718 raise Exception('No ID found for signer config: %s' % signer_config)
719
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500720 device_signer_config = None
C Shapiroadefd7c2020-05-19 16:37:21 -0500721 if signer_configs_by_design or signer_configs_by_brand:
722 design_id = hw_design.id.value
723 brand_id = device_brand.id.value
724 if design_id in signer_configs_by_design:
725 device_signer_config = signer_configs_by_design[design_id]
726 elif brand_id in signer_configs_by_brand:
727 device_signer_config = signer_configs_by_brand[brand_id]
728 else:
729 # Assume that if signer configs are set, every config is setup
Andrew Lamb2413c982020-05-29 12:15:36 -0600730 raise Exception('Signer config missing for design: %s, brand: %s' %
731 (design_id, brand_id))
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500732
Andrew Lambcd33f702020-06-11 10:45:16 -0600733 transformed_config = _transform_build_config(
C Shapiro90fda252020-04-17 14:34:57 -0500734 Config(
735 program=program,
736 hw_design=hw_design,
Andrew Lambcd33f702020-06-11 10:45:16 -0600737 odm=_lookup(hw_design.odm_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500738 hw_design_config=hw_design_config,
739 device_brand=device_brand,
740 device_signer_config=device_signer_config,
Andrew Lambcd33f702020-06-11 10:45:16 -0600741 oem=_lookup(device_brand.oem_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500742 sw_config=sw_config,
C Shapirod5545f12020-11-30 16:37:04 -0600743 brand_config=brand_config), config_files, whitelabel)
David Burger7fd1dbe2020-03-26 09:26:55 -0600744
Andrew Lamb2413c982020-05-29 12:15:36 -0600745 config_json = json.dumps(
746 transformed_config,
747 sort_keys=True,
748 indent=2,
749 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600750
751 if config_json not in results:
752 results[config_json] = transformed_config
753
754 return list(results.values())
755
756
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000757def _transform_build_config(config, config_files, whitelabel):
David Burger7fd1dbe2020-03-26 09:26:55 -0600758 """Transforms Config instance into target platform JSON schema.
759
760 Args:
761 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500762 config_files: Map to look up the generated config files.
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000763 whitelabel: Whether the config is for a whitelabel design
David Burger7fd1dbe2020-03-26 09:26:55 -0600764
765 Returns:
766 Unique config payload based on the platform JSON schema.
767 """
768 result = {
Andrew Lamb2413c982020-05-29 12:15:36 -0600769 'identity':
Andrew Lambcd33f702020-06-11 10:45:16 -0600770 _build_identity(config.sw_config.id_scan_config, config.program,
771 config.brand_config.scan_config),
Andrew Lamb2413c982020-05-29 12:15:36 -0600772 'name':
773 config.hw_design.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600774 }
775
David Burger8ee9b4d2020-06-16 17:40:21 -0600776 _upsert(_build_arc(config, config_files), result, 'arc')
777 _upsert(_build_audio(config), result, 'audio')
David Burger07af5242020-08-11 11:08:25 -0600778 _upsert(_build_bluetooth(config), result, 'bluetooth')
David Burgerceeb68a2020-09-03 11:31:10 -0600779 _upsert(_build_wifi(config, config_files), result, 'wifi')
Andrew Lambca279902020-08-06 10:13:42 -0600780 _upsert(config.brand_config.wallpaper, result, 'wallpaper')
C Shapiro2e97aad2020-11-16 11:58:10 -0600781 _upsert(config.brand_config.regulatory_label, result, 'regulatory-label')
David Burger8ee9b4d2020-06-16 17:40:21 -0600782 _upsert(config.device_brand.brand_code, result, 'brand-code')
783 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600784 _build_camera(config.hw_design_config.hardware_topology), result,
785 'camera')
David Burger8ee9b4d2020-06-16 17:40:21 -0600786 _upsert(_build_firmware(config), result, 'firmware')
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000787 _upsert(_build_fw_signing(config, whitelabel), result, 'firmware-signing')
David Burger8ee9b4d2020-06-16 17:40:21 -0600788 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600789 _build_fingerprint(config.hw_design_config.hardware_topology), result,
Andrew Lamb2413c982020-05-29 12:15:36 -0600790 'fingerprint')
Andrew Lamb0d236ab2020-06-30 12:30:20 -0600791 _upsert(_build_ui(config), result, 'ui')
David Burger7fd1dbe2020-03-26 09:26:55 -0600792 power_prefs = config.sw_config.power_config.preferences
793 power_prefs_map = dict(
Andrew Lamb2413c982020-05-29 12:15:36 -0600794 (x.replace('_', '-'), power_prefs[x]) for x in power_prefs)
David Burger8ee9b4d2020-06-16 17:40:21 -0600795 _upsert(power_prefs_map, result, 'power')
796 if config_files.camera_map:
797 camera_file = config_files.camera_map.get(config.hw_design.name, {})
798 _upsert(camera_file, result, 'camera')
David Burger52c9d322020-06-09 07:16:18 -0600799 if config_files.dptf_map:
800 # Prefer design specific if found, if not fall back to project wide config
801 # mapped under the empty string.
802 if config_files.dptf_map.get(config.hw_design.name):
803 dptf_file = config_files.dptf_map[config.hw_design.name]
804 else:
805 dptf_file = config_files.dptf_map.get('')
David Burger8ee9b4d2020-06-16 17:40:21 -0600806 _upsert(dptf_file, result, 'thermal')
807 _upsert(config_files.touch_fw, result, 'touch')
Trent Beginf067ccb2020-08-12 12:33:53 -0600808 _upsert(
809 _build_hardware_properties(config.hw_design_config.hardware_topology),
810 result, 'hardware-properties')
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000811 _upsert(_build_modem(config), result, 'modem')
David Burger7fd1dbe2020-03-26 09:26:55 -0600812
813 return result
814
815
Andrew Lambcd33f702020-06-11 10:45:16 -0600816def write_output(configs, output=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600817 """Writes a list of configs to platform JSON format.
818
819 Args:
820 configs: List of config dicts defined in cros_config_schema.yaml
821 output: Target file output (if None, prints to stdout)
822 """
Andrew Lamb2413c982020-05-29 12:15:36 -0600823 json_output = json.dumps({'chromeos': {
824 'configs': configs,
825 }},
826 sort_keys=True,
827 indent=2,
828 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600829 if output:
830 with open(output, 'w') as output_stream:
831 # Using print function adds proper trailing newline.
832 print(json_output, file=output_stream)
833 else:
834 print(json_output)
835
836
Andrew Lambcd33f702020-06-11 10:45:16 -0600837def _feature(name, present):
C Shapiro5bf23a72020-04-24 11:40:17 -0500838 attrib = {'name': name}
839 if present:
840 return etree.Element('feature', attrib=attrib)
Andrew Lambcd33f702020-06-11 10:45:16 -0600841
842 return etree.Element('unavailable-feature', attrib=attrib)
C Shapiro5bf23a72020-04-24 11:40:17 -0500843
844
Andrew Lambcd33f702020-06-11 10:45:16 -0600845def _any_present(features):
Andrew Lamb2413c982020-05-29 12:15:36 -0600846 return topology_pb2.HardwareFeatures.PRESENT in features
C Shapiro5bf23a72020-04-24 11:40:17 -0500847
848
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800849def _get_formatted_config_id(design_config):
C Shapiro5bf23a72020-04-24 11:40:17 -0500850 return design_config.id.value.lower().replace(':', '_')
851
852
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800853def _write_file(output_dir, file_name, file_content):
David Burger77a1d312020-05-23 16:05:45 -0600854 os.makedirs(output_dir, exist_ok=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800855 output = '{}/{}'.format(output_dir, file_name)
C Shapiroea33cff2020-05-11 13:32:05 -0500856 with open(output, 'wb') as f:
857 f.write(file_content)
858
859
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800860def _get_arc_camera_features(camera):
861 """Gets camera related features for ARC hardware_features.xml from camera
862 topology. Check
863 https://developer.android.com/reference/android/content/pm/PackageManager#FEATURE_CAMERA
864 and CTS android.app.cts.SystemFeaturesTest#testCameraFeatures for the correct
865 settings.
866
867 Args:
868 camera: A HardwareFeatures.Camera proto message.
869 Returns:
870 list of camera related ARC features as XML elements.
871 """
872 camera_pb = topology_pb2.HardwareFeatures.Camera
873
Ren-Pei Zeng9b5682d2020-10-14 17:37:30 +0800874 count = len(camera.devices)
875 has_front_camera = any(
876 (d.facing == camera_pb.FACING_FRONT for d in camera.devices))
877 has_back_camera = any(
878 (d.facing == camera_pb.FACING_BACK for d in camera.devices))
879 has_autofocus_back_camera = any((d.facing == camera_pb.FACING_BACK and
880 d.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS
881 for d in camera.devices))
882 # Assumes MIPI cameras support FULL-level.
883 # TODO(kamesan): Setting this in project configs when there's an exception.
884 has_level_full_camera = any(
885 (d.interface == camera_pb.INTERFACE_MIPI for d in camera.devices))
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800886
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800887 return [
888 _feature('android.hardware.camera', has_back_camera),
889 _feature('android.hardware.camera.any', count > 0),
890 _feature('android.hardware.camera.autofocus', has_autofocus_back_camera),
891 _feature('android.hardware.camera.capability.manual_post_processing',
892 has_level_full_camera),
893 _feature('android.hardware.camera.capability.manual_sensor',
894 has_level_full_camera),
895 _feature('android.hardware.camera.front', has_front_camera),
896 _feature('android.hardware.camera.level.full', has_level_full_camera),
897 ]
898
899
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800900def _generate_arc_hardware_features(hw_features):
901 """Generates ARC hardware_features.xml file content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500902
903 Args:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800904 hw_features: HardwareFeatures proto message.
C Shapiro5bf23a72020-04-24 11:40:17 -0500905 Returns:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800906 bytes of the hardware_features.xml content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500907 """
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800908 touchscreen = _any_present([hw_features.screen.touch_support])
909 acc = hw_features.accelerometer
910 gyro = hw_features.gyroscope
911 compass = hw_features.magnetometer
912 light_sensor = hw_features.light_sensor
913 root = etree.Element('permissions')
914 root.extend(
915 _get_arc_camera_features(hw_features.camera) + [
916 _feature(
917 'android.hardware.sensor.accelerometer',
918 _any_present([acc.lid_accelerometer, acc.base_accelerometer])),
919 _feature('android.hardware.sensor.gyroscope',
920 _any_present([gyro.lid_gyroscope, gyro.base_gyroscope])),
921 _feature(
922 'android.hardware.sensor.compass',
923 _any_present(
924 [compass.lid_magnetometer, compass.base_magnetometer])),
925 _feature(
926 'android.hardware.sensor.light',
927 _any_present([
928 light_sensor.lid_lightsensor, light_sensor.base_lightsensor
929 ])),
930 _feature('android.hardware.touchscreen', touchscreen),
931 _feature('android.hardware.touchscreen.multitouch', touchscreen),
932 _feature('android.hardware.touchscreen.multitouch.distinct',
933 touchscreen),
934 _feature('android.hardware.touchscreen.multitouch.jazzhand',
935 touchscreen),
936 ])
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800937 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
938
939
940def _generate_arc_media_profiles(hw_features, sw_config):
941 """Generates ARC media_profiles.xml file content.
942
943 Args:
944 hw_features: HardwareFeatures proto message.
945 sw_config: SoftwareConfig proto message.
946 Returns:
947 bytes of the media_profiles.xml content, or None if |sw_config| disables the
Ren-Pei Zengb55e4312020-11-18 17:03:01 +0800948 generation or there's no camera.
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800949 """
950
951 def _gen_camcorder_profiles(camera_id, resolutions):
952 elem = etree.Element(
953 'CamcorderProfiles', attrib={'cameraId': str(camera_id)})
954 for width, height in resolutions:
955 elem.extend([
956 _gen_encoder_profile(width, height, False),
957 _gen_encoder_profile(width, height, True),
958 ])
959 elem.extend([
960 etree.Element('ImageEncoding', attrib={'quality': '90'}),
961 etree.Element('ImageEncoding', attrib={'quality': '80'}),
962 etree.Element('ImageEncoding', attrib={'quality': '70'}),
963 etree.Element('ImageDecoding', attrib={'memCap': '20000000'}),
964 ])
965 return elem
966
967 def _gen_encoder_profile(width, height, timelapse):
968 elem = etree.Element(
969 'EncoderProfile',
970 attrib={
971 'quality': ('timelapse' if timelapse else '') + str(height) + 'p',
972 'fileFormat': 'mp4',
973 'duration': '60',
974 })
975 elem.append(
976 etree.Element(
977 'Video',
978 attrib={
979 'codec': 'h264',
980 'bitRate': '8000000',
981 'width': str(width),
982 'height': str(height),
983 'frameRate': '30',
984 }))
985 elem.append(
986 etree.Element(
987 'Audio',
988 attrib={
989 'codec': 'aac',
990 'bitRate': '96000',
991 'sampleRate': '44100',
992 'channels': '1',
993 }))
994 return elem
995
996 def _gen_video_encoder_cap(name, min_bit_rate, max_bit_rate):
997 return etree.Element(
998 'VideoEncoderCap',
999 attrib={
1000 'name': name,
1001 'enabled': 'true',
1002 'minBitRate': str(min_bit_rate),
1003 'maxBitRate': str(max_bit_rate),
1004 'minFrameWidth': '320',
1005 'maxFrameWidth': '1920',
1006 'minFrameHeight': '240',
1007 'maxFrameHeight': '1080',
1008 'minFrameRate': '15',
1009 'maxFrameRate': '30',
1010 })
1011
1012 def _gen_audio_encoder_cap(name, min_bit_rate, max_bit_rate, min_sample_rate,
1013 max_sample_rate):
1014 return etree.Element(
1015 'AudioEncoderCap',
1016 attrib={
1017 'name': name,
1018 'enabled': 'true',
1019 'minBitRate': str(min_bit_rate),
1020 'maxBitRate': str(max_bit_rate),
1021 'minSampleRate': str(min_sample_rate),
1022 'maxSampleRate': str(max_sample_rate),
1023 'minChannels': '1',
1024 'maxChannels': '1',
1025 })
1026
1027 camera_config = sw_config.camera_config
1028 if not camera_config.generate_media_profiles:
1029 return None
1030
1031 camera_pb = topology_pb2.HardwareFeatures.Camera
1032 root = etree.Element('MediaSettings')
1033 camera_id = 0
1034 for facing in [camera_pb.FACING_BACK, camera_pb.FACING_FRONT]:
1035 camera_device = next(
1036 (d for d in hw_features.camera.devices if d.facing == facing), None)
1037 if camera_device is None:
1038 continue
1039 if camera_config.camcorder_resolutions:
1040 resolutions = [
1041 (r.width, r.height) for r in camera_config.camcorder_resolutions
1042 ]
1043 else:
1044 resolutions = [(1280, 720)]
1045 if camera_device.flags & camera_pb.FLAGS_SUPPORT_1080P:
1046 resolutions.append((1920, 1080))
1047 root.append(_gen_camcorder_profiles(camera_id, resolutions))
1048 camera_id += 1
Ren-Pei Zengb55e4312020-11-18 17:03:01 +08001049 # media_profiles.xml should have at least one CamcorderProfiles.
1050 if camera_id == 0:
1051 return None
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001052
1053 root.extend([
1054 etree.Element('EncoderOutputFileFormat', attrib={'name': '3gp'}),
1055 etree.Element('EncoderOutputFileFormat', attrib={'name': 'mp4'}),
1056 _gen_video_encoder_cap('h264', 64000, 17000000),
1057 _gen_video_encoder_cap('h263', 64000, 1000000),
1058 _gen_video_encoder_cap('m4v', 64000, 2000000),
1059 _gen_audio_encoder_cap('aac', 758, 288000, 8000, 48000),
1060 _gen_audio_encoder_cap('heaac', 8000, 64000, 16000, 48000),
1061 _gen_audio_encoder_cap('aaceld', 16000, 192000, 16000, 48000),
1062 _gen_audio_encoder_cap('amrwb', 6600, 23050, 16000, 16000),
1063 _gen_audio_encoder_cap('amrnb', 5525, 12200, 8000, 8000),
1064 etree.Element(
1065 'VideoDecoderCap', attrib={
1066 'name': 'wmv',
1067 'enabled': 'false'
1068 }),
1069 etree.Element(
1070 'AudioDecoderCap', attrib={
1071 'name': 'wma',
1072 'enabled': 'false'
1073 }),
1074 ])
Ren-Pei Zeng21708cc2020-11-17 11:14:07 +08001075
1076 dtd_path = os.path.dirname(__file__)
1077 dtd = etree.DTD(os.path.join(dtd_path, 'media_profiles.dtd'))
1078 if not dtd.validate(root):
1079 raise etree.DTDValidateError(
1080 'Invalid media_profiles.xml generated:\n{}'.format(dtd.error_log))
1081
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001082 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001083
1084
1085def _write_files_by_design_config(configs, output_dir, build_dir, system_dir,
1086 file_name_template, generate_file_content):
1087 """Writes generated files for each design config.
1088
1089 Args:
1090 configs: Source ConfigBundle to process.
1091 output_dir: Path to the generated output.
1092 build_dir: Path to the config file from portage's perspective.
1093 system_dir: Path to the config file in the target device.
1094 file_name_template: Template string of the config file name including one
1095 format()-style replacement field for the config id, e.g. 'config_{}.xml'.
1096 generate_file_content: Function to generate config file content from
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001097 HardwareFeatures and SoftwareConfig proto.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001098 Returns:
1099 dict that maps the formatted config id to the correct file.
1100 """
1101 # pylint: disable=too-many-arguments,too-many-locals
C Shapiro5bf23a72020-04-24 11:40:17 -05001102 result = {}
C Shapiroea33cff2020-05-11 13:32:05 -05001103 configs_by_design = {}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001104 for hw_design in configs.design_list:
C Shapiro5bf23a72020-04-24 11:40:17 -05001105 for design_config in hw_design.configs:
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001106 sw_config = _sw_config(configs.software_configs, design_config.id.value)
1107 config_content = generate_file_content(design_config.hardware_features,
1108 sw_config)
1109 if not config_content:
1110 continue
C Shapiroea33cff2020-05-11 13:32:05 -05001111 design_name = hw_design.name.lower()
C Shapiro5bf23a72020-04-24 11:40:17 -05001112
C Shapiroea33cff2020-05-11 13:32:05 -05001113 # Constructs the following map:
1114 # design_name -> config -> design_configs
1115 # This allows any of the following file naming schemes:
1116 # - All configs within a design share config (design_name prefix only)
1117 # - Nobody shares (full design_name and config id prefix needed)
1118 #
1119 # Having shared configs when possible makes code reviews easier around
1120 # the configs and makes debugging easier on the platform side.
C Shapiroea33cff2020-05-11 13:32:05 -05001121 arc_configs = configs_by_design.get(design_name, {})
1122 design_configs = arc_configs.get(config_content, [])
1123 design_configs.append(design_config)
1124 arc_configs[config_content] = design_configs
1125 configs_by_design[design_name] = arc_configs
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001126
C Shapiroea33cff2020-05-11 13:32:05 -05001127 for design_name, unique_configs in configs_by_design.items():
1128 for file_content, design_configs in unique_configs.items():
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001129 file_name = file_name_template.format(design_name)
Andrew Lamb2413c982020-05-29 12:15:36 -06001130 if len(unique_configs) == 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001131 _write_file(output_dir, file_name, file_content)
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001132
Andrew Lamb2413c982020-05-29 12:15:36 -06001133 for design_config in design_configs:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001134 config_id = _get_formatted_config_id(design_config)
Andrew Lamb2413c982020-05-29 12:15:36 -06001135 if len(unique_configs) > 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001136 file_name = file_name_template.format(config_id)
1137 _write_file(output_dir, file_name, file_content)
1138 result[config_id] = _file_v2('{}/{}'.format(build_dir, file_name),
1139 '{}/{}'.format(system_dir, file_name))
C Shapiro5bf23a72020-04-24 11:40:17 -05001140 return result
1141
1142
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001143def _write_arc_hardware_feature_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001144 return _write_files_by_design_config(
1145 configs, output_root_dir + '/arc', build_root_dir + '/arc', '/etc',
1146 'hardware_features_{}.xml',
1147 lambda hw_features, _: _generate_arc_hardware_features(hw_features))
1148
1149
1150def _write_arc_media_profile_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001151 return _write_files_by_design_config(configs, output_root_dir + '/arc',
1152 build_root_dir + '/arc', '/etc',
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001153 'media_profiles_{}.xml',
1154 _generate_arc_media_profiles)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001155
1156
Andrew Lambcd33f702020-06-11 10:45:16 -06001157def _read_config(path):
David Burgerd4f32962020-05-02 12:07:40 -06001158 """Reads a ConfigBundle proto from a json pb file.
David Burgere6f76222020-04-27 11:08:01 -06001159
1160 Args:
David Burgerd4f32962020-05-02 12:07:40 -06001161 path: Path to the file encoding the json pb proto.
David Burgere6f76222020-04-27 11:08:01 -06001162 """
1163 config = config_bundle_pb2.ConfigBundle()
1164 with open(path, 'r') as f:
1165 return json_format.Parse(f.read(), config)
1166
1167
Andrew Lambcd33f702020-06-11 10:45:16 -06001168def _merge_configs(configs):
David Burger7fd1dbe2020-03-26 09:26:55 -06001169 result = config_bundle_pb2.ConfigBundle()
1170 for config in configs:
1171 result.MergeFrom(config)
1172
1173 return result
1174
1175
David Burger1ba78a22020-06-18 18:42:47 -06001176def _camera_map(configs, project_name):
David Burger8ee9b4d2020-06-16 17:40:21 -06001177 """Produces a camera config map for the given configs.
1178
1179 Produces a map that maps from the design name to the camera config for that
1180 design.
1181
1182 Args:
1183 configs: Source ConfigBundle to process.
David Burger1ba78a22020-06-18 18:42:47 -06001184 project_name: Name of project processing for.
David Burger8ee9b4d2020-06-16 17:40:21 -06001185
1186 Returns:
1187 map from design name to camera config.
1188 """
1189 result = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -06001190 for design in configs.design_list:
David Burger8ee9b4d2020-06-16 17:40:21 -06001191 design_name = design.name
David Burger0d9e8462020-06-19 14:12:37 -06001192 config_path = CAMERA_CONFIG_SOURCE_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001193 if os.path.exists(config_path):
David Burger0d9e8462020-06-19 14:12:37 -06001194 destination = CAMERA_CONFIG_DEST_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001195 result[design_name] = {
David Burger1ba78a22020-06-18 18:42:47 -06001196 'config-file':
1197 _file_v2(os.path.join(project_name, config_path), destination),
David Burger8ee9b4d2020-06-16 17:40:21 -06001198 }
1199 return result
1200
1201
David Burger52c9d322020-06-09 07:16:18 -06001202def _dptf_map(configs, project_name):
1203 """Produces a dptf map for the given configs.
1204
1205 Produces a map that maps from design name to the dptf file config for that
1206 design. It looks for the dptf files at:
David Burger2f0d9522020-07-30 10:52:28 -06001207 DPTF_PATH + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001208 for a project wide config, that it maps under the empty string, and at:
David Burger2f0d9522020-07-30 10:52:28 -06001209 DPTF_PATH + '/' + design_name + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001210 for design specific configs that it maps under the design name.
1211
1212 Args:
1213 configs: Source ConfigBundle to process.
1214 project_name: Name of project processing for.
1215
1216 Returns:
David Burger8ee9b4d2020-06-16 17:40:21 -06001217 map from design name or empty string (project wide), to dptf config.
David Burger52c9d322020-06-09 07:16:18 -06001218 """
1219 result = {}
David Burger52c9d322020-06-09 07:16:18 -06001220 # Looking at top level for project wide, and then for each design name
1221 # for design specific.
Sean McAllisterf66887b2020-08-03 14:00:51 -06001222 dirs = [""] + [d.name for d in configs.design_list]
David Burger52c9d322020-06-09 07:16:18 -06001223 for directory in dirs:
David Burgera2252762020-07-09 15:09:49 -06001224 design = directory.lower()
1225 if os.path.exists(os.path.join(DPTF_PATH, design, DPTF_FILE)):
David Burger2f0d9522020-07-30 10:52:28 -06001226 project_dptf_path = os.path.join(project_name, design, DPTF_FILE)
David Burger52c9d322020-06-09 07:16:18 -06001227 dptf_file = {
1228 'dptf-dv':
1229 project_dptf_path,
1230 'files': [
1231 _file(
David Burgera2252762020-07-09 15:09:49 -06001232 os.path.join(project_name, DPTF_PATH, design, DPTF_FILE),
David Burger52c9d322020-06-09 07:16:18 -06001233 os.path.join('/etc/dptf', project_dptf_path))
1234 ]
1235 }
1236 result[directory] = dptf_file
1237 return result
1238
1239
David Burgerceeb68a2020-09-03 11:31:10 -06001240def _wifi_sar_map(configs, project_name, output_dir, build_root_dir):
1241 """Constructs a map from design name to wifi sar config for that design.
1242
1243 Constructs a map from design name to the wifi sar config for that design.
1244 In the process a wifi sar hex file is generated that the config points at.
1245 This mapping is only made for the intel wifi where the generated file is
1246 provided when building coreboot.
1247
1248 Args:
1249 configs: Source ConfigBundle to process.
1250 project_name: Name of project processing for.
1251 output_dir: Path to the generated output.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001252 build_root_dir: Path to the config file from portage's perspective.
David Burgerceeb68a2020-09-03 11:31:10 -06001253
1254 Returns:
1255 dict that maps the design name onto the wifi config for that design.
1256 """
1257 # pylint: disable=too-many-locals
1258 result = {}
1259 programs = {p.id.value: p for p in configs.program_list}
1260 sw_configs = list(configs.software_configs)
1261 for hw_design in configs.design_list:
1262 for hw_design_config in hw_design.configs:
1263 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
1264 if sw_config.wifi_config.HasField('intel_config'):
1265 sar_file_content = _create_intel_sar_file_content(
1266 sw_config.wifi_config.intel_config)
1267 design_name = hw_design.name.lower()
1268 program = _lookup(hw_design.program_id, programs)
1269 wifi_sar_id = _extract_fw_config_value(hw_design_config, program,
1270 'Intel wifi sar id')
1271 output_path = os.path.join(output_dir, 'wifi')
1272 os.makedirs(output_path, exist_ok=True)
1273 filename = 'wifi_sar_{}.hex'.format(wifi_sar_id)
1274 output_path = os.path.join(output_path, filename)
1275 build_path = os.path.join(build_root_dir, 'wifi', filename)
1276 if os.path.exists(output_path):
1277 with open(output_path, 'r') as f:
1278 if f.read() != sar_file_content:
1279 raise Exception(
1280 'Project {} has conflicting wifi sar file content under '
1281 'wifi sar id {}.'.format(project_name, wifi_sar_id))
1282 else:
1283 with open(output_path, 'w') as f:
1284 f.write(sar_file_content)
1285 system_path = '/firmware/cbfs-rw-raw/{}/{}'.format(
1286 project_name, filename)
David Burger89e7cae2020-09-15 17:04:12 -06001287 result[design_name] = {'sar-file': _file_v2(build_path, system_path)}
David Burgerceeb68a2020-09-03 11:31:10 -06001288 return result
1289
1290
1291def _extract_fw_config_value(hw_design_config, program, name):
1292 """Extracts the firwmare config value with the given name.
1293
1294 Args:
1295 hw_design_config: Design extracting value from.
1296 program: Program the `hw_design_config` belongs to.
1297 name: Name of firmware config segment to extract.
1298
1299 Returns: the extracted value or raises a ValueError if no firmware
1300 configuration segment with `name` is found.
1301 """
1302 fw_config = hw_design_config.hardware_features.fw_config.value
1303 for fcs in program.firmware_configuration_segments:
1304 if fcs.name == name:
1305 value = fw_config & fcs.mask
1306 lsb_bit_set = (~fcs.mask + 1) & fcs.mask
1307 return value // lsb_bit_set
1308 raise ValueError(
1309 'No firmware configuration segment with name {} found'.format(name))
1310
1311
1312def _create_intel_sar_file_content(intel_config):
1313 """Creates and returns the intel sar file content for the given config.
1314
1315 Creates and returns the sar file content that is used with intel drivers
1316 only.
1317
1318 Args:
1319 intel_config: IntelConfig config.
1320
1321 Returns:
1322 sar file content for the given config, see:
1323 https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1324 """
1325
1326 def to_hex(val):
1327 if val > 255 or val < 0:
1328 raise Exception('Sar file value %s out of range' % val)
1329 return '{0:0{1}X}'.format(val, 2)
1330
1331 def power_table(tpc):
1332 return (to_hex(tpc.limit_2g) + to_hex(tpc.limit_5g_1) +
1333 to_hex(tpc.limit_5g_2) + to_hex(tpc.limit_5g_3) +
1334 to_hex(tpc.limit_5g_4))
1335
1336 def wgds_value(wgds):
1337 return to_hex(wgds)
1338
1339 def offset_table(offsets):
1340 return (to_hex(offsets.max_2g) + to_hex(offsets.offset_2g_a) +
1341 to_hex(offsets.offset_2g_b) + to_hex(offsets.max_5g) +
1342 to_hex(offsets.offset_5g_a) + to_hex(offsets.offset_5g_b))
1343
1344 # See https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1345 return (power_table(intel_config.tablet_mode_power_table_a) +
1346 power_table(intel_config.tablet_mode_power_table_b) +
1347 power_table(intel_config.non_tablet_mode_power_table_a) +
1348 power_table(intel_config.non_tablet_mode_power_table_b) +
1349 '00000000000000000000' + '00000000000000000000' +
1350 wgds_value(intel_config.wgds_version) +
1351 offset_table(intel_config.offset_fcc) +
1352 offset_table(intel_config.offset_eu) +
YH Lin89cddaa2021-03-08 08:31:47 -08001353 offset_table(intel_config.offset_other) + '\0')
David Burgerceeb68a2020-09-03 11:31:10 -06001354
1355
Andrew Lambcd33f702020-06-11 10:45:16 -06001356def Main(project_configs, program_config, output): # pylint: disable=invalid-name
David Burger7fd1dbe2020-03-26 09:26:55 -06001357 """Transforms source proto config into platform JSON.
1358
1359 Args:
1360 project_configs: List of source project configs to transform.
1361 program_config: Program config for the given set of projects.
1362 output: Output file that will be generated by the transform.
1363 """
Andrew Lambcd33f702020-06-11 10:45:16 -06001364 configs = _merge_configs([_read_config(program_config)] +
1365 [_read_config(config) for config in project_configs])
C Shapiro2b6d5332020-05-06 17:51:35 -05001366 touch_fw = {}
David Burger8ee9b4d2020-06-16 17:40:21 -06001367 camera_map = {}
David Burgerceeb68a2020-09-03 11:31:10 -06001368 dptf_map = {}
1369 wifi_sar_map = {}
C Shapiro5bf23a72020-04-24 11:40:17 -05001370 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -05001371 build_root_dir = output_dir
C Shapiro5c877992020-04-29 12:11:28 -05001372 if 'sw_build_config' in output_dir:
1373 full_path = os.path.realpath(output)
Andrew Lamb6b607732020-08-24 15:52:46 -06001374 project_name = re.match(r'.*/(\w*)/(public_)?sw_build_config/.*',
Andrew Lamb2413c982020-05-29 12:15:36 -06001375 full_path).groups(1)[0]
C Shapiro5c877992020-04-29 12:11:28 -05001376 # Projects don't know about each other until they are integrated into the
1377 # build system. When this happens, the files need to be able to co-exist
1378 # without any collisions. This prefixes the project name (which is how
1379 # portage maps in the project), so project files co-exist and can be
1380 # installed together.
1381 # This is necessary to allow projects to share files at the program level
1382 # without having portage file installation collisions.
1383 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -05001384
David Burger1ba78a22020-06-18 18:42:47 -06001385 camera_map = _camera_map(configs, project_name)
David Burger52c9d322020-06-09 07:16:18 -06001386 dptf_map = _dptf_map(configs, project_name)
David Burgerceeb68a2020-09-03 11:31:10 -06001387 wifi_sar_map = _wifi_sar_map(configs, project_name, output_dir,
1388 build_root_dir)
David Burger52c9d322020-06-09 07:16:18 -06001389
C Shapiro2b6d5332020-05-06 17:51:35 -05001390 if os.path.exists(TOUCH_PATH):
Andrew Lambcd33f702020-06-11 10:45:16 -06001391 touch_fw = _build_touch_file_config(configs, project_name)
Andrew Lambcd33f702020-06-11 10:45:16 -06001392 arc_hw_feature_files = _write_arc_hardware_feature_files(
1393 configs, output_dir, build_root_dir)
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001394 arc_media_profile_files = _write_arc_media_profile_files(
1395 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -05001396 config_files = ConfigFiles(
C Shapiro5bf23a72020-04-24 11:40:17 -05001397 arc_hw_features=arc_hw_feature_files,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001398 arc_media_profiles=arc_media_profile_files,
C Shapiro2b6d5332020-05-06 17:51:35 -05001399 touch_fw=touch_fw,
David Burger8ee9b4d2020-06-16 17:40:21 -06001400 dptf_map=dptf_map,
David Burgerceeb68a2020-09-03 11:31:10 -06001401 camera_map=camera_map,
1402 wifi_sar_map=wifi_sar_map)
Andrew Lambcd33f702020-06-11 10:45:16 -06001403 write_output(_transform_build_configs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -06001404
1405
1406def main(argv=None):
1407 """Main program which parses args and runs
1408
1409 Args:
1410 argv: List of command line arguments, if None uses sys.argv.
1411 """
1412 if argv is None:
1413 argv = sys.argv[1:]
Andrew Lambcd33f702020-06-11 10:45:16 -06001414 opts = parse_args(argv)
David Burger7fd1dbe2020-03-26 09:26:55 -06001415 Main(opts.project_configs, opts.program_config, opts.output)
1416
1417
1418if __name__ == '__main__':
1419 sys.exit(main(sys.argv[1:]))