mpflash 1.24.6__py3-none-any.whl → 1.24.8__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 +7 -7
- mpflash/basicgit.py +23 -57
- mpflash/bootloader/__init__.py +0 -2
- mpflash/bootloader/activate.py +1 -1
- mpflash/bootloader/detect.py +1 -2
- mpflash/bootloader/manual.py +0 -1
- mpflash/bootloader/touch1200.py +2 -2
- mpflash/cli_flash.py +28 -5
- mpflash/cli_group.py +1 -0
- mpflash/cli_list.py +2 -2
- mpflash/cli_main.py +1 -1
- mpflash/common.py +6 -14
- mpflash/config.py +26 -7
- mpflash/connected.py +6 -14
- mpflash/download.py +56 -23
- mpflash/downloaded.py +1 -5
- mpflash/flash/__init__.py +33 -18
- mpflash/flash/esp.py +40 -9
- mpflash/flash/uf2/__init__.py +18 -2
- mpflash/flash/uf2/linux.py +4 -9
- mpflash/flash/uf2/macos.py +1 -1
- mpflash/flash/uf2/windows.py +1 -1
- mpflash/flash/worklist.py +7 -2
- mpflash/list.py +17 -6
- mpflash/logger.py +1 -3
- mpflash/mpboard_id/__init__.py +6 -87
- mpflash/mpboard_id/add_boards.py +6 -8
- mpflash/mpboard_id/board_id.py +7 -6
- mpflash/mpboard_id/board_info.json +30974 -0
- mpflash/mpboard_id/board_info.zip +0 -0
- mpflash/mpboard_id/known.py +94 -0
- mpflash/mpboard_id/store.py +0 -2
- mpflash/mpremoteboard/__init__.py +13 -9
- mpflash/mpremoteboard/mpy_fw_info.py +14 -17
- mpflash/py.typed +0 -0
- mpflash/vendor/click_aliases.py +64 -0
- mpflash/vendor/dfu.py +2 -8
- mpflash/vendor/pico-universal-flash-nuke/LICENSE.txt +21 -0
- mpflash/vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2 +0 -0
- mpflash/vendor/pydfu.py +3 -14
- mpflash/vendor/readme.md +2 -0
- mpflash/versions.py +9 -6
- {mpflash-1.24.6.dist-info → mpflash-1.24.8.dist-info}/METADATA +71 -13
- mpflash-1.24.8.dist-info/RECORD +59 -0
- {mpflash-1.24.6.dist-info → mpflash-1.24.8.dist-info}/WHEEL +1 -1
- mpflash-1.24.6.dist-info/RECORD +0 -54
- {mpflash-1.24.6.dist-info → mpflash-1.24.8.dist-info}/LICENSE +0 -0
- {mpflash-1.24.6.dist-info → mpflash-1.24.8.dist-info}/entry_points.txt +0 -0
Binary file
|
@@ -0,0 +1,94 @@
|
|
1
|
+
"""
|
2
|
+
KNOWN ports and boards are sourced from the micropython repo,
|
3
|
+
this info is stored in the board_info.json file
|
4
|
+
and is used to identify the board and port for flashing.
|
5
|
+
This module provides access to the board info and the known ports and boards."""
|
6
|
+
|
7
|
+
from functools import lru_cache
|
8
|
+
from typing import List, Optional, Tuple
|
9
|
+
|
10
|
+
from mpflash.errors import MPFlashError
|
11
|
+
from mpflash.versions import clean_version
|
12
|
+
|
13
|
+
from .board import Board
|
14
|
+
from .store import read_known_boardinfo
|
15
|
+
|
16
|
+
|
17
|
+
def get_known_ports() -> List[str]:
|
18
|
+
# TODO: Filter for Version
|
19
|
+
mp_boards = read_known_boardinfo()
|
20
|
+
# select the unique ports from info
|
21
|
+
ports = set({board.port for board in mp_boards if board.port})
|
22
|
+
return sorted(list(ports))
|
23
|
+
|
24
|
+
|
25
|
+
def get_known_boards_for_port(port: Optional[str] = "", versions: Optional[List[str]] = None) -> List[Board]:
|
26
|
+
"""
|
27
|
+
Returns a list of boards for the given port and version(s)
|
28
|
+
|
29
|
+
port: The Micropython port to filter for
|
30
|
+
versions: Optional, The Micropython versions to filter for (actual versions required)
|
31
|
+
"""
|
32
|
+
mp_boards = read_known_boardinfo()
|
33
|
+
if versions:
|
34
|
+
preview_or_stable = "preview" in versions or "stable" in versions
|
35
|
+
else:
|
36
|
+
preview_or_stable = False
|
37
|
+
|
38
|
+
# filter for 'preview' as they are not in the board_info.json
|
39
|
+
# instead use stable version
|
40
|
+
versions = versions or []
|
41
|
+
if "preview" in versions:
|
42
|
+
versions.remove("preview")
|
43
|
+
versions.append("stable")
|
44
|
+
if versions:
|
45
|
+
# make sure of the v prefix
|
46
|
+
versions = [clean_version(v) for v in versions]
|
47
|
+
# filter for the version(s)
|
48
|
+
mp_boards = [board for board in mp_boards if board.version in versions]
|
49
|
+
if not mp_boards and preview_or_stable:
|
50
|
+
# nothing found - perhaps there is a newer version for which we do not have the board info yet
|
51
|
+
# use the latest known version from the board info
|
52
|
+
mp_boards = read_known_boardinfo()
|
53
|
+
last_known_version = sorted({b.version for b in mp_boards})[-1]
|
54
|
+
mp_boards = [board for board in mp_boards if board.version == last_known_version]
|
55
|
+
|
56
|
+
# filter for the port
|
57
|
+
if port:
|
58
|
+
mp_boards = [board for board in mp_boards if board.port == port]
|
59
|
+
return mp_boards
|
60
|
+
|
61
|
+
|
62
|
+
def known_stored_boards(port: str, versions: Optional[List[str]] = None) -> List[Tuple[str, str]]:
|
63
|
+
"""
|
64
|
+
Returns a list of tuples with the description and board name for the given port and version
|
65
|
+
|
66
|
+
port : str : The Micropython port to filter for
|
67
|
+
versions : List[str] : The Micropython versions to filter for (actual versions required)
|
68
|
+
"""
|
69
|
+
mp_boards = get_known_boards_for_port(port, versions)
|
70
|
+
|
71
|
+
boards = set({(f"{board.version} {board.description}", board.board_id) for board in mp_boards})
|
72
|
+
return sorted(list(boards))
|
73
|
+
|
74
|
+
|
75
|
+
@lru_cache(maxsize=20)
|
76
|
+
def find_known_board(board_id: str) -> Board:
|
77
|
+
"""Find the board for the given BOARD_ID or 'board description' and return the board info as a Board object"""
|
78
|
+
# Some functional overlap with:
|
79
|
+
# mpboard_id\board_id.py _find_board_id_by_description
|
80
|
+
info = read_known_boardinfo()
|
81
|
+
for board_info in info:
|
82
|
+
if board_id in (
|
83
|
+
board_info.board_id,
|
84
|
+
board_info.description,
|
85
|
+
) or board_info.description.startswith(board_id):
|
86
|
+
if not board_info.cpu:
|
87
|
+
# failsafe for older board_info.json files
|
88
|
+
print(f"Board {board_id} has no CPU info, using port as CPU")
|
89
|
+
if " with " in board_info.description:
|
90
|
+
board_info.cpu = board_info.description.split(" with ")[-1]
|
91
|
+
else:
|
92
|
+
board_info.cpu = board_info.port
|
93
|
+
return board_info
|
94
|
+
raise MPFlashError(f"Board {board_id} not found")
|
mpflash/mpboard_id/store.py
CHANGED
@@ -19,7 +19,6 @@ def write_boardinfo_json(board_list: List[Board], *, folder: Optional[Path] = No
|
|
19
19
|
board_list (List[Board]): The list of Board objects.
|
20
20
|
folder (Path): The folder where the compressed JSON file will be saved.
|
21
21
|
"""
|
22
|
-
import zipfile
|
23
22
|
|
24
23
|
if not folder:
|
25
24
|
folder = HERE
|
@@ -34,7 +33,6 @@ def write_boardinfo_json(board_list: List[Board], *, folder: Optional[Path] = No
|
|
34
33
|
def read_known_boardinfo(board_info: Optional[Path] = None) -> List[Board]:
|
35
34
|
"""Reads the board information from a JSON file in a zip file."""
|
36
35
|
|
37
|
-
import zipfile
|
38
36
|
|
39
37
|
if not board_info:
|
40
38
|
board_info = HERE / "board_info.zip"
|
@@ -2,6 +2,8 @@
|
|
2
2
|
Module to run mpremote commands, and retry on failure or timeout
|
3
3
|
"""
|
4
4
|
|
5
|
+
|
6
|
+
import contextlib
|
5
7
|
import sys
|
6
8
|
import time
|
7
9
|
from pathlib import Path
|
@@ -51,6 +53,7 @@ class MPRemoteBoard:
|
|
51
53
|
self.version = ""
|
52
54
|
self.port = ""
|
53
55
|
self.board = ""
|
56
|
+
self.variant= ""
|
54
57
|
self.cpu = ""
|
55
58
|
self.arch = ""
|
56
59
|
self.mpy = ""
|
@@ -65,9 +68,9 @@ class MPRemoteBoard:
|
|
65
68
|
Return a string representation of the MPRemoteBoard object.
|
66
69
|
|
67
70
|
Returns:
|
68
|
-
- str:
|
71
|
+
- str: A human readable representation of the MCU.
|
69
72
|
"""
|
70
|
-
return f"MPRemoteBoard({self.serialport}, {self.family} {self.port}, {self.board}, {self.version})"
|
73
|
+
return f"MPRemoteBoard({self.serialport}, {self.family} {self.port}, {self.board}{f'-{self.variant}' if self.variant else ''}, {self.version})"
|
71
74
|
|
72
75
|
@staticmethod
|
73
76
|
def connected_boards(bluetooth: bool = False, description: bool = False) -> List[str]:
|
@@ -137,9 +140,12 @@ class MPRemoteBoard:
|
|
137
140
|
self.description = descr = info["board"]
|
138
141
|
pos = descr.rfind(" with")
|
139
142
|
short_descr = descr[:pos].strip() if pos != -1 else ""
|
140
|
-
if
|
141
|
-
|
142
|
-
|
143
|
+
if info["_build"]:
|
144
|
+
self.board = info["_build"].split('-')[0]
|
145
|
+
self.variant = info["_build"].split('-')[1] if '-' in info["_build"] else ""
|
146
|
+
elif board_name := find_board_id_by_description(
|
147
|
+
descr, short_descr, version=self.version
|
148
|
+
):
|
143
149
|
self.board = board_name
|
144
150
|
else:
|
145
151
|
self.board = "UNKNOWN_BOARD"
|
@@ -168,7 +174,7 @@ class MPRemoteBoard:
|
|
168
174
|
log_errors=False,
|
169
175
|
)
|
170
176
|
except Exception as e:
|
171
|
-
raise ConnectionError(f"Failed to get board_info.toml for {self.serialport}:
|
177
|
+
raise ConnectionError(f"Failed to get board_info.toml for {self.serialport}:") from e
|
172
178
|
# this is optional - so only parse if we got the file
|
173
179
|
self.toml = {}
|
174
180
|
if rc in [OK]: # sometimes we get an -9 ???
|
@@ -264,8 +270,6 @@ class MPRemoteBoard:
|
|
264
270
|
total=timeout,
|
265
271
|
):
|
266
272
|
time.sleep(1)
|
267
|
-
|
273
|
+
with contextlib.suppress(ConnectionError, MPFlashError):
|
268
274
|
self.get_mcu_info()
|
269
275
|
break
|
270
|
-
except (ConnectionError, MPFlashError):
|
271
|
-
pass
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# pragma: no cover
|
2
2
|
import os
|
3
3
|
import sys
|
4
4
|
|
@@ -11,11 +11,11 @@ def _build(s):
|
|
11
11
|
return ""
|
12
12
|
s = s.split(" on ", 1)[0] if " on " in s else s
|
13
13
|
if s.startswith("v"):
|
14
|
-
if
|
14
|
+
if "-" not in s:
|
15
15
|
return ""
|
16
16
|
b = s.split("-")[1]
|
17
17
|
return b
|
18
|
-
if
|
18
|
+
if "-preview" not in s:
|
19
19
|
return ""
|
20
20
|
b = s.split("-preview")[1].split(".")[1]
|
21
21
|
return b
|
@@ -36,10 +36,9 @@ def _info(): # type:() -> dict[str, str]
|
|
36
36
|
"version": "",
|
37
37
|
"build": "",
|
38
38
|
"ver": "",
|
39
|
-
"port": (
|
40
|
-
"stm32" if sys.platform.startswith("pyb") else sys.platform
|
41
|
-
), # port: esp32 / win32 / linux / stm32
|
39
|
+
"port": ("stm32" if sys.platform.startswith("pyb") else sys.platform), # port: esp32 / win32 / linux / stm32
|
42
40
|
"board": "GENERIC",
|
41
|
+
"_build": "",
|
43
42
|
"cpu": "",
|
44
43
|
"mpy": "",
|
45
44
|
"arch": "",
|
@@ -50,17 +49,16 @@ def _info(): # type:() -> dict[str, str]
|
|
50
49
|
except AttributeError:
|
51
50
|
pass
|
52
51
|
try:
|
53
|
-
machine = (
|
54
|
-
sys.implementation._machine
|
55
|
-
if "_machine" in dir(sys.implementation)
|
56
|
-
else os.uname().machine
|
57
|
-
)
|
52
|
+
machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore
|
58
53
|
info["board"] = machine.strip()
|
54
|
+
info["_build"] = sys.implementation._build if "_build" in dir(sys.implementation) else ""
|
59
55
|
info["cpu"] = machine.split("with")[-1].strip() if "with" in machine else ""
|
60
56
|
info["mpy"] = (
|
61
57
|
sys.implementation._mpy
|
62
58
|
if "_mpy" in dir(sys.implementation)
|
63
|
-
else sys.implementation.mpy
|
59
|
+
else sys.implementation.mpy
|
60
|
+
if "mpy" in dir(sys.implementation)
|
61
|
+
else ""
|
64
62
|
)
|
65
63
|
except (AttributeError, IndexError):
|
66
64
|
pass
|
@@ -69,10 +67,10 @@ def _info(): # type:() -> dict[str, str]
|
|
69
67
|
if hasattr(sys, "version"):
|
70
68
|
info["build"] = _build(sys.version)
|
71
69
|
elif hasattr(os, "uname"):
|
72
|
-
info["build"] = _build(os.uname()[3])
|
70
|
+
info["build"] = _build(os.uname()[3]) # type: ignore
|
73
71
|
if not info["build"]:
|
74
72
|
# extract build from uname().release if available
|
75
|
-
info["build"] = _build(os.uname()[2])
|
73
|
+
info["build"] = _build(os.uname()[2]) # type: ignore
|
76
74
|
except (AttributeError, IndexError):
|
77
75
|
pass
|
78
76
|
# avoid build hashes
|
@@ -81,7 +79,7 @@ def _info(): # type:() -> dict[str, str]
|
|
81
79
|
|
82
80
|
if info["version"] == "" and sys.platform not in ("unix", "win32"):
|
83
81
|
try:
|
84
|
-
u = os.uname()
|
82
|
+
u = os.uname() # type: ignore
|
85
83
|
info["version"] = u.release
|
86
84
|
except (IndexError, AttributeError, TypeError):
|
87
85
|
pass
|
@@ -106,8 +104,7 @@ def _info(): # type:() -> dict[str, str]
|
|
106
104
|
if (
|
107
105
|
info["version"]
|
108
106
|
and info["version"].endswith(".0")
|
109
|
-
and info["version"]
|
110
|
-
>= "1.10.0" # versions from 1.10.0 to 1.20.0 do not have a micro .0
|
107
|
+
and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.20.0 do not have a micro .0
|
111
108
|
and info["version"] <= "1.19.9"
|
112
109
|
):
|
113
110
|
# drop the .0 for newer releases
|
mpflash/py.typed
ADDED
File without changes
|
mpflash/vendor/click_aliases.py
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
# The above copyright notice and this permission notice shall be included in all
|
11
11
|
# copies or substantial portions of the Software.
|
12
12
|
# ------------------------------------------------------------------------------------
|
13
|
+
# Jos Verlinde - 2024
|
13
14
|
# modified to avoid conflcts with rich_click
|
14
15
|
|
15
16
|
# sourcery skip: assign-if-exp, use-named-expression
|
@@ -20,12 +21,36 @@ _click7 = click.__version__[0] >= "7"
|
|
20
21
|
|
21
22
|
|
22
23
|
class ClickAliasedGroup(click.RichGroup):
|
24
|
+
"""
|
25
|
+
A subclass of click.RichGroup that adds support for command aliases.
|
26
|
+
|
27
|
+
This class allows defining aliases for commands and groups, enabling users
|
28
|
+
to invoke commands using alternative names.
|
29
|
+
"""
|
30
|
+
|
23
31
|
def __init__(self, *args, **kwargs):
|
32
|
+
"""
|
33
|
+
Initialize the ClickAliasedGroup instance.
|
34
|
+
|
35
|
+
Args:
|
36
|
+
*args: Positional arguments passed to the superclass.
|
37
|
+
**kwargs: Keyword arguments passed to the superclass.
|
38
|
+
"""
|
24
39
|
super().__init__(*args, **kwargs)
|
25
40
|
self._commands = {}
|
26
41
|
self._aliases = {}
|
27
42
|
|
28
43
|
def add_command(self, *args, **kwargs):
|
44
|
+
"""
|
45
|
+
Add a command to the group, optionally with aliases.
|
46
|
+
|
47
|
+
Args:
|
48
|
+
*args: Positional arguments, typically the command instance and optionally its name.
|
49
|
+
**kwargs: Keyword arguments, may include 'aliases' as a list of alternative names.
|
50
|
+
|
51
|
+
Raises:
|
52
|
+
TypeError: If the command has no name.
|
53
|
+
"""
|
29
54
|
aliases = kwargs.pop("aliases", [])
|
30
55
|
super().add_command(*args, **kwargs)
|
31
56
|
if aliases:
|
@@ -40,6 +65,16 @@ class ClickAliasedGroup(click.RichGroup):
|
|
40
65
|
self._aliases[alias] = cmd.name
|
41
66
|
|
42
67
|
def command(self, *args, **kwargs):
|
68
|
+
"""
|
69
|
+
Decorator to define a new command with optional aliases.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
*args: Positional arguments passed to the superclass decorator.
|
73
|
+
**kwargs: Keyword arguments, may include 'aliases' as a list of alternative names.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
Callable: A decorator function that registers the command and its aliases.
|
77
|
+
"""
|
43
78
|
aliases = kwargs.pop("aliases", [])
|
44
79
|
decorator = super().command(*args, **kwargs)
|
45
80
|
if not aliases:
|
@@ -56,6 +91,16 @@ class ClickAliasedGroup(click.RichGroup):
|
|
56
91
|
return _decorator
|
57
92
|
|
58
93
|
def group(self, *args, **kwargs):
|
94
|
+
"""
|
95
|
+
Decorator to define a new command group with optional aliases.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
*args: Positional arguments passed to the superclass decorator.
|
99
|
+
**kwargs: Keyword arguments, may include 'aliases' as a list of alternative names.
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
Callable: A decorator function that registers the group and its aliases.
|
103
|
+
"""
|
59
104
|
aliases = kwargs.pop("aliases", [])
|
60
105
|
decorator = super().group(*args, **kwargs)
|
61
106
|
if not aliases:
|
@@ -72,11 +117,30 @@ class ClickAliasedGroup(click.RichGroup):
|
|
72
117
|
return _decorator
|
73
118
|
|
74
119
|
def resolve_alias(self, cmd_name):
|
120
|
+
"""
|
121
|
+
Resolve a command alias to its original command name.
|
122
|
+
|
123
|
+
Args:
|
124
|
+
cmd_name (str): The command name or alias to resolve.
|
125
|
+
|
126
|
+
Returns:
|
127
|
+
str: The original command name if an alias is provided; otherwise, the input name.
|
128
|
+
"""
|
75
129
|
if cmd_name in self._aliases:
|
76
130
|
return self._aliases[cmd_name]
|
77
131
|
return cmd_name
|
78
132
|
|
79
133
|
def get_command(self, ctx, cmd_name):
|
134
|
+
"""
|
135
|
+
Retrieve a command by name or alias.
|
136
|
+
|
137
|
+
Args:
|
138
|
+
ctx (click.Context): The Click context object.
|
139
|
+
cmd_name (str): The command name or alias to retrieve.
|
140
|
+
|
141
|
+
Returns:
|
142
|
+
click.Command or None: The command object if found; otherwise, None.
|
143
|
+
"""
|
80
144
|
cmd_name = self.resolve_alias(cmd_name)
|
81
145
|
command = super().get_command(ctx, cmd_name)
|
82
146
|
if command:
|
mpflash/vendor/dfu.py
CHANGED
@@ -46,10 +46,7 @@ def parse(file, dump_images=False):
|
|
46
46
|
tprefix["name"] = cstring(tprefix["name"])
|
47
47
|
else:
|
48
48
|
tprefix["name"] = ""
|
49
|
-
print(
|
50
|
-
'%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d'
|
51
|
-
% tprefix
|
52
|
-
)
|
49
|
+
print('%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix)
|
53
50
|
tsize = tprefix["size"]
|
54
51
|
target, data = data[:tsize], data[tsize:]
|
55
52
|
for e in range(tprefix["elements"]):
|
@@ -65,10 +62,7 @@ def parse(file, dump_images=False):
|
|
65
62
|
if len(target):
|
66
63
|
print("target %d: PARSE ERROR" % t)
|
67
64
|
suffix = named(struct.unpack("<4H3sBI", data[:16]), "device product vendor dfu ufd len crc")
|
68
|
-
print(
|
69
|
-
"usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x"
|
70
|
-
% suffix
|
71
|
-
)
|
65
|
+
print("usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x" % suffix)
|
72
66
|
if crc != suffix["crc"]:
|
73
67
|
print("CRC ERROR: computed crc32 is 0x%08x" % crc)
|
74
68
|
data = data[16:]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright 2024 Phil Howard
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
4
|
+
following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
7
|
+
disclaimer.
|
8
|
+
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
10
|
+
disclaimer in the documentation and/or other materials provided with the distribution.
|
11
|
+
|
12
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
|
13
|
+
derived from this software without specific prior written permission.
|
14
|
+
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
16
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
18
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
19
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
20
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
21
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Binary file
|
mpflash/vendor/pydfu.py
CHANGED
@@ -395,10 +395,7 @@ def read_dfu_file(filename):
|
|
395
395
|
# B uint8_t len 16
|
396
396
|
# I uint32_t crc32 Checksum
|
397
397
|
dfu_suffix = named(struct.unpack("<4H3sBI", data[:16]), "device product vendor dfu ufd len crc")
|
398
|
-
print(
|
399
|
-
" usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, "
|
400
|
-
"dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x" % dfu_suffix
|
401
|
-
)
|
398
|
+
print(" usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, " "dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x" % dfu_suffix)
|
402
399
|
if crc != dfu_suffix["crc"]:
|
403
400
|
print("CRC ERROR: computed crc32 is 0x%08x" % crc)
|
404
401
|
return
|
@@ -477,19 +474,11 @@ def list_dfu_devices(*args, **kwargs):
|
|
477
474
|
if not devices:
|
478
475
|
raise SystemExit("No DFU capable devices found")
|
479
476
|
for device in devices:
|
480
|
-
print(
|
481
|
-
"Bus {} Device {:03d}: ID {:04x}:{:04x}".format(
|
482
|
-
device.bus, device.address, device.idVendor, device.idProduct
|
483
|
-
)
|
484
|
-
)
|
477
|
+
print("Bus {} Device {:03d}: ID {:04x}:{:04x}".format(device.bus, device.address, device.idVendor, device.idProduct))
|
485
478
|
layout = get_memory_layout(device)
|
486
479
|
print("Memory Layout")
|
487
480
|
for entry in layout:
|
488
|
-
print(
|
489
|
-
" 0x{:x} {:2d} pages of {:3d}K bytes".format(
|
490
|
-
entry["addr"], entry["num_pages"], entry["page_size"] // 1024
|
491
|
-
)
|
492
|
-
)
|
481
|
+
print(" 0x{:x} {:2d} pages of {:3d}K bytes".format(entry["addr"], entry["num_pages"], entry["page_size"] // 1024))
|
493
482
|
|
494
483
|
|
495
484
|
def write_elements(elements, mass_erase_used, progress=None):
|
mpflash/vendor/readme.md
CHANGED
mpflash/versions.py
CHANGED
@@ -6,10 +6,8 @@ from pathlib import Path
|
|
6
6
|
|
7
7
|
from cache_to_disk import NoCacheCondition, cache_to_disk
|
8
8
|
from loguru import logger as log
|
9
|
-
from packaging.version import Version, parse
|
10
9
|
|
11
|
-
|
12
|
-
from mpflash.common import GH_CLIENT
|
10
|
+
from mpflash.config import config
|
13
11
|
|
14
12
|
OLDEST_VERSION = "1.16"
|
15
13
|
"This is the oldest MicroPython version to build the stubs on"
|
@@ -71,15 +69,18 @@ def clean_version(
|
|
71
69
|
|
72
70
|
def is_version(version: str):
|
73
71
|
"""Check if the version is a valid version string"""
|
72
|
+
# Just in time import
|
73
|
+
from packaging.version import Version
|
74
74
|
return Version._regex.search(version) is not None
|
75
75
|
|
76
76
|
|
77
77
|
@cache_to_disk(n_days_to_cache=1)
|
78
78
|
def micropython_versions(minver: str = "v1.20", reverse: bool = False, cache_it=True):
|
79
79
|
"""Get the list of micropython versions from github tags"""
|
80
|
-
|
80
|
+
# Just in time import
|
81
|
+
from packaging.version import parse
|
81
82
|
try:
|
82
|
-
gh_client =
|
83
|
+
gh_client = config.gh_client
|
83
84
|
repo = gh_client.get_repo("micropython/micropython")
|
84
85
|
tags = [tag.name for tag in repo.get_tags() if parse(tag.name) >= parse(minver)]
|
85
86
|
versions = [v for v in tags if not v.endswith(V_PREVIEW)]
|
@@ -90,7 +91,7 @@ def micropython_versions(minver: str = "v1.20", reverse: bool = False, cache_it=
|
|
90
91
|
log.error(e)
|
91
92
|
versions = []
|
92
93
|
# returns - but does not cache
|
93
|
-
raise NoCacheCondition(function_value=versions)
|
94
|
+
raise NoCacheCondition(function_value=versions) from e
|
94
95
|
# remove any duplicates and sort
|
95
96
|
versions = sorted(list(set(versions)), reverse=reverse, key=lambda s: (not is_version(s), s))
|
96
97
|
if cache_it:
|
@@ -116,6 +117,8 @@ def get_preview_mp_version(cache_it=True) -> str:
|
|
116
117
|
# Do not cache , same path will have different versions checked out
|
117
118
|
def checkedout_version(path: Path, flat: bool = False) -> str:
|
118
119
|
"""Get the checked-out version of the repo"""
|
120
|
+
# Just in time import
|
121
|
+
import mpflash.basicgit as git
|
119
122
|
version = git.get_local_tag(path.as_posix())
|
120
123
|
if not version:
|
121
124
|
raise ValueError("No valid Tag found")
|