# Copyright (c) Kuba Szczodrzyński 2022-05-31. import re import sys from os.path import dirname, join from typing import Dict, List, Set, Tuple sys.path.append(join(dirname(__file__), "..")) from tools.util.fileio import readjson, readtext from tools.util.markdown import Markdown from tools.util.obj import get, sizeof from tools.util.platform import ( get_board_list, get_board_manifest, get_families, get_family, ) def load_boards() -> Dict[str, dict]: return {board: get_board_manifest(board) for board in get_board_list()} def load_chip_type_h() -> str: code = readtext( join( dirname(__file__), "..", "arduino", "libretuya", "core", "ChipType.h", ) ) code = re.sub(r"//.+", "", code) code = re.sub(r"/\*.+\*/", "", code) return code def check_mcus(boards: List[Tuple[str, dict]]) -> bool: for board_name, board in boards: # check if all boards' MCUs are defined in families.json family_name: str = get(board, "build.family") mcu_name: str = get(board, "build.mcu") family = get_family(short_name=family_name) if not family: print(f"Family '{family_name}' of board '{board_name}' does not exist") return False mcus = [mcu.lower() for mcu in family.mcus] if mcu_name not in mcus: print( f"MCU '{mcu_name}' of board '{board_name}' is not defined for family '{family_name}'" ) return False return True def get_family_mcus() -> Set[str]: out = [] for family in get_families(): out += family.mcus return set(out) def get_family_names() -> Set[str]: return set(family.short_name for family in get_families()) def get_board_mcus(boards: List[Tuple[str, dict]]) -> Set[str]: out = set() for _, board in boards: mcu_name: str = get(board, "build.mcu") out.add(mcu_name.upper()) return out def get_enum_keys(code: str, name: str) -> Set[str]: code = code.partition(f"enum {name}")[2] code = code.partition(";")[0] code = code.strip().strip("{}").strip() code = [line.strip().strip(",").strip() for line in code.split("\n")] code = filter(None, code) return set(line.partition(" ")[0].strip() for line in code) def get_enum_mcus(code: str) -> Set[str]: return get_enum_keys(code, "ChipType") def get_enum_families(code: str) -> Set[str]: return set(family[2:] for family in get_enum_keys(code, "ChipFamily")) def board_sort(tpl): return ( get(tpl[1], "vendor"), get(tpl[1], "build.mcu"), get(tpl[1], "mcu"), tpl[0], ) def write_chips(mcus: List[str]): md = Markdown(dirname(__file__), "supported_chips") md.add_list(*mcus) md.write() def write_boards(boards: List[Tuple[str, dict]]): md = Markdown(dirname(__file__), "supported_boards") header = [ "Name", "MCU", "Flash", "RAM", "Pins*", "Wi-Fi", "BLE", "ZigBee", "Family name", ] rows = [] vendor_prev = "" for board_name, board in boards: family = get_family(short_name=get(board, "build.family")) # add board vendor as a row vendor = get(board, "vendor") if vendor_prev != vendor: rows.append([f"**{vendor}**"]) vendor_prev = vendor # count total pin count & IO count pins = "-" pinout: Dict[str, dict] = get(board, "pcb.pinout") if pinout: pinout = [pin for name, pin in pinout.items() if name.isnumeric()] pins_total = len(pinout) pins_io = sum(1 for pin in pinout if "ARD" in pin) pins = f"{pins_total} ({pins_io} I/O)" # format row values board_url = f"[{board_name.upper()}](../boards/{board_name}/README.md)" row = [ board_url, get(board, "build.mcu").upper(), sizeof(get(board, "upload.flash_size")), sizeof(get(board, "upload.maximum_ram_size")), pins, "✔️" if "wifi" in get(board, "connectivity") else "❌", "✔️" if "ble" in get(board, "connectivity") else "❌", "✔️" if "zigbee" in get(board, "connectivity") else "❌", f"`{family.name}`", ] rows.append(row) md.add_table(header, *rows) md.write() def write_unsupported_boards( series: Dict[str, Dict[str, dict]], name: str, supported: List[str], ): md = Markdown(dirname(__file__), name) header = [ "Name", "MCU", "Flash", "RAM", "Pins", "Wi-Fi", "BLE", "ZigBee", ] rows = [] for series_name in sorted(series): series_rows = [] series_rows.append([f"**{series_name.upper()} Series**"]) boards = series[series_name] for board_name, board in sorted(boards.items(), key=board_sort): if board_name in supported: continue row = [ board_name.upper(), board["mcu"].upper(), sizeof(board["flash"]), sizeof(board["ram"]), str(board["pins_total"]), "✔️" if "wifi" in board["connectivity"] else "❌", "✔️" if "ble" in board["connectivity"] else "❌", "✔️" if "zigbee" in board["connectivity"] else "❌", ] series_rows.append(row) if series_rows: rows += series_rows md.add_table(header, *rows) md.write() def write_families(): md = Markdown(dirname(__file__), "supported_families") header = [ "Title", "Name (parent)", "Code", "Short name & ID", "Arduino Core", "Source SDK", ] rows = [] for family in get_families(): row = [ # Title "[{}]({})".format( family.description, family.url, family.name, ) if family.name else family.description, # Name (parent) f"`{family.name or '-'}`" if not family.parent else f"`{family.name}` (`{family.parent}`)", # Code f"`{family.code or '-'}`" if not family.parent else f"`{family.code}` (`{family.parent_code}`)", # Short name & ID "`{}` (0x{:X})".format( family.short_name, family.id, ), # Arduino Core "✔️" if family.has_arduino_core else "❌", # Source SDK "`{}` ([{}]({}))".format( family.framework, family.sdk_name, family.sdk, ) if family.name else "-", ] rows.append(row) md.add_table(header, *rows) md.write() def write_boards_list(boards: List[Tuple[str, dict]]): md = Markdown(dirname(__file__), join("..", "boards", "SUMMARY")) items = [] for board_name, board in boards: title = get(board, "name") items.append(f"[{title}](../boards/{board_name}/README.md)") md.add_list(*items) md.write() if __name__ == "__main__": boards = load_boards() boards = sorted(boards.items(), key=board_sort) code = load_chip_type_h() errors = False families_json = get_family_names() families_enum = get_enum_families(code) if families_json != families_enum: print(f"Inconsistent JSON families vs ChipType.h families:") print("- Missing in JSON: " + ", ".join(families_enum - families_json)) print("- Missing in enum: " + ", ".join(families_json - families_enum)) errors = True mcus_json = get_family_mcus() mcus_enum = get_enum_mcus(code) mcus_boards = get_board_mcus(boards) if mcus_json != mcus_enum: print(f"Inconsistent JSON family MCUs vs ChipType.h MCUs:") print("- Missing in JSON: " + ", ".join(mcus_enum - mcus_json)) print("- Missing in enum: " + ", ".join(mcus_json - mcus_enum)) # this is not considered an error (for now) # errors = True if not check_mcus(boards): errors = True if errors: exit(1) write_chips(sorted(mcus_boards.union(mcus_json))) write_boards(boards) write_boards_list(boards) write_families() boards_all = [ "boards_tuya_all", ] for name in boards_all: file = join(dirname(__file__), f"{name}.json") data = readjson(file) write_unsupported_boards( series=data, name=f"unsupported_{name}", supported=[tpl[0] for tpl in boards], )