6
6
import sys
7
7
import textwrap
8
8
from argparse import RawTextHelpFormatter
9
+ from collections import OrderedDict
9
10
from jinja2 import Environment , FileSystemLoader
10
11
from pathlib import Path
11
12
from xml .dom .minidom import parse , Node
64
65
"""
65
66
66
67
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
+
67
98
# mcu file parsing
68
99
def parse_mcu_file ():
69
100
global gpiofile
@@ -1274,7 +1305,7 @@ def print_boards_entry():
1274
1305
/ "CMSIS"
1275
1306
/ "Device"
1276
1307
/ "ST"
1277
- / mcu_dir
1308
+ / mcu_family_dir
1278
1309
/ "Source"
1279
1310
/ "Templates"
1280
1311
/ "gcc"
@@ -1297,8 +1328,8 @@ def print_boards_entry():
1297
1328
boards_entry_template .render (
1298
1329
generic_list = generic_list ,
1299
1330
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 ,
1302
1333
mcu_ram = mcu_ram ,
1303
1334
product_line = mcu_line ,
1304
1335
)
@@ -1621,10 +1652,13 @@ def manage_repo():
1621
1652
1622
1653
# main
1623
1654
cur_dir = Path .cwd ()
1655
+ tmp_dir = cur_dir / "variants"
1624
1656
root_dir = cur_dir .parents [1 ]
1625
1657
system_path = root_dir / "system"
1626
1658
templates_dir = cur_dir / "templates"
1627
- mcu_dir = ""
1659
+ mcu_family_dir = ""
1660
+ filtered_family = ""
1661
+ filtered_mcu_file = ""
1628
1662
periph_c_filename = "PeripheralPins.c"
1629
1663
pinvar_h_filename = "PinNamesVar.h"
1630
1664
config_filename = Path ("variant_config.json" )
@@ -1766,9 +1800,13 @@ def manage_repo():
1766
1800
print ("\n Check in " + dirMCU + " the correct name of this file" )
1767
1801
print ("\n You may use double quotes for file containing special characters" )
1768
1802
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" ))
1772
1810
1773
1811
if args .list :
1774
1812
print ("Available xml files description:" )
@@ -1781,12 +1819,15 @@ def manage_repo():
1781
1819
loader = FileSystemLoader (str (templates_dir )), trim_blocks = True , lstrip_blocks = True
1782
1820
)
1783
1821
1822
+ # Clean temporary dir
1823
+ rm_tree (tmp_dir )
1824
+
1784
1825
for mcu_file in mcu_list :
1785
1826
# Open input file
1786
1827
xml_mcu = parse (str (mcu_file ))
1787
1828
parse_mcu_file ()
1788
1829
# 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 :
1790
1831
xml_mcu .unlink ()
1791
1832
continue
1792
1833
@@ -1796,31 +1837,20 @@ def manage_repo():
1796
1837
quit ()
1797
1838
xml_gpio = parse (str (dirIP / ("GPIO-" + gpiofile + "_Modes.xml" )))
1798
1839
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 )
1807
1848
1808
1849
# 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 ()
1812
1850
periph_c_file = open (periph_c_filepath , "w" , newline = "\n " )
1813
- if pinvar_h_filepath .exists ():
1814
- pinvar_h_filepath .unlink ()
1815
1851
pinvar_h_file = open (pinvar_h_filepath , "w" , newline = "\n " )
1816
- if variant_cpp_filepath .exists ():
1817
- variant_cpp_filepath .unlink ()
1818
1852
variant_cpp_file = open (variant_cpp_filepath , "w" , newline = "\n " )
1819
- if variant_h_filepath .exists ():
1820
- variant_h_filepath .unlink ()
1821
1853
variant_h_file = open (variant_h_filepath , "w" , newline = "\n " )
1822
- if boards_entry_filepath .exists ():
1823
- boards_entry_filepath .unlink ()
1824
1854
boards_entry_file = open (boards_entry_filepath , "w" , newline = "\n " )
1825
1855
1826
1856
parse_pins ()
@@ -1856,3 +1886,151 @@ def manage_repo():
1856
1886
boards_entry_file .close ()
1857
1887
xml_mcu .unlink ()
1858
1888
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 )
0 commit comments