-__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
-import os, struct, sys, time
+"""
+General interface for Isp based AVR programmers.
+The ISP AVR programmer can load firmware into AVR chips. Which are commonly used on 3D printers.
-from serial import Serial
+ Needs to be subclassed to support different programmers.
+ Currently only the stk500v2 subclass exists.
+"""
+__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import chipDB
class IspBase():
+ """
+ Base class for ISP based AVR programmers.
+ Functions in this class raise an IspError when something goes wrong.
+ """
def programChip(self, flashData):
+ """ Program a chip with the given flash data. """
self.curExtAddr = -1
self.chip = chipDB.getChipFromDB(self.getSignature())
- if self.chip == False:
+ if not self.chip:
raise IspError("Chip with signature: " + str(self.getSignature()) + "not found")
self.chipErase()
print("Verifying %i bytes" % len(flashData))
self.verifyFlash(flashData)
- #low level ISP commands
def getSignature(self):
+ """
+ Get the AVR signature from the chip. This is a 3 byte array which describes which chip we are connected to.
+ This is important to verify that we are programming the correct type of chip and that we use proper flash block sizes.
+ """
sig = []
sig.append(self.sendISP([0x30, 0x00, 0x00, 0x00])[3])
sig.append(self.sendISP([0x30, 0x00, 0x01, 0x00])[3])
return sig
def chipErase(self):
+ """
+ Do a full chip erase, clears all data, and lockbits.
+ """
self.sendISP([0xAC, 0x80, 0x00, 0x00])
+ def writeFlash(self, flashData):
+ """
+ Write the flash data, needs to be implemented in a subclass.
+ """
+ raise IspError("Called undefined writeFlash")
+
+ def verifyFlash(self, flashData):
+ """
+ Verify the flash data, needs to be implemented in a subclass.
+ """
+ raise IspError("Called undefined verifyFlash")
+
class IspError():
def __init__(self, value):
self.value = value
+"""
+STK500v2 protocol implementation for programming AVR chips.
+The STK500v2 protocol is used by the ArduinoMega2560 and a few other Arduino platforms to load firmware.
+"""
__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import os, struct, sys, time
def treeWalk(moduleList, dirname, fnames):
""" Callback from the os.path.walk function, see if the given path is a module and import it to put it in the moduleList """
dirname = dirname.replace("\\", ".").replace("/", ".")
+ if dirname.startswith('Cura.gui'):
+ return
if dirname == 'Cura.util.pymclevel':
return
if dirname == 'Cura.util.Power':
self.sizer = wx.GridBagSizer(2, 2)
self.panel.SetSizer(self.sizer)
- sb = wx.StaticBox(self.panel, label=_("Statistics"))
+ sb = wx.StaticBox(self.panel, label=_("Info"))
boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
self.powerWarningText = wx.StaticText(parent=self.panel,
self._printerConnection.addCallback(self._doPrinterConnectionUpdate)
+ if self._printerConnection.hasActiveConnection() and not self._printerConnection.isActiveConnectionOpen():
+ self._printerConnection.openActiveConnection()
+
def OnPowerWarningChange(self, e):
type = self.powerManagement.get_providing_power_source_type()
if type == power.POWER_TYPE_AC and self.powerWarningText.IsShown():
import wx
import numpy
-from Cura.util import mesh
+from Cura.util import printableObject
def supportedExtensions():
return ['.bmp', '.jpg', '.jpeg', '.png']
v3 = v0[1:,0:-1,:]
v4 = v0[1:,1:,:]
- obj = mesh.printableObject(filename)
+ obj = printableObject.printableObject(filename)
m = obj._addMesh()
m._prepareFaceCount((w-1) * (h-1) * 2 + 2 + (w-1)*4 + (h-1)*4)
m.vertexes = numpy.array(numpy.concatenate((v1,v3,v2,v2,v3,v4), 2).reshape(((w-1) * (h-1) * 6, 3)), numpy.float32, copy=False)
import os
import numpy
-from Cura.util import mesh
+from Cura.util import printableObject
from Cura.util.meshLoaders import stl
from Cura.util.pymclevel import mclevel
if y == sy - 1 or not self.isSolid[blocks[x, y + 1, z]]:
faceCount += 1
- obj = mesh.printableObject(None)
+ obj = printableObject.printableObject(None)
m = obj._addMesh()
m._prepareFaceCount(faceCount * 2)
for x in xrange(0, sx):
+"""
+A simple generator for GCode. To assist in creation of simple GCode instructions.
+This is not intended for advanced use or complex paths. The CuraEngine generates the real GCode instructions.
+"""
__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import math
+"""
+The GCodeInterpreter module generates layer information from GCode.
+It does this by parsing the whole GCode file. On large files this can take a while and should be used from a thread.
+"""
__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import sys
pathType = line[6:].strip()
if ';' in line:
- #Slic3r GCode comment parser
comment = line[line.find(';')+1:].strip()
+ #Slic3r GCode comment parser
if comment == 'fill':
pathType = 'FILL'
elif comment == 'perimeter':
pathType = 'WALL-INNER'
elif comment == 'skirt':
pathType = 'SKIRT'
+ #Cura layer comments.
if comment.startswith('LAYER:'):
currentPath = gcodePath(moveType, pathType, layerThickness, currentPath['points'][-1])
+ layerThickness = 0.0
currentPath['extruder'] = currentExtruder
for path in currentLayer:
path['points'] = numpy.array(path['points'], numpy.float32)
if moveType == 'move' and oldPos[2] != pos[2]:
if oldPos[2] > pos[2] and abs(oldPos[2] - pos[2]) > 5.0 and pos[2] < 1.0:
oldPos[2] = 0.0
- layerThickness = abs(oldPos[2] - pos[2])
+ if layerThickness == 0.0:
+ layerThickness = abs(oldPos[2] - pos[2])
if currentPath['type'] != moveType or currentPath['pathType'] != pathType:
currentPath = gcodePath(moveType, pathType, layerThickness, currentPath['points'][-1])
currentPath['extruder'] = currentExtruder
+"""
+MachineCom handles communication with GCode based printers trough serial ports.
+For actual printing of objects this module is used from Cura.serialCommunication and ran in a seperate process.
+"""
__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import os
+"""
+The meshLoader module contains a universal interface for loading 3D files.
+Depending on the file extension the proper meshLoader is called to load the file.
+"""
__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import os
from Cura.util.meshLoaders import amf
def loadSupportedExtensions():
+ """ return a list of supported file extensions for loading. """
return ['.stl', '.obj', '.dae', '.amf']
def saveSupportedExtensions():
+ """ return a list of supported file extensions for saving. """
return ['.amf', '.stl']
def loadWildcardFilter():
wildcardList = ';'.join(map(lambda s: '*' + s, saveSupportedExtensions()))
return "Mesh files (%s)|%s;%s" % (wildcardList, wildcardList, wildcardList.upper())
-#loadMeshes loads 1 or more printableObjects from a file.
-# STL files are a single printableObject with a single mesh, these are most common.
-# OBJ files usually contain a single mesh, but they can contain multiple meshes
-# AMF can contain whole scenes of objects with each object having multiple meshes.
-# DAE files are a mess, but they can contain scenes of objects as well as grouped meshes
-
def loadMeshes(filename):
+ """
+ loadMeshes loads 1 or more printableObjects from a file.
+ STL files are a single printableObject with a single mesh, these are most common.
+ OBJ files usually contain a single mesh, but they can contain multiple meshes
+ AMF can contain whole scenes of objects with each object having multiple meshes.
+ DAE files are a mess, but they can contain scenes of objects as well as grouped meshes
+ """
ext = os.path.splitext(filename)[1].lower()
if ext == '.stl':
return stl.loadScene(filename)
return []
def saveMeshes(filename, objects):
+ """
+ Save a list of objects into the file given by the filename. Use the filename extension to find out the file format.
+ """
ext = os.path.splitext(filename)[1].lower()
if ext == '.stl':
stl.saveScene(filename, objects)
except:
from xml.etree import ElementTree
-from Cura.util import mesh
+from Cura.util import printableObject
from Cura.util import profile
def loadScene(filename):
ret = []
for amfObj in amf.iter('object'):
- obj = mesh.printableObject(filename)
+ obj = printableObject.printableObject(filename)
for amfMesh in amfObj.iter('mesh'):
vertexList = []
for vertices in amfMesh.iter('vertices'):
from xml.parsers.expat import ParserCreate
import os
-from Cura.util import mesh
+from Cura.util import printableObject
def loadScene(filename):
loader = daeLoader(filename)
class daeLoader(object):
def __init__(self, filename):
- self.obj = mesh.printableObject(filename)
+ self.obj = printableObject.printableObject(filename)
self.mesh = self.obj._addMesh()
r = ParserCreate()
__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import os
-from Cura.util import mesh
+from Cura.util import printableObject
def loadScene(filename):
- obj = mesh.printableObject(filename)
+ obj = printableObject.printableObject(filename)
m = obj._addMesh()
vertexList = []
import struct
import time
-from Cura.util import mesh
+from Cura.util import printableObject
def _loadAscii(m, f):
cnt = 0
m._addFace(data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11])
def loadScene(filename):
- obj = mesh.printableObject(filename)
+ obj = printableObject.printableObject(filename)
m = obj._addMesh()
f = open(filename, "rb")
+"""
+The objectScene module contain a objectScene class,
+this class contains a group of printableObjects that are located on the build platform.
+
+The objectScene handles the printing order of these objects, and if they collide.
+"""
__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import random
import numpy
+"""
+The printableObject module contains a printableObject class,
+which is used to represent a single object that can be printed.
+A single object can have 1 or more meshes which represent different sections for multi-material extrusion.
+"""
__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import time
setting('retraction_dual_amount', 16.5, float, 'advanced', _('Retraction')).setRange(0).setLabel(_("Dual extrusion switch amount (mm)"), _("Amount of retraction when switching nozzle with dual-extrusion, set at 0 for no retraction at all. A value of 16.0mm seems to generate good results."))
setting('retraction_min_travel', 1.5, float, 'expert', _('Retraction')).setRange(0).setLabel(_("Minimum travel (mm)"), _("Minimum amount of travel needed for a retraction to happen at all. To make sure you do not get a lot of retractions in a small area."))
setting('retraction_combing', True, bool, 'expert', _('Retraction')).setLabel(_("Enable combing"), _("Combing is the act of avoiding holes in the print for the head to travel over. If combing is disabled the printer head moves straight from the start point to the end point and it will always retract."))
-setting('retraction_minimal_extrusion',0.02, float,'expert', _('Retraction')).setRange(0).setLabel(_("Minimal extrusion before retracting (mm)"), _("The minimal amount of extrusion that needs to be done before retracting again if a retraction needs to happen before this minimal is reached the retraction is ignored.\nThis avoids retraction a lot on the same piece of filament which flattens the filament and causes grinding issues."))
+setting('retraction_minimal_extrusion',0.02, float,'expert', _('Retraction')).setRange(0).setLabel(_("Minimal extrusion before retracting (mm)"), _("The minimal amount of extrusion that needs to be done before retracting again if a retraction needs to happen before this minimal is reached the retraction is ignored.\nThis avoids retraction a lot on the same piece of filament which flattens the filament and causes grinding issues."))
+setting('retraction_hop', 0.0, float, 'expert', _('Retraction')).setRange(0).setLabel(_("Z hop when retracting (mm)"), _("When a retraction is done, the head is lifted by this amount to travel over the print. A value of 0.075 works good. This feature has a lot of positive effect on delta towers."))
setting('bottom_thickness', 0.3, float, 'advanced', _('Quality')).setRange(0).setLabel(_("Initial layer thickness (mm)"), _("Layer thickness of the bottom layer. A thicker bottom layer makes sticking to the bed easier. Set to 0.0 to have the bottom layer thickness the same as the other layers."))
setting('object_sink', 0.0, float, 'advanced', _('Quality')).setLabel(_("Cut off object bottom (mm)"), _("Sinks the object into the platform, this can be used for objects that do not have a flat bottom and thus create a too small first layer."))
#setting('enable_skin', False, bool, 'advanced', _('Quality')).setLabel(_("Duplicate outlines"), _("Skin prints the outer lines of the prints twice, each time with half the thickness. This gives the illusion of a higher print quality."))
'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
'retractionMinimalDistance': int(profile.getProfileSettingFloat('retraction_min_travel') * 1000),
'retractionAmountExtruderSwitch': int(profile.getProfileSettingFloat('retraction_dual_amount') * 1000),
+ 'retractionZHop': int(profile.getProfileSettingFloat('retraction_hop') * 1000),
'minimalExtrusionBeforeRetraction': int(profile.getProfileSettingFloat('retraction_minimal_extrusion') * 1000),
'enableCombing': 1 if profile.getProfileSetting('retraction_combing') == 'True' else 0,
'multiVolumeOverlap': int(profile.getProfileSettingFloat('overlap_dual') * 1000),