circuitpython/tools/board_summaries.py
2024-05-29 15:59:52 -07:00

198 lines
6.4 KiB
Python

# The MIT License (MIT)
#
# SPDX-FileCopyrightText: Copyright (c) 2024 Tim Chinowsky
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
import re
import sys
sys.path.append("../docs")
from shared_bindings_matrix import support_matrix_by_board
def module_incidence_matrix_csvs(support_matrix, rows=1000, present="1", absent=""):
all_modules = set()
for info in support_matrix.values():
all_modules.update(info["modules"])
all_modules = sorted(all_modules)
csvs = []
row = 0
for board, info in support_matrix.items():
if (row % rows) == 0:
csv = ["board,branded_name,mcu,flash,port,pins," + ",".join(all_modules) + "\n"]
chip_pin_set = set([chip_pin for _, chip_pin in info["pins"]])
n_chip_pins = len(chip_pin_set)
module_incidence = [present if m in info["modules"] else absent for m in all_modules]
line = (
f"{board},{info.get('branded_name')},{info.get('mcu')},"
+ f"{info.get('flash')},{info.get('port')},{n_chip_pins},"
+ ",".join(module_incidence)
+ "\n"
)
csv.append(line)
row += 1
if (row % rows) == 0:
csvs.append(csv)
if (row % rows) != 0:
csvs.append(csv)
return csvs
def frozen_incidence_matrix_csvs(support_matrix, rows=1000, present="1", absent=""):
all_frozen = set()
for info in support_matrix.values():
frozen = info["frozen_libraries"]
frozen = [f[0] if type(f) == tuple else f for f in frozen]
all_frozen.update(frozen)
all_frozen = sorted(all_frozen)
csvs = []
row = 0
for board, info in support_matrix.items():
if (row % rows) == 0:
csv = ["board,branded_name,mcu,flash,port,pins," + ",".join(all_frozen) + "\n"]
# remove urls if present
frozen = info["frozen_libraries"]
chip_pin_set = set([chip_pin for _, chip_pin in info["pins"]])
n_chip_pins = len(chip_pin_set)
frozen = [f[0] if type(f) == tuple else f for f in frozen]
frozen_incidence = [present if f in frozen else absent for f in all_frozen]
line = (
f"{board},{info.get('branded_name')},{info.get('mcu')},"
+ f"{info.get('flash')},{info.get('port')},{n_chip_pins},"
+ ",".join(frozen_incidence)
+ "\n"
)
csv.append(line)
row += 1
if (row % rows) == 0:
csvs.append(csv)
if (row % rows) != 0:
csvs.append(csv)
return csvs
def summarize_pins(pins):
"""Given a list of pin names, generate a compact string
like "BUTTON, LED1:4, PA0:10;13:14, PB5:7, SCL, SDA"
summarizing the names in the list"""
pin_prefixes = {}
for p in pins:
match = re.match(r"^(.*?)(\d*)$", p)
if match:
prefix = match.group(1)
n_str = match.group(2)
else:
raise ValueError("Cannot parse pin name")
if prefix in pin_prefixes:
pin_prefixes[prefix].add(n_str)
else:
pin_prefixes[prefix] = {n_str}
return ", ".join(
[f"{prefix}{span_string(pin_prefixes[prefix])}" for prefix in sorted(pin_prefixes.keys())]
)
def int_or_zero(s):
try:
return int(s)
except ValueError:
return 0
def span_string(number_strs):
int_strs = sorted([(int_or_zero(s), s) for s in number_strs])
last_i = None
last_s = None
run = False
for i, s in int_strs:
if last_i is None:
out = s
elif i != last_i + 1:
if run:
out += f":{last_s};{s}"
else:
out += f";{s}"
run = False
else:
run = True
last_i = i
last_s = s
if run:
out += f":{s}"
return out
def board_pins_matrix_csvs(support_matrix, rows=1000):
csvs = []
row = 0
for board, info in support_matrix.items():
if (row % rows) == 0:
csv = [
"board,branded_name,mcu,flash,port,n_board_pins,"
"board_pins,n_chip_pins,chip_pins\n"
]
board_pins = [board_pin for board_pin, _ in info["pins"]]
chip_pins = [chip_pin for _, chip_pin in info["pins"]]
line = (
f"{board},{info.get('branded_name')},{info.get('mcu')},"
+ f"{info.get('flash')},{info.get('port')},"
+ str(len(set(board_pins)))
+ ',"'
+ summarize_pins(board_pins)
+ '",'
+ str(len(set(chip_pins)))
+ ',"'
+ summarize_pins(chip_pins)
+ '"\n'
)
csv.append(line)
row += 1
if (row % rows) == 0:
csvs.append(csv)
if (row % rows) != 0:
csvs.append(csv)
return csvs
def write_csvs(rows=1000, present="1", absent="0"):
print("generating csvs...")
s = support_matrix_by_board(
use_branded_name=False, add_port=True, add_chips=True, add_pins=True, add_branded_name=True
)
csvs = {
"modules": module_incidence_matrix_csvs(s, rows=rows, present=present, absent=absent),
"frozen": frozen_incidence_matrix_csvs(s, rows=rows, present=present, absent=absent),
"pins": board_pins_matrix_csvs(s, rows=rows),
}
for key in csvs:
for i in range(len(csvs[key])):
filename = f"{key}_{i}.csv"
print(f"writing {filename}")
with open(filename, "w") as f:
f.writelines(csvs[key][i])
if __name__ == "__main__":
write_csvs()