mpflash 0.6.0__py3-none-any.whl → 0.7.1__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 +18 -3
- mpflash/cli_download.py +16 -12
- mpflash/cli_flash.py +16 -7
- mpflash/cli_group.py +1 -1
- mpflash/cli_list.py +2 -2
- mpflash/cli_main.py +4 -3
- mpflash/download.py +11 -8
- mpflash/flash_uf2.py +1 -1
- mpflash/list.py +29 -12
- mpflash/mpremoteboard/__init__.py +6 -5
- mpflash/mpremoteboard/runner.py +12 -12
- mpflash/worklist.py +1 -1
- {mpflash-0.6.0.dist-info → mpflash-0.7.1.dist-info}/METADATA +40 -33
- {mpflash-0.6.0.dist-info → mpflash-0.7.1.dist-info}/RECORD +17 -17
- {mpflash-0.6.0.dist-info → mpflash-0.7.1.dist-info}/LICENSE +0 -0
- {mpflash-0.6.0.dist-info → mpflash-0.7.1.dist-info}/WHEEL +0 -0
- {mpflash-0.6.0.dist-info → mpflash-0.7.1.dist-info}/entry_points.txt +0 -0
mpflash/ask_input.py
CHANGED
@@ -12,7 +12,7 @@ from typing import Dict, List, Sequence, Tuple, Union
|
|
12
12
|
from loguru import logger as log
|
13
13
|
|
14
14
|
from mpflash.config import config
|
15
|
-
from mpflash.mpboard_id import known_stored_boards, local_mp_ports
|
15
|
+
from mpflash.mpboard_id import get_stored_boards_for_port, known_stored_boards, local_mp_ports
|
16
16
|
from mpflash.mpremoteboard import MPRemoteBoard
|
17
17
|
from mpflash.vendor.versions import micropython_versions
|
18
18
|
|
@@ -131,7 +131,7 @@ def filter_matching_boards(answers: dict) -> Sequence[Tuple[str, str]]:
|
|
131
131
|
# Get the values of the dictionary, which are the unique items from the original list
|
132
132
|
some_boards = list(unique_dict.values())
|
133
133
|
else:
|
134
|
-
some_boards = [("No boards found", "")]
|
134
|
+
some_boards = [(f"No {answers['port']} boards found for version(s) {_versions}", "")]
|
135
135
|
return some_boards
|
136
136
|
|
137
137
|
|
@@ -186,12 +186,27 @@ def ask_versions(questions: list, *, action: str):
|
|
186
186
|
"""
|
187
187
|
# import only when needed to reduce load time
|
188
188
|
import inquirer
|
189
|
+
import inquirer.errors
|
189
190
|
|
190
191
|
input_ux = inquirer.Checkbox if action == "download" else inquirer.List
|
191
192
|
mp_versions: List[str] = micropython_versions()
|
192
193
|
mp_versions = [v for v in mp_versions if "preview" not in v]
|
194
|
+
|
195
|
+
# remove the versions for which there are no known boards in the board_info.json
|
196
|
+
# todo: this may be a little slow
|
197
|
+
mp_versions = [v for v in mp_versions if get_stored_boards_for_port("stm32", [v])]
|
198
|
+
|
193
199
|
mp_versions.append("preview")
|
194
200
|
mp_versions.reverse() # newest first
|
201
|
+
|
202
|
+
def at_least_one_validation(answers, current) -> bool:
|
203
|
+
if not current:
|
204
|
+
raise inquirer.errors.ValidationError("", reason="Please select at least one version")
|
205
|
+
if isinstance(current, list):
|
206
|
+
if not any(current):
|
207
|
+
raise inquirer.errors.ValidationError("", reason="Please select at least one version")
|
208
|
+
return True
|
209
|
+
|
195
210
|
questions.append(
|
196
211
|
input_ux(
|
197
212
|
# inquirer.List(
|
@@ -201,7 +216,7 @@ def ask_versions(questions: list, *, action: str):
|
|
201
216
|
# hints=["Use space to select multiple options"],
|
202
217
|
choices=mp_versions,
|
203
218
|
autocomplete=True,
|
204
|
-
validate=
|
219
|
+
validate=at_least_one_validation,
|
205
220
|
)
|
206
221
|
)
|
207
222
|
|
mpflash/cli_download.py
CHANGED
@@ -6,6 +6,7 @@ from typing import List, Tuple
|
|
6
6
|
import rich_click as click
|
7
7
|
from loguru import logger as log
|
8
8
|
|
9
|
+
from mpflash.errors import MPFlashError
|
9
10
|
from mpflash.mpboard_id import find_stored_board
|
10
11
|
from mpflash.vendor.versions import clean_version
|
11
12
|
|
@@ -62,9 +63,7 @@ from .download import download
|
|
62
63
|
show_default=True,
|
63
64
|
help="""Force download of firmware even if it already exists.""",
|
64
65
|
)
|
65
|
-
def cli_download(
|
66
|
-
**kwargs,
|
67
|
-
):
|
66
|
+
def cli_download(**kwargs) -> int:
|
68
67
|
params = DownloadParams(**kwargs)
|
69
68
|
params.versions = list(params.versions)
|
70
69
|
params.boards = list(params.boards)
|
@@ -77,18 +76,23 @@ def cli_download(
|
|
77
76
|
|
78
77
|
params = ask_missing_params(params, action="download")
|
79
78
|
if not params: # Cancelled by user
|
80
|
-
|
79
|
+
return 2
|
81
80
|
params.versions = [clean_version(v, drop_v=True) for v in params.versions]
|
82
81
|
assert isinstance(params, DownloadParams)
|
83
82
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
83
|
+
try:
|
84
|
+
download(
|
85
|
+
params.fw_folder,
|
86
|
+
params.ports,
|
87
|
+
params.boards,
|
88
|
+
params.versions,
|
89
|
+
params.force,
|
90
|
+
params.clean,
|
91
|
+
)
|
92
|
+
return 0
|
93
|
+
except MPFlashError as e:
|
94
|
+
log.error(f"{e}")
|
95
|
+
return 1
|
92
96
|
|
93
97
|
|
94
98
|
def connected_ports_boards() -> Tuple[List[str], List[str]]:
|
mpflash/cli_flash.py
CHANGED
@@ -13,7 +13,7 @@ from .cli_group import cli
|
|
13
13
|
from .cli_list import show_mcus
|
14
14
|
from .config import config
|
15
15
|
from .flash import flash_list
|
16
|
-
from .worklist import WorkList, full_auto_worklist, manual_worklist, single_auto_worklist
|
16
|
+
from .worklist import MPRemoteBoard, WorkList, full_auto_worklist, manual_worklist, single_auto_worklist
|
17
17
|
|
18
18
|
# #########################################################################################################
|
19
19
|
# CLI
|
@@ -28,7 +28,7 @@ from .worklist import WorkList, full_auto_worklist, manual_worklist, single_auto
|
|
28
28
|
"--firmware",
|
29
29
|
"-f",
|
30
30
|
"fw_folder",
|
31
|
-
type=click.Path(
|
31
|
+
type=click.Path(file_okay=False, dir_okay=True, path_type=Path),
|
32
32
|
default=config.firmware_folder,
|
33
33
|
show_default=True,
|
34
34
|
help="The folder to retrieve the firmware from.",
|
@@ -91,7 +91,7 @@ from .worklist import WorkList, full_auto_worklist, manual_worklist, single_auto
|
|
91
91
|
show_default=True,
|
92
92
|
help="""Enter micropython bootloader mode before flashing.""",
|
93
93
|
)
|
94
|
-
def cli_flash_board(**kwargs):
|
94
|
+
def cli_flash_board(**kwargs) -> int:
|
95
95
|
# version to versions, board to boards
|
96
96
|
kwargs["versions"] = [kwargs.pop("version")] if kwargs["version"] != None else []
|
97
97
|
if kwargs["board"] is None:
|
@@ -104,6 +104,11 @@ def cli_flash_board(**kwargs):
|
|
104
104
|
if not params.boards or params.boards == []:
|
105
105
|
# nothing specified - detect connected boards
|
106
106
|
params.ports, params.boards = connected_ports_boards()
|
107
|
+
if params.boards == []:
|
108
|
+
# No MicroPython boards detected, but it could be unflashed or not in bootloader mode
|
109
|
+
# Ask for serial port and board_id to flash
|
110
|
+
params.serial = "?"
|
111
|
+
params.boards = ["?"]
|
107
112
|
else:
|
108
113
|
for board_id in params.boards:
|
109
114
|
if board_id == "":
|
@@ -122,7 +127,7 @@ def cli_flash_board(**kwargs):
|
|
122
127
|
# Ask for missing input if needed
|
123
128
|
params = ask_missing_params(params, action="flash")
|
124
129
|
if not params: # Cancelled by user
|
125
|
-
|
130
|
+
return 2
|
126
131
|
# TODO: Just in time Download of firmware
|
127
132
|
|
128
133
|
assert isinstance(params, FlashParams)
|
@@ -130,9 +135,9 @@ def cli_flash_board(**kwargs):
|
|
130
135
|
if len(params.versions) > 1:
|
131
136
|
log.error(f"Only one version can be flashed at a time, not {params.versions}")
|
132
137
|
raise MPFlashError("Only one version can be flashed at a time")
|
133
|
-
if len(params.boards) > 1:
|
134
|
-
|
135
|
-
|
138
|
+
# if len(params.boards) > 1:
|
139
|
+
# log.error(f"Only one board can be flashed at a time, not {params.boards}")
|
140
|
+
# raise MPFlashError("Only one board can be flashed at a time")
|
136
141
|
|
137
142
|
params.versions = [clean_version(v) for v in params.versions]
|
138
143
|
worklist: WorkList = []
|
@@ -163,3 +168,7 @@ def cli_flash_board(**kwargs):
|
|
163
168
|
):
|
164
169
|
log.info(f"Flashed {len(flashed)} boards")
|
165
170
|
show_mcus(flashed, title="Updated boards after flashing")
|
171
|
+
return 0
|
172
|
+
else:
|
173
|
+
log.error("No boards were flashed")
|
174
|
+
return 1
|
mpflash/cli_group.py
CHANGED
mpflash/cli_list.py
CHANGED
@@ -26,7 +26,7 @@ from .logger import make_quiet
|
|
26
26
|
show_default=True,
|
27
27
|
help="""Show progress""",
|
28
28
|
)
|
29
|
-
def cli_list_mcus(as_json: bool, progress: bool = True):
|
29
|
+
def cli_list_mcus(as_json: bool, progress: bool = True) -> int:
|
30
30
|
"""List the connected MCU boards, and output in a nice table or json."""
|
31
31
|
if as_json:
|
32
32
|
# avoid noise in json output
|
@@ -38,4 +38,4 @@ def cli_list_mcus(as_json: bool, progress: bool = True):
|
|
38
38
|
progress = False
|
39
39
|
if progress:
|
40
40
|
show_mcus(conn_mcus, refresh=False)
|
41
|
-
return conn_mcus
|
41
|
+
return 0 if conn_mcus else 1
|
mpflash/cli_main.py
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
# import rich_click as click
|
4
4
|
|
5
|
+
import click
|
6
|
+
|
5
7
|
from .cli_download import cli_download
|
6
8
|
from .cli_flash import cli_flash_board
|
7
9
|
from .cli_group import cli
|
8
10
|
from .cli_list import cli_list_mcus
|
9
11
|
|
10
|
-
# from loguru import logger as log
|
11
|
-
|
12
12
|
|
13
13
|
def mpflash():
|
14
14
|
cli.add_command(cli_flash_board)
|
@@ -16,7 +16,8 @@ def mpflash():
|
|
16
16
|
cli.add_command(cli_download)
|
17
17
|
# cli(auto_envvar_prefix="MPFLASH")
|
18
18
|
try:
|
19
|
-
|
19
|
+
result = cli(standalone_mode=False)
|
20
|
+
exit(result)
|
20
21
|
except AttributeError as e:
|
21
22
|
print(f"Error: {e}")
|
22
23
|
exit(-1)
|
mpflash/download.py
CHANGED
@@ -19,6 +19,7 @@ from loguru import logger as log
|
|
19
19
|
from rich.progress import track
|
20
20
|
|
21
21
|
from mpflash.common import PORT_FWTYPES
|
22
|
+
from mpflash.errors import MPFlashError
|
22
23
|
|
23
24
|
jsonlines.ujson = None # type: ignore
|
24
25
|
# #########################################################################################################
|
@@ -165,7 +166,7 @@ def download_firmwares(
|
|
165
166
|
*,
|
166
167
|
force: bool = False,
|
167
168
|
clean: bool = True,
|
168
|
-
):
|
169
|
+
) -> int:
|
169
170
|
skipped = downloaded = 0
|
170
171
|
if versions is None:
|
171
172
|
versions = []
|
@@ -200,6 +201,7 @@ def download_firmwares(
|
|
200
201
|
writer.write(board)
|
201
202
|
downloaded += 1
|
202
203
|
log.info(f"Downloaded {downloaded} firmwares, skipped {skipped} existing files.")
|
204
|
+
return downloaded + skipped
|
203
205
|
|
204
206
|
|
205
207
|
def get_firmware_list(ports: List[str], boards: List[str], versions: List[str], clean: bool):
|
@@ -246,7 +248,7 @@ def download(
|
|
246
248
|
versions: List[str],
|
247
249
|
force: bool,
|
248
250
|
clean: bool,
|
249
|
-
):
|
251
|
+
) -> int:
|
250
252
|
"""
|
251
253
|
Downloads firmware files based on the specified destination, ports, boards, versions, force flag, and clean flag.
|
252
254
|
|
@@ -259,19 +261,20 @@ def download(
|
|
259
261
|
clean : A flag indicating whether to perform a clean download.
|
260
262
|
|
261
263
|
Returns:
|
262
|
-
|
264
|
+
int: The number of downloaded firmware files.
|
263
265
|
|
264
266
|
Raises:
|
265
|
-
|
267
|
+
MPFlashError : If no boards are found or specified.
|
266
268
|
|
267
269
|
"""
|
268
270
|
if not boards:
|
269
271
|
log.critical("No boards found, please connect a board or specify boards to download firmware for.")
|
270
|
-
|
272
|
+
raise MPFlashError("No boards found")
|
271
273
|
# versions = [clean_version(v, drop_v=True) for v in versions] # remove leading v from version
|
272
274
|
try:
|
273
275
|
destination.mkdir(exist_ok=True, parents=True)
|
274
276
|
except (PermissionError, FileNotFoundError) as e:
|
275
|
-
log.critical(f"Could not create folder {destination}
|
276
|
-
|
277
|
-
|
277
|
+
log.critical(f"Could not create folder {destination}")
|
278
|
+
raise MPFlashError(f"Could not create folder {destination}") from e
|
279
|
+
|
280
|
+
return download_firmwares(destination, ports, boards, versions, force=force, clean=clean)
|
mpflash/flash_uf2.py
CHANGED
@@ -56,6 +56,6 @@ def flash_uf2(mcu: MPRemoteBoard, fw_file: Path, erase: bool) -> Optional[MPRemo
|
|
56
56
|
log.success("Done copying, resetting the board and wait for it to restart")
|
57
57
|
if sys.platform in ["linux", "darwin"]:
|
58
58
|
dismount_uf2()
|
59
|
-
for _ in track(range(5 + 2)):
|
59
|
+
for _ in track(range(5 + 2), description="Waiting for the board to restart", transient=True):
|
60
60
|
time.sleep(1) # 5 secs to short on linux
|
61
61
|
return mcu
|
mpflash/list.py
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
from typing import List
|
2
2
|
|
3
3
|
from rich import print
|
4
|
-
from rich.progress import track
|
5
|
-
from rich.table import Table
|
4
|
+
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn, track
|
5
|
+
from rich.table import Column, Table
|
6
6
|
|
7
7
|
from mpflash.mpremoteboard import MPRemoteBoard
|
8
|
+
from mpflash.vendor.versions import clean_version
|
8
9
|
|
9
10
|
from .config import config
|
10
11
|
from .logger import console
|
11
12
|
|
13
|
+
rp_spinner = SpinnerColumn(finished_text="✅")
|
14
|
+
rp_text = TextColumn("{task.description} {task.fields[device]}", table_column=Column())
|
15
|
+
rp_bar = BarColumn(bar_width=None, table_column=Column())
|
16
|
+
|
12
17
|
|
13
18
|
def list_mcus(bluetooth: bool = False):
|
14
19
|
"""
|
@@ -21,12 +26,24 @@ def list_mcus(bluetooth: bool = False):
|
|
21
26
|
"""
|
22
27
|
conn_mcus = [MPRemoteBoard(sp) for sp in MPRemoteBoard.connected_boards(bluetooth) if sp not in config.ignore_ports]
|
23
28
|
|
24
|
-
|
29
|
+
# a lot of boilerplate to show a progress bar with the comport currenlty scanned
|
30
|
+
with Progress(rp_spinner, rp_text, rp_bar, TimeElapsedColumn()) as progress:
|
31
|
+
tsk_scan = progress.add_task("[green]Scanning", visible=False, total=None)
|
32
|
+
progress.tasks[tsk_scan].fields["device"] = "..."
|
33
|
+
progress.tasks[tsk_scan].visible = True
|
34
|
+
progress.start_task(tsk_scan)
|
25
35
|
try:
|
26
|
-
mcu
|
27
|
-
|
28
|
-
|
29
|
-
|
36
|
+
for mcu in conn_mcus:
|
37
|
+
progress.update(tsk_scan, device=mcu.serialport.replace("/dev/", ""))
|
38
|
+
try:
|
39
|
+
mcu.get_mcu_info()
|
40
|
+
except ConnectionError as e:
|
41
|
+
print(f"Error: {e}")
|
42
|
+
continue
|
43
|
+
finally:
|
44
|
+
# transient
|
45
|
+
progress.stop_task(tsk_scan)
|
46
|
+
progress.tasks[tsk_scan].visible = False
|
30
47
|
return conn_mcus
|
31
48
|
|
32
49
|
|
@@ -38,11 +55,10 @@ def show_mcus(
|
|
38
55
|
"""Show the list of connected boards in a nice table"""
|
39
56
|
table = Table(
|
40
57
|
title=title,
|
41
|
-
title_style="
|
42
|
-
header_style="bold
|
58
|
+
title_style="magenta",
|
59
|
+
header_style="bold magenta",
|
43
60
|
collapse_padding=True,
|
44
61
|
width=110,
|
45
|
-
row_styles=["blue", "yellow"],
|
46
62
|
)
|
47
63
|
table.add_column("Serial", overflow="fold")
|
48
64
|
table.add_column("Family")
|
@@ -59,14 +75,15 @@ def show_mcus(
|
|
59
75
|
mcu.get_mcu_info()
|
60
76
|
except ConnectionError:
|
61
77
|
continue
|
78
|
+
description = f"[italic bright_cyan]{mcu.description}" if mcu.description else ""
|
62
79
|
table.add_row(
|
63
80
|
mcu.serialport.replace("/dev/", ""),
|
64
81
|
mcu.family,
|
65
82
|
mcu.port,
|
66
|
-
f"{mcu.board}\n{
|
83
|
+
f"{mcu.board}\n{description}".strip(),
|
67
84
|
# mcu.variant,
|
68
85
|
mcu.cpu,
|
69
|
-
mcu.version,
|
86
|
+
clean_version(mcu.version),
|
70
87
|
mcu.build,
|
71
88
|
)
|
72
89
|
console.print(table)
|
@@ -65,8 +65,9 @@ class MPRemoteBoard:
|
|
65
65
|
|
66
66
|
@staticmethod
|
67
67
|
def connected_boards(bluetooth: bool = False) -> List[str]:
|
68
|
+
# TODO: rename to connected_comports
|
68
69
|
"""
|
69
|
-
Get a list of connected
|
70
|
+
Get a list of connected comports.
|
70
71
|
|
71
72
|
Parameters:
|
72
73
|
- bluetooth (bool): Whether to include Bluetooth ports. Default is False.
|
@@ -74,14 +75,14 @@ class MPRemoteBoard:
|
|
74
75
|
Returns:
|
75
76
|
- List[str]: A list of connected board ports.
|
76
77
|
"""
|
77
|
-
|
78
|
+
comports = serial.tools.list_ports.comports()
|
78
79
|
|
79
80
|
if not bluetooth:
|
80
81
|
# filter out bluetooth ports
|
81
|
-
|
82
|
-
|
82
|
+
comports = [p for p in comports if "bluetooth" not in p.description.lower()]
|
83
|
+
comports = [p for p in comports if "BTHENUM" not in p.hwid]
|
83
84
|
|
84
|
-
return sorted([p.device for p in
|
85
|
+
return sorted([p.device for p in comports])
|
85
86
|
|
86
87
|
@retry(stop=stop_after_attempt(RETRIES), wait=wait_fixed(1), reraise=True) # type: ignore ## retry_error_cls=ConnectionError,
|
87
88
|
def get_mcu_info(self, timeout: int = 2):
|
mpflash/mpremoteboard/runner.py
CHANGED
@@ -21,6 +21,17 @@ class LogTags:
|
|
21
21
|
ignore_tags: LogTagList
|
22
22
|
|
23
23
|
|
24
|
+
DEFAULT_RESET_TAGS = [
|
25
|
+
# ESP32 reset causes
|
26
|
+
"rst cause:1, boot mode:", # 1 -> hardware watch dog reset
|
27
|
+
"rst cause:2, boot mode:", # 2 -> software watch dog reset (From an exception)
|
28
|
+
"rst cause:3, boot mode:", # 3 -> software watch dog reset system_restart (Possibly unfed watchdog got angry)
|
29
|
+
"rst cause:4, boot mode:", # 4 -> soft restart (Possibly with a restart command)
|
30
|
+
"boot.esp32: PRO CPU has been reset by WDT.",
|
31
|
+
"rst:0x10 (RTCWDT_RTC_RESET)",
|
32
|
+
]
|
33
|
+
|
34
|
+
|
24
35
|
def run(
|
25
36
|
cmd: List[str],
|
26
37
|
timeout: int = 60,
|
@@ -57,18 +68,7 @@ def run(
|
|
57
68
|
The return code and the output as a list of strings
|
58
69
|
"""
|
59
70
|
if not reset_tags:
|
60
|
-
reset_tags =
|
61
|
-
"rst cause:1, boot mode:",
|
62
|
-
"rst cause:2, boot mode:",
|
63
|
-
"rst cause:3, boot mode:",
|
64
|
-
"rst cause:4, boot mode:",
|
65
|
-
]
|
66
|
-
# 0 -> normal startup by power on
|
67
|
-
# 1 -> hardware watch dog reset
|
68
|
-
# 2 -> software watch dog reset (From an exception)
|
69
|
-
# 3 -> software watch dog reset system_restart (Possibly unfed watchdog got angry)
|
70
|
-
# 4 -> soft restart (Possibly with a restart command)
|
71
|
-
# 5 -> wake up from deep-sleep
|
71
|
+
reset_tags = DEFAULT_RESET_TAGS
|
72
72
|
if not error_tags:
|
73
73
|
error_tags = ["Traceback ", "Error: ", "Exception: ", "ERROR :", "CRIT :"]
|
74
74
|
if not warning_tags:
|
mpflash/worklist.py
CHANGED
@@ -24,7 +24,7 @@ def auto_update(
|
|
24
24
|
*,
|
25
25
|
selector: Optional[Dict[str, str]] = None,
|
26
26
|
) -> WorkList:
|
27
|
-
"""Builds a list of boards to update based on the connected boards and the firmware
|
27
|
+
"""Builds a list of boards to update based on the connected boards and the firmwares available locally in the firmware folder.
|
28
28
|
|
29
29
|
Args:
|
30
30
|
conn_boards (List[MPRemoteBoard]): List of connected boards
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: mpflash
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.1
|
4
4
|
Summary: Flash and download tool for MicroPython firmwares
|
5
5
|
Home-page: https://github.com/Josverl/micropython-stubber/blob/main/src/mpflash/README.md
|
6
6
|
License: MIT
|
@@ -32,23 +32,23 @@ Requires-Dist: pygithub (>=2.1.1,<3.0.0)
|
|
32
32
|
Requires-Dist: pyusb (>=1.2.1,<2.0.0)
|
33
33
|
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
34
34
|
Requires-Dist: rich-click (>=1.7.3,<2.0.0)
|
35
|
-
Requires-Dist: strip-ansi (>=0.1.1,<0.2.0)
|
36
35
|
Requires-Dist: tenacity (==8.2.3)
|
37
36
|
Project-URL: Repository, https://github.com/Josverl/micropython-stubber
|
38
37
|
Description-Content-Type: text/markdown
|
39
38
|
|
40
|
-
#
|
41
|
-
mpflash is a command-line tool for working with MicroPython firmware. It provides various features to help you develop, build, and manage your MicroPython projects.
|
39
|
+
# MPFLASH
|
42
40
|
|
43
|
-
|
41
|
+
`mpflash` is a command-line tool for working with MicroPython firmware. It provides features to help you flash and update Micropython on one or more .
|
44
42
|
|
45
|
-
|
43
|
+
This tool was initially created to be used in a CI/CD pipeline to automate the process of downloading and flashing MicroPython firmware to multiple boards, but it has been extend with a TUI to me be used for manual downloadig, flashing and development.
|
44
|
+
|
45
|
+
`mpflash` has been tested on Windows x64, Linux X64, but not (yet) macOS.
|
46
|
+
Tested ports: `rp2`, `samd`, `esp32`, `esp32s3`, `esp32c3`, `esp8266` and `stm32`
|
46
47
|
|
47
48
|
## Features
|
48
49
|
1. List the connected boards including their firmware details, in a tabular or json format
|
49
|
-
2. Download MicroPython firmware for
|
50
|
-
3. Flash one or all connected MicroPython boards with a specific firmware or version.
|
51
|
-
Tested ports: rp2, samd, esp32, esp32s3, esp8266 and stm32
|
50
|
+
2. Download MicroPython firmware for versions, and matching a specified board or matches your current attached board.
|
51
|
+
3. Flash one or all connected MicroPython boards with a specific firmware or version.
|
52
52
|
|
53
53
|
## Installation
|
54
54
|
To install mpflash, you can use pip: `pip install mpflash`
|
@@ -69,40 +69,40 @@ On Windows this will not be an issue, but on Linux you can use udev rules to gi
|
|
69
69
|
[See the stm32_permissions documentation](./stm32_udev_rules.md) for more information.
|
70
70
|
|
71
71
|
|
72
|
-
##
|
72
|
+
## Detailed usage
|
73
73
|
You can list the connected boards using the following command:
|
74
74
|
```bash
|
75
75
|
$ mpflash list
|
76
76
|
D:\MyPython\micropython-stubber> mpflash list
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
│
|
83
|
-
│
|
84
|
-
│
|
85
|
-
│
|
86
|
-
│
|
87
|
-
|
88
|
-
└────────┴─────────────┴─────────┴────────────────────┴─────────────┴────────────────┴───────┘
|
77
|
+
Connected boards
|
78
|
+
┏━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━┓
|
79
|
+
┃ Serial ┃Family ┃Port ┃Board ┃CPU ┃Version ┃build ┃
|
80
|
+
┡━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━┩
|
81
|
+
│ COM21 │micropython │rp2 │RPI_PICO │RP2040 │v1.23.0-preview │ 236 │
|
82
|
+
│ │ │ │Raspberry Pi Pico with RP2040 │ │ │ │
|
83
|
+
│ COM23 │micropython │rp2 │RPI_PICO_W │RP2040 │v1.23.0-preview │ 176 │
|
84
|
+
│ │ │ │Raspberry Pi Pico W with RP2040 │ │ │ │
|
85
|
+
│ COM9 │micropython │rp2 │ARDUINO_NANO_RP2040_CONNECT │RP2040 │v1.23.0-preview │ 341 │
|
86
|
+
│ │ │ │Arduino Nano RP2040 Connect with RP2040 │ │ │ │
|
87
|
+
└─────────┴─────────────┴──────┴───────────────────────────────────────────┴────────┴─────────────────┴──────┘
|
89
88
|
```
|
89
|
+
## Download the firmware
|
90
90
|
|
91
|
-
|
91
|
+
To download the MicroPython firmware for some boards, use the following command:
|
92
|
+
- `mpflash download` download the latest stable firmware for all connected boards
|
93
|
+
- `mpflash download --version preview` download the current preview for all connected boards
|
94
|
+
- `mpflash download --board ESP8266_GENERIC --board SEEED_WIO_TERMINAL` download these specific boards
|
95
|
+
- `mpflash download --version ? --board ?` prompt to select a specific version and board to download
|
92
96
|
|
93
|
-
|
94
|
-
# download the firmware
|
95
|
-
$ mpflash download --board ESP8266_GENERIC --board SEEED_WIO_TERMINAL
|
96
|
-
```
|
97
|
-
This will download the latest stable version of the MicroPython firmware for the boards and save it in the `firmware` directory.
|
97
|
+
These will try to download the prebuilt MicroPython firmware for the boards from https://micropython.org/download/ and save it in your downloads folder in the `firmware` directory.
|
98
98
|
The stable version (default) is determined based on the most recent published release,
|
99
|
-
other
|
99
|
+
other versions are `--version preview` and `--version x.y.z` to download the latest preview or version x.y.z respectively.
|
100
100
|
|
101
|
-
|
101
|
+
By default the firmware will be downloaded to your OS's preferred `Downloads/firmware` folder, but you can speciy a different directory using the `--dir` option.
|
102
102
|
|
103
|
-
```bash
|
104
103
|
The directory structure will be something like this:
|
105
|
-
|
104
|
+
|
105
|
+
``` text
|
106
106
|
Downloads/firmware
|
107
107
|
| firmware.jsonl
|
108
108
|
+---esp8266
|
@@ -113,9 +113,16 @@ Downloads/firmware
|
|
113
113
|
\---samd
|
114
114
|
SEEED_WIO_TERMINAL-v1.22.2.uf2
|
115
115
|
```
|
116
|
-
|
116
|
+
|
117
|
+
## Flashing the firmware
|
118
|
+
After you have downloaded a firmware you can flash the firmware to a board using the following command: `mpflash flash`
|
117
119
|
This will (try to) autodetect the connected boards, and determine the correct firmware to flash to each board.
|
118
120
|
|
121
|
+
- `mpflash flash` will flash the latest stable firmware to all connected boards.
|
122
|
+
- `mpflash flash --serial ? --board ?` will prompt to select a specific serial port and board to flash. (the firmware must be dowloaded earlier)
|
123
|
+
|
124
|
+
|
125
|
+
### Flashing all connected boards with the latest stable firmware
|
119
126
|
```bash
|
120
127
|
> mpflash flash
|
121
128
|
22:15:55 | ℹ️ - Using latest stable version: v1.22.2
|
@@ -1,13 +1,13 @@
|
|
1
1
|
mpflash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
mpflash/ask_input.py,sha256=
|
3
|
-
mpflash/cli_download.py,sha256=
|
4
|
-
mpflash/cli_flash.py,sha256=
|
5
|
-
mpflash/cli_group.py,sha256=
|
6
|
-
mpflash/cli_list.py,sha256=
|
7
|
-
mpflash/cli_main.py,sha256=
|
2
|
+
mpflash/ask_input.py,sha256=_LlatVyrWbY1Q4TDn8TWXJO5s22q_bGl3NXmdt13jxU,8442
|
3
|
+
mpflash/cli_download.py,sha256=RNEsk1eMqzKCf9_sUPZQkDnzw6w-8L0Jnl6gDQup2Tc,3266
|
4
|
+
mpflash/cli_flash.py,sha256=DTZ1mQSL31aEr3ROGIGWzzkiir4MRSqXdwq2p4ArDWE,5847
|
5
|
+
mpflash/cli_group.py,sha256=nL3H06PHm_XUDlMuRyjgmTYeLnkrLa9mKDdahYw-KRo,1967
|
6
|
+
mpflash/cli_list.py,sha256=KIlEeqcIIBf0g-emS43fzKspUy6fn9TUuFl0u00XaK8,1024
|
7
|
+
mpflash/cli_main.py,sha256=BgqkDeEV0LBdT_Xn_Ay3zQOVJ-73pWSA4ngRf9KxGpw,656
|
8
8
|
mpflash/common.py,sha256=lucFGMLl03qz-5Ic2XVv4g5XVt6hloUU6N5v0tSaUYE,1049
|
9
9
|
mpflash/config.py,sha256=G6TxliEGxoYXy1SHQYBKgywnKccz9QzD3mGq_Vv1frg,419
|
10
|
-
mpflash/download.py,sha256=
|
10
|
+
mpflash/download.py,sha256=_yYENI7oew4tD51xEer1Ohv2B3LHrGg1lIF98LWDMCY,10991
|
11
11
|
mpflash/downloaded.py,sha256=ADMJqZn7WVcU-Rm2X6RqA8ejtBNBYXcpwxVyT3v7r6s,3803
|
12
12
|
mpflash/errors.py,sha256=Q5LR12Wo8iUCg5n_qq4GjdBdBflbvCOdKsRJ5InYRfI,96
|
13
13
|
mpflash/flash.py,sha256=YGYXuNNbjro4QvZmpwpLCo86nFsh4UxWrOJHOowUYDY,2490
|
@@ -15,26 +15,26 @@ mpflash/flash_esp.py,sha256=TjBOk2y1eLrcE8T3iYGypsiskPX7BFNfxYmCuUo_3v4,2316
|
|
15
15
|
mpflash/flash_stm32.py,sha256=d4BoQl3a9Tchnvn2ZTuq2MpYBB4MTaRukwtEncI95k0,823
|
16
16
|
mpflash/flash_stm32_cube.py,sha256=w7aGWjReeWUKl0Q3ZjXH8BRqNO1Tk9AO7gtRNUg1c9Y,3970
|
17
17
|
mpflash/flash_stm32_dfu.py,sha256=G70EZodWb-aRi507Jxbys-VEwbBGU1oZacow3_nq-d4,2972
|
18
|
-
mpflash/flash_uf2.py,sha256=
|
18
|
+
mpflash/flash_uf2.py,sha256=KvNPk1zDwQexJfPI5MlIoR7zTD0u-pQQwSHuFQjuMXg,2093
|
19
19
|
mpflash/flash_uf2_boardid.py,sha256=WZKucGu_hJ8ymb236uuZbiR6pD6AA_l4LA-7LwtQhq8,414
|
20
20
|
mpflash/flash_uf2_linux.py,sha256=LAGkzTImVq-wKo7LGUNlwkUHv1L4rGO7igR5dwxY07o,4298
|
21
21
|
mpflash/flash_uf2_windows.py,sha256=dcmA-koavH7duOuNwI0n2aDDbhF1_5ZZ-mXFAXgj8z4,1072
|
22
|
-
mpflash/list.py,sha256=
|
22
|
+
mpflash/list.py,sha256=R3upYux3mEltpqfrt467Ufs4hVatW1NE40jjhN7Ei1g,3252
|
23
23
|
mpflash/logger.py,sha256=dI_H_a7EOdQJyvoeRHQuYeZuTKYVUS3DUPTLhE9rkdM,1098
|
24
24
|
mpflash/mpboard_id/__init__.py,sha256=JYGe7VwpBV4ig2M9a6vJUQrMtgdNjZKHt_Z5N13Ycrs,3509
|
25
25
|
mpflash/mpboard_id/board_id.py,sha256=NjKkIUv3sw6X60qy--mieQWrle3WNKw5NwAepMenTHI,2230
|
26
26
|
mpflash/mpboard_id/board_info.csv,sha256=KPWDo-zHWfrPGQn9oInsDH-5IdCzhBCs6K_YAmqqSpQ,96983
|
27
27
|
mpflash/mpboard_id/board_info.json,sha256=JtVyOMIO1O7vLKzJ0hyXQ4JSxXiQBJyay2hjdNLnZM0,674442
|
28
|
-
mpflash/mpremoteboard/__init__.py,sha256=
|
28
|
+
mpflash/mpremoteboard/__init__.py,sha256=DxlO_7LiyWDz5hNRI77fzp3sI3fZQ9Sd23dnGLx4Zl0,7017
|
29
29
|
mpflash/mpremoteboard/mpy_fw_info.py,sha256=6AQbN3jtQgllqWQYl4e-63KeEtV08EXk8_JnM6XBkvo,4554
|
30
|
-
mpflash/mpremoteboard/runner.py,sha256
|
30
|
+
mpflash/mpremoteboard/runner.py,sha256=-PgzAeBGbyXaAUlwyiw4mcINsP2U1XRRjP1_QdBrxpg,4786
|
31
31
|
mpflash/vendor/dfu.py,sha256=oK_MRSOyDJrUuS6D24IMIsfL7oLcrvUq0yp_h4WIY2U,5739
|
32
32
|
mpflash/vendor/pydfu.py,sha256=_MdBRo1EeNeKDqFPSTB5tNL1jGSBJgsVeVjE5e7Pb8s,20542
|
33
33
|
mpflash/vendor/readme.md,sha256=iIIZxuLUIGHQ0KODzYVtMezsztvyxCXcNJp_AzwTIPk,86
|
34
34
|
mpflash/vendor/versions.py,sha256=ooRZjeeYepQHwp12hMu2m0p8nZXQ5s942w5mGkKmgeI,3629
|
35
|
-
mpflash/worklist.py,sha256=
|
36
|
-
mpflash-0.
|
37
|
-
mpflash-0.
|
38
|
-
mpflash-0.
|
39
|
-
mpflash-0.
|
40
|
-
mpflash-0.
|
35
|
+
mpflash/worklist.py,sha256=qZsqF3Lf5Bl7QQ31ZLVHewP6WC8fmwQPMbyNgbG7LB4,5299
|
36
|
+
mpflash-0.7.1.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
|
37
|
+
mpflash-0.7.1.dist-info/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
|
38
|
+
mpflash-0.7.1.dist-info/METADATA,sha256=aAxXPamGn_mE__rBwjcZwSQlj-lQo8KA8HzyhmUIc9U,14627
|
39
|
+
mpflash-0.7.1.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
40
|
+
mpflash-0.7.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|