mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 06:57:28 -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
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue