mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-16 03:07:53 -06:00
Changed USB printing to reflect changes in output device API
CURA-1339
This commit is contained in:
parent
2b9aa1dbb5
commit
0cd1031ec7
2 changed files with 36 additions and 135 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue