Major update on machine communication. Part 1, this breaks realtime speed tuning, pausing, M0/M1, height reporting and timelaps recording. But it is worth it.
parent
1f7924688d
commit
9c47af5797
|
@ -68,11 +68,13 @@ class PrintCommandButton(buttons.GenBitmapButton):
|
|||
self.Bind(wx.EVT_BUTTON, self.OnClick)
|
||||
|
||||
def OnClick(self, e):
|
||||
if self.parent.printIdx != None:
|
||||
if self.parent.machineCom == None or self.parent.machineCom.isPrinting():
|
||||
return;
|
||||
self.parent.sendCommand("G91")
|
||||
self.parent.sendCommand(self.command)
|
||||
self.parent.sendCommand("G90")
|
||||
if self.command.startswith('G1'):
|
||||
self.parent.machineCom.sendCommand("G91")
|
||||
self.parent.machineCom.sendCommand(self.command)
|
||||
if self.command.startswith('G1'):
|
||||
self.parent.machineCom.sendCommand("G90")
|
||||
e.Skip()
|
||||
|
||||
class printWindow(wx.Frame):
|
||||
|
@ -80,12 +82,9 @@ class printWindow(wx.Frame):
|
|||
def __init__(self):
|
||||
super(printWindow, self).__init__(None, -1, title='Printing')
|
||||
self.machineCom = None
|
||||
self.machineConnected = False
|
||||
self.thread = None
|
||||
self.gcode = None
|
||||
self.gcodeList = None
|
||||
self.sendList = []
|
||||
self.printIdx = None
|
||||
self.temp = None
|
||||
self.bedTemp = None
|
||||
self.bufferLineCount = 4
|
||||
|
@ -114,7 +113,7 @@ class printWindow(wx.Frame):
|
|||
|
||||
sb = wx.StaticBox(self.panel, label="Statistics")
|
||||
boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
|
||||
self.statsText = wx.StaticText(self.panel, -1, "Filament: ####.##m #.##g\nPrint time: #####:##")
|
||||
self.statsText = wx.StaticText(self.panel, -1, "Filament: ####.##m #.##g\nPrint time: #####:##\nMachine state: Detecting baudrate")
|
||||
boxsizer.Add(self.statsText, flag=wx.LEFT, border=5)
|
||||
|
||||
self.sizer.Add(boxsizer, pos=(0,0), span=(5,1), flag=wx.EXPAND)
|
||||
|
@ -276,10 +275,10 @@ class printWindow(wx.Frame):
|
|||
self.Centre()
|
||||
|
||||
self.UpdateButtonStates()
|
||||
self.UpdateProgress()
|
||||
#self.UpdateProgress()
|
||||
|
||||
def OnCameraTimer(self, e):
|
||||
if self.printIdx != None:
|
||||
if self.machineCom != None and not self.machineCom.isPrinting():
|
||||
return
|
||||
self.cam.takeNewImage()
|
||||
self.camPage.Refresh()
|
||||
|
@ -296,14 +295,14 @@ class printWindow(wx.Frame):
|
|||
dc.DrawBitmap(self.cam.getLastImage(), 0, 0)
|
||||
|
||||
def UpdateButtonStates(self):
|
||||
self.connectButton.Enable(not self.machineConnected)
|
||||
self.connectButton.Enable(self.machineCom == None or self.machineCom.isClosedOrError())
|
||||
#self.loadButton.Enable(self.printIdx == None)
|
||||
self.printButton.Enable(self.machineConnected and self.gcodeList != None and self.printIdx == None)
|
||||
self.pauseButton.Enable(self.printIdx != None)
|
||||
self.cancelButton.Enable(self.printIdx != None)
|
||||
self.temperatureSelect.Enable(self.machineConnected)
|
||||
self.bedTemperatureSelect.Enable(self.machineConnected)
|
||||
self.directControlPanel.Enable(self.machineConnected)
|
||||
self.printButton.Enable(self.machineCom != None and self.machineCom.isOperational() and not self.machineCom.isPrinting())
|
||||
self.pauseButton.Enable(self.machineCom != None and self.machineCom.isPrinting())
|
||||
self.cancelButton.Enable(self.machineCom != None and self.machineCom.isPrinting())
|
||||
self.temperatureSelect.Enable(self.machineCom != None and self.machineCom.isOperational())
|
||||
self.bedTemperatureSelect.Enable(self.machineCom != None and self.machineCom.isOperational())
|
||||
self.directControlPanel.Enable(self.machineCom != None and self.machineCom.isOperational())
|
||||
|
||||
def UpdateProgress(self):
|
||||
status = ""
|
||||
|
@ -315,68 +314,62 @@ class printWindow(wx.Frame):
|
|||
if cost != False:
|
||||
status += "Filament cost: %s\n" % (cost)
|
||||
status += "Print time: %02d:%02d\n" % (int(self.gcode.totalMoveTimeMinute / 60), int(self.gcode.totalMoveTimeMinute % 60))
|
||||
if self.printIdx == None:
|
||||
if self.machineCom == None or not self.machineCom.isPrinting():
|
||||
self.progress.SetValue(0)
|
||||
if self.gcodeList != None:
|
||||
status += 'Line: -/%d\n' % (len(self.gcodeList))
|
||||
else:
|
||||
status += 'Line: %d/%d\n' % (self.printIdx, len(self.gcodeList))
|
||||
status += 'Line: %d/%d\n' % (self.machineCom.getPrintPos(), len(self.gcodeList))
|
||||
status += 'Height: %f\n' % (self.currentZ)
|
||||
self.progress.SetValue(self.printIdx)
|
||||
if self.temp != None:
|
||||
status += 'Temp: %d\n' % (self.temp)
|
||||
if self.bedTemp != None and self.bedTemp > 0:
|
||||
status += 'Bed Temp: %d\n' % (self.bedTemp)
|
||||
self.bedTemperatureLabel.Show(True)
|
||||
self.bedTemperatureSelect.Show(True)
|
||||
self.temperaturePanel.Layout()
|
||||
self.progress.SetValue(self.machineCom.getPrintPos())
|
||||
if self.machineCom != None:
|
||||
if self.machineCom.getTemp() > 0:
|
||||
status += 'Temp: %d\n' % (self.machineCom.getTemp())
|
||||
if self.machineCom.getBedTemp() > 0:
|
||||
status += 'Bed Temp: %d\n' % (self.machineCom.getBedTemp())
|
||||
self.bedTemperatureLabel.Show(True)
|
||||
self.bedTemperatureSelect.Show(True)
|
||||
self.temperaturePanel.Layout()
|
||||
status += 'Machine state: %s\n' % (self.machineCom.getStateString())
|
||||
|
||||
self.statsText.SetLabel(status.strip())
|
||||
#self.Layout()
|
||||
|
||||
def OnConnect(self, e):
|
||||
if self.machineCom != None:
|
||||
self.machineCom.close()
|
||||
self.thread.join()
|
||||
self.machineCom = machineCom.MachineCom()
|
||||
self.thread = threading.Thread(target=self.PrinterMonitor)
|
||||
self.thread.start()
|
||||
self.machineCom = machineCom.MachineCom(callbackObject=self)
|
||||
self.UpdateButtonStates()
|
||||
|
||||
def OnLoad(self, e):
|
||||
pass
|
||||
|
||||
def OnPrint(self, e):
|
||||
if not self.machineConnected:
|
||||
if self.machineCom == None or not self.machineCom.isOperational():
|
||||
return
|
||||
if self.gcodeList == None:
|
||||
return
|
||||
if self.printIdx != None:
|
||||
if self.machineCom.isPrinting():
|
||||
return
|
||||
self.currentZ = -1
|
||||
if self.cam != None:
|
||||
self.cam.startTimelaps(self.filename[: self.filename.rfind('.')] + ".mpg")
|
||||
self.printIdx = 1
|
||||
self.sendLine(0)
|
||||
self.sendCnt = self.bufferLineCount
|
||||
self.machineCom.printGCode(self.gcodeList)
|
||||
self.UpdateButtonStates()
|
||||
|
||||
def OnCancel(self, e):
|
||||
if self.cam != None:
|
||||
self.cam.endTimelaps()
|
||||
self.printIdx = None
|
||||
self.pause = False
|
||||
self.pauseButton.SetLabel('Pause')
|
||||
self.sendCommand("M84")
|
||||
self.machineCom.cancelPrint()
|
||||
self.machineCom.sendCommand("M84")
|
||||
self.UpdateButtonStates()
|
||||
|
||||
def OnPause(self, e):
|
||||
if self.pause:
|
||||
self.pause = False
|
||||
self.sendLine(self.printIdx)
|
||||
self.printIdx += 1
|
||||
if self.machineCom.isPaused():
|
||||
self.machineCom.setPause(False)
|
||||
self.pauseButton.SetLabel('Pause')
|
||||
else:
|
||||
self.pause = True
|
||||
self.machineCom.setPause(True)
|
||||
self.pauseButton.SetLabel('Resume')
|
||||
|
||||
def OnClose(self, e):
|
||||
|
@ -384,14 +377,13 @@ class printWindow(wx.Frame):
|
|||
printWindowHandle = None
|
||||
if self.machineCom != None:
|
||||
self.machineCom.close()
|
||||
self.thread.join()
|
||||
self.Destroy()
|
||||
|
||||
def OnTempChange(self, e):
|
||||
self.sendCommand("M104 S%d" % (self.temperatureSelect.GetValue()))
|
||||
self.machineCom.sendCommand("M104 S%d" % (self.temperatureSelect.GetValue()))
|
||||
|
||||
def OnBedTempChange(self, e):
|
||||
self.sendCommand("M140 S%d" % (self.bedTemperatureSelect.GetValue()))
|
||||
self.machineCom.sendCommand("M140 S%d" % (self.bedTemperatureSelect.GetValue()))
|
||||
|
||||
def OnSpeedChange(self, e):
|
||||
self.feedrateRatioOuterWall = self.outerWallSpeedSelect.GetValue() / 100.0
|
||||
|
@ -407,7 +399,7 @@ class printWindow(wx.Frame):
|
|||
if line == '':
|
||||
return
|
||||
self.termLog.AppendText('>%s\n' % (line))
|
||||
self.sendCommand(line)
|
||||
self.machineCom.sendCommand(line)
|
||||
self.termHistory.append(line)
|
||||
self.termHistoryIdx = len(self.termHistory)
|
||||
self.termInput.SetValue('')
|
||||
|
@ -427,7 +419,7 @@ class printWindow(wx.Frame):
|
|||
e.Skip()
|
||||
|
||||
def LoadGCodeFile(self, filename):
|
||||
if self.printIdx != None:
|
||||
if self.machineCom != None and self.machineCom.isPrinting():
|
||||
return
|
||||
#Send an initial M110 to reset the line counter to zero.
|
||||
lineType = 'CUSTOM'
|
||||
|
@ -454,13 +446,6 @@ class printWindow(wx.Frame):
|
|||
wx.CallAfter(self.UpdateButtonStates)
|
||||
wx.CallAfter(self.UpdateProgress)
|
||||
|
||||
def sendCommand(self, cmd):
|
||||
if self.machineConnected:
|
||||
if self.printIdx == None or self.pause:
|
||||
self.machineCom.sendCommand(cmd)
|
||||
else:
|
||||
self.sendList.append(cmd)
|
||||
|
||||
def sendLine(self, lineNr):
|
||||
if lineNr >= len(self.gcodeList):
|
||||
return False
|
||||
|
@ -495,58 +480,22 @@ class printWindow(wx.Frame):
|
|||
self.machineCom.sendCommand("N%d%s*%d" % (lineNr, line, checksum))
|
||||
return True
|
||||
|
||||
def PrinterMonitor(self):
|
||||
while True:
|
||||
line = self.machineCom.readline()
|
||||
if line == None:
|
||||
self.machineConnected = False
|
||||
wx.CallAfter(self.UpdateButtonStates)
|
||||
return
|
||||
if line == '': #When we have a communication "timeout" and we're not sending gcode, then read the temperature.
|
||||
if self.printIdx == None or self.pause:
|
||||
self.machineCom.sendCommand("M105")
|
||||
else:
|
||||
wx.CallAfter(self.AddTermLog, '!!Comm timeout, forcing next line!!\n')
|
||||
line = 'ok'
|
||||
if self.machineConnected:
|
||||
while self.sendCnt > 0 and not self.pause:
|
||||
self.sendLine(self.printIdx)
|
||||
self.printIdx += 1
|
||||
self.sendCnt -= 1
|
||||
if line.startswith("start"):
|
||||
self.machineConnected = True
|
||||
wx.CallAfter(self.UpdateButtonStates)
|
||||
elif 'T:' in line:
|
||||
self.temp = float(re.search("[0-9\.]*", line.split('T:')[1]).group(0))
|
||||
if 'B:' in line:
|
||||
self.bedTemp = float(re.search("[0-9\.]*", line.split('B:')[1]).group(0))
|
||||
self.temperatureGraph.addPoint(self.temp, self.temperatureSelect.GetValue(), self.bedTemp, self.bedTemperatureSelect.GetValue())
|
||||
wx.CallAfter(self.UpdateProgress)
|
||||
elif line.strip() != 'ok':
|
||||
wx.CallAfter(self.AddTermLog, line)
|
||||
if self.printIdx != None:
|
||||
if line.startswith("ok"):
|
||||
if len(self.sendList) > 0:
|
||||
self.machineCom.sendCommand(self.sendList.pop(0))
|
||||
elif self.pause:
|
||||
self.sendCnt += 1
|
||||
else:
|
||||
if self.sendLine(self.printIdx):
|
||||
self.printIdx += 1
|
||||
else:
|
||||
if self.cam != None:
|
||||
self.cam.endTimelaps()
|
||||
self.printIdx = None
|
||||
wx.CallAfter(self.UpdateButtonStates)
|
||||
wx.CallAfter(self.UpdateProgress)
|
||||
elif "resend" in line.lower() or "rs" in line:
|
||||
try:
|
||||
lineNr=int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])
|
||||
except:
|
||||
if "rs" in line:
|
||||
lineNr=int(line.split()[1])
|
||||
self.printIdx = lineNr
|
||||
#we should actually resend the line here, but we also get an "ok" for each error from Marlin. And thus we'll resend on the OK.
|
||||
def mcLog(self, message):
|
||||
#print message
|
||||
pass
|
||||
|
||||
def mcTempUpdate(self, temp, bedTemp):
|
||||
self.temperatureGraph.addPoint(temp, self.temperatureSelect.GetValue(), bedTemp, self.bedTemperatureSelect.GetValue())
|
||||
|
||||
def mcStateChange(self, state):
|
||||
wx.CallAfter(self.UpdateButtonStates)
|
||||
wx.CallAfter(self.UpdateProgress)
|
||||
|
||||
def mcMessage(self, message):
|
||||
wx.CallAfter(self.AddTermLog, message)
|
||||
|
||||
def mcProgress(self, lineNr):
|
||||
wx.CallAfter(self.UpdateProgress)
|
||||
|
||||
class temperatureGraph(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from __future__ import absolute_import
|
||||
import __init__
|
||||
|
||||
import os, glob, sys, time, math, traceback
|
||||
import os, glob, sys, time, math, re, traceback, threading
|
||||
import Queue as queue
|
||||
|
||||
from serial import Serial
|
||||
|
||||
|
@ -84,9 +85,33 @@ class VirtualPrinter():
|
|||
def close(self):
|
||||
self.readList = None
|
||||
|
||||
class MachineCom():
|
||||
def __init__(self, port = None, baudrate = None, logCallback = None):
|
||||
self._logCallback = logCallback
|
||||
class MachineComPrintCallback(object):
|
||||
def mcLog(self, message):
|
||||
print(message)
|
||||
|
||||
def mcTempUpdate(self, temp, bedTemp):
|
||||
pass
|
||||
|
||||
def mcStateChange(self, state):
|
||||
pass
|
||||
|
||||
def mcMessage(self, message):
|
||||
pass
|
||||
|
||||
def mcProgress(self, lineNr):
|
||||
pass
|
||||
|
||||
class MachineCom(object):
|
||||
STATE_NONE = 0
|
||||
STATE_DETECT_BAUDRATE = 1
|
||||
STATE_CONNECTING = 2
|
||||
STATE_OPERATIONAL = 3
|
||||
STATE_PRINTING = 4
|
||||
STATE_CLOSED = 5
|
||||
STATE_ERROR = 6
|
||||
STATE_CLOSED_WITH_ERROR = 7
|
||||
|
||||
def __init__(self, port = None, baudrate = None, callbackObject = None):
|
||||
if port == None:
|
||||
port = profile.getPreference('serial_port')
|
||||
if baudrate == None:
|
||||
|
@ -94,7 +119,21 @@ class MachineCom():
|
|||
baudrate = 0
|
||||
else:
|
||||
baudrate = int(profile.getPreference('serial_baud'))
|
||||
if callbackObject == None:
|
||||
callbackObject = MachineComPrintCallback()
|
||||
|
||||
self._callback = callbackObject
|
||||
self._state = self.STATE_NONE
|
||||
self._serial = None
|
||||
self._baudrateDetectList = baudrateList()
|
||||
self._baudrateDetectRetry = 0
|
||||
self._temp = 0
|
||||
self._bedTemp = 0
|
||||
self._gcodeList = None
|
||||
self._gcodePos = 0
|
||||
self._commandQueue = queue.Queue()
|
||||
self._logQueue = queue.Queue(256)
|
||||
|
||||
if port == 'AUTO':
|
||||
programmer = stk500v2.Stk500v2()
|
||||
self._log("Serial port list: %s" % (str(serialList())))
|
||||
|
@ -103,83 +142,200 @@ class MachineCom():
|
|||
self._log("Connecting to: %s" % (port))
|
||||
programmer.connect(port)
|
||||
self._serial = programmer.leaveISP()
|
||||
self._configureSerialWithBaudrate(baudrate)
|
||||
break
|
||||
except ispBase.IspError as (e):
|
||||
self._log("Error while connecting to %s: %s" % (port, str(e)))
|
||||
pass
|
||||
except:
|
||||
self._log("Unexpected error while connecting to serial port: %s %s" % (port, getExceptionString()))
|
||||
programmer.close()
|
||||
programmer.close()
|
||||
elif port == 'VIRTUAL':
|
||||
self._serial = VirtualPrinter()
|
||||
else:
|
||||
try:
|
||||
self._serial = Serial(port, 115200, timeout=2)
|
||||
self._configureSerialWithBaudrate(baudrate)
|
||||
self._log("Connecting to: %s" % (port))
|
||||
if baudrate == 0:
|
||||
self._serial = Serial(port, 115200, timeout=0.1)
|
||||
else:
|
||||
self._serial = Serial(port, baudrate, timeout=2)
|
||||
except:
|
||||
self._log("Unexpected error while connecting to serial port: %s %s" % (port, getExceptionString()))
|
||||
print
|
||||
print self._serial
|
||||
self._log("Connected to: %s, starting monitor" % (self._serial))
|
||||
if baudrate == 0:
|
||||
self._changeState(self.STATE_DETECT_BAUDRATE)
|
||||
else:
|
||||
self._changeState(self.STATE_CONNECTING)
|
||||
self.thread = threading.Thread(target=self._monitor)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
|
||||
def _configureSerialWithBaudrate(self, baudrate):
|
||||
if baudrate != 0:
|
||||
self._serial.baudrate = baudrate
|
||||
def _changeState(self, newState):
|
||||
if self._state == newState:
|
||||
return
|
||||
for baudrate in baudrateList():
|
||||
try:
|
||||
self._serial.baudrate = baudrate
|
||||
self._log("Trying baudrate: %d" % (baudrate))
|
||||
except:
|
||||
self._log("Unexpected error while setting baudrate: %d %s" % (baudrate, getExceptionString()))
|
||||
continue
|
||||
time.sleep(0.5)
|
||||
starttime = time.time()
|
||||
self.sendCommand("\nM105")
|
||||
for line in self._serial:
|
||||
self._log("Recv: %s" % (unicode(line, 'utf-8', 'replace').rstrip()))
|
||||
if 'start' in line:
|
||||
return
|
||||
oldState = self.getStateString()
|
||||
self._state = newState
|
||||
self._log('Changing monitoring state from \'%s\' to \'%s\'' % (oldState, self.getStateString()))
|
||||
self._callback.mcStateChange(newState)
|
||||
|
||||
def getState(self):
|
||||
return self._state
|
||||
|
||||
def getStateString(self):
|
||||
if self._state == self.STATE_NONE:
|
||||
return "Offline"
|
||||
if self._state == self.STATE_DETECT_BAUDRATE:
|
||||
return "Detect baudrate"
|
||||
if self._state == self.STATE_CONNECTING:
|
||||
return "Connecting"
|
||||
if self._state == self.STATE_OPERATIONAL:
|
||||
return "Operational"
|
||||
if self._state == self.STATE_PRINTING:
|
||||
return "Printing"
|
||||
if self._state == self.STATE_CLOSED:
|
||||
return "Closed"
|
||||
if self._state == self.STATE_ERROR:
|
||||
return "Error: %s" % (self._errorValue)
|
||||
if self._state == self.STATE_CLOSED_WITH_ERROR:
|
||||
return "Error: %s" % (self._errorValue)
|
||||
return "?%d?" % (self._state)
|
||||
|
||||
def isClosedOrError(self):
|
||||
return self._state == self.STATE_ERROR or self._state == self.STATE_CLOSED_WITH_ERROR or self._state == self.STATE_CLOSED
|
||||
|
||||
def isOperational(self):
|
||||
return self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PRINTING
|
||||
|
||||
def isPrinting(self):
|
||||
return self._state == self.STATE_PRINTING
|
||||
|
||||
def getPrintPos(self):
|
||||
return self._gcodePos
|
||||
|
||||
def isPaused(self):
|
||||
return False
|
||||
|
||||
def getTemp(self):
|
||||
return self._temp
|
||||
|
||||
def getBedTemp(self):
|
||||
return self._bedTemp
|
||||
|
||||
def _monitor(self):
|
||||
self._timeoutTime = time.time() + 5
|
||||
while True:
|
||||
line = self._readline()
|
||||
if line == None:
|
||||
break
|
||||
|
||||
#No matter the state, if we see an error, goto the error state and store the error for reference.
|
||||
if line.startswith('Error: '):
|
||||
#Oh YEAH, consistency.
|
||||
# Marlin reports an MIN/MAX temp error as "Error: x\n: Extruder switched off. MAXTEMP triggered !\n"
|
||||
# But a bed temp error is reported as "Error: Temperature heated bed switched off. MAXTEMP triggered !!"
|
||||
# So we can have an extra newline in the most common case. Awesome work people.
|
||||
if re.match('Error: [0-9]\n', line):
|
||||
line = line.rstrip() + self._readline()
|
||||
self._errorValue = line
|
||||
self._changeState(self.STATE_ERROR)
|
||||
if 'T:' in line:
|
||||
self._temp = float(re.search("[0-9\.]*", line.split('T:')[1]).group(0))
|
||||
if 'B:' in line:
|
||||
self._bedTemp = float(re.search("[0-9\.]*", line.split('B:')[1]).group(0))
|
||||
self._callback.mcTempUpdate(self._temp, self._bedTemp)
|
||||
elif line.strip() != 'ok':
|
||||
self._callback.mcMessage(line)
|
||||
|
||||
if self._state == self.STATE_DETECT_BAUDRATE:
|
||||
if line == '' or time.time() > self._timeoutTime:
|
||||
if len(self._baudrateDetectList) < 1:
|
||||
self._log("No more baudrates to test, and no suitable baudrate found.")
|
||||
self.close()
|
||||
elif self._baudrateDetectRetry > 0:
|
||||
self._baudrateDetectRetry -= 1
|
||||
self._serial.write('\n')
|
||||
self._sendCommand("M105")
|
||||
else:
|
||||
baudrate = self._baudrateDetectList.pop(0)
|
||||
try:
|
||||
self._serial.baudrate = baudrate
|
||||
self._serial.timeout = 0.5
|
||||
self._log("Trying baudrate: %d" % (baudrate))
|
||||
self._baudrateDetectRetry = 5
|
||||
self._timeoutTime = time.time() + 5
|
||||
self._serial.write('\n')
|
||||
self._sendCommand("M105")
|
||||
except:
|
||||
self._log("Unexpected error while setting baudrate: %d %s" % (baudrate, getExceptionString()))
|
||||
elif 'ok' in line:
|
||||
self._serial.timeout = 2
|
||||
self._changeState(self.STATE_OPERATIONAL)
|
||||
elif self._state == self.STATE_CONNECTING:
|
||||
if line == '':
|
||||
self._sendCommand("M105")
|
||||
elif 'ok' in line:
|
||||
self._changeState(self.STATE_OPERATIONAL)
|
||||
if time.time() > self._timeoutTime:
|
||||
self.close()
|
||||
elif self._state == self.STATE_OPERATIONAL:
|
||||
#Request the temperature on comm timeout (every 2 seconds) when we are not printing.
|
||||
if line == '':
|
||||
self._sendCommand("M105")
|
||||
elif self._state == self.STATE_PRINTING:
|
||||
if line == '' and time.time() > self._timeoutTime:
|
||||
self._log("Communication timeout during printing, forcing a line")
|
||||
line = 'ok'
|
||||
if 'ok' in line:
|
||||
return
|
||||
#Timeout in case we get a lot of crap data from some random device.
|
||||
if starttime - time.time() > 5:
|
||||
break
|
||||
self._serial.close()
|
||||
self._serial = None
|
||||
self._timeoutTime = time.time() + 5
|
||||
if not self._commandQueue.empty():
|
||||
self._sendCommand(self._commandQueue.get())
|
||||
else:
|
||||
self._sendNext()
|
||||
elif "resend" in line.lower() or "rs" in line:
|
||||
try:
|
||||
self._gcodePos = int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])
|
||||
except:
|
||||
if "rs" in line:
|
||||
self._gcodePos = int(line.split()[1])
|
||||
self._log("Connection closed, closing down monitor")
|
||||
|
||||
def _log(self, message):
|
||||
if self._logCallback != None:
|
||||
self._logCallback(message)
|
||||
else:
|
||||
print(message)
|
||||
self._callback.mcLog(message)
|
||||
try:
|
||||
self._logQueue.put(message, False)
|
||||
except:
|
||||
#If the log queue is full, remove the first message and append the new message again
|
||||
self._logQueue.get()
|
||||
self._logQueue.put(message, False)
|
||||
|
||||
def readline(self):
|
||||
def _readline(self):
|
||||
if self._serial == None:
|
||||
return None
|
||||
try:
|
||||
ret = self._serial.readline()
|
||||
except:
|
||||
self._log("Unexpected error while reading serial port: %s" % (getExceptionString()))
|
||||
self._errorValue = getExceptionString()
|
||||
self.close(True)
|
||||
return None
|
||||
if ret == '':
|
||||
#self._log("Recv: TIMEOUT")
|
||||
return ''
|
||||
if ret != '':
|
||||
self._log("Recv: %s" % (unicode(ret, 'utf-8', 'replace').rstrip()))
|
||||
else:
|
||||
self._log("Recv: TIMEOUT")
|
||||
self._log("Recv: %s" % (unicode(ret, 'ascii', 'replace').rstrip()))
|
||||
return ret
|
||||
|
||||
def close(self):
|
||||
def close(self, isError = False):
|
||||
if self._serial != None:
|
||||
self._serial.close()
|
||||
if isError:
|
||||
self._changeState(self.STATE_CLOSED_WITH_ERROR)
|
||||
else:
|
||||
self._changeState(self.STATE_CLOSED)
|
||||
self._serial = None
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def isOpen(self):
|
||||
return self._serial != None
|
||||
|
||||
def sendCommand(self, cmd):
|
||||
def _sendCommand(self, cmd):
|
||||
if self._serial == None:
|
||||
return
|
||||
self._log('Send: %s' % (cmd))
|
||||
|
@ -188,6 +344,38 @@ class MachineCom():
|
|||
self._serial.write('\n')
|
||||
except:
|
||||
self._log("Unexpected error while writing serial port: %s" % (getExceptionString()))
|
||||
self._errorValue = getExceptionString()
|
||||
self.close(True)
|
||||
|
||||
def _sendNext(self):
|
||||
if self._gcodePos >= len(self._gcodeList):
|
||||
self._changeState(self.STATE_OPERATIONAL)
|
||||
return
|
||||
line = self._gcodeList[self._gcodePos]
|
||||
checksum = reduce(lambda x,y:x^y, map(ord, "N%d%s" % (self._gcodePos, line)))
|
||||
self._sendCommand("N%d%s*%d" % (self._gcodePos, line, checksum))
|
||||
self._gcodePos += 1
|
||||
self._callback.mcProgress(self._gcodePos)
|
||||
|
||||
def sendCommand(self, cmd):
|
||||
cmd = cmd.encode('ascii', 'replace')
|
||||
if self.isPrinting():
|
||||
self._commandQueue.put(cmd)
|
||||
elif self.isOperational():
|
||||
self._sendCommand(cmd)
|
||||
|
||||
def printGCode(self, gcodeList):
|
||||
if not self.isOperational() or self.isPrinting():
|
||||
return
|
||||
self._gcodeList = gcodeList
|
||||
self._gcodePos = 0
|
||||
self._changeState(self.STATE_PRINTING)
|
||||
for i in xrange(0, 6):
|
||||
self._sendNext()
|
||||
|
||||
def cancelPrint(self):
|
||||
if self.isOperational():
|
||||
self._changeState(self.STATE_OPERATIONAL)
|
||||
|
||||
def getExceptionString():
|
||||
locationInfo = traceback.extract_tb(sys.exc_info()[2])[0]
|
||||
|
|
Loading…
Reference in New Issue