mpflash 0.4.0.post3__py3-none-any.whl → 0.5.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 +163 -0
- mpflash/cli_download.py +16 -12
- mpflash/cli_flash.py +123 -73
- mpflash/cli_group.py +20 -1
- mpflash/cli_list.py +5 -4
- mpflash/cli_main.py +5 -4
- mpflash/common.py +24 -9
- mpflash/config.py +5 -3
- mpflash/download.py +58 -13
- mpflash/flash.py +36 -24
- mpflash/flash_esp.py +11 -11
- mpflash/flash_stm32.py +1 -1
- mpflash/flash_stm32_dfu.py +4 -7
- mpflash/flash_uf2.py +1 -1
- mpflash/mpboard_id/api.py +51 -10
- mpflash/mpboard_id/board_info.csv +2036 -16
- mpflash/mpboard_id/board_info.json +19435 -1255
- mpflash/vendored/dfu.py +9 -8
- mpflash/vendored/pydfu.py +1 -1
- {mpflash-0.4.0.post3.dist-info → mpflash-0.5.0.dist-info}/METADATA +2 -2
- mpflash-0.5.0.dist-info/RECORD +35 -0
- mpflash/basic.py +0 -41
- mpflash/download_input.py +0 -69
- mpflash/inq.py +0 -66
- mpflash/mpboard_id/get_boardnames.py +0 -213
- mpflash-0.4.0.post3.dist-info/RECORD +0 -38
- {mpflash-0.4.0.post3.dist-info → mpflash-0.5.0.dist-info}/LICENSE +0 -0
- {mpflash-0.4.0.post3.dist-info → mpflash-0.5.0.dist-info}/WHEEL +0 -0
- {mpflash-0.4.0.post3.dist-info → mpflash-0.5.0.dist-info}/entry_points.txt +0 -0
mpflash/common.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
import os
|
1
2
|
import time
|
3
|
+
from functools import lru_cache
|
2
4
|
from typing import TypedDict
|
3
5
|
|
4
|
-
from github import Github
|
6
|
+
from github import Auth, Github
|
5
7
|
from loguru import logger as log
|
6
8
|
from packaging.version import parse
|
7
9
|
from rich.progress import track
|
@@ -19,6 +21,14 @@ PORT_FWTYPES = {
|
|
19
21
|
"renesas-ra": [".hex"],
|
20
22
|
}
|
21
23
|
|
24
|
+
# Token with no permissions to avoid throttling
|
25
|
+
# https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#getting-a-higher-rate-limit
|
26
|
+
PAT_NO_ACCESS = (
|
27
|
+
"github_pat" + "_11AAHPVFQ0qAkDnSUaMKSp" + "_ZkDl5NRRwBsUN6EYg9ahp1Dvj4FDDONnXVgimxC2EtpY7Q7BUKBoQ0Jq72X"
|
28
|
+
)
|
29
|
+
PAT = os.environ.get("GITHUB_TOKEN") or PAT_NO_ACCESS
|
30
|
+
GH_CLIENT = Github(auth=Auth.Token(PAT))
|
31
|
+
|
22
32
|
|
23
33
|
class FWInfo(TypedDict):
|
24
34
|
filename: str
|
@@ -27,6 +37,7 @@ class FWInfo(TypedDict):
|
|
27
37
|
variant: str
|
28
38
|
preview: bool
|
29
39
|
version: str
|
40
|
+
build: str
|
30
41
|
|
31
42
|
|
32
43
|
#############################################################
|
@@ -52,7 +63,7 @@ def clean_version(
|
|
52
63
|
if version in {"", "-"}:
|
53
64
|
return version
|
54
65
|
if version.lower() == "stable":
|
55
|
-
_v =
|
66
|
+
_v = get_stable_mp_version()
|
56
67
|
if not _v:
|
57
68
|
log.warning("Could not determine the latest stable version")
|
58
69
|
return "stable"
|
@@ -89,12 +100,12 @@ def clean_version(
|
|
89
100
|
return version
|
90
101
|
|
91
102
|
|
92
|
-
|
103
|
+
@lru_cache(maxsize=10)
|
104
|
+
def micropython_versions(minver: str = "v1.20"):
|
93
105
|
"""Get the list of micropython versions from github tags"""
|
94
106
|
try:
|
95
|
-
|
96
|
-
|
97
|
-
repo = g.get_repo("micropython/micropython")
|
107
|
+
gh_client = GH_CLIENT
|
108
|
+
repo = gh_client.get_repo("micropython/micropython")
|
98
109
|
versions = [tag.name for tag in repo.get_tags() if parse(tag.name) >= parse(minver)]
|
99
110
|
except Exception:
|
100
111
|
versions = [
|
@@ -116,19 +127,23 @@ def micropython_versions(minver: str = "v1.9.2"):
|
|
116
127
|
"v1.12",
|
117
128
|
"v1.11",
|
118
129
|
"v1.10",
|
119
|
-
"v1.9.4",
|
120
|
-
"v1.9.3",
|
121
130
|
]
|
122
131
|
versions = [v for v in versions if parse(v) >= parse(minver)]
|
123
132
|
return sorted(versions)
|
124
133
|
|
125
134
|
|
126
|
-
def
|
135
|
+
def get_stable_mp_version() -> str:
|
127
136
|
# read the versions from the git tags
|
128
137
|
all_versions = micropython_versions(minver="v1.17")
|
129
138
|
return [v for v in all_versions if not v.endswith(V_PREVIEW)][-1]
|
130
139
|
|
131
140
|
|
141
|
+
def get_preview_mp_version() -> str:
|
142
|
+
# read the versions from the git tags
|
143
|
+
all_versions = micropython_versions(minver="v1.17")
|
144
|
+
return [v for v in all_versions if v.endswith(V_PREVIEW)][-1]
|
145
|
+
|
146
|
+
|
132
147
|
#############################################################
|
133
148
|
def wait_for_restart(mcu: MPRemoteBoard, timeout: int = 10):
|
134
149
|
"""wait for the board to restart"""
|
mpflash/config.py
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
"""centralized configuration for mpflash"""
|
2
2
|
|
3
|
-
import platformdirs
|
4
|
-
|
5
|
-
from typing import List
|
6
3
|
from pathlib import Path
|
4
|
+
from typing import List
|
5
|
+
|
6
|
+
import platformdirs
|
7
7
|
|
8
8
|
|
9
9
|
class MPtoolConfig:
|
10
10
|
"""Centralized configuration for mpflash"""
|
11
11
|
|
12
12
|
quiet: bool = False
|
13
|
+
verbose: bool = False
|
13
14
|
ignore_ports: List[str] = []
|
15
|
+
interactive: bool = True
|
14
16
|
firmware_folder: Path = platformdirs.user_downloads_path() / "firmware"
|
15
17
|
|
16
18
|
|
mpflash/download.py
CHANGED
@@ -5,19 +5,24 @@ Uses the micropython.org website to get the available versions and locations to
|
|
5
5
|
|
6
6
|
import functools
|
7
7
|
import itertools
|
8
|
-
import json
|
9
8
|
import re
|
10
9
|
from pathlib import Path
|
11
10
|
from typing import Dict, List, Optional
|
12
11
|
from urllib.parse import urljoin
|
13
12
|
|
14
|
-
|
13
|
+
# #########################################################################################################
|
14
|
+
# make sure that jsonlines does not mistake the MicroPython ujson for the CPython ujson
|
15
|
+
import jsonlines
|
15
16
|
import requests
|
16
17
|
from bs4 import BeautifulSoup
|
17
18
|
from loguru import logger as log
|
18
19
|
from rich.progress import track
|
19
20
|
|
20
|
-
|
21
|
+
from mpflash.common import PORT_FWTYPES
|
22
|
+
|
23
|
+
jsonlines.ujson = None # type: ignore
|
24
|
+
# #########################################################################################################
|
25
|
+
|
21
26
|
|
22
27
|
MICROPYTHON_ORG_URL = "https://micropython.org/"
|
23
28
|
|
@@ -78,6 +83,18 @@ FirmwareInfo = Dict[str, str]
|
|
78
83
|
# The first run takes ~60 seconds to run for 4 ports , all boards
|
79
84
|
# so it makes sense to cache the results and skip boards as soon as possible
|
80
85
|
def get_boards(ports: List[str], boards: List[str], clean: bool) -> List[FirmwareInfo]:
|
86
|
+
"""
|
87
|
+
Retrieves a list of firmware information for the specified ports and boards.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
ports (List[str]): The list of ports to check for firmware.
|
91
|
+
boards (List[str]): The list of boards to retrieve firmware information for.
|
92
|
+
clean (bool): A flag indicating whether to perform a clean retrieval.
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
List[FirmwareInfo]: A list of firmware information for the specified ports and boards.
|
96
|
+
|
97
|
+
"""
|
81
98
|
board_urls: List[FirmwareInfo] = []
|
82
99
|
for port in ports:
|
83
100
|
download_page_url = f"{MICROPYTHON_ORG_URL}download/?port={port}"
|
@@ -134,14 +151,13 @@ def download_firmwares(
|
|
134
151
|
boards: List[str],
|
135
152
|
versions: Optional[List[str]] = None,
|
136
153
|
*,
|
137
|
-
preview: bool = False,
|
138
154
|
force: bool = False,
|
139
155
|
clean: bool = True,
|
140
156
|
):
|
141
157
|
skipped = downloaded = 0
|
142
158
|
if versions is None:
|
143
159
|
versions = []
|
144
|
-
unique_boards = get_firmware_list(ports, boards, versions,
|
160
|
+
unique_boards = get_firmware_list(ports, boards, versions, clean)
|
145
161
|
|
146
162
|
for b in unique_boards:
|
147
163
|
log.debug(b["filename"])
|
@@ -151,7 +167,7 @@ def download_firmwares(
|
|
151
167
|
|
152
168
|
firmware_folder.mkdir(exist_ok=True)
|
153
169
|
|
154
|
-
with open(firmware_folder / "firmware.jsonl", "a"
|
170
|
+
with jsonlines.open(firmware_folder / "firmware.jsonl", "a") as writer:
|
155
171
|
for board in unique_boards:
|
156
172
|
filename = firmware_folder / board["port"] / board["filename"]
|
157
173
|
filename.parent.mkdir(exist_ok=True)
|
@@ -169,16 +185,28 @@ def download_firmwares(
|
|
169
185
|
except requests.RequestException as e:
|
170
186
|
log.exception(e)
|
171
187
|
continue
|
172
|
-
|
173
|
-
json_str = json.dumps(board) + "\n"
|
174
|
-
f_jsonl.write(json_str)
|
188
|
+
writer.write(board)
|
175
189
|
downloaded += 1
|
176
190
|
log.info(f"Downloaded {downloaded} firmwares, skipped {skipped} existing files.")
|
177
191
|
|
178
192
|
|
179
|
-
def get_firmware_list(ports: List[str], boards: List[str], versions: List[str],
|
180
|
-
|
193
|
+
def get_firmware_list(ports: List[str], boards: List[str], versions: List[str], clean: bool):
|
194
|
+
"""
|
195
|
+
Retrieves a list of unique firmware information based on the specified ports, boards, versions, and clean flag.
|
181
196
|
|
197
|
+
Args:
|
198
|
+
ports : The list of ports to check for firmware.
|
199
|
+
boards : The list of boards to filter the firmware by.
|
200
|
+
versions : The list of versions to filter the firmware by.
|
201
|
+
clean : A flag indicating whether to perform a clean check.
|
202
|
+
|
203
|
+
Returns:
|
204
|
+
List[FirmwareInfo]: A list of unique firmware information.
|
205
|
+
|
206
|
+
"""
|
207
|
+
|
208
|
+
log.trace("Checking MicroPython download pages")
|
209
|
+
preview = "preview" in versions
|
182
210
|
board_urls = sorted(get_boards(ports, boards, clean), key=key_fw_ver_pre_ext_bld)
|
183
211
|
|
184
212
|
log.debug(f"Total {len(board_urls)} firmwares")
|
@@ -206,8 +234,25 @@ def download(
|
|
206
234
|
versions: List[str],
|
207
235
|
force: bool,
|
208
236
|
clean: bool,
|
209
|
-
preview: bool,
|
210
237
|
):
|
238
|
+
"""
|
239
|
+
Downloads firmware files based on the specified destination, ports, boards, versions, force flag, and clean flag.
|
240
|
+
|
241
|
+
Args:
|
242
|
+
destination : The destination folder to save the downloaded firmware files.
|
243
|
+
ports : The list of ports to check for firmware.
|
244
|
+
boards : The list of boards to download firmware for.
|
245
|
+
versions : The list of versions to download firmware for.
|
246
|
+
force : A flag indicating whether to force the download even if the firmware file already exists.
|
247
|
+
clean : A flag indicating whether to perform a clean download.
|
248
|
+
|
249
|
+
Returns:
|
250
|
+
None
|
251
|
+
|
252
|
+
Raises:
|
253
|
+
SystemExit: If no boards are found or specified.
|
254
|
+
|
255
|
+
"""
|
211
256
|
if not boards:
|
212
257
|
log.critical("No boards found, please connect a board or specify boards to download firmware for.")
|
213
258
|
exit(1)
|
@@ -217,4 +262,4 @@ def download(
|
|
217
262
|
except (PermissionError, FileNotFoundError) as e:
|
218
263
|
log.critical(f"Could not create folder {destination}\n{e}")
|
219
264
|
exit(1)
|
220
|
-
download_firmwares(destination, ports, boards, versions,
|
265
|
+
download_firmwares(destination, ports, boards, versions, force=force, clean=clean)
|
mpflash/flash.py
CHANGED
@@ -5,9 +5,10 @@ from typing import Dict, List, Optional, Tuple
|
|
5
5
|
import jsonlines
|
6
6
|
from loguru import logger as log
|
7
7
|
|
8
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
9
|
+
|
8
10
|
from .common import FWInfo, clean_version
|
9
11
|
from .config import config
|
10
|
-
from .mpremoteboard import MPRemoteBoard
|
11
12
|
|
12
13
|
# #########################################################################################################
|
13
14
|
WorkList = List[Tuple[MPRemoteBoard, FWInfo]]
|
@@ -32,12 +33,11 @@ def find_firmware(
|
|
32
33
|
board: str,
|
33
34
|
version: str = "",
|
34
35
|
port: str = "",
|
35
|
-
preview: bool = False,
|
36
36
|
variants: bool = False,
|
37
37
|
fw_folder: Optional[Path] = None,
|
38
38
|
trie: int = 1,
|
39
39
|
selector: Optional[Dict[str, str]] = None,
|
40
|
-
):
|
40
|
+
) -> List[FWInfo]:
|
41
41
|
if selector is None:
|
42
42
|
selector = {}
|
43
43
|
fw_folder = fw_folder or config.firmware_folder
|
@@ -48,24 +48,8 @@ def find_firmware(
|
|
48
48
|
return []
|
49
49
|
# filter by version
|
50
50
|
version = clean_version(version, drop_v=True)
|
51
|
-
|
52
|
-
# never get a preview for an older version
|
53
|
-
fw_list = [fw for fw in fw_list if fw["preview"]]
|
54
|
-
else:
|
55
|
-
fw_list = [fw for fw in fw_list if fw["version"] == version]
|
51
|
+
fw_list = filter_fwlist(fw_list, board, version, port, variants, selector)
|
56
52
|
|
57
|
-
# filter by port
|
58
|
-
if port:
|
59
|
-
fw_list = [fw for fw in fw_list if fw["port"] == port]
|
60
|
-
|
61
|
-
if board:
|
62
|
-
if variants:
|
63
|
-
fw_list = [fw for fw in fw_list if fw["board"] == board]
|
64
|
-
else:
|
65
|
-
# the variant should match exactly the board name
|
66
|
-
fw_list = [fw for fw in fw_list if fw["variant"] == board]
|
67
|
-
if selector and port in selector:
|
68
|
-
fw_list = [fw for fw in fw_list if fw["filename"].endswith(selector[port])]
|
69
53
|
if not fw_list and trie < 2:
|
70
54
|
board_id = board.replace("_", "-")
|
71
55
|
# ESP board naming conventions have changed by adding a PORT refix
|
@@ -75,13 +59,12 @@ def find_firmware(
|
|
75
59
|
if port == "rp2" and not board_id.startswith("RPI_"):
|
76
60
|
board_id = f"RPI_{board_id}"
|
77
61
|
|
78
|
-
log.
|
62
|
+
log.info(f"Try ({trie}) to find a firmware for the board {board_id}")
|
79
63
|
fw_list = find_firmware(
|
80
64
|
fw_folder=fw_folder,
|
81
65
|
board=board_id,
|
82
66
|
version=version,
|
83
67
|
port=port,
|
84
|
-
preview=preview,
|
85
68
|
trie=trie + 1,
|
86
69
|
selector=selector,
|
87
70
|
)
|
@@ -91,6 +74,37 @@ def find_firmware(
|
|
91
74
|
return fw_list
|
92
75
|
|
93
76
|
|
77
|
+
def filter_fwlist(
|
78
|
+
fw_list: List[FWInfo],
|
79
|
+
board: str,
|
80
|
+
version: str,
|
81
|
+
port: str,
|
82
|
+
# preview: bool,
|
83
|
+
variants: bool,
|
84
|
+
selector: dict,
|
85
|
+
) -> List[FWInfo]:
|
86
|
+
"""Filter the firmware list based on the provided parameters"""
|
87
|
+
if "preview" in version:
|
88
|
+
# never get a preview for an older version
|
89
|
+
fw_list = [fw for fw in fw_list if fw["preview"]]
|
90
|
+
else:
|
91
|
+
fw_list = [fw for fw in fw_list if fw["version"] == version]
|
92
|
+
|
93
|
+
# filter by port
|
94
|
+
if port:
|
95
|
+
fw_list = [fw for fw in fw_list if fw["port"] == port]
|
96
|
+
|
97
|
+
if board:
|
98
|
+
if variants:
|
99
|
+
fw_list = [fw for fw in fw_list if fw["board"] == board]
|
100
|
+
else:
|
101
|
+
# the variant should match exactly the board name
|
102
|
+
fw_list = [fw for fw in fw_list if fw["variant"] == board]
|
103
|
+
if selector and port in selector:
|
104
|
+
fw_list = [fw for fw in fw_list if fw["filename"].endswith(selector[port])]
|
105
|
+
return fw_list
|
106
|
+
|
107
|
+
|
94
108
|
# #########################################################################################################
|
95
109
|
#
|
96
110
|
|
@@ -100,7 +114,6 @@ def auto_update(
|
|
100
114
|
target_version: str,
|
101
115
|
fw_folder: Path,
|
102
116
|
*,
|
103
|
-
preview: bool = False,
|
104
117
|
selector: Optional[Dict[str, str]] = None,
|
105
118
|
) -> WorkList:
|
106
119
|
"""Builds a list of boards to update based on the connected boards and the firmware available"""
|
@@ -118,7 +131,6 @@ def auto_update(
|
|
118
131
|
board=mcu.board,
|
119
132
|
version=target_version,
|
120
133
|
port=mcu.port,
|
121
|
-
preview=preview or "preview" in target_version,
|
122
134
|
selector=selector,
|
123
135
|
)
|
124
136
|
|
mpflash/flash_esp.py
CHANGED
@@ -4,26 +4,28 @@
|
|
4
4
|
# #########################################################################################################
|
5
5
|
"""
|
6
6
|
|
7
|
-
import time
|
8
7
|
from pathlib import Path
|
9
8
|
from typing import List, Optional
|
10
9
|
|
11
10
|
import esptool
|
12
11
|
from loguru import logger as log
|
13
12
|
|
14
|
-
from .
|
13
|
+
from mpflash.mpboard_id.api import find_mp_board
|
14
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
15
|
+
|
15
16
|
from .common import wait_for_restart
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
) -> Optional[MPRemoteBoard]:
|
18
|
+
|
19
|
+
def flash_esp(mcu: MPRemoteBoard, fw_file: Path, *, erase: bool = True) -> Optional[MPRemoteBoard]:
|
20
20
|
if mcu.port not in ["esp32", "esp8266"] or mcu.board in ["ARDUINO_NANO_ESP32"]:
|
21
|
-
log.error(
|
22
|
-
f"esptool not supported for {mcu.port} {mcu.board} on {mcu.serialport}"
|
23
|
-
)
|
21
|
+
log.error(f"esptool not supported for {mcu.port} {mcu.board} on {mcu.serialport}")
|
24
22
|
return None
|
25
23
|
|
26
24
|
log.info(f"Flashing {fw_file} on {mcu.board} on {mcu.serialport}")
|
25
|
+
if not mcu.cpu:
|
26
|
+
# Lookup CPU based on the board name
|
27
|
+
mcu.cpu = find_mp_board(mcu.board)["cpu"]
|
28
|
+
|
27
29
|
if mcu.port == "esp8266":
|
28
30
|
baud_rate = str(460_800)
|
29
31
|
else:
|
@@ -31,9 +33,7 @@ def flash_esp(
|
|
31
33
|
# baud_rate = str(115_200)
|
32
34
|
cmds: List[List[str]] = []
|
33
35
|
if erase:
|
34
|
-
cmds.append(
|
35
|
-
f"esptool --chip {mcu.cpu} --port {mcu.serialport} erase_flash".split()
|
36
|
-
)
|
36
|
+
cmds.append(f"esptool --chip {mcu.cpu} --port {mcu.serialport} erase_flash".split())
|
37
37
|
|
38
38
|
if mcu.cpu.upper() in ("ESP32", "ESP32S2"):
|
39
39
|
start_addr = "0x1000"
|
mpflash/flash_stm32.py
CHANGED
@@ -8,7 +8,7 @@ from mpflash.common import wait_for_restart
|
|
8
8
|
|
9
9
|
# from .flash_stm32_cube import flash_stm32_cubecli
|
10
10
|
from .flash_stm32_dfu import dfu_init, flash_stm32_dfu
|
11
|
-
from .mpremoteboard import MPRemoteBoard
|
11
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
12
12
|
|
13
13
|
|
14
14
|
def flash_stm32(mcu: MPRemoteBoard, fw_file: Path, *, erase: bool, stm32_dfu: bool = True):
|
mpflash/flash_stm32_dfu.py
CHANGED
@@ -1,26 +1,23 @@
|
|
1
1
|
import platform
|
2
|
-
import sys
|
3
|
-
import time
|
4
2
|
from pathlib import Path
|
5
3
|
from typing import Optional
|
6
4
|
|
7
5
|
from loguru import logger as log
|
8
6
|
|
9
|
-
from .
|
10
|
-
from .mpremoteboard import MPRemoteBoard
|
7
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
11
8
|
|
12
9
|
|
13
|
-
def init_libusb_windows():
|
10
|
+
def init_libusb_windows() -> bool:
|
14
11
|
# on windows we need to initialze the libusb backend with the correct dll
|
15
|
-
import libusb
|
12
|
+
import libusb # type: ignore
|
16
13
|
import usb.backend.libusb1 as libusb1
|
17
14
|
|
18
15
|
arch = "x64" if platform.architecture()[0] == "64bit" else "x86"
|
19
16
|
libusb1_dll = Path(libusb.__file__).parent / f"_platform\\_windows\\{arch}\\libusb-1.0.dll"
|
20
17
|
if not libusb1_dll.exists():
|
21
18
|
raise FileNotFoundError(f"libusb1.dll not found at {libusb1_dll}")
|
22
|
-
|
23
19
|
backend = libusb1.get_backend(find_library=lambda x: libusb1_dll.as_posix())
|
20
|
+
return backend is not None
|
24
21
|
|
25
22
|
|
26
23
|
try:
|
mpflash/flash_uf2.py
CHANGED
@@ -11,7 +11,7 @@ from typing import Optional
|
|
11
11
|
from loguru import logger as log
|
12
12
|
from rich.progress import track
|
13
13
|
|
14
|
-
from .mpremoteboard import MPRemoteBoard
|
14
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
15
15
|
|
16
16
|
from .common import PORT_FWTYPES
|
17
17
|
from .flash_uf2_linux import dismount_uf2, wait_for_UF2_linux
|
mpflash/mpboard_id/api.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import json
|
2
2
|
from functools import lru_cache
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import List, Tuple, TypedDict, Union
|
4
|
+
from typing import List, Optional, Tuple, TypedDict, Union
|
5
5
|
|
6
|
-
from mpflash.common import PORT_FWTYPES
|
6
|
+
from mpflash.common import PORT_FWTYPES, clean_version
|
7
7
|
|
8
8
|
|
9
9
|
# Board based on the dataclass Board but changed to TypedDict
|
@@ -18,31 +18,72 @@ class Board(TypedDict):
|
|
18
18
|
mcu_name: str
|
19
19
|
path: Union[Path, str]
|
20
20
|
version: str
|
21
|
+
cpu: str
|
21
22
|
|
22
23
|
|
23
24
|
@lru_cache(maxsize=None)
|
24
25
|
def read_boardinfo() -> List[Board]:
|
26
|
+
"""Reads the board_info.json file and returns the data as a list of Board objects"""
|
25
27
|
with open(Path(__file__).parent / "board_info.json", "r") as file:
|
26
28
|
return json.load(file)
|
27
29
|
|
28
30
|
|
29
31
|
def known_mp_ports() -> List[str]:
|
30
32
|
# TODO: Filter for Version
|
31
|
-
|
33
|
+
mp_boards = read_boardinfo()
|
32
34
|
# select the unique ports from info
|
33
|
-
ports = set({board["port"] for board in
|
35
|
+
ports = set({board["port"] for board in mp_boards if board["port"] in PORT_FWTYPES.keys()})
|
34
36
|
return sorted(list(ports))
|
35
37
|
|
36
38
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
39
|
+
def get_mp_boards_for_port(port: str, versions: Optional[List[str]] = None):
|
40
|
+
"""
|
41
|
+
Returns a list of boards for the given port and version(s)
|
42
|
+
|
43
|
+
port : str : The Micropython port to filter for
|
44
|
+
versions : List[str] : The Micropython versions to filter for (actual versions required)"""
|
45
|
+
mp_boards = read_boardinfo()
|
46
|
+
|
47
|
+
# filter for 'preview' as they are not in the board_info.json
|
48
|
+
# instead use stable version
|
49
|
+
versions = versions or []
|
50
|
+
if "preview" in versions:
|
51
|
+
versions.remove("preview")
|
52
|
+
versions.append("stable")
|
53
|
+
if versions:
|
54
|
+
# make sure of the v prefix
|
55
|
+
versions = [clean_version(v) for v in versions]
|
56
|
+
# filter for the version(s)
|
57
|
+
mp_boards = [board for board in mp_boards if board["version"] in versions]
|
58
|
+
# filter for the port
|
59
|
+
mp_boards = [board for board in mp_boards if board["port"] == port]
|
60
|
+
return mp_boards
|
61
|
+
|
62
|
+
|
63
|
+
def known_mp_boards(port: str, versions: Optional[List[str]] = None) -> List[Tuple[str, str]]:
|
64
|
+
"""
|
65
|
+
Returns a list of tuples with the description and board name for the given port and version
|
66
|
+
|
67
|
+
port : str : The Micropython port to filter for
|
68
|
+
versions : List[str] : The Micropython versions to filter for (actual versions required)
|
69
|
+
"""
|
70
|
+
mp_boards = get_mp_boards_for_port(port, versions)
|
71
|
+
|
72
|
+
boards = set(
|
73
|
+
{(f'{board["description"]} [board["board"]] {board["version"]}', board["board"]) for board in mp_boards}
|
74
|
+
)
|
40
75
|
return sorted(list(boards))
|
41
76
|
|
42
77
|
|
43
|
-
def
|
78
|
+
def find_mp_board(board: str) -> Board:
|
79
|
+
"""Find the board for the given board"""
|
44
80
|
info = read_boardinfo()
|
45
81
|
for board_info in info:
|
46
82
|
if board_info["board"] == board:
|
47
|
-
|
48
|
-
|
83
|
+
if "cpu" not in board_info or not board_info["cpu"]:
|
84
|
+
if " with " in board_info["description"]:
|
85
|
+
board_info["cpu"] = board_info["description"].split(" with ")[-1]
|
86
|
+
else:
|
87
|
+
board_info["cpu"] = board_info["port"]
|
88
|
+
return board_info
|
89
|
+
raise LookupError(f"Board {board} not found")
|