Skip to content

Commit a520f2c

Browse files
committed
[stm32variant] Aggregate generated variant if they are the same
To avoid having duplicated variants with all the same files. Signed-off-by: Frederic Pillon <frederic.pillon@st.com>
1 parent bd99f12 commit a520f2c

File tree

3 files changed

+209
-29
lines changed

3 files changed

+209
-29
lines changed

CI/utils/stm32variant.py

Lines changed: 205 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import sys
77
import textwrap
88
from argparse import RawTextHelpFormatter
9+
from collections import OrderedDict
910
from jinja2 import Environment, FileSystemLoader
1011
from pathlib import Path
1112
from xml.dom.minidom import parse, Node
@@ -64,6 +65,36 @@
6465
"""
6566

6667

68+
def rm_tree(pth: Path):
69+
if pth.exists():
70+
for child in pth.iterdir():
71+
if child.is_file():
72+
child.unlink()
73+
else:
74+
rm_tree(child)
75+
pth.rmdir()
76+
77+
78+
def update_file(filePath, compile_pattern, subs):
79+
with open(filePath, "r+", newline="\n") as file:
80+
fileContents = file.read()
81+
fileContents = compile_pattern.sub(subs, fileContents)
82+
file.seek(0)
83+
file.truncate()
84+
file.write(fileContents)
85+
86+
87+
# get xml family
88+
def get_mcu_family(mcu_file):
89+
xml_mcu = parse(str(mcu_file))
90+
mcu_node = xml_mcu.getElementsByTagName("Mcu")[0]
91+
mcu_family = mcu_node.attributes["Family"].value
92+
if mcu_family.endswith("+"):
93+
mcu_family = mcu_family[:-1]
94+
xml_mcu.unlink()
95+
return mcu_family
96+
97+
6798
# mcu file parsing
6899
def parse_mcu_file():
69100
global gpiofile
@@ -1274,7 +1305,7 @@ def print_boards_entry():
12741305
/ "CMSIS"
12751306
/ "Device"
12761307
/ "ST"
1277-
/ mcu_dir
1308+
/ mcu_family_dir
12781309
/ "Source"
12791310
/ "Templates"
12801311
/ "gcc"
@@ -1297,8 +1328,8 @@ def print_boards_entry():
12971328
boards_entry_template.render(
12981329
generic_list=generic_list,
12991330
gen_entry=gen_entry,
1300-
mcu_name=mcu_refname,
1301-
mcu_dir=mcu_dir,
1331+
mcu_dir=mcu_refname.replace("STM32", ""),
1332+
mcu_family_dir=mcu_family_dir,
13021333
mcu_ram=mcu_ram,
13031334
product_line=mcu_line,
13041335
)
@@ -1621,10 +1652,13 @@ def manage_repo():
16211652

16221653
# main
16231654
cur_dir = Path.cwd()
1655+
tmp_dir = cur_dir / "variants"
16241656
root_dir = cur_dir.parents[1]
16251657
system_path = root_dir / "system"
16261658
templates_dir = cur_dir / "templates"
1627-
mcu_dir = ""
1659+
mcu_family_dir = ""
1660+
filtered_family = ""
1661+
filtered_mcu_file = ""
16281662
periph_c_filename = "PeripheralPins.c"
16291663
pinvar_h_filename = "PinNamesVar.h"
16301664
config_filename = Path("variant_config.json")
@@ -1766,9 +1800,13 @@ def manage_repo():
17661800
print("\nCheck in " + dirMCU + " the correct name of this file")
17671801
print("\nYou may use double quotes for file containing special characters")
17681802
quit()
1769-
mcu_list.append(dirMCU / args.mcu)
1770-
else:
1771-
mcu_list = dirMCU.glob("STM32*.xml")
1803+
# Get the family of the desired mcu file
1804+
filtered_mcu_file = dirMCU / args.mcu
1805+
filtered_family = get_mcu_family(filtered_mcu_file)
1806+
if args.family:
1807+
filtered_family = args.family.upper()
1808+
# Get all xml files
1809+
mcu_list = sorted(dirMCU.glob("STM32*.xml"))
17721810

17731811
if args.list:
17741812
print("Available xml files description:")
@@ -1781,12 +1819,15 @@ def manage_repo():
17811819
loader=FileSystemLoader(str(templates_dir)), trim_blocks=True, lstrip_blocks=True
17821820
)
17831821

1822+
# Clean temporary dir
1823+
rm_tree(tmp_dir)
1824+
17841825
for mcu_file in mcu_list:
17851826
# Open input file
17861827
xml_mcu = parse(str(mcu_file))
17871828
parse_mcu_file()
17881829
# Generate only for one family
1789-
if args.family and args.family.upper() not in mcu_family:
1830+
if filtered_family and filtered_family not in mcu_family:
17901831
xml_mcu.unlink()
17911832
continue
17921833

@@ -1796,31 +1837,20 @@ def manage_repo():
17961837
quit()
17971838
xml_gpio = parse(str(dirIP / ("GPIO-" + gpiofile + "_Modes.xml")))
17981839

1799-
mcu_dir = mcu_family + "xx"
1800-
out_path = root_dir / "variants" / mcu_dir / mcu_file.stem
1801-
periph_c_filepath = out_path / periph_c_filename
1802-
pinvar_h_filepath = out_path / pinvar_h_filename
1803-
variant_cpp_filepath = out_path / variant_cpp_filename
1804-
variant_h_filepath = out_path / variant_h_filename
1805-
boards_entry_filepath = out_path / boards_entry_filename
1806-
out_path.mkdir(parents=True, exist_ok=True)
1840+
mcu_family_dir = mcu_family + "xx"
1841+
out_temp_path = tmp_dir / mcu_family_dir / mcu_file.stem.replace("STM32", "")
1842+
periph_c_filepath = out_temp_path / periph_c_filename
1843+
pinvar_h_filepath = out_temp_path / pinvar_h_filename
1844+
variant_cpp_filepath = out_temp_path / variant_cpp_filename
1845+
variant_h_filepath = out_temp_path / variant_h_filename
1846+
boards_entry_filepath = out_temp_path / boards_entry_filename
1847+
out_temp_path.mkdir(parents=True, exist_ok=True)
18071848

18081849
# open output file
1809-
# unlink(missing_ok=True) supported since python version 3.8
1810-
if periph_c_filepath.exists():
1811-
periph_c_filepath.unlink()
18121850
periph_c_file = open(periph_c_filepath, "w", newline="\n")
1813-
if pinvar_h_filepath.exists():
1814-
pinvar_h_filepath.unlink()
18151851
pinvar_h_file = open(pinvar_h_filepath, "w", newline="\n")
1816-
if variant_cpp_filepath.exists():
1817-
variant_cpp_filepath.unlink()
18181852
variant_cpp_file = open(variant_cpp_filepath, "w", newline="\n")
1819-
if variant_h_filepath.exists():
1820-
variant_h_filepath.unlink()
18211853
variant_h_file = open(variant_h_filepath, "w", newline="\n")
1822-
if boards_entry_filepath.exists():
1823-
boards_entry_filepath.unlink()
18241854
boards_entry_file = open(boards_entry_filepath, "w", newline="\n")
18251855

18261856
parse_pins()
@@ -1856,3 +1886,151 @@ def manage_repo():
18561886
boards_entry_file.close()
18571887
xml_mcu.unlink()
18581888
xml_gpio.unlink()
1889+
1890+
# Aggregating all genertaed files
1891+
print("Aggregating all generated files...")
1892+
periperalpins_regex = re.compile(r"\S+\.xml")
1893+
variant_regex = re.compile(r"defined\(ARDUINO_GENERIC_[^\s&|]*\)")
1894+
update_regex = re.compile(r"defined\(ARDUINO_GENERIC_.+\)")
1895+
board_entry_regex = re.compile(r"(Gen.+\..+variant=STM32.+xx/)\S+")
1896+
1897+
# Get mcu_family directory
1898+
out_temp_path = cur_dir / "variants"
1899+
mcu_families = sorted(out_temp_path.glob("STM32*/"))
1900+
# Compare per family
1901+
for mcu_family in mcu_families:
1902+
# Generate only for one family
1903+
if filtered_family and filtered_family not in mcu_family.name:
1904+
continue
1905+
out_family_path = root_dir / "variants" / mcu_family.name
1906+
# Get all mcu_dir
1907+
mcu_dirs = sorted(mcu_family.glob("*/"))
1908+
# Group mcu directories when only pexpressions and xml file name are differents
1909+
while mcu_dirs:
1910+
# Pop first item
1911+
group_mcu_dir = [mcu_dirs.pop(0)]
1912+
index = 0
1913+
mcu_dir = group_mcu_dir[0]
1914+
mcu_dir_files_list = [
1915+
mcu_dir / periph_c_filename,
1916+
mcu_dir / pinvar_h_filename,
1917+
mcu_dir / variant_cpp_filename,
1918+
mcu_dir / variant_h_filename,
1919+
]
1920+
periph_xml = []
1921+
variant_exp = []
1922+
# Compare the first directory to all other directories
1923+
while mcu_dirs and index < len(mcu_dirs):
1924+
# Compare all the variant file except the generic_boards.txt
1925+
mcu_dir2_files_list = [
1926+
mcu_dirs[index] / periph_c_filename,
1927+
mcu_dirs[index] / pinvar_h_filename,
1928+
mcu_dirs[index] / variant_cpp_filename,
1929+
mcu_dirs[index] / variant_h_filename,
1930+
]
1931+
for index2, fname in enumerate(mcu_dir_files_list):
1932+
with open(fname, "r") as f1:
1933+
with open(mcu_dir2_files_list[index2], "r") as f2:
1934+
diff = set(f1).symmetric_difference(f2)
1935+
diff.discard("\n")
1936+
if not diff or len(diff) == 2:
1937+
if index2 == 0:
1938+
for line in diff:
1939+
periph_xml += periperalpins_regex.findall(line)
1940+
elif index2 == 2:
1941+
for line in diff:
1942+
variant_exp += variant_regex.findall(line)
1943+
continue
1944+
else:
1945+
# Not the same directory compare with the next one
1946+
index += 1
1947+
break
1948+
# All files compared and matched
1949+
else:
1950+
# Matched files append to the group list
1951+
group_mcu_dir.append(mcu_dirs.pop(index))
1952+
1953+
group_mcu_dir.sort()
1954+
mcu_dir = group_mcu_dir.pop(0)
1955+
# Merge if needed
1956+
if group_mcu_dir:
1957+
new_mcu_dirname = mcu_dir.stem
1958+
board_entry = ""
1959+
mcu_dir_name = []
1960+
for dir_name in group_mcu_dir:
1961+
# Remove package information
1962+
mcu_dir_name.append(dir_name.stem)
1963+
1964+
if sum(new_mcu_dirname[:-2] in dname for dname in mcu_dir_name) > 1:
1965+
new_mcu_dirname = new_mcu_dirname[:-2]
1966+
# Concatenate names
1967+
for dir_name in group_mcu_dir:
1968+
nb = sum(dir_name.stem[:-2] in dname for dname in mcu_dir_name) == 1
1969+
# Only one occurence
1970+
if nb == 1:
1971+
new_mcu_dirname += "_" + dir_name.stem
1972+
else:
1973+
# Concatenate once without package information
1974+
if dir_name.stem[:-2] not in new_mcu_dirname:
1975+
new_mcu_dirname += "_" + dir_name.stem[:-2]
1976+
# Handle files
1977+
for dir_name in group_mcu_dir:
1978+
# Save board entry
1979+
with open(dir_name / boards_entry_filename) as fp:
1980+
for index, line in enumerate(fp):
1981+
# Skip first line
1982+
if index > 4:
1983+
board_entry += line
1984+
# Delete directory
1985+
for filepath in dir_name.glob("*.*"):
1986+
filepath.unlink()
1987+
dir_name.rmdir()
1988+
new_mcu_dir = out_temp_path / mcu_family.name / new_mcu_dirname
1989+
# Rename it
1990+
# With python 3.8 and above: mcu_dir = mcu_dir.replace(new_mcu_dir)
1991+
mcu_dir.replace(new_mcu_dir)
1992+
mcu_dir = new_mcu_dir
1993+
# Update files
1994+
periph_xml.sort()
1995+
periph_xml = list(OrderedDict.fromkeys(periph_xml))
1996+
new_line_c = periph_xml.pop(0)
1997+
for index, xml in enumerate(periph_xml, 1):
1998+
if index % 2 == 0:
1999+
new_line_c += "\n * {}".format(xml)
2000+
else:
2001+
new_line_c += ", {}".format(xml)
2002+
2003+
update_file(mcu_dir / periph_c_filename, periperalpins_regex, new_line_c)
2004+
2005+
variant_exp.sort()
2006+
variant_exp = list(OrderedDict.fromkeys(variant_exp))
2007+
new_line_c = variant_exp[0]
2008+
new_line_h = "{}".format(variant_exp.pop(0))
2009+
for index, pre in enumerate(variant_exp, 1):
2010+
if index % 2 == 0:
2011+
new_line_c += " ||\\\n {}".format(pre)
2012+
new_line_h += " &&\\\n !{}".format(pre)
2013+
else:
2014+
new_line_c += " || {}".format(pre)
2015+
new_line_h += " && !{}".format(pre)
2016+
update_file(mcu_dir / variant_cpp_filename, update_regex, new_line_c)
2017+
2018+
update_file(mcu_dir / variant_h_filename, update_regex, new_line_h)
2019+
2020+
# Appending to board_entry file
2021+
with open(mcu_dir / boards_entry_filename, "a", newline="\n") as fp:
2022+
fp.write(board_entry)
2023+
2024+
update_file(
2025+
mcu_dir / boards_entry_filename,
2026+
board_entry_regex,
2027+
rf"\g<1>{mcu_dir.name}",
2028+
)
2029+
2030+
# Move to variants/ folder
2031+
out_path = out_family_path / mcu_dir.stem
2032+
out_path.mkdir(parents=True, exist_ok=True)
2033+
for fname in mcu_dir.glob("*.*"):
2034+
fname.replace(out_path / fname.name)
2035+
# Clean temporary dir
2036+
rm_tree(tmp_dir)

CI/utils/templates/PeripheralPins.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* Automatically generated from {{mcu_file}}
1515
* CubeMX DB release {{db_release}}
1616
*/
17+
#if !defined(CUSTOM_PERIPHERAL_PINS)
1718
#include "Arduino.h"
1819
#include "PeripheralPins.h"
1920

@@ -73,3 +74,5 @@ WEAK const PinMap PinMap_{{periph.aname}}[] = {
7374
{% endfor %}
7475
{% endif %}
7576

77+
#endif /* !CUSTOM_PERIPHERAL_PINS */
78+

CI/utils/templates/boards_entry.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
{{gen_entry}}.menu.pnum.GENERIC_{{generic.board}}.upload.maximum_data_size={{mcu_ram}}
1111
{{gen_entry}}.menu.pnum.GENERIC_{{generic.board}}.build.board=GENERIC_{{generic.board}}
1212
{{gen_entry}}.menu.pnum.GENERIC_{{generic.board}}.build.product_line={{product_line}}
13-
{{gen_entry}}.menu.pnum.GENERIC_{{generic.board}}.build.mcu_name={{mcu_name}}
14-
{{gen_entry}}.menu.pnum.GENERIC_{{generic.board}}.build.variant={{mcu_dir}}/{{mcu_name}}
13+
{{gen_entry}}.menu.pnum.GENERIC_{{generic.board}}.build.variant={{mcu_family_dir}}/{{mcu_dir}}
1514

1615
{% endfor %}

0 commit comments

Comments
 (0)