mpflash 1.25.0rc3__py3-none-any.whl → 1.25.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/cli_download.py +0 -12
- mpflash/cli_flash.py +25 -18
- mpflash/cli_list.py +2 -0
- mpflash/common.py +11 -1
- mpflash/config.py +18 -2
- mpflash/connected.py +3 -2
- mpflash/download/jid.py +1 -1
- mpflash/flash/uf2/windows.py +3 -1
- mpflash/flash/worklist.py +32 -16
- mpflash/logger.py +8 -4
- mpflash/mpremoteboard/__init__.py +2 -1
- {mpflash-1.25.0rc3.dist-info → mpflash-1.25.1.dist-info}/METADATA +63 -11
- {mpflash-1.25.0rc3.dist-info → mpflash-1.25.1.dist-info}/RECORD +16 -16
- {mpflash-1.25.0rc3.dist-info → mpflash-1.25.1.dist-info}/LICENSE +0 -0
- {mpflash-1.25.0rc3.dist-info → mpflash-1.25.1.dist-info}/WHEEL +0 -0
- {mpflash-1.25.0rc3.dist-info → mpflash-1.25.1.dist-info}/entry_points.txt +0 -0
mpflash/cli_download.py
CHANGED
@@ -23,15 +23,6 @@ from .download import download
|
|
23
23
|
"download",
|
24
24
|
help="Download MicroPython firmware for specific ports, boards and versions.",
|
25
25
|
)
|
26
|
-
@click.option(
|
27
|
-
"--destination",
|
28
|
-
"-d",
|
29
|
-
"fw_folder",
|
30
|
-
type=click.Path(file_okay=False, dir_okay=True, path_type=Path),
|
31
|
-
default=None,
|
32
|
-
show_default=False,
|
33
|
-
help="The folder to download the firmware to.",
|
34
|
-
)
|
35
26
|
@click.option(
|
36
27
|
"--version",
|
37
28
|
"-v",
|
@@ -94,9 +85,6 @@ def cli_download(**kwargs) -> int:
|
|
94
85
|
params.boards = list(params.boards)
|
95
86
|
params.serial = list(params.serial)
|
96
87
|
params.ignore = list(params.ignore)
|
97
|
-
if params.fw_folder:
|
98
|
-
config.firmware_folder = Path(params.fw_folder)
|
99
|
-
# all_boards: List[MPRemoteBoard] = []
|
100
88
|
if params.boards:
|
101
89
|
if not params.ports:
|
102
90
|
# no ports specified - resolve ports from specified boards by resolving board IDs
|
mpflash/cli_flash.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
from pathlib import Path
|
2
1
|
from typing import List
|
3
2
|
|
4
3
|
import rich_click as click
|
@@ -10,8 +9,7 @@ from mpflash.ask_input import ask_missing_params
|
|
10
9
|
from mpflash.cli_download import connected_ports_boards
|
11
10
|
from mpflash.cli_group import cli
|
12
11
|
from mpflash.cli_list import show_mcus
|
13
|
-
from mpflash.common import BootloaderMethod, FlashParams,
|
14
|
-
from mpflash.config import config
|
12
|
+
from mpflash.common import BootloaderMethod, FlashParams, filtered_comports
|
15
13
|
from mpflash.errors import MPFlashError
|
16
14
|
from mpflash.flash import flash_list
|
17
15
|
from mpflash.flash.worklist import WorkList, full_auto_worklist, manual_worklist, single_auto_worklist
|
@@ -27,15 +25,6 @@ from mpflash.versions import clean_version
|
|
27
25
|
"flash",
|
28
26
|
short_help="Flash one or all connected MicroPython boards with a specific firmware and version.",
|
29
27
|
)
|
30
|
-
@click.option(
|
31
|
-
"--firmware",
|
32
|
-
"-f",
|
33
|
-
"fw_folder",
|
34
|
-
type=click.Path(file_okay=False, dir_okay=True, path_type=Path),
|
35
|
-
default=None,
|
36
|
-
show_default=False,
|
37
|
-
help="The folder to retrieve the firmware from.",
|
38
|
-
)
|
39
28
|
@click.option(
|
40
29
|
"--version",
|
41
30
|
"-v",
|
@@ -95,7 +84,7 @@ from mpflash.versions import clean_version
|
|
95
84
|
)
|
96
85
|
@click.option(
|
97
86
|
"--variant",
|
98
|
-
"
|
87
|
+
"--var",
|
99
88
|
"variant", # single board
|
100
89
|
multiple=False,
|
101
90
|
help="The board VARIANT to flash or '-'. If not specified will try to read the variant from the connected MCU.",
|
@@ -134,7 +123,7 @@ from mpflash.versions import clean_version
|
|
134
123
|
)
|
135
124
|
@click.option(
|
136
125
|
"--flash_mode",
|
137
|
-
"
|
126
|
+
"--fm",
|
138
127
|
type=click.Choice(["keep", "qio", "qout", "dio", "dout"]),
|
139
128
|
default="keep",
|
140
129
|
show_default=True,
|
@@ -164,8 +153,6 @@ def cli_flash_board(**kwargs) -> int:
|
|
164
153
|
# No bard specified
|
165
154
|
params.boards = ["?"]
|
166
155
|
|
167
|
-
if params.fw_folder:
|
168
|
-
config.firmware_folder = Path(params.fw_folder)
|
169
156
|
# Detect connected boards if not specified,
|
170
157
|
# and ask for input if boards cannot be detected
|
171
158
|
all_boards: List[MPRemoteBoard] = []
|
@@ -197,8 +184,23 @@ def cli_flash_board(**kwargs) -> int:
|
|
197
184
|
params.versions = [clean_version(v) for v in params.versions]
|
198
185
|
worklist: WorkList = []
|
199
186
|
|
187
|
+
if len(params.versions) == 1 and len(params.boards) == 1 and params.serial == ["*"]:
|
188
|
+
# A one or more serial port including the board / variant
|
189
|
+
comports = filtered_comports(
|
190
|
+
ignore=params.ignore,
|
191
|
+
include=params.ports,
|
192
|
+
bluetooth=params.bluetooth,
|
193
|
+
)
|
194
|
+
board_id = f"{params.boards[0]}-{params.variant}" if params.variant else params.boards[0]
|
195
|
+
log.info(f"Flashing {board_id} {params.versions[0]} to {len(comports)} serial ports")
|
196
|
+
log.info(f"Target ports: {', '.join(comports)}")
|
197
|
+
worklist = manual_worklist(
|
198
|
+
comports,
|
199
|
+
board_id=board_id,
|
200
|
+
version=params.versions[0],
|
201
|
+
)
|
200
202
|
# if serial port == auto and there are one or more specified/detected boards
|
201
|
-
|
203
|
+
elif params.serial == ["*"] and params.boards:
|
202
204
|
if not all_boards:
|
203
205
|
log.trace("No boards detected yet, scanning for connected boards")
|
204
206
|
_, _, all_boards = connected_ports_boards(include=params.ports, ignore=params.ignore)
|
@@ -215,8 +217,13 @@ def cli_flash_board(**kwargs) -> int:
|
|
215
217
|
)
|
216
218
|
elif params.versions[0] and params.boards[0] and params.serial:
|
217
219
|
# A one or more serial port including the board / variant
|
220
|
+
comports = filtered_comports(
|
221
|
+
ignore=params.ignore,
|
222
|
+
include=params.ports,
|
223
|
+
bluetooth=params.bluetooth,
|
224
|
+
)
|
218
225
|
worklist = manual_worklist(
|
219
|
-
|
226
|
+
comports,
|
220
227
|
board_id=params.boards[0],
|
221
228
|
version=params.versions[0],
|
222
229
|
)
|
mpflash/cli_list.py
CHANGED
@@ -86,6 +86,8 @@ def cli_list_mcus(serial: List[str], ignore: List[str], bluetooth: bool, as_json
|
|
86
86
|
if mcu.family == "circuitpython":
|
87
87
|
# CircuitPython boards need a special reset command
|
88
88
|
mcu.run_command(["exec", "--no-follow", "import microcontroller,time;time.sleep(0.01);microcontroller.reset()"], resume=False)
|
89
|
+
elif mcu.family == "unknown":
|
90
|
+
continue
|
89
91
|
else:
|
90
92
|
mcu.run_command("reset")
|
91
93
|
return 0 if conn_mcus else 1
|
mpflash/common.py
CHANGED
@@ -36,7 +36,6 @@ class Params:
|
|
36
36
|
boards: List[str] = field(default_factory=list)
|
37
37
|
variant: str = ""
|
38
38
|
versions: List[str] = field(default_factory=list)
|
39
|
-
fw_folder: Optional[Path] = None
|
40
39
|
serial: List[str] = field(default_factory=list)
|
41
40
|
ignore: List[str] = field(default_factory=list)
|
42
41
|
bluetooth: bool = False
|
@@ -79,6 +78,17 @@ def filtered_comports(
|
|
79
78
|
ignore: Optional[List[str]] = None,
|
80
79
|
include: Optional[List[str]] = None,
|
81
80
|
bluetooth: bool = False,
|
81
|
+
) -> List[str]:
|
82
|
+
"""
|
83
|
+
Get a list of filtered comports using the include and ignore lists.
|
84
|
+
both can be globs (e.g. COM*) or exact port names (e.g. COM1)
|
85
|
+
"""
|
86
|
+
return [p.device for p in filtered_portinfos(ignore, include, bluetooth)]
|
87
|
+
|
88
|
+
def filtered_portinfos(
|
89
|
+
ignore: Optional[List[str]] = None,
|
90
|
+
include: Optional[List[str]] = None,
|
91
|
+
bluetooth: bool = False,
|
82
92
|
) -> List[ListPortInfo]: # sourcery skip: assign-if-exp
|
83
93
|
"""
|
84
94
|
Get a list of filtered comports using the include and ignore lists.
|
mpflash/config.py
CHANGED
@@ -4,9 +4,10 @@ import os
|
|
4
4
|
from importlib.metadata import version
|
5
5
|
from pathlib import Path
|
6
6
|
from typing import List, Optional
|
7
|
-
|
8
7
|
import platformdirs
|
9
8
|
|
9
|
+
from mpflash.errors import MPFlashError
|
10
|
+
|
10
11
|
|
11
12
|
def get_version():
|
12
13
|
name = __package__ or "mpflash"
|
@@ -44,7 +45,15 @@ class MPFlashConfig:
|
|
44
45
|
def firmware_folder(self) -> Path:
|
45
46
|
"""The folder where firmware files are stored"""
|
46
47
|
if not self._firmware_folder:
|
47
|
-
|
48
|
+
from mpflash.logger import log
|
49
|
+
# Check if MPFLASH_FIRMWARE environment variable is set
|
50
|
+
env_firmware_path = os.getenv("MPFLASH_FIRMWARE")
|
51
|
+
if env_firmware_path:
|
52
|
+
firmware_path = Path(env_firmware_path)
|
53
|
+
if firmware_path.exists() and firmware_path.is_dir():
|
54
|
+
self._firmware_folder = firmware_path
|
55
|
+
else:
|
56
|
+
log.warning(f"Environment variable MPFLASH_FIRMWARE points to invalid directory: {env_firmware_path}. Using default location.")
|
48
57
|
# allow testing in CI
|
49
58
|
if Path(os.getenv("GITHUB_ACTIONS", "")).as_posix().lower() == "true":
|
50
59
|
workspace = os.getenv("GITHUB_WORKSPACE")
|
@@ -53,6 +62,13 @@ class MPFlashConfig:
|
|
53
62
|
ws_path.mkdir(parents=True, exist_ok=True)
|
54
63
|
print(f"Detected GitHub Actions environment. Using workspace path: {ws_path}")
|
55
64
|
self._firmware_folder = ws_path
|
65
|
+
if not self._firmware_folder:
|
66
|
+
self._firmware_folder = platformdirs.user_downloads_path() / "firmware"
|
67
|
+
if not self._firmware_folder.exists():
|
68
|
+
log.info(f"Creating firmware folder at {self._firmware_folder}")
|
69
|
+
self._firmware_folder.mkdir(parents=True, exist_ok=True)
|
70
|
+
if not self._firmware_folder.is_dir():
|
71
|
+
raise MPFlashError(f"Firmware folder {self._firmware_folder} is not a directory.")
|
56
72
|
return self._firmware_folder
|
57
73
|
|
58
74
|
@firmware_folder.setter
|
mpflash/connected.py
CHANGED
@@ -4,7 +4,7 @@ from rich import print
|
|
4
4
|
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
5
5
|
from rich.table import Column
|
6
6
|
|
7
|
-
from mpflash.common import
|
7
|
+
from mpflash.common import filtered_portinfos, find_serial_by_path
|
8
8
|
from mpflash.mpremoteboard import MPRemoteBoard
|
9
9
|
|
10
10
|
|
@@ -21,6 +21,7 @@ def connected_ports_boards(
|
|
21
21
|
- A list of unique board names of the connected MCUs.
|
22
22
|
- A list of MPRemoteBoard instances of the connected MCUs.
|
23
23
|
"""
|
24
|
+
conn_mcus = [b for b in list_mcus(include=include, ignore=ignore, bluetooth=bluetooth)]
|
24
25
|
conn_mcus = [b for b in list_mcus(include=include, ignore=ignore, bluetooth=bluetooth) if b.connected]
|
25
26
|
# ignore boards that have the [mpflash] ignore flag set
|
26
27
|
conn_mcus = [item for item in conn_mcus if not (item.toml.get("mpflash", {}).get("ignore", False))]
|
@@ -47,7 +48,7 @@ def list_mcus(*, ignore: List[str], include: List[str], bluetooth: bool = False)
|
|
47
48
|
"""
|
48
49
|
# conn_mcus = [MPRemoteBoard(sp) for sp in MPRemoteBoard.connected_boards(bluetooth) if sp not in config.ignore_ports]
|
49
50
|
|
50
|
-
comports =
|
51
|
+
comports = filtered_portinfos(
|
51
52
|
ignore=ignore,
|
52
53
|
include=include,
|
53
54
|
bluetooth=bluetooth,
|
mpflash/download/jid.py
CHANGED
@@ -48,7 +48,7 @@ def ensure_firmware_downloaded(worklist: WorkList, version: str, force: bool) ->
|
|
48
48
|
newlist.append((mcu, new_firmware[0]))
|
49
49
|
else:
|
50
50
|
log.info(f"Found {version} firmware {board_firmwares[-1].firmware_file} for {mcu.board} on {mcu.serialport}.")
|
51
|
-
newlist.append((mcu,
|
51
|
+
newlist.append((mcu, board_firmwares[0]))
|
52
52
|
|
53
53
|
worklist.clear()
|
54
54
|
worklist.extend(newlist)
|
mpflash/flash/uf2/windows.py
CHANGED
@@ -7,13 +7,15 @@ import time
|
|
7
7
|
from pathlib import Path
|
8
8
|
from typing import Optional
|
9
9
|
|
10
|
-
from .boardid import get_board_id
|
11
10
|
import psutil
|
12
11
|
from rich.progress import track
|
13
12
|
|
13
|
+
from .boardid import get_board_id
|
14
|
+
|
14
15
|
|
15
16
|
def wait_for_UF2_windows(board_id: str, s_max: int = 10) -> Optional[Path]:
|
16
17
|
"""Wait for the MCU to mount as a drive"""
|
18
|
+
|
17
19
|
if s_max < 1:
|
18
20
|
s_max = 10
|
19
21
|
destination = None
|
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:
|
@@ -59,12 +61,26 @@ def auto_update(
|
|
59
61
|
|
60
62
|
|
61
63
|
def manual_worklist(
|
62
|
-
serial: str,
|
64
|
+
serial: List[str],
|
63
65
|
*,
|
64
66
|
board_id: str,
|
65
67
|
version: str,
|
66
68
|
) -> WorkList:
|
67
|
-
"""Create a worklist for
|
69
|
+
"""Create a worklist for manually specified boards."""
|
70
|
+
wl: WorkList = []
|
71
|
+
for comport in serial:
|
72
|
+
log.trace(f"Manual updating {comport} to {board_id} {version}")
|
73
|
+
wl.append(manual_board(comport, board_id=board_id, version=version))
|
74
|
+
return wl
|
75
|
+
|
76
|
+
|
77
|
+
def manual_board(
|
78
|
+
serial: str,
|
79
|
+
*,
|
80
|
+
board_id: str,
|
81
|
+
version: str,
|
82
|
+
) -> FlashItem:
|
83
|
+
"""Create a Flash work item for a single board specified manually.
|
68
84
|
|
69
85
|
Args:
|
70
86
|
serial (str): Serial port of the board
|
@@ -72,7 +88,7 @@ def manual_worklist(
|
|
72
88
|
version (str): Firmware version
|
73
89
|
|
74
90
|
Returns:
|
75
|
-
|
91
|
+
FlashItem: Board and firmware information to update
|
76
92
|
"""
|
77
93
|
log.trace(f"Manual updating {serial} to {board_id} {version}")
|
78
94
|
mcu = MPRemoteBoard(serial)
|
@@ -85,14 +101,14 @@ def manual_worklist(
|
|
85
101
|
except (LookupError, MPFlashError) as e:
|
86
102
|
log.error(f"Board {board_id} not found in board database")
|
87
103
|
log.exception(e)
|
88
|
-
return
|
104
|
+
return (mcu, None)
|
89
105
|
mcu.board = board_id
|
90
106
|
firmwares = find_downloaded_firmware(board_id=board_id, version=version, port=mcu.port)
|
91
107
|
if not firmwares:
|
92
|
-
log.
|
93
|
-
return
|
108
|
+
log.trace(f"No firmware found for {mcu.port} {board_id} version {version}")
|
109
|
+
return (mcu, None)
|
94
110
|
# use the most recent matching firmware
|
95
|
-
return
|
111
|
+
return (mcu, firmwares[-1]) # type: ignore
|
96
112
|
|
97
113
|
|
98
114
|
def single_auto_worklist(
|
@@ -111,7 +127,7 @@ def single_auto_worklist(
|
|
111
127
|
"""
|
112
128
|
log.trace(f"Auto updating {serial} to {version}")
|
113
129
|
conn_boards = [MPRemoteBoard(serial)]
|
114
|
-
todo =
|
130
|
+
todo = auto_update_worklist(conn_boards, version) # type: ignore # List / list
|
115
131
|
show_mcus(conn_boards)
|
116
132
|
return todo
|
117
133
|
|
@@ -125,7 +141,7 @@ def full_auto_worklist(
|
|
125
141
|
) -> WorkList:
|
126
142
|
"""
|
127
143
|
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
|
144
|
+
This allows the firmware version of one or more boards to be changed without needing to specify the port or board_id manually.
|
129
145
|
|
130
146
|
Args:
|
131
147
|
version (str): Firmware version
|
@@ -135,7 +151,7 @@ def full_auto_worklist(
|
|
135
151
|
"""
|
136
152
|
log.trace(f"Auto updating all boards to {version}")
|
137
153
|
if selected_boards := filter_boards(all_boards, include=include, ignore=ignore):
|
138
|
-
return
|
154
|
+
return auto_update_worklist(selected_boards, version)
|
139
155
|
else:
|
140
156
|
return []
|
141
157
|
|
@@ -149,7 +165,7 @@ def filter_boards(
|
|
149
165
|
try:
|
150
166
|
comports = [
|
151
167
|
p.device
|
152
|
-
for p in
|
168
|
+
for p in filtered_portinfos(
|
153
169
|
ignore=ignore,
|
154
170
|
include=include,
|
155
171
|
bluetooth=False,
|
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
|
@@ -15,12 +16,15 @@ from .config import config
|
|
15
16
|
console = Console()
|
16
17
|
|
17
18
|
# Detect if the output encoding supports Unicode (UTF-8)
|
19
|
+
@functools.lru_cache(maxsize=1)
|
18
20
|
def _is_utf8_encoding() -> bool:
|
19
|
-
|
20
|
-
|
21
|
+
try:
|
22
|
+
encoding = getattr(sys.stdout, "encoding", None)
|
23
|
+
if encoding is None:
|
24
|
+
return False
|
25
|
+
return encoding.lower().replace("-", "") == "utf8"
|
26
|
+
except BaseException:
|
21
27
|
return False
|
22
|
-
return encoding.lower().replace("-", "") == "utf8"
|
23
|
-
|
24
28
|
|
25
29
|
def _log_formatter(record: dict) -> str:
|
26
30
|
"""
|
@@ -216,9 +216,10 @@ class MPRemoteBoard:
|
|
216
216
|
self.toml = {}
|
217
217
|
if rc in [OK]: # sometimes we get an -9 ???
|
218
218
|
try:
|
219
|
+
log.trace(result)
|
219
220
|
# Ok we have the info, now parse it
|
220
221
|
self.toml = tomllib.loads("".join(result))
|
221
|
-
log.debug(f"board_info.toml: {self.toml}")
|
222
|
+
log.debug(f"board_info.toml: {self.toml['description']}")
|
222
223
|
except Exception as e:
|
223
224
|
log.error(f"Failed to parse board_info.toml: {e}")
|
224
225
|
else:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: mpflash
|
3
|
-
Version: 1.25.
|
3
|
+
Version: 1.25.1
|
4
4
|
Summary: Flash and download tool for MicroPython firmwares
|
5
5
|
License: MIT
|
6
6
|
Keywords: MicroPython,firmware,flash,download,UF2,esptool
|
@@ -29,7 +29,7 @@ Requires-Dist: loguru (>=0.7.2,<0.8.0)
|
|
29
29
|
Requires-Dist: mpremote (>=1.22.0,<2.0.0)
|
30
30
|
Requires-Dist: packaging (>=24.2,<25.0)
|
31
31
|
Requires-Dist: platformdirs (>=4.2.0,<5.0.0)
|
32
|
-
Requires-Dist: psutil (>=
|
32
|
+
Requires-Dist: psutil (>=7.0.0,<8.0.0)
|
33
33
|
Requires-Dist: pygithub (>=2.1.1,<3.0.0)
|
34
34
|
Requires-Dist: pyusb (>=1.2.1,<2.0.0)
|
35
35
|
Requires-Dist: pywin32 (>=310,<311) ; sys_platform == "win32"
|
@@ -58,9 +58,22 @@ This tool was initially created to be used in a CI/CD pipeline to automate the p
|
|
58
58
|
- `samd`, using ` .uf2`, using filecopy
|
59
59
|
- `esp32`, using `.bin`, using esptool,
|
60
60
|
- `esp8266`, using `.bin`, using esptool
|
61
|
-
- `stm32`, using ` .dfu`, using pydfu
|
61
|
+
- `stm32`, using ` .dfu`, using pydfu (also in Windows)
|
62
62
|
|
63
63
|
Not yet implemented: `nrf`, `cc3200`, `mimxrt`, `renesas`
|
64
|
+
|
65
|
+
## Release v1.25.0(.post2)
|
66
|
+
|
67
|
+
This release includes several new features and improvements:
|
68
|
+
- **New features:**
|
69
|
+
- Added support for `--variant` option to specify a specific variant of the board when flashing.
|
70
|
+
- mpflash now uses a slqlite database to store information on all possible micropython firmwares, and the management of the downloaded firmware files.
|
71
|
+
- This allows for a better identification of boards, and matches to the correct firmware.
|
72
|
+
- Use the MicroPython v1.25.0 `sys.implementation._build` to as board_id when avaialable
|
73
|
+
- Automatically try to download firmware if not yet available locally. No lonmger need to specify the `--download` option.
|
74
|
+
- Restructured mpboard_id to use a SQLite db to be able to ID more boards and variants
|
75
|
+
- vendored and adapted `board_database.py` from mpflash, kudos @mattytrentini
|
76
|
+
|
64
77
|
|
65
78
|
## Features
|
66
79
|
1. List the connected boards including their firmware details, in a tabular or json format
|
@@ -79,15 +92,54 @@ You can use mpflash to perform various operations on your MicroPython boards. He
|
|
79
92
|
| Command | Description |
|
80
93
|
|---------|-------------|
|
81
94
|
| `mpflash list` | List the connected board(s) including their firmware details |
|
95
|
+
| `mpflash flash` | Flash the latest stable firmware to the connected board(s), downloading the firmware if needed |
|
82
96
|
| `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
97
|
|
85
|
-
|
98
|
+
**Listing connected boards:**
|
99
|
+
`mpflash list` will list all connected boards in a table , including their serial port, family, board name, CPU, version and build number.
|
100
|
+
Options are available to list the boards in a json format, or to filter the list by serial port or board type.
|
101
|
+
|
102
|
+
|
103
|
+
**Flashing boards with new firmware:**
|
104
|
+
`mpflash flash` will flash the latest stable firmware to all connected boards, downloading the firmware if needed.
|
105
|
+
It will try to determine the current micropython borad and variant, download the firmware if needed, and flash the correct firmware to each board.
|
106
|
+
|
107
|
+
Common options are:
|
108
|
+
|
109
|
+
- `--version` to specify the version of the firmware to flash, defaults to the latest stable version.
|
110
|
+
- `--serial` to specify the serial port(s) to flash, defaults to all connected boards.
|
111
|
+
- `--board` to specify which firmware to flash to a single board
|
112
|
+
- `--variant` to specify a specific variant of the board
|
113
|
+
|
114
|
+
**Downloading firmware:**
|
115
|
+
`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.
|
116
|
+
When a board is specified for which multiple variants are available, all variants will be downloaded.
|
117
|
+
|
118
|
+
Common options are:
|
119
|
+
|
120
|
+
- `--version` to specify the version of the firmware to download, defaults to the latest stable version. (e.g. `stable`, `preview`, `x.y.z`)
|
121
|
+
- `--serial` to specify the serial port(s) to flash, defaults to all connected boards.
|
122
|
+
- `--board` to specify which firmware to flash to a single board
|
86
123
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
124
|
+
## Setting the Firmware Files and Database Location
|
125
|
+
|
126
|
+
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:
|
127
|
+
|
128
|
+
```bash
|
129
|
+
export MPFLASH_FIRMWARE="/path/to/custom/firmware"
|
130
|
+
```
|
131
|
+
|
132
|
+
When this variable is set, `mpflash` will use that location to store firmware files and estabish it's database.
|
133
|
+
|
134
|
+
## Selecting or ignoring specific serial ports
|
135
|
+
|
136
|
+
You can use the `--serial` option to select a specific serial port(s) to flash,
|
137
|
+
Or you can use the `--ignore` option to ignore a specific serial port(s).
|
138
|
+
|
139
|
+
Either option can be specified multiple times, can be globs (e.g. COM*) or exact port names (e.g. /dev/ttyUSB0).
|
140
|
+
To permenently ignore a port, you can set the `MPFLASH_IGNORE` environment variable to a space-separated list of serial ports or globs.
|
141
|
+
|
142
|
+
In addition there is a --bluetooth option to simplify ignoring bluetooth ports, where the default is to ignore bluetooth ports.
|
91
143
|
|
92
144
|
```
|
93
145
|
--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 +154,9 @@ This file can contain a description of the board, which will be shown in the lis
|
|
102
154
|
description = "Blue Norwegian actuator"
|
103
155
|
```
|
104
156
|
|
105
|
-
If you want the board to be ignored by mpflash, you can add the following to the board_info.toml file:
|
157
|
+
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
158
|
```toml
|
107
|
-
description = "Blue Norwegian
|
159
|
+
description = "Blue Norwegian actuator"
|
108
160
|
[mpflash]
|
109
161
|
ignore = true
|
110
162
|
```
|
@@ -8,14 +8,14 @@ mpflash/bootloader/detect.py,sha256=OagP2QVWeLLWkZt2paqEF6r4_x3QDcBGNCPOWfMy9NQ,
|
|
8
8
|
mpflash/bootloader/manual.py,sha256=WYC4x-dxrSwVUfgnKTlu34pCzckrWJKZnWsARDocycI,3169
|
9
9
|
mpflash/bootloader/micropython.py,sha256=v_kZkvg0uWZDbMrT78gmiYHbD83QLdnrctvEClI8iRg,529
|
10
10
|
mpflash/bootloader/touch1200.py,sha256=VND7_YniS9Vx6WEaAxjI72RZZ6WBOwmBTsKJkbuaAHk,1105
|
11
|
-
mpflash/cli_download.py,sha256=
|
12
|
-
mpflash/cli_flash.py,sha256=
|
11
|
+
mpflash/cli_download.py,sha256=cfM3_4It2SE1inx7XsxVhl-j_2efhmuej0d58biOdLo,3507
|
12
|
+
mpflash/cli_flash.py,sha256=g-ii51MTzxm-CVpLMhC0TszBYREqlZVctoocNG95z9c,8463
|
13
13
|
mpflash/cli_group.py,sha256=Uf_1ZmeeSIsaGLuuKn3KPPPVi8fJVbIacJYFZx_oPHc,2684
|
14
|
-
mpflash/cli_list.py,sha256=
|
14
|
+
mpflash/cli_list.py,sha256=dznrQrWQXvev20ai5AFvz2DFe3MNDR5RIrJmtvQou6A,2693
|
15
15
|
mpflash/cli_main.py,sha256=NMhEtMtSe7ApE-210Q4p-g7ZgewgO-4z1Q-vNKLQ47Y,1277
|
16
|
-
mpflash/common.py,sha256=
|
17
|
-
mpflash/config.py,sha256=
|
18
|
-
mpflash/connected.py,sha256=
|
16
|
+
mpflash/common.py,sha256=LVN3actI__gHorWIG5-55v6dZ1cD1GSIlevk3a8Je-Y,6278
|
17
|
+
mpflash/config.py,sha256=55cPkGvCajlEd1_lEGsPNCX9YdJqUr9muqBejVOyVVA,4066
|
18
|
+
mpflash/connected.py,sha256=Bx2R-nAeWC6iNG77mXDMu0n66bvTMyM4sH7ckuKnCFw,3591
|
19
19
|
mpflash/db/__init__.py,sha256=wnIlO4nOXsPGXMbn2OCqHRsR-hUmtJsko8VdqjH3ZUE,45
|
20
20
|
mpflash/db/core.py,sha256=hyzurZp8QMl8Q9B00Q-tOkOUp68T8XhM7tj3dm5cDHw,2283
|
21
21
|
mpflash/db/gather_boards.py,sha256=8QS7NIt3n9ROqtgVAnoqU8YMeObLGaN2pvJL7d_kULA,3905
|
@@ -27,7 +27,7 @@ mpflash/db/tools.py,sha256=6SEGfshNob4yRQ4h-Cj_xcWMRY28sbA8CWauNXV_uMI,814
|
|
27
27
|
mpflash/download/__init__.py,sha256=zidXvsSFCfR-BZCZ6TiB7uEucEuUqXnZhKSfTs60lzU,7930
|
28
28
|
mpflash/download/from_web.py,sha256=PVJDaFfYLJGXlPva5fExh4Yg2H7j3idyJEcfOiVVJBs,7608
|
29
29
|
mpflash/download/fwinfo.py,sha256=gpa92PkysT1B7mxPAFJ-b_6y03QCNgHKm-J6T_RFNMI,1852
|
30
|
-
mpflash/download/jid.py,sha256=
|
30
|
+
mpflash/download/jid.py,sha256=V57M4K0uXXxBYOB4zOKkmXvUvEQdM_-w22LZ-iMIJSE,2344
|
31
31
|
mpflash/downloaded.py,sha256=508sqROPf0Ymz7UxMzReXtK6mG1EcoXA-ysGdzV-VM0,4040
|
32
32
|
mpflash/errors.py,sha256=IAidY3qkZsXy6Pm1rdmVFmGyg81ywHhse3itaPctA2w,247
|
33
33
|
mpflash/flash/__init__.py,sha256=jif7-ifsXMabidjNdqUQyl1CwD5_USjCAZFhU5W-Aw8,2992
|
@@ -39,10 +39,10 @@ mpflash/flash/uf2/boardid.py,sha256=U5wGM8VA3wEpUxQCMtuXpMZZomdVH8J_Zd5_GekUMuU,
|
|
39
39
|
mpflash/flash/uf2/linux.py,sha256=uTgqyS7C7xfQ25RrTcSUkt-m2u2Ks_o7bPLzIecPoC8,4355
|
40
40
|
mpflash/flash/uf2/macos.py,sha256=JTaIpqnR_0k4oSEvzs9amhmK-PMxUJyZLnZ_wZwxa-0,1228
|
41
41
|
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=
|
42
|
+
mpflash/flash/uf2/windows.py,sha256=OEeskObPtpIE4a5NzYIcBqg3FkM5MGPGEa4lGGOfntY,1338
|
43
|
+
mpflash/flash/worklist.py,sha256=WIiBlbluAiU7UexOu1dlXguUmkvhW0uxvvUaiUCEZ1U,6165
|
44
44
|
mpflash/list.py,sha256=NNhKpRh3ARZMdq56GLJgJ67GeuUf9SxjTzFhQjDsi9A,4008
|
45
|
-
mpflash/logger.py,sha256=
|
45
|
+
mpflash/logger.py,sha256=b2pNiAEXgpUDZKnMjtgBAGgMpPwTB3u030EhJiXyLZQ,2009
|
46
46
|
mpflash/mpboard_id/__init__.py,sha256=Z6gDDWTCSKPp2fsuaUz80zgrklBR9XDlSLF9y_evR9A,391
|
47
47
|
mpflash/mpboard_id/alternate.py,sha256=ZhqfdA9sLJmyOfJ6WwK9wrzzUn6JQdkAreiL0q5XEQg,1913
|
48
48
|
mpflash/mpboard_id/board_id.py,sha256=dGbYnqaGHm6Z68P6aCq5bv95pyhi9KKhQleQXmlyO8Y,2046
|
@@ -50,7 +50,7 @@ mpflash/mpboard_id/board_info.json,sha256=A3ZIt38KvAy2NMB5srHorSBd3Q3wOZIXufWiIs
|
|
50
50
|
mpflash/mpboard_id/board_info.zip,sha256=-2bnQGRsIQuJUfz-7_-GQ8pMWJ1evhCez6yfjhXocNw,23213
|
51
51
|
mpflash/mpboard_id/known.py,sha256=GrNe4FtzVIdi9L9xuJ1gzorzXTvdfrugX1iVc_Nblb8,3325
|
52
52
|
mpflash/mpboard_id/resolve.py,sha256=5KCZ0Tcg3FYZ3HK_zux5EguwoSC2E03kCpW2fh4rN2A,779
|
53
|
-
mpflash/mpremoteboard/__init__.py,sha256=
|
53
|
+
mpflash/mpremoteboard/__init__.py,sha256=WWzAuUo3irKs_ZfHc7PREKrsywi45aPyZXuz5MaD6go,12093
|
54
54
|
mpflash/mpremoteboard/mpy_fw_info.py,sha256=ZDEPJN9XJnoG_oeWcLNiLJAD5bkVX2yI_j4K7msUxWM,5196
|
55
55
|
mpflash/mpremoteboard/runner.py,sha256=auJuK7uBq_qdZOX9DgzRARyAsTyhT8c9ycP02VqhMf4,4943
|
56
56
|
mpflash/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -62,8 +62,8 @@ mpflash/vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2,sha256=QuPMppq
|
|
62
62
|
mpflash/vendor/pydfu.py,sha256=KD1RHHuhvhWi-l1UB6GyggkxouDKtZgkG4ivRbIfwC4,21264
|
63
63
|
mpflash/vendor/readme.md,sha256=BQ7Uxf8joeYMjTUuSLLBG49ob6a9MgFPIEwuc72-Mfw,415
|
64
64
|
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.
|
65
|
+
mpflash-1.25.1.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
|
66
|
+
mpflash-1.25.1.dist-info/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
|
67
|
+
mpflash-1.25.1.dist-info/METADATA,sha256=IO9Axs0u59gBjzoIlCR7mNbb8jb0RkMi4bQ68JWXASA,27109
|
68
|
+
mpflash-1.25.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
69
|
+
mpflash-1.25.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|