Changed USB printing to reflect changes in output device API

CURA-1339
This commit is contained in:
Jaime van Kessel 2016-04-13 15:15:37 +02:00
parent 2b9aa1dbb5
commit 0cd1031ec7
2 changed files with 36 additions and 135 deletions

View file

@ -8,6 +8,7 @@ from UM.Resources import Resources
from UM.Logger import Logger from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from cura.PrinterOutputDevice import ConnectionState
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from UM.Message import Message from UM.Message import Message
@ -20,7 +21,6 @@ import time
import os.path import os.path
from UM.Extension import Extension from UM.Extension import Extension
from PyQt5.QtQuick import QQuickView
from PyQt5.QtQml import QQmlComponent, QQmlContext from PyQt5.QtQml import QQmlComponent, QQmlContext
from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal, Qt from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal, Qt
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
@ -197,7 +197,7 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
self._printer_connections[serial_port] = connection self._printer_connections[serial_port] = connection
def _onPrinterConnectionStateChanged(self, serial_port): 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]) self.getOutputDeviceManager().addOutputDevice(self._printer_connections[serial_port])
else: else:
self.getOutputDeviceManager().removeOutputDevice(serial_port) 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 + 1,"name")
self._printer_connections_model.addRoleName(Qt.UserRole + 2, "printer") self._printer_connections_model.addRoleName(Qt.UserRole + 2, "printer")
for connection in self._printer_connections: 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]}) self._printer_connections_model.appendItem({"name":connection, "printer": self._printer_connections[connection]})
return self._printer_connections_model return self._printer_connections_model

View file

@ -11,25 +11,20 @@ import functools
import os.path import os.path
from UM.Application import Application from UM.Application import Application
from UM.Signal import Signal, SignalEmitter
from UM.Logger import Logger from UM.Logger import Logger
from UM.OutputDevice.OutputDevice import OutputDevice
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
from PyQt5.QtQuick import QQuickView
from PyQt5.QtQml import QQmlComponent, QQmlContext 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 from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter): class USBPrinterOutputDevice(PrinterOutputDevice):
def __init__(self, serial_port, parent = None): def __init__(self, serial_port):
QObject.__init__(self, parent) super().__init__(serial_port)
OutputDevice.__init__(self, serial_port)
SignalEmitter.__init__(self)
#super().__init__(serial_port)
self.setName(catalog.i18nc("@item:inmenu", "USB printing")) self.setName(catalog.i18nc("@item:inmenu", "USB printing"))
self.setShortDescription(catalog.i18nc("@action:button", "Print with USB")) self.setShortDescription(catalog.i18nc("@action:button", "Print with USB"))
self.setDescription(catalog.i18nc("@info:tooltip", "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._end_stop_thread.daemon = True
self._poll_endstop = -1 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 # 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. # response. If the baudrate is correct, this should make sense, else we get giberish.
self._required_responses_auto_baud = 3 self._required_responses_auto_baud = 3
self._progress = 0
self._listen_thread = threading.Thread(target=self._listen) self._listen_thread = threading.Thread(target=self._listen)
self._listen_thread.daemon = True self._listen_thread.daemon = True
@ -119,40 +106,26 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
self._control_view = None self._control_view = None
onError = pyqtSignal() onError = pyqtSignal()
progressChanged = pyqtSignal()
extruderTemperatureChanged = pyqtSignal()
bedTemperatureChanged = pyqtSignal()
firmwareUpdateComplete = pyqtSignal() firmwareUpdateComplete = pyqtSignal()
endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"]) endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"])
@pyqtProperty(float, notify = progressChanged) def _setTargetBedTemperature(self, temperature):
def progress(self): Logger.log("d", "Setting bed temperature to %s", temperature)
return self._progress self._sendCommand("M140 S%s" % temperature)
@pyqtProperty(float, notify = extruderTemperatureChanged) def _setHeadPosition(self, x, y , z, speed):
def extruderTemperature(self): self._sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed))
return self._extruder_temperatures[0]
@pyqtProperty(float, notify = bedTemperatureChanged) def _setHeadX(self, x, speed):
def bedTemperature(self): self._sendCommand("G0 X%s F%s" % (x, speed))
return self._bed_temperature
@pyqtProperty(str, notify = onError) def _setHeadY(self, y, speed):
def error(self): self._sendCommand("G0 Y%s F%s" % (y, speed))
return self._error_state
# TODO: Might need to add check that extruders can not be changed when it started printing or loading these settings from settings object def _setHeadZ(self, z, speed):
def setNumExtuders(self, num): self._sendCommand("G0 Y%s F%s" % (z, speed))
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
@pyqtSlot() @pyqtSlot()
def startPrint(self): def startPrint(self):
@ -163,7 +136,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
## Start a print based on a g-code. ## Start a print based on a g-code.
# \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.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") Logger.log("d", "Printer is busy or not connected, aborting print")
self.writeError.emit(self) self.writeError.emit(self)
return return
@ -198,7 +171,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
def _updateFirmware(self): def _updateFirmware(self):
self.setProgress(0, 100) self.setProgress(0, 100)
if self._is_connecting or self._is_connected: if self._connection_state != ConnectionState.CLOSED:
self.close() self.close()
hex_file = intelHex.readHex(self._firmware_file_name) hex_file = intelHex.readHex(self._firmware_file_name)
@ -253,14 +226,14 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
self._poll_endstop = False self._poll_endstop = False
def _pollEndStop(self): def _pollEndStop(self):
while self._is_connected and self._poll_endstop: while self._connection_state == ConnectionState.CONNECTED and self._poll_endstop:
self.sendCommand("M119") self.sendCommand("M119")
time.sleep(0.5) time.sleep(0.5)
## Private connect function run by thread. Can be started by calling connect. ## Private connect function run by thread. Can be started by calling connect.
def _connect(self): def _connect(self):
Logger.log("d", "Attempting to connect to %s", self._serial_port) Logger.log("d", "Attempting to connect to %s", self._serial_port)
self._is_connecting = True self.setConnectionState(ConnectionState.CONNECTING)
programmer = stk500v2.Stk500v2() programmer = stk500v2.Stk500v2()
try: try:
programmer.connect(self._serial_port) # Connect with the serial, if this succeeds, it's an arduino based usb device. 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: try:
self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout = 3, writeTimeout = 10000) self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout = 3, writeTimeout = 10000)
except serial.SerialException: 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 continue
else: else:
if not self.setBaudRate(baud_rate): if not self.setBaudRate(baud_rate):
@ -291,7 +264,8 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
while timeout_time > time.time(): while timeout_time > time.time():
line = self._readline() line = self._readline()
if line is None: 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 return
if b"T:" in line: if b"T:" in line:
@ -299,7 +273,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
sucesfull_responses += 1 sucesfull_responses += 1
if sucesfull_responses >= self._required_responses_auto_baud: if sucesfull_responses >= self._required_responses_auto_baud:
self._serial.timeout = 2 # Reset serial timeout self._serial.timeout = 2 # Reset serial timeout
self.setIsConnected(True) self.setConnectionState(ConnectionState.CONNECTED)
Logger.log("i", "Established printer connection on port %s" % self._serial_port) Logger.log("i", "Established printer connection on port %s" % self._serial_port)
return return
@ -307,7 +281,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
Logger.log("e", "Baud rate detection for %s failed", self._serial_port) Logger.log("e", "Baud rate detection for %s failed", self._serial_port)
self.close() # Unable to connect, wrap up. 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. ## Set the baud rate of the serial. This can cause exceptions, but we simply want to ignore those.
def setBaudRate(self, baud_rate): def setBaudRate(self, baud_rate):
@ -317,21 +291,9 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
except Exception as e: except Exception as e:
return False 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 ## Close the printer connection
def close(self): def close(self):
Logger.log("d", "Closing the printer connection.") Logger.log("d", "Closing the USB printer connection.")
if self._connect_thread.isAlive(): if self._connect_thread.isAlive():
try: try:
self._connect_thread.join() self._connect_thread.join()
@ -342,7 +304,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
self._connect_thread = threading.Thread(target = self._connect) self._connect_thread = threading.Thread(target = self._connect)
self._connect_thread.daemon = True self._connect_thread.daemon = True
self.setIsConnected(False) self.setConnectionState(ConnectionState.CLOSED)
if self._serial is not None: if self._serial is not None:
try: try:
self._listen_thread.join() self._listen_thread.join()
@ -354,45 +316,6 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
self._listen_thread.daemon = True self._listen_thread.daemon = True
self._serial = None 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). ## Directly send the command, withouth checking connection state (eg; printing).
# \param cmd string with g-code # \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._setErrorState("Unexpected error while writing serial port %s " % e)
self.close() self.close()
## Ensure that close gets called when object is destroyed
def __del__(self):
self.close()
def createControlInterface(self): def createControlInterface(self):
if self._control_view is None: if self._control_view is None:
Logger.log("d", "Creating control interface for printer connection") Logger.log("d", "Creating control interface for printer connection")
@ -456,7 +375,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
## Send a command to printer. ## 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.isPrinting(): if not self._progress:
self._command_queue.put(cmd) self._command_queue.put(cmd)
elif self.isConnected(): elif self.isConnected():
self._sendCommand(cmd) self._sendCommand(cmd)
@ -467,24 +386,6 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
self._error_state = error self._error_state = error
self.onError.emit() 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): def requestWrite(self, node, file_name = None, filter_by_machine = False):
self.showControlInterface() self.showControlInterface()
@ -507,7 +408,7 @@ class USBPrinterOutputDevice(OutputDevice, QObject, SignalEmitter):
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._is_connected: while self._connected:
line = self._readline() line = self._readline()
if line is None: if line is None: