Backported clear_to_send mechanism from commRefactoring
Also added temperature and sd status polling timers
This commit is contained in:
parent
9ec49d6273
commit
383f36fc48
2 changed files with 132 additions and 22 deletions
|
|
@ -14,6 +14,7 @@ import re
|
|||
import tempfile
|
||||
import logging
|
||||
import shutil
|
||||
import threading
|
||||
from functools import wraps
|
||||
import warnings
|
||||
|
||||
|
|
@ -529,4 +530,40 @@ def address_for_client(host, port):
|
|||
except:
|
||||
continue
|
||||
|
||||
class CountedEvent(object):
|
||||
|
||||
def __init__(self, value=0, max=None):
|
||||
self._counter = 0
|
||||
self._max = max
|
||||
self._mutex = threading.Lock()
|
||||
self._event = threading.Event()
|
||||
|
||||
self._internal_set(value)
|
||||
|
||||
def set(self):
|
||||
with self._mutex:
|
||||
self._internal_set(self._counter + 1)
|
||||
|
||||
def clear(self, completely=False):
|
||||
with self._mutex:
|
||||
if completely:
|
||||
self._internal_set(0)
|
||||
else:
|
||||
self._internal_set(self._counter - 1)
|
||||
|
||||
def wait(self, timeout=None):
|
||||
self._event.wait(timeout)
|
||||
|
||||
def blocked(self):
|
||||
with self._mutex:
|
||||
return self._counter == 0
|
||||
|
||||
def _internal_set(self, value):
|
||||
self._counter = value
|
||||
if self._counter <= 0:
|
||||
self._counter = 0
|
||||
self._event.clear()
|
||||
else:
|
||||
if self._max is not None and self._counter > self._max:
|
||||
self._counter = self._max
|
||||
self._event.set()
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ from octoprint.settings import settings, default_settings
|
|||
from octoprint.events import eventManager, Events
|
||||
from octoprint.filemanager import valid_file_type
|
||||
from octoprint.filemanager.destinations import FileDestinations
|
||||
from octoprint.util import get_exception_string, sanitize_ascii, filter_non_ascii
|
||||
from octoprint.util import get_exception_string, sanitize_ascii, filter_non_ascii, CountedEvent
|
||||
from octoprint.util.virtual import VirtualPrinter
|
||||
|
||||
try:
|
||||
|
|
@ -162,6 +162,11 @@ class MachineCom(object):
|
|||
self._lastResendNumber = None
|
||||
self._currentResendCount = 0
|
||||
|
||||
self._clear_to_send = CountedEvent(max=10)
|
||||
self._send_queue = queue.Queue()
|
||||
self._sd_status_timer = None
|
||||
self._temperature_timer = None
|
||||
|
||||
# hooks
|
||||
self._pluginManager = octoprint.plugin.plugin_manager()
|
||||
self._gcode_hooks = self._pluginManager.get_hooks("octoprint.comm.protocol.gcode")
|
||||
|
|
@ -206,9 +211,14 @@ class MachineCom(object):
|
|||
self._sendingLock = threading.Lock()
|
||||
|
||||
# monitoring thread
|
||||
self.thread = threading.Thread(target=self._monitor)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
self.monitoring_thread = threading.Thread(target=self._monitor)
|
||||
self.monitoring_thread.daemon = True
|
||||
self.monitoring_thread.start()
|
||||
|
||||
# sending thread
|
||||
self.sending_thread = threading.Thread(target=self._send_loop)
|
||||
self.sending_thread.daemon = True
|
||||
self.sending_thread.start()
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
|
@ -352,6 +362,18 @@ class MachineCom(object):
|
|||
##~~ external interface
|
||||
|
||||
def close(self, isError = False):
|
||||
if self._temperature_timer is not None:
|
||||
try:
|
||||
self._temperature_timer.cancel()
|
||||
except:
|
||||
pass
|
||||
|
||||
if self._sd_status_timer is not None:
|
||||
try:
|
||||
self._sd_status_timer.cancel()
|
||||
except:
|
||||
pass
|
||||
|
||||
printing = self.isPrinting() or self.isPaused()
|
||||
if self._serial is not None:
|
||||
if isError:
|
||||
|
|
@ -454,7 +476,6 @@ class MachineCom(object):
|
|||
try:
|
||||
self._currentFile.start()
|
||||
|
||||
wasPaused = self.isPaused()
|
||||
self._changeState(self.STATE_PRINTING)
|
||||
|
||||
self.sendCommand("M110 N0")
|
||||
|
|
@ -471,6 +492,7 @@ class MachineCom(object):
|
|||
self.sendCommand("M26 S0")
|
||||
self._currentFile.setFilepos(0)
|
||||
self.sendCommand("M24")
|
||||
self.sendCommand("M27")
|
||||
else:
|
||||
line = self._getNext()
|
||||
if line is not None:
|
||||
|
|
@ -565,6 +587,7 @@ class MachineCom(object):
|
|||
|
||||
if self.isSdFileSelected():
|
||||
self.sendCommand("M24")
|
||||
self.sendCommand("M27")
|
||||
else:
|
||||
line = self._getNext()
|
||||
if line is not None:
|
||||
|
|
@ -800,6 +823,10 @@ class MachineCom(object):
|
|||
self._sdFiles.append((filename, size))
|
||||
continue
|
||||
|
||||
##~~ process oks
|
||||
if line.strip().startswith("ok"):
|
||||
self._clear_to_send.set()
|
||||
|
||||
##~~ Temperature processing
|
||||
if ' T:' in line or line.startswith('T:') or ' T0:' in line or line.startswith('T0:'):
|
||||
self._processTemperatures(line)
|
||||
|
|
@ -993,8 +1020,9 @@ class MachineCom(object):
|
|||
elif self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PAUSED:
|
||||
#Request the temperature on comm timeout (every 5 seconds) when we are not printing.
|
||||
if line == "":
|
||||
self.sendCommand("M105")
|
||||
tempRequestTimeout = get_new_timeout("temperature")
|
||||
#self.sendCommand("M105")
|
||||
#tempRequestTimeout = get_new_timeout("temperature")
|
||||
pass
|
||||
|
||||
# if we still have commands to process, process them
|
||||
elif "ok" in line:
|
||||
|
|
@ -1025,19 +1053,30 @@ class MachineCom(object):
|
|||
if self._resendDelta is not None:
|
||||
self._resendNextCommand()
|
||||
else:
|
||||
if self._heatupWaitStartTime is None:
|
||||
if time.time() > tempRequestTimeout:
|
||||
self.sendCommand("M105")
|
||||
tempRequestTimeout = get_new_timeout("temperature")
|
||||
#if self._heatupWaitStartTime is None:
|
||||
# if time.time() > tempRequestTimeout:
|
||||
# self.sendCommand("M105")
|
||||
# tempRequestTimeout = get_new_timeout("temperature")
|
||||
|
||||
if self.isSdPrinting() and time.time() > sdStatusRequestTimeout:
|
||||
self.sendCommand("M27")
|
||||
sdStatusRequestTimeout = get_new_timeout("sdStatus")
|
||||
# if self.isSdPrinting() and time.time() > sdStatusRequestTimeout:
|
||||
# self.sendCommand("M27")
|
||||
# sdStatusRequestTimeout = get_new_timeout("sdStatus")
|
||||
|
||||
if self._sendFromQueue(sendChecksum=True):
|
||||
pass
|
||||
elif not self.isSdPrinting():
|
||||
self._sendNext()
|
||||
|
||||
elif line == "" and self.isSdPrinting():
|
||||
pass
|
||||
#if time.time() > tempRequestTimeout:
|
||||
# self.sendCommand("M105")
|
||||
# tempRequestTimeout = get_new_timeout("temperature")
|
||||
|
||||
#if time.time() > sdStatusRequestTimeout:
|
||||
# self.sendCommand("M27")
|
||||
# sdStatusRequestTimeout = get_new_timeout("sdStatus")
|
||||
|
||||
elif line.lower().startswith("resend") or line.lower().startswith("rs"):
|
||||
if settings().get(["feature", "swallowOkAfterResend"]):
|
||||
swallowOk = True
|
||||
|
|
@ -1052,7 +1091,38 @@ class MachineCom(object):
|
|||
eventManager().fire(Events.ERROR, {"error": self.getErrorString()})
|
||||
self._log("Connection closed, closing down monitor")
|
||||
|
||||
def _enqueue_for_sending(self, command, linenumber=None):
|
||||
self._send_queue.put((command, linenumber))
|
||||
|
||||
def _send_loop(self):
|
||||
while True:
|
||||
self._clear_to_send.wait()
|
||||
command, linenumber = self._send_queue.get()
|
||||
if linenumber is not None:
|
||||
self._doSendWithChecksum(command, linenumber)
|
||||
else:
|
||||
self._doSendWithoutChecksum(command)
|
||||
|
||||
def _poll_temperature(self):
|
||||
if self.isOperational() and not self.isStreaming() and self._heatupWaitStartTime is None:
|
||||
self.sendCommand("M105")
|
||||
|
||||
interval = get_interval("temperature")
|
||||
self._temperature_timer = threading.Timer(interval, self._poll_temperature)
|
||||
self._temperature_timer.start()
|
||||
|
||||
def _poll_sd_status(self):
|
||||
if self.isOperational() and self.isSdPrinting() and self._heatupWaitStartTime is None:
|
||||
self.sendCommand("M27")
|
||||
|
||||
interval = get_interval("sdStatus")
|
||||
self._sd_status_timer = threading.Timer(interval, self._poll_temperature)
|
||||
self._sd_status_timer.start()
|
||||
|
||||
def _onConnected(self):
|
||||
self._poll_temperature()
|
||||
self._poll_sd_status()
|
||||
|
||||
self._changeState(self.STATE_OPERATIONAL)
|
||||
if self._sdAvailable:
|
||||
self.refreshSdFiles()
|
||||
|
|
@ -1112,6 +1182,7 @@ class MachineCom(object):
|
|||
self._changeState(self.STATE_ERROR)
|
||||
eventManager().fire(Events.ERROR, {"error": self.getErrorString()})
|
||||
return False
|
||||
self._clear_to_send.set()
|
||||
return True
|
||||
|
||||
def _handleErrors(self, line):
|
||||
|
|
@ -1244,7 +1315,7 @@ class MachineCom(object):
|
|||
cmd = self._lastLines[-self._resendDelta]
|
||||
lineNumber = self._currentLine - self._resendDelta
|
||||
|
||||
self._doSendWithChecksum(cmd, lineNumber)
|
||||
self._enqueue_for_sending(cmd, linenumber=lineNumber)
|
||||
|
||||
self._resendDelta -= 1
|
||||
if self._resendDelta <= 0:
|
||||
|
|
@ -1282,9 +1353,9 @@ class MachineCom(object):
|
|||
lineNumber = self._currentLine
|
||||
self._addToLastLines(cmd)
|
||||
self._currentLine += 1
|
||||
self._doSendWithChecksum(cmd, lineNumber)
|
||||
self._enqueue_for_sending(cmd, linenumber=lineNumber)
|
||||
else:
|
||||
self._doSendWithoutChecksum(cmd)
|
||||
self._enqueue_for_sending(cmd)
|
||||
|
||||
def _doSendWithChecksum(self, cmd, lineNumber):
|
||||
self._logger.debug("Sending cmd '%s' with lineNumber %r" % (cmd, lineNumber))
|
||||
|
|
@ -1388,7 +1459,7 @@ class MachineCom(object):
|
|||
newLineNumber = 0
|
||||
|
||||
# send M110 command with new line number
|
||||
self._doSendWithChecksum(cmd, newLineNumber)
|
||||
self._enqueue_for_sending(cmd, linenumber=newLineNumber)
|
||||
self._currentLine = newLineNumber + 1
|
||||
|
||||
# after a reset of the line number we have no way to determine what line exactly the printer now wants
|
||||
|
|
@ -1659,9 +1730,11 @@ class StreamingGcodeFileInformation(PrintingGcodeFileInformation):
|
|||
|
||||
def get_new_timeout(type):
|
||||
now = time.time()
|
||||
return now + get_interval(type)
|
||||
|
||||
if type not in default_settings["serial"]["timeout"].keys():
|
||||
# timeout immediately for unknown timeout type
|
||||
return now
|
||||
|
||||
return now + settings().getFloat(["serial", "timeout", type])
|
||||
def get_interval(type):
|
||||
if type not in default_settings["serial"]["timeout"]:
|
||||
return 0
|
||||
else:
|
||||
return settings().getFloat(["serial", "timeout", type])
|
||||
Loading…
Reference in a new issue