Merge branch 'dev/positionRecordingOnPause' into devel
This commit is contained in:
commit
4689a405a3
4 changed files with 115 additions and 25 deletions
|
|
@ -78,6 +78,7 @@ class Events(object):
|
|||
CONVEYOR = "Conveyor"
|
||||
EJECT = "Eject"
|
||||
E_STOP = "EStop"
|
||||
POSITION_UPDATE = "PositionUpdate"
|
||||
REGISTERED_MESSAGE_RECEIVED = "RegisteredMessageReceived"
|
||||
|
||||
# Timelapse
|
||||
|
|
|
|||
|
|
@ -62,10 +62,10 @@ class VirtualPrinter(object):
|
|||
self.speeds = settings().get(["devel", "virtualPrinter", "movementSpeed"])
|
||||
|
||||
self._relative = True
|
||||
self._lastX = None
|
||||
self._lastY = None
|
||||
self._lastZ = None
|
||||
self._lastE = None
|
||||
self._lastX = 0.0
|
||||
self._lastY = 0.0
|
||||
self._lastZ = 0.0
|
||||
self._lastE = 0.0
|
||||
|
||||
self._unitModifier = 1
|
||||
|
||||
|
|
|
|||
|
|
@ -956,6 +956,9 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
def on_comm_temperature_update(self, temp, bedTemp):
|
||||
self._addTemperatureData(copy.deepcopy(temp), copy.deepcopy(bedTemp))
|
||||
|
||||
def on_comm_position_update(self, position):
|
||||
eventManager().fire(Events.POSITION_UPDATE, position)
|
||||
|
||||
def on_comm_state_change(self, state):
|
||||
"""
|
||||
Callback method for the comm object, called if the connection state changes.
|
||||
|
|
|
|||
|
|
@ -50,9 +50,13 @@ regex_float = re.compile(regex_float_pattern)
|
|||
"""Regex for a float value."""
|
||||
|
||||
regexes_parameters = dict(
|
||||
floatE=re.compile("(^|[^A-Za-z])[Ee](?P<value>%s)" % regex_float_pattern),
|
||||
floatF=re.compile("(^|[^A-Za-z])[Ff](?P<value>%s)" % regex_float_pattern),
|
||||
floatP=re.compile("(^|[^A-Za-z])[Pp](?P<value>%s)" % regex_float_pattern),
|
||||
floatR=re.compile("(^|[^A-Za-z])[Rr](?P<value>%s)" % regex_float_pattern),
|
||||
floatS=re.compile("(^|[^A-Za-z])[Ss](?P<value>%s)" % regex_float_pattern),
|
||||
floatX=re.compile("(^|[^A-Za-z])[Xx](?P<value>%s)" % regex_float_pattern),
|
||||
floatY=re.compile("(^|[^A-Za-z])[Yy](?P<value>%s)" % regex_float_pattern),
|
||||
floatZ=re.compile("(^|[^A-Za-z])[Zz](?P<value>%s)" % regex_float_pattern),
|
||||
intN=re.compile("(^|[^A-Za-z])[Nn](?P<value>%s)" % regex_int_pattern),
|
||||
intT=re.compile("(^|[^A-Za-z])[Tt](?P<value>%s)" % regex_int_pattern)
|
||||
|
|
@ -109,6 +113,17 @@ Groups will be as follows:
|
|||
* ``target``: new target temperature (float)
|
||||
"""
|
||||
|
||||
regex_position = re.compile("X:(?P<x>{float})\s+Y:(?P<y>{float})\s+Z:(?P<z>{float})\s+E:(?P<e>{float})".format(float=regex_float_pattern))
|
||||
"""Regex for matching position reporting.
|
||||
|
||||
Groups will be as follows:
|
||||
|
||||
* ``x``: X coordinate
|
||||
* ``y``: Y coordinate
|
||||
* ``z``: Z coordinate
|
||||
* ``e``: E coordinate
|
||||
"""
|
||||
|
||||
def serialList():
|
||||
baselist=[]
|
||||
if os.name=="nt":
|
||||
|
|
@ -188,6 +203,31 @@ gcodeToEvent = {
|
|||
"M81": Events.POWER_OFF,
|
||||
}
|
||||
|
||||
class PositionRecord(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.x = kwargs.get("x")
|
||||
self.y = kwargs.get("y")
|
||||
self.z = kwargs.get("z")
|
||||
self.e = kwargs.get("e")
|
||||
self.f = kwargs.get("f")
|
||||
self.t = kwargs.get("t")
|
||||
|
||||
def copy_from(self, other):
|
||||
self.x = other.x
|
||||
self.y = other.y
|
||||
self.z = other.z
|
||||
self.e = other.e
|
||||
self.f = other.f
|
||||
self.t = other.t
|
||||
|
||||
def as_dict(self):
|
||||
return dict(x=self.x,
|
||||
y=self.y,
|
||||
z=self.z,
|
||||
e=self.e,
|
||||
t=self.t,
|
||||
f=self.f)
|
||||
|
||||
class MachineCom(object):
|
||||
STATE_NONE = 0
|
||||
STATE_OPEN_SERIAL = 1
|
||||
|
|
@ -231,6 +271,7 @@ class MachineCom(object):
|
|||
self._tempOffsets = dict()
|
||||
self._command_queue = TypedQueue()
|
||||
self._currentZ = None
|
||||
self._currentF = None
|
||||
self._heatupWaitStartTime = None
|
||||
self._heatupWaitTimeLost = 0.0
|
||||
self._pauseWaitStartTime = None
|
||||
|
|
@ -329,6 +370,10 @@ class MachineCom(object):
|
|||
self._ignore_select = False
|
||||
self._manualStreaming = False
|
||||
|
||||
self._last_position = PositionRecord()
|
||||
self._pause_position = PositionRecord()
|
||||
self._record_pause_position = False
|
||||
|
||||
# print job
|
||||
self._currentFile = None
|
||||
|
||||
|
|
@ -601,7 +646,7 @@ class MachineCom(object):
|
|||
def fakeOk(self):
|
||||
self._handle_ok()
|
||||
|
||||
def sendCommand(self, cmd, cmd_type=None, processed=False, force=False):
|
||||
def sendCommand(self, cmd, cmd_type=None, processed=False, force=False, on_sent=None):
|
||||
cmd = to_unicode(cmd, errors="replace")
|
||||
if not processed:
|
||||
cmd = process_gcode_line(cmd)
|
||||
|
|
@ -610,20 +655,22 @@ class MachineCom(object):
|
|||
|
||||
if self.isPrinting() and not self.isSdFileSelected():
|
||||
try:
|
||||
self._command_queue.put((cmd, cmd_type), item_type=cmd_type)
|
||||
self._command_queue.put((cmd, cmd_type, on_sent), item_type=cmd_type)
|
||||
return True
|
||||
except TypeAlreadyInQueue as e:
|
||||
self._logger.debug("Type already in command queue: " + e.type)
|
||||
return False
|
||||
elif self.isOperational() or force:
|
||||
return self._sendCommand(cmd, cmd_type=cmd_type)
|
||||
return self._sendCommand(cmd, cmd_type=cmd_type, on_sent=on_sent)
|
||||
|
||||
def sendGcodeScript(self, scriptName, replacements=None):
|
||||
context = dict()
|
||||
if replacements is not None and isinstance(replacements, dict):
|
||||
context.update(replacements)
|
||||
context.update(dict(
|
||||
printer_profile=self._printerProfileManager.get_current_or_default()
|
||||
printer_profile=self._printerProfileManager.get_current_or_default(),
|
||||
last_position=self._last_position,
|
||||
pause_position=self._pause_position
|
||||
))
|
||||
|
||||
template = settings().loadScript("gcode", scriptName, context=context)
|
||||
|
|
@ -781,6 +828,9 @@ class MachineCom(object):
|
|||
self._recordFilePosition()
|
||||
self._callback.on_comm_print_job_cancelled()
|
||||
|
||||
def _pause_preparation_done(self):
|
||||
self._callback.on_comm_print_job_paused()
|
||||
|
||||
def setPause(self, pause):
|
||||
if self.isStreaming():
|
||||
return
|
||||
|
|
@ -815,8 +865,14 @@ class MachineCom(object):
|
|||
if self.isSdFileSelected():
|
||||
self.sendCommand("M25") # pause print
|
||||
|
||||
self._callback.on_comm_print_job_paused()
|
||||
def _on_M400_sent():
|
||||
# we don't call on_print_job_paused on our callback here
|
||||
# because we do this only after our M114 has been answered
|
||||
# by the firmware
|
||||
self._record_pause_position = True
|
||||
self.sendCommand("M114")
|
||||
|
||||
self.sendCommand("M400", on_sent=_on_M400_sent)
|
||||
|
||||
def getSdFiles(self):
|
||||
return self._sdFiles
|
||||
|
|
@ -1064,12 +1120,25 @@ class MachineCom(object):
|
|||
|
||||
# position report processing
|
||||
if 'X:' in line and 'Y:' in line and 'Z:' in line:
|
||||
# currently only here to prevent any "B:"s in a position report from
|
||||
# triggering temperature processing and being interpreted as a bed
|
||||
# temperature - can happen with COREXY in current Marlin
|
||||
#
|
||||
# see also issue #1373
|
||||
pass
|
||||
match = regex_position.search(line)
|
||||
if match:
|
||||
# we don't know T or F when printing from SD since
|
||||
# there's no way to query it from the firmware and
|
||||
# no way to track it ourselves when not streaming
|
||||
# the file - this all sucks sooo much
|
||||
self._last_position.x = float(match.group("x"))
|
||||
self._last_position.y = float(match.group("y"))
|
||||
self._last_position.z = float(match.group("z"))
|
||||
self._last_position.e = float(match.group("e"))
|
||||
self._last_position.t = self._currentTool if not self.isSdFileSelected() else None
|
||||
self._last_position.f = self._currentF if not self.isSdFileSelected() else None
|
||||
|
||||
if self._record_pause_position:
|
||||
self._record_pause_position = False
|
||||
self._pause_position.copy_from(self._last_position)
|
||||
self._pause_preparation_done()
|
||||
|
||||
self._callback.on_comm_position_update(self._last_position.as_dict())
|
||||
|
||||
# temperature processing
|
||||
elif ' T:' in line or line.startswith('T:') or ' T0:' in line or line.startswith('T0:') or ((' B:' in line or line.startswith('B:')) and not 'A:' in line):
|
||||
|
|
@ -1472,16 +1541,17 @@ class MachineCom(object):
|
|||
|
||||
try:
|
||||
if isinstance(entry, tuple):
|
||||
if not len(entry) == 2:
|
||||
if not len(entry) == 3:
|
||||
# something with that entry is broken, ignore it and fetch
|
||||
# the next one
|
||||
continue
|
||||
cmd, cmd_type = entry
|
||||
cmd, cmd_type, callback = entry
|
||||
else:
|
||||
cmd = entry
|
||||
cmd_type = None
|
||||
callback = None
|
||||
|
||||
if self._sendCommand(cmd, cmd_type=cmd_type):
|
||||
if self._sendCommand(cmd, cmd_type=cmd_type, on_sent=callback):
|
||||
# we actually did add this cmd to the send queue, so let's
|
||||
# return, we are done here
|
||||
return True
|
||||
|
|
@ -1809,7 +1879,7 @@ class MachineCom(object):
|
|||
|
||||
return result
|
||||
|
||||
def _sendCommand(self, cmd, cmd_type=None):
|
||||
def _sendCommand(self, cmd, cmd_type=None, on_sent=None):
|
||||
# Make sure we are only handling one sending job at a time
|
||||
with self._sendingLock:
|
||||
if self._serial is None:
|
||||
|
|
@ -1829,7 +1899,7 @@ class MachineCom(object):
|
|||
eventManager().fire(gcodeToEvent[gcode])
|
||||
|
||||
# actually enqueue the command for sending
|
||||
if self._enqueue_for_sending(cmd, command_type=cmd_type):
|
||||
if self._enqueue_for_sending(cmd, command_type=cmd_type, on_sent=on_sent):
|
||||
self._process_command_phase("queued", cmd, cmd_type, gcode=gcode)
|
||||
return True
|
||||
else:
|
||||
|
|
@ -1837,7 +1907,7 @@ class MachineCom(object):
|
|||
|
||||
##~~ send loop handling
|
||||
|
||||
def _enqueue_for_sending(self, command, linenumber=None, command_type=None):
|
||||
def _enqueue_for_sending(self, command, linenumber=None, command_type=None, on_sent=None):
|
||||
"""
|
||||
Enqueues a command an optional linenumber to use for it in the send queue.
|
||||
|
||||
|
|
@ -1848,7 +1918,7 @@ class MachineCom(object):
|
|||
"""
|
||||
|
||||
try:
|
||||
self._send_queue.put((command, linenumber, command_type), item_type=command_type)
|
||||
self._send_queue.put((command, linenumber, command_type, on_sent), item_type=command_type)
|
||||
return True
|
||||
except TypeAlreadyInQueue as e:
|
||||
self._logger.debug("Type already in send queue: " + e.type)
|
||||
|
|
@ -1872,8 +1942,8 @@ class MachineCom(object):
|
|||
if not self._send_queue_active:
|
||||
break
|
||||
|
||||
# fetch command and optional linenumber from queue
|
||||
command, linenumber, command_type = entry
|
||||
# fetch command, command type and optional linenumber and sent callback from queue
|
||||
command, linenumber, command_type, on_sent = entry
|
||||
|
||||
# some firmwares (e.g. Smoothie) might support additional in-band communication that will not
|
||||
# stick to the acknowledgement behaviour of GCODE, so we check here if we have a GCODE command
|
||||
|
|
@ -1921,6 +1991,9 @@ class MachineCom(object):
|
|||
self._do_send_without_checksum(command_to_send)
|
||||
|
||||
# trigger "sent" phase and use up one "ok"
|
||||
if on_sent is not None and callable(on_sent):
|
||||
# we have a sent callback for this specific command, let's execute it now
|
||||
on_sent()
|
||||
self._process_command_phase("sent", command, command_type, gcode=gcode)
|
||||
|
||||
# we only need to use up a clear if the command we just sent was either a gcode command or if we also
|
||||
|
|
@ -2093,7 +2166,8 @@ class MachineCom(object):
|
|||
self._currentTool = int(toolMatch.group("value"))
|
||||
|
||||
def _gcode_G0_sent(self, cmd, cmd_type=None):
|
||||
if 'Z' in cmd:
|
||||
if "Z" in cmd or "F" in cmd:
|
||||
# track Z
|
||||
match = regexes_parameters["floatZ"].search(cmd)
|
||||
if match:
|
||||
try:
|
||||
|
|
@ -2103,6 +2177,15 @@ class MachineCom(object):
|
|||
self._callback.on_comm_z_change(z)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# track F
|
||||
match = regexes_parameters["floatF"].search(cmd)
|
||||
if match:
|
||||
try:
|
||||
f = float(match.group("value"))
|
||||
self._currentF = f
|
||||
except ValueError:
|
||||
pass
|
||||
_gcode_G1_sent = _gcode_G0_sent
|
||||
|
||||
def _gcode_M0_queuing(self, cmd, cmd_type=None):
|
||||
|
|
@ -2268,6 +2351,9 @@ class MachineComPrintCallback(object):
|
|||
def on_comm_temperature_update(self, temp, bedTemp):
|
||||
pass
|
||||
|
||||
def on_comm_position_update(self, position):
|
||||
pass
|
||||
|
||||
def on_comm_state_change(self, state):
|
||||
pass
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue