Added more GCode validation to GCode editor. Made temp changes to profile really temp so they are never stored in the ini file. Fixed crash bug in skeinforge where there is no layer code.

This commit is contained in:
daid 2012-05-03 12:29:55 +02:00
parent 9385aa8c25
commit e29261a992
5 changed files with 138 additions and 31 deletions

View file

@ -406,9 +406,10 @@ class CoolSkein:
def setMultiplier(self, remainingOrbitTime):
'Set the feed and flow rate multiplier.'
layerTimeActive = self.getLayerTimeActive()
self.multiplier = min(1.0, layerTimeActive / (remainingOrbitTime + layerTimeActive))
if remainingOrbitTime + layerTimeActive > 0.00001:
self.multiplier = min(1.0, layerTimeActive / (remainingOrbitTime + layerTimeActive))
else:
self.multiplier = 1.0
def main():
'Display the cool dialog.'

View file

@ -13,21 +13,86 @@ class GcodeTextArea(wx.stc.StyledTextCtrl):
fontSize = wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize()
fontName = wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL).GetFaceName()
self.SetStyleBits(5)
self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%s,size:%d" % (fontName, fontSize))
self.StyleSetSpec(1, "fore:#008000,face:%s,size:%d" % (fontName, fontSize))
self.StyleSetSpec(0, "face:%s,size:%d" % (fontName, fontSize))
self.StyleSetSpec(1, "fore:#008000,face:%s,size:%d" % (fontName, fontSize))
self.IndicatorSetStyle(0, wx.stc.STC_INDIC_TT)
self.IndicatorSetForeground(0, "#0000FF")
self.IndicatorSetStyle(1, wx.stc.STC_INDIC_SQUIGGLE)
self.IndicatorSetForeground(1, "#FF0000")
#GCodes and MCodes as supported by Marlin
#GCode 21 is not really supported by Marlin, but we still do not report it as error as it's often used.
self.supportedGCodes = [0,1,2,3,4,21,28,90,91,92]
self.supportedMCodes = [17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,42,80,81,82,83,84,85,92,104,105,106,107,109,114,115,117,119,140,190,201,202,203,204,205,206,220,221,240,301,302,303,400,500,501,502,503,999]
def OnStyle(self, e):
lineNr = self.LineFromPosition(self.GetEndStyled())
while self.PositionFromLine(lineNr) > -1:
line = self.GetLine(lineNr)
self.StartStyling(self.PositionFromLine(lineNr), 31)
self.SetStyling(self.LineLength(lineNr), wx.stc.STC_STYLE_DEFAULT)
start = self.PositionFromLine(lineNr)
length = self.LineLength(lineNr)
self.StartStyling(start, 255)
self.SetStyling(length, 0)
if ';' in line:
pos = line.index(';')
self.StartStyling(self.PositionFromLine(lineNr) + pos, 31)
self.SetStyling(self.LineLength(lineNr) - pos, 1)
self.StartStyling(start + pos, 31)
self.SetStyling(length - pos, 1)
length = pos
pos = 0
while pos < length:
if line[pos] in " \t\n\r":
while pos < length and line[pos] in " \t\n\r":
pos += 1
else:
end = pos
while end < length and not line[end] in " \t\n\r":
end += 1
if self.checkGCodePart(line[pos:end], start + pos):
self.StartStyling(start + pos, 0x20)
self.SetStyling(end - pos, 0x20)
pos = end
lineNr += 1
def checkGCodePart(self, part, pos):
if len(part) < 2:
self.StartStyling(pos, 0x40)
self.SetStyling(1, 0x40)
return True
if not part[0] in "GMXYZFESTBPIDCJ":
self.StartStyling(pos, 0x40)
self.SetStyling(1, 0x40)
return True
if part[1] == '{':
if part[-1] != '}':
return True
tag = part[2:-1]
if not profile.isProfileSetting(tag) and not profile.isPreference(tag):
self.StartStyling(pos + 2, 0x40)
self.SetStyling(len(tag), 0x40)
return True
elif part[0] in "GM":
try:
code = int(part[1:])
except (ValueError):
self.StartStyling(pos + 1, 0x40)
self.SetStyling(len(part) - 1, 0x40)
return True
if part[0] == 'G':
if not code in self.supportedGCodes:
return True
if part[0] == 'M':
if not code in self.supportedMCodes:
return True
else:
try:
float(part[1:])
except (ValueError):
self.StartStyling(pos + 1, 0x40)
self.SetStyling(len(part) - 1, 0x40)
return True
return False
def GetValue(self):
return self.GetText()

View file

@ -285,9 +285,7 @@ class projectPlanner(wx.Frame):
return (maxX - minX) + (maxY - minY)
def OnSlice(self, e):
oldProfile = profile.getGlobalProfileString()
put = profile.putProfileSetting
put = profile.setTempOverride
put('model_multiply_x', '1')
put('model_multiply_y', '1')
@ -319,7 +317,7 @@ class projectPlanner(wx.Frame):
actionList.append(action)
#Restore the old profile.
profile.loadGlobalProfileFromString(oldProfile)
profile.resetTempOverride()
dlg=wx.FileDialog(self, "Save project gcode file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)
dlg.SetWildcard("GCode file (*.gcode)|*.gcode")
@ -670,6 +668,7 @@ class ProjectSliceProgressWindow(wx.Frame):
self.sizer.Add(self.statusText, (0,0), flag=wx.ALIGN_CENTER)
self.sizer.Add(self.progressGauge, (1, 0), flag=wx.EXPAND)
self.sizer.Add(self.progressGauge2, (2, 0), flag=wx.EXPAND)
self.sizer.Add(self.abortButton, (3,0), flag=wx.ALIGN_CENTER)
self.sizer.AddGrowableCol(0)
self.sizer.AddGrowableRow(0)
@ -702,7 +701,7 @@ class ProjectSliceProgressWindow(wx.Frame):
def OnRun(self):
resultFile = open(self.resultFilename, "w")
put = profile.putProfileSetting
put = profile.setTempOverride
for action in self.actionList:
p = subprocess.Popen(action.sliceCmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
line = p.stdout.readline()
@ -727,7 +726,6 @@ class ProjectSliceProgressWindow(wx.Frame):
line = p.stdout.readline()
self.returnCode = p.wait()
oldProfile = profile.getGlobalProfileString()
put('machine_center_x', action.centerX - self.extruderOffset[action.extruder].x)
put('machine_center_y', action.centerY - self.extruderOffset[action.extruder].y)
put('clear_z', action.clearZ)
@ -743,7 +741,7 @@ class ProjectSliceProgressWindow(wx.Frame):
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(profile.getAlterationFileContents('nextobject.gcode'))
resultFile.write(';PRINTNR:%d\n' % self.actionList.index(action))
profile.loadGlobalProfileFromString(oldProfile)
profile.resetTempOverride()
f = open(action.filename[: action.filename.rfind('.')] + "_export.project_tmp", "r")
data = f.read(4096)
@ -762,7 +760,7 @@ class ProjectSliceProgressWindow(wx.Frame):
resultFile.close()
self.abort = True
sliceTime = time.time() - self.sliceStartTime
wx.CallAfter(self.statusText.SetLabel, 'Slicing took: %d:%d' % (sliceTime / 60, sliceTime % 60))
wx.CallAfter(self.statusText.SetLabel, 'Slicing took: %02d:%02d' % (sliceTime / 60, sliceTime % 60))
wx.CallAfter(self.abortButton.SetLabel, 'Close')
def main():

View file

@ -59,21 +59,20 @@ class sliceProgessPanel(wx.Panel):
if profile.getPreference('save_profile') == 'True':
profile.saveGlobalProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini")
cmdList = []
oldProfile = profile.getGlobalProfileString()
for filename in self.filelist:
idx = self.filelist.index(filename)
print filename, idx
if idx > 0:
profile.putProfileSetting('fan_enabled', 'False')
profile.putProfileSetting('skirt_line_count', '0')
profile.putProfileSetting('machine_center_x', profile.getProfileSettingFloat('machine_center_x') - profile.getPreferenceFloat('extruder_offset_x%d' % (idx)))
profile.putProfileSetting('machine_center_y', profile.getProfileSettingFloat('machine_center_y') - profile.getPreferenceFloat('extruder_offset_y%d' % (idx)))
profile.putProfileSetting('alternative_center', self.filelist[0])
profile.setTempOverride('fan_enabled', 'False')
profile.setTempOverride('skirt_line_count', '0')
profile.setTempOverride('machine_center_x', profile.getProfileSettingFloat('machine_center_x') - profile.getPreferenceFloat('extruder_offset_x%d' % (idx)))
profile.setTempOverride('machine_center_y', profile.getProfileSettingFloat('machine_center_y') - profile.getPreferenceFloat('extruder_offset_y%d' % (idx)))
profile.setTempOverride('alternative_center', self.filelist[0])
if len(self.filelist) > 1:
profile.putProfileSetting('add_start_end_gcode', 'False')
profile.putProfileSetting('gcode_extension', 'multi_extrude_tmp')
profile.setTempOverride('add_start_end_gcode', 'False')
profile.setTempOverride('gcode_extension', 'multi_extrude_tmp')
cmdList.append(sliceRun.getSliceCommand(filename))
profile.loadGlobalProfileFromString(oldProfile)
profile.resetTempOverride()
self.thread = WorkerThread(self, filelist, cmdList)
def OnAbort(self, e):
@ -188,7 +187,10 @@ class WorkerThread(threading.Thread):
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(profile.getAlterationFileContents('start.gcode'))
for filename in self.filelist:
files.append(open(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp', "r"))
if os.path.isfile(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp'):
files.append(open(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp', "r"))
else:
return
currentExtruder = 0
resultFile.write('T%d\n' % (currentExtruder))

View file

@ -67,6 +67,9 @@ profileDefaultSettings = {
'add_start_end_gcode': 'True',
'gcode_extension': 'gcode',
'alternative_center': '',
'clear_z': '0.0',
'extruder': '0',
}
alterationDefault = {
#######################################################################################
@ -153,6 +156,7 @@ preferencesDefaultSettings = {
## Profile and preferences functions
#########################################################
## Profile functions
def getDefaultProfilePath():
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../current_profile.ini"))
@ -188,17 +192,31 @@ def getGlobalProfileString():
p = []
alt = []
tempDone = []
if globalProfileParser.has_section('profile'):
for key in globalProfileParser.options('profile'):
p.append(key + "=" + globalProfileParser.get('profile', key))
if key in tempOverride:
p.append(key + "=" + unicode(tempOverride[key]))
tempDone.append(key)
else:
p.append(key + "=" + globalProfileParser.get('profile', key))
if globalProfileParser.has_section('alterations'):
for key in globalProfileParser.options('alterations'):
alt.append(key + "=" + globalProfileParser.get('alterations', key))
if key in tempOverride:
p.append(key + "=" + tempOverride[key])
tempDone.append(key)
else:
alt.append(key + "=" + globalProfileParser.get('alterations', key))
for key in tempOverride:
if key not in tempDone:
p.append(key + "=" + unicode(tempOverride[key]))
ret = '\b'.join(p) + '\f' + '\b'.join(alt)
ret = base64.b64encode(zlib.compress(ret, 9))
return ret
def getProfileSetting(name):
if name in tempOverride:
return unicode(tempOverride[name])
#Check if we have a configuration file loaded, else load the default.
if not globals().has_key('globalProfileParser'):
loadGlobalProfile(getDefaultProfilePath())
@ -230,6 +248,12 @@ def putProfileSetting(name, value):
globalProfileParser.add_section('profile')
globalProfileParser.set('profile', name, str(value))
def isProfileSetting(name):
if name in profileDefaultSettings:
return True
return False
## Preferences functions
global globalPreferenceParser
globalPreferenceParser = None
@ -239,11 +263,12 @@ def getPreferencePath():
def getPreferenceFloat(name):
try:
return float(eval(getPreference(name), {}, {}))
except (ValueError, SyntaxError):
return 0.0
def getPreference(name):
if name in tempOverride:
return unicode(tempOverride[name])
global globalPreferenceParser
if globalPreferenceParser == None:
globalPreferenceParser = ConfigParser.ConfigParser()
@ -273,6 +298,18 @@ def putPreference(name, value):
globalPreferenceParser.set('preference', name, unicode(value).encode("utf-8"))
globalPreferenceParser.write(open(getPreferencePath(), 'w'))
def isPreference(name):
if name in preferencesDefaultSettings:
return True
return False
## Temp overrides for multi-extruder slicing and the project planner.
tempOverride = {}
def setTempOverride(name, value):
tempOverride[name] = value
def resetTempOverride():
tempOverride = {}
#########################################################
## Utility functions to calculate common profile values
#########################################################
@ -316,7 +353,11 @@ def replaceTagMatch(m):
tag = m.group(0)[1:-1]
if tag in ['print_speed', 'retraction_speed', 'travel_speed', 'max_z_speed', 'bottom_layer_speed', 'cool_min_feedrate']:
return str(getProfileSettingFloat(tag) * 60)
return str(getProfileSettingFloat(tag))
if isProfileSetting(tag):
return str(getProfileSettingFloat(tag))
if isPreference(tag):
return str(getProfileSettingFloat(tag))
return tag
### Get aleration raw contents. (Used internally in Cura)
def getAlterationFile(filename):