mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-05 08:06:39 +00:00
If there is more than one PWM than generate a define with a trailing index for the PWM. This matches what we do for GPIOs. So something like: DT_PWM_LEDS_RED_PWM_LED_PWMS_CONTROLLER_0 DT_PWM_LEDS_RED_PWM_LED_PWMS_CONTROLLER_1 ... DT_PWM_LEDS_RED_PWM_LED_PWMS_CONTROLLER_<N> Fixes #18171 Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
649 lines
21 KiB
Python
Executable File
649 lines
21 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Copyright (c) 2019 Nordic Semiconductor ASA
|
|
# Copyright (c) 2019 Linaro Limited
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
# This script uses edtlib to generate a header file and a .conf file (both
|
|
# containing the same values) from a device tree (.dts) file. Information from
|
|
# binding files in YAML format is used as well.
|
|
#
|
|
# Bindings are files that describe device tree nodes. Device tree nodes are
|
|
# usually mapped to bindings via their 'compatible = "..."' property.
|
|
#
|
|
# See the docstring/comments at the top of edtlib.py for more information.
|
|
#
|
|
# Note: Do not access private (_-prefixed) identifiers from edtlib here (and
|
|
# also note that edtlib is not meant to expose the dtlib API directly).
|
|
# Instead, think of what API you need, and add it as a public documented API in
|
|
# edtlib. This will keep this script simple.
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
import edtlib
|
|
|
|
|
|
def main():
|
|
global conf_file
|
|
global header_file
|
|
|
|
args = parse_args()
|
|
|
|
try:
|
|
edt = edtlib.EDT(args.dts, args.bindings_dirs)
|
|
except edtlib.EDTError as e:
|
|
sys.exit("device tree error: " + str(e))
|
|
|
|
conf_file = open(args.conf_out, "w", encoding="utf-8")
|
|
header_file = open(args.header_out, "w", encoding="utf-8")
|
|
|
|
out_comment("Generated by gen_defines.py", blank_before=False)
|
|
out_comment("DTS input file: " + args.dts, blank_before=False)
|
|
out_comment("Directories with bindings: " + ", ".join(args.bindings_dirs),
|
|
blank_before=False)
|
|
|
|
active_compats = set()
|
|
|
|
for dev in edt.devices:
|
|
if dev.enabled and dev.matching_compat:
|
|
# Skip 'fixed-partitions' devices since they are handled by
|
|
# write_flash() and would generate extra spurious #defines
|
|
if dev.matching_compat == "fixed-partitions":
|
|
continue
|
|
|
|
out_comment("Device tree node: " + dev.path)
|
|
out_comment("Binding (compatible = {}): {}".format(
|
|
dev.matching_compat, dev.binding_path),
|
|
blank_before=False)
|
|
out_comment("Binding description: " + dev.description,
|
|
blank_before=False)
|
|
|
|
write_regs(dev)
|
|
write_irqs(dev)
|
|
write_gpios(dev)
|
|
write_pwms(dev)
|
|
write_iochannels(dev)
|
|
write_clocks(dev)
|
|
write_spi_dev(dev)
|
|
write_props(dev)
|
|
write_bus(dev)
|
|
write_existence_flags(dev)
|
|
|
|
active_compats.update(dev.compats)
|
|
|
|
out_comment("Active compatibles (mentioned in DTS + binding found)")
|
|
for compat in sorted(active_compats):
|
|
#define DT_COMPAT_<COMPAT> 1
|
|
out("COMPAT_{}".format(str2ident(compat)), 1)
|
|
|
|
# These are derived from /chosen
|
|
write_addr_size(edt, "zephyr,sram", "SRAM")
|
|
write_addr_size(edt, "zephyr,ccm", "CCM")
|
|
write_addr_size(edt, "zephyr,dtcm", "DTCM")
|
|
|
|
# NOTE: These defines aren't used by the code and just used by
|
|
# the kconfig build system, we can remove them in the future
|
|
# if we provide a function in kconfigfunctions.py to get
|
|
# the same info
|
|
write_required_label("UART_CONSOLE_ON_DEV_NAME", edt.chosen_dev("zephyr,console"))
|
|
write_required_label("UART_SHELL_ON_DEV_NAME", edt.chosen_dev("zephyr,shell-uart"))
|
|
write_required_label("BT_UART_ON_DEV_NAME", edt.chosen_dev("zephyr,bt-uart"))
|
|
write_required_label("UART_PIPE_ON_DEV_NAME", edt.chosen_dev("zephyr,uart-pipe"))
|
|
write_required_label("BT_MONITOR_ON_DEV_NAME", edt.chosen_dev("zephyr,bt-mon-uart"))
|
|
write_required_label("UART_MCUMGR_ON_DEV_NAME", edt.chosen_dev("zephyr,uart-mcumgr"))
|
|
write_required_label("BT_C2H_UART_ON_DEV_NAME", edt.chosen_dev("zephyr,bt-c2h-uart"))
|
|
|
|
write_flash(edt.chosen_dev("zephyr,flash"))
|
|
write_code_partition(edt.chosen_dev("zephyr,code-partition"))
|
|
|
|
flash_index = 0
|
|
for dev in edt.devices:
|
|
if dev.name.startswith("partition@"):
|
|
write_flash_partition(dev, flash_index)
|
|
flash_index += 1
|
|
|
|
out_comment("Number of flash partitions")
|
|
if flash_index != 0:
|
|
out("FLASH_AREA_NUM", flash_index)
|
|
|
|
print("Device tree configuration written to " + args.conf_out)
|
|
|
|
|
|
def parse_args():
|
|
# Returns parsed command-line arguments
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--dts", required=True, help="DTS file")
|
|
parser.add_argument("--bindings-dirs", nargs='+', required=True,
|
|
help="directory with bindings in YAML format, "
|
|
"we allow multiple")
|
|
parser.add_argument("--header-out", required=True,
|
|
help="path to write header to")
|
|
parser.add_argument("--conf-out", required=True,
|
|
help="path to write configuration file to")
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def write_regs(dev):
|
|
# Writes address/size output for the registers in dev's 'reg' property
|
|
|
|
def reg_addr_name_alias(reg):
|
|
return str2ident(reg.name) + "_BASE_ADDRESS" if reg.name else None
|
|
|
|
def reg_size_name_alias(reg):
|
|
return str2ident(reg.name) + "_SIZE" if reg.name else None
|
|
|
|
for reg in dev.regs:
|
|
out_dev(dev, reg_addr_ident(reg), hex(reg.addr),
|
|
name_alias=reg_addr_name_alias(reg))
|
|
|
|
if reg.size:
|
|
out_dev(dev, reg_size_ident(reg), reg.size,
|
|
name_alias=reg_size_name_alias(reg))
|
|
|
|
|
|
def write_props(dev):
|
|
# Writes any properties defined in the "properties" section of the binding
|
|
# for the device
|
|
|
|
for prop in dev.props.values():
|
|
# Skip #size-cell and other property starting with #. Also skip mapping
|
|
# properties like 'gpio-map'.
|
|
if prop.name[0] == "#" or prop.name.endswith("-map"):
|
|
continue
|
|
|
|
# Skip properties that we handle elsewhere
|
|
if prop.name in {"reg", "interrupts", "compatible", "interrupt-controller",
|
|
"gpio-controller"}:
|
|
continue
|
|
|
|
if prop.description is not None:
|
|
out_comment(prop.description, blank_before=False)
|
|
|
|
ident = str2ident(prop.name)
|
|
|
|
if isinstance(prop.val, bool):
|
|
out_dev(dev, ident, 1 if prop.val else 0)
|
|
elif isinstance(prop.val, str):
|
|
out_dev_s(dev, ident, prop.val)
|
|
elif isinstance(prop.val, int):
|
|
out_dev(dev, ident, prop.val)
|
|
elif isinstance(prop.val, list):
|
|
for i, elm in enumerate(prop.val):
|
|
out_fn = out_dev_s if isinstance(elm, str) else out_dev
|
|
out_fn(dev, "{}_{}".format(ident, i), elm)
|
|
elif isinstance(prop.val, bytes):
|
|
out_dev(dev, ident,
|
|
"{ " + ", ".join("0x{:02x}".format(b) for b in prop.val) + " }")
|
|
|
|
# Generate DT_..._ENUM if there's an 'enum:' key in the binding
|
|
if prop.enum_index is not None:
|
|
out_dev(dev, ident + "_ENUM", prop.enum_index)
|
|
|
|
|
|
def write_bus(dev):
|
|
# Generate bus-related #defines
|
|
|
|
if not dev.bus:
|
|
return
|
|
|
|
if dev.parent.label is None:
|
|
err("missing 'label' property on {!r}".format(dev.parent))
|
|
|
|
# #define DT_<DEV-IDENT>_BUS_NAME <BUS-LABEL>
|
|
out_dev_s(dev, "BUS_NAME", str2ident(dev.parent.label))
|
|
|
|
for compat in dev.compats:
|
|
# #define DT_<COMPAT>_BUS_<BUS-TYPE> 1
|
|
out("{}_BUS_{}".format(str2ident(compat), str2ident(dev.bus)), 1)
|
|
|
|
|
|
def write_existence_flags(dev):
|
|
# Generate #defines of the form
|
|
#
|
|
# #define DT_INST_<INSTANCE>_<COMPAT> 1
|
|
#
|
|
# These are flags for which devices exist.
|
|
|
|
for compat in dev.compats:
|
|
out("INST_{}_{}".format(dev.instance_no[compat], str2ident(compat)), 1)
|
|
|
|
|
|
def reg_addr_ident(reg):
|
|
# Returns the identifier (e.g., macro name) to be used for the address of
|
|
# 'reg' in the output
|
|
|
|
dev = reg.dev
|
|
|
|
# NOTE: to maintain compat wit the old script we special case if there's
|
|
# only a single register (we drop the '_0').
|
|
if len(dev.regs) > 1:
|
|
return "BASE_ADDRESS_{}".format(dev.regs.index(reg))
|
|
else:
|
|
return "BASE_ADDRESS"
|
|
|
|
|
|
def reg_size_ident(reg):
|
|
# Returns the identifier (e.g., macro name) to be used for the size of
|
|
# 'reg' in the output
|
|
|
|
dev = reg.dev
|
|
|
|
# NOTE: to maintain compat wit the old script we special case if there's
|
|
# only a single register (we drop the '_0').
|
|
if len(dev.regs) > 1:
|
|
return "SIZE_{}".format(dev.regs.index(reg))
|
|
else:
|
|
return "SIZE"
|
|
|
|
|
|
def dev_ident(dev):
|
|
# Returns an identifier for the Device 'dev'. Used when building e.g. macro
|
|
# names.
|
|
|
|
# TODO: Handle PWM on STM
|
|
# TODO: Better document the rules of how we generate things
|
|
|
|
ident = ""
|
|
|
|
if dev.bus:
|
|
ident += "{}_{:X}_".format(
|
|
str2ident(dev.parent.matching_compat), dev.parent.unit_addr)
|
|
|
|
ident += "{}_".format(str2ident(dev.matching_compat))
|
|
|
|
if dev.unit_addr is not None:
|
|
ident += "{:X}".format(dev.unit_addr)
|
|
elif dev.parent.unit_addr is not None:
|
|
ident += "{:X}_{}".format(dev.parent.unit_addr, str2ident(dev.name))
|
|
else:
|
|
# This is a bit of a hack
|
|
ident += "{}".format(str2ident(dev.name))
|
|
|
|
return ident
|
|
|
|
|
|
def dev_aliases(dev):
|
|
# Returns a list of aliases for the Device 'dev', used e.g. when building
|
|
# macro names
|
|
|
|
return dev_path_aliases(dev) + dev_instance_aliases(dev)
|
|
|
|
|
|
def dev_path_aliases(dev):
|
|
# Returns a list of aliases for the Device 'dev', based on the aliases
|
|
# registered for the device, in the /aliases node. Used when building e.g.
|
|
# macro names.
|
|
|
|
if dev.matching_compat is None:
|
|
return []
|
|
|
|
compat_s = str2ident(dev.matching_compat)
|
|
|
|
aliases = []
|
|
for alias in dev.aliases:
|
|
aliases.append("ALIAS_{}".format(str2ident(alias)))
|
|
# TODO: See if we can remove or deprecate this form
|
|
aliases.append("{}_{}".format(compat_s, str2ident(alias)))
|
|
|
|
return aliases
|
|
|
|
|
|
def dev_instance_aliases(dev):
|
|
# Returns a list of aliases for the Device 'dev', based on the instance
|
|
# number of the device (based on how many instances of that particular
|
|
# device there are).
|
|
#
|
|
# This is a list since a device can have multiple 'compatible' strings,
|
|
# each with their own instance number.
|
|
|
|
return ["INST_{}_{}".format(dev.instance_no[compat], str2ident(compat))
|
|
for compat in dev.compats]
|
|
|
|
|
|
def write_addr_size(edt, prop_name, prefix):
|
|
# Writes <prefix>_BASE_ADDRESS and <prefix>_SIZE for the device
|
|
# pointed at by the /chosen property named 'prop_name', if it exists
|
|
|
|
dev = edt.chosen_dev(prop_name)
|
|
if not dev:
|
|
return
|
|
|
|
if not dev.regs:
|
|
err("missing 'reg' property in node pointed at by /chosen/{} ({!r})"
|
|
.format(prop_name, dev))
|
|
|
|
out_comment("/chosen/{} ({})".format(prop_name, dev.path))
|
|
out("{}_BASE_ADDRESS".format(prefix), hex(dev.regs[0].addr))
|
|
out("{}_SIZE".format(prefix), dev.regs[0].size//1024)
|
|
|
|
|
|
def write_flash(flash_dev):
|
|
# Writes output for the node pointed at by the zephyr,flash property in
|
|
# /chosen
|
|
|
|
out_comment("/chosen/zephyr,flash ({})"
|
|
.format(flash_dev.path if flash_dev else "missing"))
|
|
|
|
if not flash_dev:
|
|
# No flash device. Write dummy values.
|
|
out("FLASH_BASE_ADDRESS", 0)
|
|
out("FLASH_SIZE", 0)
|
|
return
|
|
|
|
if len(flash_dev.regs) != 1:
|
|
err("expected zephyr,flash to have a single register, has {}"
|
|
.format(len(flash_dev.regs)))
|
|
|
|
if flash_dev.bus == "spi" and len(flash_dev.parent.regs) == 2:
|
|
reg = flash_dev.parent.regs[1] # QSPI flash
|
|
else:
|
|
reg = flash_dev.regs[0]
|
|
|
|
out("FLASH_BASE_ADDRESS", hex(reg.addr))
|
|
if reg.size:
|
|
out("FLASH_SIZE", reg.size//1024)
|
|
|
|
if "erase-block-size" in flash_dev.props:
|
|
out("FLASH_ERASE_BLOCK_SIZE", flash_dev.props["erase-block-size"].val)
|
|
|
|
if "write-block-size" in flash_dev.props:
|
|
out("FLASH_WRITE_BLOCK_SIZE", flash_dev.props["write-block-size"].val)
|
|
|
|
|
|
def write_code_partition(code_dev):
|
|
# Writes output for the node pointed at by the zephyr,code-partition
|
|
# property in /chosen
|
|
|
|
out_comment("/chosen/zephyr,code-partition ({})"
|
|
.format(code_dev.path if code_dev else "missing"))
|
|
|
|
if not code_dev:
|
|
# No code partition. Write dummy values.
|
|
out("CODE_PARTITION_OFFSET", 0)
|
|
out("CODE_PARTITION_SIZE", 0)
|
|
return
|
|
|
|
if not code_dev.regs:
|
|
err("missing 'regs' property on {!r}".format(code_dev))
|
|
|
|
out("CODE_PARTITION_OFFSET", code_dev.regs[0].addr)
|
|
out("CODE_PARTITION_SIZE", code_dev.regs[0].size)
|
|
|
|
|
|
def write_flash_partition(partition_dev, index):
|
|
out_comment("Flash partition at " + partition_dev.path)
|
|
|
|
if partition_dev.label is None:
|
|
err("missing 'label' property on {!r}".format(partition_dev))
|
|
|
|
# Generate label-based identifiers
|
|
write_flash_partition_prefix(
|
|
"FLASH_AREA_" + str2ident(partition_dev.label), partition_dev, index)
|
|
|
|
# Generate index-based identifiers
|
|
write_flash_partition_prefix(
|
|
"FLASH_AREA_{}".format(index), partition_dev, index)
|
|
|
|
|
|
def write_flash_partition_prefix(prefix, partition_dev, index):
|
|
# write_flash_partition() helper. Generates identifiers starting with
|
|
# 'prefix'.
|
|
|
|
out("{}_ID".format(prefix), index)
|
|
|
|
out("{}_READ_ONLY".format(prefix), 1 if partition_dev.read_only else 0)
|
|
|
|
for i, reg in enumerate(partition_dev.regs):
|
|
# Also add aliases that point to the first sector (TODO: get rid of the
|
|
# aliases?)
|
|
out("{}_OFFSET_{}".format(prefix, i), reg.addr,
|
|
aliases=["{}_OFFSET".format(prefix)] if i == 0 else [])
|
|
out("{}_SIZE_{}".format(prefix, i), reg.size,
|
|
aliases=["{}_SIZE".format(prefix)] if i == 0 else [])
|
|
|
|
controller = partition_dev.flash_controller
|
|
if controller.label is not None:
|
|
out_s("{}_DEV".format(prefix), controller.label)
|
|
|
|
|
|
def write_required_label(ident, dev):
|
|
# Helper function. Writes '#define <ident> "<label>"', where <label>
|
|
# is the value of the 'label' property from 'dev'. Does nothing if
|
|
# 'dev' is None.
|
|
#
|
|
# Errors out if 'dev' exists but has no label.
|
|
|
|
if not dev:
|
|
return
|
|
|
|
if dev.label is None:
|
|
err("missing 'label' property on {!r}".format(dev))
|
|
|
|
out_s(ident, dev.label)
|
|
|
|
|
|
def write_irqs(dev):
|
|
# Writes IRQ num and data for the interrupts in dev's 'interrupt' property
|
|
|
|
def irq_name_alias(irq, cell_name):
|
|
if not irq.name:
|
|
return None
|
|
|
|
alias = "IRQ_{}".format(str2ident(irq.name))
|
|
if cell_name != "irq":
|
|
alias += "_" + str2ident(cell_name)
|
|
return alias
|
|
|
|
for irq_i, irq in enumerate(dev.interrupts):
|
|
# We ignore the controller for now
|
|
for cell_name, cell_value in irq.specifier.items():
|
|
ident = "IRQ_{}".format(irq_i)
|
|
if cell_name != "irq":
|
|
ident += "_" + str2ident(cell_name)
|
|
|
|
out_dev(dev, ident, cell_value,
|
|
name_alias=irq_name_alias(irq, cell_name))
|
|
|
|
|
|
def write_gpios(dev):
|
|
# Writes GPIO controller data for the gpios in dev's 'gpios' property
|
|
|
|
for gpios in dev.gpios.values():
|
|
for gpio_i, gpio in enumerate(gpios):
|
|
write_gpio(dev, gpio, gpio_i if len(gpios) > 1 else None)
|
|
|
|
|
|
def write_gpio(dev, gpio, index=None):
|
|
# Writes GPIO controller & data for the GPIO object 'gpio'. If 'index' is
|
|
# not None, it is added as a suffix to identifiers.
|
|
|
|
ctrl_ident = "GPIOS_CONTROLLER"
|
|
if gpio.name:
|
|
ctrl_ident = str2ident(gpio.name) + "_" + ctrl_ident
|
|
if index is not None:
|
|
ctrl_ident += "_{}".format(index)
|
|
|
|
out_dev_s(dev, ctrl_ident, gpio.controller.label)
|
|
|
|
for cell, val in gpio.specifier.items():
|
|
cell_ident = "GPIOS_" + str2ident(cell)
|
|
if gpio.name:
|
|
cell_ident = str2ident(gpio.name) + "_" + cell_ident
|
|
if index is not None:
|
|
cell_ident += "_{}".format(index)
|
|
|
|
out_dev(dev, cell_ident, val)
|
|
|
|
|
|
def write_spi_dev(dev):
|
|
# Writes SPI device GPIO chip select data if there is any
|
|
|
|
cs_gpio = edtlib.spi_dev_cs_gpio(dev)
|
|
if cs_gpio is not None:
|
|
write_gpio(dev, cs_gpio)
|
|
|
|
|
|
def write_pwms(dev):
|
|
# Writes PWM controller and specifier info for the PWMs in dev's 'pwms'
|
|
# property
|
|
|
|
for pwm_i, pwm in enumerate(dev.pwms):
|
|
write_pwm(dev, pwm, pwm_i if len(dev.pwms) > 1 else None)
|
|
|
|
|
|
def write_pwm(dev, pwm, index=None):
|
|
# Writes PWM controller & data for the PWM object 'pwm'. If 'index' is
|
|
# not None, it is added as a suffix to identifiers.
|
|
|
|
if pwm.controller.label is not None:
|
|
ctrl_ident = "PWMS_CONTROLLER"
|
|
if index is not None:
|
|
ctrl_ident += "_{}".format(index)
|
|
out_dev_s(dev, ctrl_ident, pwm.controller.label)
|
|
|
|
for cell, val in pwm.specifier.items():
|
|
cell_ident = "PWMS_" + str2ident(cell)
|
|
if index is not None:
|
|
cell_ident += "_{}".format(index)
|
|
|
|
out_dev(dev, cell_ident, val)
|
|
|
|
|
|
def write_iochannels(dev):
|
|
# Writes IO channel controller and specifier info for the IO
|
|
# channels in dev's 'io-channels' property
|
|
|
|
for iochannel in dev.iochannels:
|
|
if iochannel.controller.label is not None:
|
|
out_dev_s(dev, "IO_CHANNELS_CONTROLLER", iochannel.controller.label)
|
|
|
|
for spec, val in iochannel.specifier.items():
|
|
out_dev(dev, "IO_CHANNELS_" + str2ident(spec), val)
|
|
|
|
|
|
def write_clocks(dev):
|
|
# Writes clock controller and specifier info for the clock in dev's 'clock'
|
|
# property
|
|
|
|
for clock_i, clock in enumerate(dev.clocks):
|
|
if clock.controller.label is not None:
|
|
out_dev_s(dev, "CLOCK_CONTROLLER", clock.controller.label)
|
|
|
|
if clock.frequency is not None:
|
|
out_dev(dev, "CLOCKS_CLOCK_FREQUENCY", clock.frequency)
|
|
|
|
for spec, val in clock.specifier.items():
|
|
if clock_i == 0:
|
|
clk_name_alias = "CLOCK_" + str2ident(spec)
|
|
else:
|
|
clk_name_alias = None
|
|
|
|
out_dev(dev, "CLOCK_{}_{}".format(str2ident(spec), clock_i), val,
|
|
name_alias=clk_name_alias)
|
|
|
|
|
|
def str2ident(s):
|
|
# Converts 's' to a form suitable for (part of) an identifier
|
|
|
|
return s.replace("-", "_") \
|
|
.replace(",", "_") \
|
|
.replace("@", "_") \
|
|
.replace("/", "_") \
|
|
.replace(".", "_") \
|
|
.replace("+", "PLUS") \
|
|
.upper()
|
|
|
|
|
|
def out_dev(dev, ident, val, name_alias=None):
|
|
# Writes an
|
|
#
|
|
# <device prefix>_<ident> = <val>
|
|
#
|
|
# assignment, along with a set of
|
|
#
|
|
# <device alias>_<ident>
|
|
#
|
|
# aliases, for each device alias. If 'name_alias' (a string) is passed,
|
|
# then these additional aliases are generated:
|
|
#
|
|
# <device prefix>_<name alias>
|
|
# <device alias>_<name alias> (for each device alias)
|
|
#
|
|
# 'name_alias' is used for reg-names and the like.
|
|
|
|
dev_prefix = dev_ident(dev)
|
|
|
|
aliases = [alias + "_" + ident for alias in dev_aliases(dev)]
|
|
if name_alias is not None:
|
|
aliases.append(dev_prefix + "_" + name_alias)
|
|
aliases += [alias + "_" + name_alias for alias in dev_aliases(dev)]
|
|
|
|
out(dev_prefix + "_" + ident, val, aliases)
|
|
|
|
|
|
def out_dev_s(dev, ident, s):
|
|
# Like out_dev(), but puts quotes around 's' and escapes any double quotes
|
|
# and backslashes within it
|
|
|
|
# \ must be escaped before " to avoid double escaping
|
|
out_dev(dev, ident, '"{}"'.format(escape(s)))
|
|
|
|
|
|
def out_s(ident, val):
|
|
# Like out(), but puts quotes around 's' and escapes any double quotes and
|
|
# backslashes within it
|
|
|
|
out(ident, '"{}"'.format(escape(val)))
|
|
|
|
|
|
def out(ident, val, aliases=()):
|
|
# Writes '#define <ident> <val>' to the header and '<ident>=<val>' to the
|
|
# the configuration file.
|
|
#
|
|
# Also writes any aliases listed in 'aliases' (an iterable). For the
|
|
# header, these look like '#define <alias> <ident>'. For the configuration
|
|
# file, the value is just repeated as '<alias>=<val>' for each alias.
|
|
|
|
print("#define DT_{:40} {}".format(ident, val), file=header_file)
|
|
print("DT_{}={}".format(ident, val), file=conf_file)
|
|
|
|
for alias in aliases:
|
|
if alias != ident:
|
|
print("#define DT_{:40} DT_{}".format(alias, ident),
|
|
file=header_file)
|
|
# For the configuration file, the value is just repeated for all
|
|
# the aliases
|
|
print("DT_{}={}".format(alias, val), file=conf_file)
|
|
|
|
|
|
def out_comment(s, blank_before=True):
|
|
# Writes 's' as a comment to the header and configuration file. 's' is
|
|
# allowed to have multiple lines. blank_before=True adds a blank line
|
|
# before the comment.
|
|
|
|
if blank_before:
|
|
print(file=header_file)
|
|
print(file=conf_file)
|
|
|
|
# Double-space in header for readability
|
|
print("/* " + s + " */", file=header_file)
|
|
print("\n".join("# " + line for line in s.splitlines()), file=conf_file)
|
|
|
|
|
|
def escape(s):
|
|
# Backslash-escapes any double quotes and backslashes in 's'
|
|
|
|
# \ must be escaped before " to avoid double escaping
|
|
return s.replace("\\", "\\\\").replace('"', '\\"')
|
|
|
|
|
|
def err(s):
|
|
raise Exception(s)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|