mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-20 15:35:05 +00:00
Implement cleaner error handling
This commit is contained in:
parent
2e7e5d36c0
commit
27cbec1151
@ -24,5 +24,6 @@ if __name__ == "__main__":
|
|||||||
is_verbose = "--verbose" in sys.argv
|
is_verbose = "--verbose" in sys.argv
|
||||||
devicetree_yaml_config = args[0]
|
devicetree_yaml_config = args[0]
|
||||||
output_path = args[1]
|
output_path = args[1]
|
||||||
main(devicetree_yaml_config, output_path, is_verbose)
|
result = main(devicetree_yaml_config, output_path, is_verbose)
|
||||||
|
sys.exit(result)
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
from .exception import DevicetreeException
|
||||||
|
|
||||||
def find_bindings(directory_path: str) -> list[str]:
|
def find_bindings(directory_path: str) -> list[str]:
|
||||||
yaml_files = []
|
yaml_files = []
|
||||||
@ -14,6 +15,6 @@ def find_all_bindings(directory_paths: list[str]) -> list[str]:
|
|||||||
for directory_path in directory_paths:
|
for directory_path in directory_paths:
|
||||||
new_paths = find_bindings(directory_path)
|
new_paths = find_bindings(directory_path)
|
||||||
if len(new_paths) == 0:
|
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
|
yaml_files += new_paths
|
||||||
return yaml_files
|
return yaml_files
|
||||||
3
Buildscripts/DevicetreeCompiler/source/exception.py
Normal file
3
Buildscripts/DevicetreeCompiler/source/exception.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
class DevicetreeException(Exception):
|
||||||
|
def __init__(self, message):
|
||||||
|
super().__init__(message)
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import os.path
|
import os.path
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
from source.models import *
|
from source.models import *
|
||||||
|
from .exception import DevicetreeException
|
||||||
|
|
||||||
def write_include(file, include: IncludeC, verbose: bool):
|
def write_include(file, include: IncludeC, verbose: bool):
|
||||||
if verbose:
|
if verbose:
|
||||||
@ -26,9 +26,9 @@ def get_device_node_name_safe(device: Device):
|
|||||||
def get_device_type_name(device: Device, bindings: list[Binding]):
|
def get_device_type_name(device: Device, bindings: list[Binding]):
|
||||||
device_binding = find_device_binding(device, bindings)
|
device_binding = find_device_binding(device, bindings)
|
||||||
if device_binding is None:
|
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:
|
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]
|
compatible_safe = device_binding.compatible.split(",")[-1]
|
||||||
return compatible_safe.replace("-", "_")
|
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:
|
def find_device_binding(device: Device, bindings: list[Binding]) -> Binding:
|
||||||
compatible_property = find_device_property(device, "compatible")
|
compatible_property = find_device_property(device, "compatible")
|
||||||
if compatible_property is None:
|
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:
|
for binding in bindings:
|
||||||
if binding.compatible == compatible_property.value:
|
if binding.compatible == compatible_property.value:
|
||||||
return binding
|
return binding
|
||||||
@ -57,7 +57,7 @@ def find_phandle(devices: list[Device], phandle: str):
|
|||||||
for device in devices:
|
for device in devices:
|
||||||
if device.node_name == phandle or device.node_alias == phandle:
|
if device.node_name == phandle or device.node_alias == phandle:
|
||||||
return f"&{get_device_node_name_safe(device)}"
|
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:
|
def property_to_string(property: DeviceProperty, devices: list[Device]) -> str:
|
||||||
type = property.type
|
type = property.type
|
||||||
@ -74,15 +74,15 @@ def property_to_string(property: DeviceProperty, devices: list[Device]) -> str:
|
|||||||
elif type == "phandle":
|
elif type == "phandle":
|
||||||
return find_phandle(devices, property.value)
|
return find_phandle(devices, property.value)
|
||||||
else:
|
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:
|
def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], devices: list[Device]) -> list:
|
||||||
compatible_property = find_device_property(device, "compatible")
|
compatible_property = find_device_property(device, "compatible")
|
||||||
if compatible_property is None:
|
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)
|
device_binding = find_binding(compatible_property.value, bindings)
|
||||||
if device_binding is None:
|
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
|
# Filter out system properties
|
||||||
binding_properties = []
|
binding_properties = []
|
||||||
binding_property_names = set()
|
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"]:
|
if device_property.name in ["compatible"]:
|
||||||
continue
|
continue
|
||||||
if device_property.name not in binding_property_names:
|
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
|
# Allocate total expected configuration arguments
|
||||||
result = [0] * len(binding_properties)
|
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":
|
if binding_property.type == "bool":
|
||||||
result[index] = "false"
|
result[index] = "false"
|
||||||
elif binding_property.required:
|
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:
|
elif binding_property.default is not None:
|
||||||
temp_prop = DeviceProperty(
|
temp_prop = DeviceProperty(
|
||||||
name=binding_property.name,
|
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)
|
result[index] = property_to_string(temp_prop, devices)
|
||||||
else:
|
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:
|
else:
|
||||||
result[index] = property_to_string(device_property, devices)
|
result[index] = property_to_string(device_property, devices)
|
||||||
return result
|
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)
|
type_name = get_device_type_name(device, bindings)
|
||||||
compatible_property = find_device_property(device, "compatible")
|
compatible_property = find_device_property(device, "compatible")
|
||||||
if compatible_property is None:
|
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)
|
node_name = get_device_node_name_safe(device)
|
||||||
config_variable_name = f"{node_name}_config"
|
config_variable_name = f"{node_name}_config"
|
||||||
if parent_device is not None:
|
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
|
# Assemble some pre-requisites
|
||||||
compatible_property = find_device_property(device, "compatible")
|
compatible_property = find_device_property(device, "compatible")
|
||||||
if compatible_property is None:
|
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
|
# Type & instance names
|
||||||
node_name = get_device_node_name_safe(device)
|
node_name = get_device_node_name_safe(device)
|
||||||
device_variable = node_name
|
device_variable = node_name
|
||||||
|
|||||||
@ -9,38 +9,44 @@ from source.generator import *
|
|||||||
from source.binding_files import find_all_bindings
|
from source.binding_files import find_all_bindings
|
||||||
from source.binding_parser import parse_binding
|
from source.binding_parser import parse_binding
|
||||||
from source.config import *
|
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}")
|
print(f"Generating devicetree code\n config: {config_path}\n output: {output_path}")
|
||||||
if not os.path.isdir(config_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())
|
config = parse_config(config_path, os.getcwd())
|
||||||
if verbose:
|
if verbose:
|
||||||
pprint(config)
|
pprint(config)
|
||||||
|
|
||||||
project_dir = os.path.dirname(os.path.realpath(__file__))
|
try:
|
||||||
grammar_path = os.path.join(project_dir, "grammar.lark")
|
project_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
lark_data = read_file(grammar_path)
|
grammar_path = os.path.join(project_dir, "grammar.lark")
|
||||||
dts_data = read_file(config.dts)
|
lark_data = read_file(grammar_path)
|
||||||
lark = Lark(lark_data)
|
dts_data = read_file(config.dts)
|
||||||
parsed = lark.parse(dts_data)
|
lark = Lark(lark_data)
|
||||||
if verbose:
|
parsed = lark.parse(dts_data)
|
||||||
print(parsed.pretty())
|
if verbose:
|
||||||
transformed = DtsTransformer().transform(parsed)
|
print(parsed.pretty())
|
||||||
if verbose:
|
transformed = DtsTransformer().transform(parsed)
|
||||||
pprint(transformed)
|
if verbose:
|
||||||
binding_files = find_all_bindings(config.bindings)
|
pprint(transformed)
|
||||||
if verbose:
|
binding_files = find_all_bindings(config.bindings)
|
||||||
print(f"Bindings found:")
|
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:
|
for binding_file in binding_files:
|
||||||
print(f" {binding_file}")
|
bindings.append(parse_binding(binding_file, config.bindings))
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"Parsing bindings")
|
for binding in bindings:
|
||||||
bindings = []
|
pprint(binding)
|
||||||
for binding_file in binding_files:
|
generate(output_path, transformed, bindings, verbose)
|
||||||
bindings.append(parse_binding(binding_file, config.bindings))
|
return 0
|
||||||
if verbose:
|
except DevicetreeException as caught:
|
||||||
for binding in bindings:
|
print("\033[31mError: ", caught, "\033[0m")
|
||||||
pprint(binding)
|
return 1
|
||||||
generate(output_path, transformed, bindings, verbose)
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ from lark import Transformer
|
|||||||
from lark import Token
|
from lark import Token
|
||||||
from source.models import *
|
from source.models import *
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from .exception import DevicetreeException
|
||||||
|
|
||||||
def flatten_token_array(tokens: List[Token], name: str):
|
def flatten_token_array(tokens: List[Token], name: str):
|
||||||
result_list = list()
|
result_list = list()
|
||||||
@ -23,7 +24,7 @@ class DtsTransformer(Transformer):
|
|||||||
def dts_version(self, tokens: List[Token]):
|
def dts_version(self, tokens: List[Token]):
|
||||||
version = tokens[0].value
|
version = tokens[0].value
|
||||||
if version != "dts-v1":
|
if version != "dts-v1":
|
||||||
raise Exception(f"Unsupported DTS version: {version}")
|
raise DevicetreeException(f"Unsupported DTS version: {version}")
|
||||||
return DtsVersion(version)
|
return DtsVersion(version)
|
||||||
def device(self, tokens: list):
|
def device(self, tokens: list):
|
||||||
node_name = None
|
node_name = None
|
||||||
@ -46,12 +47,12 @@ class DtsTransformer(Transformer):
|
|||||||
if (len(objects) == 1) or (objects[1] is None):
|
if (len(objects) == 1) or (objects[1] is None):
|
||||||
return DeviceProperty(name, "boolean", True)
|
return DeviceProperty(name, "boolean", True)
|
||||||
if type(objects[1]) is not PropertyValue:
|
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)
|
return DeviceProperty(name, objects[1].type, objects[1].value)
|
||||||
def property_value(self, tokens: List):
|
def property_value(self, tokens: List):
|
||||||
token = tokens[0]
|
token = tokens[0]
|
||||||
if type(token) is Token:
|
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
|
return token
|
||||||
def PHANDLE(self, token: Token):
|
def PHANDLE(self, token: Token):
|
||||||
return PropertyValue(type="phandle", value=token.value[1:])
|
return PropertyValue(type="phandle", value=token.value[1:])
|
||||||
|
|||||||
@ -12,8 +12,6 @@
|
|||||||
## Higher Priority
|
## Higher Priority
|
||||||
|
|
||||||
- Make a root device type so it can be discovered more easily.
|
- 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.
|
- 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 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:
|
- Add kernel listening mechanism so that the root device init can be notified when a device becomes available:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user