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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mpflash
3
- Version: 1.25.0
3
+ Version: 1.25.0.post2
4
4
  Summary: Flash and download tool for MicroPython firmwares
5
5
  License: MIT
6
6
  Keywords: MicroPython,firmware,flash,download,UF2,esptool
@@ -29,13 +29,13 @@ Requires-Dist: loguru (>=0.7.2,<0.8.0)
29
29
  Requires-Dist: mpremote (>=1.22.0,<2.0.0)
30
30
  Requires-Dist: packaging (>=24.2,<25.0)
31
31
  Requires-Dist: platformdirs (>=4.2.0,<5.0.0)
32
- Requires-Dist: poetry (>=2.0.1,<3.0.0)
33
- Requires-Dist: psutil (>=5.9.8,<8.0.0)
32
+ Requires-Dist: psutil (>=7.0.0,<8.0.0)
34
33
  Requires-Dist: pygithub (>=2.1.1,<3.0.0)
35
34
  Requires-Dist: pyusb (>=1.2.1,<2.0.0)
36
35
  Requires-Dist: pywin32 (>=310,<311) ; sys_platform == "win32"
37
36
  Requires-Dist: requests (>=2.31.0,<3.0.0)
38
37
  Requires-Dist: rich-click (>=1.8.1,<2.0.0)
38
+ Requires-Dist: sqlalchemy (>=2.0.41,<3.0.0)
39
39
  Requires-Dist: tenacity (==9.0.0)
40
40
  Project-URL: Homepage, https://github.com/Josverl/mpflash/blob/main/README.md
41
41
  Project-URL: Repository, https://github.com/Josverl/mpflash
@@ -58,9 +58,15 @@ This tool was initially created to be used in a CI/CD pipeline to automate the p
58
58
  - `samd`, using ` .uf2`, using filecopy
59
59
  - `esp32`, using `.bin`, using esptool,
60
60
  - `esp8266`, using `.bin`, using esptool
61
- - `stm32`, using ` .dfu`, using pydfu
61
+ - `stm32`, using ` .dfu`, using pydfu (also in Windows)
62
62
 
63
63
  Not yet implemented: `nrf`, `cc3200`, `mimxrt`, `renesas`
64
+
65
+ ## Release v1.25.0 - 🪲Yanked🪲
66
+ I have yanked the release of 1.25.0 from PyPI.
67
+ It was missing a step to upgrade from a .json to a sqlite database to better identify connected boards, and I failed to identify that in testing.
68
+
69
+ There is a preview release available on PyPI, that has the fix for this issue, and it is available as `mpflash==1.25.0rc2`.
64
70
 
65
71
  ## Features
66
72
  1. List the connected boards including their firmware details, in a tabular or json format
@@ -79,15 +85,46 @@ You can use mpflash to perform various operations on your MicroPython boards. He
79
85
  | Command | Description |
80
86
  |---------|-------------|
81
87
  | `mpflash list` | List the connected board(s) including their firmware details |
88
+ | `mpflash flash` | Flash the latest stable firmware to the connected board(s), downloading the firmware if needed |
82
89
  | `mpflash download` | Download the MicroPython firmware(s) for the connected board(s) |
83
- | `mpflash flash` | Flash the latest stable firmware to the connected board(s) |
84
90
 
85
- ## selecting or ignoring specific serial ports
91
+ **Listing connected boards:**
92
+ `mpflash list` will list all connected boards in a table , including their serial port, family, board name, CPU, version and build number.
93
+ Options are available to list the boards in a json format, or to filter the list by serial port or board type.
94
+
95
+
96
+ **Flashing boards with new firmware:**
97
+ `mpflash flash` will flash the latest stable firmware to all connected boards, downloading the firmware if needed.
98
+ It will try to determine the current micropython borad and variant, download the firmware if needed, and flash the correct firmware to each board.
99
+
100
+ Common options are:
101
+
102
+ - `--version` to specify the version of the firmware to flash, defaults to the latest stable version.
103
+ - `--serial` to specify the serial port(s) to flash, defaults to all connected boards.
104
+ - `--board` to specify which firmware to flash to a single board
105
+ - `--variant` to specify a specific variant of the board
106
+
107
+ **Downloading firmware:**
108
+ `mpflash download` will download the latest stable firmware for all connected boards, or a specific board if specified. It will download the firmware from the official MicroPython website and save it in your `Downloads/firmware` directory.
109
+ When a board is specified for which multiple variants are available, all variants will be downloaded.
110
+
111
+ Common options are:
86
112
 
87
- You can use the `--serial` option to select a specific serial port to flash, or the `--ignore` option to ignore a specific serial port.
88
- both options can be specified multiple times
89
- Both can be globs (e.g. COM*) or exact port names (e.g. COM1)
90
- in addition there is a --bluetooth option to simplify ignoring bluetooth ports
113
+ - `--version` to specify the version of the firmware to download, defaults to the latest stable version. (e.g. `stable`, `preview`, `x.y.z`)
114
+ - `--serial` to specify the serial port(s) to flash, defaults to all connected boards.
115
+ - `--board` to specify which firmware to flash to a single board
116
+
117
+
118
+
119
+ ## Selecting or ignoring specific serial ports
120
+
121
+ You can use the `--serial` option to select a specific serial port(s) to flash,
122
+ Or you can use the `--ignore` option to ignore a specific serial port(s).
123
+
124
+ Either option can be specified multiple times, can be globs (e.g. COM*) or exact port names (e.g. /dev/ttyUSB0).
125
+ To permenently ignore a port, you can set the `MPFLASH_IGNORE` environment variable to a space-separated list of serial ports or globs.
126
+
127
+ In addition there is a --bluetooth option to simplify ignoring bluetooth ports, where the default is to ignore bluetooth ports.
91
128
 
92
129
  ```
93
130
  --serial,--serial-port -s SERIALPORT Serial port(s) (or globs) to list. [default: *] > > --ignore -i SERIALPORT Serial port(s) (or globs) to ignore. Defaults to MPFLASH_IGNORE. │
@@ -102,9 +139,9 @@ This file can contain a description of the board, which will be shown in the lis
102
139
  description = "Blue Norwegian actuator"
103
140
  ```
104
141
 
105
- If you want the board to be ignored by mpflash, you can add the following to the board_info.toml file:
142
+ If you want the board to be ignored by mpflash, no matter which serial port it is connected to, you can add the following to the `board_info.toml` file:
106
143
  ```toml
107
- description = "Blue Norwegian feeder"
144
+ description = "Blue Norwegian actuator"
108
145
  [mpflash]
109
146
  ignore = true
110
147
  ```
@@ -0,0 +1,69 @@
1
+ mpflash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ mpflash/add_firmware.py,sha256=P1yaNUdExfzC_qnhE-P5ALZg1Uh7XT6Xf7NYccJP7Rc,4317
3
+ mpflash/ask_input.py,sha256=YUx65Xwj6dNPwWcbQiWG7U4wDW69zEdno2HcT1KwPBg,8886
4
+ mpflash/basicgit.py,sha256=Aiz6rF6PVhQir-FU-T1NhbjsW803y39Js6xnWs8-yu4,9676
5
+ mpflash/bootloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ mpflash/bootloader/activate.py,sha256=orQOw4XTkXVZI-rMInRb0T5Wp3qA_BlzbJUA2gyBToU,2361
7
+ mpflash/bootloader/detect.py,sha256=OagP2QVWeLLWkZt2paqEF6r4_x3QDcBGNCPOWfMy9NQ,2686
8
+ mpflash/bootloader/manual.py,sha256=WYC4x-dxrSwVUfgnKTlu34pCzckrWJKZnWsARDocycI,3169
9
+ mpflash/bootloader/micropython.py,sha256=v_kZkvg0uWZDbMrT78gmiYHbD83QLdnrctvEClI8iRg,529
10
+ mpflash/bootloader/touch1200.py,sha256=VND7_YniS9Vx6WEaAxjI72RZZ6WBOwmBTsKJkbuaAHk,1105
11
+ mpflash/cli_download.py,sha256=sMMIVTE4P9O2GpWB9jcbOiKQX-XJ0nu2bBylRbWu0X8,3872
12
+ mpflash/cli_flash.py,sha256=Is8UH1QZ33XuajrkVOIdjOubyvAb5CcZKONJgdmmZGk,7966
13
+ mpflash/cli_group.py,sha256=Uf_1ZmeeSIsaGLuuKn3KPPPVi8fJVbIacJYFZx_oPHc,2684
14
+ mpflash/cli_list.py,sha256=ZuRalXXjDGo6FhgMTv54BQD_PNss7eeopeZQ_uE1J90,2632
15
+ mpflash/cli_main.py,sha256=NMhEtMtSe7ApE-210Q4p-g7ZgewgO-4z1Q-vNKLQ47Y,1277
16
+ mpflash/common.py,sha256=iKDoc6Ut8XbZ8fYLEI2XsoU7GuG_pFG0KGcRWXPl1wE,5922
17
+ mpflash/config.py,sha256=bmwNSJzk27iHcI-r3C6hm6-TeOat2ymzbbv-Q-xuO2o,3048
18
+ mpflash/connected.py,sha256=oxZdk1o-AfNPhJsSxr3KrMH_gdYfrjqc_IpT6J8Ng9k,3496
19
+ mpflash/db/__init__.py,sha256=wnIlO4nOXsPGXMbn2OCqHRsR-hUmtJsko8VdqjH3ZUE,45
20
+ mpflash/db/core.py,sha256=hyzurZp8QMl8Q9B00Q-tOkOUp68T8XhM7tj3dm5cDHw,2283
21
+ mpflash/db/gather_boards.py,sha256=8QS7NIt3n9ROqtgVAnoqU8YMeObLGaN2pvJL7d_kULA,3905
22
+ mpflash/db/loader.py,sha256=0L4I3ySaGLFlzy9FlV7_nzbqzA6MHwi0FhgDG5FJ_9U,4848
23
+ mpflash/db/meta.py,sha256=I7JycEx37MVVYowA0VFfUYFX9IURiTTsWQ1RhFgGqes,2251
24
+ mpflash/db/micropython_boards.zip,sha256=cc4m7VSskj__rhabw3j5OZCiz1yEi6yCx7JGFn1QB0k,16647
25
+ mpflash/db/models.py,sha256=Q4yjZPcNRIGWevoACeGDS1i31QX6jq1q5TsyPjmdmz4,3448
26
+ mpflash/db/tools.py,sha256=6SEGfshNob4yRQ4h-Cj_xcWMRY28sbA8CWauNXV_uMI,814
27
+ mpflash/download/__init__.py,sha256=zidXvsSFCfR-BZCZ6TiB7uEucEuUqXnZhKSfTs60lzU,7930
28
+ mpflash/download/from_web.py,sha256=PVJDaFfYLJGXlPva5fExh4Yg2H7j3idyJEcfOiVVJBs,7608
29
+ mpflash/download/fwinfo.py,sha256=gpa92PkysT1B7mxPAFJ-b_6y03QCNgHKm-J6T_RFNMI,1852
30
+ mpflash/download/jid.py,sha256=503HW4jIB22fsb9vYphXqqO33LTMtvPdENG81wKDgMs,2334
31
+ mpflash/downloaded.py,sha256=508sqROPf0Ymz7UxMzReXtK6mG1EcoXA-ysGdzV-VM0,4040
32
+ mpflash/errors.py,sha256=IAidY3qkZsXy6Pm1rdmVFmGyg81ywHhse3itaPctA2w,247
33
+ mpflash/flash/__init__.py,sha256=jif7-ifsXMabidjNdqUQyl1CwD5_USjCAZFhU5W-Aw8,2992
34
+ mpflash/flash/esp.py,sha256=4977E1hDqJ4-EIkLzwrUtgZuc0ZTD7NvP1PQZgZ2DoU,3227
35
+ mpflash/flash/stm32.py,sha256=jNgMpJaxUwtJ-v6VU1luD1t41AQprCUeNVCVEovxQe0,595
36
+ mpflash/flash/stm32_dfu.py,sha256=W-3JsRQyf3DduoIRXDmGZ35RogqtjQgcJnk-GOtQoLE,3090
37
+ mpflash/flash/uf2/__init__.py,sha256=haL84hP2p1ZjKF6dXJJHAB_NTf7jT91MuZvmvg9SpIA,3617
38
+ mpflash/flash/uf2/boardid.py,sha256=U5wGM8VA3wEpUxQCMtuXpMZZomdVH8J_Zd5_GekUMuU,423
39
+ mpflash/flash/uf2/linux.py,sha256=uTgqyS7C7xfQ25RrTcSUkt-m2u2Ks_o7bPLzIecPoC8,4355
40
+ mpflash/flash/uf2/macos.py,sha256=JTaIpqnR_0k4oSEvzs9amhmK-PMxUJyZLnZ_wZwxa-0,1228
41
+ mpflash/flash/uf2/uf2disk.py,sha256=4_P2l-kedM7VSliA2u706LQLxvu3xWSod1-lj-xjZis,298
42
+ mpflash/flash/uf2/windows.py,sha256=OEeskObPtpIE4a5NzYIcBqg3FkM5MGPGEa4lGGOfntY,1338
43
+ mpflash/flash/worklist.py,sha256=ZqbgYChXFGEVLVlGKeS9eJJDToxBYqjrfWE2NIa7Cck,5622
44
+ mpflash/list.py,sha256=NNhKpRh3ARZMdq56GLJgJ67GeuUf9SxjTzFhQjDsi9A,4008
45
+ mpflash/logger.py,sha256=b2pNiAEXgpUDZKnMjtgBAGgMpPwTB3u030EhJiXyLZQ,2009
46
+ mpflash/mpboard_id/__init__.py,sha256=Z6gDDWTCSKPp2fsuaUz80zgrklBR9XDlSLF9y_evR9A,391
47
+ mpflash/mpboard_id/alternate.py,sha256=ZhqfdA9sLJmyOfJ6WwK9wrzzUn6JQdkAreiL0q5XEQg,1913
48
+ mpflash/mpboard_id/board_id.py,sha256=dGbYnqaGHm6Z68P6aCq5bv95pyhi9KKhQleQXmlyO8Y,2046
49
+ mpflash/mpboard_id/board_info.json,sha256=A3ZIt38KvAy2NMB5srHorSBd3Q3wOZIXufWiIs3XLrs,1019745
50
+ mpflash/mpboard_id/board_info.zip,sha256=-2bnQGRsIQuJUfz-7_-GQ8pMWJ1evhCez6yfjhXocNw,23213
51
+ mpflash/mpboard_id/known.py,sha256=GrNe4FtzVIdi9L9xuJ1gzorzXTvdfrugX1iVc_Nblb8,3325
52
+ mpflash/mpboard_id/resolve.py,sha256=5KCZ0Tcg3FYZ3HK_zux5EguwoSC2E03kCpW2fh4rN2A,779
53
+ mpflash/mpremoteboard/__init__.py,sha256=MvvJy6G32YQf8IqZR2AjMXcusI82Muy6JVvjVv7dZhw,12092
54
+ mpflash/mpremoteboard/mpy_fw_info.py,sha256=ZDEPJN9XJnoG_oeWcLNiLJAD5bkVX2yI_j4K7msUxWM,5196
55
+ mpflash/mpremoteboard/runner.py,sha256=auJuK7uBq_qdZOX9DgzRARyAsTyhT8c9ycP02VqhMf4,4943
56
+ mpflash/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ mpflash/vendor/board_database.py,sha256=Cb8fEhJaZ2siMkLPW5rPwV9yzBsTtKGOqWUd9TxNgFM,8763
58
+ mpflash/vendor/click_aliases.py,sha256=adLhqLxNpJEPjSCIRSTkR-QzSgavGFKT0cwRbjxpzRU,5395
59
+ mpflash/vendor/dfu.py,sha256=6rqGCBS8mTxxaLtkdzJ8O6nc74kFk8jrkmKvxw-x-u8,5693
60
+ mpflash/vendor/pico-universal-flash-nuke/LICENSE.txt,sha256=Zkc2iTNbib2NCMwtLjMEz0vFCPglgvaw6Mj7QiWldpQ,1484
61
+ mpflash/vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2,sha256=QuPMppqHMVOt3vDVU0bikHRLsTiDRQYNUcGQ_OLRFGI,28160
62
+ mpflash/vendor/pydfu.py,sha256=KD1RHHuhvhWi-l1UB6GyggkxouDKtZgkG4ivRbIfwC4,21264
63
+ mpflash/vendor/readme.md,sha256=BQ7Uxf8joeYMjTUuSLLBG49ob6a9MgFPIEwuc72-Mfw,415
64
+ mpflash/versions.py,sha256=HuujLNdMKY_mQXyEqwXVHcU8nbuXeBiWP2TMA5JQhr4,4884
65
+ mpflash-1.25.0.post2.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
66
+ mpflash-1.25.0.post2.dist-info/LICENSE,sha256=mWpNhsIxWzetYNnTpr4eb3HtgsxGIC8KcYWxXEcxQvE,1077
67
+ mpflash-1.25.0.post2.dist-info/METADATA,sha256=bHmPpoBGN1AFCU0EeOA-fzkBeyKDzNoAvMj5JbpoJKY,26234
68
+ mpflash-1.25.0.post2.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
69
+ mpflash-1.25.0.post2.dist-info/RECORD,,
mpflash/db/boards.py DELETED
@@ -1,63 +0,0 @@
1
-
2
- from __future__ import annotations
3
-
4
- import sqlite3
5
- from pathlib import Path
6
- from typing import List
7
-
8
- from mpflash.common import FWInfo
9
- from mpflash.config import config
10
- from mpflash.logger import log
11
-
12
-
13
- def find_board_id(
14
- db_path: Path | None = None, board_id: str = "", description: str = "", version: str = "%"
15
- ) -> List[str]:
16
- """Get a list of board IDs from the database based on the board ID or description"""
17
- db_path = db_path or config.db_path
18
- conn = sqlite3.connect(db_path)
19
- conn.row_factory = sqlite3.Row
20
- rows = []
21
- with conn:
22
- cursor = conn.cursor()
23
-
24
- query = """
25
- SELECT DISTINCT board_id FROM board_downloaded
26
- where board_id like ? and version like ?
27
- ORDER BY `version` ASC
28
- """
29
- cursor.execute(query, (board_id,version))
30
- rows = cursor.fetchall()
31
- if len(rows) == 0:
32
- cursor.execute(
33
- """
34
- SELECT DISTINCT description FROM board_downloaded
35
- where description like ? and version like ?
36
- ORDER BY `description` ASC
37
- """,
38
- (description,version),
39
- )
40
- rows = cursor.fetchall()
41
-
42
- return [row['board_id'] for row in rows]
43
-
44
-
45
- def find_board_info(
46
- db_path: Path | None = None, board_id: str = "", version: str = "%"
47
- ) -> List[sqlite3.Row]:
48
- """get a list of board rows from the database based on the board ID and version"""
49
- db_path = db_path or config.db_path
50
- conn = sqlite3.connect(db_path)
51
- conn.row_factory = sqlite3.Row
52
- rows = []
53
- with conn:
54
- cursor = conn.cursor()
55
- query = """
56
- SELECT * FROM board_downloaded
57
- where board_id like ? and version like ?
58
- ORDER BY board_id, version ASC
59
- """
60
- cursor.execute(query, (board_id,version,))
61
- rows = cursor.fetchall()
62
-
63
- return rows
mpflash/db/downloads.py DELETED
@@ -1,87 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import sqlite3
4
- from pathlib import Path
5
- from typing import List
6
-
7
- from mpflash.common import FWInfo
8
- from mpflash.config import config
9
- from mpflash.logger import log
10
-
11
-
12
- def upsert_download(conn: sqlite3.Connection, board: FWInfo):
13
- """
14
- Adds a row to the downloaded firmware table in the database.
15
- - downloads.board_id <-- FWInfo.variant
16
- - downloads.source <-- FWInfo.firmware
17
-
18
- Args:
19
- conn : The database connection to use.
20
- board : The firmware information to add to the database.
21
-
22
- """
23
- with conn:
24
- conn.execute(
25
- """
26
- INSERT INTO downloads
27
- (port, board, filename, source, board_id, version, build, ext, family, custom, description)
28
- VALUES
29
- (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
30
- ON CONFLICT(filename) DO UPDATE SET
31
- port=excluded.port,
32
- board=excluded.board,
33
- source=excluded.source,
34
- board_id=excluded.board_id,
35
- version=excluded.version,
36
- build=excluded.build,
37
- ext=excluded.ext,
38
- family=excluded.family,
39
- custom=excluded.custom,
40
- description=excluded.description
41
- """,
42
- (
43
- board.port,
44
- board.board,
45
- board.filename,
46
- board.firmware,
47
- board.variant,
48
- board.version,
49
- board.build,
50
- board.ext,
51
- board.family,
52
- board.custom,
53
- board.description,
54
- ),
55
- )
56
- conn.commit()
57
-
58
- def downloaded(db_path: Path | None = None) -> List[FWInfo]:
59
- """Load a list of locally downloaded firmwares from the database"""
60
- db_path = db_path or config.db_path
61
- with sqlite3.connect(db_path) as conn:
62
- firmwares: List[FWInfo] = []
63
- try:
64
- conn.row_factory = sqlite3.Row
65
- cursor = conn.cursor()
66
- cursor.execute("SELECT * FROM downloads")
67
- rows = cursor.fetchall()
68
- for row in rows:
69
- fw_info = FWInfo.from_dict(
70
- {
71
- "filename": row["filename"],
72
- "version": row["version"],
73
- "board": row["board"],
74
- "variant": row["board_id"],
75
- "port": row["port"],
76
- "firmware": row["source"],
77
- "build": row["build"],
78
- "preview": 1 if int(row["build"]) > 0 else 0,
79
- }
80
- )
81
- firmwares.append(fw_info)
82
- except sqlite3.Error as e:
83
- log.error(f"Database error: {e}")
84
-
85
- # sort by filename
86
- firmwares.sort(key=lambda x: x.filename)
87
- return firmwares
@@ -1,260 +0,0 @@
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.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.versions import get_preview_mp_version, 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 boards and variants in the mpconfigboard*.cmake files
27
- RE_CMAKE_MICROPY_HW_BOARD_NAME = re.compile(r"MICROPY_HW_BOARD_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\"")
28
- RE_CMAKE_MICROPY_HW_MCU_NAME = re.compile(r"MICROPY_HW_MCU_NAME\s?=\s?\"(?P<variant>[\w\s\S]*)\"")
29
- # TODO: normal make files
30
-
31
-
32
- def boards_from_repo(mpy_path: Path, version: str, family: Optional[str] = None) -> List[Board]:
33
- """Collects board name and decriptions from mpconfigboard.h files.
34
-
35
- Args:
36
- mpy_path (Path): The path to the MicroPython repository.
37
- version (str): The version of MicroPython.
38
-
39
- Returns:
40
- List[Board]: A list of Board objects containing the board information.
41
- """
42
- if not mpy_path.exists() or not mpy_path.is_dir():
43
- raise FileNotFoundError(f"MicroPython path {mpy_path} does not exist.")
44
- family = family or "micropython"
45
- version = version or git.get_local_tag() # type: ignore
46
- if not version:
47
- raise ValueError("No version provided and no local tag found.")
48
- elif version in ["main", "master"]:
49
- version = get_preview_mp_version()
50
-
51
- board_list: List[Board] = []
52
- # look in mpconfigboard.h files
53
- board_list = boards_from_cmake(mpy_path, version, family)
54
-
55
- # look for boards in the .cmake files
56
- board_list.extend(boards_from_headers(mpy_path, version, family))
57
-
58
- # TODO:? look for variants in the board.json 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
- # first fetch all tags from the repository
164
- git.fetch(mpy_path)
165
- for version in track(versions, description="Searching MicroPython versions"):
166
- if git.checkout_tag(tag=version, repo=mpy_path):
167
- new_ones = boards_from_repo(mpy_path, version, family="micropython")
168
- print(f"Found {len(new_ones)} board definitions for {version}.")
169
- board_list += new_ones
170
- else:
171
- print(f"Could not checkout version {version}.")
172
-
173
- # sort the board_list by description and board
174
- print("Total number of boards found:", len(board_list))
175
-
176
- board_list = unique_boards(board_list)
177
- print("Unique board descriptions found:", len(board_list))
178
- return board_list
179
-
180
-
181
- def unique_boards(board_list: List[Board], *, key_version: bool = True):
182
- """Remove duplicate boards by 'BOARD_ID description' from the list."""
183
- seen = set()
184
- result = []
185
- for x in board_list:
186
- if key_version:
187
- key = f"{x.board_id}|{x.version}|{x.description}"
188
- else:
189
- key = f"{x.board_id}|{x.description}"
190
- if key not in seen:
191
- result.append(x)
192
- seen.add(key)
193
- result.sort(key=lambda x: x.description.lower())
194
- return result
195
-
196
-
197
- def make_table(board_list: List[Board]) -> rich.table.Table:
198
- """Creates a rich table with board information."""
199
- is_wide = True
200
-
201
- table = rich.table.Table(title="MicroPython Board Information")
202
- table.add_column("Port", justify="left", style="magenta")
203
- table.add_column("BOARD_ID", justify="left", style="green")
204
- table.add_column("Variant(s)", justify="left", style="blue")
205
- table.add_column("Description", justify="left", style="cyan")
206
- table.add_column("Board Name", justify="left", style="blue")
207
- if is_wide:
208
- table.add_column("MCU Name", justify="left", style="blue")
209
- table.add_column("Detection", justify="left", style="yellow")
210
- table.add_column("Version", justify="left", style="blue")
211
- if is_wide:
212
- table.add_column("Family", justify="left", style="blue")
213
-
214
- for board in board_list:
215
- row = [board.port, board.board_id, board.variant, board.description, board.board_name]
216
- if is_wide:
217
- row.append(board.mcu_name)
218
- row.extend((str(Path(board.path).suffix), board.version))
219
- if is_wide:
220
- row.append(board.family)
221
- table.add_row(*row)
222
-
223
- return table
224
-
225
-
226
- def ask_mpy_path():
227
- """Ask the user for the path to the MicroPython repository."""
228
- questions = [
229
- inquirer.Text(
230
- "mpy_path",
231
- message="Enter the path to the MicroPython repository",
232
- default="./repos/micropython",
233
- )
234
- ]
235
- if answers := inquirer.prompt(questions):
236
- return Path(answers["mpy_path"])
237
- else:
238
- raise ValueError("No path provided.")
239
-
240
-
241
- def main():
242
- """Main function to collect and write board information."""
243
-
244
- console = Console()
245
-
246
- mpy_path = ask_mpy_path()
247
- versions = micropython_versions(minver="v1.10") + ["master"]
248
- board_list = boards_for_versions(versions, mpy_path)
249
-
250
- here = Path(__file__).parent
251
- log.info(write_boardinfo_json(board_list, folder=here))
252
- # write_files(board_list, folder=CONFIG.board_path)
253
-
254
- # table of when the board was added
255
- table = make_table(unique_boards(board_list, key_version=False))
256
- console.print(table)
257
-
258
-
259
- if __name__ == "__main__":
260
- main()
@@ -1,40 +0,0 @@
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
- variant: str = field(default="")
24
- mcu: str = field(default="")
25
-
26
- def __post_init__(self):
27
- if not self.cpu:
28
- if " with " in self.description:
29
- self.cpu = self.description.rsplit(" with ")[-1]
30
- else:
31
- self.cpu = self.port
32
-
33
- @staticmethod
34
- def from_dict(data: dict) -> "Board":
35
- valid_keys = {field.name for field in Board.__dataclass_fields__.values()}
36
- filtered_data = {k: v for k, v in data.items() if k in valid_keys}
37
- return Board(**filtered_data)
38
-
39
- def to_dict(self) -> dict:
40
- return self.__dict__
@@ -1,47 +0,0 @@
1
- import functools
2
- import zipfile
3
- from pathlib import Path
4
- from typing import Final, List, Optional
5
- from mpflash.logger import log
6
-
7
- import jsons
8
-
9
- from mpflash.mpboard_id.board import Board
10
-
11
- ###############################################################################################
12
- HERE: Final = Path(__file__).parent
13
- ###############################################################################################
14
-
15
-
16
- def write_boardinfo_json(board_list: List[Board], *, folder: Optional[Path] = None):
17
- """Writes the board information to a JSON file.
18
-
19
- Args:
20
- board_list (List[Board]): The list of Board objects.
21
- folder (Path): The folder where the compressed JSON file will be saved.
22
- """
23
-
24
- if not folder:
25
- folder = HERE
26
- # create a zip file with the json file
27
- with zipfile.ZipFile(folder / "board_info.zip", "w", compression=zipfile.ZIP_DEFLATED) as zipf:
28
- # write the list to json file inside the zip
29
- with zipf.open("board_info.json", "w") as fp:
30
- fp.write(jsons.dumps(board_list, jdkwargs={"indent": 4}).encode())
31
-
32
-
33
- @functools.lru_cache(maxsize=20)
34
- def read_known_boardinfo(board_info: Optional[Path] = None) -> List[Board]:
35
- """Reads the board information from a JSON file in a zip file."""
36
- log.warning("read_known_boardinfo() is deprecated")
37
-
38
- if not board_info:
39
- board_info = HERE / "board_info.zip"
40
- if not board_info.exists():
41
- raise FileNotFoundError(f"Board info file not found: {board_info}")
42
-
43
- with zipfile.ZipFile(board_info, "r") as zf:
44
- with zf.open("board_info.json", "r") as file:
45
- info = jsons.loads(file.read().decode(encoding="utf-8"), List[Board])
46
-
47
- return info