micropython-stubber 1.20.0__py3-none-any.whl → 1.20.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.
- {micropython_stubber-1.20.0.dist-info → micropython_stubber-1.20.2.dist-info}/METADATA +6 -6
- {micropython_stubber-1.20.0.dist-info → micropython_stubber-1.20.2.dist-info}/RECORD +58 -51
- mpflash/README.md +54 -35
- mpflash/libusb_flash.ipynb +203 -203
- mpflash/mpflash/add_firmware.py +98 -0
- mpflash/mpflash/ask_input.py +106 -114
- mpflash/mpflash/cli_download.py +58 -37
- mpflash/mpflash/cli_flash.py +77 -35
- mpflash/mpflash/cli_group.py +14 -12
- mpflash/mpflash/cli_list.py +40 -4
- mpflash/mpflash/cli_main.py +20 -8
- mpflash/mpflash/common.py +125 -12
- mpflash/mpflash/config.py +2 -0
- mpflash/mpflash/connected.py +74 -0
- mpflash/mpflash/download.py +67 -50
- mpflash/mpflash/downloaded.py +9 -9
- mpflash/mpflash/flash.py +2 -2
- mpflash/mpflash/flash_esp.py +2 -2
- mpflash/mpflash/flash_uf2.py +16 -8
- mpflash/mpflash/flash_uf2_linux.py +5 -16
- mpflash/mpflash/flash_uf2_macos.py +78 -0
- mpflash/mpflash/flash_uf2_windows.py +1 -1
- mpflash/mpflash/list.py +58 -57
- mpflash/mpflash/mpboard_id/__init__.py +37 -44
- mpflash/mpflash/mpboard_id/add_boards.py +255 -0
- mpflash/mpflash/mpboard_id/board.py +37 -0
- mpflash/mpflash/mpboard_id/board_id.py +50 -43
- mpflash/mpflash/mpboard_id/board_info.zip +0 -0
- mpflash/mpflash/mpboard_id/store.py +42 -0
- mpflash/mpflash/mpremoteboard/__init__.py +18 -6
- mpflash/mpflash/mpremoteboard/runner.py +12 -12
- mpflash/mpflash/uf2disk.py +12 -0
- mpflash/mpflash/vendor/basicgit.py +288 -0
- mpflash/mpflash/vendor/dfu.py +1 -0
- mpflash/mpflash/vendor/versions.py +7 -3
- mpflash/mpflash/worklist.py +71 -48
- mpflash/poetry.lock +163 -137
- mpflash/pyproject.toml +18 -15
- stubber/__init__.py +1 -1
- stubber/board/createstubs.py +4 -3
- stubber/board/createstubs_db.py +5 -7
- stubber/board/createstubs_db_min.py +1 -1
- stubber/board/createstubs_db_mpy.mpy +0 -0
- stubber/board/createstubs_mem.py +6 -7
- stubber/board/createstubs_mem_min.py +1 -1
- stubber/board/createstubs_mem_mpy.mpy +0 -0
- stubber/board/createstubs_min.py +2 -2
- stubber/board/createstubs_mpy.mpy +0 -0
- stubber/board/modulelist.txt +1 -0
- stubber/commands/get_core_cmd.py +7 -6
- stubber/commands/get_docstubs_cmd.py +8 -3
- stubber/commands/get_frozen_cmd.py +5 -2
- stubber/publish/publish.py +18 -7
- stubber/utils/makeversionhdr.py +3 -2
- stubber/utils/versions.py +2 -1
- mpflash/mpflash/mpboard_id/board_info.csv +0 -2213
- mpflash/mpflash/mpboard_id/board_info.json +0 -19910
- {micropython_stubber-1.20.0.dist-info → micropython_stubber-1.20.2.dist-info}/LICENSE +0 -0
- {micropython_stubber-1.20.0.dist-info → micropython_stubber-1.20.2.dist-info}/WHEEL +0 -0
- {micropython_stubber-1.20.0.dist-info → micropython_stubber-1.20.2.dist-info}/entry_points.txt +0 -0
mpflash/mpflash/ask_input.py
CHANGED
@@ -5,97 +5,85 @@ Note: The prompts can use "{version}" and "{action}" to insert the version and a
|
|
5
5
|
The values are provided from the answers dictionary.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from
|
9
|
-
from pathlib import Path
|
10
|
-
from typing import Dict, List, Sequence, Tuple, Union
|
8
|
+
from typing import List, Sequence, Tuple, Union
|
11
9
|
|
12
10
|
from loguru import logger as log
|
13
11
|
|
14
|
-
from
|
15
|
-
from
|
16
|
-
from
|
17
|
-
from
|
18
|
-
|
19
|
-
|
20
|
-
@dataclass
|
21
|
-
class Params:
|
22
|
-
ports: List[str] = field(default_factory=list)
|
23
|
-
boards: List[str] = field(default_factory=list)
|
24
|
-
versions: List[str] = field(default_factory=list)
|
25
|
-
fw_folder: Path = Path()
|
26
|
-
|
27
|
-
|
28
|
-
@dataclass
|
29
|
-
class DownloadParams(Params):
|
30
|
-
clean: bool = False
|
31
|
-
force: bool = False
|
32
|
-
|
33
|
-
|
34
|
-
@dataclass
|
35
|
-
class FlashParams(Params):
|
36
|
-
# TODO: Should Serial port be a list?
|
37
|
-
serial: str = ""
|
38
|
-
erase: bool = True
|
39
|
-
bootloader: bool = True
|
40
|
-
cpu: str = ""
|
41
|
-
|
42
|
-
|
43
|
-
ParamType = Union[DownloadParams, FlashParams]
|
12
|
+
from .common import DownloadParams, FlashParams, ParamType
|
13
|
+
from .config import config
|
14
|
+
from .mpboard_id import get_known_boards_for_port, get_known_ports, known_stored_boards
|
15
|
+
from .mpremoteboard import MPRemoteBoard
|
16
|
+
from .vendor.versions import micropython_versions
|
44
17
|
|
45
18
|
|
46
19
|
def ask_missing_params(
|
47
20
|
params: ParamType,
|
48
|
-
action: str = "download",
|
49
21
|
) -> ParamType:
|
50
22
|
"""
|
51
23
|
Asks the user for parameters that have not been supplied on the commandline and returns the updated params.
|
52
24
|
|
53
25
|
Args:
|
54
26
|
params (ParamType): The parameters to be updated.
|
55
|
-
action (str, optional): The action to be performed. Defaults to "download".
|
56
27
|
|
57
28
|
Returns:
|
58
29
|
ParamType: The updated parameters.
|
59
30
|
"""
|
31
|
+
import inquirer
|
32
|
+
|
33
|
+
log.trace(f"ask_missing_params: {params}")
|
34
|
+
|
35
|
+
# if action flash, single input
|
36
|
+
# if action download, multiple input
|
37
|
+
multi_select = isinstance(params, DownloadParams)
|
38
|
+
action = "download" if isinstance(params, DownloadParams) else "flash"
|
60
39
|
if not config.interactive:
|
61
40
|
# no interactivity allowed
|
62
41
|
return params
|
63
|
-
# import only when needed to reduce load time
|
64
|
-
import inquirer
|
65
42
|
|
66
43
|
questions = []
|
67
|
-
answers = {"action": action}
|
68
|
-
if
|
44
|
+
answers: dict[str, Union[str, List]] = {"action": action}
|
45
|
+
if not multi_select:
|
69
46
|
if not params.serial or "?" in params.serial:
|
70
|
-
ask_serialport(
|
47
|
+
questions.append(ask_serialport(multi_select=False, bluetooth=False))
|
71
48
|
else:
|
72
49
|
answers["serial"] = params.serial
|
73
50
|
|
74
|
-
if
|
75
|
-
|
51
|
+
if params.versions == [] or "?" in params.versions:
|
52
|
+
questions.append(ask_mp_version(multi_select=multi_select, action=action))
|
76
53
|
else:
|
77
54
|
# versions is used to show only the boards for the selected versions
|
78
55
|
answers["versions"] = params.versions # type: ignore
|
79
56
|
|
80
57
|
if not params.boards or "?" in params.boards:
|
81
|
-
ask_port_board(
|
82
|
-
|
83
|
-
|
58
|
+
questions.extend(ask_port_board(multi_select=multi_select, action=action))
|
59
|
+
if questions:
|
60
|
+
answers = inquirer.prompt(questions, answers=answers) # type: ignore
|
84
61
|
if not answers:
|
85
62
|
# input cancelled by user
|
86
63
|
return [] # type: ignore
|
87
|
-
|
64
|
+
log.trace(f"answers: {answers}")
|
88
65
|
if isinstance(params, FlashParams) and "serial" in answers:
|
89
|
-
|
66
|
+
if isinstance(answers["serial"], str):
|
67
|
+
answers["serial"] = [answers["serial"]]
|
68
|
+
params.serial = [s.split()[0] for s in answers["serial"]] # split to remove the description
|
90
69
|
if "port" in answers:
|
91
|
-
params.ports = [
|
70
|
+
params.ports = [p for p in params.ports if p != "?"] # remove the "?" if present
|
71
|
+
params.ports.extend(answers["port"])
|
92
72
|
if "boards" in answers:
|
93
|
-
params.boards =
|
73
|
+
params.boards = [b for b in params.boards if b != "?"] # remove the "?" if present
|
74
|
+
params.boards.extend(answers["boards"] if isinstance(answers["boards"], list) else [answers["boards"]])
|
94
75
|
if "versions" in answers:
|
76
|
+
params.versions = [v for v in params.versions if v != "?"] # remove the "?" if present
|
95
77
|
# make sure it is a list
|
96
|
-
|
97
|
-
|
98
|
-
|
78
|
+
if isinstance(answers["versions"], (list, tuple)):
|
79
|
+
params.versions.extend(answers["versions"])
|
80
|
+
else:
|
81
|
+
params.versions.append(answers["versions"])
|
82
|
+
# remove duplicates
|
83
|
+
params.ports = list(set(params.ports))
|
84
|
+
params.boards = list(set(params.boards))
|
85
|
+
params.versions = list(set(params.versions))
|
86
|
+
log.trace(f"ask_missing_params returns: {params}")
|
99
87
|
|
100
88
|
return params
|
101
89
|
|
@@ -110,19 +98,18 @@ def filter_matching_boards(answers: dict) -> Sequence[Tuple[str, str]]:
|
|
110
98
|
Returns:
|
111
99
|
Sequence[Tuple[str, str]]: The filtered boards.
|
112
100
|
"""
|
101
|
+
versions = None
|
113
102
|
# if version is not asked ; then need to get the version from the inputs
|
114
103
|
if "versions" in answers:
|
115
|
-
|
116
|
-
if "stable" in
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
else:
|
125
|
-
some_boards = known_stored_boards(answers["port"])
|
104
|
+
versions = list(answers["versions"])
|
105
|
+
if "stable" in versions:
|
106
|
+
versions.remove("stable")
|
107
|
+
versions.append(micropython_versions()[-2]) # latest stable
|
108
|
+
elif "preview" in versions:
|
109
|
+
versions.remove("preview")
|
110
|
+
versions.extend((micropython_versions()[-1], micropython_versions()[-2])) # latest preview and stable
|
111
|
+
|
112
|
+
some_boards = known_stored_boards(answers["port"], versions) # or known_mp_boards(answers["port"])
|
126
113
|
|
127
114
|
if some_boards:
|
128
115
|
# Create a dictionary where the keys are the second elements of the tuples
|
@@ -131,11 +118,11 @@ def filter_matching_boards(answers: dict) -> Sequence[Tuple[str, str]]:
|
|
131
118
|
# Get the values of the dictionary, which are the unique items from the original list
|
132
119
|
some_boards = list(unique_dict.values())
|
133
120
|
else:
|
134
|
-
some_boards = [("No boards found", "")]
|
121
|
+
some_boards = [(f"No {answers['port']} boards found for version(s) {versions}", "")]
|
135
122
|
return some_boards
|
136
123
|
|
137
124
|
|
138
|
-
def ask_port_board(
|
125
|
+
def ask_port_board(*, multi_select: bool, action: str):
|
139
126
|
"""
|
140
127
|
Asks the user for the port and board selection.
|
141
128
|
|
@@ -149,31 +136,28 @@ def ask_port_board(questions: list, *, action: str):
|
|
149
136
|
# import only when needed to reduce load time
|
150
137
|
import inquirer
|
151
138
|
|
152
|
-
#
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
if action == "flash"
|
167
|
-
else "?"
|
168
|
-
),
|
169
|
-
choices=filter_matching_boards,
|
170
|
-
validate=lambda _, x: True if x else "Please select at least one board", # type: ignore
|
139
|
+
# if action flash, single input
|
140
|
+
# if action download, multiple input
|
141
|
+
inquirer_ux = inquirer.Checkbox if multi_select else inquirer.List
|
142
|
+
return [
|
143
|
+
inquirer.List(
|
144
|
+
"port",
|
145
|
+
message="Which port do you want to {action} " + "to {serial} ?" if action == "flash" else "?",
|
146
|
+
choices=get_known_ports(),
|
147
|
+
# autocomplete=True,
|
148
|
+
),
|
149
|
+
inquirer_ux(
|
150
|
+
"boards",
|
151
|
+
message=(
|
152
|
+
"Which {port} board firmware do you want to {action} " + "to {serial} ?" if action == "flash" else "?"
|
171
153
|
),
|
172
|
-
|
173
|
-
|
154
|
+
choices=filter_matching_boards,
|
155
|
+
validate=lambda _, x: True if x else "Please select at least one board", # type: ignore
|
156
|
+
),
|
157
|
+
]
|
174
158
|
|
175
159
|
|
176
|
-
def
|
160
|
+
def ask_mp_version(multi_select: bool, action: str):
|
177
161
|
"""
|
178
162
|
Asks the user for the version selection.
|
179
163
|
|
@@ -182,31 +166,43 @@ def ask_versions(questions: list, *, action: str):
|
|
182
166
|
action (str): The action to be performed.
|
183
167
|
|
184
168
|
Returns:
|
185
|
-
|
169
|
+
|
186
170
|
"""
|
187
171
|
# import only when needed to reduce load time
|
188
172
|
import inquirer
|
173
|
+
import inquirer.errors
|
174
|
+
|
175
|
+
input_ux = inquirer.Checkbox if multi_select else inquirer.List
|
189
176
|
|
190
|
-
input_ux = inquirer.Checkbox if action == "download" else inquirer.List
|
191
177
|
mp_versions: List[str] = micropython_versions()
|
192
|
-
mp_versions = [v for v in mp_versions if "preview" not in v]
|
193
|
-
mp_versions.append("preview")
|
194
178
|
mp_versions.reverse() # newest first
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
179
|
+
|
180
|
+
# remove the versions for which there are no known boards in the board_info.json
|
181
|
+
# todo: this may be a little slow
|
182
|
+
mp_versions = [v for v in mp_versions if "preview" in v or get_known_boards_for_port("stm32", [v])]
|
183
|
+
|
184
|
+
def at_least_one_validation(answers, current) -> bool:
|
185
|
+
if not current:
|
186
|
+
raise inquirer.errors.ValidationError("", reason="Please select at least one version")
|
187
|
+
if isinstance(current, list) and not any(current):
|
188
|
+
raise inquirer.errors.ValidationError("", reason="Please select at least one version")
|
189
|
+
return True
|
190
|
+
|
191
|
+
message = "Which version(s) do you want to {action} " + ("to {serial} ?" if action == "flash" else "?")
|
192
|
+
q = input_ux(
|
193
|
+
# inquirer.List(
|
194
|
+
"versions",
|
195
|
+
message=message,
|
196
|
+
# Hints would be nice , but needs a hint for each and every option
|
197
|
+
# hints=["Use space to select multiple options"],
|
198
|
+
choices=mp_versions,
|
199
|
+
autocomplete=True,
|
200
|
+
validate=at_least_one_validation, # type: ignore
|
206
201
|
)
|
202
|
+
return q
|
207
203
|
|
208
204
|
|
209
|
-
def ask_serialport(
|
205
|
+
def ask_serialport(*, multi_select: bool = False, bluetooth: bool = False):
|
210
206
|
"""
|
211
207
|
Asks the user for the serial port selection.
|
212
208
|
|
@@ -220,15 +216,11 @@ def ask_serialport(questions: list, *, action: str):
|
|
220
216
|
# import only when needed to reduce load time
|
221
217
|
import inquirer
|
222
218
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
validate=lambda _, x: True if x else "Please select or enter a serial port", # type: ignore
|
231
|
-
)
|
219
|
+
comports = MPRemoteBoard.connected_boards(bluetooth=bluetooth, description=True)
|
220
|
+
return inquirer.List(
|
221
|
+
"serial",
|
222
|
+
message="Which serial port do you want to {action} ?",
|
223
|
+
choices=comports,
|
224
|
+
other=True,
|
225
|
+
validate=lambda _, x: True if x else "Please select or enter a serial port", # type: ignore
|
232
226
|
)
|
233
|
-
|
234
|
-
return questions
|
mpflash/mpflash/cli_download.py
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
"""CLI to Download MicroPython firmware for specific ports, boards and versions."""
|
2
2
|
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import List, Tuple
|
5
4
|
|
6
5
|
import rich_click as click
|
7
6
|
from loguru import logger as log
|
8
7
|
|
9
|
-
from mpflash.
|
8
|
+
from mpflash.connected import connected_ports_boards
|
9
|
+
from mpflash.errors import MPFlashError
|
10
|
+
from mpflash.mpboard_id import find_known_board
|
10
11
|
from mpflash.vendor.versions import clean_version
|
11
12
|
|
12
|
-
from .ask_input import
|
13
|
+
from .ask_input import ask_missing_params
|
13
14
|
from .cli_group import cli
|
14
|
-
from .
|
15
|
+
from .common import DownloadParams
|
15
16
|
from .config import config
|
16
17
|
from .download import download
|
17
18
|
|
@@ -49,6 +50,28 @@ from .download import download
|
|
49
50
|
help="The board(s) to download the firmware for.",
|
50
51
|
metavar="BOARD_ID or ?",
|
51
52
|
)
|
53
|
+
@click.option(
|
54
|
+
"--serial",
|
55
|
+
"--serial-port",
|
56
|
+
"-s",
|
57
|
+
"serial",
|
58
|
+
default=["*"],
|
59
|
+
show_default=True,
|
60
|
+
multiple=True,
|
61
|
+
help="Which serial port(s) to flash",
|
62
|
+
metavar="SERIALPORT",
|
63
|
+
)
|
64
|
+
@click.option(
|
65
|
+
"--ignore",
|
66
|
+
"-i",
|
67
|
+
is_eager=True,
|
68
|
+
help="Serial port(s) to ignore. Defaults to MPFLASH_IGNORE.",
|
69
|
+
multiple=True,
|
70
|
+
default=[],
|
71
|
+
envvar="MPFLASH_IGNORE",
|
72
|
+
show_default=True,
|
73
|
+
metavar="SERIALPORT",
|
74
|
+
)
|
52
75
|
@click.option(
|
53
76
|
"--clean/--no-clean",
|
54
77
|
default=True,
|
@@ -62,46 +85,44 @@ from .download import download
|
|
62
85
|
show_default=True,
|
63
86
|
help="""Force download of firmware even if it already exists.""",
|
64
87
|
)
|
65
|
-
def cli_download(
|
66
|
-
**kwargs,
|
67
|
-
):
|
88
|
+
def cli_download(**kwargs) -> int:
|
68
89
|
params = DownloadParams(**kwargs)
|
69
90
|
params.versions = list(params.versions)
|
70
91
|
params.boards = list(params.boards)
|
92
|
+
params.serial = list(params.serial)
|
93
|
+
params.ignore = list(params.ignore)
|
94
|
+
|
95
|
+
# all_boards: List[MPRemoteBoard] = []
|
71
96
|
if params.boards:
|
72
|
-
|
73
|
-
|
97
|
+
if not params.ports:
|
98
|
+
# no ports specified - resolve ports from specified boards by resolving board IDs
|
99
|
+
for board in params.boards:
|
100
|
+
if board != "?":
|
101
|
+
try:
|
102
|
+
board_ = find_known_board(board)
|
103
|
+
params.ports.append(board_.port)
|
104
|
+
except MPFlashError as e:
|
105
|
+
log.error(f"{e}")
|
74
106
|
else:
|
75
|
-
# no boards specified - detect connected boards
|
76
|
-
params.ports, params.boards = connected_ports_boards()
|
107
|
+
# no boards specified - detect connected ports and boards
|
108
|
+
params.ports, params.boards, _ = connected_ports_boards(include=params.serial, ignore=params.ignore)
|
77
109
|
|
78
|
-
params = ask_missing_params(params
|
110
|
+
params = ask_missing_params(params)
|
79
111
|
if not params: # Cancelled by user
|
80
|
-
|
112
|
+
return 2
|
81
113
|
params.versions = [clean_version(v, drop_v=True) for v in params.versions]
|
82
114
|
assert isinstance(params, DownloadParams)
|
83
115
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
116
|
+
try:
|
117
|
+
download(
|
118
|
+
params.fw_folder,
|
119
|
+
params.ports,
|
120
|
+
params.boards,
|
121
|
+
params.versions,
|
122
|
+
params.force,
|
123
|
+
params.clean,
|
124
|
+
)
|
125
|
+
return 0
|
126
|
+
except MPFlashError as e:
|
127
|
+
log.error(f"{e}")
|
128
|
+
return 1
|
mpflash/mpflash/cli_flash.py
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
from pathlib import Path
|
2
|
+
from typing import List
|
2
3
|
|
3
4
|
import rich_click as click
|
4
5
|
from loguru import logger as log
|
5
6
|
|
7
|
+
# from mpflash.common import filtered_comports
|
6
8
|
from mpflash.errors import MPFlashError
|
7
|
-
from mpflash.mpboard_id import
|
9
|
+
from mpflash.mpboard_id import find_known_board
|
10
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
8
11
|
from mpflash.vendor.versions import clean_version
|
9
12
|
|
10
|
-
from .ask_input import
|
13
|
+
from .ask_input import ask_missing_params
|
11
14
|
from .cli_download import connected_ports_boards
|
12
15
|
from .cli_group import cli
|
13
16
|
from .cli_list import show_mcus
|
17
|
+
from .common import FlashParams
|
14
18
|
from .config import config
|
15
19
|
from .flash import flash_list
|
16
|
-
from .worklist import
|
20
|
+
from .worklist import WorkList, full_auto_worklist, manual_worklist, single_auto_worklist
|
17
21
|
|
18
22
|
# #########################################################################################################
|
19
23
|
# CLI
|
@@ -28,7 +32,7 @@ from .worklist import MPRemoteBoard, WorkList, full_auto_worklist, manual_workli
|
|
28
32
|
"--firmware",
|
29
33
|
"-f",
|
30
34
|
"fw_folder",
|
31
|
-
type=click.Path(
|
35
|
+
type=click.Path(file_okay=False, dir_okay=True, path_type=Path),
|
32
36
|
default=config.firmware_folder,
|
33
37
|
show_default=True,
|
34
38
|
help="The folder to retrieve the firmware from.",
|
@@ -48,10 +52,22 @@ from .worklist import MPRemoteBoard, WorkList, full_auto_worklist, manual_workli
|
|
48
52
|
"--serial-port",
|
49
53
|
"-s",
|
50
54
|
"serial",
|
51
|
-
default="
|
55
|
+
default=["*"],
|
56
|
+
multiple=True,
|
52
57
|
show_default=True,
|
53
58
|
help="Which serial port(s) to flash",
|
54
|
-
metavar="
|
59
|
+
metavar="SERIALPORT",
|
60
|
+
)
|
61
|
+
@click.option(
|
62
|
+
"--ignore",
|
63
|
+
"-i",
|
64
|
+
is_eager=True,
|
65
|
+
help="Serial port(s) to ignore. Defaults to MPFLASH_IGNORE.",
|
66
|
+
multiple=True,
|
67
|
+
default=[],
|
68
|
+
envvar="MPFLASH_IGNORE",
|
69
|
+
show_default=True,
|
70
|
+
metavar="SERIALPORT",
|
55
71
|
)
|
56
72
|
@click.option(
|
57
73
|
"--port",
|
@@ -91,7 +107,7 @@ from .worklist import MPRemoteBoard, WorkList, full_auto_worklist, manual_workli
|
|
91
107
|
show_default=True,
|
92
108
|
help="""Enter micropython bootloader mode before flashing.""",
|
93
109
|
)
|
94
|
-
def cli_flash_board(**kwargs):
|
110
|
+
def cli_flash_board(**kwargs) -> int:
|
95
111
|
# version to versions, board to boards
|
96
112
|
kwargs["versions"] = [kwargs.pop("version")] if kwargs["version"] != None else []
|
97
113
|
if kwargs["board"] is None:
|
@@ -101,33 +117,33 @@ def cli_flash_board(**kwargs):
|
|
101
117
|
kwargs["boards"] = [kwargs.pop("board")]
|
102
118
|
|
103
119
|
params = FlashParams(**kwargs)
|
120
|
+
params.versions = list(params.versions)
|
121
|
+
params.boards = list(params.boards)
|
122
|
+
params.serial = list(params.serial)
|
123
|
+
params.ignore = list(params.ignore)
|
124
|
+
|
125
|
+
# make it simple for the user to flash one board by asking for the serial port if not specified
|
126
|
+
if params.boards == ["?"] and params.serial == "*":
|
127
|
+
params.serial = ["?"]
|
128
|
+
|
129
|
+
# Detect connected boards if not specified,
|
130
|
+
# and ask for input if boards cannot be detected
|
131
|
+
all_boards: List[MPRemoteBoard] = []
|
104
132
|
if not params.boards or params.boards == []:
|
105
133
|
# nothing specified - detect connected boards
|
106
|
-
params.ports, params.boards = connected_ports_boards()
|
134
|
+
params.ports, params.boards, all_boards = connected_ports_boards(include=params.ports, ignore=params.ignore)
|
107
135
|
if params.boards == []:
|
108
136
|
# No MicroPython boards detected, but it could be unflashed or not in bootloader mode
|
109
137
|
# Ask for serial port and board_id to flash
|
110
|
-
params.serial = "?"
|
138
|
+
params.serial = ["?"]
|
111
139
|
params.boards = ["?"]
|
112
140
|
else:
|
113
|
-
|
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}")
|
141
|
+
resolve_board_ids(params)
|
126
142
|
|
127
143
|
# Ask for missing input if needed
|
128
|
-
params = ask_missing_params(params
|
144
|
+
params = ask_missing_params(params)
|
129
145
|
if not params: # Cancelled by user
|
130
|
-
|
146
|
+
return 2
|
131
147
|
# TODO: Just in time Download of firmware
|
132
148
|
|
133
149
|
assert isinstance(params, FlashParams)
|
@@ -135,27 +151,33 @@ def cli_flash_board(**kwargs):
|
|
135
151
|
if len(params.versions) > 1:
|
136
152
|
log.error(f"Only one version can be flashed at a time, not {params.versions}")
|
137
153
|
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
154
|
|
142
155
|
params.versions = [clean_version(v) for v in params.versions]
|
143
156
|
worklist: WorkList = []
|
144
157
|
# if serial port == auto and there are one or more specified/detected boards
|
145
|
-
if params.serial == "
|
146
|
-
|
158
|
+
if params.serial == ["*"] and params.boards:
|
159
|
+
if not all_boards:
|
160
|
+
log.trace("No boards detected yet, scanning for connected boards")
|
161
|
+
_, _, all_boards = connected_ports_boards(include=params.ports, ignore=params.ignore)
|
162
|
+
worklist = full_auto_worklist(
|
163
|
+
all_boards=all_boards,
|
164
|
+
version=params.versions[0],
|
165
|
+
fw_folder=params.fw_folder,
|
166
|
+
include=params.serial,
|
167
|
+
ignore=params.ignore,
|
168
|
+
)
|
147
169
|
elif params.versions[0] and params.boards[0] and params.serial:
|
148
|
-
# A
|
170
|
+
# A one or more serial port including the board / variant
|
149
171
|
worklist = manual_worklist(
|
150
|
-
params.
|
151
|
-
params.
|
152
|
-
params.
|
153
|
-
params.
|
172
|
+
params.serial[0],
|
173
|
+
board_id=params.boards[0],
|
174
|
+
version=params.versions[0],
|
175
|
+
fw_folder=params.fw_folder,
|
154
176
|
)
|
155
177
|
else:
|
156
178
|
# just this serial port on auto
|
157
179
|
worklist = single_auto_worklist(
|
158
|
-
|
180
|
+
serial=params.serial[0],
|
159
181
|
version=params.versions[0],
|
160
182
|
fw_folder=params.fw_folder,
|
161
183
|
)
|
@@ -168,3 +190,23 @@ def cli_flash_board(**kwargs):
|
|
168
190
|
):
|
169
191
|
log.info(f"Flashed {len(flashed)} boards")
|
170
192
|
show_mcus(flashed, title="Updated boards after flashing")
|
193
|
+
return 0
|
194
|
+
else:
|
195
|
+
log.error("No boards were flashed")
|
196
|
+
return 1
|
197
|
+
|
198
|
+
|
199
|
+
def resolve_board_ids(params):
|
200
|
+
"""Resolve board descriptions to board_id, and remove empty strings from list of boards"""
|
201
|
+
for board_id in params.boards:
|
202
|
+
if board_id == "":
|
203
|
+
params.boards.remove(board_id)
|
204
|
+
continue
|
205
|
+
if " " in board_id:
|
206
|
+
try:
|
207
|
+
if info := find_known_board(board_id):
|
208
|
+
log.info(f"Resolved board description: {info.board_id}")
|
209
|
+
params.boards.remove(board_id)
|
210
|
+
params.boards.append(info.board_id)
|
211
|
+
except Exception as e:
|
212
|
+
log.warning(f"Unable to resolve board description: {e}")
|