From 6bc4b712554e185a2f494c510e4e7960a2cf26ed Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 5 Feb 2026 19:20:41 +0100 Subject: [PATCH 1/7] Rename "identifier" to "node name" and improve name safety --- .../DevicetreeCompiler/source/generator.py | 46 +++++++++---------- .../DevicetreeCompiler/source/grammar.lark | 5 +- .../DevicetreeCompiler/source/models.py | 2 +- .../DevicetreeCompiler/source/transformer.py | 7 +-- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/Buildscripts/DevicetreeCompiler/source/generator.py b/Buildscripts/DevicetreeCompiler/source/generator.py index 795077f09..159235018 100644 --- a/Buildscripts/DevicetreeCompiler/source/generator.py +++ b/Buildscripts/DevicetreeCompiler/source/generator.py @@ -10,18 +10,18 @@ def write_include(file, include: IncludeC, verbose: bool): file.write(include.statement) file.write('\n') -def get_device_identifier_safe(device: Device): - if device.identifier == "/": +def get_device_node_name_safe(device: Device): + if device.node_name == "/": return "root" else: - return device.identifier + return device.node_name.replace("-", "_") 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.identifier}") + raise Exception(f"Binding not found for {device.node_name}") if device_binding.compatible is None: - raise Exception(f"Couldn't find compatible binding for {device.identifier}") + raise Exception(f"Couldn't find compatible binding for {device.node_name}") compatible_safe = device_binding.compatible.split(",")[-1] return compatible_safe.replace("-", "_") @@ -34,7 +34,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.identifier}") + raise Exception(f"property 'compatible' not found in device {device.node_name}") for binding in bindings: if binding.compatible == compatible_property.value: return binding @@ -60,10 +60,10 @@ def property_to_string(property: DeviceProperty) -> str: def resolve_parameters_from_bindings(device: Device, bindings: list[Binding]) -> list: compatible_property = find_device_property(device, "compatible") if compatible_property is None: - raise Exception(f"Cannot find 'compatible' property for {device.identifier}") + raise Exception(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.identifier} and compatible '{compatible_property.value}'") + raise Exception(f"Binding not found for {device.node_name} and compatible '{compatible_property.value}'") # Filter out system properties binding_properties = [] for property in device_binding.properties: @@ -75,7 +75,7 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding]) -> device_property = find_device_property(device, binding_property.name) if device_property is None: if binding_property.required: - raise Exception(f"device {device.identifier} doesn't have property '{binding_property.name}'") + raise Exception(f"device {device.node_name} doesn't have property '{binding_property.name}'") else: result[index] = '0' else: @@ -83,9 +83,9 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding]) -> return result def write_config(file, device: Device, bindings: list[Binding], type_name: str): - device_identifier = get_device_identifier_safe(device) + node_name = get_device_node_name_safe(device) config_type = f"{type_name}_config_dt" - config_variable_name = f"{device_identifier}_config" + config_variable_name = f"{node_name}_config" file.write(f"static const {config_type} {config_variable_name}" " = {\n") config_params = resolve_parameters_from_bindings(device, bindings) # Indent all params @@ -99,24 +99,24 @@ def write_config(file, device: Device, bindings: list[Binding], type_name: str): def write_device_structs(file, device: Device, parent_device: Device, bindings: list[Binding], verbose: bool): if verbose: - print(f"Writing device struct for '{device.identifier}'") + print(f"Writing device struct for '{device.node_name}'") # Assemble some pre-requisites 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.identifier}") - identifier = get_device_identifier_safe(device) - config_variable_name = f"{identifier}_config" + raise Exception(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: - parent_identifier = get_device_identifier_safe(parent_device) - parent_value = f"&{parent_identifier}" + parent_node_name = get_device_node_name_safe(parent_device) + parent_value = f"&{parent_node_name}" else: parent_value = "NULL" # Write config struct write_config(file, device, bindings, type_name) # Write device struct - file.write(f"static struct Device {identifier}" " = {\n") - file.write(f"\t.name = \"{device.identifier}\",\n") # Use original name + file.write(f"static struct Device {node_name}" " = {\n") + file.write(f"\t.name = \"{device.node_name}\",\n") # Use original name file.write(f"\t.config = &{config_variable_name},\n") file.write(f"\t.parent = {parent_value},\n") file.write("};\n\n") @@ -126,14 +126,14 @@ def write_device_structs(file, device: Device, parent_device: Device, bindings: def write_device_init(file, device: Device, bindings: list[Binding], verbose: bool): if verbose: - print(f"Processing device init code for '{device.identifier}'") + print(f"Processing device init code for '{device.node_name}'") # 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.identifier}") + raise Exception(f"Cannot find 'compatible' property for {device.node_name}") # Type & instance names - identifier = get_device_identifier_safe(device) - device_variable = identifier + node_name = get_device_node_name_safe(device) + device_variable = node_name # Write device struct file.write("\t{ " f"&{device_variable}, \"{compatible_property.value}\"" " },\n") # Write children diff --git a/Buildscripts/DevicetreeCompiler/source/grammar.lark b/Buildscripts/DevicetreeCompiler/source/grammar.lark index 03a539d70..341387bd7 100644 --- a/Buildscripts/DevicetreeCompiler/source/grammar.lark +++ b/Buildscripts/DevicetreeCompiler/source/grammar.lark @@ -37,9 +37,10 @@ array: NUMBER+ property_value: quoted_text_array | QUOTED_TEXT | "<" value ">" | "<" values ">" | "[" array "]" device_property: PROPERTY_NAME ["=" property_value] ";" -DEVICE_IDENTIFIER: /[a-zA-Z0-9_\-\/@]+/ +NODE_ALIAS: /[a-zA-Z0-9_\-\/@]+/ +NODE_NAME: /[a-zA-Z0-9_\-\/@]+/ -device: DEVICE_IDENTIFIER "{" (device | device_property)* "};" +device: (NODE_ALIAS ":")? NODE_NAME "{" (device | device_property)* "};" dts_version: /[0-9a-zA-Z\-]+/ diff --git a/Buildscripts/DevicetreeCompiler/source/models.py b/Buildscripts/DevicetreeCompiler/source/models.py index b747869f3..806a9dc3e 100644 --- a/Buildscripts/DevicetreeCompiler/source/models.py +++ b/Buildscripts/DevicetreeCompiler/source/models.py @@ -6,7 +6,7 @@ class DtsVersion: @dataclass class Device: - identifier: str + node_name: str properties: list devices: list diff --git a/Buildscripts/DevicetreeCompiler/source/transformer.py b/Buildscripts/DevicetreeCompiler/source/transformer.py index 13183769f..c38dd63bd 100644 --- a/Buildscripts/DevicetreeCompiler/source/transformer.py +++ b/Buildscripts/DevicetreeCompiler/source/transformer.py @@ -20,17 +20,18 @@ def dts_version(self, tokens: List[Token]): raise Exception(f"Unsupported DTS version: {version}") return DtsVersion(version) def device(self, tokens: list): - identifier = "UNKNOWN" + node_name = "UNKNOWN" properties = list() devices = list() + names = list() for index, entry in enumerate(tokens): if index == 0: - identifier = entry.value + node_name = entry.value elif type(entry) is DeviceProperty: properties.append(entry) elif type(entry) is Device: devices.append(entry) - return Device(identifier, properties, devices) + return Device(node_name, properties, devices) def device_property(self, objects: List[object]): name = objects[0] # Boolean property has no value as the value is implied to be true From 5ecfadfbc4b5e71698b208d5174b4f03cb57af74 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 5 Feb 2026 19:32:42 +0100 Subject: [PATCH 2/7] Parse node alias --- .../DevicetreeCompiler/source/models.py | 1 + .../DevicetreeCompiler/source/transformer.py | 24 ++++++++++--------- Devices/lilygo-tdeck/lilygo,tdeck.dts | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Buildscripts/DevicetreeCompiler/source/models.py b/Buildscripts/DevicetreeCompiler/source/models.py index 806a9dc3e..8bdcca249 100644 --- a/Buildscripts/DevicetreeCompiler/source/models.py +++ b/Buildscripts/DevicetreeCompiler/source/models.py @@ -7,6 +7,7 @@ class DtsVersion: @dataclass class Device: node_name: str + node_alias: str properties: list devices: list diff --git a/Buildscripts/DevicetreeCompiler/source/transformer.py b/Buildscripts/DevicetreeCompiler/source/transformer.py index c38dd63bd..64bdc7d9a 100644 --- a/Buildscripts/DevicetreeCompiler/source/transformer.py +++ b/Buildscripts/DevicetreeCompiler/source/transformer.py @@ -20,18 +20,20 @@ def dts_version(self, tokens: List[Token]): raise Exception(f"Unsupported DTS version: {version}") return DtsVersion(version) def device(self, tokens: list): - node_name = "UNKNOWN" + node_name = None + node_alias = None properties = list() - devices = list() - names = list() - for index, entry in enumerate(tokens): - if index == 0: - node_name = entry.value - elif type(entry) is DeviceProperty: - properties.append(entry) - elif type(entry) is Device: - devices.append(entry) - return Device(node_name, properties, devices) + child_devices = list() + for index, item in enumerate(tokens): + if type(item) is Token and item.type == 'NODE_NAME': + node_name = item.value + elif type(item) is Token and item.type == 'NODE_ALIAS': + node_alias = item.value + elif type(item) is DeviceProperty: + properties.append(item) + elif type(item) is Device: + child_devices.append(item) + return Device(node_name, node_alias, properties, child_devices) def device_property(self, objects: List[object]): name = objects[0] # Boolean property has no value as the value is implied to be true diff --git a/Devices/lilygo-tdeck/lilygo,tdeck.dts b/Devices/lilygo-tdeck/lilygo,tdeck.dts index 37ccd74e7..271e82228 100644 --- a/Devices/lilygo-tdeck/lilygo,tdeck.dts +++ b/Devices/lilygo-tdeck/lilygo,tdeck.dts @@ -24,7 +24,7 @@ pin-mclk = ; }; - i2c_internal { + i2c_internal: i2c0 { compatible = "espressif,esp32-i2c"; port = ; clock-frequency = <400000>; @@ -32,7 +32,7 @@ pin-scl = <8>; }; - i2c_external { + i2c_external: i2c1 { compatible = "espressif,esp32-i2c"; port = ; clock-frequency = <400000>; From 5a36f74aeb25227577440275b60731c6407b1d84 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 5 Feb 2026 20:14:34 +0100 Subject: [PATCH 3/7] Implement support for phandle type --- .../DevicetreeCompiler/source/generator.py | 47 ++++++++------ .../DevicetreeCompiler/source/grammar.lark | 4 +- .../DevicetreeCompiler/source/transformer.py | 8 +++ devicetree.c | 64 +++++++++++++++++++ 4 files changed, 103 insertions(+), 20 deletions(-) create mode 100644 devicetree.c diff --git a/Buildscripts/DevicetreeCompiler/source/generator.py b/Buildscripts/DevicetreeCompiler/source/generator.py index 159235018..2f9df54b1 100644 --- a/Buildscripts/DevicetreeCompiler/source/generator.py +++ b/Buildscripts/DevicetreeCompiler/source/generator.py @@ -46,7 +46,13 @@ def find_binding(compatible: str, bindings: list[Binding]) -> Binding: return binding return None -def property_to_string(property: DeviceProperty) -> str: +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") + +def property_to_string(property: DeviceProperty, devices: list[Device]) -> str: type = property.type if type == "value": return property.value @@ -54,10 +60,12 @@ def property_to_string(property: DeviceProperty) -> str: return f"\"{property.value}\"" elif type == "values": return "{ " + ",".join(property.value) + " }" + elif type == "phandle": + return find_phandle(devices, property.value) else: raise Exception(f"property_to_string() has an unsupported type: {type}") -def resolve_parameters_from_bindings(device: Device, bindings: list[Binding]) -> list: +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}") @@ -79,15 +87,15 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding]) -> else: result[index] = '0' else: - result[index] = property_to_string(device_property) + result[index] = property_to_string(device_property, devices) return result -def write_config(file, device: Device, bindings: list[Binding], type_name: str): +def write_config(file, device: Device, bindings: list[Binding], devices: list[Device], type_name: str): node_name = get_device_node_name_safe(device) config_type = f"{type_name}_config_dt" config_variable_name = f"{node_name}_config" file.write(f"static const {config_type} {config_variable_name}" " = {\n") - config_params = resolve_parameters_from_bindings(device, bindings) + config_params = resolve_parameters_from_bindings(device, bindings, devices) # Indent all params for index, config_param in enumerate(config_params): config_params[index] = f"\t{config_param}" @@ -97,7 +105,7 @@ def write_config(file, device: Device, bindings: list[Binding], type_name: str): file.write(f"{config_params_joined}\n") file.write("};\n\n") -def write_device_structs(file, device: Device, parent_device: Device, bindings: list[Binding], verbose: bool): +def write_device_structs(file, device: Device, parent_device: Device, bindings: list[Binding], devices: list[Device], verbose: bool): if verbose: print(f"Writing device struct for '{device.node_name}'") # Assemble some pre-requisites @@ -113,16 +121,13 @@ def write_device_structs(file, device: Device, parent_device: Device, bindings: else: parent_value = "NULL" # Write config struct - write_config(file, device, bindings, type_name) + write_config(file, device, bindings, devices, type_name) # Write device struct file.write(f"static struct Device {node_name}" " = {\n") file.write(f"\t.name = \"{device.node_name}\",\n") # Use original name file.write(f"\t.config = &{config_variable_name},\n") file.write(f"\t.parent = {parent_value},\n") file.write("};\n\n") - # Child devices - for child_device in device.devices: - write_device_structs(file, child_device, device, bindings, verbose) def write_device_init(file, device: Device, bindings: list[Binding], verbose: bool): if verbose: @@ -136,11 +141,19 @@ def write_device_init(file, device: Device, bindings: list[Binding], verbose: bo device_variable = node_name # Write device struct file.write("\t{ " f"&{device_variable}, \"{compatible_property.value}\"" " },\n") - # Write children + +# Walk the tree and gather all devices +def gather_devices(device: Device, output: list[Device]): + output.append(device) for child_device in device.devices: - write_device_init(file, child_device, bindings, verbose) + gather_devices(child_device, output) def generate_devicetree_c(filename: str, items: list[object], bindings: list[Binding], verbose: bool): + devices = list() + for item in items: + if type(item) is Device: + gather_devices(item, devices) + with open(filename, "w") as file: file.write(dedent('''\ // Default headers @@ -155,15 +168,13 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin file.write("\n") # Then write all devices - for item in items: - if type(item) is Device: - write_device_structs(file, item, None, bindings, verbose) + for device in devices: + write_device_structs(file, device, None, bindings, devices, verbose) # Init function body start file.write("struct CompatibleDevice devicetree_devices[] = {\n") # Init function body logic - for item in items: - if type(item) is Device: - write_device_init(file, item, bindings, verbose) + for device in devices: + write_device_init(file, device, bindings, verbose) # Init function body end file.write("\t{ NULL, NULL },\n") file.write("};\n") diff --git a/Buildscripts/DevicetreeCompiler/source/grammar.lark b/Buildscripts/DevicetreeCompiler/source/grammar.lark index 341387bd7..22f9a9797 100644 --- a/Buildscripts/DevicetreeCompiler/source/grammar.lark +++ b/Buildscripts/DevicetreeCompiler/source/grammar.lark @@ -27,14 +27,14 @@ QUOTED_TEXT: QUOTE /[^"]+/ QUOTE quoted_text_array: QUOTED_TEXT ("," " "* QUOTED_TEXT)+ HEX_NUMBER: "0x" HEXDIGIT+ NUMBER: SIGNED_NUMBER | HEX_NUMBER -PHANDLE: /&[0-9a-zA-Z\-]+/ +PHANDLE: /&[0-9a-zA-Z_\-]+/ C_VARIABLE: /[0-9a-zA-Z_]+/ VALUE: NUMBER | PHANDLE | C_VARIABLE value: VALUE values: VALUE+ array: NUMBER+ -property_value: quoted_text_array | QUOTED_TEXT | "<" value ">" | "<" values ">" | "[" array "]" +property_value: quoted_text_array | QUOTED_TEXT | "<" value ">" | "<" values ">" | "[" array "]" | PHANDLE device_property: PROPERTY_NAME ["=" property_value] ";" NODE_ALIAS: /[a-zA-Z0-9_\-\/@]+/ diff --git a/Buildscripts/DevicetreeCompiler/source/transformer.py b/Buildscripts/DevicetreeCompiler/source/transformer.py index 64bdc7d9a..4464ee35b 100644 --- a/Buildscripts/DevicetreeCompiler/source/transformer.py +++ b/Buildscripts/DevicetreeCompiler/source/transformer.py @@ -3,6 +3,7 @@ from lark import Transformer from lark import Token from source.models import * +from dataclasses import dataclass def flatten_token_array(tokens: List[Token], name: str): result_list = list() @@ -10,6 +11,11 @@ def flatten_token_array(tokens: List[Token], name: str): result_list.append(token.value) return Token(name, result_list) +@dataclass +class NodeNameAndAlias: + name: str + alias: str + class DtsTransformer(Transformer): # Flatten the start node into a list def start(self, tokens): @@ -47,6 +53,8 @@ def property_value(self, tokens: List): if type(token) is Token: raise Exception(f"Failed to convert token to PropertyValue: {token}") return token + def PHANDLE(self, token: Token): + return PropertyValue(type="phandle", value=token.value[1:]) def values(self, object): return PropertyValue(type="values", value=object) def value(self, object): diff --git a/devicetree.c b/devicetree.c new file mode 100644 index 000000000..c675bd3fe --- /dev/null +++ b/devicetree.c @@ -0,0 +1,64 @@ +// Default headers +#include +// DTS headers +#include +#include +#include +#include + +static const root_config_dt root_config = { + "LilyGO T-Deck" +}; + +static struct Device root = { + .name = "/", + .config = &root_config, + .parent = NULL, +}; + +static const esp32_i2s_config_dt i2s0_config = { + I2S_NUM_0, + 7, + 5, + 6, + GPIO_PIN_NONE, + GPIO_PIN_NONE +}; + +static struct Device i2s0 = { + .name = "i2s0", + .config = &i2s0_config, + .parent = &root, +}; + +static const esp32_i2c_config_dt i2c0_config = { + I2C_NUM_0, + 400000, + 18, + 8, + 0, + 0 +}; + +static struct Device i2c0 = { + .name = "i2c0", + .config = &i2c0_config, + .parent = &root, +}; + +static const esp32_i2c_config_dt i2c1_config = { + I2C_NUM_1, + 400000, + 43, + 44, + 0, + 0 +}; + +static struct Device i2c1 = { + .name = "i2c1", + .config = &i2c1_config, + .parent = &root, +}; + +static const esp32_gpio_config_dt gpio0_config = { From ec5d5ef3e75b2007f16a0af39e6d7f1fe476d5a3 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 5 Feb 2026 20:38:10 +0100 Subject: [PATCH 4/7] Implement support for #define --- Buildscripts/DevicetreeCompiler/source/generator.py | 9 +++++++++ Buildscripts/DevicetreeCompiler/source/grammar.lark | 3 ++- Buildscripts/DevicetreeCompiler/source/models.py | 4 ++++ Buildscripts/DevicetreeCompiler/source/transformer.py | 4 +++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Buildscripts/DevicetreeCompiler/source/generator.py b/Buildscripts/DevicetreeCompiler/source/generator.py index 2f9df54b1..b77d77b22 100644 --- a/Buildscripts/DevicetreeCompiler/source/generator.py +++ b/Buildscripts/DevicetreeCompiler/source/generator.py @@ -10,6 +10,13 @@ def write_include(file, include: IncludeC, verbose: bool): file.write(include.statement) file.write('\n') +def write_define(file, define: DefineC, verbose: bool): + if verbose: + print("Processing define:") + print(f" {define.statement}") + file.write(define.statement) + file.write('\n') + def get_device_node_name_safe(device: Device): if device.node_name == "/": return "root" @@ -165,6 +172,8 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin for item in items: if type(item) is IncludeC: write_include(file, item, verbose) + elif type(item) is DefineC: + write_define(file, item, verbose) file.write("\n") # Then write all devices diff --git a/Buildscripts/DevicetreeCompiler/source/grammar.lark b/Buildscripts/DevicetreeCompiler/source/grammar.lark index 25d92d847..e2a0493ff 100644 --- a/Buildscripts/DevicetreeCompiler/source/grammar.lark +++ b/Buildscripts/DevicetreeCompiler/source/grammar.lark @@ -21,6 +21,7 @@ BOOLEAN: "true" | "false" // Main INCLUDE_C: /#include <[\w\/.\-]+>/ +DEFINE_C: /#define[^\n]+/ PROPERTY_NAME: /#?[a-zA-Z0-9_\-,]+/ @@ -46,4 +47,4 @@ device: (NODE_ALIAS ":")? NODE_NAME "{" (device | device_property)* "};" dts_version: /[0-9a-zA-Z\-]+/ -start: "/" dts_version "/;" INCLUDE_C* device+ +start: "/" dts_version "/;" (INCLUDE_C | DEFINE_C)* device+ diff --git a/Buildscripts/DevicetreeCompiler/source/models.py b/Buildscripts/DevicetreeCompiler/source/models.py index 8bdcca249..a865c698f 100644 --- a/Buildscripts/DevicetreeCompiler/source/models.py +++ b/Buildscripts/DevicetreeCompiler/source/models.py @@ -26,6 +26,10 @@ class PropertyValue: class IncludeC: statement: str +@dataclass +class DefineC: + statement: str + @dataclass class BindingProperty: name: str diff --git a/Buildscripts/DevicetreeCompiler/source/transformer.py b/Buildscripts/DevicetreeCompiler/source/transformer.py index 4464ee35b..37359e14f 100644 --- a/Buildscripts/DevicetreeCompiler/source/transformer.py +++ b/Buildscripts/DevicetreeCompiler/source/transformer.py @@ -75,4 +75,6 @@ def quoted_text_array(self, tokens: List[Token]): result_list.append(token.value) return PropertyValue("text_array", result_list) def INCLUDE_C(self, token: Token): - return IncludeC(token.value) \ No newline at end of file + return IncludeC(token.value) + def DEFINE_C(self, token: Token): + return DefineC(token.value) \ No newline at end of file From 8619c23fefa0ce92e9f64d4f359f5fabd0cc565c Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 5 Feb 2026 21:54:53 +0100 Subject: [PATCH 5/7] Fix for parent setting --- .../DevicetreeCompiler/source/generator.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Buildscripts/DevicetreeCompiler/source/generator.py b/Buildscripts/DevicetreeCompiler/source/generator.py index b77d77b22..8a85e1fcc 100644 --- a/Buildscripts/DevicetreeCompiler/source/generator.py +++ b/Buildscripts/DevicetreeCompiler/source/generator.py @@ -135,6 +135,9 @@ def write_device_structs(file, device: Device, parent_device: Device, bindings: file.write(f"\t.config = &{config_variable_name},\n") file.write(f"\t.parent = {parent_value},\n") file.write("};\n\n") + # Child devices + for child_device in device.devices: + write_device_structs(file, child_device, device, bindings, devices, verbose) def write_device_init(file, device: Device, bindings: list[Binding], verbose: bool): if verbose: @@ -148,6 +151,9 @@ def write_device_init(file, device: Device, bindings: list[Binding], verbose: bo device_variable = node_name # Write device struct file.write("\t{ " f"&{device_variable}, \"{compatible_property.value}\"" " },\n") + # Write children + for child_device in device.devices: + write_device_init(file, child_device, bindings, verbose) # Walk the tree and gather all devices def gather_devices(device: Device, output: list[Device]): @@ -156,6 +162,8 @@ def gather_devices(device: Device, output: list[Device]): gather_devices(child_device, output) def generate_devicetree_c(filename: str, items: list[object], bindings: list[Binding], verbose: bool): + # Create a cache for looking up device names and aliases easily + # We still want to traverse it as a tree during code generation because of parent-setting devices = list() for item in items: if type(item) is Device: @@ -177,13 +185,15 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin file.write("\n") # Then write all devices - for device in devices: - write_device_structs(file, device, None, bindings, devices, verbose) + for item in items: + if type(item) is Device: + write_device_structs(file, item, None, bindings, devices, verbose) # Init function body start file.write("struct CompatibleDevice devicetree_devices[] = {\n") # Init function body logic - for device in devices: - write_device_init(file, device, bindings, verbose) + for item in items: + if type(item) is Device: + write_device_init(file, item, bindings, verbose) # Init function body end file.write("\t{ NULL, NULL },\n") file.write("};\n") From 4021320d3a8895985d2ce9b8a23342c21db2d60f Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 5 Feb 2026 22:37:31 +0100 Subject: [PATCH 6/7] Fix for phandle in list such as <&label> --- Buildscripts/DevicetreeCompiler/source/transformer.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Buildscripts/DevicetreeCompiler/source/transformer.py b/Buildscripts/DevicetreeCompiler/source/transformer.py index 37359e14f..bb70e3cde 100644 --- a/Buildscripts/DevicetreeCompiler/source/transformer.py +++ b/Buildscripts/DevicetreeCompiler/source/transformer.py @@ -58,10 +58,15 @@ def PHANDLE(self, token: Token): def values(self, object): return PropertyValue(type="values", value=object) def value(self, object): + # PHANDLE is already converted to PropertyValue + if isinstance(object[0], PropertyValue): + return object[0] return PropertyValue(type="value", value=object[0]) def array(self, object): return PropertyValue(type="array", value=object) def VALUE(self, token: Token): + if token.value.startswith("&"): + return PropertyValue(type="phandle", value=token.value[1:]) return token.value def NUMBER(self, token: Token): return token.value From a34b2b5b4c888340548e1ed3928b5fd5a2e34482 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 5 Feb 2026 22:38:16 +0100 Subject: [PATCH 7/7] Add TODO --- Devices/lilygo-tlora-pager/lilygo,tlora-pager.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Devices/lilygo-tlora-pager/lilygo,tlora-pager.dts b/Devices/lilygo-tlora-pager/lilygo,tlora-pager.dts index 7ed66e9fb..92d56abd7 100644 --- a/Devices/lilygo-tlora-pager/lilygo,tlora-pager.dts +++ b/Devices/lilygo-tlora-pager/lilygo,tlora-pager.dts @@ -23,7 +23,8 @@ pin-scl = <2>; }; - // ES8311 (also connected to I2C bus) + // ES8311 + // TODO: init via I2C to enable audio playback i2s0 { compatible = "espressif,esp32-i2s"; port = ;