chromeos-config: Add stylus category to schema
BUG=b:124230002
TEST=Added stylus-category to octopus bsp and queried it with
cros_config_host
Change-Id: Idf2d2381f471178b170c40643c906d5b9c0ef274
Reviewed-on: https://chromium-review.googlesource.com/1509704
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Kartik Hegde <khegde@chromium.org>
Reviewed-by: Jett Rink <jettrink@chromium.org>
diff --git a/chromeos-config/README.md b/chromeos-config/README.md
index ad4ff122..21c83cb 100644
--- a/chromeos-config/README.md
+++ b/chromeos-config/README.md
@@ -285,7 +285,7 @@
| camera | [camera](#camera) | | False | | False | |
| firmware | [firmware](#firmware) | | True | | True | |
| firmware-signing | [firmware-signing](#firmware-signing) | | False | | True | |
-| hardware-properties | [hardware-properties](#hardware-properties) | | False | | False | Contains boolean flags for hardware properties of this board, for example if it's convertible, has a touchscreen, has a camera, etc. This information is used to auto-generate C code that is consumed by the EC build process in order to do run-time configuration. If a value is defined within a config file, but not for a specific model, that value will be assumed to be false for that model. All properties must be booleans. If non-boolean properties are desired, the generation code in cros_config_schema.py must be updated to support them. |
+| hardware-properties | [hardware-properties](#hardware-properties) | | False | | False | Contains boolean flags or enums for hardware properties of this board, for example if it's convertible, has a touchscreen, has a camera, etc. This information is used to auto-generate C code that is consumed by the EC build process in order to do run-time configuration. If a value is defined within a config file, but not for a specific model, that value will be assumed to be false for that model. If a value is an enum and is not specified for a specific model, it will default to "none". All properties must be booleans or enums. If non-boolean properties are desired, the generation code in cros_config_schema.py must be updated to support them. |
| identity | [identity](#identity) | | False | | False | Defines attributes that are used by cros_config to detect the identity of the platform and which corresponding config should be used. This tuple must either contain x86 properties only or ARM properties only. |
| modem | [modem](#modem) | | False | | False | |
| name | string | ```^[_a-zA-Z0-9]{3,}``` | True | | False | Unique name for the given model. |
@@ -399,6 +399,7 @@
| has-lid-accelerometer | boolean | | False | | False | Is there an accelerometer in the lid of the device. |
| has-touchscreen | boolean | | False | | False | Does the device have a touchscreen. |
| is-lid-convertible | boolean | | False | | False | Can the lid be rotated 360 degrees. |
+| stylus-category | string | | False | | False | Denotes the category of stylus this device contains. |
### identity
| Attribute | Type | RegEx | Required | Oneof Group | Build-only | Description |
diff --git a/chromeos-config/cros_config_host/cros_config_schema.py b/chromeos-config/cros_config_host/cros_config_schema.py
index 72e6ee9..7a5128c 100755
--- a/chromeos-config/cros_config_host/cros_config_schema.py
+++ b/chromeos-config/cros_config_host/cros_config_schema.py
@@ -12,6 +12,7 @@
import copy
from jinja2 import Template
import json
+import math
import os
import re
import sys
@@ -375,18 +376,24 @@
return file_format % (',\n'.join(structs), len(structs))
-def GenerateEcCBindings(config):
+def GenerateEcCBindings(config, schema_yaml):
"""Generates EC C struct bindings
Generates .h and .c file containing C struct bindings that can be used by ec.
Args:
config: Config (transformed) that is the transform basis.
+ schema_yaml: Cros_config_schema in yaml format.
"""
json_config = json.loads(config)
device_properties = collections.defaultdict(dict)
- flag_set = set()
+ # Store the number of bits required for a hwprop's value.
+ hwprop_values_count = collections.defaultdict(int)
+ # Store a list of the elements for every enum. This
+ # will be used in the ec_config.h auto-generation code.
+ enum_to_elements_map = collections.defaultdict(list)
+ hwprop_set = set()
for config in json_config[CHROMEOS][CONFIGS]:
firmware = config['firmware']
@@ -409,24 +416,40 @@
sku = config['identity']['sku-id']
ec_build_target = firmware['build-targets']['ec'].upper()
- # Default flag value will be false.
- flag_values = collections.defaultdict(bool)
+ # Default hwprop value will be false.
+ hwprop_values = collections.defaultdict(bool)
hwprops = config.get('hardware-properties', None)
if hwprops:
- # |flag| is a user specified property of the hardware, for example
+ # |hwprop| is a user specified property of the hardware, for example
# 'is-lid-convertible', which means that the device can rotate 360.
- for flag, value in hwprops.iteritems():
- # Convert the name of the flag to a valid C identifier.
- clean_flag = flag.replace('-', '_')
- flag_set.add(clean_flag)
- flag_values[clean_flag] = value
+ for hwprop, value in hwprops.items():
+ # Convert the name of the hwprop to a valid C identifier.
+ clean_hwprop = hwprop.replace('-', '_')
+ hwprop_set.add(clean_hwprop)
+ if isinstance(value, bool):
+ hwprop_values_count[clean_hwprop] = 1
+ hwprop_values[clean_hwprop] = value
+ elif isinstance(value, unicode):
+ # Calculate the number of bits by taking the log_2 of the number
+ # of possible enumerations. Use math.ceil to round up.
+ # For example, if an enum has 7 possible values (elements, we will
+ # need 3 bits to represent all the values.
+ # log_2(7) ~= 2.807 -> round up to 3.
+ element_to_int_map = _GetElementToIntMap(schema_yaml, hwprop)
+ if value not in element_to_int_map:
+ raise ValidationError('Not a valid enum value: %s' % value)
+ enum_to_elements_map[clean_hwprop] = element_to_int_map
+ element_count = len(element_to_int_map)
+ hwprop_values_count[clean_hwprop] = int(
+ math.ceil(math.log(element_count)))
+ hwprop_values[clean_hwprop] = element_to_int_map[value]
# Duplicate skus take the last value in the config file.
- device_properties[ec_build_target][sku] = flag_values
+ device_properties[ec_build_target][sku] = hwprop_values
- flags = list(flag_set)
- flags.sort()
+ hwprops = list(hwprop_set)
+ hwprops.sort()
for ec_build_target in device_properties.iterkeys():
# Order struct definitions by sku.
device_properties[ec_build_target] = \
@@ -440,11 +463,35 @@
this_dir, TEMPLATE_DIR, (EC_OUTPUT_NAME + '.c' + TEMPLATE_SUFFIX))
c_template = Template(open(c_template_path).read())
- h_output = h_template.render(flags=flags)
- c_output = c_template.render(device_properties=device_properties, flags=flags)
+ h_output = h_template.render(
+ hwprops=hwprops,
+ hwprop_values_count=hwprop_values_count,
+ enum_to_elements_map=enum_to_elements_map)
+ c_output = c_template.render(
+ device_properties=device_properties, hwprops=hwprops)
return (h_output, c_output)
+def _GetElementToIntMap(schema_yaml, hwprop):
+ """Returns a mapping of an enum's elements to a distinct integer.
+
+ Used in the c_template to assign an integer to
+ the stylus category type.
+
+ Args:
+ schema_yaml: Cros_config_schema in yaml format.
+ hwprop: String representing the hardware property
+ of the enum (ex. stylus-category)
+ """
+ schema_json_from_yaml = libcros_schema.FormatJson(schema_yaml)
+ schema_json = json.loads(schema_json_from_yaml)
+ if hwprop not in schema_json['typeDefs']:
+ raise ValidationError('Hardware property not found: %s' % str(hwprop))
+ if "enum" not in schema_json["typeDefs"][hwprop]:
+ raise ValidationError('Hardware property is not an enum: %s' % str(hwprop))
+ return dict((element, i) for (i, element) in enumerate(
+ schema_json["typeDefs"][hwprop]["enum"]))
+
def FilterBuildElements(config, build_only_elements):
"""Removes build only elements from the schema.
@@ -598,7 +645,7 @@
compare_str))
-def _ValidateHardwarePropertiesAreBoolean(json_config):
+def _ValidateHardwarePropertiesAreValidType(json_config):
"""Checks that all fields under hardware-properties are boolean
Ensures that no key is added to hardware-properties that has a non-boolean
@@ -612,9 +659,11 @@
hardware_properties = config.get('hardware-properties', None)
if hardware_properties:
for key, value in hardware_properties.iteritems():
- if not isinstance(value, bool):
+ valid_type = isinstance(value, bool) or isinstance(value, unicode)
+ if not valid_type:
raise ValidationError(
- ('All configs under hardware-properties must be boolean flags\n'
+ ('All configs under hardware-properties must be '
+ 'boolean or an enum\n'
'However, key \'{}\' has value \'{}\'.').format(key, value))
@@ -630,7 +679,7 @@
json_config = json.loads(config)
_ValidateUniqueIdentities(json_config)
_ValidateWhitelabelBrandChangesOnly(json_config)
- _ValidateHardwarePropertiesAreBoolean(json_config)
+ _ValidateHardwarePropertiesAreValidType(json_config)
def MergeConfigs(configs):
@@ -737,7 +786,8 @@
as output_stream:
# Using print function adds proper trailing newline.
print(GenerateMosysCBindings(full_json_transform), file=output_stream)
- h_output, c_output = GenerateEcCBindings(full_json_transform)
+ h_output, c_output = GenerateEcCBindings(
+ full_json_transform, schema_yaml=yaml.load(schema_contents))
with open(os.path.join(gen_c_output_dir, EC_OUTPUT_NAME + ".h"), 'w') \
as output_stream:
print(h_output, file=output_stream)
diff --git a/chromeos-config/cros_config_host/cros_config_schema.yaml b/chromeos-config/cros_config_host/cros_config_schema.yaml
index a596bab..c4bfb5d 100644
--- a/chromeos-config/cros_config_host/cros_config_schema.yaml
+++ b/chromeos-config/cros_config_host/cros_config_schema.yaml
@@ -67,6 +67,13 @@
description: "Defines the name that is reported by 'mosys platform name'
This is typically the reference design name with the first letter capitalized"
type: string
+ stylus-category: &stylus-category
+ description: "Denotes the category of stylus this device contains."
+ type: string
+ enum:
+ - none
+ - internal
+ - external
type: object
properties:
chromeos:
@@ -387,14 +394,15 @@
additionalProperties: false
hardware-properties:
type: object
- description: Contains boolean flags for hardware properties of
- this board, for example if it's convertible, has a touchscreen,
+ description: Contains boolean flags or enums for hardware properties
+ of this board, for example if it's convertible, has a touchscreen,
has a camera, etc. This information is used to auto-generate C
code that is consumed by the EC build process in order to do
run-time configuration. If a value is defined within a config
file, but not for a specific model, that value will be assumed
- to be false for that model.
- All properties must be booleans. If non-boolean
+ to be false for that model. If a value is an enum and is not
+ specified for a specific model, it will default to "none".
+ All properties must be booleans or enums. If non-boolean
properties are desired, the generation code in
cros_config_schema.py must be updated to support them.
properties:
@@ -421,6 +429,7 @@
has-touchscreen:
description: Does the device have a touchscreen.
type: boolean
+ stylus-category: *stylus-category
additionalProperties: false
additionalProperties: false
required:
diff --git a/chromeos-config/cros_config_host/cros_config_schema_unittest.py b/chromeos-config/cros_config_host/cros_config_schema_unittest.py
index c77c665..e94782c 100755
--- a/chromeos-config/cros_config_host/cros_config_schema_unittest.py
+++ b/chromeos-config/cros_config_host/cros_config_schema_unittest.py
@@ -14,13 +14,13 @@
import os
import unittest
import re
+import yaml
import cros_config_schema
import libcros_schema
from chromite.lib import cros_test_lib
-
BASIC_CONFIG = """
reef-9042-fw: &reef-9042-fw
bcs-overlay: 'overlay-reef-private'
@@ -333,7 +333,7 @@
except cros_config_schema.ValidationError as err:
self.assertIn('Whitelabel configs can only', err.__str__())
- def testHardwarePropertiesNonBoolean(self):
+ def testHardwarePropertiesInvalid(self):
config = \
"""
chromeos:
@@ -402,6 +402,13 @@
class MainTests(cros_test_lib.TempDirTestCase):
+
+ def _GetSchemaYaml(self):
+ with open(os.path.join(
+ this_dir, 'cros_config_schema.yaml')) as schema_stream:
+ schema_contents = schema_stream.read()
+ return yaml.load(schema_contents)
+
def assertFileEqual(self, file_expected, file_actual, regen_cmd=''):
self.assertTrue(os.path.isfile(file_expected),
"Expected file does not exist at path: {}" \
@@ -554,7 +561,8 @@
"hardware-properties": {
"is-lid-convertible": false,
"has-base-accelerometer": true,
- "has-lid-accelerometer": true
+ "has-lid-accelerometer": true,
+ "stylus-category": "external"
},
"identity": {
"sku-id": 9
@@ -583,7 +591,8 @@
h_expected = open(h_expected_path).read()
c_expected = open(c_expected_path).read()
- h_actual, c_actual = cros_config_schema.GenerateEcCBindings(input_json)
+ h_actual, c_actual = cros_config_schema.GenerateEcCBindings(
+ input_json, self._GetSchemaYaml())
self.assertMultilineStringEqual(h_expected, h_actual)
self.assertMultilineStringEqual(c_expected, c_actual)
@@ -597,7 +606,8 @@
h_expected = open(h_expected_path).read()
c_expected = open(c_expected_path).read()
- h_actual, c_actual = cros_config_schema.GenerateEcCBindings(input_json)
+ h_actual, c_actual = cros_config_schema.GenerateEcCBindings(
+ input_json, self._GetSchemaYaml())
self.assertMultilineStringEqual(h_expected, h_actual)
self.assertMultilineStringEqual(c_expected, c_actual)
@@ -614,7 +624,8 @@
h_expected = open(h_expected_path).read()
c_expected = open(c_expected_path).read()
- h_actual, c_actual = cros_config_schema.GenerateEcCBindings(input_json)
+ h_actual, c_actual = cros_config_schema.GenerateEcCBindings(
+ input_json, self._GetSchemaYaml())
self.assertMultilineStringEqual(h_expected, h_actual)
self.assertMultilineStringEqual(c_expected, c_actual)
diff --git a/chromeos-config/cros_config_host/templates/ec_config.c.jinja2 b/chromeos-config/cros_config_host/templates/ec_config.c.jinja2
index 75dab37..f333978 100644
--- a/chromeos-config/cros_config_host/templates/ec_config.c.jinja2
+++ b/chromeos-config/cros_config_host/templates/ec_config.c.jinja2
@@ -16,10 +16,10 @@
{%- endif %}
const struct sku_info ALL_SKUS[] = {
- {%- for sku, flag_values in skus %}
+ {%- for sku, hwprop_values in skus %}
{.sku = {{ sku }}
- {%- for flag in flags %},
- .{{ flag }} = {{ flag_values[flag] | int }}
+ {%- for hwprop in hwprops %},
+ .{{ hwprop }} = {{ hwprop_values[hwprop] | int }}
{%- endfor -%}
}
{%- if not loop.last -%} , {%- endif -%}
diff --git a/chromeos-config/cros_config_host/templates/ec_config.h.jinja2 b/chromeos-config/cros_config_host/templates/ec_config.h.jinja2
index 3062963..407fa5d 100644
--- a/chromeos-config/cros_config_host/templates/ec_config.h.jinja2
+++ b/chromeos-config/cros_config_host/templates/ec_config.h.jinja2
@@ -8,10 +8,24 @@
#include <stdint.h>
#include <stdlib.h>
+{% for hwprop in enum_to_elements_map -%}
+{% set elems = [] -%}
+{% set namespace = hwprop | upper -%}
+{% for elem, i in (enum_to_elements_map[hwprop]).items() -%}
+{{ elems.append([namespace, '_', elem | string | upper, ' = ', i | string] | join) | default("", True) }}
+{%- if loop.last %}
+enum {{ hwprop ~ '_type' }} {
+ {{ (elems | join(',\n ')) }}
+};
+
+{% endif -%}
+{%- endfor -%}
+{% endfor -%}
+
struct sku_info {
const uint8_t sku;
- {%- for flag in flags %}
- const uint8_t {{ flag }} :1;
+ {%- for hwprop in hwprops %}
+ const uint8_t {{ hwprop }} :{{ hwprop_values_count[hwprop] }};
{%- endfor %}
};
diff --git a/chromeos-config/libcros_config/ec_test_many.c b/chromeos-config/libcros_config/ec_test_many.c
index 100d47b..c87e055 100644
--- a/chromeos-config/libcros_config/ec_test_many.c
+++ b/chromeos-config/libcros_config/ec_test_many.c
@@ -13,11 +13,13 @@
{.sku = 9,
.has_base_accelerometer = 1,
.has_lid_accelerometer = 1,
- .is_lid_convertible = 0},
+ .is_lid_convertible = 0,
+ .stylus_category = 2},
{.sku = 99,
.has_base_accelerometer = 0,
.has_lid_accelerometer = 1,
- .is_lid_convertible = 1}
+ .is_lid_convertible = 1,
+ .stylus_category = 0}
};
#elif defined(BOARD_ANOTHER)
@@ -26,7 +28,8 @@
{.sku = 40,
.has_base_accelerometer = 1,
.has_lid_accelerometer = 1,
- .is_lid_convertible = 0}
+ .is_lid_convertible = 0,
+ .stylus_category = 0}
};
#endif
diff --git a/chromeos-config/libcros_config/ec_test_many.h b/chromeos-config/libcros_config/ec_test_many.h
index ecf3bb3..d97b28a 100644
--- a/chromeos-config/libcros_config/ec_test_many.h
+++ b/chromeos-config/libcros_config/ec_test_many.h
@@ -8,11 +8,19 @@
#include <stdint.h>
#include <stdlib.h>
+
+enum stylus_category_type {
+ STYLUS_CATEGORY_NONE = 0,
+ STYLUS_CATEGORY_INTERNAL = 1,
+ STYLUS_CATEGORY_EXTERNAL = 2
+};
+
struct sku_info {
const uint8_t sku;
const uint8_t has_base_accelerometer :1;
const uint8_t has_lid_accelerometer :1;
const uint8_t is_lid_convertible :1;
+ const uint8_t stylus_category :2;
};
extern const size_t NUM_SKUS;