blob: 3ea056cf4e896c162dcfe0b19a3e238c9adfdccf [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):
193 flags['force-in-tablet-physical-state'] = None
194
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
344 return result
345
346
Andrew Lambcd33f702020-06-11 10:45:16 -0600347def _fw_bcs_path(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600348 if payload and payload.firmware_image_name:
Andrew Lamb2413c982020-05-29 12:15:36 -0600349 return 'bcs://%s.%d.%d.0.tbz2' % (payload.firmware_image_name,
350 payload.version.major,
351 payload.version.minor)
David Burger7fd1dbe2020-03-26 09:26:55 -0600352
Andrew Lambcd33f702020-06-11 10:45:16 -0600353 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600354
Andrew Lambcd33f702020-06-11 10:45:16 -0600355
356def _fw_build_target(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600357 if payload:
358 return payload.build_target_name
359
Andrew Lambcd33f702020-06-11 10:45:16 -0600360 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600361
Andrew Lambcd33f702020-06-11 10:45:16 -0600362
363def _build_firmware(config):
David Burgerb70b6762020-05-21 12:14:59 -0600364 """Returns firmware config, or None if no build targets."""
Andrew Lamb3da156d2020-04-16 16:00:56 -0600365 fw_payload_config = config.sw_config.firmware
366 fw_build_config = config.sw_config.firmware_build_config
367 main_ro = fw_payload_config.main_ro_payload
368 main_rw = fw_payload_config.main_rw_payload
369 ec_ro = fw_payload_config.ec_ro_payload
370 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600371
372 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600373
David Burger8ee9b4d2020-06-16 17:40:21 -0600374 _upsert(fw_build_config.build_targets.depthcharge, build_targets,
375 'depthcharge')
376 _upsert(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
377 _upsert(fw_build_config.build_targets.ec, build_targets, 'ec')
378 _upsert(
Andrew Lambf8954ee2020-04-21 10:24:40 -0600379 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
David Burger8ee9b4d2020-06-16 17:40:21 -0600380 _upsert(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
David Burger7fd1dbe2020-03-26 09:26:55 -0600381
David Burgerb70b6762020-05-21 12:14:59 -0600382 if not build_targets:
383 return None
384
David Burger7fd1dbe2020-03-26 09:26:55 -0600385 result = {
C Shapirod5545f12020-11-30 16:37:04 -0600386 'bcs-overlay': 'overlay-%s-private' % config.program.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600387 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600388 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600389
David Burger8ee9b4d2020-06-16 17:40:21 -0600390 _upsert(main_ro.firmware_image_name.lower(), result, 'image-name')
Andrew Lamb883fa042020-04-06 11:37:22 -0600391
David Burger8ee9b4d2020-06-16 17:40:21 -0600392 _upsert(_fw_bcs_path(main_ro), result, 'main-ro-image')
393 _upsert(_fw_bcs_path(main_rw), result, 'main-rw-image')
394 _upsert(_fw_bcs_path(ec_ro), result, 'ec-ro-image')
395 _upsert(_fw_bcs_path(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600396
David Burger8ee9b4d2020-06-16 17:40:21 -0600397 _upsert(
Andrew Lambf39fbe82020-04-13 16:14:33 -0600398 config.hw_design_config.hardware_features.fw_config.value,
399 result,
400 'firmware-config',
401 )
402
David Burger7fd1dbe2020-03-26 09:26:55 -0600403 return result
404
405
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000406def _build_fw_signing(config, whitelabel):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500407 if config.sw_config.firmware and config.device_signer_config:
David Burger68e0d142020-05-15 17:29:33 -0600408 hw_design = config.hw_design.name.lower()
Sam McNally2fc807f2020-07-16 18:13:53 +1000409 brand_scan_config = config.brand_config.scan_config
410 if brand_scan_config and brand_scan_config.whitelabel_tag:
411 signature_id = '%s-%s' % (hw_design, brand_scan_config.whitelabel_tag)
412 else:
413 signature_id = hw_design
414
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000415 result = {
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500416 'key-id': config.device_signer_config.key_id,
Sam McNally2fc807f2020-07-16 18:13:53 +1000417 'signature-id': signature_id,
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500418 }
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000419 if whitelabel:
420 result['sig-id-in-customization-id'] = True
421 return result
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500422 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600423
424
Andrew Lambcd33f702020-06-11 10:45:16 -0600425def _file(source, destination):
Andrew Lamb2413c982020-05-29 12:15:36 -0600426 return {'destination': destination, 'source': source}
David Burger7fd1dbe2020-03-26 09:26:55 -0600427
428
David Burger40dfe3a2020-06-18 17:09:13 -0600429def _file_v2(build_path, system_path):
430 return {'build-path': build_path, 'system-path': system_path}
431
432
Andrew Lambcd33f702020-06-11 10:45:16 -0600433def _build_audio(config):
David Burger178f3ef2020-06-26 12:11:57 -0600434 if not config.sw_config.audio_configs:
435 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600436 alsa_path = '/usr/share/alsa/ucm'
437 cras_path = '/etc/cras'
438 project_name = config.hw_design.name.lower()
David Burger43250662020-05-07 11:21:50 -0600439 program_name = config.program.name.lower()
David Burger7fd1dbe2020-03-26 09:26:55 -0600440 files = []
David Burger178f3ef2020-06-26 12:11:57 -0600441 ucm_suffix = None
442 for audio in config.sw_config.audio_configs:
443 card = audio.card_name
444 card_with_suffix = audio.card_name
445 if audio.ucm_suffix:
446 # TODO: last ucm_suffix wins.
447 ucm_suffix = audio.ucm_suffix
448 card_with_suffix += '.' + audio.ucm_suffix
449 if audio.ucm_file:
450 files.append(
451 _file(audio.ucm_file,
452 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
453 if audio.ucm_master_file:
454 files.append(
455 _file(
456 audio.ucm_master_file, '%s/%s/%s.conf' %
Andrew Lamb2413c982020-05-29 12:15:36 -0600457 (alsa_path, card_with_suffix, card_with_suffix)))
David Burger178f3ef2020-06-26 12:11:57 -0600458 if audio.card_config_file:
459 files.append(
460 _file(audio.card_config_file,
461 '%s/%s/%s' % (cras_path, project_name, card)))
462 if audio.dsp_file:
463 files.append(
464 _file(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, project_name)))
465 if audio.module_file:
466 files.append(
467 _file(audio.module_file,
468 '/etc/modprobe.d/alsa-%s.conf' % program_name))
469 if audio.board_file:
470 files.append(
471 _file(audio.board_file,
472 '%s/%s/board.ini' % (cras_path, project_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600473
474 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600475 'main': {
476 'cras-config-dir': project_name,
477 'files': files,
478 }
479 }
David Burger178f3ef2020-06-26 12:11:57 -0600480
481 if ucm_suffix:
482 result['main']['ucm-suffix'] = ucm_suffix
David Burger599ff7b2020-04-06 16:29:31 -0600483
484 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600485
486
Andrew Lambcd33f702020-06-11 10:45:16 -0600487def _build_camera(hw_topology):
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800488 camera_pb = topology_pb2.HardwareFeatures.Camera
489 camera = hw_topology.camera.hardware_feature.camera
490 result = {'count': len(camera.devices)}
491 if camera.devices:
492 result['devices'] = []
493 for device in camera.devices:
494 interface = {
495 camera_pb.INTERFACE_USB: 'usb',
496 camera_pb.INTERFACE_MIPI: 'mipi',
497 }[device.interface]
498 facing = {
499 camera_pb.FACING_FRONT: 'front',
500 camera_pb.FACING_BACK: 'back',
501 }[device.facing]
502 orientation = {
503 camera_pb.ORIENTATION_0: 0,
504 camera_pb.ORIENTATION_90: 90,
505 camera_pb.ORIENTATION_180: 180,
506 camera_pb.ORIENTATION_270: 270,
507 }[device.orientation]
508 flags = {
509 'support-1080p':
510 bool(device.flags & camera_pb.FLAGS_SUPPORT_1080P),
511 'support-autofocus':
512 bool(device.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS),
513 }
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100514 dev = {
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800515 'interface': interface,
516 'facing': facing,
517 'orientation': orientation,
518 'flags': flags,
519 'ids': list(device.ids),
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100520 }
521 if device.privacy_switch != topology_pb2.HardwareFeatures.PRESENT_UNKNOWN:
522 dev['has-privacy-switch'] = device.privacy_switch == topology_pb2.HardwareFeatures.PRESENT
523 result['devices'].append(dev)
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800524 return result
David Burger8aa8fa32020-04-14 08:30:34 -0600525
Andrew Lambcd33f702020-06-11 10:45:16 -0600526
527def _build_identity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600528 identity = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600529 _upsert(hw_scan_config.firmware_sku, identity, 'sku-id')
530 _upsert(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600531 # 'platform-name' is needed to support 'mosys platform name'. Clients should
Sean McAllister0b757772020-11-13 12:22:36 -0700532 # no longer require platform name, but set it here for backwards compatibility.
533 if program.mosys_platform_name:
534 _upsert(program.mosys_platform_name, identity, 'platform-name')
535 else:
536 _upsert(program.name, identity, 'platform-name')
537
David Burger7fd1dbe2020-03-26 09:26:55 -0600538 # ARM architecture
David Burger8ee9b4d2020-06-16 17:40:21 -0600539 _upsert(hw_scan_config.device_tree_compatible_match, identity,
540 'device-tree-compatible-match')
David Burger7fd1dbe2020-03-26 09:26:55 -0600541
542 if brand_scan_config:
David Burger8ee9b4d2020-06-16 17:40:21 -0600543 _upsert(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
David Burger7fd1dbe2020-03-26 09:26:55 -0600544
545 return identity
546
547
Andrew Lambcd33f702020-06-11 10:45:16 -0600548def _lookup(id_value, id_map):
549 if not id_value.value:
550 return None
551
552 key = id_value.value
553 if key in id_map:
554 return id_map[id_value.value]
555 error = 'Failed to lookup %s with value: %s' % (
556 id_value.__class__.__name__.replace('Id', ''), key)
557 print(error)
558 print('Check the config contents provided:')
559 printer = pprint.PrettyPrinter(indent=4)
560 printer.pprint(id_map)
561 raise Exception(error)
David Burger7fd1dbe2020-03-26 09:26:55 -0600562
563
Andrew Lambcd33f702020-06-11 10:45:16 -0600564def _build_touch_file_config(config, project_name):
Sean McAllistereaf10b72020-08-03 13:41:06 -0600565 partners = {x.id.value: x for x in config.partner_list}
C Shapiro2b6d5332020-05-06 17:51:35 -0500566 files = []
567 for comp in config.components:
C Shapiro4813be62020-05-13 17:31:58 -0500568 touch = comp.touchscreen
569 # Everything is the same for Touch screen/pad, except different fields
570 if comp.HasField('touchpad'):
571 touch = comp.touchpad
572 if touch.product_id:
Andrew Lambcd33f702020-06-11 10:45:16 -0600573 vendor = _lookup(comp.manufacturer_id, partners)
C Shapiro2b6d5332020-05-06 17:51:35 -0500574 if not vendor:
Andrew Lamb2413c982020-05-29 12:15:36 -0600575 raise Exception("Manufacturer must be set for touch device %s" %
576 comp.id.value)
C Shapiro2b6d5332020-05-06 17:51:35 -0500577
C Shapiro4813be62020-05-13 17:31:58 -0500578 product_id = touch.product_id
579 fw_version = touch.fw_version
C Shapiro2b6d5332020-05-06 17:51:35 -0500580
C Shapiro2b6d5332020-05-06 17:51:35 -0500581 file_name = "%s_%s.bin" % (product_id, fw_version)
582 fw_file_path = os.path.join(TOUCH_PATH, vendor.name, file_name)
583
584 if not os.path.exists(fw_file_path):
Andrew Lamb2413c982020-05-29 12:15:36 -0600585 raise Exception("Touchscreen fw bin file doesn't exist at: %s" %
586 fw_file_path)
C Shapiro2b6d5332020-05-06 17:51:35 -0500587
C Shapiro303cece2020-07-22 07:15:21 -0500588 touch_vendor = vendor.touch_vendor
589 sym_link = touch_vendor.symlink_file_format.format(
590 vendor_name=vendor.name,
591 vendor_id=touch_vendor.vendor_id,
592 product_id=product_id,
593 fw_version=fw_version,
594 product_series=touch.product_series)
595
596 dest = "%s_%s" % (vendor.name, file_name)
597 if touch_vendor.destination_file_format:
598 dest = touch_vendor.destination_file_format.format(
599 vendor_name=vendor.name,
600 vendor_id=touch_vendor.vendor_id,
601 product_id=product_id,
602 fw_version=fw_version,
603 product_series=touch.product_series)
604
C Shapiro2b6d5332020-05-06 17:51:35 -0500605 files.append({
C Shapiro303cece2020-07-22 07:15:21 -0500606 "destination": os.path.join("/opt/google/touch/firmware", dest),
YH Lin9160fc52020-07-22 16:35:28 -0700607 "source": os.path.join(project_name, fw_file_path),
608 "symlink": os.path.join("/lib/firmware", sym_link),
C Shapiro2b6d5332020-05-06 17:51:35 -0500609 })
610
611 result = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600612 _upsert(files, result, 'files')
C Shapiro2b6d5332020-05-06 17:51:35 -0500613 return result
614
615
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000616def _build_modem(config):
617 """Returns the cellular modem configuration, or None if absent."""
618 hw_features = config.hw_design_config.hardware_features
619 lte_support = _any_present([hw_features.lte.present])
620 if not lte_support:
621 return None
622 return {'firmware-variant': config.hw_design.name.lower()}
623
624
David Burgerceeb68a2020-09-03 11:31:10 -0600625def _sw_config(sw_configs, design_config_id):
626 """Returns the correct software config for `design_config_id`.
627
628 Returns the correct software config match for `design_config_id`. If no such
629 config or multiple such configs are found an exception is raised.
630 """
631 sw_config_matches = [
632 x for x in sw_configs if x.design_config_id.value == design_config_id
633 ]
634 if len(sw_config_matches) == 1:
635 return sw_config_matches[0]
636 if len(sw_config_matches) > 1:
637 raise ValueError('Multiple software configs found for: %s' %
638 design_config_id)
639 raise ValueError('Software config is required for: %s' % design_config_id)
640
641
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000642def _is_whitelabel(brand_configs, device_brands):
643 for device_brand in device_brands:
644 if device_brand.id.value in brand_configs:
645 brand_scan_config = brand_configs[device_brand.id.value].scan_config
646 if brand_scan_config and brand_scan_config.whitelabel_tag:
647 return True
648 return False
649
650
David Burgerceeb68a2020-09-03 11:31:10 -0600651def _transform_build_configs(config,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800652 config_files=ConfigFiles({}, {}, {}, {}, {}, {})):
Andrew Lambcd33f702020-06-11 10:45:16 -0600653 # pylint: disable=too-many-locals,too-many-branches
Sean McAllistereaf10b72020-08-03 13:41:06 -0600654 partners = {x.id.value: x for x in config.partner_list}
Sean McAllisterf38d1e92020-08-03 13:57:53 -0600655 programs = {x.id.value: x for x in config.program_list}
David Burger7fd1dbe2020-03-26 09:26:55 -0600656 sw_configs = list(config.software_configs)
Andrew Lambcd33f702020-06-11 10:45:16 -0600657 brand_configs = {x.brand_id.value: x for x in config.brand_configs}
David Burger7fd1dbe2020-03-26 09:26:55 -0600658
659 results = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600660 for hw_design in config.design_list:
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600661 if config.device_brand_list:
Andrew Lamb2413c982020-05-29 12:15:36 -0600662 device_brands = [
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600663 x for x in config.device_brand_list
Andrew Lamb2413c982020-05-29 12:15:36 -0600664 if x.design_id.value == hw_design.id.value
665 ]
David Burger7fd1dbe2020-03-26 09:26:55 -0600666 else:
667 device_brands = [device_brand_pb2.DeviceBrand()]
668
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000669 whitelabel = _is_whitelabel(brand_configs, device_brands)
670
David Burger7fd1dbe2020-03-26 09:26:55 -0600671 for device_brand in device_brands:
672 # Brand config can be empty since platform JSON config allows it
673 brand_config = brand_config_pb2.BrandConfig()
674 if device_brand.id.value in brand_configs:
675 brand_config = brand_configs[device_brand.id.value]
676
677 for hw_design_config in hw_design.configs:
David Burgerceeb68a2020-09-03 11:31:10 -0600678 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
Andrew Lambcd33f702020-06-11 10:45:16 -0600679 program = _lookup(hw_design.program_id, programs)
C Shapiroadefd7c2020-05-19 16:37:21 -0500680 signer_configs_by_design = {}
681 signer_configs_by_brand = {}
682 for signer_config in program.device_signer_configs:
683 design_id = signer_config.design_id.value
684 brand_id = signer_config.brand_id.value
685 if design_id:
686 signer_configs_by_design[design_id] = signer_config
687 elif brand_id:
688 signer_configs_by_brand[brand_id] = signer_config
689 else:
690 raise Exception('No ID found for signer config: %s' % signer_config)
691
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500692 device_signer_config = None
C Shapiroadefd7c2020-05-19 16:37:21 -0500693 if signer_configs_by_design or signer_configs_by_brand:
694 design_id = hw_design.id.value
695 brand_id = device_brand.id.value
696 if design_id in signer_configs_by_design:
697 device_signer_config = signer_configs_by_design[design_id]
698 elif brand_id in signer_configs_by_brand:
699 device_signer_config = signer_configs_by_brand[brand_id]
700 else:
701 # Assume that if signer configs are set, every config is setup
Andrew Lamb2413c982020-05-29 12:15:36 -0600702 raise Exception('Signer config missing for design: %s, brand: %s' %
703 (design_id, brand_id))
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500704
Andrew Lambcd33f702020-06-11 10:45:16 -0600705 transformed_config = _transform_build_config(
C Shapiro90fda252020-04-17 14:34:57 -0500706 Config(
707 program=program,
708 hw_design=hw_design,
Andrew Lambcd33f702020-06-11 10:45:16 -0600709 odm=_lookup(hw_design.odm_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500710 hw_design_config=hw_design_config,
711 device_brand=device_brand,
712 device_signer_config=device_signer_config,
Andrew Lambcd33f702020-06-11 10:45:16 -0600713 oem=_lookup(device_brand.oem_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500714 sw_config=sw_config,
C Shapirod5545f12020-11-30 16:37:04 -0600715 brand_config=brand_config), config_files, whitelabel)
David Burger7fd1dbe2020-03-26 09:26:55 -0600716
Andrew Lamb2413c982020-05-29 12:15:36 -0600717 config_json = json.dumps(
718 transformed_config,
719 sort_keys=True,
720 indent=2,
721 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600722
723 if config_json not in results:
724 results[config_json] = transformed_config
725
726 return list(results.values())
727
728
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000729def _transform_build_config(config, config_files, whitelabel):
David Burger7fd1dbe2020-03-26 09:26:55 -0600730 """Transforms Config instance into target platform JSON schema.
731
732 Args:
733 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500734 config_files: Map to look up the generated config files.
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000735 whitelabel: Whether the config is for a whitelabel design
David Burger7fd1dbe2020-03-26 09:26:55 -0600736
737 Returns:
738 Unique config payload based on the platform JSON schema.
739 """
740 result = {
Andrew Lamb2413c982020-05-29 12:15:36 -0600741 'identity':
Andrew Lambcd33f702020-06-11 10:45:16 -0600742 _build_identity(config.sw_config.id_scan_config, config.program,
743 config.brand_config.scan_config),
Andrew Lamb2413c982020-05-29 12:15:36 -0600744 'name':
745 config.hw_design.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600746 }
747
David Burger8ee9b4d2020-06-16 17:40:21 -0600748 _upsert(_build_arc(config, config_files), result, 'arc')
749 _upsert(_build_audio(config), result, 'audio')
David Burger07af5242020-08-11 11:08:25 -0600750 _upsert(_build_bluetooth(config), result, 'bluetooth')
David Burgerceeb68a2020-09-03 11:31:10 -0600751 _upsert(_build_wifi(config, config_files), result, 'wifi')
Andrew Lambca279902020-08-06 10:13:42 -0600752 _upsert(config.brand_config.wallpaper, result, 'wallpaper')
C Shapiro2e97aad2020-11-16 11:58:10 -0600753 _upsert(config.brand_config.regulatory_label, result, 'regulatory-label')
David Burger8ee9b4d2020-06-16 17:40:21 -0600754 _upsert(config.device_brand.brand_code, result, 'brand-code')
755 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600756 _build_camera(config.hw_design_config.hardware_topology), result,
757 'camera')
David Burger8ee9b4d2020-06-16 17:40:21 -0600758 _upsert(_build_firmware(config), result, 'firmware')
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000759 _upsert(_build_fw_signing(config, whitelabel), result, 'firmware-signing')
David Burger8ee9b4d2020-06-16 17:40:21 -0600760 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600761 _build_fingerprint(config.hw_design_config.hardware_topology), result,
Andrew Lamb2413c982020-05-29 12:15:36 -0600762 'fingerprint')
Andrew Lamb0d236ab2020-06-30 12:30:20 -0600763 _upsert(_build_ui(config), result, 'ui')
David Burger7fd1dbe2020-03-26 09:26:55 -0600764 power_prefs = config.sw_config.power_config.preferences
765 power_prefs_map = dict(
Andrew Lamb2413c982020-05-29 12:15:36 -0600766 (x.replace('_', '-'), power_prefs[x]) for x in power_prefs)
David Burger8ee9b4d2020-06-16 17:40:21 -0600767 _upsert(power_prefs_map, result, 'power')
768 if config_files.camera_map:
769 camera_file = config_files.camera_map.get(config.hw_design.name, {})
770 _upsert(camera_file, result, 'camera')
David Burger52c9d322020-06-09 07:16:18 -0600771 if config_files.dptf_map:
772 # Prefer design specific if found, if not fall back to project wide config
773 # mapped under the empty string.
774 if config_files.dptf_map.get(config.hw_design.name):
775 dptf_file = config_files.dptf_map[config.hw_design.name]
776 else:
777 dptf_file = config_files.dptf_map.get('')
David Burger8ee9b4d2020-06-16 17:40:21 -0600778 _upsert(dptf_file, result, 'thermal')
779 _upsert(config_files.touch_fw, result, 'touch')
Trent Beginf067ccb2020-08-12 12:33:53 -0600780 _upsert(
781 _build_hardware_properties(config.hw_design_config.hardware_topology),
782 result, 'hardware-properties')
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000783 _upsert(_build_modem(config), result, 'modem')
David Burger7fd1dbe2020-03-26 09:26:55 -0600784
785 return result
786
787
Andrew Lambcd33f702020-06-11 10:45:16 -0600788def write_output(configs, output=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600789 """Writes a list of configs to platform JSON format.
790
791 Args:
792 configs: List of config dicts defined in cros_config_schema.yaml
793 output: Target file output (if None, prints to stdout)
794 """
Andrew Lamb2413c982020-05-29 12:15:36 -0600795 json_output = json.dumps({'chromeos': {
796 'configs': configs,
797 }},
798 sort_keys=True,
799 indent=2,
800 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600801 if output:
802 with open(output, 'w') as output_stream:
803 # Using print function adds proper trailing newline.
804 print(json_output, file=output_stream)
805 else:
806 print(json_output)
807
808
Andrew Lambcd33f702020-06-11 10:45:16 -0600809def _feature(name, present):
C Shapiro5bf23a72020-04-24 11:40:17 -0500810 attrib = {'name': name}
811 if present:
812 return etree.Element('feature', attrib=attrib)
Andrew Lambcd33f702020-06-11 10:45:16 -0600813
814 return etree.Element('unavailable-feature', attrib=attrib)
C Shapiro5bf23a72020-04-24 11:40:17 -0500815
816
Andrew Lambcd33f702020-06-11 10:45:16 -0600817def _any_present(features):
Andrew Lamb2413c982020-05-29 12:15:36 -0600818 return topology_pb2.HardwareFeatures.PRESENT in features
C Shapiro5bf23a72020-04-24 11:40:17 -0500819
820
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800821def _get_formatted_config_id(design_config):
C Shapiro5bf23a72020-04-24 11:40:17 -0500822 return design_config.id.value.lower().replace(':', '_')
823
824
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800825def _write_file(output_dir, file_name, file_content):
David Burger77a1d312020-05-23 16:05:45 -0600826 os.makedirs(output_dir, exist_ok=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800827 output = '{}/{}'.format(output_dir, file_name)
C Shapiroea33cff2020-05-11 13:32:05 -0500828 with open(output, 'wb') as f:
829 f.write(file_content)
830
831
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800832def _get_arc_camera_features(camera):
833 """Gets camera related features for ARC hardware_features.xml from camera
834 topology. Check
835 https://developer.android.com/reference/android/content/pm/PackageManager#FEATURE_CAMERA
836 and CTS android.app.cts.SystemFeaturesTest#testCameraFeatures for the correct
837 settings.
838
839 Args:
840 camera: A HardwareFeatures.Camera proto message.
841 Returns:
842 list of camera related ARC features as XML elements.
843 """
844 camera_pb = topology_pb2.HardwareFeatures.Camera
845
Ren-Pei Zeng9b5682d2020-10-14 17:37:30 +0800846 count = len(camera.devices)
847 has_front_camera = any(
848 (d.facing == camera_pb.FACING_FRONT for d in camera.devices))
849 has_back_camera = any(
850 (d.facing == camera_pb.FACING_BACK for d in camera.devices))
851 has_autofocus_back_camera = any((d.facing == camera_pb.FACING_BACK and
852 d.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS
853 for d in camera.devices))
854 # Assumes MIPI cameras support FULL-level.
855 # TODO(kamesan): Setting this in project configs when there's an exception.
856 has_level_full_camera = any(
857 (d.interface == camera_pb.INTERFACE_MIPI for d in camera.devices))
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800858
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800859 return [
860 _feature('android.hardware.camera', has_back_camera),
861 _feature('android.hardware.camera.any', count > 0),
862 _feature('android.hardware.camera.autofocus', has_autofocus_back_camera),
863 _feature('android.hardware.camera.capability.manual_post_processing',
864 has_level_full_camera),
865 _feature('android.hardware.camera.capability.manual_sensor',
866 has_level_full_camera),
867 _feature('android.hardware.camera.front', has_front_camera),
868 _feature('android.hardware.camera.level.full', has_level_full_camera),
869 ]
870
871
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800872def _generate_arc_hardware_features(hw_features):
873 """Generates ARC hardware_features.xml file content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500874
875 Args:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800876 hw_features: HardwareFeatures proto message.
C Shapiro5bf23a72020-04-24 11:40:17 -0500877 Returns:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800878 bytes of the hardware_features.xml content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500879 """
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800880 touchscreen = _any_present([hw_features.screen.touch_support])
881 acc = hw_features.accelerometer
882 gyro = hw_features.gyroscope
883 compass = hw_features.magnetometer
884 light_sensor = hw_features.light_sensor
885 root = etree.Element('permissions')
886 root.extend(
887 _get_arc_camera_features(hw_features.camera) + [
888 _feature(
889 'android.hardware.sensor.accelerometer',
890 _any_present([acc.lid_accelerometer, acc.base_accelerometer])),
891 _feature('android.hardware.sensor.gyroscope',
892 _any_present([gyro.lid_gyroscope, gyro.base_gyroscope])),
893 _feature(
894 'android.hardware.sensor.compass',
895 _any_present(
896 [compass.lid_magnetometer, compass.base_magnetometer])),
897 _feature(
898 'android.hardware.sensor.light',
899 _any_present([
900 light_sensor.lid_lightsensor, light_sensor.base_lightsensor
901 ])),
902 _feature('android.hardware.touchscreen', touchscreen),
903 _feature('android.hardware.touchscreen.multitouch', touchscreen),
904 _feature('android.hardware.touchscreen.multitouch.distinct',
905 touchscreen),
906 _feature('android.hardware.touchscreen.multitouch.jazzhand',
907 touchscreen),
908 ])
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800909 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
910
911
912def _generate_arc_media_profiles(hw_features, sw_config):
913 """Generates ARC media_profiles.xml file content.
914
915 Args:
916 hw_features: HardwareFeatures proto message.
917 sw_config: SoftwareConfig proto message.
918 Returns:
919 bytes of the media_profiles.xml content, or None if |sw_config| disables the
Ren-Pei Zengb55e4312020-11-18 17:03:01 +0800920 generation or there's no camera.
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800921 """
922
923 def _gen_camcorder_profiles(camera_id, resolutions):
924 elem = etree.Element(
925 'CamcorderProfiles', attrib={'cameraId': str(camera_id)})
926 for width, height in resolutions:
927 elem.extend([
928 _gen_encoder_profile(width, height, False),
929 _gen_encoder_profile(width, height, True),
930 ])
931 elem.extend([
932 etree.Element('ImageEncoding', attrib={'quality': '90'}),
933 etree.Element('ImageEncoding', attrib={'quality': '80'}),
934 etree.Element('ImageEncoding', attrib={'quality': '70'}),
935 etree.Element('ImageDecoding', attrib={'memCap': '20000000'}),
936 ])
937 return elem
938
939 def _gen_encoder_profile(width, height, timelapse):
940 elem = etree.Element(
941 'EncoderProfile',
942 attrib={
943 'quality': ('timelapse' if timelapse else '') + str(height) + 'p',
944 'fileFormat': 'mp4',
945 'duration': '60',
946 })
947 elem.append(
948 etree.Element(
949 'Video',
950 attrib={
951 'codec': 'h264',
952 'bitRate': '8000000',
953 'width': str(width),
954 'height': str(height),
955 'frameRate': '30',
956 }))
957 elem.append(
958 etree.Element(
959 'Audio',
960 attrib={
961 'codec': 'aac',
962 'bitRate': '96000',
963 'sampleRate': '44100',
964 'channels': '1',
965 }))
966 return elem
967
968 def _gen_video_encoder_cap(name, min_bit_rate, max_bit_rate):
969 return etree.Element(
970 'VideoEncoderCap',
971 attrib={
972 'name': name,
973 'enabled': 'true',
974 'minBitRate': str(min_bit_rate),
975 'maxBitRate': str(max_bit_rate),
976 'minFrameWidth': '320',
977 'maxFrameWidth': '1920',
978 'minFrameHeight': '240',
979 'maxFrameHeight': '1080',
980 'minFrameRate': '15',
981 'maxFrameRate': '30',
982 })
983
984 def _gen_audio_encoder_cap(name, min_bit_rate, max_bit_rate, min_sample_rate,
985 max_sample_rate):
986 return etree.Element(
987 'AudioEncoderCap',
988 attrib={
989 'name': name,
990 'enabled': 'true',
991 'minBitRate': str(min_bit_rate),
992 'maxBitRate': str(max_bit_rate),
993 'minSampleRate': str(min_sample_rate),
994 'maxSampleRate': str(max_sample_rate),
995 'minChannels': '1',
996 'maxChannels': '1',
997 })
998
999 camera_config = sw_config.camera_config
1000 if not camera_config.generate_media_profiles:
1001 return None
1002
1003 camera_pb = topology_pb2.HardwareFeatures.Camera
1004 root = etree.Element('MediaSettings')
1005 camera_id = 0
1006 for facing in [camera_pb.FACING_BACK, camera_pb.FACING_FRONT]:
1007 camera_device = next(
1008 (d for d in hw_features.camera.devices if d.facing == facing), None)
1009 if camera_device is None:
1010 continue
1011 if camera_config.camcorder_resolutions:
1012 resolutions = [
1013 (r.width, r.height) for r in camera_config.camcorder_resolutions
1014 ]
1015 else:
1016 resolutions = [(1280, 720)]
1017 if camera_device.flags & camera_pb.FLAGS_SUPPORT_1080P:
1018 resolutions.append((1920, 1080))
1019 root.append(_gen_camcorder_profiles(camera_id, resolutions))
1020 camera_id += 1
Ren-Pei Zengb55e4312020-11-18 17:03:01 +08001021 # media_profiles.xml should have at least one CamcorderProfiles.
1022 if camera_id == 0:
1023 return None
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001024
1025 root.extend([
1026 etree.Element('EncoderOutputFileFormat', attrib={'name': '3gp'}),
1027 etree.Element('EncoderOutputFileFormat', attrib={'name': 'mp4'}),
1028 _gen_video_encoder_cap('h264', 64000, 17000000),
1029 _gen_video_encoder_cap('h263', 64000, 1000000),
1030 _gen_video_encoder_cap('m4v', 64000, 2000000),
1031 _gen_audio_encoder_cap('aac', 758, 288000, 8000, 48000),
1032 _gen_audio_encoder_cap('heaac', 8000, 64000, 16000, 48000),
1033 _gen_audio_encoder_cap('aaceld', 16000, 192000, 16000, 48000),
1034 _gen_audio_encoder_cap('amrwb', 6600, 23050, 16000, 16000),
1035 _gen_audio_encoder_cap('amrnb', 5525, 12200, 8000, 8000),
1036 etree.Element(
1037 'VideoDecoderCap', attrib={
1038 'name': 'wmv',
1039 'enabled': 'false'
1040 }),
1041 etree.Element(
1042 'AudioDecoderCap', attrib={
1043 'name': 'wma',
1044 'enabled': 'false'
1045 }),
1046 ])
Ren-Pei Zeng21708cc2020-11-17 11:14:07 +08001047
1048 dtd_path = os.path.dirname(__file__)
1049 dtd = etree.DTD(os.path.join(dtd_path, 'media_profiles.dtd'))
1050 if not dtd.validate(root):
1051 raise etree.DTDValidateError(
1052 'Invalid media_profiles.xml generated:\n{}'.format(dtd.error_log))
1053
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001054 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001055
1056
1057def _write_files_by_design_config(configs, output_dir, build_dir, system_dir,
1058 file_name_template, generate_file_content):
1059 """Writes generated files for each design config.
1060
1061 Args:
1062 configs: Source ConfigBundle to process.
1063 output_dir: Path to the generated output.
1064 build_dir: Path to the config file from portage's perspective.
1065 system_dir: Path to the config file in the target device.
1066 file_name_template: Template string of the config file name including one
1067 format()-style replacement field for the config id, e.g. 'config_{}.xml'.
1068 generate_file_content: Function to generate config file content from
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001069 HardwareFeatures and SoftwareConfig proto.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001070 Returns:
1071 dict that maps the formatted config id to the correct file.
1072 """
1073 # pylint: disable=too-many-arguments,too-many-locals
C Shapiro5bf23a72020-04-24 11:40:17 -05001074 result = {}
C Shapiroea33cff2020-05-11 13:32:05 -05001075 configs_by_design = {}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001076 for hw_design in configs.design_list:
C Shapiro5bf23a72020-04-24 11:40:17 -05001077 for design_config in hw_design.configs:
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001078 sw_config = _sw_config(configs.software_configs, design_config.id.value)
1079 config_content = generate_file_content(design_config.hardware_features,
1080 sw_config)
1081 if not config_content:
1082 continue
C Shapiroea33cff2020-05-11 13:32:05 -05001083 design_name = hw_design.name.lower()
C Shapiro5bf23a72020-04-24 11:40:17 -05001084
C Shapiroea33cff2020-05-11 13:32:05 -05001085 # Constructs the following map:
1086 # design_name -> config -> design_configs
1087 # This allows any of the following file naming schemes:
1088 # - All configs within a design share config (design_name prefix only)
1089 # - Nobody shares (full design_name and config id prefix needed)
1090 #
1091 # Having shared configs when possible makes code reviews easier around
1092 # the configs and makes debugging easier on the platform side.
C Shapiroea33cff2020-05-11 13:32:05 -05001093 arc_configs = configs_by_design.get(design_name, {})
1094 design_configs = arc_configs.get(config_content, [])
1095 design_configs.append(design_config)
1096 arc_configs[config_content] = design_configs
1097 configs_by_design[design_name] = arc_configs
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001098
C Shapiroea33cff2020-05-11 13:32:05 -05001099 for design_name, unique_configs in configs_by_design.items():
1100 for file_content, design_configs in unique_configs.items():
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001101 file_name = file_name_template.format(design_name)
Andrew Lamb2413c982020-05-29 12:15:36 -06001102 if len(unique_configs) == 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001103 _write_file(output_dir, file_name, file_content)
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001104
Andrew Lamb2413c982020-05-29 12:15:36 -06001105 for design_config in design_configs:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001106 config_id = _get_formatted_config_id(design_config)
Andrew Lamb2413c982020-05-29 12:15:36 -06001107 if len(unique_configs) > 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001108 file_name = file_name_template.format(config_id)
1109 _write_file(output_dir, file_name, file_content)
1110 result[config_id] = _file_v2('{}/{}'.format(build_dir, file_name),
1111 '{}/{}'.format(system_dir, file_name))
C Shapiro5bf23a72020-04-24 11:40:17 -05001112 return result
1113
1114
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001115def _write_arc_hardware_feature_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001116 return _write_files_by_design_config(
1117 configs, output_root_dir + '/arc', build_root_dir + '/arc', '/etc',
1118 'hardware_features_{}.xml',
1119 lambda hw_features, _: _generate_arc_hardware_features(hw_features))
1120
1121
1122def _write_arc_media_profile_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001123 return _write_files_by_design_config(configs, output_root_dir + '/arc',
1124 build_root_dir + '/arc', '/etc',
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001125 'media_profiles_{}.xml',
1126 _generate_arc_media_profiles)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001127
1128
Andrew Lambcd33f702020-06-11 10:45:16 -06001129def _read_config(path):
David Burgerd4f32962020-05-02 12:07:40 -06001130 """Reads a ConfigBundle proto from a json pb file.
David Burgere6f76222020-04-27 11:08:01 -06001131
1132 Args:
David Burgerd4f32962020-05-02 12:07:40 -06001133 path: Path to the file encoding the json pb proto.
David Burgere6f76222020-04-27 11:08:01 -06001134 """
1135 config = config_bundle_pb2.ConfigBundle()
1136 with open(path, 'r') as f:
1137 return json_format.Parse(f.read(), config)
1138
1139
Andrew Lambcd33f702020-06-11 10:45:16 -06001140def _merge_configs(configs):
David Burger7fd1dbe2020-03-26 09:26:55 -06001141 result = config_bundle_pb2.ConfigBundle()
1142 for config in configs:
1143 result.MergeFrom(config)
1144
1145 return result
1146
1147
David Burger1ba78a22020-06-18 18:42:47 -06001148def _camera_map(configs, project_name):
David Burger8ee9b4d2020-06-16 17:40:21 -06001149 """Produces a camera config map for the given configs.
1150
1151 Produces a map that maps from the design name to the camera config for that
1152 design.
1153
1154 Args:
1155 configs: Source ConfigBundle to process.
David Burger1ba78a22020-06-18 18:42:47 -06001156 project_name: Name of project processing for.
David Burger8ee9b4d2020-06-16 17:40:21 -06001157
1158 Returns:
1159 map from design name to camera config.
1160 """
1161 result = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -06001162 for design in configs.design_list:
David Burger8ee9b4d2020-06-16 17:40:21 -06001163 design_name = design.name
David Burger0d9e8462020-06-19 14:12:37 -06001164 config_path = CAMERA_CONFIG_SOURCE_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001165 if os.path.exists(config_path):
David Burger0d9e8462020-06-19 14:12:37 -06001166 destination = CAMERA_CONFIG_DEST_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001167 result[design_name] = {
David Burger1ba78a22020-06-18 18:42:47 -06001168 'config-file':
1169 _file_v2(os.path.join(project_name, config_path), destination),
David Burger8ee9b4d2020-06-16 17:40:21 -06001170 }
1171 return result
1172
1173
David Burger52c9d322020-06-09 07:16:18 -06001174def _dptf_map(configs, project_name):
1175 """Produces a dptf map for the given configs.
1176
1177 Produces a map that maps from design name to the dptf file config for that
1178 design. It looks for the dptf files at:
David Burger2f0d9522020-07-30 10:52:28 -06001179 DPTF_PATH + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001180 for a project wide config, that it maps under the empty string, and at:
David Burger2f0d9522020-07-30 10:52:28 -06001181 DPTF_PATH + '/' + design_name + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001182 for design specific configs that it maps under the design name.
1183
1184 Args:
1185 configs: Source ConfigBundle to process.
1186 project_name: Name of project processing for.
1187
1188 Returns:
David Burger8ee9b4d2020-06-16 17:40:21 -06001189 map from design name or empty string (project wide), to dptf config.
David Burger52c9d322020-06-09 07:16:18 -06001190 """
1191 result = {}
David Burger52c9d322020-06-09 07:16:18 -06001192 # Looking at top level for project wide, and then for each design name
1193 # for design specific.
Sean McAllisterf66887b2020-08-03 14:00:51 -06001194 dirs = [""] + [d.name for d in configs.design_list]
David Burger52c9d322020-06-09 07:16:18 -06001195 for directory in dirs:
David Burgera2252762020-07-09 15:09:49 -06001196 design = directory.lower()
1197 if os.path.exists(os.path.join(DPTF_PATH, design, DPTF_FILE)):
David Burger2f0d9522020-07-30 10:52:28 -06001198 project_dptf_path = os.path.join(project_name, design, DPTF_FILE)
David Burger52c9d322020-06-09 07:16:18 -06001199 dptf_file = {
1200 'dptf-dv':
1201 project_dptf_path,
1202 'files': [
1203 _file(
David Burgera2252762020-07-09 15:09:49 -06001204 os.path.join(project_name, DPTF_PATH, design, DPTF_FILE),
David Burger52c9d322020-06-09 07:16:18 -06001205 os.path.join('/etc/dptf', project_dptf_path))
1206 ]
1207 }
1208 result[directory] = dptf_file
1209 return result
1210
1211
David Burgerceeb68a2020-09-03 11:31:10 -06001212def _wifi_sar_map(configs, project_name, output_dir, build_root_dir):
1213 """Constructs a map from design name to wifi sar config for that design.
1214
1215 Constructs a map from design name to the wifi sar config for that design.
1216 In the process a wifi sar hex file is generated that the config points at.
1217 This mapping is only made for the intel wifi where the generated file is
1218 provided when building coreboot.
1219
1220 Args:
1221 configs: Source ConfigBundle to process.
1222 project_name: Name of project processing for.
1223 output_dir: Path to the generated output.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001224 build_root_dir: Path to the config file from portage's perspective.
David Burgerceeb68a2020-09-03 11:31:10 -06001225
1226 Returns:
1227 dict that maps the design name onto the wifi config for that design.
1228 """
1229 # pylint: disable=too-many-locals
1230 result = {}
1231 programs = {p.id.value: p for p in configs.program_list}
1232 sw_configs = list(configs.software_configs)
1233 for hw_design in configs.design_list:
1234 for hw_design_config in hw_design.configs:
1235 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
1236 if sw_config.wifi_config.HasField('intel_config'):
1237 sar_file_content = _create_intel_sar_file_content(
1238 sw_config.wifi_config.intel_config)
1239 design_name = hw_design.name.lower()
1240 program = _lookup(hw_design.program_id, programs)
1241 wifi_sar_id = _extract_fw_config_value(hw_design_config, program,
1242 'Intel wifi sar id')
1243 output_path = os.path.join(output_dir, 'wifi')
1244 os.makedirs(output_path, exist_ok=True)
1245 filename = 'wifi_sar_{}.hex'.format(wifi_sar_id)
1246 output_path = os.path.join(output_path, filename)
1247 build_path = os.path.join(build_root_dir, 'wifi', filename)
1248 if os.path.exists(output_path):
1249 with open(output_path, 'r') as f:
1250 if f.read() != sar_file_content:
1251 raise Exception(
1252 'Project {} has conflicting wifi sar file content under '
1253 'wifi sar id {}.'.format(project_name, wifi_sar_id))
1254 else:
1255 with open(output_path, 'w') as f:
1256 f.write(sar_file_content)
1257 system_path = '/firmware/cbfs-rw-raw/{}/{}'.format(
1258 project_name, filename)
David Burger89e7cae2020-09-15 17:04:12 -06001259 result[design_name] = {'sar-file': _file_v2(build_path, system_path)}
David Burgerceeb68a2020-09-03 11:31:10 -06001260 return result
1261
1262
1263def _extract_fw_config_value(hw_design_config, program, name):
1264 """Extracts the firwmare config value with the given name.
1265
1266 Args:
1267 hw_design_config: Design extracting value from.
1268 program: Program the `hw_design_config` belongs to.
1269 name: Name of firmware config segment to extract.
1270
1271 Returns: the extracted value or raises a ValueError if no firmware
1272 configuration segment with `name` is found.
1273 """
1274 fw_config = hw_design_config.hardware_features.fw_config.value
1275 for fcs in program.firmware_configuration_segments:
1276 if fcs.name == name:
1277 value = fw_config & fcs.mask
1278 lsb_bit_set = (~fcs.mask + 1) & fcs.mask
1279 return value // lsb_bit_set
1280 raise ValueError(
1281 'No firmware configuration segment with name {} found'.format(name))
1282
1283
1284def _create_intel_sar_file_content(intel_config):
1285 """Creates and returns the intel sar file content for the given config.
1286
1287 Creates and returns the sar file content that is used with intel drivers
1288 only.
1289
1290 Args:
1291 intel_config: IntelConfig config.
1292
1293 Returns:
1294 sar file content for the given config, see:
1295 https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1296 """
1297
1298 def to_hex(val):
1299 if val > 255 or val < 0:
1300 raise Exception('Sar file value %s out of range' % val)
1301 return '{0:0{1}X}'.format(val, 2)
1302
1303 def power_table(tpc):
1304 return (to_hex(tpc.limit_2g) + to_hex(tpc.limit_5g_1) +
1305 to_hex(tpc.limit_5g_2) + to_hex(tpc.limit_5g_3) +
1306 to_hex(tpc.limit_5g_4))
1307
1308 def wgds_value(wgds):
1309 return to_hex(wgds)
1310
1311 def offset_table(offsets):
1312 return (to_hex(offsets.max_2g) + to_hex(offsets.offset_2g_a) +
1313 to_hex(offsets.offset_2g_b) + to_hex(offsets.max_5g) +
1314 to_hex(offsets.offset_5g_a) + to_hex(offsets.offset_5g_b))
1315
1316 # See https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1317 return (power_table(intel_config.tablet_mode_power_table_a) +
1318 power_table(intel_config.tablet_mode_power_table_b) +
1319 power_table(intel_config.non_tablet_mode_power_table_a) +
1320 power_table(intel_config.non_tablet_mode_power_table_b) +
1321 '00000000000000000000' + '00000000000000000000' +
1322 wgds_value(intel_config.wgds_version) +
1323 offset_table(intel_config.offset_fcc) +
1324 offset_table(intel_config.offset_eu) +
1325 offset_table(intel_config.offset_other))
1326
1327
Andrew Lambcd33f702020-06-11 10:45:16 -06001328def Main(project_configs, program_config, output): # pylint: disable=invalid-name
David Burger7fd1dbe2020-03-26 09:26:55 -06001329 """Transforms source proto config into platform JSON.
1330
1331 Args:
1332 project_configs: List of source project configs to transform.
1333 program_config: Program config for the given set of projects.
1334 output: Output file that will be generated by the transform.
1335 """
Andrew Lambcd33f702020-06-11 10:45:16 -06001336 configs = _merge_configs([_read_config(program_config)] +
1337 [_read_config(config) for config in project_configs])
C Shapiro2b6d5332020-05-06 17:51:35 -05001338 touch_fw = {}
David Burger8ee9b4d2020-06-16 17:40:21 -06001339 camera_map = {}
David Burgerceeb68a2020-09-03 11:31:10 -06001340 dptf_map = {}
1341 wifi_sar_map = {}
C Shapiro5bf23a72020-04-24 11:40:17 -05001342 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -05001343 build_root_dir = output_dir
C Shapiro5c877992020-04-29 12:11:28 -05001344 if 'sw_build_config' in output_dir:
1345 full_path = os.path.realpath(output)
Andrew Lamb6b607732020-08-24 15:52:46 -06001346 project_name = re.match(r'.*/(\w*)/(public_)?sw_build_config/.*',
Andrew Lamb2413c982020-05-29 12:15:36 -06001347 full_path).groups(1)[0]
C Shapiro5c877992020-04-29 12:11:28 -05001348 # Projects don't know about each other until they are integrated into the
1349 # build system. When this happens, the files need to be able to co-exist
1350 # without any collisions. This prefixes the project name (which is how
1351 # portage maps in the project), so project files co-exist and can be
1352 # installed together.
1353 # This is necessary to allow projects to share files at the program level
1354 # without having portage file installation collisions.
1355 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -05001356
David Burger1ba78a22020-06-18 18:42:47 -06001357 camera_map = _camera_map(configs, project_name)
David Burger52c9d322020-06-09 07:16:18 -06001358 dptf_map = _dptf_map(configs, project_name)
David Burgerceeb68a2020-09-03 11:31:10 -06001359 wifi_sar_map = _wifi_sar_map(configs, project_name, output_dir,
1360 build_root_dir)
David Burger52c9d322020-06-09 07:16:18 -06001361
C Shapiro2b6d5332020-05-06 17:51:35 -05001362 if os.path.exists(TOUCH_PATH):
Andrew Lambcd33f702020-06-11 10:45:16 -06001363 touch_fw = _build_touch_file_config(configs, project_name)
Andrew Lambcd33f702020-06-11 10:45:16 -06001364 arc_hw_feature_files = _write_arc_hardware_feature_files(
1365 configs, output_dir, build_root_dir)
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001366 arc_media_profile_files = _write_arc_media_profile_files(
1367 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -05001368 config_files = ConfigFiles(
C Shapiro5bf23a72020-04-24 11:40:17 -05001369 arc_hw_features=arc_hw_feature_files,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001370 arc_media_profiles=arc_media_profile_files,
C Shapiro2b6d5332020-05-06 17:51:35 -05001371 touch_fw=touch_fw,
David Burger8ee9b4d2020-06-16 17:40:21 -06001372 dptf_map=dptf_map,
David Burgerceeb68a2020-09-03 11:31:10 -06001373 camera_map=camera_map,
1374 wifi_sar_map=wifi_sar_map)
Andrew Lambcd33f702020-06-11 10:45:16 -06001375 write_output(_transform_build_configs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -06001376
1377
1378def main(argv=None):
1379 """Main program which parses args and runs
1380
1381 Args:
1382 argv: List of command line arguments, if None uses sys.argv.
1383 """
1384 if argv is None:
1385 argv = sys.argv[1:]
Andrew Lambcd33f702020-06-11 10:45:16 -06001386 opts = parse_args(argv)
David Burger7fd1dbe2020-03-26 09:26:55 -06001387 Main(opts.project_configs, opts.program_config, opts.output)
1388
1389
1390if __name__ == '__main__':
1391 sys.exit(main(sys.argv[1:]))