mpflash 1.25.0rc4__py3-none-any.whl → 1.25.2__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/basicgit.py +19 -0
- mpflash/cli_add.py +131 -0
- mpflash/cli_download.py +3 -14
- mpflash/cli_flash.py +44 -26
- mpflash/cli_group.py +1 -0
- mpflash/cli_list.py +2 -0
- mpflash/cli_main.py +7 -0
- mpflash/common.py +14 -2
- mpflash/config.py +22 -1
- mpflash/connected.py +8 -6
- mpflash/custom/__init__.py +144 -0
- mpflash/custom/naming.py +91 -0
- mpflash/db/core.py +84 -6
- mpflash/db/gather_boards.py +6 -4
- mpflash/db/loader.py +4 -3
- mpflash/db/meta.py +4 -3
- mpflash/db/micropython_boards.zip +0 -0
- mpflash/db/models.py +2 -0
- mpflash/download/__init__.py +58 -1
- mpflash/download/fwinfo.py +1 -1
- mpflash/download/jid.py +1 -1
- mpflash/downloaded.py +8 -4
- mpflash/flash/__init__.py +10 -1
- mpflash/flash/uf2/windows.py +1 -1
- mpflash/flash/worklist.py +40 -19
- mpflash/list.py +2 -0
- mpflash/logger.py +27 -7
- mpflash/mpboard_id/board_id.py +13 -17
- mpflash/mpboard_id/known.py +8 -2
- mpflash/mpremoteboard/__init__.py +61 -3
- mpflash/mpremoteboard/runner.py +1 -0
- {mpflash-1.25.0rc4.dist-info → mpflash-1.25.2.dist-info}/METADATA +63 -10
- {mpflash-1.25.0rc4.dist-info → mpflash-1.25.2.dist-info}/RECORD +36 -34
- {mpflash-1.25.0rc4.dist-info → mpflash-1.25.2.dist-info}/WHEEL +1 -1
- mpflash/add_firmware.py +0 -125
- {mpflash-1.25.0rc4.dist-info → mpflash-1.25.2.dist-info}/LICENSE +0 -0
- {mpflash-1.25.0rc4.dist-info → mpflash-1.25.2.dist-info}/entry_points.txt +0 -0
mpflash/flash/worklist.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
"""Worklist for updating boards"""
|
2
2
|
|
3
|
-
from
|
4
|
-
from typing import Dict, List, Optional, Tuple
|
3
|
+
from typing import List, Optional, Tuple
|
5
4
|
|
6
5
|
from loguru import logger as log
|
6
|
+
from serial.tools.list_ports_common import ListPortInfo
|
7
|
+
from typing_extensions import TypeAlias
|
7
8
|
|
8
|
-
from mpflash.common import
|
9
|
+
from mpflash.common import filtered_portinfos
|
9
10
|
from mpflash.db.models import Firmware
|
10
11
|
from mpflash.downloaded import find_downloaded_firmware
|
11
12
|
from mpflash.errors import MPFlashError
|
@@ -14,11 +15,12 @@ from mpflash.mpboard_id import find_known_board
|
|
14
15
|
from mpflash.mpremoteboard import MPRemoteBoard
|
15
16
|
|
16
17
|
# #########################################################################################################
|
17
|
-
|
18
|
+
FlashItem: TypeAlias = Tuple[MPRemoteBoard, Optional[Firmware]]
|
19
|
+
WorkList: TypeAlias = List[FlashItem]
|
18
20
|
# #########################################################################################################
|
19
21
|
|
20
22
|
|
21
|
-
def
|
23
|
+
def auto_update_worklist(
|
22
24
|
conn_boards: List[MPRemoteBoard],
|
23
25
|
target_version: str,
|
24
26
|
) -> WorkList:
|
@@ -32,6 +34,7 @@ def auto_update(
|
|
32
34
|
Returns:
|
33
35
|
WorkList: List of boards and firmware information to update
|
34
36
|
"""
|
37
|
+
log.debug(f"auto_update_worklist: {len(conn_boards)} boards, target version: {target_version}")
|
35
38
|
wl: WorkList = []
|
36
39
|
for mcu in conn_boards:
|
37
40
|
if mcu.family not in ("micropython", "unknown"):
|
@@ -59,12 +62,29 @@ def auto_update(
|
|
59
62
|
|
60
63
|
|
61
64
|
def manual_worklist(
|
62
|
-
serial: str,
|
65
|
+
serial: List[str],
|
63
66
|
*,
|
64
67
|
board_id: str,
|
65
68
|
version: str,
|
69
|
+
custom: bool = False,
|
66
70
|
) -> WorkList:
|
67
|
-
"""Create a worklist for
|
71
|
+
"""Create a worklist for manually specified boards."""
|
72
|
+
log.debug(f"manual_worklist: {len(serial)} serial ports, board_id: {board_id}, version: {version}")
|
73
|
+
wl: WorkList = []
|
74
|
+
for comport in serial:
|
75
|
+
log.trace(f"Manual updating {comport} to {board_id} {version}")
|
76
|
+
wl.append(manual_board(comport, board_id=board_id, version=version, custom=custom))
|
77
|
+
return wl
|
78
|
+
|
79
|
+
|
80
|
+
def manual_board(
|
81
|
+
serial: str,
|
82
|
+
*,
|
83
|
+
board_id: str,
|
84
|
+
version: str,
|
85
|
+
custom: bool = False,
|
86
|
+
) -> FlashItem:
|
87
|
+
"""Create a Flash work item for a single board specified manually.
|
68
88
|
|
69
89
|
Args:
|
70
90
|
serial (str): Serial port of the board
|
@@ -72,9 +92,9 @@ def manual_worklist(
|
|
72
92
|
version (str): Firmware version
|
73
93
|
|
74
94
|
Returns:
|
75
|
-
|
95
|
+
FlashItem: Board and firmware information to update
|
76
96
|
"""
|
77
|
-
log.
|
97
|
+
log.debug(f"manual_board: {serial} {board_id} {version}")
|
78
98
|
mcu = MPRemoteBoard(serial)
|
79
99
|
# Lookup the matching port and cpu in board_info based in the board name
|
80
100
|
try:
|
@@ -85,14 +105,14 @@ def manual_worklist(
|
|
85
105
|
except (LookupError, MPFlashError) as e:
|
86
106
|
log.error(f"Board {board_id} not found in board database")
|
87
107
|
log.exception(e)
|
88
|
-
return
|
108
|
+
return (mcu, None)
|
89
109
|
mcu.board = board_id
|
90
|
-
firmwares = find_downloaded_firmware(board_id=board_id, version=version, port=mcu.port)
|
110
|
+
firmwares = find_downloaded_firmware(board_id=board_id, version=version, port=mcu.port, custom=custom)
|
91
111
|
if not firmwares:
|
92
|
-
log.
|
93
|
-
return
|
112
|
+
log.trace(f"No firmware found for {mcu.port} {board_id} version {version}")
|
113
|
+
return (mcu, None)
|
94
114
|
# use the most recent matching firmware
|
95
|
-
return
|
115
|
+
return (mcu, firmwares[-1]) # type: ignore
|
96
116
|
|
97
117
|
|
98
118
|
def single_auto_worklist(
|
@@ -109,9 +129,10 @@ def single_auto_worklist(
|
|
109
129
|
Returns:
|
110
130
|
WorkList: List of boards and firmware information to update
|
111
131
|
"""
|
132
|
+
log.debug(f"single_auto_worklist: {serial} version: {version}")
|
112
133
|
log.trace(f"Auto updating {serial} to {version}")
|
113
134
|
conn_boards = [MPRemoteBoard(serial)]
|
114
|
-
todo =
|
135
|
+
todo = auto_update_worklist(conn_boards, version) # type: ignore # List / list
|
115
136
|
show_mcus(conn_boards)
|
116
137
|
return todo
|
117
138
|
|
@@ -125,7 +146,7 @@ def full_auto_worklist(
|
|
125
146
|
) -> WorkList:
|
126
147
|
"""
|
127
148
|
Create a worklist for all connected micropython boards based on the information retrieved from the board.
|
128
|
-
This allows the firmware version of one or
|
149
|
+
This allows the firmware version of one or more boards to be changed without needing to specify the port or board_id manually.
|
129
150
|
|
130
151
|
Args:
|
131
152
|
version (str): Firmware version
|
@@ -133,9 +154,9 @@ def full_auto_worklist(
|
|
133
154
|
Returns:
|
134
155
|
WorkList: List of boards and firmware information to update
|
135
156
|
"""
|
136
|
-
log.
|
157
|
+
log.debug(f"full_auto_worklist: {len(all_boards)} boards, include: {include}, ignore: {ignore}, version: {version}")
|
137
158
|
if selected_boards := filter_boards(all_boards, include=include, ignore=ignore):
|
138
|
-
return
|
159
|
+
return auto_update_worklist(selected_boards, version)
|
139
160
|
else:
|
140
161
|
return []
|
141
162
|
|
@@ -149,7 +170,7 @@ def filter_boards(
|
|
149
170
|
try:
|
150
171
|
comports = [
|
151
172
|
p.device
|
152
|
-
for p in
|
173
|
+
for p in filtered_portinfos(
|
153
174
|
ignore=ignore,
|
154
175
|
include=include,
|
155
176
|
bluetooth=False,
|
mpflash/list.py
CHANGED
@@ -90,6 +90,7 @@ def mcu_table(
|
|
90
90
|
if needs_build:
|
91
91
|
table.add_column("Build" if is_wide else "Bld", justify="right")
|
92
92
|
if config.usb:
|
93
|
+
table.add_column("vid:pid", overflow="fold", max_width=14)
|
93
94
|
table.add_column("Location", overflow="fold", max_width=60)
|
94
95
|
# fill the table with the data
|
95
96
|
for mcu in conn_mcus:
|
@@ -111,6 +112,7 @@ def mcu_table(
|
|
111
112
|
if needs_build:
|
112
113
|
row.append(mcu.build)
|
113
114
|
if config.usb:
|
115
|
+
row.append(f"{mcu.vid:04x}:{mcu.pid:04x}")
|
114
116
|
row.append(mcu.location)
|
115
117
|
|
116
118
|
table.add_row(*row)
|
mpflash/logger.py
CHANGED
@@ -5,6 +5,7 @@ Ensures log messages are compatible with the current console encoding.
|
|
5
5
|
Removes or replaces Unicode icons if the encoding is not UTF-8.
|
6
6
|
"""
|
7
7
|
|
8
|
+
import functools
|
8
9
|
import sys
|
9
10
|
|
10
11
|
from loguru import logger as log
|
@@ -14,12 +15,17 @@ from .config import config
|
|
14
15
|
|
15
16
|
console = Console()
|
16
17
|
|
18
|
+
|
17
19
|
# Detect if the output encoding supports Unicode (UTF-8)
|
20
|
+
@functools.lru_cache(maxsize=1)
|
18
21
|
def _is_utf8_encoding() -> bool:
|
19
|
-
|
20
|
-
|
22
|
+
try:
|
23
|
+
encoding = getattr(sys.stdout, "encoding", None)
|
24
|
+
if encoding is None:
|
25
|
+
return False
|
26
|
+
return encoding.lower().replace("-", "") == "utf8"
|
27
|
+
except BaseException:
|
21
28
|
return False
|
22
|
-
return encoding.lower().replace("-", "") == "utf8"
|
23
29
|
|
24
30
|
|
25
31
|
def _log_formatter(record: dict) -> str:
|
@@ -27,6 +33,7 @@ def _log_formatter(record: dict) -> str:
|
|
27
33
|
Log message formatter for loguru and rich.
|
28
34
|
|
29
35
|
Removes Unicode icons if console encoding is not UTF-8.
|
36
|
+
Handles messages containing curly braces safely.
|
30
37
|
"""
|
31
38
|
color_map = {
|
32
39
|
"TRACE": "cyan",
|
@@ -43,21 +50,34 @@ def _log_formatter(record: dict) -> str:
|
|
43
50
|
icon = record["level"].icon
|
44
51
|
else:
|
45
52
|
icon = record["level"].name # fallback to text
|
46
|
-
#
|
47
|
-
|
53
|
+
# Escape curly braces in the message to prevent format conflicts
|
54
|
+
safe_message = record["message"].replace("{", "{{").replace("}", "}}")
|
55
|
+
# Use string concatenation to avoid f-string format conflicts
|
56
|
+
time_part = "[not bold green]{time:HH:mm:ss}[/not bold green]"
|
57
|
+
message_part = f"[{lvl_color}]{safe_message}[/{lvl_color}]"
|
58
|
+
return f"{time_part} | {icon} {message_part}"
|
48
59
|
|
49
60
|
|
50
61
|
def set_loglevel(loglevel: str) -> None:
|
51
62
|
"""
|
52
63
|
Set the log level for the logger.
|
53
64
|
|
54
|
-
Ensures Unicode safety for log output.
|
65
|
+
Ensures Unicode safety for log output and handles format errors.
|
55
66
|
"""
|
56
67
|
try:
|
57
68
|
log.remove()
|
58
69
|
except ValueError:
|
59
70
|
pass
|
60
|
-
|
71
|
+
|
72
|
+
# Add error handling for format issues
|
73
|
+
def safe_format_wrapper(message):
|
74
|
+
try:
|
75
|
+
console.print(message)
|
76
|
+
except (KeyError, ValueError) as e:
|
77
|
+
# Fallback to simple text output if formatting fails
|
78
|
+
console.print(f"[LOG FORMAT ERROR] {message} (Error: {e})")
|
79
|
+
|
80
|
+
log.add(safe_format_wrapper, level=loglevel.upper(), colorize=False, format=_log_formatter) # type: ignore
|
61
81
|
|
62
82
|
|
63
83
|
def make_quiet() -> None:
|
mpflash/mpboard_id/board_id.py
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
Translate board description to board designator
|
3
3
|
"""
|
4
4
|
|
5
|
-
|
6
5
|
from typing import List, Optional
|
7
6
|
|
8
7
|
from mpflash.db.core import Session
|
@@ -17,25 +16,24 @@ def find_board_id_by_description(
|
|
17
16
|
short_descr: str,
|
18
17
|
*,
|
19
18
|
version: str,
|
20
|
-
) ->
|
19
|
+
) -> str:
|
21
20
|
"""Find the MicroPython BOARD_ID based on the description in the firmware"""
|
22
21
|
version = clean_version(version) if version else ""
|
23
|
-
|
22
|
+
boards = _find_board_id_by_description(
|
23
|
+
descr=descr,
|
24
|
+
short_descr=short_descr,
|
25
|
+
version=version,
|
26
|
+
)
|
27
|
+
if not boards:
|
28
|
+
log.debug(f"Version {version} not found in board info, using any version")
|
24
29
|
boards = _find_board_id_by_description(
|
25
30
|
descr=descr,
|
26
31
|
short_descr=short_descr,
|
27
|
-
version=version
|
32
|
+
version="%", # any version
|
28
33
|
)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
descr=descr,
|
33
|
-
short_descr=short_descr,
|
34
|
-
version="%", # any version
|
35
|
-
)
|
36
|
-
return boards[0].board_id if boards else None
|
37
|
-
except MPFlashError:
|
38
|
-
return "UNKNOWN_BOARD"
|
34
|
+
if not boards:
|
35
|
+
raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
|
36
|
+
return boards[0].board_id
|
39
37
|
|
40
38
|
|
41
39
|
def _find_board_id_by_description(
|
@@ -63,7 +61,5 @@ def _find_board_id_by_description(
|
|
63
61
|
)
|
64
62
|
boards = qry.all()
|
65
63
|
|
66
|
-
if not boards:
|
67
|
-
raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
|
68
|
-
return boards
|
69
64
|
|
65
|
+
return boards
|
mpflash/mpboard_id/known.py
CHANGED
@@ -64,9 +64,15 @@ def known_stored_boards(port: str, versions: List[str] = []) -> List[Tuple[str,
|
|
64
64
|
|
65
65
|
|
66
66
|
def find_known_board(board_id: str, version="") -> Board:
|
67
|
-
"""
|
67
|
+
"""
|
68
|
+
Find the board for the given BOARD_ID or 'board description'
|
69
|
+
if the board_id is not found, it will try to find it by description.
|
70
|
+
|
71
|
+
if the board_id contains an @, it will split it and use the first part as the board_id
|
72
|
+
Returns the board info as a Board object
|
73
|
+
"""
|
68
74
|
with Session() as session:
|
69
|
-
qry = session.query(Board).filter(Board.board_id == board_id)
|
75
|
+
qry = session.query(Board).filter(Board.board_id == board_id.split("@")[0])
|
70
76
|
if version:
|
71
77
|
qry = qry.filter(Board.version == version)
|
72
78
|
board = qry.first()
|
@@ -3,6 +3,7 @@ Module to run mpremote commands, and retry on failure or timeout
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import contextlib
|
6
|
+
import re
|
6
7
|
import sys
|
7
8
|
import time
|
8
9
|
from pathlib import Path
|
@@ -22,6 +23,8 @@ if sys.version_info >= (3, 11):
|
|
22
23
|
else:
|
23
24
|
import tomli as tomllib # type: ignore
|
24
25
|
|
26
|
+
import tomli_w
|
27
|
+
|
25
28
|
###############################################################################################
|
26
29
|
HERE = Path(__file__).parent
|
27
30
|
|
@@ -61,6 +64,13 @@ class MPRemoteBoard:
|
|
61
64
|
self.build = ""
|
62
65
|
self.location = location # USB location
|
63
66
|
self.toml = {}
|
67
|
+
portinfo = list(serial.tools.list_ports.grep(serialport)) # type: ignore
|
68
|
+
if not portinfo or len(portinfo) != 1:
|
69
|
+
self.vid = 0x00
|
70
|
+
self.pid = 0x00
|
71
|
+
else:
|
72
|
+
self.vid = portinfo[0].vid
|
73
|
+
self.pid = portinfo[0].pid
|
64
74
|
if update:
|
65
75
|
self.get_mcu_info()
|
66
76
|
|
@@ -76,7 +86,14 @@ class MPRemoteBoard:
|
|
76
86
|
|
77
87
|
@property
|
78
88
|
def board(self) -> str:
|
79
|
-
|
89
|
+
_board = self._board_id.split("-")[0]
|
90
|
+
# Workaround for Pimoroni boards
|
91
|
+
if not "-" in self._board_id:
|
92
|
+
# match with the regex : (.*)(_\d+MB)$
|
93
|
+
match = re.match(r"(.*)_(\d+MB)$", self._board_id)
|
94
|
+
if match:
|
95
|
+
_board = match.group(1)
|
96
|
+
return _board
|
80
97
|
|
81
98
|
@board.setter
|
82
99
|
def board(self, value: str) -> None:
|
@@ -84,7 +101,14 @@ class MPRemoteBoard:
|
|
84
101
|
|
85
102
|
@property
|
86
103
|
def variant(self) -> str:
|
87
|
-
|
104
|
+
_variant = self._board_id.split("-")[1] if "-" in self._board_id else ""
|
105
|
+
if not _variant:
|
106
|
+
# Workaround for Pimoroni boards
|
107
|
+
# match with the regex : (.*)(_\d+MB)$
|
108
|
+
match = re.match(r"(.*)_(\d+MB)$", self._board_id)
|
109
|
+
if match:
|
110
|
+
_variant = match.group(2)
|
111
|
+
return _variant
|
88
112
|
|
89
113
|
@variant.setter
|
90
114
|
def variant(self, value: str) -> None:
|
@@ -216,14 +240,48 @@ class MPRemoteBoard:
|
|
216
240
|
self.toml = {}
|
217
241
|
if rc in [OK]: # sometimes we get an -9 ???
|
218
242
|
try:
|
243
|
+
log.trace(result)
|
219
244
|
# Ok we have the info, now parse it
|
220
245
|
self.toml = tomllib.loads("".join(result))
|
221
|
-
log.debug(f"board_info.toml: {self.toml}")
|
246
|
+
log.debug(f"board_info.toml: {self.toml['description']}")
|
222
247
|
except Exception as e:
|
223
248
|
log.error(f"Failed to parse board_info.toml: {e}")
|
224
249
|
else:
|
225
250
|
log.trace(f"Did not find a board_info.toml: {result}")
|
226
251
|
|
252
|
+
def set_board_info_toml(self, timeout: int = 1):
|
253
|
+
"""
|
254
|
+
Writes the current board information to the board_info.toml file on the connected board.
|
255
|
+
|
256
|
+
Parameters:
|
257
|
+
- timeout (int): The timeout value in seconds.
|
258
|
+
"""
|
259
|
+
if not self.connected:
|
260
|
+
raise MPFlashError("Board is not connected")
|
261
|
+
if not self.toml:
|
262
|
+
log.warning("No board_info.toml to write")
|
263
|
+
return
|
264
|
+
# write the toml file to a temp file, then copy to the board
|
265
|
+
|
266
|
+
toml_path = HERE / "tmp_board_info.toml"
|
267
|
+
try:
|
268
|
+
with open(toml_path, "wb") as f:
|
269
|
+
tomli_w.dump(self.toml, f)
|
270
|
+
|
271
|
+
log.debug(f"Writing board_info.toml to {self.serialport}")
|
272
|
+
rc, result = self.run_command(
|
273
|
+
["cp", str(toml_path), ":board_info.toml"],
|
274
|
+
no_info=True,
|
275
|
+
timeout=timeout,
|
276
|
+
log_errors=False,
|
277
|
+
)
|
278
|
+
except Exception as e:
|
279
|
+
raise MPFlashError(f"Failed to write board_info.toml for {self.serialport}: {e}") from e
|
280
|
+
finally:
|
281
|
+
# remove the temp file
|
282
|
+
if toml_path.exists():
|
283
|
+
toml_path.unlink()
|
284
|
+
|
227
285
|
def disconnect(self) -> bool:
|
228
286
|
"""
|
229
287
|
Disconnect from a board.
|
mpflash/mpremoteboard/runner.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: mpflash
|
3
|
-
Version: 1.25.
|
3
|
+
Version: 1.25.2
|
4
4
|
Summary: Flash and download tool for MicroPython firmwares
|
5
5
|
License: MIT
|
6
6
|
Keywords: MicroPython,firmware,flash,download,UF2,esptool
|
@@ -37,6 +37,7 @@ Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
37
37
|
Requires-Dist: rich-click (>=1.8.1,<2.0.0)
|
38
38
|
Requires-Dist: sqlalchemy (>=2.0.41,<3.0.0)
|
39
39
|
Requires-Dist: tenacity (==9.0.0)
|
40
|
+
Requires-Dist: tomli-w (>=1.2.0,<2.0.0)
|
40
41
|
Project-URL: Homepage, https://github.com/Josverl/mpflash/blob/main/README.md
|
41
42
|
Project-URL: Repository, https://github.com/Josverl/mpflash
|
42
43
|
Description-Content-Type: text/markdown
|
@@ -58,9 +59,22 @@ This tool was initially created to be used in a CI/CD pipeline to automate the p
|
|
58
59
|
- `samd`, using ` .uf2`, using filecopy
|
59
60
|
- `esp32`, using `.bin`, using esptool,
|
60
61
|
- `esp8266`, using `.bin`, using esptool
|
61
|
-
- `stm32`, using ` .dfu`, using pydfu
|
62
|
+
- `stm32`, using ` .dfu`, using pydfu (also in Windows)
|
62
63
|
|
63
64
|
Not yet implemented: `nrf`, `cc3200`, `mimxrt`, `renesas`
|
65
|
+
|
66
|
+
## Release v1.25.0(.post2)
|
67
|
+
|
68
|
+
This release includes several new features and improvements:
|
69
|
+
- **New features:**
|
70
|
+
- Added support for `--variant` option to specify a specific variant of the board when flashing.
|
71
|
+
- mpflash now uses a slqlite database to store information on all possible micropython firmwares, and the management of the downloaded firmware files.
|
72
|
+
- This allows for a better identification of boards, and matches to the correct firmware.
|
73
|
+
- Use the MicroPython v1.25.0 `sys.implementation._build` to as board_id when avaialable
|
74
|
+
- Automatically try to download firmware if not yet available locally. No lonmger need to specify the `--download` option.
|
75
|
+
- Restructured mpboard_id to use a SQLite db to be able to ID more boards and variants
|
76
|
+
- vendored and adapted `board_database.py` from mpflash, kudos @mattytrentini
|
77
|
+
|
64
78
|
|
65
79
|
## Features
|
66
80
|
1. List the connected boards including their firmware details, in a tabular or json format
|
@@ -79,15 +93,54 @@ You can use mpflash to perform various operations on your MicroPython boards. He
|
|
79
93
|
| Command | Description |
|
80
94
|
|---------|-------------|
|
81
95
|
| `mpflash list` | List the connected board(s) including their firmware details |
|
96
|
+
| `mpflash flash` | Flash the latest stable firmware to the connected board(s), downloading the firmware if needed |
|
82
97
|
| `mpflash download` | Download the MicroPython firmware(s) for the connected board(s) |
|
83
|
-
| `mpflash flash` | Flash the latest stable firmware to the connected board(s) |
|
84
98
|
|
85
|
-
|
99
|
+
**Listing connected boards:**
|
100
|
+
`mpflash list` will list all connected boards in a table , including their serial port, family, board name, CPU, version and build number.
|
101
|
+
Options are available to list the boards in a json format, or to filter the list by serial port or board type.
|
102
|
+
|
103
|
+
|
104
|
+
**Flashing boards with new firmware:**
|
105
|
+
`mpflash flash` will flash the latest stable firmware to all connected boards, downloading the firmware if needed.
|
106
|
+
It will try to determine the current micropython borad and variant, download the firmware if needed, and flash the correct firmware to each board.
|
107
|
+
|
108
|
+
Common options are:
|
109
|
+
|
110
|
+
- `--version` to specify the version of the firmware to flash, defaults to the latest stable version.
|
111
|
+
- `--serial` to specify the serial port(s) to flash, defaults to all connected boards.
|
112
|
+
- `--board` to specify which firmware to flash to a single board
|
113
|
+
- `--variant` to specify a specific variant of the board
|
114
|
+
|
115
|
+
**Downloading firmware:**
|
116
|
+
`mpflash download` will download the latest stable firmware for all connected boards, or a specific board if specified. It will download the firmware from the official MicroPython website and save it in your `Downloads/firmware` directory.
|
117
|
+
When a board is specified for which multiple variants are available, all variants will be downloaded.
|
118
|
+
|
119
|
+
Common options are:
|
120
|
+
|
121
|
+
- `--version` to specify the version of the firmware to download, defaults to the latest stable version. (e.g. `stable`, `preview`, `x.y.z`)
|
122
|
+
- `--serial` to specify the serial port(s) to flash, defaults to all connected boards.
|
123
|
+
- `--board` to specify which firmware to flash to a single board
|
86
124
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
125
|
+
## Setting the Firmware Files and Database Location
|
126
|
+
|
127
|
+
You can override the default location for firmware files and the MPFlash database by setting the `MPFLASH_FIRMWARE` environment variable. For example, in a Bash shell:
|
128
|
+
|
129
|
+
```bash
|
130
|
+
export MPFLASH_FIRMWARE="/path/to/custom/firmware"
|
131
|
+
```
|
132
|
+
|
133
|
+
When this variable is set, `mpflash` will use that location to store firmware files and estabish it's database.
|
134
|
+
|
135
|
+
## Selecting or ignoring specific serial ports
|
136
|
+
|
137
|
+
You can use the `--serial` option to select a specific serial port(s) to flash,
|
138
|
+
Or you can use the `--ignore` option to ignore a specific serial port(s).
|
139
|
+
|
140
|
+
Either option can be specified multiple times, can be globs (e.g. COM*) or exact port names (e.g. /dev/ttyUSB0).
|
141
|
+
To permenently ignore a port, you can set the `MPFLASH_IGNORE` environment variable to a space-separated list of serial ports or globs.
|
142
|
+
|
143
|
+
In addition there is a --bluetooth option to simplify ignoring bluetooth ports, where the default is to ignore bluetooth ports.
|
91
144
|
|
92
145
|
```
|
93
146
|
--serial,--serial-port -s SERIALPORT Serial port(s) (or globs) to list. [default: *] > > --ignore -i SERIALPORT Serial port(s) (or globs) to ignore. Defaults to MPFLASH_IGNORE. │
|
@@ -102,9 +155,9 @@ This file can contain a description of the board, which will be shown in the lis
|
|
102
155
|
description = "Blue Norwegian actuator"
|
103
156
|
```
|
104
157
|
|
105
|
-
If you want the board to be ignored by mpflash, you can add the following to the board_info.toml file:
|
158
|
+
If you want the board to be ignored by mpflash, no matter which serial port it is connected to, you can add the following to the `board_info.toml` file:
|
106
159
|
```toml
|
107
|
-
description = "Blue Norwegian
|
160
|
+
description = "Blue Norwegian actuator"
|
108
161
|
[mpflash]
|
109
162
|
ignore = true
|
110
163
|
```
|
@@ -1,36 +1,38 @@
|
|
1
1
|
mpflash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
mpflash/add_firmware.py,sha256=P1yaNUdExfzC_qnhE-P5ALZg1Uh7XT6Xf7NYccJP7Rc,4317
|
3
2
|
mpflash/ask_input.py,sha256=YUx65Xwj6dNPwWcbQiWG7U4wDW69zEdno2HcT1KwPBg,8886
|
4
|
-
mpflash/basicgit.py,sha256=
|
3
|
+
mpflash/basicgit.py,sha256=J1jWsM3QuYZLjj-e9yTsj7dLkxPvT4MFz3_YaEttyXg,10190
|
5
4
|
mpflash/bootloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
5
|
mpflash/bootloader/activate.py,sha256=orQOw4XTkXVZI-rMInRb0T5Wp3qA_BlzbJUA2gyBToU,2361
|
7
6
|
mpflash/bootloader/detect.py,sha256=OagP2QVWeLLWkZt2paqEF6r4_x3QDcBGNCPOWfMy9NQ,2686
|
8
7
|
mpflash/bootloader/manual.py,sha256=WYC4x-dxrSwVUfgnKTlu34pCzckrWJKZnWsARDocycI,3169
|
9
8
|
mpflash/bootloader/micropython.py,sha256=v_kZkvg0uWZDbMrT78gmiYHbD83QLdnrctvEClI8iRg,529
|
10
9
|
mpflash/bootloader/touch1200.py,sha256=VND7_YniS9Vx6WEaAxjI72RZZ6WBOwmBTsKJkbuaAHk,1105
|
11
|
-
mpflash/
|
12
|
-
mpflash/
|
13
|
-
mpflash/
|
14
|
-
mpflash/
|
15
|
-
mpflash/
|
16
|
-
mpflash/
|
17
|
-
mpflash/
|
18
|
-
mpflash/
|
10
|
+
mpflash/cli_add.py,sha256=hI-o-9hAGD3U8cbpXvy9Nuv1KHNTZ6mS57LC4BTBtj8,3495
|
11
|
+
mpflash/cli_download.py,sha256=EeAK5NcuJq0UeePSyHtPvBj_jEt92gh0jBmeNUcA7i0,3555
|
12
|
+
mpflash/cli_flash.py,sha256=SekC3goAu9_8UvMRMTEzIiiOK8js1GJRC6ymyA3BQWg,8820
|
13
|
+
mpflash/cli_group.py,sha256=RITn2u1_77jKptapX0Vz3oUriPtGMzLVmjZOtM5SP88,2686
|
14
|
+
mpflash/cli_list.py,sha256=dznrQrWQXvev20ai5AFvz2DFe3MNDR5RIrJmtvQou6A,2693
|
15
|
+
mpflash/cli_main.py,sha256=w5o3swYWDZUnYwIH46hGMCiFdPKVL1-R1YJRM-RSMiY,1496
|
16
|
+
mpflash/common.py,sha256=wO3BjG1wtbfi37wNWPnmLk3jNi7kRUl1vTzgJUOwm9I,6355
|
17
|
+
mpflash/config.py,sha256=3JIOuKcVIWzV3Y24n6ag_XJpSczMcCbd1fa6FpWGiz8,4143
|
18
|
+
mpflash/connected.py,sha256=SZvqbnLztJH-DBByjGrWT24S5DGTSevWSwYncH6dFqk,3707
|
19
|
+
mpflash/custom/__init__.py,sha256=l9RU9hRm9j7IuRgacw-gHYjA2Op-5prvRO5yyODhFMQ,5269
|
20
|
+
mpflash/custom/naming.py,sha256=uHQzFIDzuWQUNajeGSUcf_A-o7cxX37kfgXhzpFHNtk,3304
|
19
21
|
mpflash/db/__init__.py,sha256=wnIlO4nOXsPGXMbn2OCqHRsR-hUmtJsko8VdqjH3ZUE,45
|
20
|
-
mpflash/db/core.py,sha256=
|
21
|
-
mpflash/db/gather_boards.py,sha256=
|
22
|
-
mpflash/db/loader.py,sha256=
|
23
|
-
mpflash/db/meta.py,sha256=
|
24
|
-
mpflash/db/micropython_boards.zip,sha256=
|
25
|
-
mpflash/db/models.py,sha256=
|
22
|
+
mpflash/db/core.py,sha256=6Ftp-Br3fmVO5prsvR7oc-XfF3qLJrTOy2YKosQeQQk,5271
|
23
|
+
mpflash/db/gather_boards.py,sha256=r867g1U4xRRSGLie8cYtdotLyqy9Y7plxfqGQb-1ayw,3970
|
24
|
+
mpflash/db/loader.py,sha256=CDlTj2T6w9Ch9s3RHi00E1TbUhjFsgXAsYSQr5kliB0,4889
|
25
|
+
mpflash/db/meta.py,sha256=2pFTpFH-1zejGIDp2vs0hbX5rqUONt7B1WIvf8qBx5s,2248
|
26
|
+
mpflash/db/micropython_boards.zip,sha256=K9Y0P6JBYlgoY_mR6m_pEVtNxzO9JHaQlb_TCZACcPI,17059
|
27
|
+
mpflash/db/models.py,sha256=hZrum-nS-TNFaZAksApjxYMBgGKI_kJ-4oFxc8a4WRk,3572
|
26
28
|
mpflash/db/tools.py,sha256=6SEGfshNob4yRQ4h-Cj_xcWMRY28sbA8CWauNXV_uMI,814
|
27
|
-
mpflash/download/__init__.py,sha256=
|
29
|
+
mpflash/download/__init__.py,sha256=EQez0Gj70rgrcJDbWEMYlezQyGgD747ipwmB0nt9eUI,9575
|
28
30
|
mpflash/download/from_web.py,sha256=PVJDaFfYLJGXlPva5fExh4Yg2H7j3idyJEcfOiVVJBs,7608
|
29
|
-
mpflash/download/fwinfo.py,sha256=
|
30
|
-
mpflash/download/jid.py,sha256=
|
31
|
-
mpflash/downloaded.py,sha256=
|
31
|
+
mpflash/download/fwinfo.py,sha256=XGWOWoJ9cqRVtBAgzVYWCIWaBZpLK595SniXn7bzrRk,1844
|
32
|
+
mpflash/download/jid.py,sha256=V57M4K0uXXxBYOB4zOKkmXvUvEQdM_-w22LZ-iMIJSE,2344
|
33
|
+
mpflash/downloaded.py,sha256=xaeMYrTIGj_v4scUBojeJPL-U1kWJG-bdvkvJMbPh4Q,4218
|
32
34
|
mpflash/errors.py,sha256=IAidY3qkZsXy6Pm1rdmVFmGyg81ywHhse3itaPctA2w,247
|
33
|
-
mpflash/flash/__init__.py,sha256=
|
35
|
+
mpflash/flash/__init__.py,sha256=fkA_3pax9ZLckb14zFxATGk1YWMenpHBlvi66qJCIJA,3433
|
34
36
|
mpflash/flash/esp.py,sha256=4977E1hDqJ4-EIkLzwrUtgZuc0ZTD7NvP1PQZgZ2DoU,3227
|
35
37
|
mpflash/flash/stm32.py,sha256=jNgMpJaxUwtJ-v6VU1luD1t41AQprCUeNVCVEovxQe0,595
|
36
38
|
mpflash/flash/stm32_dfu.py,sha256=W-3JsRQyf3DduoIRXDmGZ35RogqtjQgcJnk-GOtQoLE,3090
|
@@ -39,20 +41,20 @@ mpflash/flash/uf2/boardid.py,sha256=U5wGM8VA3wEpUxQCMtuXpMZZomdVH8J_Zd5_GekUMuU,
|
|
39
41
|
mpflash/flash/uf2/linux.py,sha256=uTgqyS7C7xfQ25RrTcSUkt-m2u2Ks_o7bPLzIecPoC8,4355
|
40
42
|
mpflash/flash/uf2/macos.py,sha256=JTaIpqnR_0k4oSEvzs9amhmK-PMxUJyZLnZ_wZwxa-0,1228
|
41
43
|
mpflash/flash/uf2/uf2disk.py,sha256=4_P2l-kedM7VSliA2u706LQLxvu3xWSod1-lj-xjZis,298
|
42
|
-
mpflash/flash/uf2/windows.py,sha256=
|
43
|
-
mpflash/flash/worklist.py,sha256=
|
44
|
-
mpflash/list.py,sha256=
|
45
|
-
mpflash/logger.py,sha256=
|
44
|
+
mpflash/flash/uf2/windows.py,sha256=OEeskObPtpIE4a5NzYIcBqg3FkM5MGPGEa4lGGOfntY,1338
|
45
|
+
mpflash/flash/worklist.py,sha256=wf-R9yPsmcE54dnoPA29pEEzNPZI3JwY85V_DB0hXNI,6584
|
46
|
+
mpflash/list.py,sha256=IrJa3UBjhHHfStbb9fPVYA8JJzoFTyXtbcKGNRSH8sE,4132
|
47
|
+
mpflash/logger.py,sha256=XLu4VzMhMPlCdOo2HeS4GfyatE1swwwonV8c6a-GoD4,2651
|
46
48
|
mpflash/mpboard_id/__init__.py,sha256=Z6gDDWTCSKPp2fsuaUz80zgrklBR9XDlSLF9y_evR9A,391
|
47
49
|
mpflash/mpboard_id/alternate.py,sha256=ZhqfdA9sLJmyOfJ6WwK9wrzzUn6JQdkAreiL0q5XEQg,1913
|
48
|
-
mpflash/mpboard_id/board_id.py,sha256=
|
50
|
+
mpflash/mpboard_id/board_id.py,sha256=xdOna_ZpTHVnsV8XQ5rrTIRCuzU69HD_ZJoY19d7dCE,1894
|
49
51
|
mpflash/mpboard_id/board_info.json,sha256=A3ZIt38KvAy2NMB5srHorSBd3Q3wOZIXufWiIs3XLrs,1019745
|
50
52
|
mpflash/mpboard_id/board_info.zip,sha256=-2bnQGRsIQuJUfz-7_-GQ8pMWJ1evhCez6yfjhXocNw,23213
|
51
|
-
mpflash/mpboard_id/known.py,sha256=
|
53
|
+
mpflash/mpboard_id/known.py,sha256=t-oREfW5P5Zue5zbte7WB9e7-mpZBF-NfHGTEUsOVLM,3521
|
52
54
|
mpflash/mpboard_id/resolve.py,sha256=5KCZ0Tcg3FYZ3HK_zux5EguwoSC2E03kCpW2fh4rN2A,779
|
53
|
-
mpflash/mpremoteboard/__init__.py,sha256=
|
55
|
+
mpflash/mpremoteboard/__init__.py,sha256=4OIKAry-GeYUSgnEcs5TRb0xea0bstVQCOb28MjLDyk,14210
|
54
56
|
mpflash/mpremoteboard/mpy_fw_info.py,sha256=ZDEPJN9XJnoG_oeWcLNiLJAD5bkVX2yI_j4K7msUxWM,5196
|
55
|
-
mpflash/mpremoteboard/runner.py,sha256=
|
57
|
+
mpflash/mpremoteboard/runner.py,sha256=H5f5JBcRnpF06Ui3xDY7IoDdO2Hex9lsI_eGMq5c2A4,4945
|
56
58
|
mpflash/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
59
|
mpflash/vendor/board_database.py,sha256=Cb8fEhJaZ2siMkLPW5rPwV9yzBsTtKGOqWUd9TxNgFM,8763
|
58
60
|
mpflash/vendor/click_aliases.py,sha256=adLhqLxNpJEPjSCIRSTkR-QzSgavGFKT0cwRbjxpzRU,5395
|
@@ -62,8 +64,8 @@ mpflash/vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2,sha256=QuPMppq
|
|
62
64
|
mpflash/vendor/pydfu.py,sha256=KD1RHHuhvhWi-l1UB6GyggkxouDKtZgkG4ivRbIfwC4,21264
|
63
65
|
mpflash/vendor/readme.md,sha256=BQ7Uxf8joeYMjTUuSLLBG49ob6a9MgFPIEwuc72-Mfw,415
|
64
66
|
mpflash/versions.py,sha256=HuujLNdMKY_mQXyEqwXVHcU8nbuXeBiWP2TMA5JQhr4,4884
|
65
|
-
mpflash-1.25.
|
66
|
-
mpflash-1.25.
|
67
|
-
mpflash-1.25.
|
68
|
-
mpflash-1.25.
|
69
|
-
mpflash-1.25.
|
67
|
+
mpflash-1.25.2.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
|
68
|
+
mpflash-1.25.2.dist-info/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
|
69
|
+
mpflash-1.25.2.dist-info/METADATA,sha256=FkHpU3o9_3njLQFFOODMRmgFcoejObaRF9w2JoJ3mrM,27149
|
70
|
+
mpflash-1.25.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
71
|
+
mpflash-1.25.2.dist-info/RECORD,,
|