mpflash 1.24.7__py3-none-any.whl → 1.25.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mpflash/ask_input.py +7 -7
- mpflash/basicgit.py +26 -59
- mpflash/bootloader/__init__.py +0 -2
- mpflash/bootloader/detect.py +1 -2
- mpflash/bootloader/manual.py +0 -1
- mpflash/bootloader/touch1200.py +2 -2
- mpflash/cli_flash.py +28 -5
- mpflash/cli_group.py +1 -0
- mpflash/cli_list.py +7 -8
- mpflash/cli_main.py +2 -2
- mpflash/common.py +6 -14
- mpflash/config.py +30 -6
- mpflash/connected.py +6 -14
- mpflash/db/boards.py +63 -0
- mpflash/db/downloads.py +87 -0
- mpflash/download/__init__.py +221 -0
- mpflash/download/from_web.py +204 -0
- mpflash/downloaded.py +9 -34
- mpflash/flash/__init__.py +33 -18
- mpflash/flash/esp.py +39 -8
- mpflash/flash/uf2/linux.py +4 -9
- mpflash/flash/uf2/macos.py +1 -1
- mpflash/flash/uf2/windows.py +1 -1
- mpflash/flash/worklist.py +10 -5
- mpflash/list.py +17 -6
- mpflash/logger.py +1 -3
- mpflash/mpboard_id/__init__.py +6 -87
- mpflash/mpboard_id/add_boards.py +3 -8
- mpflash/mpboard_id/board.py +5 -2
- mpflash/mpboard_id/board_id.py +67 -7
- mpflash/mpboard_id/board_info.json +30974 -0
- mpflash/mpboard_id/board_info.zip +0 -0
- mpflash/mpboard_id/known.py +108 -0
- mpflash/mpboard_id/store.py +2 -3
- mpflash/mpremoteboard/__init__.py +85 -17
- mpflash/mpremoteboard/mpy_fw_info.py +23 -22
- mpflash/py.typed +0 -0
- mpflash/vendor/board_database.py +86 -1
- mpflash/vendor/click_aliases.py +64 -0
- mpflash/vendor/dfu.py +2 -8
- mpflash/vendor/pydfu.py +3 -14
- mpflash/versions.py +16 -6
- {mpflash-1.24.7.dist-info → mpflash-1.25.0.dist-info}/METADATA +71 -13
- mpflash-1.25.0.dist-info/RECORD +62 -0
- {mpflash-1.24.7.dist-info → mpflash-1.25.0.dist-info}/WHEEL +1 -1
- mpflash/download.py +0 -364
- mpflash-1.24.7.dist-info/RECORD +0 -56
- {mpflash-1.24.7.dist-info → mpflash-1.25.0.dist-info}/LICENSE +0 -0
- {mpflash-1.24.7.dist-info → mpflash-1.25.0.dist-info}/entry_points.txt +0 -0
mpflash/flash/esp.py
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
from pathlib import Path
|
8
|
-
from typing import List, Optional
|
8
|
+
from typing import List, Literal, Optional
|
9
9
|
|
10
10
|
import esptool
|
11
11
|
from loguru import logger as log
|
@@ -13,8 +13,16 @@ from loguru import logger as log
|
|
13
13
|
from mpflash.mpboard_id import find_known_board
|
14
14
|
from mpflash.mpremoteboard import MPRemoteBoard
|
15
15
|
|
16
|
+
FlashMode = Literal["keep", "qio", "qout", "dio", "dout"]
|
16
17
|
|
17
|
-
def flash_esp(
|
18
|
+
def flash_esp(
|
19
|
+
mcu: MPRemoteBoard,
|
20
|
+
fw_file: Path,
|
21
|
+
*,
|
22
|
+
erase: bool = True,
|
23
|
+
flash_mode: FlashMode = "keep", # keep, qio, qout, dio, dout
|
24
|
+
flash_size: str = "detect",
|
25
|
+
) -> Optional[MPRemoteBoard]:
|
18
26
|
if mcu.port not in ["esp32", "esp8266"] or mcu.board.startswith("ARDUINO_"):
|
19
27
|
log.error(f"esptool not supported for {mcu.port} {mcu.board} on {mcu.serialport}")
|
20
28
|
return None
|
@@ -25,26 +33,49 @@ def flash_esp(mcu: MPRemoteBoard, fw_file: Path, *, erase: bool = True) -> Optio
|
|
25
33
|
mcu.cpu = find_known_board(mcu.board).cpu
|
26
34
|
|
27
35
|
cmds: List[List[str]] = []
|
28
|
-
if erase:
|
29
|
-
cmds.append(f"esptool --chip {mcu.cpu} --port {mcu.serialport} erase_flash".split())
|
30
36
|
|
37
|
+
chip = "auto"
|
38
|
+
start_addr = "0x0"
|
31
39
|
if mcu.cpu.upper().startswith("ESP32"):
|
40
|
+
start_addr = "0x0"
|
41
|
+
|
32
42
|
baud_rate = str(921_600)
|
33
|
-
if mcu.cpu.upper()
|
43
|
+
if mcu.cpu.upper() == "ESP32":
|
44
|
+
start_addr = "0x1000"
|
45
|
+
chip = "esp32"
|
46
|
+
elif "C2" in mcu.cpu.upper():
|
47
|
+
start_addr = "0x1000"
|
48
|
+
chip = "esp32c2"
|
49
|
+
elif "S2" in mcu.cpu.upper():
|
34
50
|
start_addr = "0x1000"
|
35
|
-
|
51
|
+
chip = "esp32s2"
|
52
|
+
baud_rate = str(460_800)
|
53
|
+
elif "S3" in mcu.cpu.upper():
|
36
54
|
start_addr = "0x0"
|
55
|
+
chip = "esp32s3"
|
56
|
+
elif "C3" in mcu.cpu.upper():
|
57
|
+
start_addr = "0x0"
|
58
|
+
chip = "esp32c3"
|
59
|
+
elif "C6" in mcu.cpu.upper():
|
60
|
+
start_addr = "0x0"
|
61
|
+
chip = "esp32c6"
|
62
|
+
baud_rate = str(460_800)
|
63
|
+
|
37
64
|
cmds.append(
|
38
|
-
f"esptool --chip {
|
65
|
+
f"esptool --chip {chip} --port {mcu.serialport} -b {baud_rate} write_flash --flash_mode {flash_mode} --flash_size {flash_size} --compress {start_addr}".split()
|
39
66
|
+ [str(fw_file)]
|
40
67
|
)
|
41
68
|
elif mcu.cpu.upper() == "ESP8266":
|
42
69
|
baud_rate = str(460_800)
|
43
70
|
start_addr = "0x0"
|
71
|
+
chip = "esp8266"
|
44
72
|
cmds.append(
|
45
|
-
f"esptool --chip {
|
73
|
+
f"esptool --chip {chip} --port {mcu.serialport} -b {baud_rate} write_flash --flash_mode {flash_mode} --flash_size=detect {start_addr}".split()
|
46
74
|
+ [str(fw_file)]
|
47
75
|
)
|
76
|
+
# now that we have the chip, we can do the erare properly
|
77
|
+
if erase:
|
78
|
+
cmds.insert(0, f"esptool --chip {chip} --port {mcu.serialport} erase_flash".split())
|
48
79
|
try:
|
49
80
|
for cmd in cmds:
|
50
81
|
log.info(f"Running {' '.join(cmd)} ")
|
mpflash/flash/uf2/linux.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
"""
|
1
|
+
"""Flashing UF2 based MCU on Linux"""
|
2
2
|
|
3
3
|
# sourcery skip: snake-case-functions
|
4
4
|
from __future__ import annotations
|
@@ -42,10 +42,7 @@ def get_uf2_drives():
|
|
42
42
|
uf2.mountpoint = uf2_part["mountpoint"]
|
43
43
|
yield uf2
|
44
44
|
elif disk["type"] == "disk" and disk.get("children") and len(disk.get("children")) > 0:
|
45
|
-
if (
|
46
|
-
disk.get("children")[0]["type"] == "part"
|
47
|
-
and disk.get("children")[0]["fstype"] == "vfat"
|
48
|
-
):
|
45
|
+
if disk.get("children")[0]["type"] == "part" and disk.get("children")[0]["fstype"] == "vfat":
|
49
46
|
uf2_part = disk.get("children")[0]
|
50
47
|
# print( json.dumps(uf2_part, indent=4))
|
51
48
|
uf2 = UF2Disk()
|
@@ -69,9 +66,7 @@ def pmount(disk: UF2Disk):
|
|
69
66
|
# drive is always vfat - so specify to have quicker results
|
70
67
|
subprocess.run(["pmount", "-t", "vfat", disk.device_path, disk.mountpoint])
|
71
68
|
except FileNotFoundError:
|
72
|
-
log.error(
|
73
|
-
"pmount not found, please install it using 'sudo apt install pmount', and add this user to the plugdev group."
|
74
|
-
)
|
69
|
+
log.error("pmount not found, please install it using 'sudo apt install pmount', and add this user to the plugdev group.")
|
75
70
|
return
|
76
71
|
log.debug(f"Mounted {disk.label} at {disk.mountpoint}")
|
77
72
|
glb_dismount_me.append(disk)
|
@@ -89,7 +84,7 @@ def pumount(disk: UF2Disk):
|
|
89
84
|
if disk.mountpoint:
|
90
85
|
subprocess.run(["pumount", disk.mountpoint]) # ), f"/media/{disk.label}"])
|
91
86
|
log.info(f"Unmounted {disk.label} from {disk.mountpoint}")
|
92
|
-
disk.mountpoint =
|
87
|
+
disk.mountpoint = ""
|
93
88
|
else:
|
94
89
|
log.warning(f"{disk.label} already dismounted")
|
95
90
|
|
mpflash/flash/uf2/macos.py
CHANGED
mpflash/flash/uf2/windows.py
CHANGED
@@ -12,7 +12,7 @@ import psutil
|
|
12
12
|
from rich.progress import track
|
13
13
|
|
14
14
|
|
15
|
-
def wait_for_UF2_windows(board_id: str, s_max: int = 10)-> Optional[Path]:
|
15
|
+
def wait_for_UF2_windows(board_id: str, s_max: int = 10) -> Optional[Path]:
|
16
16
|
"""Wait for the MCU to mount as a drive"""
|
17
17
|
if s_max < 1:
|
18
18
|
s_max = 10
|
mpflash/flash/worklist.py
CHANGED
@@ -43,8 +43,8 @@ def auto_update(
|
|
43
43
|
log.warning(f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware")
|
44
44
|
continue
|
45
45
|
board_firmwares = find_downloaded_firmware(
|
46
|
-
|
47
|
-
board_id=mcu.board,
|
46
|
+
db_path=fw_folder,
|
47
|
+
board_id=mcu.board if not mcu.variant else f"{mcu.board}-{mcu.variant}",
|
48
48
|
version=target_version,
|
49
49
|
port=mcu.port,
|
50
50
|
selector=selector,
|
@@ -91,11 +91,11 @@ def manual_worklist(
|
|
91
91
|
# need the CPU type for the esptool
|
92
92
|
mcu.cpu = info.cpu
|
93
93
|
except (LookupError, MPFlashError) as e:
|
94
|
-
log.error(f"Board {board_id} not found in
|
94
|
+
log.error(f"Board {board_id} not found in board database")
|
95
95
|
log.exception(e)
|
96
96
|
return []
|
97
97
|
mcu.board = board_id
|
98
|
-
firmwares = find_downloaded_firmware(
|
98
|
+
firmwares = find_downloaded_firmware(db_path=fw_folder, board_id=board_id, version=version, port=mcu.port)
|
99
99
|
if not firmwares:
|
100
100
|
log.error(f"No firmware found for {mcu.port} {board_id} version {version}")
|
101
101
|
return []
|
@@ -127,7 +127,12 @@ def single_auto_worklist(
|
|
127
127
|
|
128
128
|
|
129
129
|
def full_auto_worklist(
|
130
|
-
all_boards: List[MPRemoteBoard],
|
130
|
+
all_boards: List[MPRemoteBoard],
|
131
|
+
*,
|
132
|
+
include: List[str],
|
133
|
+
ignore: List[str],
|
134
|
+
version: str,
|
135
|
+
fw_folder: Path,
|
131
136
|
) -> WorkList:
|
132
137
|
"""
|
133
138
|
Create a worklist for all connected micropython boards based on the information retrieved from the board.
|
mpflash/list.py
CHANGED
@@ -14,13 +14,16 @@ def show_mcus(
|
|
14
14
|
conn_mcus: List[MPRemoteBoard],
|
15
15
|
title: str = "Connected boards",
|
16
16
|
refresh: bool = True,
|
17
|
+
*,
|
18
|
+
title_style="magenta",
|
19
|
+
header_style="bold magenta",
|
17
20
|
):
|
18
|
-
console.print(mcu_table(conn_mcus, title, refresh))
|
21
|
+
console.print(mcu_table(conn_mcus, title, refresh, title_style=title_style, header_style=header_style))
|
19
22
|
|
20
23
|
|
21
24
|
def abbrv_family(family: str, is_wide: bool) -> str:
|
22
25
|
if not is_wide:
|
23
|
-
ABRV = {"micropython": "
|
26
|
+
ABRV = {"micropython": "mpy", "circuitpython": "cpy", "unknown": "?"}
|
24
27
|
return ABRV.get(family, family[:4])
|
25
28
|
return family
|
26
29
|
|
@@ -29,15 +32,19 @@ def mcu_table(
|
|
29
32
|
conn_mcus: List[MPRemoteBoard],
|
30
33
|
title: str = "Connected boards",
|
31
34
|
refresh: bool = True,
|
35
|
+
*,
|
36
|
+
title_style="magenta",
|
37
|
+
header_style="bold magenta",
|
32
38
|
):
|
33
39
|
"""
|
34
40
|
builds a rich table with the connected boards information
|
35
|
-
The columns of the table are adjusted to the terminal width
|
41
|
+
The columns of the table are adjusted to the terminal width > 90
|
36
42
|
the columns are :
|
37
43
|
Narrow Wide
|
38
44
|
- Serial Yes Yes
|
39
45
|
- Family abbrv. Yes
|
40
46
|
- Port - yes
|
47
|
+
- Variant Yes Yes only if any of the mcus have a variant
|
41
48
|
- Board Yes Yes BOARD_ID and Description, and the description from board_info.toml
|
42
49
|
- CPU - Yes
|
43
50
|
- Version Yes Yes
|
@@ -59,8 +66,8 @@ def mcu_table(
|
|
59
66
|
continue
|
60
67
|
table = Table(
|
61
68
|
title=title,
|
62
|
-
title_style=
|
63
|
-
header_style=
|
69
|
+
title_style=title_style,
|
70
|
+
header_style=header_style,
|
64
71
|
collapse_padding=True,
|
65
72
|
padding=(0, 0),
|
66
73
|
)
|
@@ -68,13 +75,15 @@ def mcu_table(
|
|
68
75
|
# check if the terminal is wide enough to show all columns or if we need to collapse some
|
69
76
|
is_wide = console.width > 99
|
70
77
|
needs_build = any(mcu.build for mcu in conn_mcus)
|
78
|
+
needs_variant = any(mcu.variant for mcu in conn_mcus)
|
71
79
|
|
72
80
|
table.add_column("Serial" if is_wide else "Ser.", overflow="fold")
|
73
81
|
table.add_column("Family" if is_wide else "Fam.", overflow="crop", max_width=None if is_wide else 4)
|
74
82
|
if is_wide:
|
75
83
|
table.add_column("Port")
|
76
84
|
table.add_column("Board", overflow="fold")
|
77
|
-
|
85
|
+
if needs_variant:
|
86
|
+
table.add_column("Variant")
|
78
87
|
if is_wide:
|
79
88
|
table.add_column("CPU")
|
80
89
|
table.add_column("Version", overflow="fold", min_width=5, max_width=16)
|
@@ -94,6 +103,8 @@ def mcu_table(
|
|
94
103
|
if is_wide:
|
95
104
|
row.append(mcu.port)
|
96
105
|
row.append(f"{mcu.board}\n{description}".strip())
|
106
|
+
if needs_variant:
|
107
|
+
row.append(mcu.variant)
|
97
108
|
if is_wide:
|
98
109
|
row.append(mcu.cpu)
|
99
110
|
row.append(clean_version(mcu.version))
|
mpflash/logger.py
CHANGED
@@ -20,9 +20,7 @@ def _log_formatter(record: dict) -> str:
|
|
20
20
|
"CRITICAL": "bold white on red",
|
21
21
|
}
|
22
22
|
lvl_color = color_map.get(record["level"].name, "cyan")
|
23
|
-
return
|
24
|
-
"[not bold green]{time:HH:mm:ss}[/not bold green] | {level.icon} " + f"[{lvl_color}]{{message}}[/{lvl_color}]"
|
25
|
-
)
|
23
|
+
return "[not bold green]{time:HH:mm:ss}[/not bold green] | {level.icon} " + f"[{lvl_color}]{{message}}[/{lvl_color}]"
|
26
24
|
|
27
25
|
|
28
26
|
def set_loglevel(loglevel: str):
|
mpflash/mpboard_id/__init__.py
CHANGED
@@ -6,93 +6,12 @@ that is included in the module.
|
|
6
6
|
|
7
7
|
from functools import lru_cache
|
8
8
|
from typing import List, Optional, Tuple
|
9
|
-
|
9
|
+
import importlib
|
10
10
|
from mpflash.errors import MPFlashError
|
11
|
-
from
|
12
|
-
from mpflash.mpboard_id.store import read_known_boardinfo
|
13
|
-
from mpflash.versions import clean_version
|
14
|
-
|
15
|
-
# KNOWN ports and boards are sourced from the micropython repo,
|
16
|
-
# this info is stored in the board_info.json file
|
17
|
-
|
18
|
-
|
19
|
-
def get_known_ports() -> List[str]:
|
20
|
-
# TODO: Filter for Version
|
21
|
-
mp_boards = read_known_boardinfo()
|
22
|
-
# select the unique ports from info
|
23
|
-
ports = set({board.port for board in mp_boards if board.port})
|
24
|
-
return sorted(list(ports))
|
25
|
-
|
26
|
-
|
27
|
-
def get_known_boards_for_port(
|
28
|
-
port: Optional[str] = "", versions: Optional[List[str]] = None
|
29
|
-
) -> List[Board]:
|
30
|
-
"""
|
31
|
-
Returns a list of boards for the given port and version(s)
|
32
|
-
|
33
|
-
port: The Micropython port to filter for
|
34
|
-
versions: Optional, The Micropython versions to filter for (actual versions required)
|
35
|
-
"""
|
36
|
-
mp_boards = read_known_boardinfo()
|
37
|
-
if versions:
|
38
|
-
preview_or_stable = "preview" in versions or "stable" in versions
|
39
|
-
else:
|
40
|
-
preview_or_stable = False
|
41
|
-
|
42
|
-
# filter for 'preview' as they are not in the board_info.json
|
43
|
-
# instead use stable version
|
44
|
-
versions = versions or []
|
45
|
-
if "preview" in versions:
|
46
|
-
versions.remove("preview")
|
47
|
-
versions.append("stable")
|
48
|
-
if versions:
|
49
|
-
# make sure of the v prefix
|
50
|
-
versions = [clean_version(v) for v in versions]
|
51
|
-
# filter for the version(s)
|
52
|
-
mp_boards = [board for board in mp_boards if board.version in versions]
|
53
|
-
if not mp_boards and preview_or_stable:
|
54
|
-
# nothing found - perhaps there is a newer version for which we do not have the board info yet
|
55
|
-
# use the latest known version from the board info
|
56
|
-
mp_boards = read_known_boardinfo()
|
57
|
-
last_known_version = sorted({b.version for b in mp_boards})[-1]
|
58
|
-
mp_boards = [board for board in mp_boards if board.version == last_known_version]
|
59
|
-
|
60
|
-
# filter for the port
|
61
|
-
if port:
|
62
|
-
mp_boards = [board for board in mp_boards if board.port == port]
|
63
|
-
return mp_boards
|
64
|
-
|
65
|
-
|
66
|
-
def known_stored_boards(port: str, versions: Optional[List[str]] = None) -> List[Tuple[str, str]]:
|
67
|
-
"""
|
68
|
-
Returns a list of tuples with the description and board name for the given port and version
|
69
|
-
|
70
|
-
port : str : The Micropython port to filter for
|
71
|
-
versions : List[str] : The Micropython versions to filter for (actual versions required)
|
72
|
-
"""
|
73
|
-
mp_boards = get_known_boards_for_port(port, versions)
|
74
|
-
|
75
|
-
boards = set({(f"{board.version} {board.description}", board.board_id) for board in mp_boards})
|
76
|
-
return sorted(list(boards))
|
11
|
+
from .board import Board
|
77
12
|
|
13
|
+
from mpflash.versions import clean_version
|
14
|
+
from .store import read_known_boardinfo
|
15
|
+
from .known import get_known_ports, get_known_boards_for_port
|
16
|
+
from .known import known_stored_boards, find_known_board
|
78
17
|
|
79
|
-
@lru_cache(maxsize=20)
|
80
|
-
def find_known_board(board_id: str) -> Board:
|
81
|
-
"""Find the board for the given BOARD_ID or 'board description' and return the board info as a Board object"""
|
82
|
-
# Some functional overlap with:
|
83
|
-
# mpboard_id\board_id.py _find_board_id_by_description
|
84
|
-
info = read_known_boardinfo()
|
85
|
-
for board_info in info:
|
86
|
-
if board_id in (
|
87
|
-
board_info.board_id,
|
88
|
-
board_info.description,
|
89
|
-
) or board_info.description.startswith(board_id):
|
90
|
-
if not board_info.cpu:
|
91
|
-
# failsafe for older board_info.json files
|
92
|
-
print(f"Board {board_id} has no CPU info, using port as CPU")
|
93
|
-
if " with " in board_info.description:
|
94
|
-
board_info.cpu = board_info.description.split(" with ")[-1]
|
95
|
-
else:
|
96
|
-
board_info.cpu = board_info.port
|
97
|
-
return board_info
|
98
|
-
raise MPFlashError(f"Board {board_id} not found")
|
mpflash/mpboard_id/add_boards.py
CHANGED
@@ -16,8 +16,7 @@ import mpflash.basicgit as git
|
|
16
16
|
from mpflash.logger import log
|
17
17
|
from mpflash.mpboard_id import Board
|
18
18
|
from mpflash.mpboard_id.store import write_boardinfo_json
|
19
|
-
from mpflash.versions import
|
20
|
-
micropython_versions)
|
19
|
+
from mpflash.versions import get_preview_mp_version, micropython_versions
|
21
20
|
|
22
21
|
# look for all mpconfigboard.h files and extract the board name
|
23
22
|
# from the #define MICROPY_HW_BOARD_NAME "PYBD_SF6"
|
@@ -25,9 +24,7 @@ from mpflash.versions import (get_preview_mp_version, get_stable_mp_version,
|
|
25
24
|
RE_H_MICROPY_HW_BOARD_NAME = re.compile(r"#define\s+MICROPY_HW_BOARD_NAME\s+\"(.+)\"")
|
26
25
|
RE_H_MICROPY_HW_MCU_NAME = re.compile(r"#define\s+MICROPY_HW_MCU_NAME\s+\"(.+)\"")
|
27
26
|
# find boards and variants in the mpconfigboard*.cmake files
|
28
|
-
RE_CMAKE_MICROPY_HW_BOARD_NAME = re.compile(
|
29
|
-
r"MICROPY_HW_BOARD_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\""
|
30
|
-
)
|
27
|
+
RE_CMAKE_MICROPY_HW_BOARD_NAME = re.compile(r"MICROPY_HW_BOARD_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\"")
|
31
28
|
RE_CMAKE_MICROPY_HW_MCU_NAME = re.compile(r"MICROPY_HW_MCU_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\"")
|
32
29
|
# TODO: normal make files
|
33
30
|
|
@@ -121,9 +118,7 @@ def boards_from_headers(mpy_path: Path, version: str, family: str):
|
|
121
118
|
mcu_name = match[1]
|
122
119
|
found += 1
|
123
120
|
if found == 2:
|
124
|
-
description =
|
125
|
-
f"{board_name} with {mcu_name}" if mcu_name != "-" else board_name
|
126
|
-
)
|
121
|
+
description = f"{board_name} with {mcu_name}" if mcu_name != "-" else board_name
|
127
122
|
board_list.append(
|
128
123
|
Board(
|
129
124
|
board_id=board,
|
mpflash/mpboard_id/board.py
CHANGED
@@ -21,17 +21,20 @@ class Board:
|
|
21
21
|
mcu_name: str = field(default="")
|
22
22
|
cpu: str = field(default="")
|
23
23
|
variant: str = field(default="")
|
24
|
+
mcu: str = field(default="")
|
24
25
|
|
25
26
|
def __post_init__(self):
|
26
27
|
if not self.cpu:
|
27
28
|
if " with " in self.description:
|
28
|
-
self.cpu = self.description.
|
29
|
+
self.cpu = self.description.rsplit(" with ")[-1]
|
29
30
|
else:
|
30
31
|
self.cpu = self.port
|
31
32
|
|
32
33
|
@staticmethod
|
33
34
|
def from_dict(data: dict) -> "Board":
|
34
|
-
|
35
|
+
valid_keys = {field.name for field in Board.__dataclass_fields__.values()}
|
36
|
+
filtered_data = {k: v for k, v in data.items() if k in valid_keys}
|
37
|
+
return Board(**filtered_data)
|
35
38
|
|
36
39
|
def to_dict(self) -> dict:
|
37
40
|
return self.__dict__
|
mpflash/mpboard_id/board_id.py
CHANGED
@@ -3,11 +3,15 @@ Translate board description to board designator
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import functools
|
6
|
+
import re
|
7
|
+
import sqlite3
|
6
8
|
from pathlib import Path
|
7
|
-
from typing import Optional
|
9
|
+
from typing import List, Optional
|
8
10
|
|
11
|
+
from mpflash.config import config
|
9
12
|
from mpflash.errors import MPFlashError
|
10
13
|
from mpflash.logger import log
|
14
|
+
from mpflash.mpboard_id.board import Board
|
11
15
|
from mpflash.mpboard_id.store import read_known_boardinfo
|
12
16
|
from mpflash.versions import clean_version, get_preview_mp_version, get_stable_mp_version
|
13
17
|
|
@@ -20,21 +24,78 @@ def find_board_id_by_description(
|
|
20
24
|
board_info: Optional[Path] = None,
|
21
25
|
) -> Optional[str]:
|
22
26
|
"""Find the MicroPython BOARD_ID based on the description in the firmware"""
|
23
|
-
|
27
|
+
version = clean_version(version) if version else ""
|
24
28
|
try:
|
25
29
|
boards = _find_board_id_by_description(
|
26
30
|
descr=descr,
|
27
31
|
short_descr=short_descr,
|
28
|
-
|
29
|
-
version=
|
32
|
+
db_path=board_info,
|
33
|
+
version=version,
|
30
34
|
)
|
31
|
-
|
35
|
+
if not boards:
|
36
|
+
log.debug(f"Version {version} not found in board info, using any version")
|
37
|
+
boards = _find_board_id_by_description(
|
38
|
+
descr=descr,
|
39
|
+
short_descr=short_descr,
|
40
|
+
db_path=board_info,
|
41
|
+
version="%", # any version
|
42
|
+
)
|
43
|
+
return boards[0].board_id if boards else None
|
32
44
|
except MPFlashError:
|
33
45
|
return "UNKNOWN_BOARD"
|
34
46
|
|
35
47
|
|
36
|
-
@functools.lru_cache(maxsize=20)
|
37
48
|
def _find_board_id_by_description(
|
49
|
+
*,
|
50
|
+
descr: str,
|
51
|
+
short_descr: str,
|
52
|
+
version: Optional[str] = None,
|
53
|
+
variant: str = "",
|
54
|
+
db_path: Optional[Path] = None,
|
55
|
+
):
|
56
|
+
short_descr = short_descr or ""
|
57
|
+
boards: List[Board] = []
|
58
|
+
version = clean_version(version) if version else "%"
|
59
|
+
if "-preview" in version:
|
60
|
+
version = version.replace("-preview", "%")
|
61
|
+
descriptions = [descr, short_descr]
|
62
|
+
if descr.startswith("Generic"):
|
63
|
+
descriptions.append(descr[8:])
|
64
|
+
descriptions.append(short_descr[8:])
|
65
|
+
|
66
|
+
try:
|
67
|
+
with sqlite3.connect(db_path or config.db_path) as conn:
|
68
|
+
conn.row_factory = sqlite3.Row
|
69
|
+
cursor = conn.cursor()
|
70
|
+
|
71
|
+
qry = f"""
|
72
|
+
SELECT
|
73
|
+
*
|
74
|
+
FROM board_downloaded
|
75
|
+
WHERE
|
76
|
+
board_id IN (
|
77
|
+
SELECT DISTINCT board_id
|
78
|
+
FROM board_downloaded
|
79
|
+
WHERE description IN {str(tuple(descriptions))}
|
80
|
+
)
|
81
|
+
AND version like '{version}'
|
82
|
+
AND variant like '{variant}'
|
83
|
+
"""
|
84
|
+
cursor.execute(qry)
|
85
|
+
rows = cursor.fetchall()
|
86
|
+
for row in rows:
|
87
|
+
r = dict(row)
|
88
|
+
|
89
|
+
boards.append(Board.from_dict(dict(row)))
|
90
|
+
except sqlite3.OperationalError as e:
|
91
|
+
raise MPFlashError("Database error") from e
|
92
|
+
if not boards:
|
93
|
+
raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
|
94
|
+
return boards
|
95
|
+
|
96
|
+
|
97
|
+
@functools.lru_cache(maxsize=20)
|
98
|
+
def _find_board_id_by_description_xx(
|
38
99
|
*,
|
39
100
|
descr: str,
|
40
101
|
short_descr: str,
|
@@ -89,4 +150,3 @@ def _find_board_id_by_description(
|
|
89
150
|
if not matches:
|
90
151
|
raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
|
91
152
|
return sorted(matches, key=lambda x: x.version)
|
92
|
-
|