mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-23 14:44:13 -06:00
Fix USBPrinterOutputDevice to work with the Print Monitor
CURA-1036
This commit is contained in:
parent
c9b2a1d938
commit
6800991fa1
2 changed files with 43 additions and 107 deletions
|
@ -1,72 +0,0 @@
|
||||||
// Copyright (c) 2015 Ultimaker B.V.
|
|
||||||
// Cura is released under the terms of the AGPLv3 or higher.
|
|
||||||
|
|
||||||
import QtQuick 2.1
|
|
||||||
import QtQuick.Controls 1.1
|
|
||||||
import QtQuick.Layouts 1.1
|
|
||||||
import QtQuick.Window 2.1
|
|
||||||
|
|
||||||
import UM 1.1 as UM
|
|
||||||
|
|
||||||
UM.Dialog
|
|
||||||
{
|
|
||||||
width: 500 * Screen.devicePixelRatio;
|
|
||||||
height: 100 * Screen.devicePixelRatio;
|
|
||||||
modality: Qt.NonModal
|
|
||||||
|
|
||||||
title: catalog.i18nc("@title:window", "Print via USB")
|
|
||||||
|
|
||||||
Column
|
|
||||||
{
|
|
||||||
anchors.fill: parent;
|
|
||||||
Row
|
|
||||||
{
|
|
||||||
spacing: UM.Theme.getSize("default_margin").width;
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
//: USB Printing dialog label, %1 is head temperature
|
|
||||||
text: catalog.i18nc("@label","Extruder Temperature %1").arg(manager.hotendTemperatures[0])
|
|
||||||
}
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
//: USB Printing dialog label, %1 is bed temperature
|
|
||||||
text: catalog.i18nc("@label","Bed Temperature %1").arg(manager.bedTemperature)
|
|
||||||
}
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
text: "" + manager.error
|
|
||||||
}
|
|
||||||
|
|
||||||
UM.I18nCatalog{id: catalog; name:"cura"}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgressBar
|
|
||||||
{
|
|
||||||
id: prog;
|
|
||||||
anchors.left: parent.left;
|
|
||||||
anchors.right: parent.right;
|
|
||||||
|
|
||||||
minimumValue: 0;
|
|
||||||
maximumValue: 100;
|
|
||||||
value: manager.progress
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rightButtons: [
|
|
||||||
Button
|
|
||||||
{
|
|
||||||
//: USB Printing dialog start print button
|
|
||||||
text: catalog.i18nc("@action:button","Print");
|
|
||||||
onClicked: { manager.startPrint() }
|
|
||||||
enabled: manager.progress == 0 ? true : false
|
|
||||||
},
|
|
||||||
Button
|
|
||||||
{
|
|
||||||
//: USB Printing dialog cancel print button
|
|
||||||
text: catalog.i18nc("@action:button","Cancel");
|
|
||||||
onClicked: { manager.cancelPrint() }
|
|
||||||
enabled: manager.progress == 0 ? false: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -51,13 +51,14 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
|
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
|
||||||
self._update_firmware_thread.daemon = True
|
self._update_firmware_thread.daemon = True
|
||||||
self.firmwareUpdateComplete.connect(self._onFirmwareUpdateComplete)
|
self.firmwareUpdateComplete.connect(self._onFirmwareUpdateComplete)
|
||||||
|
|
||||||
self._heatup_wait_start_time = time.time()
|
self._heatup_wait_start_time = time.time()
|
||||||
|
|
||||||
## Queue for commands that need to be send. Used when command is sent when a print is active.
|
## Queue for commands that need to be send. Used when command is sent when a print is active.
|
||||||
self._command_queue = queue.Queue()
|
self._command_queue = queue.Queue()
|
||||||
|
|
||||||
self._is_printing = False
|
self._is_printing = False
|
||||||
|
self._is_paused = False
|
||||||
|
|
||||||
## Set when print is started in order to check running time.
|
## Set when print is started in order to check running time.
|
||||||
self._print_start_time = None
|
self._print_start_time = None
|
||||||
|
@ -80,13 +81,15 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
|
|
||||||
# In order to keep the connection alive we request the temperature every so often from a different extruder.
|
# In order to keep the connection alive we request the temperature every so often from a different extruder.
|
||||||
# This index is the extruder we requested data from the last time.
|
# This index is the extruder we requested data from the last time.
|
||||||
self._temperature_requested_extruder_index = 0
|
self._temperature_requested_extruder_index = 0
|
||||||
|
|
||||||
|
self._current_z = 0
|
||||||
|
|
||||||
self._updating_firmware = False
|
self._updating_firmware = False
|
||||||
|
|
||||||
self._firmware_file_name = None
|
self._firmware_file_name = None
|
||||||
|
|
||||||
self._control_view = None
|
self._error_message = None
|
||||||
|
|
||||||
onError = pyqtSignal()
|
onError = pyqtSignal()
|
||||||
|
|
||||||
|
@ -120,10 +123,10 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
def _homeBed(self):
|
def _homeBed(self):
|
||||||
self._sendCommand("G28 Z")
|
self._sendCommand("G28 Z")
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def startPrint(self):
|
def startPrint(self):
|
||||||
self.writeStarted.emit(self)
|
self.writeStarted.emit(self)
|
||||||
gcode_list = getattr( Application.getInstance().getController().getScene(), "gcode_list")
|
gcode_list = getattr( Application.getInstance().getController().getScene(), "gcode_list")
|
||||||
|
self._updateJobState("printing")
|
||||||
self.printGCode(gcode_list)
|
self.printGCode(gcode_list)
|
||||||
|
|
||||||
def _moveHead(self, x, y, z, speed):
|
def _moveHead(self, x, y, z, speed):
|
||||||
|
@ -135,6 +138,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
# \param gcode_list List with gcode (strings).
|
# \param gcode_list List with gcode (strings).
|
||||||
def printGCode(self, gcode_list):
|
def printGCode(self, gcode_list):
|
||||||
if self._progress or self._connection_state != ConnectionState.connected:
|
if self._progress or self._connection_state != ConnectionState.connected:
|
||||||
|
self._error_message = Message(i18n_catalog.i18nc("@info:status", "Printer is busy or not connected. Unable to start a new job."))
|
||||||
|
self._error_message.show()
|
||||||
Logger.log("d", "Printer is busy or not connected, aborting print")
|
Logger.log("d", "Printer is busy or not connected, aborting print")
|
||||||
self.writeError.emit(self)
|
self.writeError.emit(self)
|
||||||
return
|
return
|
||||||
|
@ -344,23 +349,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
self._setErrorState("Unexpected error while writing serial port %s " % e)
|
self._setErrorState("Unexpected error while writing serial port %s " % e)
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def createControlInterface(self):
|
## Send a command to printer.
|
||||||
if self._control_view is None:
|
|
||||||
Logger.log("d", "Creating control interface for printer connection")
|
|
||||||
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("USBPrinting"), "ControlWindow.qml"))
|
|
||||||
component = QQmlComponent(Application.getInstance()._engine, path)
|
|
||||||
self._control_context = QQmlContext(Application.getInstance()._engine.rootContext())
|
|
||||||
self._control_context.setContextProperty("manager", self)
|
|
||||||
self._control_view = component.create(self._control_context)
|
|
||||||
|
|
||||||
## Show control interface.
|
|
||||||
# This will create the view if its not already created.
|
|
||||||
def showControlInterface(self):
|
|
||||||
if self._control_view is None:
|
|
||||||
self.createControlInterface()
|
|
||||||
self._control_view.show()
|
|
||||||
|
|
||||||
## Send a command to printer.
|
|
||||||
# \param cmd string with g-code
|
# \param cmd string with g-code
|
||||||
def sendCommand(self, cmd):
|
def sendCommand(self, cmd):
|
||||||
if self._progress:
|
if self._progress:
|
||||||
|
@ -371,11 +360,12 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
## Set the error state with a message.
|
## Set the error state with a message.
|
||||||
# \param error String with the error message.
|
# \param error String with the error message.
|
||||||
def _setErrorState(self, error):
|
def _setErrorState(self, error):
|
||||||
|
self._updateJobState("error")
|
||||||
self._error_state = error
|
self._error_state = error
|
||||||
self.onError.emit()
|
self.onError.emit()
|
||||||
|
|
||||||
def requestWrite(self, node, file_name = None, filter_by_machine = False):
|
def requestWrite(self, node, file_name = None, filter_by_machine = False):
|
||||||
self.showControlInterface()
|
self.startPrint()
|
||||||
|
|
||||||
def _setEndstopState(self, endstop_key, value):
|
def _setEndstopState(self, endstop_key, value):
|
||||||
if endstop_key == b"x_min":
|
if endstop_key == b"x_min":
|
||||||
|
@ -391,14 +381,14 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
self.endstopStateChanged.emit("z_min", value)
|
self.endstopStateChanged.emit("z_min", value)
|
||||||
self._z_min_endstop_pressed = value
|
self._z_min_endstop_pressed = value
|
||||||
|
|
||||||
## Listen thread function.
|
## Listen thread function.
|
||||||
def _listen(self):
|
def _listen(self):
|
||||||
Logger.log("i", "Printer connection listen thread started for %s" % self._serial_port)
|
Logger.log("i", "Printer connection listen thread started for %s" % self._serial_port)
|
||||||
temperature_request_timeout = time.time()
|
temperature_request_timeout = time.time()
|
||||||
ok_timeout = time.time()
|
ok_timeout = time.time()
|
||||||
while self._connection_state == ConnectionState.connected:
|
while self._connection_state == ConnectionState.connected:
|
||||||
line = self._readline()
|
line = self._readline()
|
||||||
if line is None:
|
if line is None:
|
||||||
break # None is only returned when something went wrong. Stop listening
|
break # None is only returned when something went wrong. Stop listening
|
||||||
|
|
||||||
if time.time() > temperature_request_timeout:
|
if time.time() > temperature_request_timeout:
|
||||||
|
@ -423,7 +413,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
self._setErrorState(line[6:])
|
self._setErrorState(line[6:])
|
||||||
|
|
||||||
elif b" T:" in line or line.startswith(b"T:"): # Temperature message
|
elif b" T:" in line or line.startswith(b"T:"): # Temperature message
|
||||||
try:
|
try:
|
||||||
self._setHotendTemperature(self._temperature_requested_extruder_index, float(re.search(b"T: *([0-9\.]*)", line).group(1)))
|
self._setHotendTemperature(self._temperature_requested_extruder_index, float(re.search(b"T: *([0-9\.]*)", line).group(1)))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -445,6 +435,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
ok_timeout = time.time() + 5
|
ok_timeout = time.time() + 5
|
||||||
if not self._command_queue.empty():
|
if not self._command_queue.empty():
|
||||||
self._sendCommand(self._command_queue.get())
|
self._sendCommand(self._command_queue.get())
|
||||||
|
elif self._is_paused:
|
||||||
|
line = b"" # Force getting temperature as keep alive
|
||||||
else:
|
else:
|
||||||
self._sendNextGcodeLine()
|
self._sendNextGcodeLine()
|
||||||
elif b"resend" in line.lower() or b"rs" in line: # Because a resend can be asked with "resend" and "rs"
|
elif b"resend" in line.lower() or b"rs" in line: # Because a resend can be asked with "resend" and "rs"
|
||||||
|
@ -454,13 +446,14 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
if b"rs" in line:
|
if b"rs" in line:
|
||||||
self._gcode_position = int(line.split()[1])
|
self._gcode_position = int(line.split()[1])
|
||||||
|
|
||||||
else: # Request the temperature on comm timeout (every 2 seconds) when we are not printing.)
|
# Request the temperature on comm timeout (every 2 seconds) when we are not printing.)
|
||||||
if line == b"":
|
if line == b"":
|
||||||
if self._num_extruders > 0:
|
if self._num_extruders > 0:
|
||||||
self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._num_extruders
|
self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._num_extruders
|
||||||
self.sendCommand("M105 T%d" % self._temperature_requested_extruder_index)
|
self.sendCommand("M105 T%d" % self._temperature_requested_extruder_index)
|
||||||
else:
|
else:
|
||||||
self.sendCommand("M105")
|
self.sendCommand("M105")
|
||||||
|
|
||||||
Logger.log("i", "Printer connection listen thread stopped for %s" % self._serial_port)
|
Logger.log("i", "Printer connection listen thread stopped for %s" % self._serial_port)
|
||||||
|
|
||||||
## Send next Gcode in the gcode list
|
## Send next Gcode in the gcode list
|
||||||
|
@ -487,10 +480,22 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
checksum = functools.reduce(lambda x,y: x^y, map(ord, "N%d%s" % (self._gcode_position, line)))
|
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))
|
self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum))
|
||||||
self._gcode_position += 1
|
self._gcode_position += 1
|
||||||
self.setProgress((self._gcode_position / len(self._gcode)) * 100)
|
self.setProgress((self._gcode_position / len(self._gcode)) * 100)
|
||||||
self.progressChanged.emit()
|
self.progressChanged.emit()
|
||||||
|
|
||||||
|
## Set the state of the print.
|
||||||
|
# Sent from the print monitor
|
||||||
|
def _setJobState(self, job_state):
|
||||||
|
if job_state == "pause":
|
||||||
|
self._is_paused = True
|
||||||
|
self._updateJobState("paused")
|
||||||
|
elif job_state == "print":
|
||||||
|
self._is_paused = False
|
||||||
|
self._updateJobState("printing")
|
||||||
|
elif job_state == "abort":
|
||||||
|
self.cancelPrint()
|
||||||
|
|
||||||
## Set the progress of the print.
|
## Set the progress of the print.
|
||||||
# It will be normalized (based on max_progress) to range 0 - 100
|
# It will be normalized (based on max_progress) to range 0 - 100
|
||||||
def setProgress(self, progress, max_progress = 100):
|
def setProgress(self, progress, max_progress = 100):
|
||||||
|
@ -498,16 +503,19 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
self.progressChanged.emit()
|
self.progressChanged.emit()
|
||||||
|
|
||||||
## Cancel the current print. Printer connection wil continue to listen.
|
## Cancel the current print. Printer connection wil continue to listen.
|
||||||
@pyqtSlot()
|
|
||||||
def cancelPrint(self):
|
def cancelPrint(self):
|
||||||
self._gcode_position = 0
|
self._gcode_position = 0
|
||||||
self.setProgress(0)
|
self.setProgress(0)
|
||||||
self._gcode = []
|
self._gcode = []
|
||||||
|
|
||||||
# Turn of temperatures
|
# Turn off temperatures, fan and steppers
|
||||||
self._sendCommand("M140 S0")
|
self._sendCommand("M140 S0")
|
||||||
self._sendCommand("M104 S0")
|
self._sendCommand("M104 S0")
|
||||||
|
self._sendCommand("M107")
|
||||||
|
self._sendCommand("M84")
|
||||||
self._is_printing = False
|
self._is_printing = False
|
||||||
|
self._is_paused = False
|
||||||
|
self._updateJobState("ready")
|
||||||
|
|
||||||
## Check if the process did not encounter an error yet.
|
## Check if the process did not encounter an error yet.
|
||||||
def hasError(self):
|
def hasError(self):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue