feat: implement firmware build
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
This commit is contained in:
169
kiauh/components/klipper_firmware/firmware_utils.py
Normal file
169
kiauh/components/klipper_firmware/firmware_utils.py
Normal 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
|
||||||
111
kiauh/components/klipper_firmware/menus/klipper_build_menu.py
Normal file
111
kiauh/components/klipper_firmware/menus/klipper_build_menu.py
Normal 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()
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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 < ? > "
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user