From 0cd1031ec7f51356188672d657a02028a1c7afa0 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 13 Apr 2016 15:15:37 +0200 Subject: [PATCH] Changed USB printing to reflect changes in output device API CURA-1339 --- plugins/USBPrinting/USBPrinterManager.py | 6 +- plugins/USBPrinting/USBPrinterOutputDevice.py | 165 ++++-------------- 2 files changed, 36 insertions(+), 135 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterManager.py b/plugins/USBPrinting/USBPrinterManager.py index 1188fce28f..1c2c96484f 100644 --- a/plugins/USBPrinting/USBPrinterManager.py +++ b/plugins/USBPrinting/USBPrinterManager.py @@ -8,6 +8,7 @@ from UM.Resources import Resources from UM.Logger import Logger from UM.PluginRegistry import PluginRegistry from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin +from cura.PrinterOutputDevice import ConnectionState from UM.Qt.ListModel import ListModel from UM.Message import Message @@ -20,7 +21,6 @@ import time import os.path from UM.Extension import Extension -from PyQt5.QtQuick import QQuickView from PyQt5.QtQml import QQmlComponent, QQmlContext from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal, Qt from UM.i18n import i18nCatalog @@ -197,7 +197,7 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension): self._printer_connections[serial_port] = connection def _onPrinterConnectionStateChanged(self, serial_port): - if self._printer_connections[serial_port].isConnected(): + if self._printer_connections[serial_port].connectionState == ConnectionState.CLOSED: self.getOutputDeviceManager().addOutputDevice(self._printer_connections[serial_port]) else: self.getOutputDeviceManager().removeOutputDevice(serial_port) @@ -209,7 +209,7 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension): self._printer_connections_model.addRoleName(Qt.UserRole + 1,"name") self._printer_connections_model.addRoleName(Qt.UserRole + 2, "printer") for connection in self._printer_connections: - if self._printer_connections[connection].isConnected(): + if self._printer_connections[connection].isConnected: self._printer_connections_model.appendItem({"name":connection, "printer": self._printer_connections[connection]}) return self._printer_connections_model diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index a2dcaa5dca..4514d58ae3 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -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: