|
@@ -11,25 +11,20 @@ import functools
|
|
|
import os.path
|
|
|
|
|
|
from UM.Application import Application
|
|
|
-from UM.Signal import Signal, SignalEmitter
|
|
|
from UM.Logger import Logger
|
|
|
-from UM.OutputDevice.OutputDevice import OutputDevice
|
|
|
from UM.PluginRegistry import PluginRegistry
|
|
|
+from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
|
|
|
|
|
|
-from PyQt5.QtQuick import QQuickView
|
|
|
from PyQt5.QtQml import QQmlComponent, QQmlContext
|
|
|
-from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal, Qt
|
|
|
+from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal
|
|
|
|
|
|
from UM.i18n import i18nCatalog
|
|
|
catalog = i18nCatalog("cura")
|
|
|
|
|
|
|
|
|
-class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
- def __init__(self, serial_port, parent = None):
|
|
|
- QObject.__init__(self, parent)
|
|
|
- OutputDevice.__init__(self, serial_port)
|
|
|
- SignalEmitter.__init__(self)
|
|
|
- #super().__init__(serial_port)
|
|
|
+class USBPrinterOutputDevice(PrinterOutputDevice):
|
|
|
+ def __init__(self, serial_port):
|
|
|
+ super().__init__(serial_port)
|
|
|
self.setName(catalog.i18nc("@item:inmenu", "USB printing"))
|
|
|
self.setShortDescription(catalog.i18nc("@action:button", "Print with USB"))
|
|
|
self.setDescription(catalog.i18nc("@info:tooltip", "Print with USB"))
|
|
@@ -46,18 +41,10 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
self._end_stop_thread.daemon = True
|
|
|
self._poll_endstop = -1
|
|
|
|
|
|
- # Printer is connected
|
|
|
- self._is_connected = False
|
|
|
-
|
|
|
- # Printer is in the process of connecting
|
|
|
- self._is_connecting = False
|
|
|
-
|
|
|
# The baud checking is done by sending a number of m105 commands to the printer and waiting for a readable
|
|
|
# response. If the baudrate is correct, this should make sense, else we get giberish.
|
|
|
self._required_responses_auto_baud = 3
|
|
|
|
|
|
- self._progress = 0
|
|
|
-
|
|
|
self._listen_thread = threading.Thread(target=self._listen)
|
|
|
self._listen_thread.daemon = True
|
|
|
|
|
@@ -119,40 +106,26 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
self._control_view = None
|
|
|
|
|
|
onError = pyqtSignal()
|
|
|
- progressChanged = pyqtSignal()
|
|
|
- extruderTemperatureChanged = pyqtSignal()
|
|
|
- bedTemperatureChanged = pyqtSignal()
|
|
|
+
|
|
|
firmwareUpdateComplete = pyqtSignal()
|
|
|
|
|
|
endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"])
|
|
|
|
|
|
- @pyqtProperty(float, notify = progressChanged)
|
|
|
- def progress(self):
|
|
|
- return self._progress
|
|
|
+ def _setTargetBedTemperature(self, temperature):
|
|
|
+ Logger.log("d", "Setting bed temperature to %s", temperature)
|
|
|
+ self._sendCommand("M140 S%s" % temperature)
|
|
|
|
|
|
- @pyqtProperty(float, notify = extruderTemperatureChanged)
|
|
|
- def extruderTemperature(self):
|
|
|
- return self._extruder_temperatures[0]
|
|
|
+ def _setHeadPosition(self, x, y , z, speed):
|
|
|
+ self._sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed))
|
|
|
|
|
|
- @pyqtProperty(float, notify = bedTemperatureChanged)
|
|
|
- def bedTemperature(self):
|
|
|
- return self._bed_temperature
|
|
|
+ def _setHeadX(self, x, speed):
|
|
|
+ self._sendCommand("G0 X%s F%s" % (x, speed))
|
|
|
|
|
|
- @pyqtProperty(str, notify = onError)
|
|
|
- def error(self):
|
|
|
- return self._error_state
|
|
|
+ def _setHeadY(self, y, speed):
|
|
|
+ self._sendCommand("G0 Y%s F%s" % (y, speed))
|
|
|
|
|
|
- # TODO: Might need to add check that extruders can not be changed when it started printing or loading these settings from settings object
|
|
|
- def setNumExtuders(self, num):
|
|
|
- self._extruder_count = num
|
|
|
- self._extruder_temperatures = [0] * self._extruder_count
|
|
|
- self._target_extruder_temperatures = [0] * self._extruder_count
|
|
|
-
|
|
|
- ## Is the printer actively printing
|
|
|
- def isPrinting(self):
|
|
|
- if not self._is_connected or self._serial is None:
|
|
|
- return False
|
|
|
- return self._is_printing
|
|
|
+ def _setHeadZ(self, z, speed):
|
|
|
+ self._sendCommand("G0 Y%s F%s" % (z, speed))
|
|
|
|
|
|
@pyqtSlot()
|
|
|
def startPrint(self):
|
|
@@ -163,7 +136,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
## Start a print based on a g-code.
|
|
|
# \param gcode_list List with gcode (strings).
|
|
|
def printGCode(self, gcode_list):
|
|
|
- if self.isPrinting() or not self._is_connected:
|
|
|
+ if not self._progress or self._connection_state != ConnectionState.CONNECTED:
|
|
|
Logger.log("d", "Printer is busy or not connected, aborting print")
|
|
|
self.writeError.emit(self)
|
|
|
return
|
|
@@ -198,7 +171,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
def _updateFirmware(self):
|
|
|
self.setProgress(0, 100)
|
|
|
|
|
|
- if self._is_connecting or self._is_connected:
|
|
|
+ if self._connection_state != ConnectionState.CLOSED:
|
|
|
self.close()
|
|
|
hex_file = intelHex.readHex(self._firmware_file_name)
|
|
|
|
|
@@ -253,14 +226,14 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
self._poll_endstop = False
|
|
|
|
|
|
def _pollEndStop(self):
|
|
|
- while self._is_connected and self._poll_endstop:
|
|
|
+ while self._connection_state == ConnectionState.CONNECTED and self._poll_endstop:
|
|
|
self.sendCommand("M119")
|
|
|
time.sleep(0.5)
|
|
|
|
|
|
## Private connect function run by thread. Can be started by calling connect.
|
|
|
def _connect(self):
|
|
|
Logger.log("d", "Attempting to connect to %s", self._serial_port)
|
|
|
- self._is_connecting = True
|
|
|
+ self.setConnectionState(ConnectionState.CONNECTING)
|
|
|
programmer = stk500v2.Stk500v2()
|
|
|
try:
|
|
|
programmer.connect(self._serial_port) # Connect with the serial, if this succeeds, it's an arduino based usb device.
|
|
@@ -277,7 +250,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
try:
|
|
|
self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout = 3, writeTimeout = 10000)
|
|
|
except serial.SerialException:
|
|
|
- #Logger.log("i", "Could not open port %s" % self._serial_port)
|
|
|
+ Logger.log("d", "Could not open port %s" % self._serial_port)
|
|
|
continue
|
|
|
else:
|
|
|
if not self.setBaudRate(baud_rate):
|
|
@@ -291,15 +264,16 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
while timeout_time > time.time():
|
|
|
line = self._readline()
|
|
|
if line is None:
|
|
|
- self.setIsConnected(False) # Something went wrong with reading, could be that close was called.
|
|
|
+ # Something went wrong with reading, could be that close was called.
|
|
|
+ self.setConnectionState(ConnectionState.CLOSED)
|
|
|
return
|
|
|
|
|
|
if b"T:" in line:
|
|
|
self._serial.timeout = 0.5
|
|
|
sucesfull_responses += 1
|
|
|
if sucesfull_responses >= self._required_responses_auto_baud:
|
|
|
- self._serial.timeout = 2 #Reset serial timeout
|
|
|
- self.setIsConnected(True)
|
|
|
+ self._serial.timeout = 2 # Reset serial timeout
|
|
|
+ self.setConnectionState(ConnectionState.CONNECTED)
|
|
|
Logger.log("i", "Established printer connection on port %s" % self._serial_port)
|
|
|
return
|
|
|
|
|
@@ -307,7 +281,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
|
|
|
Logger.log("e", "Baud rate detection for %s failed", self._serial_port)
|
|
|
self.close() # Unable to connect, wrap up.
|
|
|
- self.setIsConnected(False)
|
|
|
+ self.setConnectionState(ConnectionState.CLOSED)
|
|
|
|
|
|
## Set the baud rate of the serial. This can cause exceptions, but we simply want to ignore those.
|
|
|
def setBaudRate(self, baud_rate):
|
|
@@ -317,21 +291,9 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
except Exception as e:
|
|
|
return False
|
|
|
|
|
|
- def setIsConnected(self, state):
|
|
|
- self._is_connecting = False
|
|
|
- if self._is_connected != state:
|
|
|
- self._is_connected = state
|
|
|
- self.connectionStateChanged.emit(self._serial_port)
|
|
|
- if self._is_connected:
|
|
|
- self._listen_thread.start() #Start listening
|
|
|
- else:
|
|
|
- Logger.log("w", "Printer connection state was not changed")
|
|
|
-
|
|
|
- connectionStateChanged = Signal()
|
|
|
-
|
|
|
## Close the printer connection
|
|
|
def close(self):
|
|
|
- Logger.log("d", "Closing the printer connection.")
|
|
|
+ Logger.log("d", "Closing the USB printer connection.")
|
|
|
if self._connect_thread.isAlive():
|
|
|
try:
|
|
|
self._connect_thread.join()
|
|
@@ -339,10 +301,10 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
Logger.log("d", "PrinterConnection.close: %s (expected)", e)
|
|
|
pass # This should work, but it does fail sometimes for some reason
|
|
|
|
|
|
- self._connect_thread = threading.Thread(target=self._connect)
|
|
|
+ self._connect_thread = threading.Thread(target = self._connect)
|
|
|
self._connect_thread.daemon = True
|
|
|
|
|
|
- self.setIsConnected(False)
|
|
|
+ self.setConnectionState(ConnectionState.CLOSED)
|
|
|
if self._serial is not None:
|
|
|
try:
|
|
|
self._listen_thread.join()
|
|
@@ -350,49 +312,10 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
pass
|
|
|
self._serial.close()
|
|
|
|
|
|
- self._listen_thread = threading.Thread(target=self._listen)
|
|
|
+ self._listen_thread = threading.Thread(target = self._listen)
|
|
|
self._listen_thread.daemon = True
|
|
|
self._serial = None
|
|
|
|
|
|
- def isConnected(self):
|
|
|
- return self._is_connected
|
|
|
-
|
|
|
- @pyqtSlot(int)
|
|
|
- def heatupNozzle(self, temperature):
|
|
|
- Logger.log("d", "Setting nozzle temperature to %s", temperature)
|
|
|
- self._sendCommand("M104 S%s" % temperature)
|
|
|
-
|
|
|
- @pyqtSlot(int)
|
|
|
- def heatupBed(self, temperature):
|
|
|
- Logger.log("d", "Setting bed temperature to %s", temperature)
|
|
|
- self._sendCommand("M140 S%s" % temperature)
|
|
|
-
|
|
|
- @pyqtSlot()
|
|
|
- def setMoveToRelative(self):
|
|
|
- self._sendCommand("G91")
|
|
|
-
|
|
|
- @pyqtSlot()
|
|
|
- def setMoveToAbsolute(self):
|
|
|
- self._sendCommand("G90")
|
|
|
-
|
|
|
- @pyqtSlot("long", "long","long")
|
|
|
- def moveHead(self, x, y, z):
|
|
|
- Logger.log("d","Moving head to %s, %s , %s", x, y, z)
|
|
|
- self._sendCommand("G0 X%s Y%s Z%s F3000" % (x, y, z))
|
|
|
-
|
|
|
- @pyqtSlot("long", "long","long")
|
|
|
- def moveHeadRelative(self, x, y, z):
|
|
|
- self.setMoveToRelative()
|
|
|
- self.moveHead(x,y,z)
|
|
|
- self.setMoveToAbsolute()
|
|
|
-
|
|
|
- @pyqtSlot()
|
|
|
- def homeHead(self):
|
|
|
- self._sendCommand("G28")
|
|
|
-
|
|
|
- @pyqtSlot()
|
|
|
- def homeBed(self):
|
|
|
- self._sendCommand("G28 Z")
|
|
|
|
|
|
## Directly send the command, withouth checking connection state (eg; printing).
|
|
|
# \param cmd string with g-code
|
|
@@ -433,10 +356,6 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
self._setErrorState("Unexpected error while writing serial port %s " % e)
|
|
|
self.close()
|
|
|
|
|
|
- ## Ensure that close gets called when object is destroyed
|
|
|
- def __del__(self):
|
|
|
- self.close()
|
|
|
-
|
|
|
def createControlInterface(self):
|
|
|
if self._control_view is None:
|
|
|
Logger.log("d", "Creating control interface for printer connection")
|
|
@@ -456,7 +375,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
## Send a command to printer.
|
|
|
# \param cmd string with g-code
|
|
|
def sendCommand(self, cmd):
|
|
|
- if self.isPrinting():
|
|
|
+ if not self._progress:
|
|
|
self._command_queue.put(cmd)
|
|
|
elif self.isConnected():
|
|
|
self._sendCommand(cmd)
|
|
@@ -467,24 +386,6 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
self._error_state = error
|
|
|
self.onError.emit()
|
|
|
|
|
|
- ## Private function to set the temperature of an extruder
|
|
|
- # \param index index of the extruder
|
|
|
- # \param temperature received temperature
|
|
|
- def _setExtruderTemperature(self, index, temperature):
|
|
|
- try:
|
|
|
- self._extruder_temperatures[index] = temperature
|
|
|
- self.extruderTemperatureChanged.emit()
|
|
|
- except Exception as e:
|
|
|
- Logger.log("d", "PrinterConnection._setExtruderTemperature: ", e)
|
|
|
- pass
|
|
|
-
|
|
|
- ## Private function to set the temperature of the bed.
|
|
|
- # As all printers (as of time of writing) only support a single heated bed,
|
|
|
- # these are not indexed as with extruders.
|
|
|
- def _setBedTemperature(self, temperature):
|
|
|
- self._bed_temperature = temperature
|
|
|
- self.bedTemperatureChanged.emit()
|
|
|
-
|
|
|
def requestWrite(self, node, file_name = None, filter_by_machine = False):
|
|
|
self.showControlInterface()
|
|
|
|
|
@@ -507,7 +408,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
|
|
|
Logger.log("i", "Printer connection listen thread started for %s" % self._serial_port)
|
|
|
temperature_request_timeout = time.time()
|
|
|
ok_timeout = time.time()
|
|
|
- while self._is_connected:
|
|
|
+ while self._connected:
|
|
|
line = self._readline()
|
|
|
|
|
|
if line is None:
|