blob: fed0e6ffdad1d3a4d945e30c2ae7bd7a9ebf7760 [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(),
184 'edge':
185 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
Andrew Lamb2e641e22020-06-15 12:30:41 -0600195 return sorted([f'--{k}={v}' if v else f'--{k}' for k, v in flags.items()])
Andrew Lamb319cc922020-06-15 10:45:46 -0600196
197
198def _build_ui(config: Config) -> dict:
199 """Builds the 'ui' property from cros_config_schema."""
200 return {'extra-ash-flags': _build_ash_flags(config)}
201
202
David Burger07af5242020-08-11 11:08:25 -0600203def _build_bluetooth(config):
C Shapiro90fda252020-04-17 14:34:57 -0500204 bt_flags = config.sw_config.bluetooth_config.flags
205 # Convert to native map (from proto wrapper)
206 bt_flags_map = dict(bt_flags)
207 result = {}
208 if bt_flags_map:
209 result['flags'] = bt_flags_map
C Shapiro90fda252020-04-17 14:34:57 -0500210 return result
211
David Burger7fd1dbe2020-03-26 09:26:55 -0600212
David Burgerceeb68a2020-09-03 11:31:10 -0600213def _build_ath10k_config(ath10k_config):
214 """Builds the wifi configuration for the ath10k driver.
215
216 Args:
217 ath10k_config: Ath10kConfig config.
218
219 Returns:
220 wifi configuration for the ath10k driver.
221 """
David Burgerec753912020-08-10 12:59:11 -0600222 result = {}
David Burgerec753912020-08-10 12:59:11 -0600223
David Burgerceeb68a2020-09-03 11:31:10 -0600224 def power_chain(power):
225 return {
226 'limit-2g': power.limit_2g,
227 'limit-5g': power.limit_5g,
228 }
David Burgerec753912020-08-10 12:59:11 -0600229
David Burgerceeb68a2020-09-03 11:31:10 -0600230 result['tablet-mode-power-table-ath10k'] = power_chain(
231 ath10k_config.tablet_mode_power_table)
232 result['non-tablet-mode-power-table-ath10k'] = power_chain(
233 ath10k_config.non_tablet_mode_power_table)
David Burgerec753912020-08-10 12:59:11 -0600234 return result
235
236
David Burgerceeb68a2020-09-03 11:31:10 -0600237def _build_rtw88_config(rtw88_config):
238 """Builds the wifi configuration for the rtw88 driver.
239
240 Args:
241 rtw88_config: Rtw88Config config.
242
243 Returns:
244 wifi configuration for the rtw88 driver.
245 """
246 result = {}
247
248 def power_chain(power):
249 return {
250 'limit-2g': power.limit_2g,
251 'limit-5g-1': power.limit_5g_1,
252 'limit-5g-3': power.limit_5g_3,
253 'limit-5g-4': power.limit_5g_4,
254 }
255
256 result['tablet-mode-power-table-rtw'] = power_chain(
257 rtw88_config.tablet_mode_power_table)
258 result['non-tablet-mode-power-table-rtw'] = power_chain(
259 rtw88_config.non_tablet_mode_power_table)
260
261 def offsets(offset):
262 return {
263 'offset-2g': offset.offset_2g,
264 'offset-5g': offset.offset_5g,
265 }
266
267 result['geo-offsets-fcc'] = offsets(rtw88_config.offset_fcc)
268 result['geo-offsets-eu'] = offsets(rtw88_config.offset_eu)
269 result['geo-offsets-rest-of-world'] = offsets(rtw88_config.offset_other)
270 return result
271
272
273def _build_intel_config(config, config_files):
274 """Builds the wifi configuration for the intel driver.
275
276 Args:
277 config: Config namedtuple
278 config_files: Map to look up the generated config files.
279
280 Returns:
281 wifi configuration for the intel driver.
282 """
283 design_name = config.hw_design.name.lower()
284 return config_files.wifi_sar_map.get(design_name)
285
286
287def _build_wifi(config, config_files):
288 """Builds the wifi configuration.
289
290 Args:
291 config: Config namedtuple
292 config_files: Map to look up the generated config files.
293
294 Returns:
295 wifi configuration.
296 """
297 config_field = config.sw_config.wifi_config.WhichOneof('wifi_config')
298 if config_field == 'ath10k_config':
299 return _build_ath10k_config(config.sw_config.wifi_config.ath10k_config)
300 if config_field == 'rtw88_config':
301 return _build_rtw88_config(config.sw_config.wifi_config.rtw88_config)
302 if config_field == 'intel_config':
303 return _build_intel_config(config, config_files)
304 return {}
305
306
Andrew Lambcd33f702020-06-11 10:45:16 -0600307def _build_fingerprint(hw_topology):
308 if not hw_topology.HasField('fingerprint'):
309 return None
310
311 fp = hw_topology.fingerprint.hardware_feature.fingerprint
312 result = {}
313 if fp.location != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
314 location = fp.Location.DESCRIPTOR.values_by_number[fp.location].name
315 result['sensor-location'] = location.lower().replace('_', '-')
316 if fp.board:
317 result['board'] = fp.board
Tom Hughesdfc35402020-06-29 16:02:09 -0700318 if fp.ro_version:
319 result['ro-version'] = fp.ro_version
320
Andrew Lambcd33f702020-06-11 10:45:16 -0600321 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600322
323
Trent Beginf067ccb2020-08-12 12:33:53 -0600324def _build_hardware_properties(hw_topology):
325 if not hw_topology.HasField('form_factor'):
326 return None
327
328 form_factor = hw_topology.form_factor.hardware_feature.form_factor.form_factor
329 result = {}
330 if form_factor in [
331 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
332 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE,
333 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
334 ]:
335 result['psu-type'] = "AC_only"
336 else:
337 result['psu-type'] = "battery"
338
339 result['has-backlight'] = form_factor not in [
340 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
341 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
342 ]
343
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100344 form_factor_names = {
Nikolai Artemievaf103a32021-02-15 14:37:16 +1100345 topology_pb2.HardwareFeatures.FormFactor.CLAMSHELL: "CHROMEBOOK",
346 topology_pb2.HardwareFeatures.FormFactor.CONVERTIBLE: "CHROMEBOOK",
347 topology_pb2.HardwareFeatures.FormFactor.DETACHABLE: "CHROMEBOOK",
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100348 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE: "CHROMEBASE",
Nikolai Artemievaf103a32021-02-15 14:37:16 +1100349 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX: "CHROMEBOX",
350 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT: "CHROMEBIT",
351 topology_pb2.HardwareFeatures.FormFactor.CHROMESLATE: "CHROMEBOOK",
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100352 }
353 if form_factor in form_factor_names:
354 result['form-factor'] = form_factor_names[form_factor]
355
Trent Beginf067ccb2020-08-12 12:33:53 -0600356 return result
357
358
Andrew Lambcd33f702020-06-11 10:45:16 -0600359def _fw_bcs_path(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600360 if payload and payload.firmware_image_name:
YH Lin873742a2021-03-02 07:02:31 -0800361 return 'bcs://%s.%d.%d.%d.tbz2' % (
362 payload.firmware_image_name, payload.version.major,
363 payload.version.minor, payload.version.patch)
David Burger7fd1dbe2020-03-26 09:26:55 -0600364
Andrew Lambcd33f702020-06-11 10:45:16 -0600365 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600366
Andrew Lambcd33f702020-06-11 10:45:16 -0600367
368def _fw_build_target(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600369 if payload:
370 return payload.build_target_name
371
Andrew Lambcd33f702020-06-11 10:45:16 -0600372 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600373
Andrew Lambcd33f702020-06-11 10:45:16 -0600374
375def _build_firmware(config):
David Burgerb70b6762020-05-21 12:14:59 -0600376 """Returns firmware config, or None if no build targets."""
Andrew Lamb3da156d2020-04-16 16:00:56 -0600377 fw_payload_config = config.sw_config.firmware
378 fw_build_config = config.sw_config.firmware_build_config
379 main_ro = fw_payload_config.main_ro_payload
380 main_rw = fw_payload_config.main_rw_payload
381 ec_ro = fw_payload_config.ec_ro_payload
382 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600383
384 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600385
David Burger8ee9b4d2020-06-16 17:40:21 -0600386 _upsert(fw_build_config.build_targets.depthcharge, build_targets,
387 'depthcharge')
388 _upsert(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
389 _upsert(fw_build_config.build_targets.ec, build_targets, 'ec')
390 _upsert(
Andrew Lambf8954ee2020-04-21 10:24:40 -0600391 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
David Burger8ee9b4d2020-06-16 17:40:21 -0600392 _upsert(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
YH Lind4809502021-04-06 13:46:40 -0700393 _upsert(fw_build_config.build_targets.zephyr_ec, build_targets, 'zephyr-ec')
David Burger7fd1dbe2020-03-26 09:26:55 -0600394
David Burgerb70b6762020-05-21 12:14:59 -0600395 if not build_targets:
396 return None
397
David Burger7fd1dbe2020-03-26 09:26:55 -0600398 result = {
C Shapirod5545f12020-11-30 16:37:04 -0600399 'bcs-overlay': 'overlay-%s-private' % config.program.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600400 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600401 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600402
David Burger8ee9b4d2020-06-16 17:40:21 -0600403 _upsert(main_ro.firmware_image_name.lower(), result, 'image-name')
Andrew Lamb883fa042020-04-06 11:37:22 -0600404
David Burger8ee9b4d2020-06-16 17:40:21 -0600405 _upsert(_fw_bcs_path(main_ro), result, 'main-ro-image')
406 _upsert(_fw_bcs_path(main_rw), result, 'main-rw-image')
407 _upsert(_fw_bcs_path(ec_ro), result, 'ec-ro-image')
408 _upsert(_fw_bcs_path(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600409
David Burger8ee9b4d2020-06-16 17:40:21 -0600410 _upsert(
Andrew Lambf39fbe82020-04-13 16:14:33 -0600411 config.hw_design_config.hardware_features.fw_config.value,
412 result,
413 'firmware-config',
414 )
415
David Burger7fd1dbe2020-03-26 09:26:55 -0600416 return result
417
418
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000419def _build_fw_signing(config, whitelabel):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500420 if config.sw_config.firmware and config.device_signer_config:
David Burger68e0d142020-05-15 17:29:33 -0600421 hw_design = config.hw_design.name.lower()
Sam McNally2fc807f2020-07-16 18:13:53 +1000422 brand_scan_config = config.brand_config.scan_config
423 if brand_scan_config and brand_scan_config.whitelabel_tag:
424 signature_id = '%s-%s' % (hw_design, brand_scan_config.whitelabel_tag)
425 else:
426 signature_id = hw_design
427
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000428 result = {
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500429 'key-id': config.device_signer_config.key_id,
Sam McNally2fc807f2020-07-16 18:13:53 +1000430 'signature-id': signature_id,
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500431 }
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000432 if whitelabel:
433 result['sig-id-in-customization-id'] = True
434 return result
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500435 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600436
437
Andrew Lambcd33f702020-06-11 10:45:16 -0600438def _file(source, destination):
Andrew Lamb2413c982020-05-29 12:15:36 -0600439 return {'destination': destination, 'source': source}
David Burger7fd1dbe2020-03-26 09:26:55 -0600440
441
David Burger40dfe3a2020-06-18 17:09:13 -0600442def _file_v2(build_path, system_path):
443 return {'build-path': build_path, 'system-path': system_path}
444
445
Andrew Lambcd33f702020-06-11 10:45:16 -0600446def _build_audio(config):
David Burger178f3ef2020-06-26 12:11:57 -0600447 if not config.sw_config.audio_configs:
448 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600449 alsa_path = '/usr/share/alsa/ucm'
450 cras_path = '/etc/cras'
Judy Hsiao1ae95122020-12-23 15:39:50 +0800451 sound_card_init_path = '/etc/sound_card_init'
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800452 design_name = config.hw_design.name.lower()
David Burger43250662020-05-07 11:21:50 -0600453 program_name = config.program.name.lower()
David Burger7fd1dbe2020-03-26 09:26:55 -0600454 files = []
David Burger178f3ef2020-06-26 12:11:57 -0600455 ucm_suffix = None
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800456 sound_card_init_conf = None
457
David Burger178f3ef2020-06-26 12:11:57 -0600458 for audio in config.sw_config.audio_configs:
459 card = audio.card_name
460 card_with_suffix = audio.card_name
461 if audio.ucm_suffix:
462 # TODO: last ucm_suffix wins.
463 ucm_suffix = audio.ucm_suffix
464 card_with_suffix += '.' + audio.ucm_suffix
465 if audio.ucm_file:
466 files.append(
467 _file(audio.ucm_file,
468 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
469 if audio.ucm_master_file:
470 files.append(
471 _file(
472 audio.ucm_master_file, '%s/%s/%s.conf' %
Andrew Lamb2413c982020-05-29 12:15:36 -0600473 (alsa_path, card_with_suffix, card_with_suffix)))
David Burger178f3ef2020-06-26 12:11:57 -0600474 if audio.card_config_file:
475 files.append(
476 _file(audio.card_config_file,
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800477 '%s/%s/%s' % (cras_path, design_name, card)))
David Burger178f3ef2020-06-26 12:11:57 -0600478 if audio.dsp_file:
479 files.append(
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800480 _file(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, design_name)))
David Burger178f3ef2020-06-26 12:11:57 -0600481 if audio.module_file:
482 files.append(
483 _file(audio.module_file,
484 '/etc/modprobe.d/alsa-%s.conf' % program_name))
485 if audio.board_file:
486 files.append(
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800487 _file(audio.board_file, '%s/%s/board.ini' % (cras_path, design_name)))
Judy Hsiao1ae95122020-12-23 15:39:50 +0800488 if audio.sound_card_init_file:
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800489 sound_card_init_conf = design_name + ".yaml"
Judy Hsiao1ae95122020-12-23 15:39:50 +0800490 files.append(
491 _file(audio.sound_card_init_file,
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800492 '%s/%s.yaml' % (sound_card_init_path, design_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600493
494 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600495 'main': {
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800496 'cras-config-dir': design_name,
David Burger7fd1dbe2020-03-26 09:26:55 -0600497 'files': files,
498 }
499 }
David Burger178f3ef2020-06-26 12:11:57 -0600500
501 if ucm_suffix:
502 result['main']['ucm-suffix'] = ucm_suffix
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800503 if sound_card_init_conf:
504 result['main']['sound-card-init-conf'] = sound_card_init_conf
David Burger599ff7b2020-04-06 16:29:31 -0600505
506 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600507
508
Andrew Lambcd33f702020-06-11 10:45:16 -0600509def _build_camera(hw_topology):
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800510 camera_pb = topology_pb2.HardwareFeatures.Camera
511 camera = hw_topology.camera.hardware_feature.camera
512 result = {'count': len(camera.devices)}
513 if camera.devices:
514 result['devices'] = []
515 for device in camera.devices:
516 interface = {
517 camera_pb.INTERFACE_USB: 'usb',
518 camera_pb.INTERFACE_MIPI: 'mipi',
519 }[device.interface]
520 facing = {
521 camera_pb.FACING_FRONT: 'front',
522 camera_pb.FACING_BACK: 'back',
523 }[device.facing]
524 orientation = {
525 camera_pb.ORIENTATION_0: 0,
526 camera_pb.ORIENTATION_90: 90,
527 camera_pb.ORIENTATION_180: 180,
528 camera_pb.ORIENTATION_270: 270,
529 }[device.orientation]
530 flags = {
531 'support-1080p':
532 bool(device.flags & camera_pb.FLAGS_SUPPORT_1080P),
533 'support-autofocus':
534 bool(device.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS),
535 }
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100536 dev = {
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800537 'interface': interface,
538 'facing': facing,
539 'orientation': orientation,
540 'flags': flags,
541 'ids': list(device.ids),
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100542 }
543 if device.privacy_switch != topology_pb2.HardwareFeatures.PRESENT_UNKNOWN:
544 dev['has-privacy-switch'] = device.privacy_switch == topology_pb2.HardwareFeatures.PRESENT
545 result['devices'].append(dev)
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800546 return result
David Burger8aa8fa32020-04-14 08:30:34 -0600547
Andrew Lambcd33f702020-06-11 10:45:16 -0600548
549def _build_identity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600550 identity = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600551 _upsert(hw_scan_config.firmware_sku, identity, 'sku-id')
552 _upsert(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600553 # 'platform-name' is needed to support 'mosys platform name'. Clients should
Sean McAllister0b757772020-11-13 12:22:36 -0700554 # no longer require platform name, but set it here for backwards compatibility.
555 if program.mosys_platform_name:
556 _upsert(program.mosys_platform_name, identity, 'platform-name')
557 else:
558 _upsert(program.name, identity, 'platform-name')
559
David Burger7fd1dbe2020-03-26 09:26:55 -0600560 # ARM architecture
David Burger8ee9b4d2020-06-16 17:40:21 -0600561 _upsert(hw_scan_config.device_tree_compatible_match, identity,
562 'device-tree-compatible-match')
David Burger7fd1dbe2020-03-26 09:26:55 -0600563
564 if brand_scan_config:
David Burger8ee9b4d2020-06-16 17:40:21 -0600565 _upsert(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
David Burger7fd1dbe2020-03-26 09:26:55 -0600566
567 return identity
568
569
Andrew Lambcd33f702020-06-11 10:45:16 -0600570def _lookup(id_value, id_map):
571 if not id_value.value:
572 return None
573
574 key = id_value.value
575 if key in id_map:
576 return id_map[id_value.value]
577 error = 'Failed to lookup %s with value: %s' % (
578 id_value.__class__.__name__.replace('Id', ''), key)
579 print(error)
580 print('Check the config contents provided:')
581 printer = pprint.PrettyPrinter(indent=4)
582 printer.pprint(id_map)
583 raise Exception(error)
David Burger7fd1dbe2020-03-26 09:26:55 -0600584
585
Andrew Lambcd33f702020-06-11 10:45:16 -0600586def _build_touch_file_config(config, project_name):
Sean McAllistereaf10b72020-08-03 13:41:06 -0600587 partners = {x.id.value: x for x in config.partner_list}
C Shapiro2b6d5332020-05-06 17:51:35 -0500588 files = []
589 for comp in config.components:
C Shapiro4813be62020-05-13 17:31:58 -0500590 touch = comp.touchscreen
591 # Everything is the same for Touch screen/pad, except different fields
592 if comp.HasField('touchpad'):
593 touch = comp.touchpad
594 if touch.product_id:
Andrew Lambcd33f702020-06-11 10:45:16 -0600595 vendor = _lookup(comp.manufacturer_id, partners)
C Shapiro2b6d5332020-05-06 17:51:35 -0500596 if not vendor:
Andrew Lamb2413c982020-05-29 12:15:36 -0600597 raise Exception("Manufacturer must be set for touch device %s" %
598 comp.id.value)
C Shapiro2b6d5332020-05-06 17:51:35 -0500599
C Shapiro4813be62020-05-13 17:31:58 -0500600 product_id = touch.product_id
601 fw_version = touch.fw_version
C Shapiro2b6d5332020-05-06 17:51:35 -0500602
C Shapiro2b6d5332020-05-06 17:51:35 -0500603 file_name = "%s_%s.bin" % (product_id, fw_version)
604 fw_file_path = os.path.join(TOUCH_PATH, vendor.name, file_name)
605
606 if not os.path.exists(fw_file_path):
Andrew Lamb2413c982020-05-29 12:15:36 -0600607 raise Exception("Touchscreen fw bin file doesn't exist at: %s" %
608 fw_file_path)
C Shapiro2b6d5332020-05-06 17:51:35 -0500609
C Shapiro303cece2020-07-22 07:15:21 -0500610 touch_vendor = vendor.touch_vendor
611 sym_link = touch_vendor.symlink_file_format.format(
612 vendor_name=vendor.name,
613 vendor_id=touch_vendor.vendor_id,
614 product_id=product_id,
615 fw_version=fw_version,
616 product_series=touch.product_series)
617
618 dest = "%s_%s" % (vendor.name, file_name)
619 if touch_vendor.destination_file_format:
620 dest = touch_vendor.destination_file_format.format(
621 vendor_name=vendor.name,
622 vendor_id=touch_vendor.vendor_id,
623 product_id=product_id,
624 fw_version=fw_version,
625 product_series=touch.product_series)
626
C Shapiro2b6d5332020-05-06 17:51:35 -0500627 files.append({
C Shapiro303cece2020-07-22 07:15:21 -0500628 "destination": os.path.join("/opt/google/touch/firmware", dest),
YH Lin9160fc52020-07-22 16:35:28 -0700629 "source": os.path.join(project_name, fw_file_path),
630 "symlink": os.path.join("/lib/firmware", sym_link),
C Shapiro2b6d5332020-05-06 17:51:35 -0500631 })
632
633 result = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600634 _upsert(files, result, 'files')
C Shapiro2b6d5332020-05-06 17:51:35 -0500635 return result
636
637
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000638def _build_modem(config):
639 """Returns the cellular modem configuration, or None if absent."""
640 hw_features = config.hw_design_config.hardware_features
641 lte_support = _any_present([hw_features.lte.present])
642 if not lte_support:
643 return None
644 return {'firmware-variant': config.hw_design.name.lower()}
645
646
David Burgerceeb68a2020-09-03 11:31:10 -0600647def _sw_config(sw_configs, design_config_id):
648 """Returns the correct software config for `design_config_id`.
649
650 Returns the correct software config match for `design_config_id`. If no such
651 config or multiple such configs are found an exception is raised.
652 """
653 sw_config_matches = [
654 x for x in sw_configs if x.design_config_id.value == design_config_id
655 ]
656 if len(sw_config_matches) == 1:
657 return sw_config_matches[0]
658 if len(sw_config_matches) > 1:
659 raise ValueError('Multiple software configs found for: %s' %
660 design_config_id)
661 raise ValueError('Software config is required for: %s' % design_config_id)
662
663
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000664def _is_whitelabel(brand_configs, device_brands):
665 for device_brand in device_brands:
666 if device_brand.id.value in brand_configs:
667 brand_scan_config = brand_configs[device_brand.id.value].scan_config
668 if brand_scan_config and brand_scan_config.whitelabel_tag:
669 return True
670 return False
671
672
David Burgerceeb68a2020-09-03 11:31:10 -0600673def _transform_build_configs(config,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800674 config_files=ConfigFiles({}, {}, {}, {}, {}, {})):
Andrew Lambcd33f702020-06-11 10:45:16 -0600675 # pylint: disable=too-many-locals,too-many-branches
Sean McAllistereaf10b72020-08-03 13:41:06 -0600676 partners = {x.id.value: x for x in config.partner_list}
Sean McAllisterf38d1e92020-08-03 13:57:53 -0600677 programs = {x.id.value: x for x in config.program_list}
David Burger7fd1dbe2020-03-26 09:26:55 -0600678 sw_configs = list(config.software_configs)
Andrew Lambcd33f702020-06-11 10:45:16 -0600679 brand_configs = {x.brand_id.value: x for x in config.brand_configs}
David Burger7fd1dbe2020-03-26 09:26:55 -0600680
681 results = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600682 for hw_design in config.design_list:
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600683 if config.device_brand_list:
Andrew Lamb2413c982020-05-29 12:15:36 -0600684 device_brands = [
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600685 x for x in config.device_brand_list
Andrew Lamb2413c982020-05-29 12:15:36 -0600686 if x.design_id.value == hw_design.id.value
687 ]
David Burger7fd1dbe2020-03-26 09:26:55 -0600688 else:
689 device_brands = [device_brand_pb2.DeviceBrand()]
690
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000691 whitelabel = _is_whitelabel(brand_configs, device_brands)
692
David Burger7fd1dbe2020-03-26 09:26:55 -0600693 for device_brand in device_brands:
694 # Brand config can be empty since platform JSON config allows it
695 brand_config = brand_config_pb2.BrandConfig()
696 if device_brand.id.value in brand_configs:
697 brand_config = brand_configs[device_brand.id.value]
698
699 for hw_design_config in hw_design.configs:
David Burgerceeb68a2020-09-03 11:31:10 -0600700 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
Andrew Lambcd33f702020-06-11 10:45:16 -0600701 program = _lookup(hw_design.program_id, programs)
C Shapiroadefd7c2020-05-19 16:37:21 -0500702 signer_configs_by_design = {}
703 signer_configs_by_brand = {}
704 for signer_config in program.device_signer_configs:
705 design_id = signer_config.design_id.value
706 brand_id = signer_config.brand_id.value
707 if design_id:
708 signer_configs_by_design[design_id] = signer_config
709 elif brand_id:
710 signer_configs_by_brand[brand_id] = signer_config
711 else:
712 raise Exception('No ID found for signer config: %s' % signer_config)
713
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500714 device_signer_config = None
C Shapiroadefd7c2020-05-19 16:37:21 -0500715 if signer_configs_by_design or signer_configs_by_brand:
716 design_id = hw_design.id.value
717 brand_id = device_brand.id.value
718 if design_id in signer_configs_by_design:
719 device_signer_config = signer_configs_by_design[design_id]
720 elif brand_id in signer_configs_by_brand:
721 device_signer_config = signer_configs_by_brand[brand_id]
722 else:
723 # Assume that if signer configs are set, every config is setup
Andrew Lamb2413c982020-05-29 12:15:36 -0600724 raise Exception('Signer config missing for design: %s, brand: %s' %
725 (design_id, brand_id))
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500726
Andrew Lambcd33f702020-06-11 10:45:16 -0600727 transformed_config = _transform_build_config(
C Shapiro90fda252020-04-17 14:34:57 -0500728 Config(
729 program=program,
730 hw_design=hw_design,
Andrew Lambcd33f702020-06-11 10:45:16 -0600731 odm=_lookup(hw_design.odm_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500732 hw_design_config=hw_design_config,
733 device_brand=device_brand,
734 device_signer_config=device_signer_config,
Andrew Lambcd33f702020-06-11 10:45:16 -0600735 oem=_lookup(device_brand.oem_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500736 sw_config=sw_config,
C Shapirod5545f12020-11-30 16:37:04 -0600737 brand_config=brand_config), config_files, whitelabel)
David Burger7fd1dbe2020-03-26 09:26:55 -0600738
Andrew Lamb2413c982020-05-29 12:15:36 -0600739 config_json = json.dumps(
740 transformed_config,
741 sort_keys=True,
742 indent=2,
743 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600744
745 if config_json not in results:
746 results[config_json] = transformed_config
747
748 return list(results.values())
749
750
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000751def _transform_build_config(config, config_files, whitelabel):
David Burger7fd1dbe2020-03-26 09:26:55 -0600752 """Transforms Config instance into target platform JSON schema.
753
754 Args:
755 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500756 config_files: Map to look up the generated config files.
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000757 whitelabel: Whether the config is for a whitelabel design
David Burger7fd1dbe2020-03-26 09:26:55 -0600758
759 Returns:
760 Unique config payload based on the platform JSON schema.
761 """
762 result = {
Andrew Lamb2413c982020-05-29 12:15:36 -0600763 'identity':
Andrew Lambcd33f702020-06-11 10:45:16 -0600764 _build_identity(config.sw_config.id_scan_config, config.program,
765 config.brand_config.scan_config),
Andrew Lamb2413c982020-05-29 12:15:36 -0600766 'name':
767 config.hw_design.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600768 }
769
David Burger8ee9b4d2020-06-16 17:40:21 -0600770 _upsert(_build_arc(config, config_files), result, 'arc')
771 _upsert(_build_audio(config), result, 'audio')
David Burger07af5242020-08-11 11:08:25 -0600772 _upsert(_build_bluetooth(config), result, 'bluetooth')
David Burgerceeb68a2020-09-03 11:31:10 -0600773 _upsert(_build_wifi(config, config_files), result, 'wifi')
Andrew Lambca279902020-08-06 10:13:42 -0600774 _upsert(config.brand_config.wallpaper, result, 'wallpaper')
C Shapiro2e97aad2020-11-16 11:58:10 -0600775 _upsert(config.brand_config.regulatory_label, result, 'regulatory-label')
David Burger8ee9b4d2020-06-16 17:40:21 -0600776 _upsert(config.device_brand.brand_code, result, 'brand-code')
777 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600778 _build_camera(config.hw_design_config.hardware_topology), result,
779 'camera')
David Burger8ee9b4d2020-06-16 17:40:21 -0600780 _upsert(_build_firmware(config), result, 'firmware')
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000781 _upsert(_build_fw_signing(config, whitelabel), result, 'firmware-signing')
David Burger8ee9b4d2020-06-16 17:40:21 -0600782 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600783 _build_fingerprint(config.hw_design_config.hardware_topology), result,
Andrew Lamb2413c982020-05-29 12:15:36 -0600784 'fingerprint')
Andrew Lamb0d236ab2020-06-30 12:30:20 -0600785 _upsert(_build_ui(config), result, 'ui')
David Burger7fd1dbe2020-03-26 09:26:55 -0600786 power_prefs = config.sw_config.power_config.preferences
787 power_prefs_map = dict(
Andrew Lamb2413c982020-05-29 12:15:36 -0600788 (x.replace('_', '-'), power_prefs[x]) for x in power_prefs)
David Burger8ee9b4d2020-06-16 17:40:21 -0600789 _upsert(power_prefs_map, result, 'power')
790 if config_files.camera_map:
791 camera_file = config_files.camera_map.get(config.hw_design.name, {})
792 _upsert(camera_file, result, 'camera')
David Burger52c9d322020-06-09 07:16:18 -0600793 if config_files.dptf_map:
794 # Prefer design specific if found, if not fall back to project wide config
795 # mapped under the empty string.
796 if config_files.dptf_map.get(config.hw_design.name):
797 dptf_file = config_files.dptf_map[config.hw_design.name]
798 else:
799 dptf_file = config_files.dptf_map.get('')
David Burger8ee9b4d2020-06-16 17:40:21 -0600800 _upsert(dptf_file, result, 'thermal')
801 _upsert(config_files.touch_fw, result, 'touch')
Trent Beginf067ccb2020-08-12 12:33:53 -0600802 _upsert(
803 _build_hardware_properties(config.hw_design_config.hardware_topology),
804 result, 'hardware-properties')
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000805 _upsert(_build_modem(config), result, 'modem')
David Burger7fd1dbe2020-03-26 09:26:55 -0600806
807 return result
808
809
Andrew Lambcd33f702020-06-11 10:45:16 -0600810def write_output(configs, output=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600811 """Writes a list of configs to platform JSON format.
812
813 Args:
814 configs: List of config dicts defined in cros_config_schema.yaml
815 output: Target file output (if None, prints to stdout)
816 """
Andrew Lamb2413c982020-05-29 12:15:36 -0600817 json_output = json.dumps({'chromeos': {
818 'configs': configs,
819 }},
820 sort_keys=True,
821 indent=2,
822 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600823 if output:
824 with open(output, 'w') as output_stream:
825 # Using print function adds proper trailing newline.
826 print(json_output, file=output_stream)
827 else:
828 print(json_output)
829
830
Andrew Lambcd33f702020-06-11 10:45:16 -0600831def _feature(name, present):
C Shapiro5bf23a72020-04-24 11:40:17 -0500832 attrib = {'name': name}
833 if present:
834 return etree.Element('feature', attrib=attrib)
Andrew Lambcd33f702020-06-11 10:45:16 -0600835
836 return etree.Element('unavailable-feature', attrib=attrib)
C Shapiro5bf23a72020-04-24 11:40:17 -0500837
838
Andrew Lambcd33f702020-06-11 10:45:16 -0600839def _any_present(features):
Andrew Lamb2413c982020-05-29 12:15:36 -0600840 return topology_pb2.HardwareFeatures.PRESENT in features
C Shapiro5bf23a72020-04-24 11:40:17 -0500841
842
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800843def _get_formatted_config_id(design_config):
C Shapiro5bf23a72020-04-24 11:40:17 -0500844 return design_config.id.value.lower().replace(':', '_')
845
846
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800847def _write_file(output_dir, file_name, file_content):
David Burger77a1d312020-05-23 16:05:45 -0600848 os.makedirs(output_dir, exist_ok=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800849 output = '{}/{}'.format(output_dir, file_name)
C Shapiroea33cff2020-05-11 13:32:05 -0500850 with open(output, 'wb') as f:
851 f.write(file_content)
852
853
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800854def _get_arc_camera_features(camera):
855 """Gets camera related features for ARC hardware_features.xml from camera
856 topology. Check
857 https://developer.android.com/reference/android/content/pm/PackageManager#FEATURE_CAMERA
858 and CTS android.app.cts.SystemFeaturesTest#testCameraFeatures for the correct
859 settings.
860
861 Args:
862 camera: A HardwareFeatures.Camera proto message.
863 Returns:
864 list of camera related ARC features as XML elements.
865 """
866 camera_pb = topology_pb2.HardwareFeatures.Camera
867
Ren-Pei Zeng9b5682d2020-10-14 17:37:30 +0800868 count = len(camera.devices)
869 has_front_camera = any(
870 (d.facing == camera_pb.FACING_FRONT for d in camera.devices))
871 has_back_camera = any(
872 (d.facing == camera_pb.FACING_BACK for d in camera.devices))
873 has_autofocus_back_camera = any((d.facing == camera_pb.FACING_BACK and
874 d.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS
875 for d in camera.devices))
876 # Assumes MIPI cameras support FULL-level.
877 # TODO(kamesan): Setting this in project configs when there's an exception.
878 has_level_full_camera = any(
879 (d.interface == camera_pb.INTERFACE_MIPI for d in camera.devices))
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800880
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800881 return [
882 _feature('android.hardware.camera', has_back_camera),
883 _feature('android.hardware.camera.any', count > 0),
884 _feature('android.hardware.camera.autofocus', has_autofocus_back_camera),
885 _feature('android.hardware.camera.capability.manual_post_processing',
886 has_level_full_camera),
887 _feature('android.hardware.camera.capability.manual_sensor',
888 has_level_full_camera),
889 _feature('android.hardware.camera.front', has_front_camera),
890 _feature('android.hardware.camera.level.full', has_level_full_camera),
891 ]
892
893
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800894def _generate_arc_hardware_features(hw_features):
895 """Generates ARC hardware_features.xml file content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500896
897 Args:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800898 hw_features: HardwareFeatures proto message.
C Shapiro5bf23a72020-04-24 11:40:17 -0500899 Returns:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800900 bytes of the hardware_features.xml content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500901 """
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800902 touchscreen = _any_present([hw_features.screen.touch_support])
903 acc = hw_features.accelerometer
904 gyro = hw_features.gyroscope
905 compass = hw_features.magnetometer
906 light_sensor = hw_features.light_sensor
907 root = etree.Element('permissions')
908 root.extend(
909 _get_arc_camera_features(hw_features.camera) + [
910 _feature(
911 'android.hardware.sensor.accelerometer',
912 _any_present([acc.lid_accelerometer, acc.base_accelerometer])),
913 _feature('android.hardware.sensor.gyroscope',
914 _any_present([gyro.lid_gyroscope, gyro.base_gyroscope])),
915 _feature(
916 'android.hardware.sensor.compass',
917 _any_present(
918 [compass.lid_magnetometer, compass.base_magnetometer])),
919 _feature(
920 'android.hardware.sensor.light',
921 _any_present([
922 light_sensor.lid_lightsensor, light_sensor.base_lightsensor
923 ])),
924 _feature('android.hardware.touchscreen', touchscreen),
925 _feature('android.hardware.touchscreen.multitouch', touchscreen),
926 _feature('android.hardware.touchscreen.multitouch.distinct',
927 touchscreen),
928 _feature('android.hardware.touchscreen.multitouch.jazzhand',
929 touchscreen),
930 ])
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800931 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
932
933
934def _generate_arc_media_profiles(hw_features, sw_config):
935 """Generates ARC media_profiles.xml file content.
936
937 Args:
938 hw_features: HardwareFeatures proto message.
939 sw_config: SoftwareConfig proto message.
940 Returns:
941 bytes of the media_profiles.xml content, or None if |sw_config| disables the
Ren-Pei Zengb55e4312020-11-18 17:03:01 +0800942 generation or there's no camera.
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800943 """
944
945 def _gen_camcorder_profiles(camera_id, resolutions):
946 elem = etree.Element(
947 'CamcorderProfiles', attrib={'cameraId': str(camera_id)})
948 for width, height in resolutions:
949 elem.extend([
950 _gen_encoder_profile(width, height, False),
951 _gen_encoder_profile(width, height, True),
952 ])
953 elem.extend([
954 etree.Element('ImageEncoding', attrib={'quality': '90'}),
955 etree.Element('ImageEncoding', attrib={'quality': '80'}),
956 etree.Element('ImageEncoding', attrib={'quality': '70'}),
957 etree.Element('ImageDecoding', attrib={'memCap': '20000000'}),
958 ])
959 return elem
960
961 def _gen_encoder_profile(width, height, timelapse):
962 elem = etree.Element(
963 'EncoderProfile',
964 attrib={
965 'quality': ('timelapse' if timelapse else '') + str(height) + 'p',
966 'fileFormat': 'mp4',
967 'duration': '60',
968 })
969 elem.append(
970 etree.Element(
971 'Video',
972 attrib={
973 'codec': 'h264',
974 'bitRate': '8000000',
975 'width': str(width),
976 'height': str(height),
977 'frameRate': '30',
978 }))
979 elem.append(
980 etree.Element(
981 'Audio',
982 attrib={
983 'codec': 'aac',
984 'bitRate': '96000',
985 'sampleRate': '44100',
986 'channels': '1',
987 }))
988 return elem
989
990 def _gen_video_encoder_cap(name, min_bit_rate, max_bit_rate):
991 return etree.Element(
992 'VideoEncoderCap',
993 attrib={
994 'name': name,
995 'enabled': 'true',
996 'minBitRate': str(min_bit_rate),
997 'maxBitRate': str(max_bit_rate),
998 'minFrameWidth': '320',
999 'maxFrameWidth': '1920',
1000 'minFrameHeight': '240',
1001 'maxFrameHeight': '1080',
1002 'minFrameRate': '15',
1003 'maxFrameRate': '30',
1004 })
1005
1006 def _gen_audio_encoder_cap(name, min_bit_rate, max_bit_rate, min_sample_rate,
1007 max_sample_rate):
1008 return etree.Element(
1009 'AudioEncoderCap',
1010 attrib={
1011 'name': name,
1012 'enabled': 'true',
1013 'minBitRate': str(min_bit_rate),
1014 'maxBitRate': str(max_bit_rate),
1015 'minSampleRate': str(min_sample_rate),
1016 'maxSampleRate': str(max_sample_rate),
1017 'minChannels': '1',
1018 'maxChannels': '1',
1019 })
1020
1021 camera_config = sw_config.camera_config
1022 if not camera_config.generate_media_profiles:
1023 return None
1024
1025 camera_pb = topology_pb2.HardwareFeatures.Camera
1026 root = etree.Element('MediaSettings')
1027 camera_id = 0
1028 for facing in [camera_pb.FACING_BACK, camera_pb.FACING_FRONT]:
1029 camera_device = next(
1030 (d for d in hw_features.camera.devices if d.facing == facing), None)
1031 if camera_device is None:
1032 continue
1033 if camera_config.camcorder_resolutions:
1034 resolutions = [
1035 (r.width, r.height) for r in camera_config.camcorder_resolutions
1036 ]
1037 else:
1038 resolutions = [(1280, 720)]
1039 if camera_device.flags & camera_pb.FLAGS_SUPPORT_1080P:
1040 resolutions.append((1920, 1080))
1041 root.append(_gen_camcorder_profiles(camera_id, resolutions))
1042 camera_id += 1
Ren-Pei Zengb55e4312020-11-18 17:03:01 +08001043 # media_profiles.xml should have at least one CamcorderProfiles.
1044 if camera_id == 0:
1045 return None
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001046
1047 root.extend([
1048 etree.Element('EncoderOutputFileFormat', attrib={'name': '3gp'}),
1049 etree.Element('EncoderOutputFileFormat', attrib={'name': 'mp4'}),
1050 _gen_video_encoder_cap('h264', 64000, 17000000),
1051 _gen_video_encoder_cap('h263', 64000, 1000000),
1052 _gen_video_encoder_cap('m4v', 64000, 2000000),
1053 _gen_audio_encoder_cap('aac', 758, 288000, 8000, 48000),
1054 _gen_audio_encoder_cap('heaac', 8000, 64000, 16000, 48000),
1055 _gen_audio_encoder_cap('aaceld', 16000, 192000, 16000, 48000),
1056 _gen_audio_encoder_cap('amrwb', 6600, 23050, 16000, 16000),
1057 _gen_audio_encoder_cap('amrnb', 5525, 12200, 8000, 8000),
1058 etree.Element(
1059 'VideoDecoderCap', attrib={
1060 'name': 'wmv',
1061 'enabled': 'false'
1062 }),
1063 etree.Element(
1064 'AudioDecoderCap', attrib={
1065 'name': 'wma',
1066 'enabled': 'false'
1067 }),
1068 ])
Ren-Pei Zeng21708cc2020-11-17 11:14:07 +08001069
1070 dtd_path = os.path.dirname(__file__)
1071 dtd = etree.DTD(os.path.join(dtd_path, 'media_profiles.dtd'))
1072 if not dtd.validate(root):
1073 raise etree.DTDValidateError(
1074 'Invalid media_profiles.xml generated:\n{}'.format(dtd.error_log))
1075
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001076 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001077
1078
1079def _write_files_by_design_config(configs, output_dir, build_dir, system_dir,
1080 file_name_template, generate_file_content):
1081 """Writes generated files for each design config.
1082
1083 Args:
1084 configs: Source ConfigBundle to process.
1085 output_dir: Path to the generated output.
1086 build_dir: Path to the config file from portage's perspective.
1087 system_dir: Path to the config file in the target device.
1088 file_name_template: Template string of the config file name including one
1089 format()-style replacement field for the config id, e.g. 'config_{}.xml'.
1090 generate_file_content: Function to generate config file content from
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001091 HardwareFeatures and SoftwareConfig proto.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001092 Returns:
1093 dict that maps the formatted config id to the correct file.
1094 """
1095 # pylint: disable=too-many-arguments,too-many-locals
C Shapiro5bf23a72020-04-24 11:40:17 -05001096 result = {}
C Shapiroea33cff2020-05-11 13:32:05 -05001097 configs_by_design = {}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001098 for hw_design in configs.design_list:
C Shapiro5bf23a72020-04-24 11:40:17 -05001099 for design_config in hw_design.configs:
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001100 sw_config = _sw_config(configs.software_configs, design_config.id.value)
1101 config_content = generate_file_content(design_config.hardware_features,
1102 sw_config)
1103 if not config_content:
1104 continue
C Shapiroea33cff2020-05-11 13:32:05 -05001105 design_name = hw_design.name.lower()
C Shapiro5bf23a72020-04-24 11:40:17 -05001106
C Shapiroea33cff2020-05-11 13:32:05 -05001107 # Constructs the following map:
1108 # design_name -> config -> design_configs
1109 # This allows any of the following file naming schemes:
1110 # - All configs within a design share config (design_name prefix only)
1111 # - Nobody shares (full design_name and config id prefix needed)
1112 #
1113 # Having shared configs when possible makes code reviews easier around
1114 # the configs and makes debugging easier on the platform side.
C Shapiroea33cff2020-05-11 13:32:05 -05001115 arc_configs = configs_by_design.get(design_name, {})
1116 design_configs = arc_configs.get(config_content, [])
1117 design_configs.append(design_config)
1118 arc_configs[config_content] = design_configs
1119 configs_by_design[design_name] = arc_configs
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001120
C Shapiroea33cff2020-05-11 13:32:05 -05001121 for design_name, unique_configs in configs_by_design.items():
1122 for file_content, design_configs in unique_configs.items():
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001123 file_name = file_name_template.format(design_name)
Andrew Lamb2413c982020-05-29 12:15:36 -06001124 if len(unique_configs) == 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001125 _write_file(output_dir, file_name, file_content)
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001126
Andrew Lamb2413c982020-05-29 12:15:36 -06001127 for design_config in design_configs:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001128 config_id = _get_formatted_config_id(design_config)
Andrew Lamb2413c982020-05-29 12:15:36 -06001129 if len(unique_configs) > 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001130 file_name = file_name_template.format(config_id)
1131 _write_file(output_dir, file_name, file_content)
1132 result[config_id] = _file_v2('{}/{}'.format(build_dir, file_name),
1133 '{}/{}'.format(system_dir, file_name))
C Shapiro5bf23a72020-04-24 11:40:17 -05001134 return result
1135
1136
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001137def _write_arc_hardware_feature_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001138 return _write_files_by_design_config(
1139 configs, output_root_dir + '/arc', build_root_dir + '/arc', '/etc',
1140 'hardware_features_{}.xml',
1141 lambda hw_features, _: _generate_arc_hardware_features(hw_features))
1142
1143
1144def _write_arc_media_profile_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001145 return _write_files_by_design_config(configs, output_root_dir + '/arc',
1146 build_root_dir + '/arc', '/etc',
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001147 'media_profiles_{}.xml',
1148 _generate_arc_media_profiles)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001149
1150
Andrew Lambcd33f702020-06-11 10:45:16 -06001151def _read_config(path):
David Burgerd4f32962020-05-02 12:07:40 -06001152 """Reads a ConfigBundle proto from a json pb file.
David Burgere6f76222020-04-27 11:08:01 -06001153
1154 Args:
David Burgerd4f32962020-05-02 12:07:40 -06001155 path: Path to the file encoding the json pb proto.
David Burgere6f76222020-04-27 11:08:01 -06001156 """
1157 config = config_bundle_pb2.ConfigBundle()
1158 with open(path, 'r') as f:
1159 return json_format.Parse(f.read(), config)
1160
1161
Andrew Lambcd33f702020-06-11 10:45:16 -06001162def _merge_configs(configs):
David Burger7fd1dbe2020-03-26 09:26:55 -06001163 result = config_bundle_pb2.ConfigBundle()
1164 for config in configs:
1165 result.MergeFrom(config)
1166
1167 return result
1168
1169
David Burger1ba78a22020-06-18 18:42:47 -06001170def _camera_map(configs, project_name):
David Burger8ee9b4d2020-06-16 17:40:21 -06001171 """Produces a camera config map for the given configs.
1172
1173 Produces a map that maps from the design name to the camera config for that
1174 design.
1175
1176 Args:
1177 configs: Source ConfigBundle to process.
David Burger1ba78a22020-06-18 18:42:47 -06001178 project_name: Name of project processing for.
David Burger8ee9b4d2020-06-16 17:40:21 -06001179
1180 Returns:
1181 map from design name to camera config.
1182 """
1183 result = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -06001184 for design in configs.design_list:
David Burger8ee9b4d2020-06-16 17:40:21 -06001185 design_name = design.name
David Burger0d9e8462020-06-19 14:12:37 -06001186 config_path = CAMERA_CONFIG_SOURCE_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001187 if os.path.exists(config_path):
David Burger0d9e8462020-06-19 14:12:37 -06001188 destination = CAMERA_CONFIG_DEST_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001189 result[design_name] = {
David Burger1ba78a22020-06-18 18:42:47 -06001190 'config-file':
1191 _file_v2(os.path.join(project_name, config_path), destination),
David Burger8ee9b4d2020-06-16 17:40:21 -06001192 }
1193 return result
1194
1195
David Burger52c9d322020-06-09 07:16:18 -06001196def _dptf_map(configs, project_name):
1197 """Produces a dptf map for the given configs.
1198
1199 Produces a map that maps from design name to the dptf file config for that
1200 design. It looks for the dptf files at:
David Burger2f0d9522020-07-30 10:52:28 -06001201 DPTF_PATH + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001202 for a project wide config, that it maps under the empty string, and at:
David Burger2f0d9522020-07-30 10:52:28 -06001203 DPTF_PATH + '/' + design_name + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001204 for design specific configs that it maps under the design name.
1205
1206 Args:
1207 configs: Source ConfigBundle to process.
1208 project_name: Name of project processing for.
1209
1210 Returns:
David Burger8ee9b4d2020-06-16 17:40:21 -06001211 map from design name or empty string (project wide), to dptf config.
David Burger52c9d322020-06-09 07:16:18 -06001212 """
1213 result = {}
David Burger52c9d322020-06-09 07:16:18 -06001214 # Looking at top level for project wide, and then for each design name
1215 # for design specific.
Sean McAllisterf66887b2020-08-03 14:00:51 -06001216 dirs = [""] + [d.name for d in configs.design_list]
David Burger52c9d322020-06-09 07:16:18 -06001217 for directory in dirs:
David Burgera2252762020-07-09 15:09:49 -06001218 design = directory.lower()
1219 if os.path.exists(os.path.join(DPTF_PATH, design, DPTF_FILE)):
David Burger2f0d9522020-07-30 10:52:28 -06001220 project_dptf_path = os.path.join(project_name, design, DPTF_FILE)
David Burger52c9d322020-06-09 07:16:18 -06001221 dptf_file = {
1222 'dptf-dv':
1223 project_dptf_path,
1224 'files': [
1225 _file(
David Burgera2252762020-07-09 15:09:49 -06001226 os.path.join(project_name, DPTF_PATH, design, DPTF_FILE),
David Burger52c9d322020-06-09 07:16:18 -06001227 os.path.join('/etc/dptf', project_dptf_path))
1228 ]
1229 }
1230 result[directory] = dptf_file
1231 return result
1232
1233
David Burgerceeb68a2020-09-03 11:31:10 -06001234def _wifi_sar_map(configs, project_name, output_dir, build_root_dir):
1235 """Constructs a map from design name to wifi sar config for that design.
1236
1237 Constructs a map from design name to the wifi sar config for that design.
1238 In the process a wifi sar hex file is generated that the config points at.
1239 This mapping is only made for the intel wifi where the generated file is
1240 provided when building coreboot.
1241
1242 Args:
1243 configs: Source ConfigBundle to process.
1244 project_name: Name of project processing for.
1245 output_dir: Path to the generated output.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001246 build_root_dir: Path to the config file from portage's perspective.
David Burgerceeb68a2020-09-03 11:31:10 -06001247
1248 Returns:
1249 dict that maps the design name onto the wifi config for that design.
1250 """
1251 # pylint: disable=too-many-locals
1252 result = {}
1253 programs = {p.id.value: p for p in configs.program_list}
1254 sw_configs = list(configs.software_configs)
1255 for hw_design in configs.design_list:
1256 for hw_design_config in hw_design.configs:
1257 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
1258 if sw_config.wifi_config.HasField('intel_config'):
1259 sar_file_content = _create_intel_sar_file_content(
1260 sw_config.wifi_config.intel_config)
1261 design_name = hw_design.name.lower()
1262 program = _lookup(hw_design.program_id, programs)
1263 wifi_sar_id = _extract_fw_config_value(hw_design_config, program,
1264 'Intel wifi sar id')
1265 output_path = os.path.join(output_dir, 'wifi')
1266 os.makedirs(output_path, exist_ok=True)
1267 filename = 'wifi_sar_{}.hex'.format(wifi_sar_id)
1268 output_path = os.path.join(output_path, filename)
1269 build_path = os.path.join(build_root_dir, 'wifi', filename)
1270 if os.path.exists(output_path):
1271 with open(output_path, 'r') as f:
1272 if f.read() != sar_file_content:
1273 raise Exception(
1274 'Project {} has conflicting wifi sar file content under '
1275 'wifi sar id {}.'.format(project_name, wifi_sar_id))
1276 else:
1277 with open(output_path, 'w') as f:
1278 f.write(sar_file_content)
1279 system_path = '/firmware/cbfs-rw-raw/{}/{}'.format(
1280 project_name, filename)
David Burger89e7cae2020-09-15 17:04:12 -06001281 result[design_name] = {'sar-file': _file_v2(build_path, system_path)}
David Burgerceeb68a2020-09-03 11:31:10 -06001282 return result
1283
1284
1285def _extract_fw_config_value(hw_design_config, program, name):
1286 """Extracts the firwmare config value with the given name.
1287
1288 Args:
1289 hw_design_config: Design extracting value from.
1290 program: Program the `hw_design_config` belongs to.
1291 name: Name of firmware config segment to extract.
1292
1293 Returns: the extracted value or raises a ValueError if no firmware
1294 configuration segment with `name` is found.
1295 """
1296 fw_config = hw_design_config.hardware_features.fw_config.value
1297 for fcs in program.firmware_configuration_segments:
1298 if fcs.name == name:
1299 value = fw_config & fcs.mask
1300 lsb_bit_set = (~fcs.mask + 1) & fcs.mask
1301 return value // lsb_bit_set
1302 raise ValueError(
1303 'No firmware configuration segment with name {} found'.format(name))
1304
1305
1306def _create_intel_sar_file_content(intel_config):
1307 """Creates and returns the intel sar file content for the given config.
1308
1309 Creates and returns the sar file content that is used with intel drivers
1310 only.
1311
1312 Args:
1313 intel_config: IntelConfig config.
1314
1315 Returns:
1316 sar file content for the given config, see:
1317 https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1318 """
1319
1320 def to_hex(val):
1321 if val > 255 or val < 0:
1322 raise Exception('Sar file value %s out of range' % val)
1323 return '{0:0{1}X}'.format(val, 2)
1324
1325 def power_table(tpc):
1326 return (to_hex(tpc.limit_2g) + to_hex(tpc.limit_5g_1) +
1327 to_hex(tpc.limit_5g_2) + to_hex(tpc.limit_5g_3) +
1328 to_hex(tpc.limit_5g_4))
1329
1330 def wgds_value(wgds):
1331 return to_hex(wgds)
1332
1333 def offset_table(offsets):
1334 return (to_hex(offsets.max_2g) + to_hex(offsets.offset_2g_a) +
1335 to_hex(offsets.offset_2g_b) + to_hex(offsets.max_5g) +
1336 to_hex(offsets.offset_5g_a) + to_hex(offsets.offset_5g_b))
1337
1338 # See https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1339 return (power_table(intel_config.tablet_mode_power_table_a) +
1340 power_table(intel_config.tablet_mode_power_table_b) +
1341 power_table(intel_config.non_tablet_mode_power_table_a) +
1342 power_table(intel_config.non_tablet_mode_power_table_b) +
1343 '00000000000000000000' + '00000000000000000000' +
1344 wgds_value(intel_config.wgds_version) +
1345 offset_table(intel_config.offset_fcc) +
1346 offset_table(intel_config.offset_eu) +
YH Lin89cddaa2021-03-08 08:31:47 -08001347 offset_table(intel_config.offset_other) + '\0')
David Burgerceeb68a2020-09-03 11:31:10 -06001348
1349
Andrew Lambcd33f702020-06-11 10:45:16 -06001350def Main(project_configs, program_config, output): # pylint: disable=invalid-name
David Burger7fd1dbe2020-03-26 09:26:55 -06001351 """Transforms source proto config into platform JSON.
1352
1353 Args:
1354 project_configs: List of source project configs to transform.
1355 program_config: Program config for the given set of projects.
1356 output: Output file that will be generated by the transform.
1357 """
Andrew Lambcd33f702020-06-11 10:45:16 -06001358 configs = _merge_configs([_read_config(program_config)] +
1359 [_read_config(config) for config in project_configs])
C Shapiro2b6d5332020-05-06 17:51:35 -05001360 touch_fw = {}
David Burger8ee9b4d2020-06-16 17:40:21 -06001361 camera_map = {}
David Burgerceeb68a2020-09-03 11:31:10 -06001362 dptf_map = {}
1363 wifi_sar_map = {}
C Shapiro5bf23a72020-04-24 11:40:17 -05001364 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -05001365 build_root_dir = output_dir
C Shapiro5c877992020-04-29 12:11:28 -05001366 if 'sw_build_config' in output_dir:
1367 full_path = os.path.realpath(output)
Andrew Lamb6b607732020-08-24 15:52:46 -06001368 project_name = re.match(r'.*/(\w*)/(public_)?sw_build_config/.*',
Andrew Lamb2413c982020-05-29 12:15:36 -06001369 full_path).groups(1)[0]
C Shapiro5c877992020-04-29 12:11:28 -05001370 # Projects don't know about each other until they are integrated into the
1371 # build system. When this happens, the files need to be able to co-exist
1372 # without any collisions. This prefixes the project name (which is how
1373 # portage maps in the project), so project files co-exist and can be
1374 # installed together.
1375 # This is necessary to allow projects to share files at the program level
1376 # without having portage file installation collisions.
1377 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -05001378
David Burger1ba78a22020-06-18 18:42:47 -06001379 camera_map = _camera_map(configs, project_name)
David Burger52c9d322020-06-09 07:16:18 -06001380 dptf_map = _dptf_map(configs, project_name)
David Burgerceeb68a2020-09-03 11:31:10 -06001381 wifi_sar_map = _wifi_sar_map(configs, project_name, output_dir,
1382 build_root_dir)
David Burger52c9d322020-06-09 07:16:18 -06001383
C Shapiro2b6d5332020-05-06 17:51:35 -05001384 if os.path.exists(TOUCH_PATH):
Andrew Lambcd33f702020-06-11 10:45:16 -06001385 touch_fw = _build_touch_file_config(configs, project_name)
Andrew Lambcd33f702020-06-11 10:45:16 -06001386 arc_hw_feature_files = _write_arc_hardware_feature_files(
1387 configs, output_dir, build_root_dir)
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001388 arc_media_profile_files = _write_arc_media_profile_files(
1389 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -05001390 config_files = ConfigFiles(
C Shapiro5bf23a72020-04-24 11:40:17 -05001391 arc_hw_features=arc_hw_feature_files,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001392 arc_media_profiles=arc_media_profile_files,
C Shapiro2b6d5332020-05-06 17:51:35 -05001393 touch_fw=touch_fw,
David Burger8ee9b4d2020-06-16 17:40:21 -06001394 dptf_map=dptf_map,
David Burgerceeb68a2020-09-03 11:31:10 -06001395 camera_map=camera_map,
1396 wifi_sar_map=wifi_sar_map)
Andrew Lambcd33f702020-06-11 10:45:16 -06001397 write_output(_transform_build_configs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -06001398
1399
1400def main(argv=None):
1401 """Main program which parses args and runs
1402
1403 Args:
1404 argv: List of command line arguments, if None uses sys.argv.
1405 """
1406 if argv is None:
1407 argv = sys.argv[1:]
Andrew Lambcd33f702020-06-11 10:45:16 -06001408 opts = parse_args(argv)
David Burger7fd1dbe2020-03-26 09:26:55 -06001409 Main(opts.project_configs, opts.program_config, opts.output)
1410
1411
1412if __name__ == '__main__':
1413 sys.exit(main(sys.argv[1:]))