mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 06:57:28 -06:00
Starting a print with USB printer now works with reworked printeroutputmodel
CL-541
This commit is contained in:
parent
d3b9ac0d45
commit
d3d9a6e1bb
1 changed files with 116 additions and 10 deletions
|
@ -4,17 +4,21 @@
|
|||
from UM.Logger import Logger
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Application import Application
|
||||
from UM.Qt.Duration import DurationFormat
|
||||
|
||||
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
|
||||
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
|
||||
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
|
||||
|
||||
from .AutoDetectBaudJob import AutoDetectBaudJob
|
||||
|
||||
from serial import Serial, SerialException
|
||||
from threading import Thread
|
||||
from time import time
|
||||
from queue import Queue
|
||||
|
||||
import re
|
||||
import functools # Used for reduce
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
|
@ -32,9 +36,15 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
|
||||
self._timeout = 3
|
||||
|
||||
# List of gcode lines to be printed
|
||||
self._gcode = []
|
||||
self._gcode_position = 0
|
||||
|
||||
self._use_auto_detect = True
|
||||
|
||||
self._baud_rate = baud_rate
|
||||
|
||||
|
||||
self._all_baud_rates = [115200, 250000, 230400, 57600, 38400, 19200, 9600]
|
||||
|
||||
# Instead of using a timer, we really need the update to be as a thread, as reading from serial can block.
|
||||
|
@ -42,6 +52,48 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
|
||||
self._last_temperature_request = None
|
||||
|
||||
self._is_printing = False # A print is being sent.
|
||||
|
||||
## Set when print is started in order to check running time.
|
||||
self._print_start_time = None
|
||||
self._print_estimated_time = None
|
||||
|
||||
# Queue for commands that need to be send. Used when command is sent when a print is active.
|
||||
self._command_queue = Queue()
|
||||
|
||||
## Request the current scene to be sent to a USB-connected printer.
|
||||
#
|
||||
# \param nodes A collection of scene nodes to send. This is ignored.
|
||||
# \param file_name \type{string} A suggestion for a file name to write.
|
||||
# \param filter_by_machine Whether to filter MIME types by machine. This
|
||||
# is ignored.
|
||||
# \param kwargs Keyword arguments.
|
||||
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None, **kwargs):
|
||||
gcode_list = getattr(Application.getInstance().getController().getScene(), "gcode_list")
|
||||
self._printGCode(gcode_list)
|
||||
|
||||
## Start a print based on a g-code.
|
||||
# \param gcode_list List with gcode (strings).
|
||||
def _printGCode(self, gcode_list):
|
||||
self._gcode.clear()
|
||||
|
||||
for layer in gcode_list:
|
||||
self._gcode.extend(layer.split("\n"))
|
||||
|
||||
# Reset line number. If this is not done, first line is sometimes ignored
|
||||
self._gcode.insert(0, "M110")
|
||||
self._gcode_position = 0
|
||||
self._is_printing = True
|
||||
self._print_start_time = time()
|
||||
|
||||
self._print_estimated_time = int(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.Seconds))
|
||||
|
||||
for i in range(0, 4): # Push first 4 entries before accepting other inputs
|
||||
self._sendNextGcodeLine()
|
||||
|
||||
self.writeFinished.emit(self)
|
||||
|
||||
|
||||
def _autoDetectFinished(self, job):
|
||||
result = job.getResult()
|
||||
if result is not None:
|
||||
|
@ -76,18 +128,19 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
self._update_thread.start()
|
||||
|
||||
def sendCommand(self, command):
|
||||
if self._connection_state == ConnectionState.connected:
|
||||
if self._is_printing:
|
||||
self._command_queue.put(command)
|
||||
elif self._connection_state == ConnectionState.connected:
|
||||
self._sendCommand(command)
|
||||
|
||||
def _sendCommand(self, command):
|
||||
if self._serial is None:
|
||||
return
|
||||
|
||||
if type(command == str):q
|
||||
if type(command == str):
|
||||
command = (command + "\n").encode()
|
||||
if not command.endswith(b"\n"):
|
||||
command += b"\n"
|
||||
|
||||
self._serial.write(b"\n")
|
||||
self._serial.write(command)
|
||||
|
||||
|
@ -103,12 +156,65 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
extruder_temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line)
|
||||
# Update all temperature values
|
||||
for match, extruder in zip(extruder_temperature_matches, self._printers[0].extruders):
|
||||
extruder.updateHotendTemperature(float(match[1]))
|
||||
extruder.updateTargetHotendTemperature(float(match[2]))
|
||||
if match[1]:
|
||||
extruder.updateHotendTemperature(float(match[1]))
|
||||
if match[2]:
|
||||
extruder.updateTargetHotendTemperature(float(match[2]))
|
||||
|
||||
bed_temperature_matches = re.findall(b"B: ?([\d\.]+) ?\/?([\d\.]+)?", line)
|
||||
match = bed_temperature_matches[0]
|
||||
if match[0]:
|
||||
self._printers[0].updateBedTemperature(float(match[0]))
|
||||
if match[1]:
|
||||
self._printers[0].updateTargetBedTemperature(float(match[1]))
|
||||
if bed_temperature_matches:
|
||||
match = bed_temperature_matches[0]
|
||||
if match[0]:
|
||||
self._printers[0].updateBedTemperature(float(match[0]))
|
||||
if match[1]:
|
||||
self._printers[0].updateTargetBedTemperature(float(match[1]))
|
||||
|
||||
if self._is_printing:
|
||||
if b"ok" in line:
|
||||
if not self._command_queue.empty():
|
||||
self._sendCommand(self._command_queue.get())
|
||||
else:
|
||||
self._sendNextGcodeLine()
|
||||
elif b"resend" in line.lower() or b"rs" in line:
|
||||
# A resend can be requested either by Resend, resend or rs.
|
||||
try:
|
||||
self._gcode_position = int(line.replace(b"N:", b" ").replace(b"N", b" ").replace(b":", b" ").split()[-1])
|
||||
except:
|
||||
if b"rs" in line:
|
||||
# In some cases of the RS command it needs to be handled differently.
|
||||
self._gcode_position = int(line.split()[1])
|
||||
|
||||
def _sendNextGcodeLine(self):
|
||||
if self._gcode_position >= len(self._gcode):
|
||||
return
|
||||
line = self._gcode[self._gcode_position]
|
||||
|
||||
if ";" in line:
|
||||
line = line[:line.find(";")]
|
||||
|
||||
line = line.strip()
|
||||
|
||||
# Don't send empty lines. But we do have to send something, so send M105 instead.
|
||||
# Don't send the M0 or M1 to the machine, as M0 and M1 are handled as an LCD menu pause.
|
||||
if line == "" or line == "M0" or line == "M1":
|
||||
line = "M105"
|
||||
|
||||
checksum = functools.reduce(lambda x, y: x ^ y, map(ord, "N%d%s" % (self._gcode_position, line)))
|
||||
|
||||
self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum))
|
||||
|
||||
progress = (self._gcode_position / len(self._gcode))
|
||||
|
||||
elapsed_time = int(time() - self._print_start_time)
|
||||
print_job = self._printers[0].activePrintJob
|
||||
if print_job is None:
|
||||
print_job = PrintJobOutputModel(output_controller = None)
|
||||
self._printers[0].updateActivePrintJob(print_job)
|
||||
|
||||
print_job.updateTimeElapsed(elapsed_time)
|
||||
estimated_time = self._print_estimated_time
|
||||
if progress > .1:
|
||||
estimated_time = self._print_estimated_time * (1 - progress) + elapsed_time
|
||||
print_job.updateTimeTotal(estimated_time)
|
||||
|
||||
self._gcode_position += 1
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue