s.Add(wx.StaticText(p, -1, '(This dialog is only shown once)'))
s.Add(wx.StaticLine(p), flag=wx.EXPAND|wx.TOP|wx.BOTTOM, border=10)
s.Add(wx.StaticText(p, -1, 'New in this version:'))
- s.Add(wx.StaticText(p, -1, '* Fixed a rare bug that caused the CuraEngine to crash on some models.'))
- s.Add(wx.StaticText(p, -1, '* Added support for multiple Doodle3D boxes on the same network.'))
- s.Add(wx.StaticText(p, -1, '* Made it possible to switch between "all at once" and "one at a time printing"'))
- s.Add(wx.StaticText(p, -1, '* Improved USB communication stability.'))
- s.Add(wx.StaticText(p, -1, '* Improved USB auto-detection for none-Ultimaker printers.'))
- s.Add(wx.StaticText(p, -1, '* Set retraction enabled by default and in the quickprint profiles.'))
- s.Add(wx.StaticText(p, -1, '* Fixed a bug that caused loading of really small objects to fail.'))
- s.Add(wx.StaticText(p, -1, '* Made camera keyboard controls accessible in the GCode view, use shift+up/down for layer changes now.'))
+ s.Add(wx.StaticText(p, -1, '* Improved the LayerView rendering speed.'))
+ s.Add(wx.StaticText(p, -1, '* Made the LayerView update during slicing, so you can see the result before it is ready.'))
self.hasUltimaker = None
self.hasUltimaker2 = None
button = wx.Button(p, -1, 'Install now')
self.Bind(wx.EVT_BUTTON, self.OnUltimakerFirmware, button)
s.Add(button, flag=wx.TOP, border=5)
- if self.hasUltimaker2 is not None:
+ if self.hasUltimaker2 is not None and False:
s.Add(wx.StaticLine(p), flag=wx.EXPAND|wx.TOP|wx.BOTTOM, border=10)
s.Add(wx.StaticText(p, -1, 'New firmware for your Ultimaker2:'))
- s.Add(wx.StaticText(p, -1, '* Fixed the bug where aborting a print caused massive retraction.'))
- s.Add(wx.StaticText(p, -1, '* Fixed a bug where going into move-material when the printer was still moving caused a bed-crash.'))
- s.Add(wx.StaticText(p, -1, '* Added bed temperature when cooling down the printer.'))
- s.Add(wx.StaticText(p, -1, '* Allow abort if bed-leveling is selected.'))
+ s.Add(wx.StaticText(p, -1, '* .'))
button = wx.Button(p, -1, 'Install now')
self.Bind(wx.EVT_BUTTON, self.OnUltimaker2Firmware, button)
s.Add(button, flag=wx.TOP, border=5)
def OnPrintButton(self, button):
if button == 1:
connectionGroup = self._printerConnectionManager.getAvailableGroup()
- if machineCom.machineIsConnected():
- self.showPrintWindow()
- elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
+ if len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
drives = removableStorage.getPossibleSDcardDrives()
if len(drives) > 1:
dlg = wx.SingleChoiceDialog(self, "Select SD drive", "Multiple removable drives have been found,\nplease select your SD card drive", map(lambda n: n[0], drives))
self.showSaveGCode()
if button == 3:
menu = wx.Menu()
- self.Bind(wx.EVT_MENU, lambda e: self.showPrintWindow(), menu.Append(-1, _("Print with USB")))
connections = self._printerConnectionManager.getAvailableConnections()
menu.connectionMap = {}
for connection in connections:
else:
self.notification.message("Failed to start print...")
- def showPrintWindow(self):
- if self._gcodeFilename is None:
- return
- if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
- wx.MessageBox(_("USB printing on the Ultimaker2 is not supported."), _("USB Printing Error"), wx.OK | wx.ICON_WARNING)
- return
- #TODO: Fix for _engine.getResult
- self._usbPrintMonitor.loadFile(self._gcodeFilename, self._engine.getID())
- if self._gcodeFilename is None:
- self._engine.submitInfoOnline()
-
def showSaveGCode(self):
if len(self._scene._objectList) < 1:
return
def OnPaint(self,e):
connectionGroup = self._printerConnectionManager.getAvailableGroup()
- if machineCom.machineIsConnected():
- self.printButton._imageID = 6
- self.printButton._tooltip = _("Print")
- elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
+ if len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
self.printButton._imageID = 2
self.printButton._tooltip = _("Toolpath to SD")
elif connectionGroup is not None:
--- /dev/null
+__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
+
+# Serial communication with the printer for printing is done from a separate process,
+# this to ensure that the PIL does not block the serial printing.
+
+import sys
+import time
+import os
+
+from Cura.util import machineCom
+
+class serialComm(object):
+ def __init__(self, portName):
+ self._comm = None
+ self._gcodeList = []
+
+ self._comm = machineCom.MachineCom(portName, callbackObject=self)
+
+ def mcLog(self, message):
+ sys.stdout.write('log:%s\n' % (message))
+
+ def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
+ sys.stdout.write('temp:%s\n' % str(temp))
+
+ def mcStateChange(self, state):
+ if self._comm is None:
+ return
+ sys.stdout.write('state:%d:%s\n' % (state, self._comm.getStateString()))
+
+ def mcMessage(self, message):
+ sys.stdout.write('message:%s\n' % (message))
+
+ def mcProgress(self, lineNr):
+ sys.stdout.write('progress:%d\n' % (lineNr))
+
+ def mcZChange(self, newZ):
+ sys.stdout.write('changeZ:%d\n' % (newZ))
+
+ def monitorStdin(self):
+
+ while not self._comm.isClosed():
+ line = sys.stdin.readline().strip()
+ line = line.split(':', 1)
+ if line[0] == 'STOP':
+ self._comm.cancelPrint()
+ self._gcodeList = []
+ elif line[0] == 'G':
+ self._gcodeList.append(line[1])
+ elif line[0] == 'START':
+ self._comm.printGCode(self._gcodeList)
+ else:
+ sys.stderr.write(str(line))
+
+def main():
+ if len(sys.argv) != 2:
+ return
+ sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+ portName = sys.argv[1]
+ comm = serialComm(portName)
+ comm.monitorStdin()
+
+if __name__ == '__main__':
+ main()
return "?%d?" % (self._state)
def getShortErrorString(self):
- if len(self._errorValue) < 30:
+ if len(self._errorValue) < 35:
return self._errorValue
- return self._errorValue[:30] + "..."
+ return self._errorValue[:35] + "..."
def getErrorString(self):
return self._errorValue
-
+
+ def isClosed(self):
+ return self._state == self.STATE_CLOSED_WITH_ERROR or self._state == self.STATE_CLOSED
+
def isClosedOrError(self):
return self._state == self.STATE_ERROR or self._state == self.STATE_CLOSED_WITH_ERROR or self._state == self.STATE_CLOSED
def checkPlatform(self, obj):
area = obj._printAreaHull + obj.getPosition()
+ if obj.getSize()[2] > self._machineSize[2]:
+ return False
if not polygon.fullInside(area, self._machinePolygons[0]):
return False
#Check the "no go zones"
def getPriority(self):
return 100
- def __cmp__(self, other):
- return self.getPriority() - other.getPriority()
-
- def __repr__(self):
- return self.name
-
def _doodle3DThread(self):
self._waitDelay = 0
while True:
def getAvailableConnections(self):
return self._list
+ def getIconID(self):
+ return 5
+
+ def getPriority(self):
+ return -100
+
#Dummy printer class which is always
class dummyConnection(printerConnectionBase.printerConnectionBase):
def __init__(self, name):
return 5
def getPriority(self):
- return -1
+ return -100
def __cmp__(self, other):
return self.getPriority() - other.getPriority()
def __repr__(self):
- return self.name
+ return '%s %d' % (self._name, self.getPriority())
#Base class for different printer connection implementations.
# A printer connection can connect to printers in different ways, trough network, USB or carrier pigeons.
from Cura.util import version
from Cura.util.printerConnection import dummyConnection
+from Cura.util.printerConnection import serialConnection
from Cura.util.printerConnection import doodle3dConnect
class PrinterConnectionManager(object):
self._groupList = []
if version.isDevVersion():
self._groupList.append(dummyConnection.dummyConnectionGroup())
+ self._groupList.append(serialConnection.serialConnectionGroup())
self._groupList.append(doodle3dConnect.doodle3dConnectionGroup())
#Sort the connections by highest priority first.
--- /dev/null
+__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
+
+import threading
+import time
+import platform
+import os
+import sys
+import subprocess
+
+from Cura.util import machineCom
+from Cura.util.printerConnection import printerConnectionBase
+
+class serialConnectionGroup(printerConnectionBase.printerConnectionGroup):
+ def __init__(self):
+ super(serialConnectionGroup, self).__init__("USB")
+ self._connectionMap = {}
+
+ def getAvailableConnections(self):
+ serialList = machineCom.serialList(True)
+ for port in machineCom.serialList(True):
+ if port not in self._connectionMap:
+ self._connectionMap[port] = serialConnection(port)
+ for key in self._connectionMap.keys():
+ if key not in serialList and not self._connectionMap[key].isActiveConnectionOpen():
+ self._connectionMap[key] = None
+ return self._connectionMap.values()
+
+ def getIconID(self):
+ return 6
+
+ def getPriority(self):
+ return 50
+
+class serialConnection(printerConnectionBase.printerConnectionBase):
+ def __init__(self, port):
+ super(serialConnection, self).__init__(port)
+ self._portName = port
+
+ self._process = None
+ self._thread = None
+
+ self._lineCount = 0
+ self._commState = None
+ self._commStateString = None
+ self._gcodeData = []
+
+ #Load the data into memory for printing, returns True on success
+ def loadGCodeData(self, dataStream):
+ if self.isPrinting() is None:
+ return False
+ self._gcodeData = []
+ for line in dataStream:
+ #Strip out comments, we do not need to send comments
+ if ';' in line:
+ line = line[:line.index(';')]
+ #Strip out whitespace at the beginning/end this saves data to send.
+ line = line.strip()
+
+ if len(line) < 1:
+ continue
+ self._gcodeData.append(line)
+ return True
+
+ #Start printing the previously loaded file
+ def startPrint(self):
+ if self.isPrinting() or len(self._gcodeData) < 1 or self._process is None:
+ return
+ self._process.stdin.write('STOP\n')
+ for line in self._gcodeData:
+ self._process.stdin.write('G:%s\n' % (line))
+ self._process.stdin.write('START\n')
+
+ #Abort the previously loaded print file
+ def cancelPrint(self):
+ pass
+
+ def isPrinting(self):
+ return self._commState == machineCom.MachineCom.STATE_PRINTING
+
+ #Amount of progression of the current print file. 0.0 to 1.0
+ def getPrintProgress(self):
+ if self._lineCount < 1:
+ return 0.0
+ return float(self._progressLine) / float(self._lineCount)
+
+ # Return if the printer with this connection type is available
+ def isAvailable(self):
+ return True
+
+ # Get the connection status string. This is displayed to the user and can be used to communicate
+ # various information to the user.
+ def getStatusString(self):
+ return "%s" % (self._commStateString)
+
+ #Returns true if we need to establish an active connection. True for serial connections.
+ def hasActiveConnection(self):
+ return True
+
+ #Open the active connection to the printer so we can send commands
+ def openActiveConnection(self):
+ self.closeActiveConnection()
+ self._thread = threading.Thread(target=self._serialCommunicationThread)
+ self._thread.daemon = True
+ self._thread.start()
+
+ #Close the active connection to the printer
+ def closeActiveConnection(self):
+ if self._process is not None:
+ self._process.terminate()
+ self._thread.join()
+
+ #Is the active connection open right now.
+ def isActiveConnectionOpen(self):
+ if self._process is None:
+ return False
+ return self._commState == machineCom.MachineCom.STATE_OPERATIONAL or self._commState == machineCom.MachineCom.STATE_PRINTING or self._commState == machineCom.MachineCom.STATE_PAUSED
+
+ def _serialCommunicationThread(self):
+ if platform.system() == "Darwin" and hasattr(sys, 'frozen'):
+ cmdList = [os.path.join(os.path.dirname(sys.executable), 'Cura')]
+ else:
+ cmdList = [sys.executable, '-m', 'Cura.serialCommunication']
+ cmdList += [self._portName]
+ if platform.system() == "Darwin":
+ if platform.machine() == 'i386':
+ cmdList = ['arch', '-i386'] + cmdList
+ self._process = subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ line = self._process.stdout.readline()
+ while len(line) > 0:
+ line = line.strip()
+ line = line.split(':', 1)
+ if line[0] == 'log':
+ pass
+ elif line[0] == 'temp':
+ pass
+ elif line[0] == 'state':
+ line = line[1].split(':', 1)
+ self._commState = int(line[0])
+ self._commStateString = line[1]
+ self._doCallback()
+ else:
+ print line
+ line = self._process.stdout.readline()
+ self._process = None
extruderCount = max(extruderCount, profile.minimalExtruderCount())
- commandList = [getEngineFilename(), '-vvv']
+ commandList = [getEngineFilename(), '-v', '-p']
for k, v in self._engineSettings(extruderCount).iteritems():
commandList += ['-s', '%s=%s' % (k, str(v))]
commandList += ['-g', '%d' % self._serverPortNr]