mpflash 0.5.0__py3-none-any.whl → 0.7.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 +94 -23
- mpflash/cli_download.py +31 -15
- mpflash/cli_flash.py +58 -113
- mpflash/cli_group.py +1 -1
- mpflash/cli_list.py +2 -60
- mpflash/cli_main.py +7 -3
- mpflash/common.py +2 -126
- mpflash/download.py +15 -3
- mpflash/downloaded.py +108 -0
- mpflash/errors.py +5 -0
- mpflash/flash.py +38 -133
- mpflash/flash_esp.py +10 -15
- mpflash/flash_stm32.py +1 -3
- mpflash/flash_stm32_cube.py +0 -1
- mpflash/flash_stm32_dfu.py +19 -5
- mpflash/flash_uf2.py +1 -1
- mpflash/list.py +88 -0
- mpflash/mpboard_id/{api.py → __init__.py} +23 -16
- mpflash/mpboard_id/board_id.py +40 -22
- mpflash/mpremoteboard/__init__.py +98 -27
- mpflash/mpremoteboard/runner.py +5 -1
- mpflash/vendor/versions.py +113 -0
- mpflash/worklist.py +147 -0
- {mpflash-0.5.0.dist-info → mpflash-0.7.0.dist-info}/METADATA +4 -4
- mpflash-0.7.0.dist-info/RECORD +40 -0
- mpflash-0.5.0.dist-info/RECORD +0 -35
- /mpflash/{vendored → vendor}/dfu.py +0 -0
- /mpflash/{vendored → vendor}/pydfu.py +0 -0
- /mpflash/{vendored → vendor}/readme.md +0 -0
- {mpflash-0.5.0.dist-info → mpflash-0.7.0.dist-info}/LICENSE +0 -0
- {mpflash-0.5.0.dist-info → mpflash-0.7.0.dist-info}/WHEEL +0 -0
- {mpflash-0.5.0.dist-info → mpflash-0.7.0.dist-info}/entry_points.txt +0 -0
mpflash/ask_input.py
CHANGED
@@ -1,15 +1,20 @@
|
|
1
|
-
"""
|
1
|
+
"""
|
2
|
+
Interactive input for mpflash.
|
3
|
+
|
4
|
+
Note: The prompts can use "{version}" and "{action}" to insert the version and action in the prompt without needing an f-string.
|
5
|
+
The values are provided from the answers dictionary.
|
6
|
+
"""
|
2
7
|
|
3
8
|
from dataclasses import dataclass, field
|
4
9
|
from pathlib import Path
|
5
|
-
from typing import List, Sequence, Tuple, Union
|
10
|
+
from typing import Dict, List, Sequence, Tuple, Union
|
6
11
|
|
7
12
|
from loguru import logger as log
|
8
13
|
|
9
|
-
from mpflash.common import micropython_versions
|
10
14
|
from mpflash.config import config
|
11
|
-
from mpflash.mpboard_id
|
15
|
+
from mpflash.mpboard_id import known_stored_boards, local_mp_ports
|
12
16
|
from mpflash.mpremoteboard import MPRemoteBoard
|
17
|
+
from mpflash.vendor.versions import micropython_versions
|
13
18
|
|
14
19
|
|
15
20
|
@dataclass
|
@@ -42,6 +47,16 @@ def ask_missing_params(
|
|
42
47
|
params: ParamType,
|
43
48
|
action: str = "download",
|
44
49
|
) -> ParamType:
|
50
|
+
"""
|
51
|
+
Asks the user for parameters that have not been supplied on the commandline and returns the updated params.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
params (ParamType): The parameters to be updated.
|
55
|
+
action (str, optional): The action to be performed. Defaults to "download".
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
ParamType: The updated parameters.
|
59
|
+
"""
|
45
60
|
if not config.interactive:
|
46
61
|
# no interactivity allowed
|
47
62
|
return params
|
@@ -49,25 +64,33 @@ def ask_missing_params(
|
|
49
64
|
import inquirer
|
50
65
|
|
51
66
|
questions = []
|
52
|
-
|
53
|
-
|
67
|
+
answers = {"action": action}
|
68
|
+
if isinstance(params, FlashParams):
|
69
|
+
if not params.serial or "?" in params.serial:
|
70
|
+
ask_serialport(questions, action=action)
|
71
|
+
else:
|
72
|
+
answers["serial"] = params.serial
|
54
73
|
|
55
74
|
if not params.versions or "?" in params.versions:
|
56
75
|
ask_versions(questions, action=action)
|
76
|
+
else:
|
77
|
+
# versions is used to show only the boards for the selected versions
|
78
|
+
answers["versions"] = params.versions # type: ignore
|
57
79
|
|
58
80
|
if not params.boards or "?" in params.boards:
|
59
81
|
ask_port_board(questions, action=action)
|
60
82
|
|
61
|
-
answers = inquirer.prompt(questions)
|
83
|
+
answers = inquirer.prompt(questions, answers=answers)
|
62
84
|
if not answers:
|
63
|
-
|
85
|
+
# input cancelled by user
|
86
|
+
return [] # type: ignore
|
64
87
|
# print(repr(answers))
|
65
88
|
if isinstance(params, FlashParams) and "serial" in answers:
|
66
89
|
params.serial = answers["serial"]
|
67
90
|
if "port" in answers:
|
68
91
|
params.ports = [answers["port"]]
|
69
92
|
if "boards" in answers:
|
70
|
-
params.boards = answers["boards"]
|
93
|
+
params.boards = answers["boards"] if isinstance(answers["boards"], list) else [answers["boards"]]
|
71
94
|
if "versions" in answers:
|
72
95
|
# make sure it is a list
|
73
96
|
params.versions = answers["versions"] if isinstance(answers["versions"], list) else [answers["versions"]]
|
@@ -77,20 +100,29 @@ def ask_missing_params(
|
|
77
100
|
return params
|
78
101
|
|
79
102
|
|
80
|
-
def
|
103
|
+
def filter_matching_boards(answers: dict) -> Sequence[Tuple[str, str]]:
|
104
|
+
"""
|
105
|
+
Filters the known boards based on the selected versions and returns the filtered boards.
|
106
|
+
|
107
|
+
Args:
|
108
|
+
answers (dict): The user's answers.
|
109
|
+
|
110
|
+
Returns:
|
111
|
+
Sequence[Tuple[str, str]]: The filtered boards.
|
112
|
+
"""
|
113
|
+
# if version is not asked ; then need to get the version from the inputs
|
81
114
|
if "versions" in answers:
|
82
115
|
_versions = list(answers["versions"])
|
83
116
|
if "stable" in _versions:
|
84
117
|
_versions.remove("stable")
|
85
|
-
_versions.append(micropython_versions()[-2])
|
118
|
+
_versions.append(micropython_versions()[-2]) # latest stable
|
86
119
|
if "preview" in _versions:
|
87
120
|
_versions.remove("preview")
|
88
|
-
_versions.
|
89
|
-
_versions.append(micropython_versions()[-2])
|
121
|
+
_versions.extend((micropython_versions()[-1], micropython_versions()[-2])) # latest preview and stable
|
90
122
|
|
91
|
-
some_boards =
|
123
|
+
some_boards = known_stored_boards(answers["port"], _versions) # or known_mp_boards(answers["port"])
|
92
124
|
else:
|
93
|
-
some_boards =
|
125
|
+
some_boards = known_stored_boards(answers["port"])
|
94
126
|
|
95
127
|
if some_boards:
|
96
128
|
# Create a dictionary where the keys are the second elements of the tuples
|
@@ -104,21 +136,37 @@ def some_boards(answers: dict) -> Sequence[Tuple[str, str]]:
|
|
104
136
|
|
105
137
|
|
106
138
|
def ask_port_board(questions: list, *, action: str):
|
139
|
+
"""
|
140
|
+
Asks the user for the port and board selection.
|
141
|
+
|
142
|
+
Args:
|
143
|
+
questions (list): The list of questions to be asked.
|
144
|
+
action (str): The action to be performed.
|
145
|
+
|
146
|
+
Returns:
|
147
|
+
None
|
148
|
+
"""
|
107
149
|
# import only when needed to reduce load time
|
108
150
|
import inquirer
|
109
151
|
|
152
|
+
# TODO: if action = flash, Use Inquirer.List for boards
|
153
|
+
inquirer_ux = inquirer.Checkbox if action == "download" else inquirer.List
|
110
154
|
questions.extend(
|
111
155
|
(
|
112
156
|
inquirer.List(
|
113
157
|
"port",
|
114
|
-
message=
|
115
|
-
choices=
|
158
|
+
message="Which port do you want to {action} " + "to {serial} ?" if action == "flash" else "?",
|
159
|
+
choices=local_mp_ports(),
|
116
160
|
autocomplete=True,
|
117
161
|
),
|
118
|
-
|
162
|
+
inquirer_ux(
|
119
163
|
"boards",
|
120
|
-
message=
|
121
|
-
|
164
|
+
message=(
|
165
|
+
"Which {port} board firmware do you want to {action} " + "to {serial} ?"
|
166
|
+
if action == "flash"
|
167
|
+
else "?"
|
168
|
+
),
|
169
|
+
choices=filter_matching_boards,
|
122
170
|
validate=lambda _, x: True if x else "Please select at least one board", # type: ignore
|
123
171
|
),
|
124
172
|
)
|
@@ -126,6 +174,16 @@ def ask_port_board(questions: list, *, action: str):
|
|
126
174
|
|
127
175
|
|
128
176
|
def ask_versions(questions: list, *, action: str):
|
177
|
+
"""
|
178
|
+
Asks the user for the version selection.
|
179
|
+
|
180
|
+
Args:
|
181
|
+
questions (list): The list of questions to be asked.
|
182
|
+
action (str): The action to be performed.
|
183
|
+
|
184
|
+
Returns:
|
185
|
+
None
|
186
|
+
"""
|
129
187
|
# import only when needed to reduce load time
|
130
188
|
import inquirer
|
131
189
|
|
@@ -136,8 +194,11 @@ def ask_versions(questions: list, *, action: str):
|
|
136
194
|
mp_versions.reverse() # newest first
|
137
195
|
questions.append(
|
138
196
|
input_ux(
|
197
|
+
# inquirer.List(
|
139
198
|
"versions",
|
140
|
-
message=
|
199
|
+
message="Which version(s) do you want to {action} " + ("to {serial} ?" if action == "flash" else "?"),
|
200
|
+
# Hints would be nice , but needs a hint for each and every option
|
201
|
+
# hints=["Use space to select multiple options"],
|
141
202
|
choices=mp_versions,
|
142
203
|
autocomplete=True,
|
143
204
|
validate=lambda _, x: True if x else "Please select at least one version", # type: ignore
|
@@ -146,6 +207,16 @@ def ask_versions(questions: list, *, action: str):
|
|
146
207
|
|
147
208
|
|
148
209
|
def ask_serialport(questions: list, *, action: str):
|
210
|
+
"""
|
211
|
+
Asks the user for the serial port selection.
|
212
|
+
|
213
|
+
Args:
|
214
|
+
questions (list): The list of questions to be asked.
|
215
|
+
action (str): The action to be performed.
|
216
|
+
|
217
|
+
Returns:
|
218
|
+
None
|
219
|
+
"""
|
149
220
|
# import only when needed to reduce load time
|
150
221
|
import inquirer
|
151
222
|
|
@@ -153,10 +224,10 @@ def ask_serialport(questions: list, *, action: str):
|
|
153
224
|
questions.append(
|
154
225
|
inquirer.List(
|
155
226
|
"serial",
|
156
|
-
message="
|
157
|
-
validate=lambda _, x: True if x else "Please enter a serial port", # type: ignore
|
227
|
+
message="Which serial port do you want to {action} ?",
|
158
228
|
choices=serialports,
|
159
229
|
other=True,
|
230
|
+
validate=lambda _, x: True if x else "Please select or enter a serial port", # type: ignore
|
160
231
|
)
|
161
232
|
)
|
162
233
|
|
mpflash/cli_download.py
CHANGED
@@ -4,8 +4,10 @@ from pathlib import Path
|
|
4
4
|
from typing import List, Tuple
|
5
5
|
|
6
6
|
import rich_click as click
|
7
|
+
from loguru import logger as log
|
7
8
|
|
8
|
-
from mpflash.
|
9
|
+
from mpflash.mpboard_id import find_stored_board
|
10
|
+
from mpflash.vendor.versions import clean_version
|
9
11
|
|
10
12
|
from .ask_input import DownloadParams, ask_missing_params
|
11
13
|
from .cli_group import cli
|
@@ -14,13 +16,6 @@ from .config import config
|
|
14
16
|
from .download import download
|
15
17
|
|
16
18
|
|
17
|
-
def connected_ports_boards() -> Tuple[List[str], List[str]]:
|
18
|
-
mpr_boards = list_mcus()
|
19
|
-
ports = list({b.port for b in mpr_boards})
|
20
|
-
boards = list({b.board for b in mpr_boards})
|
21
|
-
return ports, boards
|
22
|
-
|
23
|
-
|
24
19
|
@cli.command(
|
25
20
|
"download",
|
26
21
|
help="Download MicroPython firmware for specific ports, boards and versions.",
|
@@ -49,7 +44,7 @@ def connected_ports_boards() -> Tuple[List[str], List[str]]:
|
|
49
44
|
"-b",
|
50
45
|
"boards",
|
51
46
|
multiple=True,
|
52
|
-
default=[
|
47
|
+
default=[],
|
53
48
|
show_default=True,
|
54
49
|
help="The board(s) to download the firmware for.",
|
55
50
|
metavar="BOARD_ID or ?",
|
@@ -71,16 +66,21 @@ def cli_download(
|
|
71
66
|
**kwargs,
|
72
67
|
):
|
73
68
|
params = DownloadParams(**kwargs)
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
params.versions = list(params.versions)
|
70
|
+
params.boards = list(params.boards)
|
71
|
+
if params.boards:
|
72
|
+
pass
|
73
|
+
# TODO Clean board - same as in cli_flash.py
|
74
|
+
else:
|
75
|
+
# no boards specified - detect connected boards
|
77
76
|
params.ports, params.boards = connected_ports_boards()
|
78
|
-
|
77
|
+
|
79
78
|
params = ask_missing_params(params, action="download")
|
79
|
+
if not params: # Cancelled by user
|
80
|
+
exit(1)
|
81
|
+
params.versions = [clean_version(v, drop_v=True) for v in params.versions]
|
80
82
|
assert isinstance(params, DownloadParams)
|
81
83
|
|
82
|
-
params.versions = [clean_version(v, drop_v=True) for v in params.versions] # remove leading v from version
|
83
|
-
|
84
84
|
download(
|
85
85
|
params.fw_folder,
|
86
86
|
params.ports,
|
@@ -89,3 +89,19 @@ def cli_download(
|
|
89
89
|
params.force,
|
90
90
|
params.clean,
|
91
91
|
)
|
92
|
+
|
93
|
+
|
94
|
+
def connected_ports_boards() -> Tuple[List[str], List[str]]:
|
95
|
+
"""
|
96
|
+
Returns a tuple containing lists of unique ports and boards from the connected MCUs.
|
97
|
+
Boards that are physically connected, but give no tangible response are ignored.
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
A tuple containing two lists:
|
101
|
+
- A list of unique ports where MCUs are connected.
|
102
|
+
- A list of unique board names of the connected MCUs.
|
103
|
+
"""
|
104
|
+
mpr_boards = [b for b in list_mcus() if b.connected]
|
105
|
+
ports = list({b.port for b in mpr_boards})
|
106
|
+
boards = list({b.board for b in mpr_boards})
|
107
|
+
return ports, boards
|
mpflash/cli_flash.py
CHANGED
@@ -1,21 +1,19 @@
|
|
1
1
|
from pathlib import Path
|
2
|
-
from typing import List
|
3
2
|
|
4
3
|
import rich_click as click
|
5
4
|
from loguru import logger as log
|
6
5
|
|
6
|
+
from mpflash.errors import MPFlashError
|
7
|
+
from mpflash.mpboard_id import find_stored_board
|
8
|
+
from mpflash.vendor.versions import clean_version
|
9
|
+
|
7
10
|
from .ask_input import FlashParams, ask_missing_params
|
8
11
|
from .cli_download import connected_ports_boards
|
9
12
|
from .cli_group import cli
|
10
13
|
from .cli_list import show_mcus
|
11
|
-
from .common import clean_version
|
12
14
|
from .config import config
|
13
|
-
from .flash import
|
14
|
-
from .
|
15
|
-
from .flash_stm32 import flash_stm32
|
16
|
-
from .flash_uf2 import flash_uf2
|
17
|
-
from .mpboard_id.api import find_mp_board
|
18
|
-
from .mpremoteboard import MPRemoteBoard
|
15
|
+
from .flash import flash_list
|
16
|
+
from .worklist import MPRemoteBoard, WorkList, full_auto_worklist, manual_worklist, single_auto_worklist
|
19
17
|
|
20
18
|
# #########################################################################################################
|
21
19
|
# CLI
|
@@ -67,9 +65,8 @@ from .mpremoteboard import MPRemoteBoard
|
|
67
65
|
@click.option(
|
68
66
|
"--board",
|
69
67
|
"-b",
|
70
|
-
"
|
68
|
+
"board", # single board
|
71
69
|
multiple=False,
|
72
|
-
default=[],
|
73
70
|
help="The MicroPython board ID to flash. If not specified will try to read the BOARD_ID from the connected MCU.",
|
74
71
|
metavar="BOARD_ID or ?",
|
75
72
|
)
|
@@ -95,131 +92,79 @@ from .mpremoteboard import MPRemoteBoard
|
|
95
92
|
help="""Enter micropython bootloader mode before flashing.""",
|
96
93
|
)
|
97
94
|
def cli_flash_board(**kwargs):
|
98
|
-
|
95
|
+
# version to versions, board to boards
|
96
|
+
kwargs["versions"] = [kwargs.pop("version")] if kwargs["version"] != None else []
|
97
|
+
if kwargs["board"] is None:
|
98
|
+
kwargs["boards"] = []
|
99
|
+
kwargs.pop("board")
|
100
|
+
else:
|
101
|
+
kwargs["boards"] = [kwargs.pop("board")]
|
99
102
|
|
100
|
-
# version to versions
|
101
|
-
if "version" in kwargs:
|
102
|
-
kwargs["versions"] = [kwargs.pop("version")]
|
103
103
|
params = FlashParams(**kwargs)
|
104
|
-
|
105
|
-
# print(f"{params.version=}")
|
106
|
-
print(f"{params.versions=}")
|
107
|
-
if not params.boards:
|
104
|
+
if not params.boards or params.boards == []:
|
108
105
|
# nothing specified - detect connected boards
|
109
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 = ["?"]
|
112
|
+
else:
|
113
|
+
for board_id in params.boards:
|
114
|
+
if board_id == "":
|
115
|
+
params.boards.remove(board_id)
|
116
|
+
continue
|
117
|
+
if " " in board_id:
|
118
|
+
try:
|
119
|
+
info = find_stored_board(board_id)
|
120
|
+
if info:
|
121
|
+
log.info(f"Resolved board description: {info['board']}")
|
122
|
+
params.boards.remove(board_id)
|
123
|
+
params.boards.append(info["board"])
|
124
|
+
except Exception as e:
|
125
|
+
log.warning(f"unable to resolve board description: {e}")
|
126
|
+
|
110
127
|
# Ask for missing input if needed
|
111
128
|
params = ask_missing_params(params, action="flash")
|
129
|
+
if not params: # Cancelled by user
|
130
|
+
exit(1)
|
112
131
|
# TODO: Just in time Download of firmware
|
113
132
|
|
114
133
|
assert isinstance(params, FlashParams)
|
115
134
|
|
116
135
|
if len(params.versions) > 1:
|
117
|
-
print(repr(params.versions))
|
118
136
|
log.error(f"Only one version can be flashed at a time, not {params.versions}")
|
119
|
-
|
137
|
+
raise MPFlashError("Only one version can be flashed at a time")
|
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")
|
141
|
+
|
120
142
|
params.versions = [clean_version(v) for v in params.versions]
|
121
|
-
|
122
|
-
|
123
|
-
|
143
|
+
worklist: WorkList = []
|
144
|
+
# if serial port == auto and there are one or more specified/detected boards
|
145
|
+
if params.serial == "auto" and params.boards:
|
146
|
+
worklist = full_auto_worklist(version=params.versions[0], fw_folder=params.fw_folder)
|
147
|
+
elif params.versions[0] and params.boards[0] and params.serial:
|
148
|
+
# A single serial port including the board / variant
|
149
|
+
worklist = manual_worklist(
|
124
150
|
params.versions[0],
|
125
151
|
params.fw_folder,
|
126
152
|
params.serial,
|
127
153
|
params.boards[0],
|
128
|
-
# params.ports[0],
|
129
154
|
)
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
params.versions[0],
|
138
|
-
params.fw_folder,
|
139
|
-
params.serial,
|
140
|
-
)
|
155
|
+
else:
|
156
|
+
# just this serial port on auto
|
157
|
+
worklist = single_auto_worklist(
|
158
|
+
serial_port=params.serial,
|
159
|
+
version=params.versions[0],
|
160
|
+
fw_folder=params.fw_folder,
|
161
|
+
)
|
141
162
|
|
142
163
|
if flashed := flash_list(
|
143
|
-
|
164
|
+
worklist,
|
144
165
|
params.fw_folder,
|
145
166
|
params.erase,
|
146
167
|
params.bootloader,
|
147
168
|
):
|
148
169
|
log.info(f"Flashed {len(flashed)} boards")
|
149
|
-
show_mcus(flashed, title="
|
150
|
-
|
151
|
-
|
152
|
-
def oneport_worklist(
|
153
|
-
version: str,
|
154
|
-
fw_folder: Path,
|
155
|
-
serial_port: str,
|
156
|
-
# preview: bool,
|
157
|
-
) -> WorkList:
|
158
|
-
"""Create a worklist for a single serial-port."""
|
159
|
-
conn_boards = [MPRemoteBoard(serial_port)]
|
160
|
-
todo = auto_update(conn_boards, version, fw_folder) # type: ignore # List / list
|
161
|
-
show_mcus(conn_boards) # type: ignore
|
162
|
-
return todo
|
163
|
-
|
164
|
-
|
165
|
-
def auto_worklist(version: str, fw_folder: Path) -> WorkList:
|
166
|
-
conn_boards = [MPRemoteBoard(sp) for sp in MPRemoteBoard.connected_boards() if sp not in config.ignore_ports]
|
167
|
-
return auto_update(conn_boards, version, fw_folder) # type: ignore
|
168
|
-
|
169
|
-
|
170
|
-
def manual_worklist(
|
171
|
-
version: str,
|
172
|
-
fw_folder: Path,
|
173
|
-
serial_port: str,
|
174
|
-
board: str,
|
175
|
-
# port: str,
|
176
|
-
) -> WorkList:
|
177
|
-
mcu = MPRemoteBoard(serial_port)
|
178
|
-
# TODO : Find a way to avoid needing to specify the port
|
179
|
-
# Lookup the matching port and cpu in board_info based in the board name
|
180
|
-
port = find_mp_board(board)["port"]
|
181
|
-
mcu.port = port
|
182
|
-
mcu.cpu = port if port.startswith("esp") else ""
|
183
|
-
mcu.board = board
|
184
|
-
firmwares = find_firmware(fw_folder=fw_folder, board=board, version=version, port=port)
|
185
|
-
if not firmwares:
|
186
|
-
log.error(f"No firmware found for {port} {board} version {version}")
|
187
|
-
return []
|
188
|
-
# use the most recent matching firmware
|
189
|
-
return [(mcu, firmwares[-1])] # type: ignore
|
190
|
-
|
191
|
-
|
192
|
-
def flash_list(
|
193
|
-
todo: WorkList,
|
194
|
-
fw_folder: Path,
|
195
|
-
erase: bool,
|
196
|
-
bootloader: bool,
|
197
|
-
):
|
198
|
-
"""Flash a list of boards with the specified firmware."""
|
199
|
-
flashed = []
|
200
|
-
for mcu, fw_info in todo:
|
201
|
-
fw_file = fw_folder / fw_info["filename"] # type: ignore
|
202
|
-
if not fw_file.exists():
|
203
|
-
log.error(f"File {fw_file} does not exist, skipping {mcu.board} on {mcu.serialport}")
|
204
|
-
continue
|
205
|
-
log.info(f"Updating {mcu.board} on {mcu.serialport} to {fw_info['version']}")
|
206
|
-
updated = None
|
207
|
-
# try:
|
208
|
-
if mcu.port in ["samd", "rp2", "nrf"]: # [k for k, v in PORT_FWTYPES.items() if v == ".uf2"]:
|
209
|
-
if bootloader:
|
210
|
-
enter_bootloader(mcu)
|
211
|
-
updated = flash_uf2(mcu, fw_file=fw_file, erase=erase)
|
212
|
-
elif mcu.port in ["stm32"]:
|
213
|
-
if bootloader:
|
214
|
-
enter_bootloader(mcu)
|
215
|
-
updated = flash_stm32(mcu, fw_file, erase=erase)
|
216
|
-
elif mcu.port in ["esp32", "esp8266"]:
|
217
|
-
# bootloader is handled by esptool for esp32/esp8266
|
218
|
-
updated = flash_esp(mcu, fw_file=fw_file, erase=erase)
|
219
|
-
else:
|
220
|
-
log.error(f"Don't (yet) know how to flash {mcu.port}-{mcu.board} on {mcu.serialport}")
|
221
|
-
|
222
|
-
if updated:
|
223
|
-
flashed.append(updated)
|
224
|
-
else:
|
225
|
-
log.error(f"Failed to flash {mcu.board} on {mcu.serialport}")
|
170
|
+
show_mcus(flashed, title="Updated boards after flashing")
|
mpflash/cli_group.py
CHANGED
mpflash/cli_list.py
CHANGED
@@ -1,16 +1,11 @@
|
|
1
1
|
import json
|
2
|
-
from typing import List
|
3
2
|
|
4
3
|
import rich_click as click
|
5
4
|
from rich import print
|
6
|
-
from rich.progress import track
|
7
|
-
from rich.table import Table
|
8
|
-
|
9
|
-
from mpflash.mpremoteboard import MPRemoteBoard
|
10
5
|
|
11
6
|
from .cli_group import cli
|
12
|
-
from .
|
13
|
-
from .logger import
|
7
|
+
from .list import list_mcus, show_mcus
|
8
|
+
from .logger import make_quiet
|
14
9
|
|
15
10
|
|
16
11
|
@cli.command("list", help="List the connected MCU boards.")
|
@@ -44,56 +39,3 @@ def cli_list_mcus(as_json: bool, progress: bool = True):
|
|
44
39
|
if progress:
|
45
40
|
show_mcus(conn_mcus, refresh=False)
|
46
41
|
return conn_mcus
|
47
|
-
|
48
|
-
|
49
|
-
def list_mcus():
|
50
|
-
conn_mcus = [MPRemoteBoard(sp) for sp in MPRemoteBoard.connected_boards() if sp not in config.ignore_ports]
|
51
|
-
|
52
|
-
for mcu in track(conn_mcus, description="Getting board info", transient=True, update_period=0.1):
|
53
|
-
try:
|
54
|
-
mcu.get_mcu_info()
|
55
|
-
except ConnectionError as e:
|
56
|
-
print(f"Error: {e}")
|
57
|
-
continue
|
58
|
-
return conn_mcus
|
59
|
-
|
60
|
-
|
61
|
-
def show_mcus(
|
62
|
-
conn_mcus: List[MPRemoteBoard],
|
63
|
-
title: str = "Connected boards",
|
64
|
-
refresh: bool = True,
|
65
|
-
): # sourcery skip: extract-duplicate-method
|
66
|
-
"""Show the list of connected boards in a nice table"""
|
67
|
-
table = Table(
|
68
|
-
title=title,
|
69
|
-
header_style="bold blue",
|
70
|
-
collapse_padding=True,
|
71
|
-
width=110,
|
72
|
-
row_styles=["blue", "yellow"],
|
73
|
-
)
|
74
|
-
table.add_column("Serial", overflow="fold")
|
75
|
-
table.add_column("Family")
|
76
|
-
table.add_column("Port")
|
77
|
-
table.add_column("Board", overflow="fold")
|
78
|
-
# table.add_column("Variant") # TODO: add variant
|
79
|
-
table.add_column("CPU")
|
80
|
-
table.add_column("Version")
|
81
|
-
table.add_column("build", justify="right")
|
82
|
-
|
83
|
-
for mcu in track(conn_mcus, description="Updating board info", transient=True, update_period=0.1):
|
84
|
-
if refresh:
|
85
|
-
try:
|
86
|
-
mcu.get_mcu_info()
|
87
|
-
except ConnectionError:
|
88
|
-
continue
|
89
|
-
table.add_row(
|
90
|
-
mcu.serialport.replace("/dev/", ""),
|
91
|
-
mcu.family,
|
92
|
-
mcu.port,
|
93
|
-
f"{mcu.board}\n{mcu.description}".strip(),
|
94
|
-
# mcu.variant,
|
95
|
-
mcu.cpu,
|
96
|
-
mcu.version,
|
97
|
-
mcu.build,
|
98
|
-
)
|
99
|
-
console.print(table)
|
mpflash/cli_main.py
CHANGED
@@ -15,8 +15,12 @@ def mpflash():
|
|
15
15
|
cli.add_command(cli_list_mcus)
|
16
16
|
cli.add_command(cli_download)
|
17
17
|
# cli(auto_envvar_prefix="MPFLASH")
|
18
|
-
|
18
|
+
try:
|
19
|
+
exit(cli())
|
20
|
+
except AttributeError as e:
|
21
|
+
print(f"Error: {e}")
|
22
|
+
exit(-1)
|
19
23
|
|
20
24
|
|
21
|
-
|
22
|
-
mpflash()
|
25
|
+
if __name__ == "__main__":
|
26
|
+
mpflash()
|