# Copyright (c) 2024 The Linux Foundation # SPDX-License-Identifier: Apache-2.0 import logging from collections import namedtuple from pathlib import Path import list_boards, list_hardware import yaml import zephyr_module from gen_devicetree_rest import VndLookup ZEPHYR_BASE = Path(__file__).parents[2] logger = logging.getLogger(__name__) def guess_file_from_patterns(directory, patterns, name, extensions): for pattern in patterns: for ext in extensions: matching_file = next(directory.glob(pattern.format(name=name, ext=ext)), None) if matching_file: return matching_file return None def guess_image(board_or_shield): img_exts = ["jpg", "jpeg", "webp", "png"] patterns = [ "**/{name}.{ext}", "**/*{name}*.{ext}", "**/*.{ext}", ] img_file = guess_file_from_patterns( board_or_shield.dir, patterns, board_or_shield.name, img_exts ) return (img_file.relative_to(ZEPHYR_BASE)).as_posix() if img_file else None def guess_doc_page(board_or_shield): patterns = [ "doc/index.{ext}", "**/{name}.{ext}", "**/*{name}*.{ext}", "**/*.{ext}", ] doc_file = guess_file_from_patterns( board_or_shield.dir, patterns, board_or_shield.name, ["rst"] ) return doc_file def get_catalog(): vnd_lookup = VndLookup(ZEPHYR_BASE / "dts/bindings/vendor-prefixes.txt", []) module_settings = { "arch_root": [ZEPHYR_BASE], "board_root": [ZEPHYR_BASE], "soc_root": [ZEPHYR_BASE], } for module in zephyr_module.parse_modules(ZEPHYR_BASE): for key in module_settings: root = module.meta.get("build", {}).get("settings", {}).get(key) if root is not None: module_settings[key].append(Path(module.project) / root) Args = namedtuple("args", ["arch_roots", "board_roots", "soc_roots", "board_dir", "board"]) args_find_boards = Args( arch_roots=module_settings["arch_root"], board_roots=module_settings["board_root"], soc_roots=module_settings["soc_root"], board_dir=ZEPHYR_BASE / "boards", board=None, ) boards = list_boards.find_v2_boards(args_find_boards) systems = list_hardware.find_v2_systems(args_find_boards) board_catalog = {} for board in boards: # We could use board.vendor but it is often incorrect. Instead, deduce vendor from # containing folder. There are a few exceptions, like the "native" and "others" folders # which we know are not actual vendors so treat them as such. for folder in board.dir.parents: if folder.name in ["native", "others"]: vendor = "others" break elif vnd_lookup.vnd2vendor.get(folder.name): vendor = folder.name break # Grab all the twister files for this board and use them to figure out all the archs it # supports. archs = set() pattern = f"{board.name}*.yaml" for twister_file in board.dir.glob(pattern): try: with open(twister_file, "r") as f: board_data = yaml.safe_load(f) archs.add(board_data.get("arch")) except Exception as e: logger.error(f"Error parsing twister file {twister_file}: {e}") socs = {soc.name for soc in board.socs} full_name = board.full_name or board.name doc_page = guess_doc_page(board) board_catalog[board.name] = { "name": board.name, "full_name": full_name, "doc_page": doc_page.relative_to(ZEPHYR_BASE).as_posix() if doc_page else None, "vendor": vendor, "archs": list(archs), "socs": list(socs), "image": guess_image(board), } socs_hierarchy = {} for soc in systems.get_socs(): family = soc.family or "" series = soc.series or "" socs_hierarchy.setdefault(family, {}).setdefault(series, []).append(soc.name) return { "boards": board_catalog, "vendors": {**vnd_lookup.vnd2vendor, "others": "Other/Unknown"}, "socs": socs_hierarchy, }