User thread lock instead of boolean to ensure only one concurrent sending thread, introduced wait flag for repetier printers

master
Gina Häußge 2013-03-29 22:17:44 +01:00
parent 48a2fd71a7
commit f050567a1c
5 changed files with 107 additions and 75 deletions

View File

@ -360,6 +360,7 @@ def getSettings():
"feature": {
"gcodeViewer": s.getBoolean(["feature", "gCodeVisualizer"]),
"waitForStart": s.getBoolean(["feature", "waitForStartOnConnect"]),
"waitForWaitAfterStart": s.getBoolean(["feature", "waitForWaitAfterStartOnConnect"]),
"alwaysSendChecksum": s.getBoolean(["feature", "alwaysSendChecksum"]),
"resetLineNumbersWithPrefixedN": s.getBoolean(["feature", "resetLineNumbersWithPrefixedN"])
},
@ -403,6 +404,7 @@ def setSettings():
if "feature" in data.keys():
if "gcodeViewer" in data["feature"].keys(): s.setBoolean(["feature", "gCodeVisualizer"], data["feature"]["gcodeViewer"])
if "waitForStart" in data["feature"].keys(): s.setBoolean(["feature", "waitForStartOnConnect"], data["feature"]["waitForStart"])
if "waitForWait" in data["feature"].keys(): s.setBoolean(["feature", "waitForWaitOnConnect"], data["feature"]["waitForWait"]),
if "alwaysSendChecksum" in data["feature"].keys(): s.setBoolean(["feature", "alwaysSendChecksum"], data["feature"]["alwaysSendChecksum"])
if "resetLineNumbersWithPrefixedN" in data["feature"].keys(): s.setBoolean(["feature", "resetLineNumbersWithPrefixedN"], data["feature"]["resetLineNumbersWithPrefixedN"])

View File

@ -40,6 +40,7 @@ default_settings = {
"feature": {
"gCodeVisualizer": True,
"waitForStartOnConnect": False,
"waitForWaitOnConnect": False,
"alwaysSendChecksum": False,
"resetLineNumbersWithPrefixedN": False
},

View File

@ -618,6 +618,7 @@ function TerminalViewModel() {
if (!self.log)
self.log = []
self.log = self.log.concat(data)
self.log = self.log.slice(-300)
self.updateOutput();
}
@ -959,6 +960,7 @@ function SettingsViewModel() {
self.feature_gcodeViewer = ko.observable(undefined);
self.feature_waitForStart = ko.observable(undefined);
self.feature_waitForWait = ko.observable(undefined);
self.feature_alwaysSendChecksum = ko.observable(undefined);
self.feature_resetLineNumbersWithPrefixedN = ko.observable(undefined);
@ -1005,6 +1007,7 @@ function SettingsViewModel() {
self.feature_gcodeViewer(response.feature.gcodeViewer);
self.feature_waitForStart(response.feature.waitForStart);
self.feature_waitForWait(response.feature.waitForWait);
self.feature_alwaysSendChecksum(response.feature.alwaysSendChecksum);
self.feature_resetLineNumbersWithPrefixedN(response.feature.resetLineNumbersWithPrefixedN);
@ -1040,6 +1043,7 @@ function SettingsViewModel() {
"feature": {
"gcodeViewer": self.feature_gcodeViewer(),
"waitForStart": self.feature_waitForStart(),
"waitForWait": self.feature_waitForWait(),
"alwaysSendChecksum": self.feature_alwaysSendChecksum(),
"resetLineNumbersWithPrefixedN": self.feature_resetLineNumbersWithPrefixedN()
},

View File

@ -102,21 +102,28 @@
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_waitForStart" id="settings-featureWaitForStart"> Wait for start on connect
<input type="checkbox" data-bind="checked: feature_waitForStart" id="settings-featureWaitForStart"> Wait for <code>start</code> on connect
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_alwaysSendChecksum" id="settings-featureAlwaysSendChecksum"> Send a checksum with <strong>every</strong> command
<input type="checkbox" data-bind="checked: feature_waitForWait" id="settings-featureWaitForWait"> Wait for <code>wait</code> on connect <span class="label">Repetier</span>
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_resetLineNumbersWithPrefixedN" id="settings-resetLineNumbersWithPrefixedN"> Send M110 commands with target line number as N-prefix
<input type="checkbox" data-bind="checked: feature_alwaysSendChecksum" id="settings-featureAlwaysSendChecksum"> Send a checksum with <strong>every</strong> command <span class="label">Repetier</span>
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_resetLineNumbersWithPrefixedN" id="settings-resetLineNumbersWithPrefixedN"> Send M110 commands with target line number as N-prefix <span class="label">Repetier</span>
</label>
</div>
</div>

View File

@ -66,6 +66,9 @@ class VirtualPrinter():
self.currentLine = 0
waitThread = threading.Thread(target=self._sendWaitAfterTimeout)
waitThread.start()
def write(self, data):
if self.readList is None:
return
@ -125,6 +128,10 @@ class VirtualPrinter():
def close(self):
self.readList = None
def _sendWaitAfterTimeout(self, timeout=5):
time.sleep(timeout)
self.readList.append("wait")
class MachineComPrintCallback(object):
def mcLog(self, message):
pass
@ -197,7 +204,9 @@ class MachineCom(object):
self._currentLine = 1
self._resendDelta = None
self._lastLines = []
self._sending = False
self._sendingLock = threading.Lock()
self.thread = threading.Thread(target=self._monitor)
self.thread.daemon = True
self.thread.start()
@ -338,6 +347,7 @@ class MachineCom(object):
timeout = time.time() + 5
tempRequestTimeout = timeout
startSeen = not settings().getBoolean(["feature", "waitForStartOnConnect"])
waitSeen = not settings().getBoolean(["feature", "waitForWaitOnConnect"])
while True:
line = self._readline()
if line == None:
@ -429,13 +439,13 @@ class MachineCom(object):
### Connection attempt
elif self._state == self.STATE_CONNECTING:
#if (line == "" or "wait" in line) and startSeen:
#This modification allows more reliable initial connection.
if ("wait" in line) and startSeen:
if line == "" and startSeen and waitSeen:
self._sendCommand("M105")
elif "start" in line:
startSeen = True
elif "ok" in line and startSeen:
elif "wait" in line:
waitSeen = True
elif "ok" in line and startSeen and waitSeen:
self._changeState(self.STATE_OPERATIONAL)
elif time.time() > timeout:
self.close()
@ -444,8 +454,16 @@ 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 == "" or "wait" in line:
self._sendCommand("M105")
if self._resendDelta is not None:
self._resendNextCommand()
elif not self._commandQueue.empty():
self._sendCommand(self._commandQueue.get())
else:
self._sendCommand("M105")
tempRequestTimeout = time.time() + 5
# resend -> start resend procedure from requested line
elif "resend" in line.lower() or "rs" in line:
self._handleResendRequest(line)
### Printing
elif self._state == self.STATE_PRINTING:
@ -468,23 +486,26 @@ class MachineCom(object):
self._sendNext()
# resend -> start resend procedure from requested line
elif "resend" in line.lower() or "rs" in line:
lineToResend = None
try:
lineToResend = int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])
except:
if "rs" in line:
lineToResend = int(line.split()[1])
if lineToResend is not None:
self._resendDelta = self._currentLine - lineToResend
if self._resendDelta > len(self._lastLines):
self._errorValue = "Printer requested line %d but history is only available up to line %d" % (lineToResend, self._currentLine - len(self._lastLines))
self._changeState(self.STATE_ERROR)
self._logger.warn(self._errorValue)
else:
self._resendNextCommand()
self._handleResendRequest(line)
self._log("Connection closed, closing down monitor")
def _handleResendRequest(self, line):
lineToResend = None
try:
lineToResend = int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])
except:
if "rs" in line:
lineToResend = int(line.split()[1])
if lineToResend is not None:
self._resendDelta = self._currentLine - lineToResend
if self._resendDelta > len(self._lastLines):
self._errorValue = "Printer requested line %d but history is only available up to line %d" % (lineToResend, self._currentLine - len(self._lastLines))
self._changeState(self.STATE_ERROR)
self._logger.warn(self._errorValue)
else:
self._resendNextCommand()
def _log(self, message):
self._callback.mcLog(message)
self._serialLogger.debug(message)
@ -527,62 +548,63 @@ class MachineCom(object):
self.close()
def _resendNextCommand(self):
self._logger.debug("Resending line %d, delta is %d, history log is %s items strong" % (self._currentLine - self._resendDelta, self._resendDelta, len(self._lastLines)))
cmd = self._lastLines[-self._resendDelta]
lineNumber = self._currentLine - self._resendDelta
# Make sure we are only handling one sending job at a time
with self._sendingLock:
self._logger.debug("Resending line %d, delta is %d, history log is %s items strong" % (self._currentLine - self._resendDelta, self._resendDelta, len(self._lastLines)))
cmd = self._lastLines[-self._resendDelta]
lineNumber = self._currentLine - self._resendDelta
self._doSendWithChecksum(cmd, lineNumber)
self._doSendWithChecksum(cmd, lineNumber)
self._resendDelta -= 1
if self._resendDelta <= 0:
self._resendDelta = None
self._resendDelta -= 1
if self._resendDelta <= 0:
self._resendDelta = None
def _sendCommand(self, cmd, sendChecksum=False):
cmd = cmd.upper()
#Wait for current send to finish.
while self._sending:
pass
self._sending = True
if self._serial is None:
return
if 'M109' in cmd or 'M190' in cmd:
self._heatupWaitStartTime = time.time()
if 'M104' in cmd or 'M109' in cmd:
try:
self._targetTemp = float(re.search('S([0-9]+)', cmd).group(1))
except:
pass
if 'M140' in cmd or 'M190' in cmd:
try:
self._bedTargetTemp = float(re.search('S([0-9]+)', cmd).group(1))
except:
pass
# Make sure we are only handling one sending job at a time
with self._sendingLock:
cmd = cmd.upper()
if "M110" in cmd:
newLineNumber = None
if " N" in cmd:
if self._serial is None:
return
if 'M109' in cmd or 'M190' in cmd:
self._heatupWaitStartTime = time.time()
if 'M104' in cmd or 'M109' in cmd:
try:
newLineNumber = int(re.search("N([0-9]+)", cmd).group(1))
self._targetTemp = float(re.search('S([0-9]+)', cmd).group(1))
except:
pass
if 'M140' in cmd or 'M190' in cmd:
try:
self._bedTargetTemp = float(re.search('S([0-9]+)', cmd).group(1))
except:
pass
else:
newLineNumber = 0
if settings().getBoolean(["feature", "resetLineNumbersWithPrefixedN"]) and newLineNumber is not None:
# let's rewrite the M110 command to fit repetier syntax
self._doSendWithChecksum("M110", newLineNumber)
self._addToLastLines(cmd)
self._currentLine = newLineNumber + 1
else:
self._doSend(cmd, sendChecksum)
if "M110" in cmd:
newLineNumber = None
if " N" in cmd:
try:
newLineNumber = int(re.search("N([0-9]+)", cmd).group(1))
except:
pass
else:
newLineNumber = 0
if settings().getBoolean(["feature", "resetLineNumbersWithPrefixedN"]) and newLineNumber is not None:
# let's rewrite the M110 command to fit repetier syntax
self._addToLastLines(cmd)
self._doSendWithChecksum("M110", newLineNumber)
else:
self._doSend(cmd, sendChecksum)
if newLineNumber is not None:
self._currentLine = newLineNumber + 1
# after a reset of the line number we have no way to determine what line exactly the printer now wants
self._lastLines = []
self._resendDelta = None
else:
self._doSend(cmd, sendChecksum)
# after a reset of the line number we have no way to determine what line exactly the printer now wants
self._lastLines = []
self._resendDelta = None
else:
self._doSend(cmd, sendChecksum)
def _addToLastLines(self, cmd):
self._lastLines.append(cmd)
@ -596,17 +618,15 @@ class MachineCom(object):
lineNumber = self._currentLine
else:
lineNumber = self._gcodePos
self._doSendWithChecksum(cmd, lineNumber)
self._addToLastLines(cmd)
self._currentLine += 1
self._doSendWithChecksum(cmd, lineNumber)
else:
self._doSendWithoutChecksum(cmd)
def _doSendWithChecksum(self, cmd, lineNumber=None):
def _doSendWithChecksum(self, cmd, lineNumber):
self._logger.debug("Sending cmd '%s' with lineNumber %r" % (cmd, lineNumber))
if lineNumber is None:
lineNumber = self._currentLine
checksum = reduce(lambda x,y:x^y, map(ord, "N%d%s" % (lineNumber, cmd)))
commandToSend = "N%d%s*%d" % (lineNumber, cmd, checksum)
self._doSendWithoutChecksum(commandToSend)
@ -627,8 +647,6 @@ class MachineCom(object):
self._log("Unexpected error while writing serial port: %s" % (getExceptionString()))
self._errorValue = getExceptionString()
self.close(True)
#clear sending flag
self._sending = False
def _sendNext(self):
if self._gcodePos >= len(self._gcodeList):