Skip to content

Commit

Permalink
Add board_database module to handle board.json files and update vendo…
Browse files Browse the repository at this point in the history
…r readme

Signed-off-by: Jos Verlinde <[email protected]>

chore: formatting

Signed-off-by: Jos Verlinde <[email protected]>
  • Loading branch information
Josverl committed Jan 1, 2025
1 parent 18f8061 commit a119c8e
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 12 deletions.
5 changes: 2 additions & 3 deletions src/mpflash/mpflash/mpboard_id/add_boards.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
# and the #define MICROPY_HW_MCU_NAME "STM32F767xx"
RE_H_MICROPY_HW_BOARD_NAME = re.compile(r"#define\s+MICROPY_HW_BOARD_NAME\s+\"(.+)\"")
RE_H_MICROPY_HW_MCU_NAME = re.compile(r"#define\s+MICROPY_HW_MCU_NAME\s+\"(.+)\"")
# find in the mpconfigboard.cmake files

# find boards and variants in the mpconfigboard*.cmake files
RE_CMAKE_MICROPY_HW_BOARD_NAME = re.compile(
r"MICROPY_HW_BOARD_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\""
)
Expand Down Expand Up @@ -64,7 +63,7 @@ def boards_from_repo(mpy_path: Path, version: str, family: Optional[str] = None)
def boards_from_cmake(mpy_path: Path, version: str, family: str):
"""Get boards from the mpconfigboard.cmake files to the board_list."""
board_list = []
for path in mpy_path.glob("ports/**/mpconfigboard.cmake"):
for path in mpy_path.glob("ports/**/mpconfigboard*.cmake"):
board = path.parent.name
port = path.parent.parent.parent.name
with open(path, "r") as f:
Expand Down
21 changes: 13 additions & 8 deletions src/mpflash/mpflash/mpremoteboard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __init__(self, serialport: str = "", update: bool = False, *, location: str
self.arch = ""
self.mpy = ""
self.build = ""
self.location = location # USB location
self.location = location # USB location
self.toml = {}
if update:
self.get_mcu_info()
Expand Down Expand Up @@ -97,7 +97,9 @@ def connected_boards(bluetooth: bool = False, description: bool = False) -> List

if sys.platform == "win32":
# Windows sort of comports by number - but fallback to device name
return sorted(output, key=lambda x: int(x.split()[0][3:]) if x.split()[0][3:].isdigit() else x)
return sorted(
output, key=lambda x: int(x.split()[0][3:]) if x.split()[0][3:].isdigit() else x
)
# sort by device name
return sorted(output)

Expand All @@ -116,9 +118,10 @@ def get_mcu_info(self, timeout: int = 2):
["run", str(HERE / "mpy_fw_info.py")],
no_info=True,
timeout=timeout,
resume=True, # Avoid restarts
resume=False, # Avoid restarts
)
if rc != OK:
if rc:
log.debug(f"rc: {rc}, result: {result}")
raise ConnectionError(f"Failed to get mcu_info for {self.serialport}")
# Ok we have the info, now parse it
raw_info = result[0].strip()
Expand All @@ -134,7 +137,9 @@ def get_mcu_info(self, timeout: int = 2):
self.description = descr = info["board"]
pos = descr.rfind(" with")
short_descr = descr[:pos].strip() if pos != -1 else ""
if board_name := find_board_id_by_description(descr, short_descr, version=self.version):
if board_name := find_board_id_by_description(
descr, short_descr, version=self.version
):
self.board = board_name
else:
self.board = "UNKNOWN_BOARD"
Expand Down Expand Up @@ -174,7 +179,7 @@ def get_board_info_toml(self, timeout: int = 1):
except Exception as e:
log.error(f"Failed to parse board_info.toml: {e}")
else:
log.trace(f"Failed to read board_info.toml: {result}")
log.trace(f"Did not find a board_info.toml: {result}")

def disconnect(self) -> bool:
"""
Expand Down Expand Up @@ -202,7 +207,7 @@ def run_command(
log_errors: bool = True,
no_info: bool = False,
timeout: int = 60,
resume: bool = False,
resume: Optional[bool] = None,
**kwargs,
):
"""
Expand All @@ -223,7 +228,7 @@ def run_command(
if self.serialport:
prefix += ["connect", self.serialport]
# if connected add resume to keep state between commands
if self.connected or resume:
if (resume != False) and self.connected or resume:
prefix += ["resume"]
cmd = prefix + cmd
log.debug(" ".join(cmd))
Expand Down
187 changes: 187 additions & 0 deletions src/mpflash/mpflash/vendor/board_database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
"""
The micropython git repo contains many 'board.json' files.
This is an example:
ports/stm32/boards/PYBV11/board.json
{
"deploy": [
"../PYBV10/deploy.md"
],
"docs": "",
"features": [],
"images": [
"PYBv1_1.jpg",
"PYBv1_1-C.jpg",
"PYBv1_1-E.jpg"
],
"mcu": "stm32f4",
"product": "Pyboard v1.1",
"thumbnail": "",
"url": "https://store.micropython.org/product/PYBv1.1",
"variants": {
"DP": "Double-precision float",
"DP_THREAD": "Double precision float + Threads",
"NETWORK": "Wiznet 5200 Driver",
"THREAD": "Threading"
},
"vendor": "George Robotics"
}
This module implements `class Database` which reads all 'board.json' files and
provides a way to browse it's data.
"""

from __future__ import annotations

from pathlib import Path
import json
from dataclasses import dataclass, field
from glob import glob


@dataclass(order=True)
class Variant:
name: str
"""
Example: "DP_THREAD"
"""
text: str
"""
Example: "Double precision float + Threads"
"""
board: Board = field(repr=False)


@dataclass(order=True)
class Board:
name: str
"""
Example: "PYBV11"
"""
variants: list[Variant]
"""
List of variants available for this board.
Variants are sorted. May be an empty list if no variants are available.
Example key: "DP_THREAD"
"""
url: str
"""
Primary URL to link to this board.
"""
mcu: str
"""
Example: "stm32f4"
"""
product: str
"""
Example: "Pyboard v1.1"
"""
vendor: str
"""
Example: "George Robotics"
"""
images: list[str]
"""
Images of this board, stored in the micropython-media repository.
Example: ["PYBv1_1.jpg", "PYBv1_1-C.jpg", "PYBv1_1-E.jpg"]
"""
deploy: list[str]
"""
Files that explain how to deploy for this board:
Example: ["../PYBV10/deploy.md"]
"""
port: Port | None= field(default=None, compare=False)

@staticmethod
def factory(filename_json: Path) -> Board:
with filename_json.open() as f:
board_json = json.load(f)

board = Board(
name=filename_json.parent.name,
variants=[],
url=board_json["url"],
mcu=board_json["mcu"],
product=board_json["product"],
vendor=board_json["vendor"],
images=board_json["images"],
deploy=board_json["deploy"],
)
board.variants.extend(
sorted([Variant(*v, board) for v in board_json.get("variants", {}).items()])
)
return board


@dataclass(order=True)
class Port:
name: str
"""
Example: "stm32"
"""
boards: dict[str, Board] = field(default_factory=dict, repr=False)
"""
Example key: "PYBV11"
"""


@dataclass
class Database:
"""
This database contains all information retrieved from all 'board.json' files.
"""

mpy_root_directory: Path = field(repr=False)
port_filter: str = field(default="", repr=False)

ports: dict[str, Port] = field(default_factory=dict)
boards: dict[str, Board] = field(default_factory=dict)

def __post_init__(self) -> None:
mpy_dir = self.mpy_root_directory
# Take care to avoid using Path.glob! Performance was 15x slower.
for p in glob(f"{mpy_dir}/ports/**/boards/**/board.json"):
filename_json = Path(p)
port_name = filename_json.parent.parent.parent.name
if self.port_filter and self.port_filter != port_name:
continue

# Create a port
port = self.ports.get(port_name, None)
if port is None:
port = Port(port_name)
self.ports[port_name] = port

# Load board.json and attach it to the board
board = Board.factory(filename_json)
board.port = port

port.boards[board.name] = board
self.boards[board.name] = board

# Add 'special' ports, that don't have boards
# TODO(mst) Tidy up later (variant descriptions etc)
for special_port_name in ["unix", "webassembly", "windows"]:
if self.port_filter and self.port_filter != special_port_name:
continue
path = Path(mpy_dir, "ports", special_port_name)
variant_names = [
var.name for var in path.glob("variants/*") if var.is_dir()
]
board = Board(
special_port_name,
[],
f"https://github.com/micropython/micropython/blob/master/ports/{special_port_name}/README.md",
"",
"",
"",
[],
[],
)
board.variants = [Variant(v, "", board) for v in variant_names]
port = Port(special_port_name, {special_port_name: board})
board.port = port

self.ports[special_port_name] = port
self.boards[board.name] = board
11 changes: 10 additions & 1 deletion src/mpflash/mpflash/vendor/readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
These modules are vendored from the following repositories:

micropython/micropython
- https://github.com/micropython/micropython (MIT)
- dfu.py
- pydfy.py

- https://github.com/mattytrentini/mpbuild (MIT)
- board_database.py

- https://github.com/click-contrib/click-aliases (Public Domain)
- click_aliases.py (Robbin Bonthond)

0 comments on commit a119c8e

Please sign in to comment.