micropython-stubber 1.20.1__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.
Files changed (58) hide show
  1. {micropython_stubber-1.20.1.dist-info → micropython_stubber-1.20.2.dist-info}/METADATA +3 -3
  2. {micropython_stubber-1.20.1.dist-info → micropython_stubber-1.20.2.dist-info}/RECORD +56 -49
  3. mpflash/README.md +16 -5
  4. mpflash/mpflash/add_firmware.py +98 -0
  5. mpflash/mpflash/ask_input.py +97 -120
  6. mpflash/mpflash/cli_download.py +42 -25
  7. mpflash/mpflash/cli_flash.py +70 -32
  8. mpflash/mpflash/cli_group.py +14 -12
  9. mpflash/mpflash/cli_list.py +39 -3
  10. mpflash/mpflash/cli_main.py +17 -6
  11. mpflash/mpflash/common.py +125 -12
  12. mpflash/mpflash/config.py +2 -0
  13. mpflash/mpflash/connected.py +74 -0
  14. mpflash/mpflash/download.py +56 -42
  15. mpflash/mpflash/downloaded.py +9 -9
  16. mpflash/mpflash/flash.py +2 -2
  17. mpflash/mpflash/flash_esp.py +2 -2
  18. mpflash/mpflash/flash_uf2.py +16 -8
  19. mpflash/mpflash/flash_uf2_linux.py +5 -16
  20. mpflash/mpflash/flash_uf2_macos.py +78 -0
  21. mpflash/mpflash/flash_uf2_windows.py +1 -1
  22. mpflash/mpflash/list.py +57 -57
  23. mpflash/mpflash/mpboard_id/__init__.py +37 -44
  24. mpflash/mpflash/mpboard_id/add_boards.py +255 -0
  25. mpflash/mpflash/mpboard_id/board.py +37 -0
  26. mpflash/mpflash/mpboard_id/board_id.py +38 -34
  27. mpflash/mpflash/mpboard_id/board_info.zip +0 -0
  28. mpflash/mpflash/mpboard_id/store.py +42 -0
  29. mpflash/mpflash/mpremoteboard/__init__.py +18 -6
  30. mpflash/mpflash/uf2disk.py +12 -0
  31. mpflash/mpflash/vendor/basicgit.py +288 -0
  32. mpflash/mpflash/vendor/dfu.py +1 -0
  33. mpflash/mpflash/vendor/versions.py +7 -3
  34. mpflash/mpflash/worklist.py +71 -48
  35. mpflash/poetry.lock +164 -138
  36. mpflash/pyproject.toml +18 -15
  37. stubber/__init__.py +1 -1
  38. stubber/board/createstubs.py +4 -3
  39. stubber/board/createstubs_db.py +5 -7
  40. stubber/board/createstubs_db_min.py +329 -825
  41. stubber/board/createstubs_db_mpy.mpy +0 -0
  42. stubber/board/createstubs_mem.py +6 -7
  43. stubber/board/createstubs_mem_min.py +304 -765
  44. stubber/board/createstubs_mem_mpy.mpy +0 -0
  45. stubber/board/createstubs_min.py +293 -975
  46. stubber/board/createstubs_mpy.mpy +0 -0
  47. stubber/board/modulelist.txt +1 -0
  48. stubber/commands/get_core_cmd.py +7 -6
  49. stubber/commands/get_docstubs_cmd.py +8 -3
  50. stubber/commands/get_frozen_cmd.py +5 -2
  51. stubber/publish/publish.py +18 -7
  52. stubber/utils/makeversionhdr.py +3 -2
  53. stubber/utils/versions.py +2 -1
  54. mpflash/mpflash/mpboard_id/board_info.csv +0 -2213
  55. mpflash/mpflash/mpboard_id/board_info.json +0 -19910
  56. {micropython_stubber-1.20.1.dist-info → micropython_stubber-1.20.2.dist-info}/LICENSE +0 -0
  57. {micropython_stubber-1.20.1.dist-info → micropython_stubber-1.20.2.dist-info}/WHEEL +0 -0
  58. {micropython_stubber-1.20.1.dist-info → micropython_stubber-1.20.2.dist-info}/entry_points.txt +0 -0
@@ -4,53 +4,38 @@ that is included in the module.
4
4
 
5
5
  """
6
6
 
7
- import json
8
7
  from functools import lru_cache
9
- from pathlib import Path
10
- from typing import List, Optional, Tuple, TypedDict, Union
8
+ from typing import List, Optional, Tuple
11
9
 
12
10
  from mpflash.errors import MPFlashError
13
- from mpflash.common import PORT_FWTYPES
11
+ from mpflash.mpboard_id.board import Board
12
+ from mpflash.mpboard_id.store import read_known_boardinfo
14
13
  from mpflash.vendor.versions import clean_version
15
14
 
15
+ # KNOWN ports and boards are sourced from the micropython repo,
16
+ # this info is stored in the board_info.json file
16
17
 
17
- # Board based on the dataclass Board but changed to TypedDict
18
- # - source : get_boardnames.py
19
- class Board(TypedDict):
20
- """MicroPython Board definition"""
21
18
 
22
- description: str
23
- port: str
24
- board: str
25
- board_name: str
26
- mcu_name: str
27
- path: Union[Path, str]
28
- version: str
29
- cpu: str
30
-
31
-
32
- @lru_cache(maxsize=None)
33
- def read_stored_boardinfo() -> List[Board]:
34
- """Reads the board_info.json file and returns the data as a list of Board objects"""
35
- with open(Path(__file__).parent / "board_info.json", "r") as file:
36
- return json.load(file)
37
-
38
-
39
- def local_mp_ports() -> List[str]:
19
+ def get_known_ports() -> List[str]:
40
20
  # TODO: Filter for Version
41
- mp_boards = read_stored_boardinfo()
21
+ mp_boards = read_known_boardinfo()
42
22
  # select the unique ports from info
43
- ports = set({board["port"] for board in mp_boards if board["port"] in PORT_FWTYPES.keys()})
23
+ ports = set({board.port for board in mp_boards if board.port})
44
24
  return sorted(list(ports))
45
25
 
46
26
 
47
- def get_stored_boards_for_port(port: str, versions: Optional[List[str]] = None):
27
+ def get_known_boards_for_port(port: Optional[str] = "", versions: Optional[List[str]] = None) -> List[Board]:
48
28
  """
49
29
  Returns a list of boards for the given port and version(s)
50
30
 
51
- port : str : The Micropython port to filter for
52
- versions : List[str] : The Micropython versions to filter for (actual versions required)"""
53
- mp_boards = read_stored_boardinfo()
31
+ port: The Micropython port to filter for
32
+ versions: Optional, The Micropython versions to filter for (actual versions required)
33
+ """
34
+ mp_boards = read_known_boardinfo()
35
+ if versions:
36
+ preview_or_stable = "preview" in versions or "stable" in versions
37
+ else:
38
+ preview_or_stable = False
54
39
 
55
40
  # filter for 'preview' as they are not in the board_info.json
56
41
  # instead use stable version
@@ -62,9 +47,17 @@ def get_stored_boards_for_port(port: str, versions: Optional[List[str]] = None):
62
47
  # make sure of the v prefix
63
48
  versions = [clean_version(v) for v in versions]
64
49
  # filter for the version(s)
65
- mp_boards = [board for board in mp_boards if board["version"] in versions]
50
+ mp_boards = [board for board in mp_boards if board.version in versions]
51
+ if not mp_boards and preview_or_stable:
52
+ # nothing found - perhaps there is a newer version for which we do not have the board info yet
53
+ # use the latest known version from the board info
54
+ mp_boards = read_known_boardinfo()
55
+ last_known_version = sorted({b.version for b in mp_boards})[-1]
56
+ mp_boards = [board for board in mp_boards if board.version == last_known_version]
57
+
66
58
  # filter for the port
67
- mp_boards = [board for board in mp_boards if board["port"] == port]
59
+ if port:
60
+ mp_boards = [board for board in mp_boards if board.port == port]
68
61
  return mp_boards
69
62
 
70
63
 
@@ -75,22 +68,22 @@ def known_stored_boards(port: str, versions: Optional[List[str]] = None) -> List
75
68
  port : str : The Micropython port to filter for
76
69
  versions : List[str] : The Micropython versions to filter for (actual versions required)
77
70
  """
78
- mp_boards = get_stored_boards_for_port(port, versions)
71
+ mp_boards = get_known_boards_for_port(port, versions)
79
72
 
80
- boards = set({(f'{board["version"]} {board["description"]}', board["board"]) for board in mp_boards})
73
+ boards = set({(f"{board.version} {board.description}", board.board_id) for board in mp_boards})
81
74
  return sorted(list(boards))
82
75
 
83
76
 
84
77
  @lru_cache(maxsize=20)
85
- def find_stored_board(board_id: str) -> Board:
86
- """Find the board for the given board_ID or 'board description' and return the board info as a Board object"""
87
- info = read_stored_boardinfo()
78
+ def find_known_board(board_id: str) -> Board:
79
+ """Find the board for the given BOARD_ID or 'board description' and return the board info as a Board object"""
80
+ info = read_known_boardinfo()
88
81
  for board_info in info:
89
- if board_id in (board_info["board"], board_info["description"]):
90
- if "cpu" not in board_info or not board_info["cpu"]:
91
- if " with " in board_info["description"]:
92
- board_info["cpu"] = board_info["description"].split(" with ")[-1]
82
+ if board_id in (board_info.board_id, board_info.description):
83
+ if not board_info.cpu:
84
+ if " with " in board_info.description:
85
+ board_info.cpu = board_info.description.split(" with ")[-1]
93
86
  else:
94
- board_info["cpu"] = board_info["port"]
87
+ board_info.cpu = board_info.port
95
88
  return board_info
96
89
  raise MPFlashError(f"Board {board_id} not found")
@@ -0,0 +1,255 @@
1
+ """
2
+ Collects board name and description information from MicroPython and writes it to JSON and CSV files.
3
+ """
4
+
5
+ import re
6
+ from pathlib import Path
7
+ from typing import List, Optional
8
+
9
+ import inquirer
10
+ import rich
11
+ import rich.table
12
+ from rich.console import Console
13
+ from rich.progress import track
14
+
15
+ import mpflash.vendor.basicgit as git
16
+ from mpflash.logger import log
17
+ from mpflash.mpboard_id import Board
18
+ from mpflash.mpboard_id.store import write_boardinfo_json
19
+ from mpflash.vendor.versions import micropython_versions
20
+
21
+ # look for all mpconfigboard.h files and extract the board name
22
+ # from the #define MICROPY_HW_BOARD_NAME "PYBD_SF6"
23
+ # and the #define MICROPY_HW_MCU_NAME "STM32F767xx"
24
+ RE_H_MICROPY_HW_BOARD_NAME = re.compile(r"#define\s+MICROPY_HW_BOARD_NAME\s+\"(.+)\"")
25
+ RE_H_MICROPY_HW_MCU_NAME = re.compile(r"#define\s+MICROPY_HW_MCU_NAME\s+\"(.+)\"")
26
+ # find in the mpconfigboard.cmake files
27
+
28
+ RE_CMAKE_MICROPY_HW_BOARD_NAME = re.compile(r"MICROPY_HW_BOARD_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\"")
29
+ RE_CMAKE_MICROPY_HW_MCU_NAME = re.compile(r"MICROPY_HW_MCU_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\"")
30
+ # TODO: normal make files
31
+
32
+
33
+ def boards_from_repo(mpy_path: Path, version: str, family: Optional[str] = None) -> List[Board]:
34
+ """Collects board name and decriptions from mpconfigboard.h files.
35
+
36
+ Args:
37
+ mpy_path (Path): The path to the MicroPython repository.
38
+ version (str): The version of MicroPython.
39
+
40
+ Returns:
41
+ List[Board]: A list of Board objects containing the board information.
42
+ """
43
+ if not mpy_path.exists() or not mpy_path.is_dir():
44
+ raise FileNotFoundError(f"MicroPython path {mpy_path} does not exist.")
45
+ if not family:
46
+ family = "micropython"
47
+ if not version:
48
+ version = git.get_local_tag() # type: ignore
49
+ if not version:
50
+ raise ValueError("No version provided and no local tag found.")
51
+
52
+ board_list: List[Board] = []
53
+ # look in mpconfigboard.h files
54
+ board_list = boards_from_cmake(mpy_path, version, family)
55
+
56
+ # look for variants in the .cmake files
57
+ board_list.extend(boards_from_headers(mpy_path, version, family))
58
+ # TODO:? look for variants in the Makefile files
59
+
60
+ return board_list
61
+
62
+
63
+ def boards_from_cmake(mpy_path: Path, version: str, family: str):
64
+ """Get boards from the mpconfigboard.cmake files to the board_list."""
65
+ board_list = []
66
+ for path in mpy_path.glob("ports/**/mpconfigboard.cmake"):
67
+ board = path.parent.name
68
+ port = path.parent.parent.parent.name
69
+ with open(path, "r") as f:
70
+ board_name = mcu_name = "-"
71
+ for line in f:
72
+ line = line.strip()
73
+ if match := RE_CMAKE_MICROPY_HW_BOARD_NAME.match(line):
74
+ description = match["variant"]
75
+ board_list.append(
76
+ Board(
77
+ board_id=board,
78
+ port=port,
79
+ board_name=board_name,
80
+ mcu_name=mcu_name,
81
+ description=description,
82
+ path=path.relative_to(mpy_path),
83
+ version=version,
84
+ family=family,
85
+ )
86
+ )
87
+ elif match := RE_CMAKE_MICROPY_HW_MCU_NAME.match(line):
88
+ description = match["variant"]
89
+ board_list.append(
90
+ Board(
91
+ board_id=board,
92
+ port=port,
93
+ board_name=board_name,
94
+ mcu_name=mcu_name,
95
+ description=description,
96
+ path=path.relative_to(mpy_path),
97
+ version=version,
98
+ family=family,
99
+ )
100
+ )
101
+ return board_list
102
+
103
+
104
+ def boards_from_headers(mpy_path: Path, version: str, family: str):
105
+ """Get boards from the mpconfigboard.h files to the board_list."""
106
+ board_list = []
107
+ for path in mpy_path.glob("ports/**/mpconfigboard.h"):
108
+ board = path.parent.name
109
+ port = path.parent.parent.parent.name
110
+ with open(path, "r") as f:
111
+ board_name = mcu_name = "-"
112
+ found = 0
113
+ for line in f:
114
+ if match := RE_H_MICROPY_HW_BOARD_NAME.match(line):
115
+ board_name = match[1]
116
+ found += 1
117
+ elif match := RE_H_MICROPY_HW_MCU_NAME.match(line):
118
+ mcu_name = match[1]
119
+ found += 1
120
+ if found == 2:
121
+ description = f"{board_name} with {mcu_name}" if mcu_name != "-" else board_name
122
+ board_list.append(
123
+ Board(
124
+ board_id=board,
125
+ port=port,
126
+ board_name=board_name,
127
+ mcu_name=mcu_name,
128
+ description=description,
129
+ path=path.relative_to(mpy_path),
130
+ version=version,
131
+ family=family,
132
+ )
133
+ )
134
+ found = 0
135
+ if found == 1:
136
+ description = board_name
137
+ board_list.append(
138
+ Board(
139
+ board_id=board,
140
+ port=port,
141
+ board_name=board_name,
142
+ mcu_name=mcu_name,
143
+ description=description,
144
+ path=path.relative_to(mpy_path),
145
+ version=version,
146
+ family=family,
147
+ )
148
+ )
149
+ return board_list
150
+
151
+
152
+ def boards_for_versions(versions: List[str], mpy_path: Path):
153
+ """Gets the list of boards for multiple versions of MicroPython.
154
+
155
+ Args:
156
+ versions (List[str]): The list of MicroPython versions.
157
+ mpy_path (Path): The path to the MicroPython repository.
158
+
159
+ Returns:
160
+ List[Board]: The list of Board objects.
161
+ """
162
+ board_list: List[Board] = []
163
+ for version in track(versions, description="Searching MicroPython versions"):
164
+ if git.checkout_tag(tag=version, repo=mpy_path):
165
+ new_ones = boards_from_repo(mpy_path, version, family="micropython")
166
+ print(f"Found {len(new_ones)} board definitions for {version}.")
167
+ board_list += new_ones
168
+ else:
169
+ print(f"Could not checkout version {version}.")
170
+
171
+ # sort the board_list by description and board
172
+ print("Total number of boards found:", len(board_list))
173
+
174
+ board_list = unique_boards(board_list)
175
+ print("Unique board descriptions found:", len(board_list))
176
+ return board_list
177
+
178
+
179
+ def unique_boards(board_list: List[Board], *, key_version: bool = True):
180
+ """Remove duplicate boards by 'BOARD_ID description' from the list."""
181
+ seen = set()
182
+ result = []
183
+ for x in board_list:
184
+ if key_version:
185
+ key = f"{x.board_id}|{x.version}|{x.description}"
186
+ else:
187
+ key = f"{x.board_id}|{x.description}"
188
+ if key not in seen:
189
+ result.append(x)
190
+ seen.add(key)
191
+ result.sort(key=lambda x: x.description.lower())
192
+ return result
193
+
194
+
195
+ def make_table(board_list: List[Board]) -> rich.table.Table:
196
+ """Creates a rich table with board information."""
197
+ is_wide = True
198
+
199
+ table = rich.table.Table(title="MicroPython Board Information")
200
+ table.add_column("BOARD_ID", justify="left", style="green")
201
+ table.add_column("Description", justify="left", style="cyan")
202
+ table.add_column("Port", justify="left", style="magenta")
203
+ table.add_column("Board Name", justify="left", style="blue")
204
+ if is_wide:
205
+ table.add_column("MCU Name", justify="left", style="blue")
206
+ table.add_column("Detection", justify="left", style="yellow")
207
+ table.add_column("Version", justify="left", style="blue")
208
+ if is_wide:
209
+ table.add_column("Family", justify="left", style="blue")
210
+
211
+ for board in board_list:
212
+ row = [board.board_id, board.description, *(board.port, board.board_name)]
213
+ if is_wide:
214
+ row.append(board.mcu_name)
215
+ row.extend((str(Path(board.path).suffix), board.version))
216
+ if is_wide:
217
+ row.append(board.family)
218
+ table.add_row(*row)
219
+
220
+ return table
221
+
222
+
223
+ def ask_mpy_path():
224
+ """Ask the user for the path to the MicroPython repository."""
225
+ questions = [
226
+ inquirer.Text(
227
+ "mpy_path", message="Enter the path to the MicroPython repository", default=".\\repos\\micropython"
228
+ )
229
+ ]
230
+ if answers := inquirer.prompt(questions):
231
+ return Path(answers["mpy_path"])
232
+ else:
233
+ raise ValueError("No path provided.")
234
+
235
+
236
+ def main():
237
+ """Main function to collect and write board information."""
238
+
239
+ console = Console()
240
+
241
+ mpy_path = ask_mpy_path()
242
+ versions = micropython_versions(minver="v1.10") + ["master"]
243
+ board_list = boards_for_versions(versions, mpy_path)
244
+
245
+ here = Path(__file__).parent
246
+ log.info(write_boardinfo_json(board_list, folder=here))
247
+ # write_files(board_list, folder=CONFIG.board_path)
248
+
249
+ # table of when the board was added
250
+ table = make_table(unique_boards(board_list, key_version=False))
251
+ console.print(table)
252
+
253
+
254
+ if __name__ == "__main__":
255
+ main()
@@ -0,0 +1,37 @@
1
+ from dataclasses import dataclass, field
2
+ from pathlib import Path
3
+ from typing import Union
4
+
5
+
6
+ # - source : get_boardnames.py
7
+ @dataclass
8
+ class Board:
9
+ """
10
+ MicroPython Board definitions, parsed from the make and header files
11
+ """
12
+
13
+ port: str # micropython port
14
+ board_id: str # BOARD_ID (Foldername) as used in the make files
15
+ board_name: str # Short board description
16
+ description: str # Long board description
17
+ path: Union[Path, str]
18
+ version: str = field(default="") # version of MicroPython""
19
+ # versions: List[str] = field(default=[]) # version of MicroPython""
20
+ family: str = field(default="micropython")
21
+ mcu_name: str = field(default="")
22
+ cpu: str = field(default="")
23
+ # TODO: add variant
24
+
25
+ def __post_init__(self):
26
+ if not self.cpu:
27
+ if " with " in self.description:
28
+ self.cpu = self.description.split(" with ")[-1]
29
+ else:
30
+ self.cpu = self.port
31
+
32
+ @staticmethod
33
+ def from_dict(data: dict) -> "Board":
34
+ return Board(**data)
35
+
36
+ def to_dict(self) -> dict:
37
+ return self.__dict__
@@ -3,64 +3,68 @@ Translate board description to board designator
3
3
  """
4
4
 
5
5
  import functools
6
- import json
7
6
  from pathlib import Path
8
7
  from typing import Optional
9
8
 
10
9
  from mpflash.errors import MPFlashError
11
- from mpflash.vendor.versions import clean_version
10
+ from mpflash.logger import log
11
+ from mpflash.mpboard_id.store import read_known_boardinfo
12
+ from mpflash.vendor.versions import clean_version, get_stable_mp_version
12
13
 
13
- ###############################################################################################
14
- HERE = Path(__file__).parent
15
- ###############################################################################################
16
14
 
17
-
18
- def find_board_id(
19
- descr: str, short_descr: str, board_info: Optional[Path] = None, version: str = "stable"
15
+ def find_board_id_by_description(
16
+ descr: str,
17
+ short_descr: str,
18
+ *,
19
+ version: str,
20
+ board_info: Optional[Path] = None,
20
21
  ) -> Optional[str]:
21
22
  """Find the MicroPython BOARD_ID based on the description in the firmware"""
23
+
22
24
  try:
23
- boards = find_board_id_by_description(
25
+ boards = _find_board_id_by_description(
24
26
  descr=descr,
25
27
  short_descr=short_descr,
26
28
  board_info=board_info,
27
- version=clean_version(version),
29
+ version=clean_version(version) if version else None,
28
30
  )
29
- return boards[-1]["board"]
31
+ return boards[-1].board_id
30
32
  except MPFlashError:
31
33
  return "UNKNOWN_BOARD"
32
34
 
33
35
 
34
36
  @functools.lru_cache(maxsize=20)
35
- def find_board_id_by_description(*, descr: str, short_descr: str, version="v1.21.0", board_info: Optional[Path] = None):
37
+ def _find_board_id_by_description(
38
+ *,
39
+ descr: str,
40
+ short_descr: str,
41
+ version: Optional[str] = None,
42
+ board_info: Optional[Path] = None,
43
+ ):
36
44
  """
37
45
  Find the MicroPython BOARD_ID based on the description in the firmware
38
46
  using the pre-built board_info.json file
39
47
  """
40
- if not board_info:
41
- board_info = HERE / "board_info.json"
42
- if not board_info.exists():
43
- raise FileNotFoundError(f"Board info file not found: {board_info}")
44
48
 
45
- info = _read_board_info(board_info)
49
+ candidate_boards = read_known_boardinfo(board_info)
46
50
 
47
- # filter for matching version
48
- if version == "preview":
49
- # TODO: match last stable
50
- version = "v1.22.2"
51
- version_matches = [b for b in info if b["version"].startswith(version)]
52
- if not version_matches:
53
- raise MPFlashError(f"No board info found for version {version}")
54
- matches = [b for b in version_matches if b["description"] == descr]
51
+ if version:
52
+ # filter for matching version
53
+ if version in ("preview", "stable"):
54
+ # match last stable
55
+ version = get_stable_mp_version()
56
+ known_versions = sorted({b.version for b in candidate_boards})
57
+ if version not in known_versions:
58
+ # FIXME if latest stable is newer than the last version in the boardlist this will fail
59
+ log.trace(f"Version {version} not found in board info, using latest known version {known_versions[-1]}")
60
+ version = known_versions[-1]
61
+ version_matches = [b for b in candidate_boards if b.version.startswith(version)]
62
+ if not version_matches:
63
+ raise MPFlashError(f"No board info found for version {version}")
64
+ candidate_boards = version_matches
65
+ matches = [b for b in candidate_boards if b.description == descr]
55
66
  if not matches and short_descr:
56
- matches = [b for b in version_matches if b["description"] == short_descr]
67
+ matches = [b for b in candidate_boards if b.description == short_descr]
57
68
  if not matches:
58
69
  raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
59
- return sorted(matches, key=lambda x: x["version"])
60
-
61
-
62
- @functools.lru_cache(maxsize=20)
63
- def _read_board_info(board_info):
64
- with open(board_info, "r") as file:
65
- info = json.load(file)
66
- return info
70
+ return sorted(matches, key=lambda x: x.version)
@@ -0,0 +1,42 @@
1
+ import functools
2
+ import zipfile
3
+ from pathlib import Path
4
+ from typing import List, Optional
5
+
6
+ import jsons
7
+
8
+ from mpflash.mpboard_id.board import Board
9
+
10
+ ###############################################################################################
11
+ HERE = Path(__file__).parent
12
+ ###############################################################################################
13
+
14
+
15
+ def write_boardinfo_json(board_list: List[Board], *, folder: Path):
16
+ """Writes the board information to JSON and CSV files.
17
+
18
+ Args:
19
+ board_list (List[Board]): The list of Board objects.
20
+ """
21
+ import zipfile
22
+
23
+ # create a zip file with the json file
24
+ with zipfile.ZipFile(folder / "board_info.zip", "w", compression=zipfile.ZIP_DEFLATED) as zipf:
25
+ # write the list to json file inside the zip
26
+ with zipf.open("board_info.json", "w") as fp:
27
+ fp.write(jsons.dumps(board_list, jdkwargs={"indent": 4}).encode())
28
+
29
+
30
+ @functools.lru_cache(maxsize=20)
31
+ def read_known_boardinfo(board_info: Optional[Path] = None) -> List[Board]:
32
+
33
+ if not board_info:
34
+ board_info = HERE / "board_info.zip"
35
+ if not board_info.exists():
36
+ raise FileNotFoundError(f"Board info file not found: {board_info}")
37
+
38
+ with zipfile.ZipFile(board_info, "r") as zf:
39
+ with zf.open("board_info.json", "r") as file:
40
+ info = jsons.loads(file.read().decode(encoding="utf-8"), List[Board])
41
+
42
+ return info
@@ -13,7 +13,7 @@ from rich.progress import track
13
13
  from tenacity import retry, stop_after_attempt, wait_fixed
14
14
 
15
15
  from mpflash.errors import MPFlashError
16
- from mpflash.mpboard_id.board_id import find_board_id
16
+ from mpflash.mpboard_id.board_id import find_board_id_by_description
17
17
  from mpflash.mpremoteboard.runner import run
18
18
 
19
19
  ###############################################################################################
@@ -64,7 +64,7 @@ class MPRemoteBoard:
64
64
  return f"MPRemoteBoard({self.serialport}, {self.family} {self.port}, {self.board}, {self.version})"
65
65
 
66
66
  @staticmethod
67
- def connected_boards(bluetooth: bool = False) -> List[str]:
67
+ def connected_boards(bluetooth: bool = False, description: bool = False) -> List[str]:
68
68
  # TODO: rename to connected_comports
69
69
  """
70
70
  Get a list of connected comports.
@@ -81,8 +81,19 @@ class MPRemoteBoard:
81
81
  # filter out bluetooth ports
82
82
  comports = [p for p in comports if "bluetooth" not in p.description.lower()]
83
83
  comports = [p for p in comports if "BTHENUM" not in p.hwid]
84
-
85
- return sorted([p.device for p in comports])
84
+ if description:
85
+ output = [
86
+ f"{p.device} {(p.manufacturer + ' ') if p.manufacturer and not p.description.startswith(p.manufacturer) else ''}{p.description}"
87
+ for p in comports
88
+ ]
89
+ else:
90
+ output = [p.device for p in comports]
91
+
92
+ if sys.platform == "win32":
93
+ # Windows sort of comports by number - but fallback to device name
94
+ return sorted(output, key=lambda x: int(x.split()[0][3:]) if x.split()[0][3:].isdigit() else x)
95
+ # sort by device name
96
+ return sorted(output)
86
97
 
87
98
  @retry(stop=stop_after_attempt(RETRIES), wait=wait_fixed(1), reraise=True) # type: ignore ## retry_error_cls=ConnectionError,
88
99
  def get_mcu_info(self, timeout: int = 2):
@@ -116,10 +127,10 @@ class MPRemoteBoard:
116
127
  self.description = descr = info["board"]
117
128
  pos = descr.rfind(" with")
118
129
  short_descr = descr[:pos].strip() if pos != -1 else ""
119
- if board_name := find_board_id(descr, short_descr):
130
+ if board_name := find_board_id_by_description(descr, short_descr, version=self.version):
120
131
  self.board = board_name
121
132
  else:
122
- self.board = "UNKNOWN"
133
+ self.board = "UNKNOWN_BOARD"
123
134
 
124
135
  def disconnect(self) -> bool:
125
136
  """
@@ -200,6 +211,7 @@ class MPRemoteBoard:
200
211
  transient=True,
201
212
  get_time=lambda: time.time(),
202
213
  show_speed=False,
214
+ refresh_per_second=1,
203
215
  ):
204
216
  time.sleep(1)
205
217
  try:
@@ -0,0 +1,12 @@
1
+ """Info to support mounting and unmounting of UF2 drives on linux and macos"""
2
+
3
+
4
+ class UF2Disk:
5
+ """Info to support mounting and unmounting of UF2 drives on linux"""
6
+
7
+ device_path: str
8
+ label: str
9
+ mountpoint: str
10
+
11
+ def __repr__(self):
12
+ return repr(self.__dict__)