diff --git a/Buildscripts/DevicetreeCompiler/compile.py b/Buildscripts/DevicetreeCompiler/compile.py index b5db6034..9f21731e 100644 --- a/Buildscripts/DevicetreeCompiler/compile.py +++ b/Buildscripts/DevicetreeCompiler/compile.py @@ -24,5 +24,6 @@ if __name__ == "__main__": is_verbose = "--verbose" in sys.argv devicetree_yaml_config = args[0] output_path = args[1] - main(devicetree_yaml_config, output_path, is_verbose) + result = main(devicetree_yaml_config, output_path, is_verbose) + sys.exit(result) diff --git a/Buildscripts/DevicetreeCompiler/source/binding_files.py b/Buildscripts/DevicetreeCompiler/source/binding_files.py index d6973310..504036dd 100644 --- a/Buildscripts/DevicetreeCompiler/source/binding_files.py +++ b/Buildscripts/DevicetreeCompiler/source/binding_files.py @@ -1,4 +1,5 @@ import os +from .exception import DevicetreeException def find_bindings(directory_path: str) -> list[str]: yaml_files = [] @@ -14,6 +15,6 @@ def find_all_bindings(directory_paths: list[str]) -> list[str]: for directory_path in directory_paths: new_paths = find_bindings(directory_path) if len(new_paths) == 0: - raise Exception(f"No bindings found in {directory_path}") + raise DevicetreeException(f"No bindings found in {directory_path}") yaml_files += new_paths return yaml_files \ No newline at end of file diff --git a/Buildscripts/DevicetreeCompiler/source/exception.py b/Buildscripts/DevicetreeCompiler/source/exception.py new file mode 100644 index 00000000..de70efd1 --- /dev/null +++ b/Buildscripts/DevicetreeCompiler/source/exception.py @@ -0,0 +1,3 @@ +class DevicetreeException(Exception): + def __init__(self, message): + super().__init__(message) diff --git a/Buildscripts/DevicetreeCompiler/source/generator.py b/Buildscripts/DevicetreeCompiler/source/generator.py index dd98c27c..c6d7685f 100644 --- a/Buildscripts/DevicetreeCompiler/source/generator.py +++ b/Buildscripts/DevicetreeCompiler/source/generator.py @@ -1,7 +1,7 @@ import os.path from textwrap import dedent - from source.models import * +from .exception import DevicetreeException def write_include(file, include: IncludeC, verbose: bool): if verbose: @@ -26,9 +26,9 @@ def get_device_node_name_safe(device: Device): def get_device_type_name(device: Device, bindings: list[Binding]): device_binding = find_device_binding(device, bindings) if device_binding is None: - raise Exception(f"Binding not found for {device.node_name}") + raise DevicetreeException(f"Binding not found for {device.node_name}") if device_binding.compatible is None: - raise Exception(f"Couldn't find compatible binding for {device.node_name}") + raise DevicetreeException(f"Couldn't find compatible binding for {device.node_name}") compatible_safe = device_binding.compatible.split(",")[-1] return compatible_safe.replace("-", "_") @@ -41,7 +41,7 @@ def find_device_property(device: Device, name: str) -> DeviceProperty: def find_device_binding(device: Device, bindings: list[Binding]) -> Binding: compatible_property = find_device_property(device, "compatible") if compatible_property is None: - raise Exception(f"property 'compatible' not found in device {device.node_name}") + raise DevicetreeException(f"property 'compatible' not found in device {device.node_name}") for binding in bindings: if binding.compatible == compatible_property.value: return binding @@ -57,7 +57,7 @@ def find_phandle(devices: list[Device], phandle: str): for device in devices: if device.node_name == phandle or device.node_alias == phandle: return f"&{get_device_node_name_safe(device)}" - raise Exception(f"phandle '{phandle}' not found in device tree") + raise DevicetreeException(f"phandle '{phandle}' not found in device tree") def property_to_string(property: DeviceProperty, devices: list[Device]) -> str: type = property.type @@ -74,15 +74,15 @@ def property_to_string(property: DeviceProperty, devices: list[Device]) -> str: elif type == "phandle": return find_phandle(devices, property.value) else: - raise Exception(f"property_to_string() has an unsupported type: {type}") + raise DevicetreeException(f"property_to_string() has an unsupported type: {type}") def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], devices: list[Device]) -> list: compatible_property = find_device_property(device, "compatible") if compatible_property is None: - raise Exception(f"Cannot find 'compatible' property for {device.node_name}") + raise DevicetreeException(f"Cannot find 'compatible' property for {device.node_name}") device_binding = find_binding(compatible_property.value, bindings) if device_binding is None: - raise Exception(f"Binding not found for {device.node_name} and compatible '{compatible_property.value}'") + raise DevicetreeException(f"Binding not found for {device.node_name} and compatible '{compatible_property.value}'") # Filter out system properties binding_properties = [] binding_property_names = set() @@ -96,7 +96,7 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], de if device_property.name in ["compatible"]: continue if device_property.name not in binding_property_names: - raise Exception(f"Device '{device.node_name}' has invalid property '{device_property.name}'") + raise DevicetreeException(f"Device '{device.node_name}' has invalid property '{device_property.name}'") # Allocate total expected configuration arguments result = [0] * len(binding_properties) @@ -106,7 +106,7 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], de if binding_property.type == "bool": result[index] = "false" elif binding_property.required: - raise Exception(f"device {device.node_name} doesn't have property '{binding_property.name}'") + raise DevicetreeException(f"device {device.node_name} doesn't have property '{binding_property.name}'") elif binding_property.default is not None: temp_prop = DeviceProperty( name=binding_property.name, @@ -115,7 +115,7 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], de ) result[index] = property_to_string(temp_prop, devices) else: - raise Exception(f"Device {device.node_name} doesn't have property '{binding_property.name}' and no default value is set") + raise DevicetreeException(f"Device {device.node_name} doesn't have property '{binding_property.name}' and no default value is set") else: result[index] = property_to_string(device_property, devices) return result @@ -142,7 +142,7 @@ def write_device_structs(file, device: Device, parent_device: Device, bindings: type_name = get_device_type_name(device, bindings) compatible_property = find_device_property(device, "compatible") if compatible_property is None: - raise Exception(f"Cannot find 'compatible' property for {device.node_name}") + raise DevicetreeException(f"Cannot find 'compatible' property for {device.node_name}") node_name = get_device_node_name_safe(device) config_variable_name = f"{node_name}_config" if parent_device is not None: @@ -169,7 +169,7 @@ def write_device_init(file, device: Device, bindings: list[Binding], verbose: bo # Assemble some pre-requisites compatible_property = find_device_property(device, "compatible") if compatible_property is None: - raise Exception(f"Cannot find 'compatible' property for {device.node_name}") + raise DevicetreeException(f"Cannot find 'compatible' property for {device.node_name}") # Type & instance names node_name = get_device_node_name_safe(device) device_variable = node_name diff --git a/Buildscripts/DevicetreeCompiler/source/main.py b/Buildscripts/DevicetreeCompiler/source/main.py index 97b7f0be..cca88576 100644 --- a/Buildscripts/DevicetreeCompiler/source/main.py +++ b/Buildscripts/DevicetreeCompiler/source/main.py @@ -9,38 +9,44 @@ from source.generator import * from source.binding_files import find_all_bindings from source.binding_parser import parse_binding from source.config import * +from source.exception import DevicetreeException -def main(config_path: str, output_path: str, verbose: bool): +def main(config_path: str, output_path: str, verbose: bool) -> int: print(f"Generating devicetree code\n config: {config_path}\n output: {output_path}") if not os.path.isdir(config_path): - raise Exception(f"Directory not found: {config_path}") + raise DevicetreeException(f"Directory not found: {config_path}") config = parse_config(config_path, os.getcwd()) if verbose: pprint(config) - project_dir = os.path.dirname(os.path.realpath(__file__)) - grammar_path = os.path.join(project_dir, "grammar.lark") - lark_data = read_file(grammar_path) - dts_data = read_file(config.dts) - lark = Lark(lark_data) - parsed = lark.parse(dts_data) - if verbose: - print(parsed.pretty()) - transformed = DtsTransformer().transform(parsed) - if verbose: - pprint(transformed) - binding_files = find_all_bindings(config.bindings) - if verbose: - print(f"Bindings found:") + try: + project_dir = os.path.dirname(os.path.realpath(__file__)) + grammar_path = os.path.join(project_dir, "grammar.lark") + lark_data = read_file(grammar_path) + dts_data = read_file(config.dts) + lark = Lark(lark_data) + parsed = lark.parse(dts_data) + if verbose: + print(parsed.pretty()) + transformed = DtsTransformer().transform(parsed) + if verbose: + pprint(transformed) + binding_files = find_all_bindings(config.bindings) + if verbose: + print(f"Bindings found:") + for binding_file in binding_files: + print(f" {binding_file}") + if verbose: + print(f"Parsing bindings") + bindings = [] for binding_file in binding_files: - print(f" {binding_file}") - if verbose: - print(f"Parsing bindings") - bindings = [] - for binding_file in binding_files: - bindings.append(parse_binding(binding_file, config.bindings)) - if verbose: - for binding in bindings: - pprint(binding) - generate(output_path, transformed, bindings, verbose) + bindings.append(parse_binding(binding_file, config.bindings)) + if verbose: + for binding in bindings: + pprint(binding) + generate(output_path, transformed, bindings, verbose) + return 0 + except DevicetreeException as caught: + print("\033[31mError: ", caught, "\033[0m") + return 1 diff --git a/Buildscripts/DevicetreeCompiler/source/transformer.py b/Buildscripts/DevicetreeCompiler/source/transformer.py index bb70e3cd..ffd6441c 100644 --- a/Buildscripts/DevicetreeCompiler/source/transformer.py +++ b/Buildscripts/DevicetreeCompiler/source/transformer.py @@ -4,6 +4,7 @@ from lark import Transformer from lark import Token from source.models import * from dataclasses import dataclass +from .exception import DevicetreeException def flatten_token_array(tokens: List[Token], name: str): result_list = list() @@ -23,7 +24,7 @@ class DtsTransformer(Transformer): def dts_version(self, tokens: List[Token]): version = tokens[0].value if version != "dts-v1": - raise Exception(f"Unsupported DTS version: {version}") + raise DevicetreeException(f"Unsupported DTS version: {version}") return DtsVersion(version) def device(self, tokens: list): node_name = None @@ -46,12 +47,12 @@ class DtsTransformer(Transformer): if (len(objects) == 1) or (objects[1] is None): return DeviceProperty(name, "boolean", True) if type(objects[1]) is not PropertyValue: - raise Exception(f"Object was not converted to PropertyValue: {objects[1]}") + raise DevicetreeException(f"Object was not converted to PropertyValue: {objects[1]}") return DeviceProperty(name, objects[1].type, objects[1].value) def property_value(self, tokens: List): token = tokens[0] if type(token) is Token: - raise Exception(f"Failed to convert token to PropertyValue: {token}") + raise DevicetreeException(f"Failed to convert token to PropertyValue: {token}") return token def PHANDLE(self, token: Token): return PropertyValue(type="phandle", value=token.value[1:]) diff --git a/Documentation/ideas.md b/Documentation/ideas.md index b41ee4f7..ed7fed5b 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -12,8 +12,6 @@ ## Higher Priority - Make a root device type so it can be discovered more easily. -- DTS/yaml: Consider support for default values. -- DTS: throw custom exceptions and catch them to show cleaner error messages. - When device.py selects a new device, it should automatically delete the build dirs (build/, cmake-*/) when it detects that the platform has changed. - Add font design tokens such as "regular", "title" and "smaller". Perhaps via the LVGL kernel module. - Add kernel listening mechanism so that the root device init can be notified when a device becomes available: