blob: a77cc77ca2e0667861f2d5e982ab8e0de6c8e599 [file] [log] [blame]
David Burger7fd1dbe2020-03-26 09:26:55 -06001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright 2020 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""Transforms config from /config/proto/api proto format to platform JSON."""
7
Ren-Pei Zengce869dd2020-08-18 01:29:37 +08008# pylint: disable=too-many-lines
9
David Burger7fd1dbe2020-03-26 09:26:55 -060010import argparse
11import json
12import pprint
C Shapiro90fda252020-04-17 14:34:57 -050013import os
David Burger7fd1dbe2020-03-26 09:26:55 -060014import sys
C Shapiro90fda252020-04-17 14:34:57 -050015import re
David Burger7fd1dbe2020-03-26 09:26:55 -060016
Andrew Lamb319cc922020-06-15 10:45:46 -060017from typing import List
18
David Burger7fd1dbe2020-03-26 09:26:55 -060019from collections import namedtuple
20
Andrew Lambcd33f702020-06-11 10:45:16 -060021from google.protobuf import json_format
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080022from lxml import etree
Andrew Lambcd33f702020-06-11 10:45:16 -060023
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070024from chromiumos.config.api import device_brand_pb2
David Burger92609a32020-04-23 10:38:50 -060025from chromiumos.config.api import topology_pb2
C Shapiro5bf23a72020-04-24 11:40:17 -050026from chromiumos.config.payload import config_bundle_pb2
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070027from chromiumos.config.api.software import brand_config_pb2
David Burger7fd1dbe2020-03-26 09:26:55 -060028
Andrew Lamb2413c982020-05-29 12:15:36 -060029Config = namedtuple('Config', [
30 'program', 'hw_design', 'odm', 'hw_design_config', 'device_brand',
C Shapirod5545f12020-11-30 16:37:04 -060031 'device_signer_config', 'oem', 'sw_config', 'brand_config'
Andrew Lamb2413c982020-05-29 12:15:36 -060032])
David Burger7fd1dbe2020-03-26 09:26:55 -060033
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080034ConfigFiles = namedtuple('ConfigFiles', [
35 'arc_hw_features', 'arc_media_profiles', 'touch_fw', 'dptf_map',
36 'camera_map', 'wifi_sar_map'
37])
David Burger8ee9b4d2020-06-16 17:40:21 -060038
39CAMERA_CONFIG_DEST_PATH_TEMPLATE = '/etc/camera/camera_config_{}.json'
40CAMERA_CONFIG_SOURCE_PATH_TEMPLATE = (
41 'sw_build_config/platform/chromeos-config/camera/camera_config_{}.json')
C Shapiro5bf23a72020-04-24 11:40:17 -050042
David Burger52c9d322020-06-09 07:16:18 -060043DPTF_PATH = 'sw_build_config/platform/chromeos-config/thermal'
44DPTF_FILE = 'dptf.dv'
David Burger2f0d9522020-07-30 10:52:28 -060045
C Shapiro2b6d5332020-05-06 17:51:35 -050046TOUCH_PATH = 'sw_build_config/platform/chromeos-config/touch'
Andrew Lamb6c42efc2020-06-16 10:40:43 -060047WALLPAPER_BASE_PATH = '/usr/share/chromeos-assets/wallpaper'
David Burger7fd1dbe2020-03-26 09:26:55 -060048
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080049XML_DECLARATION = b'<?xml version="1.0" encoding="utf-8"?>\n'
50
Andrew Lamb2413c982020-05-29 12:15:36 -060051
Andrew Lambcd33f702020-06-11 10:45:16 -060052def parse_args(argv):
David Burger7fd1dbe2020-03-26 09:26:55 -060053 """Parse the available arguments.
54
55 Invalid arguments or -h cause this function to print a message and exit.
56
57 Args:
58 argv: List of string arguments (excluding program name / argv[0])
59
60 Returns:
61 argparse.Namespace object containing the attributes.
62 """
63 parser = argparse.ArgumentParser(
64 description='Converts source proto config into platform JSON config.')
65 parser.add_argument(
66 '-c',
67 '--project_configs',
68 nargs='+',
69 type=str,
70 help='Space delimited list of source protobinary project config files.')
71 parser.add_argument(
72 '-p',
73 '--program_config',
74 type=str,
75 help='Path to the source program-level protobinary file')
76 parser.add_argument(
Andrew Lamb2413c982020-05-29 12:15:36 -060077 '-o', '--output', type=str, help='Output file that will be generated')
David Burger7fd1dbe2020-03-26 09:26:55 -060078 return parser.parse_args(argv)
79
80
David Burger8ee9b4d2020-06-16 17:40:21 -060081def _upsert(field, target, target_name):
82 """Updates or inserts `field` within `target`.
83
84 If `target_name` already exists within `target` an update is performed,
85 otherwise, an insert is performed.
86 """
Sam McNally9a873f72020-06-05 19:47:22 +100087 if field or field == 0:
David Burger8ee9b4d2020-06-16 17:40:21 -060088 if target_name in target:
89 target[target_name].update(field)
90 else:
91 target[target_name] = field
David Burger7fd1dbe2020-03-26 09:26:55 -060092
93
Andrew Lambcd33f702020-06-11 10:45:16 -060094def _build_arc(config, config_files):
Andrew Lambcd33f702020-06-11 10:45:16 -060095 build_properties = {
C Shapirod5545f12020-11-30 16:37:04 -060096 # TODO(chromium:1126527) - Push this into the overlay itself.
97 # This isn't/can't be device specific and shouldn't be configured as such.
98 'device': "%s_cheets" % config.program.name.lower(),
99 'first-api-level': '28',
Andrew Lambcd33f702020-06-11 10:45:16 -0600100 'marketing-name': config.device_brand.brand_name,
101 'metrics-tag': config.hw_design.name.lower(),
C Shapirod5545f12020-11-30 16:37:04 -0600102 'product': config.program.name.lower(),
Andrew Lambcd33f702020-06-11 10:45:16 -0600103 }
104 if config.oem:
105 build_properties['oem'] = config.oem.name
106 result = {'build-properties': build_properties}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800107 config_id = _get_formatted_config_id(config.hw_design_config)
108 if config_id in config_files.arc_hw_features:
109 result['hardware-features'] = config_files.arc_hw_features[config_id]
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800110 if config_id in config_files.arc_media_profiles:
111 result['media-profiles'] = config_files.arc_media_profiles[config_id]
Andrew Lambcd33f702020-06-11 10:45:16 -0600112 topology = config.hw_design_config.hardware_topology
113 ppi = topology.screen.hardware_feature.screen.panel_properties.pixels_per_in
114 # Only set for high resolution displays
115 if ppi and ppi > 250:
116 result['scale'] = ppi
David Burger2f0d9522020-07-30 10:52:28 -0600117
Andrew Lambcd33f702020-06-11 10:45:16 -0600118 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600119
Andrew Lamb2413c982020-05-29 12:15:36 -0600120
Andrew Lamb319cc922020-06-15 10:45:46 -0600121def _build_ash_flags(config: Config) -> List[str]:
122 """Returns a list of Ash flags for config.
123
124 Ash is the window manager and system UI for ChromeOS, see
125 https://chromium.googlesource.com/chromium/src/+/refs/heads/master/ash/.
126 """
127 # A map from flag name -> value. Value may be None for boolean flags.
128 flags = {}
129
130 hw_features = config.hw_design_config.hardware_features
131 if hw_features.stylus.stylus == topology_pb2.HardwareFeatures.Stylus.INTERNAL:
Andrew Lamb2e641e22020-06-15 12:30:41 -0600132 flags['has-internal-stylus'] = None
Andrew Lamb319cc922020-06-15 10:45:46 -0600133
Andrew Lamb2e641e22020-06-15 12:30:41 -0600134 fp_loc = hw_features.fingerprint.location
135 if fp_loc and fp_loc != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
136 loc_name = topology_pb2.HardwareFeatures.Fingerprint.Location.Name(fp_loc)
137 flags['fingerprint-sensor-location'] = loc_name.lower().replace('_', '-')
138
Andrew Lamb6c42efc2020-06-16 10:40:43 -0600139 wallpaper = config.brand_config.wallpaper
140 # If a wallpaper is set, the 'default-wallpaper-is-oem' flag needs to be set.
141 # If a wallpaper is not set, the 'default_[large|small].jpg' wallpapers
142 # should still be set.
143 if wallpaper:
144 flags['default-wallpaper-is-oem'] = None
145 else:
146 wallpaper = 'default'
147
148 for size in ('small', 'large'):
149 flags[f'default-wallpaper-{size}'] = (
150 f'{WALLPAPER_BASE_PATH}/{wallpaper}_{size}.jpg')
151
152 # For each size, also install 'guest' and 'child' wallpapers.
153 for wallpaper_type in ('guest', 'child'):
154 flags[f'{wallpaper_type}-wallpaper-{size}'] = (
155 f'{WALLPAPER_BASE_PATH}/{wallpaper_type}_{size}.jpg')
156
C Shapiro2e97aad2020-11-16 11:58:10 -0600157 regulatory_label = config.brand_config.regulatory_label
158 if regulatory_label:
159 flags['regulatory-label-dir'] = (regulatory_label)
160
C Shapirod5545f12020-11-30 16:37:04 -0600161 flags['arc-build-properties'] = {
162 'device': "%s_cheets" % config.program.name.lower(),
163 'firstApiLevel': '28',
164 }
Andrew Lamb72d41362020-06-17 09:19:02 -0600165
Andrew Lamb90b168c2020-06-22 10:42:30 -0600166 power_button = hw_features.power_button
167 if power_button.edge:
168 flags['ash-power-button-position'] = json.dumps({
169 'edge':
170 topology_pb2.HardwareFeatures.Button.Edge.Name(power_button.edge
171 ).lower(),
172 # Starlark sometimes represents float literals strangely, e.g. changing
173 # 0.9 to 0.899999. Round to two digits here.
174 'position':
175 round(power_button.position, 2)
176 })
177
178 volume_button = hw_features.volume_button
179 if volume_button.edge:
180 flags['ash-side-volume-button-position'] = json.dumps({
181 'region':
182 topology_pb2.HardwareFeatures.Button.Region.Name(
183 volume_button.region).lower(),
Sam McNallye1f77422021-04-20 21:08:24 +1000184 'side':
Andrew Lamb90b168c2020-06-22 10:42:30 -0600185 topology_pb2.HardwareFeatures.Button.Edge.Name(volume_button.edge
186 ).lower(),
187 })
188
Nikolai Artemievda87d992020-12-04 15:09:00 +1100189 form_factor = hw_features.form_factor.form_factor
190 lid_accel = hw_features.accelerometer.lid_accelerometer
191 if (form_factor == topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE and
192 lid_accel == topology_pb2.HardwareFeatures.PRESENT):
Nikolai Artemiev03de0e02021-03-23 17:46:49 +1100193 flags['supports-clamshell-auto-rotation'] = None
Nikolai Artemievda87d992020-12-04 15:09:00 +1100194
Tim Sergeant7a022462021-04-07 20:23:32 +1000195 if config.sw_config.ui_config.extra_web_apps_dir:
196 flags['extra-web-apps-dir'] = config.sw_config.ui_config.extra_web_apps_dir
197
Toni Barzicf802a702021-05-18 19:40:23 -0700198 if hw_features.microphone_mute_switch.present == topology_pb2.HardwareFeatures.PRESENT:
199 flags['enable-microphone-mute-switch-device'] = None
200
Andrew Lamb2e641e22020-06-15 12:30:41 -0600201 return sorted([f'--{k}={v}' if v else f'--{k}' for k, v in flags.items()])
Andrew Lamb319cc922020-06-15 10:45:46 -0600202
203
204def _build_ui(config: Config) -> dict:
205 """Builds the 'ui' property from cros_config_schema."""
206 return {'extra-ash-flags': _build_ash_flags(config)}
207
208
David Burger07af5242020-08-11 11:08:25 -0600209def _build_bluetooth(config):
C Shapiro90fda252020-04-17 14:34:57 -0500210 bt_flags = config.sw_config.bluetooth_config.flags
211 # Convert to native map (from proto wrapper)
212 bt_flags_map = dict(bt_flags)
213 result = {}
214 if bt_flags_map:
215 result['flags'] = bt_flags_map
C Shapiro90fda252020-04-17 14:34:57 -0500216 return result
217
David Burger7fd1dbe2020-03-26 09:26:55 -0600218
David Burgerceeb68a2020-09-03 11:31:10 -0600219def _build_ath10k_config(ath10k_config):
220 """Builds the wifi configuration for the ath10k driver.
221
222 Args:
223 ath10k_config: Ath10kConfig config.
224
225 Returns:
226 wifi configuration for the ath10k driver.
227 """
David Burgerec753912020-08-10 12:59:11 -0600228 result = {}
David Burgerec753912020-08-10 12:59:11 -0600229
David Burgerceeb68a2020-09-03 11:31:10 -0600230 def power_chain(power):
231 return {
232 'limit-2g': power.limit_2g,
233 'limit-5g': power.limit_5g,
234 }
David Burgerec753912020-08-10 12:59:11 -0600235
David Burgerceeb68a2020-09-03 11:31:10 -0600236 result['tablet-mode-power-table-ath10k'] = power_chain(
237 ath10k_config.tablet_mode_power_table)
238 result['non-tablet-mode-power-table-ath10k'] = power_chain(
239 ath10k_config.non_tablet_mode_power_table)
David Burgerec753912020-08-10 12:59:11 -0600240 return result
241
242
David Burgerceeb68a2020-09-03 11:31:10 -0600243def _build_rtw88_config(rtw88_config):
244 """Builds the wifi configuration for the rtw88 driver.
245
246 Args:
247 rtw88_config: Rtw88Config config.
248
249 Returns:
250 wifi configuration for the rtw88 driver.
251 """
252 result = {}
253
254 def power_chain(power):
255 return {
256 'limit-2g': power.limit_2g,
257 'limit-5g-1': power.limit_5g_1,
258 'limit-5g-3': power.limit_5g_3,
259 'limit-5g-4': power.limit_5g_4,
260 }
261
262 result['tablet-mode-power-table-rtw'] = power_chain(
263 rtw88_config.tablet_mode_power_table)
264 result['non-tablet-mode-power-table-rtw'] = power_chain(
265 rtw88_config.non_tablet_mode_power_table)
266
267 def offsets(offset):
268 return {
269 'offset-2g': offset.offset_2g,
270 'offset-5g': offset.offset_5g,
271 }
272
273 result['geo-offsets-fcc'] = offsets(rtw88_config.offset_fcc)
274 result['geo-offsets-eu'] = offsets(rtw88_config.offset_eu)
275 result['geo-offsets-rest-of-world'] = offsets(rtw88_config.offset_other)
276 return result
277
278
279def _build_intel_config(config, config_files):
280 """Builds the wifi configuration for the intel driver.
281
282 Args:
283 config: Config namedtuple
284 config_files: Map to look up the generated config files.
285
286 Returns:
287 wifi configuration for the intel driver.
288 """
289 design_name = config.hw_design.name.lower()
290 return config_files.wifi_sar_map.get(design_name)
291
292
293def _build_wifi(config, config_files):
294 """Builds the wifi configuration.
295
296 Args:
297 config: Config namedtuple
298 config_files: Map to look up the generated config files.
299
300 Returns:
301 wifi configuration.
302 """
303 config_field = config.sw_config.wifi_config.WhichOneof('wifi_config')
304 if config_field == 'ath10k_config':
305 return _build_ath10k_config(config.sw_config.wifi_config.ath10k_config)
306 if config_field == 'rtw88_config':
307 return _build_rtw88_config(config.sw_config.wifi_config.rtw88_config)
308 if config_field == 'intel_config':
309 return _build_intel_config(config, config_files)
310 return {}
311
312
Andrew Lambcd33f702020-06-11 10:45:16 -0600313def _build_fingerprint(hw_topology):
314 if not hw_topology.HasField('fingerprint'):
315 return None
316
317 fp = hw_topology.fingerprint.hardware_feature.fingerprint
318 result = {}
319 if fp.location != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
320 location = fp.Location.DESCRIPTOR.values_by_number[fp.location].name
321 result['sensor-location'] = location.lower().replace('_', '-')
322 if fp.board:
323 result['board'] = fp.board
Tom Hughesdfc35402020-06-29 16:02:09 -0700324 if fp.ro_version:
325 result['ro-version'] = fp.ro_version
326
Andrew Lambcd33f702020-06-11 10:45:16 -0600327 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600328
329
Trent Beginf067ccb2020-08-12 12:33:53 -0600330def _build_hardware_properties(hw_topology):
331 if not hw_topology.HasField('form_factor'):
332 return None
333
334 form_factor = hw_topology.form_factor.hardware_feature.form_factor.form_factor
335 result = {}
336 if form_factor in [
337 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
338 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE,
339 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
340 ]:
341 result['psu-type'] = "AC_only"
342 else:
343 result['psu-type'] = "battery"
344
345 result['has-backlight'] = form_factor not in [
346 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
347 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
348 ]
349
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100350 form_factor_names = {
Nikolai Artemievaf103a32021-02-15 14:37:16 +1100351 topology_pb2.HardwareFeatures.FormFactor.CLAMSHELL: "CHROMEBOOK",
352 topology_pb2.HardwareFeatures.FormFactor.CONVERTIBLE: "CHROMEBOOK",
353 topology_pb2.HardwareFeatures.FormFactor.DETACHABLE: "CHROMEBOOK",
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100354 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE: "CHROMEBASE",
Nikolai Artemievaf103a32021-02-15 14:37:16 +1100355 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX: "CHROMEBOX",
356 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT: "CHROMEBIT",
357 topology_pb2.HardwareFeatures.FormFactor.CHROMESLATE: "CHROMEBOOK",
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100358 }
359 if form_factor in form_factor_names:
360 result['form-factor'] = form_factor_names[form_factor]
361
Trent Beginf067ccb2020-08-12 12:33:53 -0600362 return result
363
364
Andrew Lambcd33f702020-06-11 10:45:16 -0600365def _fw_bcs_path(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600366 if payload and payload.firmware_image_name:
YH Lin873742a2021-03-02 07:02:31 -0800367 return 'bcs://%s.%d.%d.%d.tbz2' % (
368 payload.firmware_image_name, payload.version.major,
369 payload.version.minor, payload.version.patch)
David Burger7fd1dbe2020-03-26 09:26:55 -0600370
Andrew Lambcd33f702020-06-11 10:45:16 -0600371 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600372
Andrew Lambcd33f702020-06-11 10:45:16 -0600373
374def _fw_build_target(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600375 if payload:
376 return payload.build_target_name
377
Andrew Lambcd33f702020-06-11 10:45:16 -0600378 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600379
Andrew Lambcd33f702020-06-11 10:45:16 -0600380
381def _build_firmware(config):
David Burgerb70b6762020-05-21 12:14:59 -0600382 """Returns firmware config, or None if no build targets."""
Andrew Lamb3da156d2020-04-16 16:00:56 -0600383 fw_payload_config = config.sw_config.firmware
384 fw_build_config = config.sw_config.firmware_build_config
385 main_ro = fw_payload_config.main_ro_payload
386 main_rw = fw_payload_config.main_rw_payload
387 ec_ro = fw_payload_config.ec_ro_payload
388 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600389
390 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600391
David Burger8ee9b4d2020-06-16 17:40:21 -0600392 _upsert(fw_build_config.build_targets.depthcharge, build_targets,
393 'depthcharge')
394 _upsert(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
395 _upsert(fw_build_config.build_targets.ec, build_targets, 'ec')
396 _upsert(
Andrew Lambf8954ee2020-04-21 10:24:40 -0600397 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
David Burger8ee9b4d2020-06-16 17:40:21 -0600398 _upsert(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
YH Lind4809502021-04-06 13:46:40 -0700399 _upsert(fw_build_config.build_targets.zephyr_ec, build_targets, 'zephyr-ec')
David Burger7fd1dbe2020-03-26 09:26:55 -0600400
David Burgerb70b6762020-05-21 12:14:59 -0600401 if not build_targets:
402 return None
403
David Burger7fd1dbe2020-03-26 09:26:55 -0600404 result = {
C Shapirod5545f12020-11-30 16:37:04 -0600405 'bcs-overlay': 'overlay-%s-private' % config.program.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600406 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600407 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600408
David Burger8ee9b4d2020-06-16 17:40:21 -0600409 _upsert(main_ro.firmware_image_name.lower(), result, 'image-name')
Andrew Lamb883fa042020-04-06 11:37:22 -0600410
David Burger8ee9b4d2020-06-16 17:40:21 -0600411 _upsert(_fw_bcs_path(main_ro), result, 'main-ro-image')
412 _upsert(_fw_bcs_path(main_rw), result, 'main-rw-image')
413 _upsert(_fw_bcs_path(ec_ro), result, 'ec-ro-image')
414 _upsert(_fw_bcs_path(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600415
David Burger8ee9b4d2020-06-16 17:40:21 -0600416 _upsert(
Andrew Lambf39fbe82020-04-13 16:14:33 -0600417 config.hw_design_config.hardware_features.fw_config.value,
418 result,
419 'firmware-config',
420 )
421
David Burger7fd1dbe2020-03-26 09:26:55 -0600422 return result
423
424
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000425def _build_fw_signing(config, whitelabel):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500426 if config.sw_config.firmware and config.device_signer_config:
David Burger68e0d142020-05-15 17:29:33 -0600427 hw_design = config.hw_design.name.lower()
Sam McNally2fc807f2020-07-16 18:13:53 +1000428 brand_scan_config = config.brand_config.scan_config
429 if brand_scan_config and brand_scan_config.whitelabel_tag:
430 signature_id = '%s-%s' % (hw_design, brand_scan_config.whitelabel_tag)
431 else:
432 signature_id = hw_design
433
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000434 result = {
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500435 'key-id': config.device_signer_config.key_id,
Sam McNally2fc807f2020-07-16 18:13:53 +1000436 'signature-id': signature_id,
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500437 }
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000438 if whitelabel:
439 result['sig-id-in-customization-id'] = True
440 return result
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500441 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600442
443
Andrew Lambcd33f702020-06-11 10:45:16 -0600444def _file(source, destination):
Andrew Lamb2413c982020-05-29 12:15:36 -0600445 return {'destination': destination, 'source': source}
David Burger7fd1dbe2020-03-26 09:26:55 -0600446
447
David Burger40dfe3a2020-06-18 17:09:13 -0600448def _file_v2(build_path, system_path):
449 return {'build-path': build_path, 'system-path': system_path}
450
451
Andrew Lambcd33f702020-06-11 10:45:16 -0600452def _build_audio(config):
David Burger178f3ef2020-06-26 12:11:57 -0600453 if not config.sw_config.audio_configs:
454 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600455 alsa_path = '/usr/share/alsa/ucm'
456 cras_path = '/etc/cras'
Judy Hsiao1ae95122020-12-23 15:39:50 +0800457 sound_card_init_path = '/etc/sound_card_init'
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800458 design_name = config.hw_design.name.lower()
David Burger43250662020-05-07 11:21:50 -0600459 program_name = config.program.name.lower()
David Burger7fd1dbe2020-03-26 09:26:55 -0600460 files = []
David Burger178f3ef2020-06-26 12:11:57 -0600461 ucm_suffix = None
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800462 sound_card_init_conf = None
463
David Burger178f3ef2020-06-26 12:11:57 -0600464 for audio in config.sw_config.audio_configs:
465 card = audio.card_name
466 card_with_suffix = audio.card_name
467 if audio.ucm_suffix:
468 # TODO: last ucm_suffix wins.
469 ucm_suffix = audio.ucm_suffix
470 card_with_suffix += '.' + audio.ucm_suffix
471 if audio.ucm_file:
472 files.append(
473 _file(audio.ucm_file,
474 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
475 if audio.ucm_master_file:
476 files.append(
477 _file(
478 audio.ucm_master_file, '%s/%s/%s.conf' %
Andrew Lamb2413c982020-05-29 12:15:36 -0600479 (alsa_path, card_with_suffix, card_with_suffix)))
David Burger178f3ef2020-06-26 12:11:57 -0600480 if audio.card_config_file:
481 files.append(
482 _file(audio.card_config_file,
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800483 '%s/%s/%s' % (cras_path, design_name, card)))
David Burger178f3ef2020-06-26 12:11:57 -0600484 if audio.dsp_file:
485 files.append(
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800486 _file(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, design_name)))
David Burger178f3ef2020-06-26 12:11:57 -0600487 if audio.module_file:
488 files.append(
489 _file(audio.module_file,
490 '/etc/modprobe.d/alsa-%s.conf' % program_name))
491 if audio.board_file:
492 files.append(
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800493 _file(audio.board_file, '%s/%s/board.ini' % (cras_path, design_name)))
Judy Hsiao1ae95122020-12-23 15:39:50 +0800494 if audio.sound_card_init_file:
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800495 sound_card_init_conf = design_name + ".yaml"
Judy Hsiao1ae95122020-12-23 15:39:50 +0800496 files.append(
497 _file(audio.sound_card_init_file,
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800498 '%s/%s.yaml' % (sound_card_init_path, design_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600499
500 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600501 'main': {
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800502 'cras-config-dir': design_name,
David Burger7fd1dbe2020-03-26 09:26:55 -0600503 'files': files,
504 }
505 }
David Burger178f3ef2020-06-26 12:11:57 -0600506
507 if ucm_suffix:
508 result['main']['ucm-suffix'] = ucm_suffix
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800509 if sound_card_init_conf:
510 result['main']['sound-card-init-conf'] = sound_card_init_conf
David Burger599ff7b2020-04-06 16:29:31 -0600511
512 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600513
514
Andrew Lambcd33f702020-06-11 10:45:16 -0600515def _build_camera(hw_topology):
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800516 camera_pb = topology_pb2.HardwareFeatures.Camera
517 camera = hw_topology.camera.hardware_feature.camera
518 result = {'count': len(camera.devices)}
519 if camera.devices:
520 result['devices'] = []
521 for device in camera.devices:
522 interface = {
523 camera_pb.INTERFACE_USB: 'usb',
524 camera_pb.INTERFACE_MIPI: 'mipi',
525 }[device.interface]
526 facing = {
527 camera_pb.FACING_FRONT: 'front',
528 camera_pb.FACING_BACK: 'back',
529 }[device.facing]
530 orientation = {
531 camera_pb.ORIENTATION_0: 0,
532 camera_pb.ORIENTATION_90: 90,
533 camera_pb.ORIENTATION_180: 180,
534 camera_pb.ORIENTATION_270: 270,
535 }[device.orientation]
536 flags = {
537 'support-1080p':
538 bool(device.flags & camera_pb.FLAGS_SUPPORT_1080P),
539 'support-autofocus':
540 bool(device.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS),
541 }
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100542 dev = {
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800543 'interface': interface,
544 'facing': facing,
545 'orientation': orientation,
546 'flags': flags,
547 'ids': list(device.ids),
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100548 }
549 if device.privacy_switch != topology_pb2.HardwareFeatures.PRESENT_UNKNOWN:
550 dev['has-privacy-switch'] = device.privacy_switch == topology_pb2.HardwareFeatures.PRESENT
551 result['devices'].append(dev)
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800552 return result
David Burger8aa8fa32020-04-14 08:30:34 -0600553
Andrew Lambcd33f702020-06-11 10:45:16 -0600554
555def _build_identity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600556 identity = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600557 _upsert(hw_scan_config.firmware_sku, identity, 'sku-id')
558 _upsert(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600559 # 'platform-name' is needed to support 'mosys platform name'. Clients should
Sean McAllister0b757772020-11-13 12:22:36 -0700560 # no longer require platform name, but set it here for backwards compatibility.
561 if program.mosys_platform_name:
562 _upsert(program.mosys_platform_name, identity, 'platform-name')
563 else:
564 _upsert(program.name, identity, 'platform-name')
565
David Burger7fd1dbe2020-03-26 09:26:55 -0600566 # ARM architecture
David Burger8ee9b4d2020-06-16 17:40:21 -0600567 _upsert(hw_scan_config.device_tree_compatible_match, identity,
568 'device-tree-compatible-match')
David Burger7fd1dbe2020-03-26 09:26:55 -0600569
570 if brand_scan_config:
David Burger8ee9b4d2020-06-16 17:40:21 -0600571 _upsert(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
David Burger7fd1dbe2020-03-26 09:26:55 -0600572
573 return identity
574
575
Andrew Lambcd33f702020-06-11 10:45:16 -0600576def _lookup(id_value, id_map):
577 if not id_value.value:
578 return None
579
580 key = id_value.value
581 if key in id_map:
582 return id_map[id_value.value]
583 error = 'Failed to lookup %s with value: %s' % (
584 id_value.__class__.__name__.replace('Id', ''), key)
585 print(error)
586 print('Check the config contents provided:')
587 printer = pprint.PrettyPrinter(indent=4)
588 printer.pprint(id_map)
589 raise Exception(error)
David Burger7fd1dbe2020-03-26 09:26:55 -0600590
591
Andrew Lambcd33f702020-06-11 10:45:16 -0600592def _build_touch_file_config(config, project_name):
Sean McAllistereaf10b72020-08-03 13:41:06 -0600593 partners = {x.id.value: x for x in config.partner_list}
C Shapiro2b6d5332020-05-06 17:51:35 -0500594 files = []
595 for comp in config.components:
C Shapiro4813be62020-05-13 17:31:58 -0500596 touch = comp.touchscreen
597 # Everything is the same for Touch screen/pad, except different fields
598 if comp.HasField('touchpad'):
599 touch = comp.touchpad
600 if touch.product_id:
Andrew Lambcd33f702020-06-11 10:45:16 -0600601 vendor = _lookup(comp.manufacturer_id, partners)
C Shapiro2b6d5332020-05-06 17:51:35 -0500602 if not vendor:
Andrew Lamb2413c982020-05-29 12:15:36 -0600603 raise Exception("Manufacturer must be set for touch device %s" %
604 comp.id.value)
C Shapiro2b6d5332020-05-06 17:51:35 -0500605
C Shapiro4813be62020-05-13 17:31:58 -0500606 product_id = touch.product_id
607 fw_version = touch.fw_version
C Shapiro2b6d5332020-05-06 17:51:35 -0500608
C Shapiro2b6d5332020-05-06 17:51:35 -0500609 file_name = "%s_%s.bin" % (product_id, fw_version)
610 fw_file_path = os.path.join(TOUCH_PATH, vendor.name, file_name)
611
612 if not os.path.exists(fw_file_path):
Andrew Lamb2413c982020-05-29 12:15:36 -0600613 raise Exception("Touchscreen fw bin file doesn't exist at: %s" %
614 fw_file_path)
C Shapiro2b6d5332020-05-06 17:51:35 -0500615
C Shapiro303cece2020-07-22 07:15:21 -0500616 touch_vendor = vendor.touch_vendor
617 sym_link = touch_vendor.symlink_file_format.format(
618 vendor_name=vendor.name,
619 vendor_id=touch_vendor.vendor_id,
620 product_id=product_id,
621 fw_version=fw_version,
622 product_series=touch.product_series)
623
624 dest = "%s_%s" % (vendor.name, file_name)
625 if touch_vendor.destination_file_format:
626 dest = touch_vendor.destination_file_format.format(
627 vendor_name=vendor.name,
628 vendor_id=touch_vendor.vendor_id,
629 product_id=product_id,
630 fw_version=fw_version,
631 product_series=touch.product_series)
632
C Shapiro2b6d5332020-05-06 17:51:35 -0500633 files.append({
C Shapiro303cece2020-07-22 07:15:21 -0500634 "destination": os.path.join("/opt/google/touch/firmware", dest),
YH Lin9160fc52020-07-22 16:35:28 -0700635 "source": os.path.join(project_name, fw_file_path),
636 "symlink": os.path.join("/lib/firmware", sym_link),
C Shapiro2b6d5332020-05-06 17:51:35 -0500637 })
638
639 result = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600640 _upsert(files, result, 'files')
C Shapiro2b6d5332020-05-06 17:51:35 -0500641 return result
642
643
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000644def _build_modem(config):
645 """Returns the cellular modem configuration, or None if absent."""
646 hw_features = config.hw_design_config.hardware_features
647 lte_support = _any_present([hw_features.lte.present])
648 if not lte_support:
649 return None
Vincent Palatin0ebdfd32021-04-23 15:54:43 +0200650 firmware_variant = config.hw_design.name.lower()
651 if hw_features.lte.model:
652 firmware_variant += '_' + hw_features.lte.model.lower()
653 return {'firmware-variant': firmware_variant}
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000654
655
David Burgerceeb68a2020-09-03 11:31:10 -0600656def _sw_config(sw_configs, design_config_id):
657 """Returns the correct software config for `design_config_id`.
658
659 Returns the correct software config match for `design_config_id`. If no such
660 config or multiple such configs are found an exception is raised.
661 """
662 sw_config_matches = [
663 x for x in sw_configs if x.design_config_id.value == design_config_id
664 ]
665 if len(sw_config_matches) == 1:
666 return sw_config_matches[0]
667 if len(sw_config_matches) > 1:
668 raise ValueError('Multiple software configs found for: %s' %
669 design_config_id)
670 raise ValueError('Software config is required for: %s' % design_config_id)
671
672
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000673def _is_whitelabel(brand_configs, device_brands):
674 for device_brand in device_brands:
675 if device_brand.id.value in brand_configs:
676 brand_scan_config = brand_configs[device_brand.id.value].scan_config
677 if brand_scan_config and brand_scan_config.whitelabel_tag:
678 return True
679 return False
680
681
David Burgerceeb68a2020-09-03 11:31:10 -0600682def _transform_build_configs(config,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800683 config_files=ConfigFiles({}, {}, {}, {}, {}, {})):
Andrew Lambcd33f702020-06-11 10:45:16 -0600684 # pylint: disable=too-many-locals,too-many-branches
Sean McAllistereaf10b72020-08-03 13:41:06 -0600685 partners = {x.id.value: x for x in config.partner_list}
Sean McAllisterf38d1e92020-08-03 13:57:53 -0600686 programs = {x.id.value: x for x in config.program_list}
David Burger7fd1dbe2020-03-26 09:26:55 -0600687 sw_configs = list(config.software_configs)
Andrew Lambcd33f702020-06-11 10:45:16 -0600688 brand_configs = {x.brand_id.value: x for x in config.brand_configs}
David Burger7fd1dbe2020-03-26 09:26:55 -0600689
690 results = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600691 for hw_design in config.design_list:
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600692 if config.device_brand_list:
Andrew Lamb2413c982020-05-29 12:15:36 -0600693 device_brands = [
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600694 x for x in config.device_brand_list
Andrew Lamb2413c982020-05-29 12:15:36 -0600695 if x.design_id.value == hw_design.id.value
696 ]
David Burger7fd1dbe2020-03-26 09:26:55 -0600697 else:
698 device_brands = [device_brand_pb2.DeviceBrand()]
699
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000700 whitelabel = _is_whitelabel(brand_configs, device_brands)
701
David Burger7fd1dbe2020-03-26 09:26:55 -0600702 for device_brand in device_brands:
703 # Brand config can be empty since platform JSON config allows it
704 brand_config = brand_config_pb2.BrandConfig()
705 if device_brand.id.value in brand_configs:
706 brand_config = brand_configs[device_brand.id.value]
707
708 for hw_design_config in hw_design.configs:
David Burgerceeb68a2020-09-03 11:31:10 -0600709 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
Andrew Lambcd33f702020-06-11 10:45:16 -0600710 program = _lookup(hw_design.program_id, programs)
C Shapiroadefd7c2020-05-19 16:37:21 -0500711 signer_configs_by_design = {}
712 signer_configs_by_brand = {}
713 for signer_config in program.device_signer_configs:
714 design_id = signer_config.design_id.value
715 brand_id = signer_config.brand_id.value
716 if design_id:
717 signer_configs_by_design[design_id] = signer_config
718 elif brand_id:
719 signer_configs_by_brand[brand_id] = signer_config
720 else:
721 raise Exception('No ID found for signer config: %s' % signer_config)
722
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500723 device_signer_config = None
C Shapiroadefd7c2020-05-19 16:37:21 -0500724 if signer_configs_by_design or signer_configs_by_brand:
725 design_id = hw_design.id.value
726 brand_id = device_brand.id.value
727 if design_id in signer_configs_by_design:
728 device_signer_config = signer_configs_by_design[design_id]
729 elif brand_id in signer_configs_by_brand:
730 device_signer_config = signer_configs_by_brand[brand_id]
731 else:
732 # Assume that if signer configs are set, every config is setup
Andrew Lamb2413c982020-05-29 12:15:36 -0600733 raise Exception('Signer config missing for design: %s, brand: %s' %
734 (design_id, brand_id))
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500735
Andrew Lambcd33f702020-06-11 10:45:16 -0600736 transformed_config = _transform_build_config(
C Shapiro90fda252020-04-17 14:34:57 -0500737 Config(
738 program=program,
739 hw_design=hw_design,
Andrew Lambcd33f702020-06-11 10:45:16 -0600740 odm=_lookup(hw_design.odm_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500741 hw_design_config=hw_design_config,
742 device_brand=device_brand,
743 device_signer_config=device_signer_config,
Andrew Lambcd33f702020-06-11 10:45:16 -0600744 oem=_lookup(device_brand.oem_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500745 sw_config=sw_config,
C Shapirod5545f12020-11-30 16:37:04 -0600746 brand_config=brand_config), config_files, whitelabel)
David Burger7fd1dbe2020-03-26 09:26:55 -0600747
Andrew Lamb2413c982020-05-29 12:15:36 -0600748 config_json = json.dumps(
749 transformed_config,
750 sort_keys=True,
751 indent=2,
752 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600753
754 if config_json not in results:
755 results[config_json] = transformed_config
756
757 return list(results.values())
758
759
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000760def _transform_build_config(config, config_files, whitelabel):
David Burger7fd1dbe2020-03-26 09:26:55 -0600761 """Transforms Config instance into target platform JSON schema.
762
763 Args:
764 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500765 config_files: Map to look up the generated config files.
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000766 whitelabel: Whether the config is for a whitelabel design
David Burger7fd1dbe2020-03-26 09:26:55 -0600767
768 Returns:
769 Unique config payload based on the platform JSON schema.
770 """
771 result = {
Andrew Lamb2413c982020-05-29 12:15:36 -0600772 'identity':
Andrew Lambcd33f702020-06-11 10:45:16 -0600773 _build_identity(config.sw_config.id_scan_config, config.program,
774 config.brand_config.scan_config),
Andrew Lamb2413c982020-05-29 12:15:36 -0600775 'name':
776 config.hw_design.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600777 }
778
David Burger8ee9b4d2020-06-16 17:40:21 -0600779 _upsert(_build_arc(config, config_files), result, 'arc')
780 _upsert(_build_audio(config), result, 'audio')
David Burger07af5242020-08-11 11:08:25 -0600781 _upsert(_build_bluetooth(config), result, 'bluetooth')
David Burgerceeb68a2020-09-03 11:31:10 -0600782 _upsert(_build_wifi(config, config_files), result, 'wifi')
Andrew Lambca279902020-08-06 10:13:42 -0600783 _upsert(config.brand_config.wallpaper, result, 'wallpaper')
C Shapiro2e97aad2020-11-16 11:58:10 -0600784 _upsert(config.brand_config.regulatory_label, result, 'regulatory-label')
David Burger8ee9b4d2020-06-16 17:40:21 -0600785 _upsert(config.device_brand.brand_code, result, 'brand-code')
786 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600787 _build_camera(config.hw_design_config.hardware_topology), result,
788 'camera')
David Burger8ee9b4d2020-06-16 17:40:21 -0600789 _upsert(_build_firmware(config), result, 'firmware')
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000790 _upsert(_build_fw_signing(config, whitelabel), result, 'firmware-signing')
David Burger8ee9b4d2020-06-16 17:40:21 -0600791 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600792 _build_fingerprint(config.hw_design_config.hardware_topology), result,
Andrew Lamb2413c982020-05-29 12:15:36 -0600793 'fingerprint')
Andrew Lamb0d236ab2020-06-30 12:30:20 -0600794 _upsert(_build_ui(config), result, 'ui')
David Burger7fd1dbe2020-03-26 09:26:55 -0600795 power_prefs = config.sw_config.power_config.preferences
796 power_prefs_map = dict(
Andrew Lamb2413c982020-05-29 12:15:36 -0600797 (x.replace('_', '-'), power_prefs[x]) for x in power_prefs)
David Burger8ee9b4d2020-06-16 17:40:21 -0600798 _upsert(power_prefs_map, result, 'power')
799 if config_files.camera_map:
800 camera_file = config_files.camera_map.get(config.hw_design.name, {})
801 _upsert(camera_file, result, 'camera')
David Burger52c9d322020-06-09 07:16:18 -0600802 if config_files.dptf_map:
803 # Prefer design specific if found, if not fall back to project wide config
804 # mapped under the empty string.
805 if config_files.dptf_map.get(config.hw_design.name):
806 dptf_file = config_files.dptf_map[config.hw_design.name]
807 else:
808 dptf_file = config_files.dptf_map.get('')
David Burger8ee9b4d2020-06-16 17:40:21 -0600809 _upsert(dptf_file, result, 'thermal')
810 _upsert(config_files.touch_fw, result, 'touch')
Trent Beginf067ccb2020-08-12 12:33:53 -0600811 _upsert(
812 _build_hardware_properties(config.hw_design_config.hardware_topology),
813 result, 'hardware-properties')
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000814 _upsert(_build_modem(config), result, 'modem')
David Burger7fd1dbe2020-03-26 09:26:55 -0600815
816 return result
817
818
Andrew Lambcd33f702020-06-11 10:45:16 -0600819def write_output(configs, output=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600820 """Writes a list of configs to platform JSON format.
821
822 Args:
823 configs: List of config dicts defined in cros_config_schema.yaml
824 output: Target file output (if None, prints to stdout)
825 """
Andrew Lamb2413c982020-05-29 12:15:36 -0600826 json_output = json.dumps({'chromeos': {
827 'configs': configs,
828 }},
829 sort_keys=True,
830 indent=2,
831 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600832 if output:
833 with open(output, 'w') as output_stream:
834 # Using print function adds proper trailing newline.
835 print(json_output, file=output_stream)
836 else:
837 print(json_output)
838
839
Andrew Lambcd33f702020-06-11 10:45:16 -0600840def _feature(name, present):
C Shapiro5bf23a72020-04-24 11:40:17 -0500841 attrib = {'name': name}
842 if present:
843 return etree.Element('feature', attrib=attrib)
Andrew Lambcd33f702020-06-11 10:45:16 -0600844
845 return etree.Element('unavailable-feature', attrib=attrib)
C Shapiro5bf23a72020-04-24 11:40:17 -0500846
847
Andrew Lambcd33f702020-06-11 10:45:16 -0600848def _any_present(features):
Andrew Lamb2413c982020-05-29 12:15:36 -0600849 return topology_pb2.HardwareFeatures.PRESENT in features
C Shapiro5bf23a72020-04-24 11:40:17 -0500850
851
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800852def _get_formatted_config_id(design_config):
C Shapiro5bf23a72020-04-24 11:40:17 -0500853 return design_config.id.value.lower().replace(':', '_')
854
855
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800856def _write_file(output_dir, file_name, file_content):
David Burger77a1d312020-05-23 16:05:45 -0600857 os.makedirs(output_dir, exist_ok=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800858 output = '{}/{}'.format(output_dir, file_name)
C Shapiroea33cff2020-05-11 13:32:05 -0500859 with open(output, 'wb') as f:
860 f.write(file_content)
861
862
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800863def _get_arc_camera_features(camera):
864 """Gets camera related features for ARC hardware_features.xml from camera
865 topology. Check
866 https://developer.android.com/reference/android/content/pm/PackageManager#FEATURE_CAMERA
867 and CTS android.app.cts.SystemFeaturesTest#testCameraFeatures for the correct
868 settings.
869
870 Args:
871 camera: A HardwareFeatures.Camera proto message.
872 Returns:
873 list of camera related ARC features as XML elements.
874 """
875 camera_pb = topology_pb2.HardwareFeatures.Camera
876
Ren-Pei Zeng9b5682d2020-10-14 17:37:30 +0800877 count = len(camera.devices)
878 has_front_camera = any(
879 (d.facing == camera_pb.FACING_FRONT for d in camera.devices))
880 has_back_camera = any(
881 (d.facing == camera_pb.FACING_BACK for d in camera.devices))
882 has_autofocus_back_camera = any((d.facing == camera_pb.FACING_BACK and
883 d.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS
884 for d in camera.devices))
885 # Assumes MIPI cameras support FULL-level.
886 # TODO(kamesan): Setting this in project configs when there's an exception.
887 has_level_full_camera = any(
888 (d.interface == camera_pb.INTERFACE_MIPI for d in camera.devices))
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800889
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800890 return [
891 _feature('android.hardware.camera', has_back_camera),
892 _feature('android.hardware.camera.any', count > 0),
893 _feature('android.hardware.camera.autofocus', has_autofocus_back_camera),
894 _feature('android.hardware.camera.capability.manual_post_processing',
895 has_level_full_camera),
896 _feature('android.hardware.camera.capability.manual_sensor',
897 has_level_full_camera),
898 _feature('android.hardware.camera.front', has_front_camera),
899 _feature('android.hardware.camera.level.full', has_level_full_camera),
900 ]
901
902
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800903def _generate_arc_hardware_features(hw_features):
904 """Generates ARC hardware_features.xml file content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500905
906 Args:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800907 hw_features: HardwareFeatures proto message.
C Shapiro5bf23a72020-04-24 11:40:17 -0500908 Returns:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800909 bytes of the hardware_features.xml content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500910 """
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800911 touchscreen = _any_present([hw_features.screen.touch_support])
912 acc = hw_features.accelerometer
913 gyro = hw_features.gyroscope
914 compass = hw_features.magnetometer
915 light_sensor = hw_features.light_sensor
916 root = etree.Element('permissions')
917 root.extend(
918 _get_arc_camera_features(hw_features.camera) + [
919 _feature(
920 'android.hardware.sensor.accelerometer',
921 _any_present([acc.lid_accelerometer, acc.base_accelerometer])),
922 _feature('android.hardware.sensor.gyroscope',
923 _any_present([gyro.lid_gyroscope, gyro.base_gyroscope])),
924 _feature(
925 'android.hardware.sensor.compass',
926 _any_present(
927 [compass.lid_magnetometer, compass.base_magnetometer])),
928 _feature(
929 'android.hardware.sensor.light',
930 _any_present([
931 light_sensor.lid_lightsensor, light_sensor.base_lightsensor
932 ])),
933 _feature('android.hardware.touchscreen', touchscreen),
934 _feature('android.hardware.touchscreen.multitouch', touchscreen),
935 _feature('android.hardware.touchscreen.multitouch.distinct',
936 touchscreen),
937 _feature('android.hardware.touchscreen.multitouch.jazzhand',
938 touchscreen),
939 ])
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800940 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
941
942
943def _generate_arc_media_profiles(hw_features, sw_config):
944 """Generates ARC media_profiles.xml file content.
945
946 Args:
947 hw_features: HardwareFeatures proto message.
948 sw_config: SoftwareConfig proto message.
949 Returns:
950 bytes of the media_profiles.xml content, or None if |sw_config| disables the
Ren-Pei Zengb55e4312020-11-18 17:03:01 +0800951 generation or there's no camera.
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800952 """
953
954 def _gen_camcorder_profiles(camera_id, resolutions):
955 elem = etree.Element(
956 'CamcorderProfiles', attrib={'cameraId': str(camera_id)})
957 for width, height in resolutions:
958 elem.extend([
959 _gen_encoder_profile(width, height, False),
960 _gen_encoder_profile(width, height, True),
961 ])
962 elem.extend([
963 etree.Element('ImageEncoding', attrib={'quality': '90'}),
964 etree.Element('ImageEncoding', attrib={'quality': '80'}),
965 etree.Element('ImageEncoding', attrib={'quality': '70'}),
966 etree.Element('ImageDecoding', attrib={'memCap': '20000000'}),
967 ])
968 return elem
969
970 def _gen_encoder_profile(width, height, timelapse):
971 elem = etree.Element(
972 'EncoderProfile',
973 attrib={
974 'quality': ('timelapse' if timelapse else '') + str(height) + 'p',
975 'fileFormat': 'mp4',
976 'duration': '60',
977 })
978 elem.append(
979 etree.Element(
980 'Video',
981 attrib={
982 'codec': 'h264',
983 'bitRate': '8000000',
984 'width': str(width),
985 'height': str(height),
986 'frameRate': '30',
987 }))
988 elem.append(
989 etree.Element(
990 'Audio',
991 attrib={
992 'codec': 'aac',
993 'bitRate': '96000',
994 'sampleRate': '44100',
995 'channels': '1',
996 }))
997 return elem
998
999 def _gen_video_encoder_cap(name, min_bit_rate, max_bit_rate):
1000 return etree.Element(
1001 'VideoEncoderCap',
1002 attrib={
1003 'name': name,
1004 'enabled': 'true',
1005 'minBitRate': str(min_bit_rate),
1006 'maxBitRate': str(max_bit_rate),
1007 'minFrameWidth': '320',
1008 'maxFrameWidth': '1920',
1009 'minFrameHeight': '240',
1010 'maxFrameHeight': '1080',
1011 'minFrameRate': '15',
1012 'maxFrameRate': '30',
1013 })
1014
1015 def _gen_audio_encoder_cap(name, min_bit_rate, max_bit_rate, min_sample_rate,
1016 max_sample_rate):
1017 return etree.Element(
1018 'AudioEncoderCap',
1019 attrib={
1020 'name': name,
1021 'enabled': 'true',
1022 'minBitRate': str(min_bit_rate),
1023 'maxBitRate': str(max_bit_rate),
1024 'minSampleRate': str(min_sample_rate),
1025 'maxSampleRate': str(max_sample_rate),
1026 'minChannels': '1',
1027 'maxChannels': '1',
1028 })
1029
1030 camera_config = sw_config.camera_config
1031 if not camera_config.generate_media_profiles:
1032 return None
1033
1034 camera_pb = topology_pb2.HardwareFeatures.Camera
1035 root = etree.Element('MediaSettings')
1036 camera_id = 0
1037 for facing in [camera_pb.FACING_BACK, camera_pb.FACING_FRONT]:
1038 camera_device = next(
1039 (d for d in hw_features.camera.devices if d.facing == facing), None)
1040 if camera_device is None:
1041 continue
1042 if camera_config.camcorder_resolutions:
1043 resolutions = [
1044 (r.width, r.height) for r in camera_config.camcorder_resolutions
1045 ]
1046 else:
1047 resolutions = [(1280, 720)]
1048 if camera_device.flags & camera_pb.FLAGS_SUPPORT_1080P:
1049 resolutions.append((1920, 1080))
1050 root.append(_gen_camcorder_profiles(camera_id, resolutions))
1051 camera_id += 1
Ren-Pei Zengb55e4312020-11-18 17:03:01 +08001052 # media_profiles.xml should have at least one CamcorderProfiles.
1053 if camera_id == 0:
1054 return None
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001055
1056 root.extend([
1057 etree.Element('EncoderOutputFileFormat', attrib={'name': '3gp'}),
1058 etree.Element('EncoderOutputFileFormat', attrib={'name': 'mp4'}),
1059 _gen_video_encoder_cap('h264', 64000, 17000000),
1060 _gen_video_encoder_cap('h263', 64000, 1000000),
1061 _gen_video_encoder_cap('m4v', 64000, 2000000),
1062 _gen_audio_encoder_cap('aac', 758, 288000, 8000, 48000),
1063 _gen_audio_encoder_cap('heaac', 8000, 64000, 16000, 48000),
1064 _gen_audio_encoder_cap('aaceld', 16000, 192000, 16000, 48000),
1065 _gen_audio_encoder_cap('amrwb', 6600, 23050, 16000, 16000),
1066 _gen_audio_encoder_cap('amrnb', 5525, 12200, 8000, 8000),
1067 etree.Element(
1068 'VideoDecoderCap', attrib={
1069 'name': 'wmv',
1070 'enabled': 'false'
1071 }),
1072 etree.Element(
1073 'AudioDecoderCap', attrib={
1074 'name': 'wma',
1075 'enabled': 'false'
1076 }),
1077 ])
Ren-Pei Zeng21708cc2020-11-17 11:14:07 +08001078
1079 dtd_path = os.path.dirname(__file__)
1080 dtd = etree.DTD(os.path.join(dtd_path, 'media_profiles.dtd'))
1081 if not dtd.validate(root):
1082 raise etree.DTDValidateError(
1083 'Invalid media_profiles.xml generated:\n{}'.format(dtd.error_log))
1084
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001085 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001086
1087
1088def _write_files_by_design_config(configs, output_dir, build_dir, system_dir,
1089 file_name_template, generate_file_content):
1090 """Writes generated files for each design config.
1091
1092 Args:
1093 configs: Source ConfigBundle to process.
1094 output_dir: Path to the generated output.
1095 build_dir: Path to the config file from portage's perspective.
1096 system_dir: Path to the config file in the target device.
1097 file_name_template: Template string of the config file name including one
1098 format()-style replacement field for the config id, e.g. 'config_{}.xml'.
1099 generate_file_content: Function to generate config file content from
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001100 HardwareFeatures and SoftwareConfig proto.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001101 Returns:
1102 dict that maps the formatted config id to the correct file.
1103 """
1104 # pylint: disable=too-many-arguments,too-many-locals
C Shapiro5bf23a72020-04-24 11:40:17 -05001105 result = {}
C Shapiroea33cff2020-05-11 13:32:05 -05001106 configs_by_design = {}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001107 for hw_design in configs.design_list:
C Shapiro5bf23a72020-04-24 11:40:17 -05001108 for design_config in hw_design.configs:
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001109 sw_config = _sw_config(configs.software_configs, design_config.id.value)
1110 config_content = generate_file_content(design_config.hardware_features,
1111 sw_config)
1112 if not config_content:
1113 continue
C Shapiroea33cff2020-05-11 13:32:05 -05001114 design_name = hw_design.name.lower()
C Shapiro5bf23a72020-04-24 11:40:17 -05001115
C Shapiroea33cff2020-05-11 13:32:05 -05001116 # Constructs the following map:
1117 # design_name -> config -> design_configs
1118 # This allows any of the following file naming schemes:
1119 # - All configs within a design share config (design_name prefix only)
1120 # - Nobody shares (full design_name and config id prefix needed)
1121 #
1122 # Having shared configs when possible makes code reviews easier around
1123 # the configs and makes debugging easier on the platform side.
C Shapiroea33cff2020-05-11 13:32:05 -05001124 arc_configs = configs_by_design.get(design_name, {})
1125 design_configs = arc_configs.get(config_content, [])
1126 design_configs.append(design_config)
1127 arc_configs[config_content] = design_configs
1128 configs_by_design[design_name] = arc_configs
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001129
C Shapiroea33cff2020-05-11 13:32:05 -05001130 for design_name, unique_configs in configs_by_design.items():
1131 for file_content, design_configs in unique_configs.items():
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001132 file_name = file_name_template.format(design_name)
Andrew Lamb2413c982020-05-29 12:15:36 -06001133 if len(unique_configs) == 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001134 _write_file(output_dir, file_name, file_content)
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001135
Andrew Lamb2413c982020-05-29 12:15:36 -06001136 for design_config in design_configs:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001137 config_id = _get_formatted_config_id(design_config)
Andrew Lamb2413c982020-05-29 12:15:36 -06001138 if len(unique_configs) > 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001139 file_name = file_name_template.format(config_id)
1140 _write_file(output_dir, file_name, file_content)
1141 result[config_id] = _file_v2('{}/{}'.format(build_dir, file_name),
1142 '{}/{}'.format(system_dir, file_name))
C Shapiro5bf23a72020-04-24 11:40:17 -05001143 return result
1144
1145
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001146def _write_arc_hardware_feature_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001147 return _write_files_by_design_config(
1148 configs, output_root_dir + '/arc', build_root_dir + '/arc', '/etc',
1149 'hardware_features_{}.xml',
1150 lambda hw_features, _: _generate_arc_hardware_features(hw_features))
1151
1152
1153def _write_arc_media_profile_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001154 return _write_files_by_design_config(configs, output_root_dir + '/arc',
1155 build_root_dir + '/arc', '/etc',
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001156 'media_profiles_{}.xml',
1157 _generate_arc_media_profiles)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001158
1159
Andrew Lambcd33f702020-06-11 10:45:16 -06001160def _read_config(path):
David Burgerd4f32962020-05-02 12:07:40 -06001161 """Reads a ConfigBundle proto from a json pb file.
David Burgere6f76222020-04-27 11:08:01 -06001162
1163 Args:
David Burgerd4f32962020-05-02 12:07:40 -06001164 path: Path to the file encoding the json pb proto.
David Burgere6f76222020-04-27 11:08:01 -06001165 """
1166 config = config_bundle_pb2.ConfigBundle()
1167 with open(path, 'r') as f:
1168 return json_format.Parse(f.read(), config)
1169
1170
Andrew Lambcd33f702020-06-11 10:45:16 -06001171def _merge_configs(configs):
David Burger7fd1dbe2020-03-26 09:26:55 -06001172 result = config_bundle_pb2.ConfigBundle()
1173 for config in configs:
1174 result.MergeFrom(config)
1175
1176 return result
1177
1178
David Burger1ba78a22020-06-18 18:42:47 -06001179def _camera_map(configs, project_name):
David Burger8ee9b4d2020-06-16 17:40:21 -06001180 """Produces a camera config map for the given configs.
1181
1182 Produces a map that maps from the design name to the camera config for that
1183 design.
1184
1185 Args:
1186 configs: Source ConfigBundle to process.
David Burger1ba78a22020-06-18 18:42:47 -06001187 project_name: Name of project processing for.
David Burger8ee9b4d2020-06-16 17:40:21 -06001188
1189 Returns:
1190 map from design name to camera config.
1191 """
1192 result = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -06001193 for design in configs.design_list:
David Burger8ee9b4d2020-06-16 17:40:21 -06001194 design_name = design.name
David Burger0d9e8462020-06-19 14:12:37 -06001195 config_path = CAMERA_CONFIG_SOURCE_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001196 if os.path.exists(config_path):
David Burger0d9e8462020-06-19 14:12:37 -06001197 destination = CAMERA_CONFIG_DEST_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001198 result[design_name] = {
David Burger1ba78a22020-06-18 18:42:47 -06001199 'config-file':
1200 _file_v2(os.path.join(project_name, config_path), destination),
David Burger8ee9b4d2020-06-16 17:40:21 -06001201 }
1202 return result
1203
1204
David Burger52c9d322020-06-09 07:16:18 -06001205def _dptf_map(configs, project_name):
1206 """Produces a dptf map for the given configs.
1207
1208 Produces a map that maps from design name to the dptf file config for that
1209 design. It looks for the dptf files at:
David Burger2f0d9522020-07-30 10:52:28 -06001210 DPTF_PATH + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001211 for a project wide config, that it maps under the empty string, and at:
David Burger2f0d9522020-07-30 10:52:28 -06001212 DPTF_PATH + '/' + design_name + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001213 for design specific configs that it maps under the design name.
1214
1215 Args:
1216 configs: Source ConfigBundle to process.
1217 project_name: Name of project processing for.
1218
1219 Returns:
David Burger8ee9b4d2020-06-16 17:40:21 -06001220 map from design name or empty string (project wide), to dptf config.
David Burger52c9d322020-06-09 07:16:18 -06001221 """
1222 result = {}
David Burger52c9d322020-06-09 07:16:18 -06001223 # Looking at top level for project wide, and then for each design name
1224 # for design specific.
Sean McAllisterf66887b2020-08-03 14:00:51 -06001225 dirs = [""] + [d.name for d in configs.design_list]
David Burger52c9d322020-06-09 07:16:18 -06001226 for directory in dirs:
David Burgera2252762020-07-09 15:09:49 -06001227 design = directory.lower()
1228 if os.path.exists(os.path.join(DPTF_PATH, design, DPTF_FILE)):
David Burger2f0d9522020-07-30 10:52:28 -06001229 project_dptf_path = os.path.join(project_name, design, DPTF_FILE)
David Burger52c9d322020-06-09 07:16:18 -06001230 dptf_file = {
1231 'dptf-dv':
1232 project_dptf_path,
1233 'files': [
1234 _file(
David Burgera2252762020-07-09 15:09:49 -06001235 os.path.join(project_name, DPTF_PATH, design, DPTF_FILE),
David Burger52c9d322020-06-09 07:16:18 -06001236 os.path.join('/etc/dptf', project_dptf_path))
1237 ]
1238 }
1239 result[directory] = dptf_file
1240 return result
1241
1242
David Burgerceeb68a2020-09-03 11:31:10 -06001243def _wifi_sar_map(configs, project_name, output_dir, build_root_dir):
1244 """Constructs a map from design name to wifi sar config for that design.
1245
1246 Constructs a map from design name to the wifi sar config for that design.
1247 In the process a wifi sar hex file is generated that the config points at.
1248 This mapping is only made for the intel wifi where the generated file is
1249 provided when building coreboot.
1250
1251 Args:
1252 configs: Source ConfigBundle to process.
1253 project_name: Name of project processing for.
1254 output_dir: Path to the generated output.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001255 build_root_dir: Path to the config file from portage's perspective.
David Burgerceeb68a2020-09-03 11:31:10 -06001256
1257 Returns:
1258 dict that maps the design name onto the wifi config for that design.
1259 """
1260 # pylint: disable=too-many-locals
1261 result = {}
1262 programs = {p.id.value: p for p in configs.program_list}
1263 sw_configs = list(configs.software_configs)
1264 for hw_design in configs.design_list:
1265 for hw_design_config in hw_design.configs:
1266 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
1267 if sw_config.wifi_config.HasField('intel_config'):
1268 sar_file_content = _create_intel_sar_file_content(
1269 sw_config.wifi_config.intel_config)
1270 design_name = hw_design.name.lower()
1271 program = _lookup(hw_design.program_id, programs)
1272 wifi_sar_id = _extract_fw_config_value(hw_design_config, program,
1273 'Intel wifi sar id')
1274 output_path = os.path.join(output_dir, 'wifi')
1275 os.makedirs(output_path, exist_ok=True)
1276 filename = 'wifi_sar_{}.hex'.format(wifi_sar_id)
1277 output_path = os.path.join(output_path, filename)
1278 build_path = os.path.join(build_root_dir, 'wifi', filename)
1279 if os.path.exists(output_path):
1280 with open(output_path, 'r') as f:
1281 if f.read() != sar_file_content:
1282 raise Exception(
1283 'Project {} has conflicting wifi sar file content under '
1284 'wifi sar id {}.'.format(project_name, wifi_sar_id))
1285 else:
1286 with open(output_path, 'w') as f:
1287 f.write(sar_file_content)
1288 system_path = '/firmware/cbfs-rw-raw/{}/{}'.format(
1289 project_name, filename)
David Burger89e7cae2020-09-15 17:04:12 -06001290 result[design_name] = {'sar-file': _file_v2(build_path, system_path)}
David Burgerceeb68a2020-09-03 11:31:10 -06001291 return result
1292
1293
1294def _extract_fw_config_value(hw_design_config, program, name):
1295 """Extracts the firwmare config value with the given name.
1296
1297 Args:
1298 hw_design_config: Design extracting value from.
1299 program: Program the `hw_design_config` belongs to.
1300 name: Name of firmware config segment to extract.
1301
1302 Returns: the extracted value or raises a ValueError if no firmware
1303 configuration segment with `name` is found.
1304 """
1305 fw_config = hw_design_config.hardware_features.fw_config.value
1306 for fcs in program.firmware_configuration_segments:
1307 if fcs.name == name:
1308 value = fw_config & fcs.mask
1309 lsb_bit_set = (~fcs.mask + 1) & fcs.mask
1310 return value // lsb_bit_set
1311 raise ValueError(
1312 'No firmware configuration segment with name {} found'.format(name))
1313
1314
1315def _create_intel_sar_file_content(intel_config):
1316 """Creates and returns the intel sar file content for the given config.
1317
1318 Creates and returns the sar file content that is used with intel drivers
1319 only.
1320
1321 Args:
1322 intel_config: IntelConfig config.
1323
1324 Returns:
1325 sar file content for the given config, see:
1326 https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1327 """
1328
1329 def to_hex(val):
1330 if val > 255 or val < 0:
1331 raise Exception('Sar file value %s out of range' % val)
1332 return '{0:0{1}X}'.format(val, 2)
1333
1334 def power_table(tpc):
1335 return (to_hex(tpc.limit_2g) + to_hex(tpc.limit_5g_1) +
1336 to_hex(tpc.limit_5g_2) + to_hex(tpc.limit_5g_3) +
1337 to_hex(tpc.limit_5g_4))
1338
1339 def wgds_value(wgds):
1340 return to_hex(wgds)
1341
1342 def offset_table(offsets):
1343 return (to_hex(offsets.max_2g) + to_hex(offsets.offset_2g_a) +
1344 to_hex(offsets.offset_2g_b) + to_hex(offsets.max_5g) +
1345 to_hex(offsets.offset_5g_a) + to_hex(offsets.offset_5g_b))
1346
1347 # See https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1348 return (power_table(intel_config.tablet_mode_power_table_a) +
1349 power_table(intel_config.tablet_mode_power_table_b) +
1350 power_table(intel_config.non_tablet_mode_power_table_a) +
1351 power_table(intel_config.non_tablet_mode_power_table_b) +
1352 '00000000000000000000' + '00000000000000000000' +
1353 wgds_value(intel_config.wgds_version) +
1354 offset_table(intel_config.offset_fcc) +
1355 offset_table(intel_config.offset_eu) +
YH Lin89cddaa2021-03-08 08:31:47 -08001356 offset_table(intel_config.offset_other) + '\0')
David Burgerceeb68a2020-09-03 11:31:10 -06001357
1358
Andrew Lambcd33f702020-06-11 10:45:16 -06001359def Main(project_configs, program_config, output): # pylint: disable=invalid-name
David Burger7fd1dbe2020-03-26 09:26:55 -06001360 """Transforms source proto config into platform JSON.
1361
1362 Args:
1363 project_configs: List of source project configs to transform.
1364 program_config: Program config for the given set of projects.
1365 output: Output file that will be generated by the transform.
1366 """
Andrew Lambcd33f702020-06-11 10:45:16 -06001367 configs = _merge_configs([_read_config(program_config)] +
1368 [_read_config(config) for config in project_configs])
C Shapiro2b6d5332020-05-06 17:51:35 -05001369 touch_fw = {}
David Burger8ee9b4d2020-06-16 17:40:21 -06001370 camera_map = {}
David Burgerceeb68a2020-09-03 11:31:10 -06001371 dptf_map = {}
1372 wifi_sar_map = {}
C Shapiro5bf23a72020-04-24 11:40:17 -05001373 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -05001374 build_root_dir = output_dir
C Shapiro5c877992020-04-29 12:11:28 -05001375 if 'sw_build_config' in output_dir:
1376 full_path = os.path.realpath(output)
Andrew Lamb6b607732020-08-24 15:52:46 -06001377 project_name = re.match(r'.*/(\w*)/(public_)?sw_build_config/.*',
Andrew Lamb2413c982020-05-29 12:15:36 -06001378 full_path).groups(1)[0]
C Shapiro5c877992020-04-29 12:11:28 -05001379 # Projects don't know about each other until they are integrated into the
1380 # build system. When this happens, the files need to be able to co-exist
1381 # without any collisions. This prefixes the project name (which is how
1382 # portage maps in the project), so project files co-exist and can be
1383 # installed together.
1384 # This is necessary to allow projects to share files at the program level
1385 # without having portage file installation collisions.
1386 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -05001387
David Burger1ba78a22020-06-18 18:42:47 -06001388 camera_map = _camera_map(configs, project_name)
David Burger52c9d322020-06-09 07:16:18 -06001389 dptf_map = _dptf_map(configs, project_name)
David Burgerceeb68a2020-09-03 11:31:10 -06001390 wifi_sar_map = _wifi_sar_map(configs, project_name, output_dir,
1391 build_root_dir)
David Burger52c9d322020-06-09 07:16:18 -06001392
C Shapiro2b6d5332020-05-06 17:51:35 -05001393 if os.path.exists(TOUCH_PATH):
Andrew Lambcd33f702020-06-11 10:45:16 -06001394 touch_fw = _build_touch_file_config(configs, project_name)
Andrew Lambcd33f702020-06-11 10:45:16 -06001395 arc_hw_feature_files = _write_arc_hardware_feature_files(
1396 configs, output_dir, build_root_dir)
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001397 arc_media_profile_files = _write_arc_media_profile_files(
1398 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -05001399 config_files = ConfigFiles(
C Shapiro5bf23a72020-04-24 11:40:17 -05001400 arc_hw_features=arc_hw_feature_files,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001401 arc_media_profiles=arc_media_profile_files,
C Shapiro2b6d5332020-05-06 17:51:35 -05001402 touch_fw=touch_fw,
David Burger8ee9b4d2020-06-16 17:40:21 -06001403 dptf_map=dptf_map,
David Burgerceeb68a2020-09-03 11:31:10 -06001404 camera_map=camera_map,
1405 wifi_sar_map=wifi_sar_map)
Andrew Lambcd33f702020-06-11 10:45:16 -06001406 write_output(_transform_build_configs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -06001407
1408
1409def main(argv=None):
1410 """Main program which parses args and runs
1411
1412 Args:
1413 argv: List of command line arguments, if None uses sys.argv.
1414 """
1415 if argv is None:
1416 argv = sys.argv[1:]
Andrew Lambcd33f702020-06-11 10:45:16 -06001417 opts = parse_args(argv)
David Burger7fd1dbe2020-03-26 09:26:55 -06001418 Main(opts.project_configs, opts.program_config, opts.output)
1419
1420
1421if __name__ == '__main__':
1422 sys.exit(main(sys.argv[1:]))