feat: implement firmware build

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
This commit is contained in:
dw-0
2024-04-15 21:29:13 +02:00
parent da4c5fe109
commit ecb673a088
7 changed files with 451 additions and 74 deletions

View File

@@ -0,0 +1,169 @@
# ======================================================================= #
# Copyright (C) 2020 - 2024 Dominik Willner <th33xitus@gmail.com> #
# #
# This file is part of KIAUH - Klipper Installation And Update Helper #
# https://github.com/dw-0/kiauh #
# #
# This file may be distributed under the terms of the GNU GPLv3 license #
# ======================================================================= #
from subprocess import CalledProcessError, check_output, Popen, PIPE, STDOUT, run
from typing import List
from components.klipper import KLIPPER_DIR
from components.klipper_firmware import SD_FLASH_SCRIPT
from components.klipper_firmware.flash_options import (
FlashOptions,
FlashMethod,
)
from utils.logger import Logger
from utils.system_utils import log_process
def find_firmware_file(method: FlashMethod) -> bool:
target = KLIPPER_DIR.joinpath("out")
target_exists = target.exists()
if method is FlashMethod.REGULAR:
f1 = "klipper.elf.hex"
f2 = "klipper.elf"
fw_file_exists = target.joinpath(f1).exists() and target.joinpath(f2).exists()
elif method is FlashMethod.SD_CARD:
fw_file_exists = target.joinpath("klipper.bin").exists()
else:
raise Exception("Unknown flash method")
return target_exists and fw_file_exists
def find_usb_device_by_id() -> List[str]:
try:
command = "find /dev/serial/by-id/* 2>/dev/null"
output = check_output(command, shell=True, text=True)
return output.splitlines()
except CalledProcessError as e:
Logger.print_error("Unable to find a USB device!")
Logger.print_error(e, prefix=False)
return []
def find_uart_device() -> List[str]:
try:
command = '"find /dev -maxdepth 1 -regextype posix-extended -regex "^\/dev\/tty(AMA0|S0)$" 2>/dev/null"'
output = check_output(command, shell=True, text=True)
return output.splitlines()
except CalledProcessError as e:
Logger.print_error("Unable to find a UART device!")
Logger.print_error(e, prefix=False)
return []
def find_usb_dfu_device() -> List[str]:
try:
command = '"lsusb | grep "DFU" | cut -d " " -f 6 2>/dev/null"'
output = check_output(command, shell=True, text=True)
return output.splitlines()
except CalledProcessError as e:
Logger.print_error("Unable to find a USB DFU device!")
Logger.print_error(e, prefix=False)
return []
def get_sd_flash_board_list() -> List[str]:
if not KLIPPER_DIR.exists() or not SD_FLASH_SCRIPT.exists():
return []
try:
cmd = f"{SD_FLASH_SCRIPT} -l"
blist = check_output(cmd, shell=True, text=True)
return blist.splitlines()[1:]
except CalledProcessError as e:
Logger.print_error(f"An unexpected error occured:\n{e}")
def start_flash_process(flash_options: FlashOptions) -> None:
Logger.print_status(f"Flashing '{flash_options.selected_mcu}' ...")
try:
if not flash_options.flash_method:
raise Exception("Missing value for flash_method!")
if not flash_options.flash_command:
raise Exception("Missing value for flash_command!")
if not flash_options.selected_mcu:
raise Exception("Missing value for selected_mcu!")
if not flash_options.connection_type:
raise Exception("Missing value for connection_type!")
if (
flash_options.flash_method == FlashMethod.SD_CARD
and not flash_options.selected_board
):
raise Exception("Missing value for selected_board!")
if flash_options.flash_method is FlashMethod.REGULAR:
cmd = [
"make",
flash_options.flash_command.value,
f"FLASH_DEVICE={flash_options.selected_mcu}",
]
elif flash_options.flash_method is FlashMethod.SD_CARD:
if not SD_FLASH_SCRIPT.exists():
raise Exception("Unable to find Klippers sdcard flash script!")
cmd = [
SD_FLASH_SCRIPT,
"-b",
flash_options.selected_baudrate,
flash_options.selected_mcu,
flash_options.selected_board,
]
else:
raise Exception("Invalid value for flash_method!")
process = Popen(cmd, cwd=KLIPPER_DIR, stdout=PIPE, stderr=STDOUT, text=True)
log_process(process)
rc = process.returncode
if rc != 0:
raise Exception(f"Flashing failed with returncode: {rc}")
else:
Logger.print_ok("Flashing successfull!", start="\n", end="\n\n")
except (Exception, CalledProcessError):
Logger.print_error("Flashing failed!", start="\n")
Logger.print_error("See the console output above!", end="\n\n")
def run_make_clean() -> None:
try:
run(
"make clean",
cwd=KLIPPER_DIR,
shell=True,
check=True,
)
except CalledProcessError as e:
Logger.print_error(f"Unexpected error:\n{e}")
raise
def run_make_menuconfig() -> None:
try:
run(
"make PYTHON=python3 menuconfig",
cwd=KLIPPER_DIR,
shell=True,
check=True,
)
except CalledProcessError as e:
Logger.print_error(f"Unexpected error:\n{e}")
raise
def run_make() -> None:
try:
run(
"make PYTHON=python3",
cwd=KLIPPER_DIR,
shell=True,
check=True,
)
except CalledProcessError as e:
Logger.print_error(f"Unexpected error:\n{e}")
raise

View File

@@ -0,0 +1,111 @@
# ======================================================================= #
# Copyright (C) 2020 - 2024 Dominik Willner <th33xitus@gmail.com> #
# #
# This file is part of KIAUH - Klipper Installation And Update Helper #
# https://github.com/dw-0/kiauh #
# #
# This file may be distributed under the terms of the GNU GPLv3 license #
# ======================================================================= #
import textwrap
from typing import Type, Optional
from components.klipper import KLIPPER_DIR
from components.klipper_firmware.firmware_utils import (
run_make_clean,
run_make_menuconfig,
run_make,
)
from core.menus import Option
from core.menus.base_menu import BaseMenu
from utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_GREEN, COLOR_RED
from utils.logger import Logger
from utils.system_utils import (
check_package_install,
update_system_package_lists,
install_system_packages,
)
# noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic
class KlipperBuildFirmwareMenu(BaseMenu):
def __init__(self, previous_menu: Optional[Type[BaseMenu]] = None):
super().__init__()
self.deps = ["build-essential", "dpkg-dev", "make"]
self.missing_deps = check_package_install(self.deps)
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
from core.menus.advanced_menu import AdvancedMenu
self.previous_menu: Type[BaseMenu] = (
previous_menu if previous_menu is not None else AdvancedMenu
)
def set_options(self) -> None:
if len(self.missing_deps) == 0:
self.input_label_txt = "Press ENTER to continue"
self.default_option = Option(method=self.start_build_process, menu=False)
else:
self.input_label_txt = "Press ENTER to install dependencies"
self.default_option = Option(method=self.install_missing_deps, menu=False)
def print_menu(self) -> None:
header = " [ Build Firmware Menu ] "
color = COLOR_CYAN
count = 62 - len(color) - len(RESET_FORMAT)
menu = textwrap.dedent(
f"""
/=======================================================\\
| {color}{header:~^{count}}{RESET_FORMAT} |
|-------------------------------------------------------|
| The following dependencies are required: |
| |
"""
)[1:]
for d in self.deps:
status_ok = f"{COLOR_GREEN}*INSTALLED*{RESET_FORMAT}"
status_missing = f"{COLOR_RED}*MISSING*{RESET_FORMAT}"
status = status_missing if d in self.missing_deps else status_ok
padding = 39 - len(d) + len(status) + (len(status_ok) - len(status))
d = f" {COLOR_CYAN}{d}{RESET_FORMAT}"
menu += f"| {d}{status:>{padding}} |\n"
menu += "| |\n"
if len(self.missing_deps) == 0:
line = f"{COLOR_GREEN}All dependencies are met!{RESET_FORMAT}"
else:
line = f"{COLOR_RED}Dependencies are missing!{RESET_FORMAT}"
menu += f"| {line:<62} |\n"
print(menu, end="")
def install_missing_deps(self, **kwargs) -> None:
try:
update_system_package_lists(silent=False)
Logger.print_status("Installing system packages...")
install_system_packages(self.missing_deps)
except Exception as e:
Logger.print_error(e)
Logger.print_error("Installding dependencies failed!")
finally:
# restart this menu
KlipperBuildFirmwareMenu().run()
def start_build_process(self, **kwargs) -> None:
try:
run_make_clean()
run_make_menuconfig()
run_make()
Logger.print_ok("Firmware successfully built!")
Logger.print_ok(f"Firmware file located in '{KLIPPER_DIR}/out'!")
except Exception as e:
Logger.print_error(e)
Logger.print_error("Building Klipper Firmware failed!")
finally:
self.previous_menu().run()

View File

@@ -7,9 +7,10 @@
# This file may be distributed under the terms of the GNU GPLv3 license # # This file may be distributed under the terms of the GNU GPLv3 license #
# ======================================================================= # # ======================================================================= #
import textwrap import textwrap
from typing import Optional, Type
from components.klipper_firmware.flash_options import FlashOptions, FlashMethod from components.klipper_firmware.flash_options import FlashOptions, FlashMethod
from core.menus import FooterType from core.menus import FooterType, Option
from core.menus.base_menu import BaseMenu from core.menus.base_menu import BaseMenu
from utils.constants import COLOR_RED, RESET_FORMAT from utils.constants import COLOR_RED, RESET_FORMAT
@@ -20,11 +21,19 @@ class KlipperNoFirmwareErrorMenu(BaseMenu):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.set_previous_menu(None)
self.set_options()
self.flash_options = FlashOptions() self.flash_options = FlashOptions()
self.default_option = self.go_back
self.footer_type = FooterType.BLANK self.footer_type = FooterType.BLANK
self.input_label_txt = "Press ENTER to go back to [Advanced Menu]" self.input_label_txt = "Press ENTER to go back to [Advanced Menu]"
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
pass
def set_options(self) -> None:
self.default_option = Option(self.go_back, False)
def print_menu(self) -> None: def print_menu(self) -> None:
header = "!!! NO FIRMWARE FILE FOUND !!!" header = "!!! NO FIRMWARE FILE FOUND !!!"
color = COLOR_RED color = COLOR_RED
@@ -62,11 +71,15 @@ class KlipperNoFirmwareErrorMenu(BaseMenu):
class KlipperNoBoardTypesErrorMenu(BaseMenu): class KlipperNoBoardTypesErrorMenu(BaseMenu):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.default_option = self.go_back
self.footer_type = FooterType.BLANK self.footer_type = FooterType.BLANK
self.input_label_txt = "Press ENTER to go back to [Main Menu]" self.input_label_txt = "Press ENTER to go back to [Main Menu]"
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
pass
def set_options(self) -> None:
self.default_option = Option(self.go_back, False)
def print_menu(self) -> None: def print_menu(self) -> None:
header = "!!! ERROR GETTING BOARD LIST !!!" header = "!!! ERROR GETTING BOARD LIST !!!"
color = COLOR_RED color = COLOR_RED

View File

@@ -7,16 +7,28 @@
# This file may be distributed under the terms of the GNU GPLv3 license # # This file may be distributed under the terms of the GNU GPLv3 license #
# ======================================================================= # # ======================================================================= #
import textwrap import textwrap
from typing import Type, Optional
from core.menus.base_menu import BaseMenu from core.menus.base_menu import BaseMenu
from utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_YELLOW from utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_YELLOW
# noinspection DuplicatedCode
class KlipperFlashMethodHelpMenu(BaseMenu): class KlipperFlashMethodHelpMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu): def __init__(self):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
from components.klipper_firmware.menus.klipper_flash_menu import (
KlipperFlashMethodMenu,
)
self.previous_menu: Type[BaseMenu] = (
previous_menu if previous_menu is not None else KlipperFlashMethodMenu
)
def set_options(self) -> None:
pass
def print_menu(self) -> None: def print_menu(self) -> None:
header = " < ? > Help: Flash MCU < ? > " header = " < ? > Help: Flash MCU < ? > "
@@ -57,11 +69,22 @@ class KlipperFlashMethodHelpMenu(BaseMenu):
print(menu, end="") print(menu, end="")
# noinspection DuplicatedCode
class KlipperFlashCommandHelpMenu(BaseMenu): class KlipperFlashCommandHelpMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu): def __init__(self):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
from components.klipper_firmware.menus.klipper_flash_menu import (
KlipperFlashCommandMenu,
)
self.previous_menu: Type[BaseMenu] = (
previous_menu if previous_menu is not None else KlipperFlashCommandMenu
)
def set_options(self) -> None:
pass
def print_menu(self) -> None: def print_menu(self) -> None:
header = " < ? > Help: Flash MCU < ? > " header = " < ? > Help: Flash MCU < ? > "
@@ -89,11 +112,24 @@ class KlipperFlashCommandHelpMenu(BaseMenu):
print(menu, end="") print(menu, end="")
# noinspection DuplicatedCode
class KlipperMcuConnectionHelpMenu(BaseMenu): class KlipperMcuConnectionHelpMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu): def __init__(self):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
from components.klipper_firmware.menus.klipper_flash_menu import (
KlipperSelectMcuConnectionMenu,
)
self.previous_menu: Type[BaseMenu] = (
previous_menu
if previous_menu is not None
else KlipperSelectMcuConnectionMenu
)
def set_options(self) -> None:
pass
def print_menu(self) -> None: def print_menu(self) -> None:
header = " < ? > Help: Flash MCU < ? > " header = " < ? > Help: Flash MCU < ? > "

View File

@@ -9,6 +9,7 @@
import textwrap import textwrap
import time import time
from typing import Type, Optional
from components.klipper_firmware.flash_options import ( from components.klipper_firmware.flash_options import (
FlashOptions, FlashOptions,
@@ -16,7 +17,7 @@ from components.klipper_firmware.flash_options import (
FlashCommand, FlashCommand,
ConnectionType, ConnectionType,
) )
from components.klipper_firmware.flash_utils import ( from components.klipper_firmware.firmware_utils import (
find_usb_device_by_id, find_usb_device_by_id,
find_uart_device, find_uart_device,
find_usb_dfu_device, find_usb_dfu_device,
@@ -33,7 +34,7 @@ from components.klipper_firmware.menus.klipper_flash_help_menu import (
KlipperFlashCommandHelpMenu, KlipperFlashCommandHelpMenu,
KlipperFlashMethodHelpMenu, KlipperFlashMethodHelpMenu,
) )
from core.menus import FooterType from core.menus import FooterType, Option
from core.menus.base_menu import BaseMenu from core.menus.base_menu import BaseMenu
from utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_YELLOW, COLOR_RED from utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_YELLOW, COLOR_RED
@@ -44,20 +45,22 @@ from utils.logger import Logger
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class KlipperFlashMethodMenu(BaseMenu): class KlipperFlashMethodMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu): def __init__(self, previous_menu: Optional[Type[BaseMenu]] = None):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu
self.help_menu = KlipperFlashMethodHelpMenu self.help_menu = KlipperFlashMethodHelpMenu
self.options = {
"1": self.select_regular,
"2": self.select_sdcard,
}
self.input_label_txt = "Select flash method" self.input_label_txt = "Select flash method"
self.footer_type = FooterType.BACK_HELP self.footer_type = FooterType.BACK_HELP
self.flash_options = FlashOptions() self.flash_options = FlashOptions()
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
self.previous_menu: Type[BaseMenu] = previous_menu
def set_options(self) -> None:
self.options = {
"1": Option(self.select_regular, menu=False),
"2": Option(self.select_sdcard, menu=False),
}
def print_menu(self) -> None: def print_menu(self) -> None:
header = " [ MCU Flash Menu ] " header = " [ MCU Flash Menu ] "
subheader = f"{COLOR_YELLOW}ATTENTION:{RESET_FORMAT}" subheader = f"{COLOR_YELLOW}ATTENTION:{RESET_FORMAT}"
@@ -95,7 +98,7 @@ class KlipperFlashMethodMenu(BaseMenu):
def goto_next_menu(self, **kwargs): def goto_next_menu(self, **kwargs):
if find_firmware_file(self.flash_options.flash_method): if find_firmware_file(self.flash_options.flash_method):
KlipperFlashCommandMenu(previous_menu=self).run() KlipperFlashCommandMenu(previous_menu=self.__class__).run()
else: else:
KlipperNoFirmwareErrorMenu().run() KlipperNoFirmwareErrorMenu().run()
@@ -103,21 +106,25 @@ class KlipperFlashMethodMenu(BaseMenu):
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class KlipperFlashCommandMenu(BaseMenu): class KlipperFlashCommandMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu): def __init__(self, previous_menu: Optional[Type[BaseMenu]] = None):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu
self.help_menu = KlipperFlashCommandHelpMenu self.help_menu = KlipperFlashCommandHelpMenu
self.options = {
"1": self.select_flash,
"2": self.select_serialflash,
}
self.default_option = self.select_flash
self.input_label_txt = "Select flash command" self.input_label_txt = "Select flash command"
self.footer_type = FooterType.BACK_HELP self.footer_type = FooterType.BACK_HELP
self.flash_options = FlashOptions() self.flash_options = FlashOptions()
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
self.previous_menu: Type[BaseMenu] = (
previous_menu if previous_menu is not None else KlipperFlashMethodMenu
)
def set_options(self) -> None:
self.options = {
"1": Option(self.select_flash, menu=False),
"2": Option(self.select_serialflash, menu=False),
}
self.default_option = Option(self.select_flash, menu=False)
def print_menu(self) -> None: def print_menu(self) -> None:
menu = textwrap.dedent( menu = textwrap.dedent(
""" """
@@ -140,28 +147,34 @@ class KlipperFlashCommandMenu(BaseMenu):
self.goto_next_menu() self.goto_next_menu()
def goto_next_menu(self, **kwargs): def goto_next_menu(self, **kwargs):
KlipperSelectMcuConnectionMenu(previous_menu=self).run() KlipperSelectMcuConnectionMenu(previous_menu=self.__class__).run()
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class KlipperSelectMcuConnectionMenu(BaseMenu): class KlipperSelectMcuConnectionMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu, standalone: bool = False): def __init__(
self, previous_menu: Optional[Type[BaseMenu]] = None, standalone: bool = False
):
super().__init__() super().__init__()
self.__standalone = standalone self.__standalone = standalone
self.previous_menu: BaseMenu = previous_menu
self.help_menu = KlipperMcuConnectionHelpMenu self.help_menu = KlipperMcuConnectionHelpMenu
self.options = {
"1": self.select_usb,
"2": self.select_dfu,
"3": self.select_usb_dfu,
}
self.input_label_txt = "Select connection type" self.input_label_txt = "Select connection type"
self.footer_type = FooterType.BACK_HELP self.footer_type = FooterType.BACK_HELP
self.flash_options = FlashOptions() self.flash_options = FlashOptions()
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
self.previous_menu: Type[BaseMenu] = (
previous_menu if previous_menu is not None else KlipperFlashCommandMenu
)
def set_options(self) -> None:
self.options = {
"1": Option(method=self.select_usb, menu=False),
"2": Option(method=self.select_dfu, menu=False),
"3": Option(method=self.select_usb_dfu, menu=False),
}
def print_menu(self) -> None: def print_menu(self) -> None:
header = "Make sure that the controller board is connected now!" header = "Make sure that the controller board is connected now!"
color = COLOR_YELLOW color = COLOR_YELLOW
@@ -221,23 +234,32 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
self.goto_next_menu() self.goto_next_menu()
def goto_next_menu(self, **kwargs): def goto_next_menu(self, **kwargs):
KlipperSelectMcuIdMenu(previous_menu=self).run() KlipperSelectMcuIdMenu(previous_menu=self.__class__).run()
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class KlipperSelectMcuIdMenu(BaseMenu): class KlipperSelectMcuIdMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu): def __init__(self, previous_menu: Optional[Type[BaseMenu]] = None):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu
self.flash_options = FlashOptions() self.flash_options = FlashOptions()
self.mcu_list = self.flash_options.mcu_list self.mcu_list = self.flash_options.mcu_list
options = {f"{index}": self.flash_mcu for index in range(len(self.mcu_list))}
self.options = options
self.input_label_txt = "Select MCU to flash" self.input_label_txt = "Select MCU to flash"
self.footer_type = FooterType.BACK_HELP self.footer_type = FooterType.BACK_HELP
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
self.previous_menu: Type[BaseMenu] = (
previous_menu
if previous_menu is not None
else KlipperSelectMcuConnectionMenu
)
def set_options(self) -> None:
self.options = {
f"{i}": Option(self.flash_mcu, False, f"{i}")
for i in range(len(self.mcu_list))
}
def print_menu(self) -> None: def print_menu(self) -> None:
header = "!!! ATTENTION !!!" header = "!!! ATTENTION !!!"
header2 = f"[{COLOR_CYAN}List of available MCUs{RESET_FORMAT}]" header2 = f"[{COLOR_CYAN}List of available MCUs{RESET_FORMAT}]"
@@ -268,24 +290,30 @@ class KlipperSelectMcuIdMenu(BaseMenu):
self.flash_options.selected_mcu = selected_mcu self.flash_options.selected_mcu = selected_mcu
if self.flash_options.flash_method == FlashMethod.SD_CARD: if self.flash_options.flash_method == FlashMethod.SD_CARD:
KlipperSelectSDFlashBoardMenu(previous_menu=self).run() KlipperSelectSDFlashBoardMenu(previous_menu=self.__class__).run()
elif self.flash_options.flash_method == FlashMethod.REGULAR: elif self.flash_options.flash_method == FlashMethod.REGULAR:
KlipperFlashOverviewMenu(previous_menu=self).run() KlipperFlashOverviewMenu(previous_menu=self.__class__).run()
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class KlipperSelectSDFlashBoardMenu(BaseMenu): class KlipperSelectSDFlashBoardMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu): def __init__(self, previous_menu: Optional[Type[BaseMenu]] = None):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu
self.flash_options = FlashOptions() self.flash_options = FlashOptions()
self.available_boards = get_sd_flash_board_list() self.available_boards = get_sd_flash_board_list()
self.input_label_txt = "Select board type" self.input_label_txt = "Select board type"
options = {f"{i}": self.board_select for i in range(len(self.available_boards))} def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
self.options = options self.previous_menu: Type[BaseMenu] = (
previous_menu if previous_menu is not None else KlipperSelectMcuIdMenu
)
def set_options(self) -> None:
self.options = {
f"{i}": Option(self.board_select, False, f"{i}")
for i in range(len(self.available_boards))
}
def print_menu(self) -> None: def print_menu(self) -> None:
if len(self.available_boards) < 1: if len(self.available_boards) < 1:
@@ -331,20 +359,27 @@ class KlipperSelectSDFlashBoardMenu(BaseMenu):
min_count=0, min_count=0,
allow_go_back=True, allow_go_back=True,
) )
KlipperFlashOverviewMenu(previous_menu=self).run() KlipperFlashOverviewMenu(previous_menu=self.__class__).run()
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class KlipperFlashOverviewMenu(BaseMenu): class KlipperFlashOverviewMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu): def __init__(self, previous_menu: Optional[Type[BaseMenu]] = None):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu
self.flash_options = FlashOptions() self.flash_options = FlashOptions()
self.options = {"Y": self.execute_flash, "N": self.abort_process}
self.input_label_txt = "Perform action (default=Y)" self.input_label_txt = "Perform action (default=Y)"
self.default_option = self.execute_flash
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
self.previous_menu: Type[BaseMenu] = previous_menu
def set_options(self) -> None:
self.options = {
"Y": Option(self.execute_flash, menu=False),
"N": Option(self.abort_process, menu=False),
}
self.default_option = Option(self.execute_flash, menu=False)
def print_menu(self) -> None: def print_menu(self) -> None:
header = "!!! ATTENTION !!!" header = "!!! ATTENTION !!!"
@@ -397,7 +432,7 @@ class KlipperFlashOverviewMenu(BaseMenu):
start_flash_process(self.flash_options) start_flash_process(self.flash_options)
Logger.print_info("Returning to MCU Flash Menu in 5 seconds ...") Logger.print_info("Returning to MCU Flash Menu in 5 seconds ...")
time.sleep(5) time.sleep(5)
KlipperFlashMethodMenu(previous_menu=AdvancedMenu()).run() KlipperFlashMethodMenu(previous_menu=AdvancedMenu).run()
def abort_process(self, **kwargs): def abort_process(self, **kwargs):
from core.menus.advanced_menu import AdvancedMenu from core.menus.advanced_menu import AdvancedMenu

View File

@@ -8,30 +8,37 @@
# ======================================================================= # # ======================================================================= #
import textwrap import textwrap
from typing import Type, Optional
from components.klipper_firmware.menus.klipper_build_menu import (
KlipperBuildFirmwareMenu,
)
from components.klipper_firmware.menus.klipper_flash_menu import ( from components.klipper_firmware.menus.klipper_flash_menu import (
KlipperFlashMethodMenu, KlipperFlashMethodMenu,
KlipperSelectMcuConnectionMenu, KlipperSelectMcuConnectionMenu,
) )
from core.menus import Option
from core.menus.base_menu import BaseMenu from core.menus.base_menu import BaseMenu
from utils.constants import COLOR_YELLOW, RESET_FORMAT from utils.constants import COLOR_YELLOW, RESET_FORMAT
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
class AdvancedMenu(BaseMenu): class AdvancedMenu(BaseMenu):
def __init__(self): def __init__(self, previous_menu: Optional[Type[BaseMenu]] = None):
super().__init__() super().__init__()
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
from core.menus.main_menu import MainMenu from core.menus.main_menu import MainMenu
self.previous_menu: BaseMenu = MainMenu() self.previous_menu: Type[BaseMenu] = (
previous_menu if previous_menu is not None else MainMenu
)
def set_options(self):
self.options = { self.options = {
"1": None, "3": Option(method=self.build, menu=True),
"2": None, "4": Option(method=self.flash, menu=False),
"3": None, "6": Option(method=self.get_id, menu=False),
"4": self.flash,
"5": None,
"6": self.get_id,
} }
def print_menu(self): def print_menu(self):
@@ -56,8 +63,14 @@ class AdvancedMenu(BaseMenu):
)[1:] )[1:]
print(menu, end="") print(menu, end="")
def build(self, **kwargs):
KlipperBuildFirmwareMenu(previous_menu=self.__class__).run()
def flash(self, **kwargs): def flash(self, **kwargs):
KlipperFlashMethodMenu(previous_menu=self).run() KlipperFlashMethodMenu(previous_menu=self.__class__).run()
def get_id(self, **kwargs): def get_id(self, **kwargs):
KlipperSelectMcuConnectionMenu(previous_menu=self, standalone=True).run() KlipperSelectMcuConnectionMenu(
previous_menu=self.__class__,
standalone=True,
).run()

View File

@@ -190,7 +190,8 @@ def update_system_package_lists(silent: bool, rls_info_change=False) -> None:
Logger.print_ok("System package list update successful!") Logger.print_ok("System package list update successful!")
except CalledProcessError as e: except CalledProcessError as e:
kill(f"Error updating system package list:\n{e.stderr.decode()}") Logger.print_error(f"Error updating system package list:\n{e.stderr.decode()}")
raise
def check_package_install(packages: List[str]) -> List[str]: def check_package_install(packages: List[str]) -> List[str]:
@@ -210,8 +211,6 @@ def check_package_install(packages: List[str]) -> List[str]:
) )
if "installed" not in result.stdout.strip("'").split(): if "installed" not in result.stdout.strip("'").split():
not_installed.append(package) not_installed.append(package)
else:
Logger.print_ok(f"{package} already installed.")
return not_installed return not_installed
@@ -230,7 +229,8 @@ def install_system_packages(packages: List[str]) -> None:
Logger.print_ok("Packages installed successfully.") Logger.print_ok("Packages installed successfully.")
except CalledProcessError as e: except CalledProcessError as e:
kill(f"Error installing packages:\n{e.stderr.decode()}") Logger.print_error(f"Error installing packages:\n{e.stderr.decode()}")
raise
def mask_system_service(service_name: str) -> None: def mask_system_service(service_name: str) -> None: