mpflash 1.0.1__py3-none-any.whl → 1.0.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.
- mpflash/add_firmware.py +98 -98
- mpflash/ask_input.py +236 -236
- mpflash/basicgit.py +284 -284
- mpflash/bootloader/__init__.py +2 -2
- mpflash/bootloader/activate.py +60 -60
- mpflash/bootloader/detect.py +82 -82
- mpflash/bootloader/manual.py +101 -101
- mpflash/bootloader/micropython.py +12 -12
- mpflash/bootloader/touch1200.py +36 -36
- mpflash/cli_download.py +129 -129
- mpflash/cli_flash.py +224 -216
- mpflash/cli_group.py +111 -111
- mpflash/cli_list.py +87 -87
- mpflash/cli_main.py +39 -39
- mpflash/common.py +210 -177
- mpflash/config.py +44 -44
- mpflash/connected.py +104 -77
- mpflash/download.py +364 -364
- mpflash/downloaded.py +130 -130
- mpflash/errors.py +9 -9
- mpflash/flash/__init__.py +55 -55
- mpflash/flash/esp.py +59 -59
- mpflash/flash/stm32.py +19 -19
- mpflash/flash/stm32_dfu.py +104 -104
- mpflash/flash/uf2/__init__.py +88 -88
- mpflash/flash/uf2/boardid.py +15 -15
- mpflash/flash/uf2/linux.py +136 -130
- mpflash/flash/uf2/macos.py +42 -42
- mpflash/flash/uf2/uf2disk.py +12 -12
- mpflash/flash/uf2/windows.py +43 -43
- mpflash/flash/worklist.py +170 -170
- mpflash/list.py +106 -106
- mpflash/logger.py +41 -41
- mpflash/mpboard_id/__init__.py +93 -93
- mpflash/mpboard_id/add_boards.py +251 -251
- mpflash/mpboard_id/board.py +37 -37
- mpflash/mpboard_id/board_id.py +86 -86
- mpflash/mpboard_id/store.py +43 -43
- mpflash/mpremoteboard/__init__.py +266 -266
- mpflash/mpremoteboard/mpy_fw_info.py +141 -141
- mpflash/mpremoteboard/runner.py +140 -140
- mpflash/vendor/click_aliases.py +91 -91
- mpflash/vendor/dfu.py +165 -165
- mpflash/vendor/pydfu.py +605 -605
- mpflash/vendor/readme.md +2 -2
- mpflash/versions.py +135 -135
- {mpflash-1.0.1.dist-info → mpflash-1.0.2.dist-info}/LICENSE +20 -20
- {mpflash-1.0.1.dist-info → mpflash-1.0.2.dist-info}/METADATA +1 -1
- mpflash-1.0.2.dist-info/RECORD +53 -0
- mpflash-1.0.1.dist-info/RECORD +0 -53
- {mpflash-1.0.1.dist-info → mpflash-1.0.2.dist-info}/WHEEL +0 -0
- {mpflash-1.0.1.dist-info → mpflash-1.0.2.dist-info}/entry_points.txt +0 -0
mpflash/flash/worklist.py
CHANGED
@@ -1,170 +1,170 @@
|
|
1
|
-
"""Worklist for updating boards"""
|
2
|
-
|
3
|
-
from pathlib import Path
|
4
|
-
from typing import Dict, List, Optional, Tuple
|
5
|
-
|
6
|
-
from loguru import logger as log
|
7
|
-
|
8
|
-
from mpflash.common import FWInfo, filtered_comports
|
9
|
-
from mpflash.downloaded import find_downloaded_firmware
|
10
|
-
from mpflash.errors import MPFlashError
|
11
|
-
from mpflash.list import show_mcus
|
12
|
-
from mpflash.mpboard_id import find_known_board
|
13
|
-
from mpflash.mpremoteboard import MPRemoteBoard
|
14
|
-
|
15
|
-
# #########################################################################################################
|
16
|
-
WorkList = List[Tuple[MPRemoteBoard, FWInfo]]
|
17
|
-
# #########################################################################################################
|
18
|
-
|
19
|
-
|
20
|
-
def auto_update(
|
21
|
-
conn_boards: List[MPRemoteBoard],
|
22
|
-
target_version: str,
|
23
|
-
fw_folder: Path,
|
24
|
-
*,
|
25
|
-
selector: Optional[Dict[str, str]] = None,
|
26
|
-
) -> WorkList:
|
27
|
-
"""Builds a list of boards to update based on the connected boards and the firmwares available locally in the firmware folder.
|
28
|
-
|
29
|
-
Args:
|
30
|
-
conn_boards (List[MPRemoteBoard]): List of connected boards
|
31
|
-
target_version (str): Target firmware version
|
32
|
-
fw_folder (Path): Path to the firmware folder
|
33
|
-
selector (Optional[Dict[str, str]], optional): Selector for filtering firmware. Defaults to None.
|
34
|
-
|
35
|
-
Returns:
|
36
|
-
WorkList: List of boards and firmware information to update
|
37
|
-
"""
|
38
|
-
if selector is None:
|
39
|
-
selector = {}
|
40
|
-
wl: WorkList = []
|
41
|
-
for mcu in conn_boards:
|
42
|
-
if mcu.family not in ("micropython", "unknown"):
|
43
|
-
log.warning(f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware")
|
44
|
-
continue
|
45
|
-
board_firmwares = find_downloaded_firmware(
|
46
|
-
fw_folder=fw_folder,
|
47
|
-
board_id=mcu.board,
|
48
|
-
version=target_version,
|
49
|
-
port=mcu.port,
|
50
|
-
selector=selector,
|
51
|
-
)
|
52
|
-
|
53
|
-
if not board_firmwares:
|
54
|
-
log.error(f"No {target_version} firmware found for {mcu.board} on {mcu.serialport}.")
|
55
|
-
continue
|
56
|
-
|
57
|
-
if len(board_firmwares) > 1:
|
58
|
-
log.warning(f"Multiple {target_version} firmwares found for {mcu.board} on {mcu.serialport}.")
|
59
|
-
|
60
|
-
# just use the last firmware
|
61
|
-
fw_info = board_firmwares[-1]
|
62
|
-
log.info(f"Found {target_version} firmware {fw_info.filename} for {mcu.board} on {mcu.serialport}.")
|
63
|
-
wl.append((mcu, fw_info))
|
64
|
-
return wl
|
65
|
-
|
66
|
-
|
67
|
-
def manual_worklist(
|
68
|
-
serial: str,
|
69
|
-
*,
|
70
|
-
board_id: str,
|
71
|
-
version: str,
|
72
|
-
fw_folder: Path,
|
73
|
-
) -> WorkList:
|
74
|
-
"""Create a worklist for a single board specified manually.
|
75
|
-
|
76
|
-
Args:
|
77
|
-
serial (str): Serial port of the board
|
78
|
-
board (str): Board_ID
|
79
|
-
version (str): Firmware version
|
80
|
-
fw_folder (Path): Path to the firmware folder
|
81
|
-
|
82
|
-
Returns:
|
83
|
-
WorkList: List of boards and firmware information to update
|
84
|
-
"""
|
85
|
-
log.trace(f"Manual updating {serial} to {board_id} {version}")
|
86
|
-
mcu = MPRemoteBoard(serial)
|
87
|
-
# Lookup the matching port and cpu in board_info based in the board name
|
88
|
-
try:
|
89
|
-
info = find_known_board(board_id)
|
90
|
-
mcu.port = info.port
|
91
|
-
# need the CPU type for the esptool
|
92
|
-
mcu.cpu = info.cpu
|
93
|
-
except (LookupError, MPFlashError) as e:
|
94
|
-
log.error(f"Board {board_id} not found in board_info.zip")
|
95
|
-
log.exception(e)
|
96
|
-
return []
|
97
|
-
mcu.board = board_id
|
98
|
-
firmwares = find_downloaded_firmware(fw_folder=fw_folder, board_id=board_id, version=version, port=mcu.port)
|
99
|
-
if not firmwares:
|
100
|
-
log.error(f"No firmware found for {mcu.port} {board_id} version {version}")
|
101
|
-
return []
|
102
|
-
# use the most recent matching firmware
|
103
|
-
return [(mcu, firmwares[-1])] # type: ignore
|
104
|
-
|
105
|
-
|
106
|
-
def single_auto_worklist(
|
107
|
-
serial: str,
|
108
|
-
*,
|
109
|
-
version: str,
|
110
|
-
fw_folder: Path,
|
111
|
-
) -> WorkList:
|
112
|
-
"""Create a worklist for a single serial-port.
|
113
|
-
|
114
|
-
Args:
|
115
|
-
serial_port (str): Serial port of the board
|
116
|
-
version (str): Firmware version
|
117
|
-
fw_folder (Path): Path to the firmware folder
|
118
|
-
|
119
|
-
Returns:
|
120
|
-
WorkList: List of boards and firmware information to update
|
121
|
-
"""
|
122
|
-
log.trace(f"Auto updating {serial} to {version}")
|
123
|
-
conn_boards = [MPRemoteBoard(serial)]
|
124
|
-
todo = auto_update(conn_boards, version, fw_folder) # type: ignore # List / list
|
125
|
-
show_mcus(conn_boards) # type: ignore
|
126
|
-
return todo
|
127
|
-
|
128
|
-
|
129
|
-
def full_auto_worklist(
|
130
|
-
all_boards: List[MPRemoteBoard], *, include: List[str], ignore: List[str], version: str, fw_folder: Path
|
131
|
-
) -> WorkList:
|
132
|
-
"""
|
133
|
-
Create a worklist for all connected micropython boards based on the information retrieved from the board.
|
134
|
-
This allows the firmware version of one or moae boards to be changed without needing to specify the port or board_id manually.
|
135
|
-
|
136
|
-
Args:
|
137
|
-
version (str): Firmware version
|
138
|
-
fw_folder (Path): Path to the firmware folder
|
139
|
-
|
140
|
-
Returns:
|
141
|
-
WorkList: List of boards and firmware information to update
|
142
|
-
"""
|
143
|
-
log.trace(f"Auto updating all boards to {version}")
|
144
|
-
if selected_boards := filter_boards(all_boards, include=include, ignore=ignore):
|
145
|
-
return auto_update(selected_boards, version, fw_folder)
|
146
|
-
else:
|
147
|
-
return []
|
148
|
-
|
149
|
-
|
150
|
-
def filter_boards(
|
151
|
-
all_boards: List[MPRemoteBoard],
|
152
|
-
*,
|
153
|
-
include: List[str],
|
154
|
-
ignore: List[str],
|
155
|
-
):
|
156
|
-
try:
|
157
|
-
comports = [
|
158
|
-
p.device
|
159
|
-
for p in filtered_comports(
|
160
|
-
ignore=ignore,
|
161
|
-
include=include,
|
162
|
-
bluetooth=False,
|
163
|
-
)
|
164
|
-
]
|
165
|
-
selected_boards = [b for b in all_boards if b.serialport in comports]
|
166
|
-
# [MPRemoteBoard(port.device, update=True) for port in comports]
|
167
|
-
except ConnectionError as e:
|
168
|
-
log.error(f"Error connecting to boards: {e}")
|
169
|
-
return []
|
170
|
-
return selected_boards # type: ignore
|
1
|
+
"""Worklist for updating boards"""
|
2
|
+
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Dict, List, Optional, Tuple
|
5
|
+
|
6
|
+
from loguru import logger as log
|
7
|
+
|
8
|
+
from mpflash.common import FWInfo, filtered_comports
|
9
|
+
from mpflash.downloaded import find_downloaded_firmware
|
10
|
+
from mpflash.errors import MPFlashError
|
11
|
+
from mpflash.list import show_mcus
|
12
|
+
from mpflash.mpboard_id import find_known_board
|
13
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
14
|
+
|
15
|
+
# #########################################################################################################
|
16
|
+
WorkList = List[Tuple[MPRemoteBoard, FWInfo]]
|
17
|
+
# #########################################################################################################
|
18
|
+
|
19
|
+
|
20
|
+
def auto_update(
|
21
|
+
conn_boards: List[MPRemoteBoard],
|
22
|
+
target_version: str,
|
23
|
+
fw_folder: Path,
|
24
|
+
*,
|
25
|
+
selector: Optional[Dict[str, str]] = None,
|
26
|
+
) -> WorkList:
|
27
|
+
"""Builds a list of boards to update based on the connected boards and the firmwares available locally in the firmware folder.
|
28
|
+
|
29
|
+
Args:
|
30
|
+
conn_boards (List[MPRemoteBoard]): List of connected boards
|
31
|
+
target_version (str): Target firmware version
|
32
|
+
fw_folder (Path): Path to the firmware folder
|
33
|
+
selector (Optional[Dict[str, str]], optional): Selector for filtering firmware. Defaults to None.
|
34
|
+
|
35
|
+
Returns:
|
36
|
+
WorkList: List of boards and firmware information to update
|
37
|
+
"""
|
38
|
+
if selector is None:
|
39
|
+
selector = {}
|
40
|
+
wl: WorkList = []
|
41
|
+
for mcu in conn_boards:
|
42
|
+
if mcu.family not in ("micropython", "unknown"):
|
43
|
+
log.warning(f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware")
|
44
|
+
continue
|
45
|
+
board_firmwares = find_downloaded_firmware(
|
46
|
+
fw_folder=fw_folder,
|
47
|
+
board_id=mcu.board,
|
48
|
+
version=target_version,
|
49
|
+
port=mcu.port,
|
50
|
+
selector=selector,
|
51
|
+
)
|
52
|
+
|
53
|
+
if not board_firmwares:
|
54
|
+
log.error(f"No {target_version} firmware found for {mcu.board} on {mcu.serialport}.")
|
55
|
+
continue
|
56
|
+
|
57
|
+
if len(board_firmwares) > 1:
|
58
|
+
log.warning(f"Multiple {target_version} firmwares found for {mcu.board} on {mcu.serialport}.")
|
59
|
+
|
60
|
+
# just use the last firmware
|
61
|
+
fw_info = board_firmwares[-1]
|
62
|
+
log.info(f"Found {target_version} firmware {fw_info.filename} for {mcu.board} on {mcu.serialport}.")
|
63
|
+
wl.append((mcu, fw_info))
|
64
|
+
return wl
|
65
|
+
|
66
|
+
|
67
|
+
def manual_worklist(
|
68
|
+
serial: str,
|
69
|
+
*,
|
70
|
+
board_id: str,
|
71
|
+
version: str,
|
72
|
+
fw_folder: Path,
|
73
|
+
) -> WorkList:
|
74
|
+
"""Create a worklist for a single board specified manually.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
serial (str): Serial port of the board
|
78
|
+
board (str): Board_ID
|
79
|
+
version (str): Firmware version
|
80
|
+
fw_folder (Path): Path to the firmware folder
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
WorkList: List of boards and firmware information to update
|
84
|
+
"""
|
85
|
+
log.trace(f"Manual updating {serial} to {board_id} {version}")
|
86
|
+
mcu = MPRemoteBoard(serial)
|
87
|
+
# Lookup the matching port and cpu in board_info based in the board name
|
88
|
+
try:
|
89
|
+
info = find_known_board(board_id)
|
90
|
+
mcu.port = info.port
|
91
|
+
# need the CPU type for the esptool
|
92
|
+
mcu.cpu = info.cpu
|
93
|
+
except (LookupError, MPFlashError) as e:
|
94
|
+
log.error(f"Board {board_id} not found in board_info.zip")
|
95
|
+
log.exception(e)
|
96
|
+
return []
|
97
|
+
mcu.board = board_id
|
98
|
+
firmwares = find_downloaded_firmware(fw_folder=fw_folder, board_id=board_id, version=version, port=mcu.port)
|
99
|
+
if not firmwares:
|
100
|
+
log.error(f"No firmware found for {mcu.port} {board_id} version {version}")
|
101
|
+
return []
|
102
|
+
# use the most recent matching firmware
|
103
|
+
return [(mcu, firmwares[-1])] # type: ignore
|
104
|
+
|
105
|
+
|
106
|
+
def single_auto_worklist(
|
107
|
+
serial: str,
|
108
|
+
*,
|
109
|
+
version: str,
|
110
|
+
fw_folder: Path,
|
111
|
+
) -> WorkList:
|
112
|
+
"""Create a worklist for a single serial-port.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
serial_port (str): Serial port of the board
|
116
|
+
version (str): Firmware version
|
117
|
+
fw_folder (Path): Path to the firmware folder
|
118
|
+
|
119
|
+
Returns:
|
120
|
+
WorkList: List of boards and firmware information to update
|
121
|
+
"""
|
122
|
+
log.trace(f"Auto updating {serial} to {version}")
|
123
|
+
conn_boards = [MPRemoteBoard(serial)]
|
124
|
+
todo = auto_update(conn_boards, version, fw_folder) # type: ignore # List / list
|
125
|
+
show_mcus(conn_boards) # type: ignore
|
126
|
+
return todo
|
127
|
+
|
128
|
+
|
129
|
+
def full_auto_worklist(
|
130
|
+
all_boards: List[MPRemoteBoard], *, include: List[str], ignore: List[str], version: str, fw_folder: Path
|
131
|
+
) -> WorkList:
|
132
|
+
"""
|
133
|
+
Create a worklist for all connected micropython boards based on the information retrieved from the board.
|
134
|
+
This allows the firmware version of one or moae boards to be changed without needing to specify the port or board_id manually.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
version (str): Firmware version
|
138
|
+
fw_folder (Path): Path to the firmware folder
|
139
|
+
|
140
|
+
Returns:
|
141
|
+
WorkList: List of boards and firmware information to update
|
142
|
+
"""
|
143
|
+
log.trace(f"Auto updating all boards to {version}")
|
144
|
+
if selected_boards := filter_boards(all_boards, include=include, ignore=ignore):
|
145
|
+
return auto_update(selected_boards, version, fw_folder)
|
146
|
+
else:
|
147
|
+
return []
|
148
|
+
|
149
|
+
|
150
|
+
def filter_boards(
|
151
|
+
all_boards: List[MPRemoteBoard],
|
152
|
+
*,
|
153
|
+
include: List[str],
|
154
|
+
ignore: List[str],
|
155
|
+
):
|
156
|
+
try:
|
157
|
+
comports = [
|
158
|
+
p.device
|
159
|
+
for p in filtered_comports(
|
160
|
+
ignore=ignore,
|
161
|
+
include=include,
|
162
|
+
bluetooth=False,
|
163
|
+
)
|
164
|
+
]
|
165
|
+
selected_boards = [b for b in all_boards if b.serialport in comports]
|
166
|
+
# [MPRemoteBoard(port.device, update=True) for port in comports]
|
167
|
+
except ConnectionError as e:
|
168
|
+
log.error(f"Error connecting to boards: {e}")
|
169
|
+
return []
|
170
|
+
return selected_boards # type: ignore
|
mpflash/list.py
CHANGED
@@ -1,106 +1,106 @@
|
|
1
|
-
from typing import List
|
2
|
-
|
3
|
-
from rich.progress import track
|
4
|
-
from rich.table import Table
|
5
|
-
|
6
|
-
from mpflash.config import config
|
7
|
-
from mpflash.mpremoteboard import MPRemoteBoard
|
8
|
-
from mpflash.versions import clean_version
|
9
|
-
|
10
|
-
from .logger import console
|
11
|
-
|
12
|
-
|
13
|
-
def show_mcus(
|
14
|
-
conn_mcus: List[MPRemoteBoard],
|
15
|
-
title: str = "Connected boards",
|
16
|
-
refresh: bool = True,
|
17
|
-
):
|
18
|
-
console.print(mcu_table(conn_mcus, title, refresh))
|
19
|
-
|
20
|
-
|
21
|
-
def abbrv_family(family: str, is_wide: bool) -> str:
|
22
|
-
if not is_wide:
|
23
|
-
ABRV = {"micropython": "upy", "circuitpython": "cpy", "unknown": "?"}
|
24
|
-
return ABRV.get(family, family[:4])
|
25
|
-
return family
|
26
|
-
|
27
|
-
|
28
|
-
def mcu_table(
|
29
|
-
conn_mcus: List[MPRemoteBoard],
|
30
|
-
title: str = "Connected boards",
|
31
|
-
refresh: bool = True,
|
32
|
-
):
|
33
|
-
"""
|
34
|
-
builds a rich table with the connected boards information
|
35
|
-
The columns of the table are adjusted to the terminal width
|
36
|
-
the columns are :
|
37
|
-
Narrow Wide
|
38
|
-
- Serial Yes Yes
|
39
|
-
- Family abbrv. Yes
|
40
|
-
- Port - yes
|
41
|
-
- Board Yes Yes BOARD_ID and Description, and the description from board_info.toml
|
42
|
-
- CPU - Yes
|
43
|
-
- Version Yes Yes
|
44
|
-
- Build * * only if any of the mcus have a build
|
45
|
-
- Location - - only if --usb is given
|
46
|
-
"""
|
47
|
-
# refresh if requested
|
48
|
-
if refresh:
|
49
|
-
for mcu in track(
|
50
|
-
conn_mcus,
|
51
|
-
description="Updating board info",
|
52
|
-
transient=True,
|
53
|
-
show_speed=False,
|
54
|
-
refresh_per_second=1,
|
55
|
-
):
|
56
|
-
try:
|
57
|
-
mcu.get_mcu_info()
|
58
|
-
except ConnectionError:
|
59
|
-
continue
|
60
|
-
table = Table(
|
61
|
-
title=title,
|
62
|
-
title_style="magenta",
|
63
|
-
header_style="bold magenta",
|
64
|
-
collapse_padding=True,
|
65
|
-
padding=(0, 0),
|
66
|
-
)
|
67
|
-
# Build the table
|
68
|
-
# check if the terminal is wide enough to show all columns or if we need to collapse some
|
69
|
-
is_wide = console.width > 99
|
70
|
-
needs_build = any(mcu.build for mcu in conn_mcus)
|
71
|
-
|
72
|
-
table.add_column("Serial" if is_wide else "Ser.", overflow="fold")
|
73
|
-
table.add_column("Family" if is_wide else "Fam.", overflow="crop", max_width=None if is_wide else 4)
|
74
|
-
if is_wide:
|
75
|
-
table.add_column("Port")
|
76
|
-
table.add_column("Board", overflow="fold")
|
77
|
-
# table.add_column("Variant") # TODO: add variant
|
78
|
-
if is_wide:
|
79
|
-
table.add_column("CPU")
|
80
|
-
table.add_column("Version", overflow="fold", min_width=5, max_width=16)
|
81
|
-
if needs_build:
|
82
|
-
table.add_column("Build" if is_wide else "Bld", justify="right")
|
83
|
-
if config.usb:
|
84
|
-
table.add_column("Location", overflow="fold", max_width=
|
85
|
-
# fill the table with the data
|
86
|
-
for mcu in conn_mcus:
|
87
|
-
description = f"[italic bright_cyan]{mcu.description}" if mcu.description else ""
|
88
|
-
if "description" in mcu.toml:
|
89
|
-
description += f"\n[italic bright_green]{mcu.toml['description']}"
|
90
|
-
row = [
|
91
|
-
mcu.serialport.replace("/dev/", ""),
|
92
|
-
abbrv_family(mcu.family, is_wide),
|
93
|
-
]
|
94
|
-
if is_wide:
|
95
|
-
row.append(mcu.port)
|
96
|
-
row.append(f"{mcu.board}\n{description}".strip())
|
97
|
-
if is_wide:
|
98
|
-
row.append(mcu.cpu)
|
99
|
-
row.append(clean_version(mcu.version))
|
100
|
-
if needs_build:
|
101
|
-
row.append(mcu.build)
|
102
|
-
if config.usb:
|
103
|
-
row.append(mcu.location)
|
104
|
-
|
105
|
-
table.add_row(*row)
|
106
|
-
return table
|
1
|
+
from typing import List
|
2
|
+
|
3
|
+
from rich.progress import track
|
4
|
+
from rich.table import Table
|
5
|
+
|
6
|
+
from mpflash.config import config
|
7
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
8
|
+
from mpflash.versions import clean_version
|
9
|
+
|
10
|
+
from .logger import console
|
11
|
+
|
12
|
+
|
13
|
+
def show_mcus(
|
14
|
+
conn_mcus: List[MPRemoteBoard],
|
15
|
+
title: str = "Connected boards",
|
16
|
+
refresh: bool = True,
|
17
|
+
):
|
18
|
+
console.print(mcu_table(conn_mcus, title, refresh))
|
19
|
+
|
20
|
+
|
21
|
+
def abbrv_family(family: str, is_wide: bool) -> str:
|
22
|
+
if not is_wide:
|
23
|
+
ABRV = {"micropython": "upy", "circuitpython": "cpy", "unknown": "?"}
|
24
|
+
return ABRV.get(family, family[:4])
|
25
|
+
return family
|
26
|
+
|
27
|
+
|
28
|
+
def mcu_table(
|
29
|
+
conn_mcus: List[MPRemoteBoard],
|
30
|
+
title: str = "Connected boards",
|
31
|
+
refresh: bool = True,
|
32
|
+
):
|
33
|
+
"""
|
34
|
+
builds a rich table with the connected boards information
|
35
|
+
The columns of the table are adjusted to the terminal width
|
36
|
+
the columns are :
|
37
|
+
Narrow Wide
|
38
|
+
- Serial Yes Yes
|
39
|
+
- Family abbrv. Yes
|
40
|
+
- Port - yes
|
41
|
+
- Board Yes Yes BOARD_ID and Description, and the description from board_info.toml
|
42
|
+
- CPU - Yes
|
43
|
+
- Version Yes Yes
|
44
|
+
- Build * * only if any of the mcus have a build
|
45
|
+
- Location - - only if --usb is given
|
46
|
+
"""
|
47
|
+
# refresh if requested
|
48
|
+
if refresh:
|
49
|
+
for mcu in track(
|
50
|
+
conn_mcus,
|
51
|
+
description="Updating board info",
|
52
|
+
transient=True,
|
53
|
+
show_speed=False,
|
54
|
+
refresh_per_second=1,
|
55
|
+
):
|
56
|
+
try:
|
57
|
+
mcu.get_mcu_info()
|
58
|
+
except ConnectionError:
|
59
|
+
continue
|
60
|
+
table = Table(
|
61
|
+
title=title,
|
62
|
+
title_style="magenta",
|
63
|
+
header_style="bold magenta",
|
64
|
+
collapse_padding=True,
|
65
|
+
padding=(0, 0),
|
66
|
+
)
|
67
|
+
# Build the table
|
68
|
+
# check if the terminal is wide enough to show all columns or if we need to collapse some
|
69
|
+
is_wide = console.width > 99
|
70
|
+
needs_build = any(mcu.build for mcu in conn_mcus)
|
71
|
+
|
72
|
+
table.add_column("Serial" if is_wide else "Ser.", overflow="fold")
|
73
|
+
table.add_column("Family" if is_wide else "Fam.", overflow="crop", max_width=None if is_wide else 4)
|
74
|
+
if is_wide:
|
75
|
+
table.add_column("Port")
|
76
|
+
table.add_column("Board", overflow="fold")
|
77
|
+
# table.add_column("Variant") # TODO: add variant
|
78
|
+
if is_wide:
|
79
|
+
table.add_column("CPU")
|
80
|
+
table.add_column("Version", overflow="fold", min_width=5, max_width=16)
|
81
|
+
if needs_build:
|
82
|
+
table.add_column("Build" if is_wide else "Bld", justify="right")
|
83
|
+
if config.usb:
|
84
|
+
table.add_column("Location", overflow="fold", max_width=60)
|
85
|
+
# fill the table with the data
|
86
|
+
for mcu in conn_mcus:
|
87
|
+
description = f"[italic bright_cyan]{mcu.description}" if mcu.description else ""
|
88
|
+
if "description" in mcu.toml:
|
89
|
+
description += f"\n[italic bright_green]{mcu.toml['description']}"
|
90
|
+
row = [
|
91
|
+
mcu.serialport if is_wide else mcu.serialport.replace("/dev/tty", "tty"),
|
92
|
+
abbrv_family(mcu.family, is_wide),
|
93
|
+
]
|
94
|
+
if is_wide:
|
95
|
+
row.append(mcu.port)
|
96
|
+
row.append(f"{mcu.board}\n{description}".strip())
|
97
|
+
if is_wide:
|
98
|
+
row.append(mcu.cpu)
|
99
|
+
row.append(clean_version(mcu.version))
|
100
|
+
if needs_build:
|
101
|
+
row.append(mcu.build)
|
102
|
+
if config.usb:
|
103
|
+
row.append(mcu.location)
|
104
|
+
|
105
|
+
table.add_row(*row)
|
106
|
+
return table
|
mpflash/logger.py
CHANGED
@@ -1,41 +1,41 @@
|
|
1
|
-
"""Logging."""
|
2
|
-
|
3
|
-
from loguru import logger as log
|
4
|
-
from rich.console import Console
|
5
|
-
|
6
|
-
from .config import config
|
7
|
-
|
8
|
-
console = Console()
|
9
|
-
|
10
|
-
|
11
|
-
def _log_formatter(record: dict) -> str:
|
12
|
-
"""Log message formatter to combine loguru and rich formatting."""
|
13
|
-
color_map = {
|
14
|
-
"TRACE": "dim blue",
|
15
|
-
"DEBUG": "cyan",
|
16
|
-
"INFO": "bold",
|
17
|
-
"SUCCESS": "bold green",
|
18
|
-
"WARNING": "yellow",
|
19
|
-
"ERROR": "bold red",
|
20
|
-
"CRITICAL": "bold white on red",
|
21
|
-
}
|
22
|
-
lvl_color = color_map.get(record["level"].name, "cyan")
|
23
|
-
return (
|
24
|
-
"[not bold green]{time:HH:mm:ss}[/not bold green] | {level.icon} " + f"[{lvl_color}]{{message}}[/{lvl_color}]"
|
25
|
-
)
|
26
|
-
|
27
|
-
|
28
|
-
def set_loglevel(loglevel: str):
|
29
|
-
"""Set the log level for the logger"""
|
30
|
-
try:
|
31
|
-
log.remove()
|
32
|
-
except ValueError:
|
33
|
-
pass
|
34
|
-
log.add(console.print, level=loglevel.upper(), colorize=False, format=_log_formatter) # type: ignore
|
35
|
-
|
36
|
-
|
37
|
-
def make_quiet():
|
38
|
-
"""Make the logger quiet"""
|
39
|
-
config.quiet = True
|
40
|
-
console.quiet = True
|
41
|
-
set_loglevel("CRITICAL")
|
1
|
+
"""Logging."""
|
2
|
+
|
3
|
+
from loguru import logger as log
|
4
|
+
from rich.console import Console
|
5
|
+
|
6
|
+
from .config import config
|
7
|
+
|
8
|
+
console = Console()
|
9
|
+
|
10
|
+
|
11
|
+
def _log_formatter(record: dict) -> str:
|
12
|
+
"""Log message formatter to combine loguru and rich formatting."""
|
13
|
+
color_map = {
|
14
|
+
"TRACE": "dim blue",
|
15
|
+
"DEBUG": "cyan",
|
16
|
+
"INFO": "bold",
|
17
|
+
"SUCCESS": "bold green",
|
18
|
+
"WARNING": "yellow",
|
19
|
+
"ERROR": "bold red",
|
20
|
+
"CRITICAL": "bold white on red",
|
21
|
+
}
|
22
|
+
lvl_color = color_map.get(record["level"].name, "cyan")
|
23
|
+
return (
|
24
|
+
"[not bold green]{time:HH:mm:ss}[/not bold green] | {level.icon} " + f"[{lvl_color}]{{message}}[/{lvl_color}]"
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
def set_loglevel(loglevel: str):
|
29
|
+
"""Set the log level for the logger"""
|
30
|
+
try:
|
31
|
+
log.remove()
|
32
|
+
except ValueError:
|
33
|
+
pass
|
34
|
+
log.add(console.print, level=loglevel.upper(), colorize=False, format=_log_formatter) # type: ignore
|
35
|
+
|
36
|
+
|
37
|
+
def make_quiet():
|
38
|
+
"""Make the logger quiet"""
|
39
|
+
config.quiet = True
|
40
|
+
console.quiet = True
|
41
|
+
set_loglevel("CRITICAL")
|