Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle the new re-print LCD menu item in FW 3.14 #877

Merged
merged 1 commit into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* Periodically send a keepalive gcode to keep the printer in PrusaLink mode
* Support the set ready and cancel ready LCD menu toggle
* Add gcodes that flag the state of a usb print for the printer statistics to get saved
* Handle the new re-print LCD menu item

0.7.1rc1 (2023-08-10)
* Fixed HTTP response status on HEAD request for non-existing files
Expand Down
25 changes: 25 additions & 0 deletions prusa/link/printer_adapter/command_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from ..serial.helpers import enqueue_instruction, enqueue_list_from_str
from ..util import file_is_on_sd, round_to_five
from .command import Command, CommandFailed, FileNotFound, NotStateToPrint
from .model import Model
from .state_manager import StateChange
from .structures.model_classes import JobState
from .structures.regular_expressions import (
Expand Down Expand Up @@ -555,3 +556,27 @@ def _run_command(self):
default_source=self.source))
self.state_manager.idle()
self.state_manager.stop_expecting_change()


class RePrint(StartPrint):
"""Class for starting the last job again"""
command_name = "re-print"

def __init__(self, **kwargs):
# Need to get the model sooner than it's available in self
model = Model.get_instance()
path = model.job.last_job_path
if path is None:
path = ""
super().__init__(path=path, **kwargs)

def _run_command(self):
"""Re-prints the last job, makes a noise and sends an LCD message
if that fails"""
try:
super()._run_command()
except CommandFailed as exception:
# Not an ideal way to do this, but less time-consuming
enqueue_instruction(self.serial_queue, "M300 P200 S600")
enqueue_instruction(self.serial_queue, "M117 \x7ECannot re-print")
raise exception
11 changes: 10 additions & 1 deletion prusa/link/printer_adapter/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ def __init__(self,
printing_file_byte=None,
job_state=JobState.IDLE,
job_id=None,
job_id_offset=0)
job_id_offset=0,
last_job_path=None)
self.data = self.model.job

self.job_id_updated_signal.send(self,
Expand Down Expand Up @@ -100,6 +101,7 @@ def job_started(self, command_id=None):
self.model.print_stats.has_inbuilt_stats
self.change_state(JobState.IN_PROGRESS)
self.write()
self.update_last_job_path()
log.debug("New job started, id = %s", self.data.job_id)
self.job_id_updated_signal.send(self,
job_id=self.data.get_job_id_for_api())
Expand Down Expand Up @@ -192,8 +194,15 @@ def set_file_path(self, path, path_incomplete, prepend_sd_storage):
self.data.selected_file_size = file_obj.attrs["size"]
self.model.job.from_sd = path.startswith(
os.path.join("/", SD_STORAGE_NAME))
self.update_last_job_path()
self.job_info_updated()

def update_last_job_path(self):
"""Updates the last job path to be used for the re-print menu item"""
if self.data.job_state != JobState.IN_PROGRESS:
return
self.data.last_job_path = self.data.selected_file_path

def get_job_info_data(self, for_connect=False):
"""Compiles the job info data into a dict"""
if for_connect:
Expand Down
12 changes: 12 additions & 0 deletions prusa/link/printer_adapter/prusa_link.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
JobInfo,
LoadFilament,
PausePrint,
RePrint,
ResetPrinter,
ResumePrint,
SetReady,
Expand Down Expand Up @@ -87,6 +88,7 @@
PAUSE_PRINT_REGEX,
PRINTER_BOOT_REGEX,
READY_REGEX,
REPRINT_REGEX,
RESUME_PRINT_REGEX,
TM_CAL_END_REGEX,
TM_CAL_START_REGEX,
Expand Down Expand Up @@ -196,6 +198,8 @@ def __init__(self, cfg: Config, settings: Settings) -> None:
READY_REGEX, lambda sender, match: self.fw_set_ready())
self.serial_parser.add_decoupled_handler(
NOT_READY_REGEX, lambda sender, match: self.fw_cancel_ready())
self.serial_parser.add_decoupled_handler(
REPRINT_REGEX, lambda sender, match: self.fw_reprint())

# Init components first, so they all exist for signal binding stuff
# TODO: does not need printer, the transfer object should be
Expand Down Expand Up @@ -362,6 +366,8 @@ def debug_shell(self) -> None:
result: Any = ""
if command == "pause":
result = self.command_queue.do_command(PausePrint())
elif command == "reprint":
result = self.command_queue.do_command(RePrint())
elif command == "resume":
result = self.command_queue.do_command(ResumePrint())
elif command == "stop":
Expand Down Expand Up @@ -600,6 +606,12 @@ def fw_cancel_ready(self) -> None:
command = CancelReady(source=Source.USER)
self.command_queue.enqueue_command(command)

def fw_reprint(self) -> None:
"""Prints the last job again, activated from the printer LCD screen"""
prctl_name()
command = RePrint(source=Source.USER)
self.command_queue.enqueue_command(command)

# --- Signal handlers ---
def layer_trigger(self, _):
"""Passes the call to trigger to the camera controller"""
Expand Down
2 changes: 2 additions & 0 deletions prusa/link/printer_adapter/structures/module_data_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class JobData(BaseModel):
from_sd: Optional[bool]
inbuilt_reporting: Optional[bool]

last_job_path: Optional[str]

job_state: JobState

def get_job_id_for_api(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
CANCEL_REGEX = re.compile("^// action:cancel$")
READY_REGEX = re.compile("^// action:ready$")
NOT_READY_REGEX = re.compile("^// action:not_ready$")
REPRINT_REGEX = re.compile("^// action:reprint$")
# This girthy regexp tries to capture all error messages requiring printer
# reset using M999 or manual button, with connect, only manual reset shall
# be accepted
Expand Down
2 changes: 2 additions & 0 deletions prusa/link/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ def get_gcode(line):

def file_is_on_sd(path_parts):
"""Checks if the file path starts wit the sd cards' storage name"""
if len(path_parts) < 2:
return False
return path_parts[1] == SD_STORAGE_NAME


Expand Down