1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/stm32/dist/kconfig/gen_kconfig.py

158 lines
5.4 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright (C) 2020 Inria
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import os
import argparse
import xlrd
from jinja2 import FileSystemLoader, Environment
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
RIOTBASE = os.getenv(
"RIOTBASE", os.path.abspath(os.path.join(CURRENT_DIR, "../../../..")))
STM32_KCONFIG_DIR = os.path.join(RIOTBASE, "cpu/stm32/kconfigs")
STM32_VENDOR_DIR = os.path.join(RIOTBASE, "cpu/stm32/include/vendor/cmsis")
def parse_sheet(cpu_fam, sheets):
"""Parse the Excel sheet and return a dict."""
models = []
for sheet in sheets:
# Load the content of the xlsx sheet
work_book = xlrd.open_workbook(sheet)
sheet = work_book.sheet_by_name('ProductsList')
# Extract models from sheet
for rownum in range(sheet.nrows):
row = sheet.row_values(rownum)
if not row[0].startswith("STM32"):
continue
models.append(row[0].replace("-", "_"))
return sorted(models)
def parse_cpu_lines(cpu_fam):
"""Return the list of available CPU lines."""
headers_dir = os.path.join(STM32_VENDOR_DIR, cpu_fam, "Include")
cpu_lines = [
header[:-2].upper() for header in os.listdir(headers_dir)
if (
header.startswith("stm32") and
header != "stm32{}xx.h".format(cpu_fam)
)
]
return sorted(cpu_lines)
def _match(model, line):
"""Return True if a cpu model matches a cpu line, False otherwise."""
model = model.replace("_", "")
family_model = model[6:9]
family_model_letter1 = model[9]
family_model_letter2 = model[10] if len(model) >= 11 else None
family_model_letter3 = model[11] if len(model) == 12 else None
family_line = line[6:9]
family_line_letter1 = line[9]
family_line_letter2 = line[10] if len(line) >= 11 else None
family_line_letter3 = line[11] if len(line) == 12 else None
if family_line_letter1 == "X" and family_line_letter2 == "X":
letters_match = True
elif family_line_letter1 == "X":
if family_model_letter3 is not None or family_line_letter3 is not None:
letters_match = (
(family_line_letter2 == family_model_letter2) and
(family_line_letter3 == family_model_letter3)
)
else:
letters_match = family_line_letter2 == family_model_letter2
elif family_line_letter2 == "X":
letters_match = family_line_letter1 == family_model_letter1
else:
letters_match = False
return family_model == family_line and letters_match
def get_context(cpu_fam, models, lines):
"""Return a dict where keys are the models and values are the lines/fam."""
mapping = []
for model in models:
found_line = False
for line in lines:
if _match(model, line):
mapping.append(
{"model": model, "line": "CPU_LINE_{}".format(line)}
)
found_line = True
# if a model has no matching line, just match it to the upper cpu
# fam level
if not found_line:
mapping.append(
{"model": model, "line": "CPU_FAM_{}".format(cpu_fam)}
)
return {"models": mapping, "lines": lines, "fam": cpu_fam}
def generate_kconfig(kconfig, context, overwrite, verbose):
"""Generic kconfig file generator."""
loader = FileSystemLoader(searchpath=CURRENT_DIR)
env = Environment(
loader=loader, trim_blocks=False, lstrip_blocks=True,
keep_trailing_newline=True
)
template_file = os.path.join("Kconfig.{}.j2".format(kconfig))
env.globals.update(zip=zip)
template = env.get_template(template_file)
render = template.render(**context)
kconfig_dir = os.path.join(STM32_KCONFIG_DIR, context["fam"])
kconfig_file = os.path.join(kconfig_dir, "Kconfig.{}".format(kconfig))
# Create family Kconfig dir if it doesn't exist yet
if not os.path.exists(kconfig_dir):
os.makedirs(kconfig_dir)
if (not os.path.exists(kconfig_file) or
(os.path.exists(kconfig_file) and
overwrite is True and
kconfig == "models")):
with open(kconfig_file, "w") as f_dest:
f_dest.write(render)
if verbose:
print("{}:".format(os.path.basename(kconfig_file)))
print("-" * (len(os.path.basename(kconfig_file)) + 1) + "\n")
print(render)
def main(args):
"""Main function."""
models = parse_sheet(args.cpu_fam, args.sheets)
lines = parse_cpu_lines(args.cpu_fam)
context = get_context(args.cpu_fam, models, lines)
if args.verbose:
print("Generated kconfig files:\n")
for kconfig in ["lines", "models"]:
generate_kconfig(kconfig, context, args.overwrite, args.verbose)
PARSER = argparse.ArgumentParser()
PARSER.add_argument("cpu_fam",
help="STM32 CPU Family")
PARSER.add_argument("--sheets", "-s", nargs='+',
help="Excel sheet containing the list of products")
PARSER.add_argument("--overwrite", "-o", action="store_true",
help="Overwrite any existing Kconfig file")
PARSER.add_argument("--verbose", "-v", action="store_true",
help="Print generated file content")
if __name__ == "__main__":
main(PARSER.parse_args())