mpflash 1.25.0__py3-none-any.whl → 1.25.0.post2__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 (52) hide show
  1. mpflash/add_firmware.py +43 -16
  2. mpflash/ask_input.py +4 -4
  3. mpflash/basicgit.py +2 -2
  4. mpflash/bootloader/manual.py +1 -1
  5. mpflash/cli_download.py +8 -5
  6. mpflash/cli_flash.py +31 -35
  7. mpflash/cli_group.py +3 -0
  8. mpflash/cli_list.py +8 -3
  9. mpflash/cli_main.py +4 -0
  10. mpflash/common.py +2 -38
  11. mpflash/config.py +21 -0
  12. mpflash/db/__init__.py +2 -0
  13. mpflash/db/core.py +61 -0
  14. mpflash/db/gather_boards.py +112 -0
  15. mpflash/db/loader.py +122 -0
  16. mpflash/db/meta.py +78 -0
  17. mpflash/db/micropython_boards.zip +0 -0
  18. mpflash/db/models.py +93 -0
  19. mpflash/db/tools.py +27 -0
  20. mpflash/download/__init__.py +46 -64
  21. mpflash/download/from_web.py +26 -36
  22. mpflash/download/fwinfo.py +41 -0
  23. mpflash/download/jid.py +56 -0
  24. mpflash/downloaded.py +79 -93
  25. mpflash/flash/__init__.py +7 -3
  26. mpflash/flash/esp.py +2 -1
  27. mpflash/flash/stm32.py +1 -1
  28. mpflash/flash/uf2/windows.py +3 -1
  29. mpflash/flash/worklist.py +16 -28
  30. mpflash/list.py +3 -3
  31. mpflash/logger.py +43 -9
  32. mpflash/mpboard_id/__init__.py +3 -9
  33. mpflash/mpboard_id/alternate.py +56 -0
  34. mpflash/mpboard_id/board_id.py +11 -94
  35. mpflash/mpboard_id/known.py +45 -73
  36. mpflash/mpboard_id/resolve.py +19 -0
  37. mpflash/mpremoteboard/__init__.py +4 -3
  38. mpflash/mpremoteboard/mpy_fw_info.py +1 -0
  39. mpflash/mpremoteboard/runner.py +5 -2
  40. mpflash/vendor/pydfu.py +33 -6
  41. mpflash/versions.py +3 -0
  42. {mpflash-1.25.0.dist-info → mpflash-1.25.0.post2.dist-info}/METADATA +49 -12
  43. mpflash-1.25.0.post2.dist-info/RECORD +69 -0
  44. mpflash/db/boards.py +0 -63
  45. mpflash/db/downloads.py +0 -87
  46. mpflash/mpboard_id/add_boards.py +0 -260
  47. mpflash/mpboard_id/board.py +0 -40
  48. mpflash/mpboard_id/store.py +0 -47
  49. mpflash-1.25.0.dist-info/RECORD +0 -62
  50. {mpflash-1.25.0.dist-info → mpflash-1.25.0.post2.dist-info}/LICENSE +0 -0
  51. {mpflash-1.25.0.dist-info → mpflash-1.25.0.post2.dist-info}/WHEEL +0 -0
  52. {mpflash-1.25.0.dist-info → mpflash-1.25.0.post2.dist-info}/entry_points.txt +0 -0
@@ -5,18 +5,16 @@ from pathlib import Path
5
5
  from typing import Dict, List, Optional
6
6
  from urllib.parse import urljoin
7
7
 
8
-
9
8
  from loguru import logger as log
10
9
  from rich.progress import track
11
10
 
12
- from mpflash.common import PORT_FWTYPES, FWInfo
11
+ from mpflash.common import PORT_FWTYPES
12
+ from mpflash.db.models import Firmware
13
13
  from mpflash.downloaded import clean_downloaded_firmwares
14
14
  from mpflash.errors import MPFlashError
15
- from mpflash.mpboard_id import get_known_ports
15
+ from mpflash.mpboard_id import known_ports
16
16
  from mpflash.versions import clean_version
17
17
 
18
-
19
-
20
18
  MICROPYTHON_ORG_URL = "https://micropython.org/"
21
19
 
22
20
 
@@ -24,8 +22,8 @@ MICROPYTHON_ORG_URL = "https://micropython.org/"
24
22
  RE_DATE = r"(-\d{8}-)"
25
23
  RE_HASH = r"(.g[0-9a-f]+\.)"
26
24
  # regex to extract the version and the build from the firmware filename
27
- # group 1 is the version, group 2 is the build
28
- RE_VERSION_PREVIEW = r"v([\d\.]+)-?(?:preview\.)?(\d+)?\."
25
+ # group 1 is the version+Preview , gr2 just the version, group 3 is the build
26
+ RE_VERSION_PREVIEW = r"v(([\d\.]+)(?:-preview)?)\.?(\d+)?\."
29
27
 
30
28
 
31
29
  # 'RPI_PICO_W-v1.23.uf2'
@@ -107,7 +105,7 @@ def board_firmware_urls(board_url: str, base_url: str, ext: str) -> List[str]:
107
105
  # boards we are interested in ( this avoids getting a lot of boards we don't care about)
108
106
  # The first run takes ~60 seconds to run for 4 ports , all boards
109
107
  # so it makes sense to cache the results and skip boards as soon as possible
110
- def get_boards(ports: List[str], boards: List[str], clean: bool) -> List[FWInfo]:
108
+ def get_boards(ports: List[str], boards: List[str], clean: bool) -> List[Firmware]:
111
109
  # sourcery skip: use-getitem-for-re-match-groups
112
110
  """
113
111
  Retrieves a list of firmware information for the specified ports and boards.
@@ -115,15 +113,15 @@ def get_boards(ports: List[str], boards: List[str], clean: bool) -> List[FWInfo]
115
113
  Args:
116
114
  ports (List[str]): The list of ports to check for firmware.
117
115
  boards (List[str]): The list of boards to retrieve firmware information for.
118
- clean (bool): A flag indicating whether to perform a clean retrieval.
116
+ clean (bool): Remove date and hash from the firmware name.
119
117
 
120
118
  Returns:
121
119
  List[FWInfo]: A list of firmware information for the specified ports and boards.
122
120
 
123
121
  """
124
- board_urls: List[FWInfo] = []
122
+ board_urls: List[Firmware] = []
125
123
  if ports is None:
126
- ports = get_known_ports()
124
+ ports = known_ports()
127
125
  for port in ports:
128
126
  download_page_url = f"{MICROPYTHON_ORG_URL}download/?port={port}"
129
127
  urls = get_board_urls(download_page_url)
@@ -152,52 +150,44 @@ def get_boards(ports: List[str], boards: List[str], clean: bool) -> List[FWInfo]
152
150
  fname = re.sub(RE_DATE, "-", fname)
153
151
  # remove hash from firmware name
154
152
  fname = re.sub(RE_HASH, ".", fname)
155
- fw_info = FWInfo(
156
- filename=fname,
153
+ fw_info = Firmware(
154
+ firmware_file=fname,
157
155
  port=port,
158
- board=board["board"],
159
- preview="preview" in _url,
160
- firmware=_url,
156
+ board_id=board["board"],
157
+ source=_url,
161
158
  version="",
159
+ custom=False,
160
+ description="", # todo : add description from download page
162
161
  )
163
- # board["firmware"] = _url
164
- # board["preview"] = "preview" in _url # type: ignore
165
162
  if ver_match := re.search(RE_VERSION_PREVIEW, _url):
166
- fw_info.version = clean_version(ver_match.group(1))
167
- fw_info.build = ver_match.group(2) or "0"
168
- fw_info.preview = fw_info.build != "0"
169
- # # else:
170
- # # board.$1= ""
171
- # if "preview." in fw_info.version:
172
- # fw_info.build = fw_info.version.split("preview.")[-1]
173
- # else:
174
- # fw_info.build = "0"
175
-
176
- fw_info.ext = Path(fw_info.firmware).suffix
177
- fw_info.variant = fw_info.filename.split("-v")[0] if "-v" in fw_info.filename else ""
163
+ fw_info.version = clean_version(ver_match[1])
164
+ fw_info.build = int(ver_match[3] or 0)
165
+ if "-v" in fname:
166
+ # get the full board_id[-variant] from the filename
167
+ # filename : 'ESP32_GENERIC-v1.25.0.bin'
168
+ fw_info.board_id = fname.split("-v")[0]
178
169
 
179
170
  board_urls.append(fw_info)
180
171
  return board_urls
181
172
 
182
173
 
183
-
184
- def fetch_firmware_files(available_firmwares: List[FWInfo], firmware_folder: Path, force: bool):
174
+ def fetch_firmware_files(available_firmwares: List[Firmware], firmware_folder: Path, force: bool):
185
175
  # Just in time import
186
176
  import requests
187
177
 
188
178
  for board in available_firmwares:
189
- filename = firmware_folder / board.port / board.filename
179
+ filename = firmware_folder / board.port / board.firmware_file
190
180
  filename.parent.mkdir(exist_ok=True)
191
181
  if filename.exists() and not force:
192
182
  log.debug(f" {filename} already exists, skip download")
193
183
  continue
194
- log.info(f"Downloading {board.firmware}")
184
+ log.info(f"Downloading {board.source}")
195
185
  log.info(f" to {filename}")
196
186
  try:
197
- r = requests.get(board.firmware, allow_redirects=True)
187
+ r = requests.get(board.source, allow_redirects=True)
198
188
  with open(filename, "wb") as fw:
199
189
  fw.write(r.content)
200
- board.filename = str(filename.relative_to(firmware_folder))
190
+ board.firmware_file = str(filename.relative_to(firmware_folder))
201
191
  except requests.RequestException as e:
202
192
  log.exception(e)
203
193
  continue
@@ -0,0 +1,41 @@
1
+ from dataclasses import dataclass, field
2
+ from pathlib import Path
3
+
4
+
5
+ @dataclass
6
+ class FWInfo:
7
+ """
8
+ Downloaded Firmware information
9
+ is somewhat related to the BOARD class in the mpboard_id module
10
+ """
11
+
12
+ port: str # MicroPython port
13
+ board: str # MicroPython board
14
+ filename: str = field(default="") # relative filename of the firmware image
15
+ url: str = field(default="") # url or path to original firmware image
16
+ variant: str = field(default="") # MicroPython variant
17
+ preview: bool = field(default=False) # True if the firmware is a preview version
18
+ version: str = field(default="") # MicroPython version (NO v prefix)
19
+ url: str = field(default="") # url to the firmware image download folder
20
+ build: str = field(default="0") # The build = number of commits since the last release
21
+ ext: str = field(default="") # the file extension of the firmware
22
+ family: str = field(default="micropython") # The family of the firmware
23
+ custom: bool = field(default=False) # True if the firmware is a custom build
24
+ description: str = field(default="") # Description used by this firmware (custom only)
25
+ mcu: str = field(default="")
26
+
27
+ def to_dict(self) -> dict:
28
+ """Convert the object to a dictionary"""
29
+ return self.__dict__
30
+
31
+ @classmethod
32
+ def from_dict(cls, data: dict) -> "FWInfo":
33
+ """Create a FWInfo object from a dictionary"""
34
+ valid_keys = {field.name for field in FWInfo.__dataclass_fields__.values()}
35
+ filtered_data = {k: v for k, v in data.items() if k in valid_keys}
36
+ # add missing keys
37
+ if "ext" not in data:
38
+ data["ext"] = Path(data["filename"]).suffix
39
+ if "family" not in data:
40
+ data["family"] = "micropython"
41
+ return FWInfo(**filtered_data)
@@ -0,0 +1,56 @@
1
+ # Just In-time Download of firmware if not already available
2
+ from loguru import logger as log
3
+
4
+ from mpflash.common import Params
5
+ from mpflash.download import download
6
+ from mpflash.downloaded import find_downloaded_firmware
7
+ from mpflash.errors import MPFlashError
8
+ from mpflash.flash.worklist import WorkList
9
+ from mpflash.mpboard_id.alternate import alternate_board_names
10
+
11
+
12
+ def ensure_firmware_downloaded(worklist: WorkList, version: str, force: bool) -> None:
13
+ """
14
+ Ensure all firmware in the worklist is downloaded for the given version.
15
+
16
+ Iterates over the worklist, downloads missing firmware, and updates the worklist
17
+ with the downloaded firmware.
18
+
19
+ Raises MPFlashError if download fails.
20
+ """
21
+ # iterate over the worklist ann update missing firmware
22
+ newlist: WorkList = []
23
+ for mcu, firmware in worklist:
24
+ if force:
25
+ board_firmwares = []
26
+ else:
27
+ if firmware:
28
+ # firmware is already downloaded
29
+ newlist.append((mcu, firmware))
30
+ continue
31
+ # check if the firmware is already downloaded
32
+ board_firmwares = find_downloaded_firmware(
33
+ board_id=f"{mcu.board}-{mcu.variant}" if mcu.variant else mcu.board,
34
+ version=version,
35
+ port=mcu.port,
36
+ )
37
+ if not board_firmwares:
38
+ # download the firmware
39
+ log.info(f"Downloading {version} firmware for {mcu.board} on {mcu.serialport}.")
40
+ download(ports=[mcu.port], boards=alternate_board_names(mcu.board, mcu.port), versions=[version], force=True, clean=True)
41
+ new_firmware = find_downloaded_firmware(
42
+ board_id=f"{mcu.board}-{mcu.variant}" if mcu.variant else mcu.board,
43
+ version=version,
44
+ port=mcu.port,
45
+ )
46
+ if not new_firmware:
47
+ raise MPFlashError(f"Failed to download {version} firmware for {mcu.board} on {mcu.serialport}.")
48
+ newlist.append((mcu, new_firmware[0]))
49
+ else:
50
+ log.info(f"Found {version} firmware {board_firmwares[-1].firmware_file} for {mcu.board} on {mcu.serialport}.")
51
+ newlist.append((mcu, firmware))
52
+
53
+ worklist.clear()
54
+ worklist.extend(newlist)
55
+
56
+ pass
mpflash/downloaded.py CHANGED
@@ -1,113 +1,99 @@
1
+ import os
1
2
  from pathlib import Path
2
- from typing import Dict, List, Optional
3
+ from typing import List
3
4
 
4
- import jsonlines
5
5
  from loguru import logger as log
6
6
 
7
- from mpflash.common import PORT_FWTYPES, FWInfo
8
- from mpflash.db.downloads import downloaded
7
+ from mpflash.config import config
8
+ from mpflash.db.core import Session
9
+ from mpflash.db.models import Firmware
10
+ from mpflash.mpboard_id.alternate import alternate_board_names
9
11
  from mpflash.versions import clean_version
10
12
 
11
- from .config import config
12
-
13
13
  # #########################################################################################################
14
14
 
15
15
 
16
- def clean_downloaded_firmwares(fw_folder: Path) -> None:
16
+ def clean_downloaded_firmwares() -> None:
17
+ """
18
+ - Check if all firmware records in the database are still available on disk.
19
+ - If not, remove the record from the database.
20
+ - For all firmware files on disk that are not in the database:
21
+ - loag a warning message.
22
+ - Check if the file is a valid firmware file.
23
+ - If so, add it to the database.
24
+
17
25
  """
18
- Remove duplicate entries from the firmware.jsonl file, keeping the latest one
19
- uniqueness is based on the filename
20
26
  """
21
- # Duplication should no longer happen,
22
- # but is would be a good idea to check the consistence between the DB and the downloads folder sometimes
23
- pass
27
+ Get all firmware files in the firmware directory and its subfolders.
28
+ """
24
29
 
30
+ firmware_dir = Path(config.firmware_folder)
25
31
 
26
- def find_downloaded_firmware(
27
- *,
28
- board_id: str,
29
- version: str = "", # v1.2.3
30
- port: str = "",
31
- variants: bool = False,
32
- db_path: Optional[Path] = None,
33
- trie: int = 1,
34
- selector: Optional[Dict[str, str]] = None,
35
- ) -> List[FWInfo]:
36
- if selector is None:
37
- selector = {}
38
-
39
- # Use the information in firmwares.jsonl to find the firmware file
40
- log.debug(f"{trie}] Looking for firmware for {board_id} {version} ")
41
- fw_list = downloaded()
42
- if not fw_list:
43
- log.error("No firmware files found. Please download the firmware first.")
44
- return []
45
- # filter by version
46
- version = clean_version(version)
47
- fw_list = filter_downloaded_fwlist(fw_list, board_id, version, port, variants, selector)
32
+ """
33
+ Returns a set of firmware file paths (relative to firmware_dir) found on disk.
34
+ Uses a generator for performance and includes files in subfolders.
35
+ Skips files with certain extensions.
36
+ """
37
+ firmware_files_on_disk = {
38
+ str(f.relative_to(firmware_dir)) for f in firmware_dir.rglob("*") if f.is_file() and f.suffix not in {".db", ".bak", ".jsonl"}
39
+ }
48
40
 
49
- if not fw_list and trie < 3:
50
- log.info(f"Try ({trie+1}) to find a firmware for the board {board_id}")
51
- if trie == 1:
52
- # ESP board naming conventions have changed by adding a PORT prefix
53
- if port.startswith("esp") and not board_id.startswith(port.upper()):
54
- board_id = f"{port.upper()}_{board_id}"
55
- # RP2 board naming conventions have changed by adding a _RPI prefix
56
- if port == "rp2" and not board_id.startswith("RPI_"):
57
- board_id = f"RPI_{board_id}"
58
- elif trie == 2:
59
- board_id = board_id.replace("_", "-")
41
+ with Session() as session:
42
+ db_firmwares = session.query(Firmware).all()
43
+ db_firmware_files = {fw.firmware_file for fw in db_firmwares}
60
44
 
61
- fw_list = find_downloaded_firmware(
62
- db_path=db_path,
63
- board_id=board_id,
64
- version=version,
65
- port=port,
66
- trie=trie + 1,
67
- selector=selector,
68
- )
69
- # hope we have a match now for the board
70
- # sort by filename
71
- fw_list.sort(key=lambda x: x.filename)
72
- return fw_list
45
+ # Remove DB records for files not on disk
46
+ for fw in db_firmwares:
47
+ if fw.firmware_file not in firmware_files_on_disk:
48
+ log.warning(f"Firmware file missing on disk, removing DB record: {fw.firmware_file}")
49
+ session.delete(fw)
50
+ session.commit()
73
51
 
52
+ # Warn about files on disk not in DB
53
+ for fw_file in firmware_files_on_disk - db_firmware_files:
54
+ log.debug(f"Found file in firmware folder but not in DB: {fw_file}")
74
55
 
75
- def filter_downloaded_fwlist(
76
- fw_list: List[FWInfo],
77
- board_id: str,
78
- version: str, # v1.2.3
79
- port: str,
80
- # preview: bool,
81
- variants: bool,
82
- selector: dict,
83
- ) -> List[FWInfo]:
84
- """Filter the downloaded firmware list based on the provided parameters"""
85
- if "preview" in version:
86
- # never get a preview for an older version
87
- fw_list = [fw for fw in fw_list if fw.preview]
88
- else:
89
- # older FWInfo version has no v1.2.3 prefix
90
- either = [clean_version(version, drop_v=False), clean_version(version, drop_v=True)]
91
- fw_list = [fw for fw in fw_list if fw.version in either]
92
- log.trace(f"Filtering firmware for {version} : {len(fw_list)} found.")
93
- # filter by port
94
- if port:
95
- fw_list = [fw for fw in fw_list if fw.port == port and Path(fw.firmware).suffix in PORT_FWTYPES[port]]
96
- log.trace(f"Filtering firmware for {port} : {len(fw_list)} found.")
97
56
 
98
- if board_id:
99
- if variants:
100
- # any variant of this board_id
101
- fw_list = [fw for fw in fw_list if fw.board == board_id]
57
+ def find_downloaded_firmware(
58
+ board_id: str,
59
+ version: str = "",
60
+ port: str = "",
61
+ variants: bool = False,
62
+ ) -> List[Firmware]:
63
+ version = clean_version(version)
64
+ log.debug(f"Looking for firmware for {board_id} {version} ")
65
+ # Special handling for preview versions
66
+ with Session() as session:
67
+ if version == "preview" or "preview" in version:
68
+ # Find all preview firmwares for this board/port, return the latest (highest build)
69
+ query = session.query(Firmware).filter(Firmware.board_id == board_id)
70
+ if port:
71
+ query = query.filter(Firmware.port == port)
72
+ query = query.filter(Firmware.firmware_file.contains("preview")).order_by(Firmware.build.desc())
73
+ fw_list = query.all()
74
+ if fw_list:
75
+ return [fw_list[0]] # Return the latest preview only
102
76
  else:
103
- # the firmware variant should match exactly the board_id
104
- fw_list = [fw for fw in fw_list if fw.variant == board_id]
105
- log.trace(f"Filtering firmware for {board_id} : {len(fw_list)} found.")
106
-
107
- if selector and port in selector:
108
- fw_list = [fw for fw in fw_list if fw.filename.endswith(selector[port])]
109
- return fw_list
110
-
77
+ fw_list = session.query(Firmware).filter(Firmware.board_id == board_id, Firmware.version == version).all()
78
+ if fw_list:
79
+ return fw_list
80
+ #
81
+ more_board_ids = alternate_board_names(board_id, port)
82
+ #
83
+ log.debug(f"2nd search with renamed board_id :{board_id}")
84
+ with Session() as session:
85
+ if version == "preview" or "preview" in version:
86
+ query = session.query(Firmware).filter(Firmware.board_id.in_(more_board_ids))
87
+ if port:
88
+ query = query.filter(Firmware.port == port)
89
+ query = query.filter(Firmware.firmware_file.contains("preview")).order_by(Firmware.build.desc())
90
+ fw_list = query.all()
91
+ if fw_list:
92
+ return [fw_list[0]]
93
+ else:
94
+ fw_list = session.query(Firmware).filter(Firmware.board_id.in_(more_board_ids), Firmware.version == version).all()
95
+ if fw_list:
96
+ return fw_list
97
+ log.warning(f"No firmware files found for board {board_id} version {version}")
98
+ return []
111
99
 
112
- # #########################################################################################################
113
- #
mpflash/flash/__init__.py CHANGED
@@ -3,7 +3,8 @@ from pathlib import Path
3
3
  from loguru import logger as log
4
4
 
5
5
  from mpflash.bootloader.activate import enter_bootloader
6
- from mpflash.common import PORT_FWTYPES, BootloaderMethod, UF2_PORTS
6
+ from mpflash.common import PORT_FWTYPES, UF2_PORTS, BootloaderMethod
7
+ from mpflash.config import config
7
8
  from mpflash.errors import MPFlashError
8
9
 
9
10
  from .esp import flash_esp
@@ -15,7 +16,6 @@ from .worklist import WorkList
15
16
 
16
17
  def flash_list(
17
18
  todo: WorkList,
18
- fw_folder: Path,
19
19
  erase: bool,
20
20
  bootloader: BootloaderMethod,
21
21
  **kwargs
@@ -23,7 +23,11 @@ def flash_list(
23
23
  """Flash a list of boards with the specified firmware."""
24
24
  flashed = []
25
25
  for mcu, fw_info in todo:
26
- fw_file = fw_folder / fw_info.filename
26
+ if not fw_info:
27
+ log.error(f"Firmware not found for {mcu.board} on {mcu.serialport}, skipping")
28
+ continue
29
+
30
+ fw_file = config.firmware_folder / fw_info.firmware_file
27
31
  if not fw_file.exists():
28
32
  log.error(f"File {fw_file} does not exist, skipping {mcu.board} on {mcu.serialport}")
29
33
  continue
mpflash/flash/esp.py CHANGED
@@ -15,6 +15,7 @@ from mpflash.mpremoteboard import MPRemoteBoard
15
15
 
16
16
  FlashMode = Literal["keep", "qio", "qout", "dio", "dout"]
17
17
 
18
+
18
19
  def flash_esp(
19
20
  mcu: MPRemoteBoard,
20
21
  fw_file: Path,
@@ -30,7 +31,7 @@ def flash_esp(
30
31
  log.info(f"Flashing {fw_file} on {mcu.board} on {mcu.serialport}")
31
32
  if not mcu.cpu:
32
33
  # Lookup CPU based on the board name
33
- mcu.cpu = find_known_board(mcu.board).cpu
34
+ mcu.cpu = find_known_board(mcu.board).mcu
34
35
 
35
36
  cmds: List[List[str]] = []
36
37
 
mpflash/flash/stm32.py CHANGED
@@ -15,5 +15,5 @@ def flash_stm32(mcu: MPRemoteBoard, fw_file: Path, *, erase: bool):
15
15
  dfu_init()
16
16
  if updated := flash_stm32_dfu(mcu, fw_file=fw_file, erase=erase):
17
17
  mcu.wait_for_restart()
18
- log.success(f"Flashed {mcu.version} to {mcu.board}")
18
+ log.success(f"Flashed {mcu.board_id} {mcu.version} to {mcu.serialport}.")
19
19
  return updated
@@ -7,13 +7,15 @@ import time
7
7
  from pathlib import Path
8
8
  from typing import Optional
9
9
 
10
- from .boardid import get_board_id
11
10
  import psutil
12
11
  from rich.progress import track
13
12
 
13
+ from .boardid import get_board_id
14
+
14
15
 
15
16
  def wait_for_UF2_windows(board_id: str, s_max: int = 10) -> Optional[Path]:
16
17
  """Wait for the MCU to mount as a drive"""
18
+
17
19
  if s_max < 1:
18
20
  s_max = 10
19
21
  destination = None
mpflash/flash/worklist.py CHANGED
@@ -5,7 +5,8 @@ from typing import Dict, List, Optional, Tuple
5
5
 
6
6
  from loguru import logger as log
7
7
 
8
- from mpflash.common import FWInfo, filtered_comports
8
+ from mpflash.common import filtered_comports
9
+ from mpflash.db.models import Firmware
9
10
  from mpflash.downloaded import find_downloaded_firmware
10
11
  from mpflash.errors import MPFlashError
11
12
  from mpflash.list import show_mcus
@@ -13,45 +14,38 @@ from mpflash.mpboard_id import find_known_board
13
14
  from mpflash.mpremoteboard import MPRemoteBoard
14
15
 
15
16
  # #########################################################################################################
16
- WorkList = List[Tuple[MPRemoteBoard, FWInfo]]
17
+ WorkList = List[Tuple[MPRemoteBoard, Optional[Firmware]]]
17
18
  # #########################################################################################################
18
19
 
19
20
 
20
21
  def auto_update(
21
22
  conn_boards: List[MPRemoteBoard],
22
23
  target_version: str,
23
- fw_folder: Path,
24
- *,
25
- selector: Optional[Dict[str, str]] = None,
26
24
  ) -> WorkList:
27
25
  """Builds a list of boards to update based on the connected boards and the firmwares available locally in the firmware folder.
28
26
 
29
27
  Args:
30
28
  conn_boards (List[MPRemoteBoard]): List of connected boards
31
29
  target_version (str): Target firmware version
32
- fw_folder (Path): Path to the firmware folder
33
30
  selector (Optional[Dict[str, str]], optional): Selector for filtering firmware. Defaults to None.
34
31
 
35
32
  Returns:
36
33
  WorkList: List of boards and firmware information to update
37
34
  """
38
- if selector is None:
39
- selector = {}
40
35
  wl: WorkList = []
41
36
  for mcu in conn_boards:
42
37
  if mcu.family not in ("micropython", "unknown"):
43
38
  log.warning(f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware")
44
39
  continue
45
40
  board_firmwares = find_downloaded_firmware(
46
- db_path=fw_folder,
47
- board_id=mcu.board if not mcu.variant else f"{mcu.board}-{mcu.variant}",
41
+ board_id=f"{mcu.board}-{mcu.variant}" if mcu.variant else mcu.board,
48
42
  version=target_version,
49
43
  port=mcu.port,
50
- selector=selector,
51
44
  )
52
45
 
53
46
  if not board_firmwares:
54
- log.error(f"No {target_version} firmware found for {mcu.board} on {mcu.serialport}.")
47
+ log.warning(f"No {target_version} firmware found for {mcu.board} on {mcu.serialport}.")
48
+ wl.append((mcu, None))
55
49
  continue
56
50
 
57
51
  if len(board_firmwares) > 1:
@@ -59,7 +53,7 @@ def auto_update(
59
53
 
60
54
  # just use the last firmware
61
55
  fw_info = board_firmwares[-1]
62
- log.info(f"Found {target_version} firmware {fw_info.filename} for {mcu.board} on {mcu.serialport}.")
56
+ log.info(f"Found {target_version} firmware {fw_info.firmware_file} for {mcu.board} on {mcu.serialport}.")
63
57
  wl.append((mcu, fw_info))
64
58
  return wl
65
59
 
@@ -69,7 +63,6 @@ def manual_worklist(
69
63
  *,
70
64
  board_id: str,
71
65
  version: str,
72
- fw_folder: Path,
73
66
  ) -> WorkList:
74
67
  """Create a worklist for a single board specified manually.
75
68
 
@@ -77,7 +70,6 @@ def manual_worklist(
77
70
  serial (str): Serial port of the board
78
71
  board (str): Board_ID
79
72
  version (str): Firmware version
80
- fw_folder (Path): Path to the firmware folder
81
73
 
82
74
  Returns:
83
75
  WorkList: List of boards and firmware information to update
@@ -89,13 +81,13 @@ def manual_worklist(
89
81
  info = find_known_board(board_id)
90
82
  mcu.port = info.port
91
83
  # need the CPU type for the esptool
92
- mcu.cpu = info.cpu
84
+ mcu.cpu = info.mcu
93
85
  except (LookupError, MPFlashError) as e:
94
86
  log.error(f"Board {board_id} not found in board database")
95
87
  log.exception(e)
96
88
  return []
97
89
  mcu.board = board_id
98
- firmwares = find_downloaded_firmware(db_path=fw_folder, board_id=board_id, version=version, port=mcu.port)
90
+ firmwares = find_downloaded_firmware(board_id=board_id, version=version, port=mcu.port)
99
91
  if not firmwares:
100
92
  log.error(f"No firmware found for {mcu.port} {board_id} version {version}")
101
93
  return []
@@ -107,32 +99,29 @@ def single_auto_worklist(
107
99
  serial: str,
108
100
  *,
109
101
  version: str,
110
- fw_folder: Path,
111
102
  ) -> WorkList:
112
103
  """Create a worklist for a single serial-port.
113
104
 
114
105
  Args:
115
106
  serial_port (str): Serial port of the board
116
107
  version (str): Firmware version
117
- fw_folder (Path): Path to the firmware folder
118
108
 
119
109
  Returns:
120
110
  WorkList: List of boards and firmware information to update
121
111
  """
122
112
  log.trace(f"Auto updating {serial} to {version}")
123
113
  conn_boards = [MPRemoteBoard(serial)]
124
- todo = auto_update(conn_boards, version, fw_folder) # type: ignore # List / list
125
- show_mcus(conn_boards) # type: ignore
114
+ todo = auto_update(conn_boards, version) # type: ignore # List / list
115
+ show_mcus(conn_boards)
126
116
  return todo
127
117
 
128
118
 
129
119
  def full_auto_worklist(
130
120
  all_boards: List[MPRemoteBoard],
131
- *,
132
- include: List[str],
133
- ignore: List[str],
134
- version: str,
135
- fw_folder: Path,
121
+ *,
122
+ include: List[str],
123
+ ignore: List[str],
124
+ version: str,
136
125
  ) -> WorkList:
137
126
  """
138
127
  Create a worklist for all connected micropython boards based on the information retrieved from the board.
@@ -140,14 +129,13 @@ def full_auto_worklist(
140
129
 
141
130
  Args:
142
131
  version (str): Firmware version
143
- fw_folder (Path): Path to the firmware folder
144
132
 
145
133
  Returns:
146
134
  WorkList: List of boards and firmware information to update
147
135
  """
148
136
  log.trace(f"Auto updating all boards to {version}")
149
137
  if selected_boards := filter_boards(all_boards, include=include, ignore=ignore):
150
- return auto_update(selected_boards, version, fw_folder)
138
+ return auto_update(selected_boards, version)
151
139
  else:
152
140
  return []
153
141