Large update adding:

-Python based firmware loader (not used yet)
-Beginning of the first run wizard
-Preferences window
Also moved around a few functions, cleaned somethings up
This commit is contained in:
Daid 2012-03-05 22:30:54 +01:00
parent 85e0068641
commit d3af800217
12 changed files with 490 additions and 99 deletions

View file

@ -0,0 +1,14 @@
avrChipDB = {
'ATMega2560': {
'signature': [0x1E, 0x98, 0x01],
'pageSize': 128,
'pageCount': 1024,
},
}
def getChipFromDB(sig):
for chip in avrChipDB.values():
if chip['signature'] == sig:
return chip
return False

View file

@ -0,0 +1,35 @@
import io
def readHex(filename):
data = []
extraAddr = 0
f = io.open(filename, "r")
for line in f:
line = line.strip()
if line[0] != ':':
raise Exception("Hex file has a line not starting with ':'")
recLen = int(line[1:3], 16)
addr = int(line[3:7], 16) + extraAddr
recType = int(line[7:9], 16)
if len(line) != recLen * 2 + 11:
raise Exception("Error in hex file: " + line)
checkSum = 0
for i in xrange(0, recLen + 5):
checkSum += int(line[i*2+1:i*2+3], 16)
checkSum &= 0xFF
if checkSum != 0:
raise Exception("Checksum error in hex file: " + line)
if recType == 0:#Data record
while len(data) < addr + recLen:
data.append(0)
for i in xrange(0, recLen):
data[addr + i] = int(line[i*2+9:i*2+11], 16)
elif recType == 1: #End Of File record
pass
elif recType == 2: #Extended Segment Address Record
extraAddr = int(line[9:13], 16) * 16
else:
print recType, recLen, addr, checkSum, line
f.close()
return data

View file

@ -0,0 +1,38 @@
import os, struct, sys, time
from serial import Serial
import chipDB
class IspBase():
def programChip(self, flashData):
self.curExtAddr = -1
self.chip = chipDB.getChipFromDB(self.getSignature())
if self.chip == False:
print "Chip with signature: " + str(self.getSignature()) + "not found"
return False
self.chipErase()
print "Flashing %i bytes" % len(flashData)
self.writeFlash(flashData)
print "Verifying %i bytes" % len(flashData)
self.verifyFlash(flashData)
return True
#low level ISP commands
def getSignature(self):
sig = []
sig.append(self.sendISP([0x30, 0x00, 0x00, 0x00])[3])
sig.append(self.sendISP([0x30, 0x00, 0x01, 0x00])[3])
sig.append(self.sendISP([0x30, 0x00, 0x02, 0x00])[3])
return sig
def chipErase(self):
self.sendISP([0xAC, 0x80, 0x00, 0x00])
class IspError():
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)

View file

@ -0,0 +1,112 @@
import os, struct, sys, time
from serial import Serial
import ispBase, intelHex
class Stk500v2(ispBase.IspBase):
def __init__(self):
self.serial = None
self.seq = 1
self.lastAddr = -1
def connect(self, port = 'COM3', speed = 115200):
if self.serial != None:
self.serial.close()
self.serial = Serial(port, speed, timeout=5)
self.seq = 1
#Reset the controller
self.serial.setDTR(1)
self.serial.setDTR(0)
time.sleep(0.2)
self.sendMessage([1])
if self.sendMessage([0x10, 0xc8, 0x64, 0x19, 0x20, 0x00, 0x53, 0x03, 0xac, 0x53, 0x00, 0x00]) != [0x10, 0x00]:
raise ispBase.IspError("Failed to enter programming mode")
def sendISP(self, data):
recv = self.sendMessage([0x1D, 4, 4, 0, data[0], data[1], data[2], data[3]])
return recv[2:6]
def writeFlash(self, flashData):
#Set load addr to 0 (with more then 64k load)
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
loadCount = (len(flashData) + 0xFF) / 0x100
for i in xrange(0, loadCount):
recv = self.sendMessage([0x13, 0x01, 0x00, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flashData[(i * 0x100):(i * 0x100 + 0x100)])
print "#%i#%i#" % (i + 1, loadCount)
def verifyFlash(self, flashData):
#Set load addr to 0 (with more then 64k load)
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
loadCount = (len(flashData) + 0xFF) / 0x100
for i in xrange(0, loadCount):
recv = self.sendMessage([0x14, 0x01, 0x00, 0x20])[2:0x102]
print "#%i#%i#" % (i + 1, loadCount)
for j in xrange(0, 0x100):
if i * 0x100 + j < len(flashData) and flashData[i * 0x100 + j] != recv[j]:
raise ispBase.IspError('Verify error at: 0x%x' % (i * 0x100 + j))
def sendMessage(self, data):
message = struct.pack(">BBHB", 0x1B, self.seq, len(data), 0x0E)
for c in data:
message += struct.pack(">B", c)
checksum = 0
for c in message:
checksum ^= ord(c)
message += struct.pack(">B", checksum)
self.serial.write(message)
self.serial.flush()
self.seq = (self.seq + 1) & 0xFF
return self.recvMessage()
def recvMessage(self):
state = 'Start'
checksum = 0
while True:
s = self.serial.read()
if len(s) < 1:
raise ispBase.IspError("Timeout")
b = struct.unpack(">B", s)[0]
checksum ^= b
#print hex(b)
if state == 'Start':
if b == 0x1B:
state = 'GetSeq'
checksum = 0x1B
elif state == 'GetSeq':
state = 'MsgSize1'
elif state == 'MsgSize1':
msgSize = b << 8
state = 'MsgSize2'
elif state == 'MsgSize2':
msgSize |= b
state = 'Token'
elif state == 'Token':
if b != 0x0E:
state = 'Start'
else:
state = 'Data'
data = []
elif state == 'Data':
data.append(b)
if len(data) == msgSize:
state = 'Checksum'
elif state == 'Checksum':
if checksum != 0:
state = 'Start'
else:
return data
def main():
programmer = Stk500v2()
programmer.connect()
programmer.programChip(intelHex.readHex("cfg_4f55234def059.hex"))
sys.exit(1)
if __name__ == '__main__':
main()

View file

@ -17,20 +17,20 @@ def DEFSET(setting):
return setting.value
def storedSetting(name):
return lambda setting: getSetting(name, setting.value)
return lambda setting: getProfileSetting(name, setting.value)
def ifSettingAboveZero(name):
return lambda setting: float(getSetting(name, '0.0')) > 0
return lambda setting: float(getProfileSetting(name, '0.0')) > 0
def ifSettingIs(name, value):
return lambda setting: getSetting(name) == value
return lambda setting: getProfileSetting(name) == value
def storedPercentSetting(name):
return lambda setting: float(getSetting(name, setting.value)) / 100
return lambda setting: float(getProfileSetting(name, setting.value)) / 100
def calculateEdgeWidth(setting):
wallThickness = float(getSetting('wall_thickness'))
nozzleSize = float(getSetting('nozzle_size'))
wallThickness = float(getProfileSetting('wall_thickness'))
nozzleSize = float(getProfileSetting('nozzle_size'))
if wallThickness < nozzleSize:
return wallThickness
@ -43,13 +43,13 @@ def calculateEdgeWidth(setting):
return lineWidth
def calculateShells(setting):
return calculateShellsImp(float(getSetting('wall_thickness')))
return calculateShellsImp(float(getProfileSetting('wall_thickness')))
def calculateShellsBase(setting):
return calculateShellsImp(float(getSetting('wall_thickness')) + float(getSetting('extra_base_wall_thickness', '0')))
return calculateShellsImp(float(getProfileSetting('wall_thickness')) + float(getProfileSetting('extra_base_wall_thickness', '0')))
def calculateShellsImp(wallThickness):
nozzleSize = float(getSetting('nozzle_size'))
nozzleSize = float(getProfileSetting('nozzle_size'))
if wallThickness < nozzleSize:
return 0
@ -62,14 +62,14 @@ def calculateShellsImp(wallThickness):
return lineCount - 1
def calculateSolidLayerCount(setting):
layerHeight = float(getSetting('layer_height'))
solidThickness = float(getSetting('solid_layer_thickness'))
layerHeight = float(getProfileSetting('layer_height'))
solidThickness = float(getProfileSetting('solid_layer_thickness'))
ret = int(math.ceil(solidThickness / layerHeight - 0.0001))
return ret
def firstLayerSpeedRatio(setting):
bottomSpeed = float(getSetting('bottom_layer_speed'))
speed = float(getSetting('print_speed'))
bottomSpeed = float(getProfileSetting('bottom_layer_speed'))
speed = float(getProfileSetting('print_speed'))
return bottomSpeed/speed
def getSkeinPyPyProfileInformation():
@ -379,7 +379,7 @@ def loadGlobalProfile(filename):
def saveGlobalProfile(filename):
globalProfileParser.write(open(filename, 'w'))
def getSetting(name, default = "", section = 'profile'):
def getProfileSetting(name, default = "ERR", section = 'profile'):
#Check if we have a configuration file loaded, else load the default.
if not globals().has_key('globalProfileParser'):
loadGlobalProfile(getDefaultProfilePath())
@ -387,11 +387,11 @@ def getSetting(name, default = "", section = 'profile'):
if not globalProfileParser.has_section(section):
globalProfileParser.add_section(section)
globalProfileParser.set(section, name, str(default))
print name + " not found in profile, so using default"
print name + " not found in profile, so using default: " + str(default)
return default
return globalProfileParser.get(section, name)
def putSetting(name, value, section = 'profile'):
def putProfileSetting(name, value, section = 'profile'):
#Check if we have a configuration file loaded, else load the default.
if not globals().has_key('globalProfileParser'):
loadGlobalProfile(getDefaultProfilePath())
@ -399,6 +399,37 @@ def putSetting(name, value, section = 'profile'):
globalProfileParser.add_section(section)
globalProfileParser.set(section, name, str(value))
global globalPreferenceParser
globalPreferenceParser = None
def getPreferencePath():
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../preferences.ini"))
def getPreference(name, default = "ERR"):
global globalPreferenceParser
if globalPreferenceParser == None:
globalPreferenceParser = ConfigParser.ConfigParser()
globalPreferenceParser.read(getPreferencePath())
if not globalPreferenceParser.has_option('preference', name):
if not globalPreferenceParser.has_section('preference'):
globalPreferenceParser.add_section('preference')
globalPreferenceParser.set('preference', name, str(default))
print name + " not found in preferences, so using default: " + str(default)
return default
return globalPreferenceParser.get('preference', name)
def putPreference(name, value):
#Check if we have a configuration file loaded, else load the default.
global globalPreferenceParser
if globalPreferenceParser == None:
globalPreferenceParser = ConfigParser.ConfigParser()
globalPreferenceParser.read(getPreferencePath())
if not globalPreferenceParser.has_section('preference'):
globalPreferenceParser.add_section('preference')
globalPreferenceParser.set('preference', name, str(value))
globalPreferenceParser.write(open(getPreferencePath(), 'w'))
def getDefaultProfilePath():
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../current_profile.ini"))
@ -450,10 +481,10 @@ def getAlterationFile(fileName, allowMagicPrefix = True):
if fileName == 'start.gcode':
#For the start code, hack the temperature and the steps per E value into it. So the temperature is reached before the start code extrusion.
#We also set our steps per E here, if configured.
eSteps = float(getSetting('steps_per_e_unit', '0'))
eSteps = float(getProfileSetting('steps_per_e_unit', '0'))
if eSteps > 0:
prefix += 'M92 E'+str(eSteps)+'\n'
temp = float(getSetting('print_temperature', '0'))
temp = float(getProfileSetting('print_temperature', '0'))
if temp > 0:
prefix += 'M109 S'+str(temp)+'\n'
elif fileName == 'replace.csv':

View file

@ -17,12 +17,13 @@ class advancedConfigWindow(configBase.configWindowBase):
def __init__(self):
super(advancedConfigWindow, self).__init__(title='Advanced config')
wx.EVT_CLOSE(self, self.OnClose)
left, right, main = self.CreateConfigPanel(self)
configBase.TitleRow(left, "Accuracy")
c = configBase.SettingRow(left, "Extra Wall thickness for bottom/top (mm)", 'extra_base_wall_thickness', '0.0', 'Additional wall thickness of the bottom and top layers.')
validators.validFloat(c, 0.0)
validators.wallThicknessValidator(c)
configBase.TitleRow(left, "Sequence")
c = configBase.SettingRow(left, "Print order sequence", 'sequence', ['Loops > Perimeter > Infill', 'Loops > Infill > Perimeter', 'Infill > Loops > Perimeter', 'Infill > Perimeter > Loops', 'Perimeter > Infill > Loops', 'Perimeter > Loops > Infill'], 'Sequence of printing. The perimeter is the outer print edge, the loops are the insides of the walls, and the infill is the insides.');
c = configBase.SettingRow(left, "Force first layer sequence", 'force_first_layer_sequence', ['True', 'False'], 'This setting forces the order of the first layer to be \'Perimeter > Loops > Infill\'')
@ -37,3 +38,5 @@ class advancedConfigWindow(configBase.configWindowBase):
main.Fit()
self.Fit()
def OnClose(self, e):
self.Destroy()

View file

@ -2,7 +2,6 @@ from __future__ import absolute_import
import __init__
import wx, os, platform, types
import ConfigParser
from fabmetheus_utilities import settings
@ -53,11 +52,11 @@ class configWindowBase(wx.Frame):
def OnPopupDisplay(self, setting):
x, y = setting.ctrl.ClientToScreenXY(0, 0)
sx, sy = setting.ctrl.GetSizeTuple()
if platform.system() == "Windows":
#for some reason, under windows, the popup is relative to the main window...
wx, wy = self.ClientToScreenXY(0, 0)
x -= wx
y -= wy
#if platform.system() == "Windows":
# for some reason, under windows, the popup is relative to the main window... in some cases. (Wierd ass bug)
# wx, wy = self.ClientToScreenXY(0, 0)
# x -= wx
# y -= wy
self.popup.setting = setting
self.UpdatePopup(setting)
self.popup.SetPosition((x, y+sy))
@ -78,7 +77,10 @@ class configWindowBase(wx.Frame):
def updateProfileToControls(self):
"Update the configuration wx controls to show the new configuration settings"
for setting in self.settingControlList:
setting.SetValue(settings.getSetting(setting.configName))
if setting.type == 'profile':
setting.SetValue(settings.getProfileSetting(setting.configName))
else:
setting.SetValue(settings.getPreference(setting.configName))
class TitleRow():
def __init__(self, panel, name):
@ -91,7 +93,7 @@ class TitleRow():
sizer.SetRows(sizer.GetRows() + 2)
class SettingRow():
def __init__(self, panel, label, configName, defaultValue = '', helpText = 'Help: TODO'):
def __init__(self, panel, label, configName, defaultValue = '', helpText = 'Help: TODO', type = 'profile'):
"Add a setting to the configuration panel"
sizer = panel.GetSizer()
x = sizer.GetRows()
@ -102,12 +104,19 @@ class SettingRow():
self.helpText = helpText
self.configName = configName
self.panel = panel
self.type = type
self.label = wx.StaticText(panel, -1, label)
if isinstance(defaultValue, types.StringTypes):
self.ctrl = wx.TextCtrl(panel, -1, settings.getSetting(configName, defaultValue))
if self.type == 'profile':
if isinstance(defaultValue, types.StringTypes):
self.ctrl = wx.TextCtrl(panel, -1, settings.getProfileSetting(configName, defaultValue))
else:
self.ctrl = wx.ComboBox(panel, -1, settings.getProfileSetting(configName, defaultValue[0]), choices=defaultValue, style=wx.CB_DROPDOWN|wx.CB_READONLY)
else:
self.ctrl = wx.ComboBox(panel, -1, settings.getSetting(configName, defaultValue[0]), choices=defaultValue, style=wx.CB_DROPDOWN|wx.CB_READONLY)
if isinstance(defaultValue, types.StringTypes):
self.ctrl = wx.TextCtrl(panel, -1, settings.getPreference(configName, defaultValue))
else:
self.ctrl = wx.ComboBox(panel, -1, settings.getPreference(configName, defaultValue[0]), choices=defaultValue, style=wx.CB_DROPDOWN|wx.CB_READONLY)
#self.helpButton = wx.Button(panel, -1, "?", style=wx.BU_EXACTFIT)
#self.helpButton.SetToolTip(wx.ToolTip(help))
@ -123,7 +132,10 @@ class SettingRow():
sizer.SetRows(x+1)
def OnSettingTextChange(self, e):
settings.putSetting(self.configName, self.GetValue())
if self.type == 'profile':
settings.putProfileSetting(self.configName, self.GetValue())
else:
settings.putPreference(self.configName, self.GetValue())
result = validators.SUCCESS
msgs = []
for validator in self.validators:
@ -165,29 +177,3 @@ class settingNotify():
return validators.SUCCESS, ''
except ValueError:
return validators.SUCCESS, ''
def getPreferencePath():
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../preferences.ini"))
def getPreference(name, default):
if not globals().has_key('globalPreferenceParser'):
globalPreferenceParser = ConfigParser.ConfigParser()
globalPreferenceParser.read(getPreferencePath())
if not globalPreferenceParser.has_option('preference', name):
if not globalPreferenceParser.has_section('preference'):
globalPreferenceParser.add_section('preference')
globalPreferenceParser.set('preference', name, str(default))
print name + " not found in profile, so using default"
return default
return globalPreferenceParser.get('preference', name)
def putPreference(name, value):
#Check if we have a configuration file loaded, else load the default.
if not globals().has_key('globalPreferenceParser'):
globalPreferenceParser = ConfigParser.ConfigParser()
globalPreferenceParser.read(getPreferencePath())
if not globalPreferenceParser.has_section('preference'):
globalPreferenceParser.add_section('preference')
globalPreferenceParser.set('preference', name, str(value))
globalPreferenceParser.write(open(getPreferencePath(), 'w'))

View file

@ -0,0 +1,129 @@
from __future__ import absolute_import
import __init__
import wx, os, platform, types
import wx.wizard
from fabmetheus_utilities import settings
class InfoPage(wx.wizard.WizardPageSimple):
def __init__(self, parent, title):
"""Constructor"""
wx.wizard.WizardPageSimple.__init__(self, parent)
sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer = sizer
self.SetSizer(sizer)
title = wx.StaticText(self, -1, title)
title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)
def AddText(self,info):
self.GetSizer().Add(wx.StaticText(self, -1, info), 0, wx.LEFT|wx.RIGHT, 5)
def AddSeperator(self):
self.GetSizer().Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)
def AddHiddenSeperator(self):
self.AddText('')
def AddRadioButton(self, label, style = 0):
radio = wx.RadioButton(self, -1, label, style=style)
self.GetSizer().Add(radio, 0, wx.EXPAND|wx.ALL, 5)
return radio
def AllowNext(self):
return True
def StoreData(self):
pass
class FirstInfoPage(InfoPage):
def __init__(self, parent):
super(FirstInfoPage, self).__init__(parent, "First time run wizard")
self.AddText('Welcome, and thanks for trying SkeinPyPy!')
self.AddSeperator()
self.AddText('This wizard will help you with the following steps:')
self.AddText('* Configure SkeinPyPy for your machine')
self.AddText('* Upgrade your firmware')
self.AddText('* Calibrate your machine')
#self.AddText('* Do your first print')
class MachineSelectPage(InfoPage):
def __init__(self, parent):
super(MachineSelectPage, self).__init__(parent, "Select your machine")
self.AddText('What kind of machine do you have:')
self.UltimakerRadio = self.AddRadioButton("Ultimaker", style=wx.RB_GROUP)
self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
self.OtherRadio = self.AddRadioButton("Other (Ex: RepRap)")
self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
def OnUltimakerSelect(self, e):
wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
def OnOtherSelect(self, e):
wx.wizard.WizardPageSimple.Chain(self, self.GetParent().configureMachineDimensions)
def StoreData(self):
if self.UltimakerRadio.GetValue():
settings.putPreference('machine_width', '205')
settings.putPreference('machine_depth', '205')
settings.putPreference('machine_height', '200')
settings.putProfileSetting('nozzle_size', '0.4')
settings.putProfileSetting('machine_center_x', '100')
settings.putProfileSetting('machine_center_x', '100')
class FirmwareUpgradePage(InfoPage):
def __init__(self, parent):
super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")
self.AddText('Firmware is the piece of software running directly on your 3D printer.\nThis firmware controls the step motors, regulates the temperature\nand ultimately makes your printer work.')
self.AddHiddenSeperator()
self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')
self.AddHiddenSeperator()
self.AddText('SkeinPyPy requires these new features and thus\nyour firmware will most likely need to be upgraded.\nYou will get the chance to do so now.')
self.AddHiddenSeperator()
button = wx.Button(self, -1, 'Upgrade firmware')
self.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
self.GetSizer().Add(button, 0)
self.AddHiddenSeperator()
self.AddText('Do not upgrade to this firmware if:')
self.AddText('* You have an older machine based on ATMega1280')
self.AddText('* Using an LCD panel')
self.AddText('* Have other changes in the firmware')
def OnUpgradeClick(self, e):
pass
class configWizard(wx.wizard.Wizard):
def __init__(self):
super(configWizard, self).__init__(None, -1, "Configuration Wizard")
self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
self.firstInfoPage = FirstInfoPage(self)
self.machineSelectPage = MachineSelectPage(self)
self.ultimakerFirmwareUpgradePage = FirmwareUpgradePage(self)
self.configureMachineDimensions = InfoPage(self, 'BLA2')
wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerFirmwareUpgradePage)
self.FitToPage(self.firstInfoPage)
self.GetPageAreaSizer().Add(self.firstInfoPage)
self.RunWizard(self.firstInfoPage)
self.Destroy()
def OnPageChanging(self, e):
e.GetPage().StoreData()
def OnPageChanged(self, e):
if e.GetPage().AllowNext():
self.FindWindowById(wx.ID_FORWARD).Enable()
else:
self.FindWindowById(wx.ID_FORWARD).Disable()
self.FindWindowById(wx.ID_BACKWARD).Disable()

View file

@ -2,7 +2,6 @@ from __future__ import absolute_import
import __init__
import wx, os, platform, types
import ConfigParser
from fabmetheus_utilities import settings
@ -12,6 +11,8 @@ from newui import preview3d
from newui import sliceProgessPanel
from newui import alterationPanel
from newui import validators
from newui import preferencesDialog
from newui import configWizard
def main():
app = wx.App(False)
@ -25,12 +26,19 @@ class mainWindow(configBase.configWindowBase):
wx.EVT_CLOSE(self, self.OnClose)
if settings.getPreference('wizardDone', 'False') == 'False':
configWizard.configWizard()
menubar = wx.MenuBar()
fileMenu = wx.Menu()
i = fileMenu.Append(-1, 'Open Profile...', 'Open Profile...')
self.Bind(wx.EVT_MENU, self.OnLoadProfile, i)
i = fileMenu.Append(-1, 'Save Profile...', 'Save Profile...')
self.Bind(wx.EVT_MENU, self.OnSaveProfile, i)
fileMenu.AppendSeparator()
i = fileMenu.Append(-1, 'Preferences...', 'Preferences...')
self.Bind(wx.EVT_MENU, self.OnPreferences, i)
fileMenu.AppendSeparator()
i = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quit application')
self.Bind(wx.EVT_MENU, self.OnQuit, i)
menubar.Append(fileMenu, '&File')
@ -42,7 +50,7 @@ class mainWindow(configBase.configWindowBase):
self.SetMenuBar(menubar)
self.lastPath = ""
self.filename = configBase.getPreference('lastFile', None)
self.filename = settings.getPreference('lastFile', "None")
self.progressPanelList = []
#Preview window
@ -89,7 +97,7 @@ class mainWindow(configBase.configWindowBase):
c = configBase.SettingRow(right, "Support type", 'support', ['None', 'Exterior only', 'Everywhere', 'Empty layers only'], 'Type of support structure build.\nNone does not do any support.\nExterior only only creates support on the outside.\nEverywhere creates support even on the insides of the model.\nOnly on empty layers is for stacked objects.')
configBase.TitleRow(right, "Filament")
c = configBase.SettingRow(right, "Diameter (mm)", 'filament_diameter', '2.98', 'Diameter of your filament, as accurately as possible.\nIf you cannot measure this value you will have to callibrate it, a higher number means less extrusion, a smaller number generates more extrusion.')
c = configBase.SettingRow(right, "Diameter (mm)", 'filament_diameter', '2.89', 'Diameter of your filament, as accurately as possible.\nIf you cannot measure this value you will have to callibrate it, a higher number means less extrusion, a smaller number generates more extrusion.')
validators.validFloat(c, 1.0)
c = configBase.SettingRow(right, "Packing Density", 'filament_density', '1.00', 'Packing density of your filament. This should be 1.00 for PLA and 0.85 for ABS')
validators.validFloat(c, 0.5, 1.5)
@ -156,7 +164,7 @@ class mainWindow(configBase.configWindowBase):
sizer.Add(sliceButton, (1,2))
self.sizer = sizer
if self.filename != None:
if self.filename != "None":
self.preview3d.loadModelFile(self.filename)
self.lastPath = os.path.split(self.filename)[0]
@ -185,12 +193,17 @@ class mainWindow(configBase.configWindowBase):
settings.saveGlobalProfile(profileFile)
dlg.Destroy()
def OnPreferences(self, e):
prefDialog = preferencesDialog.preferencesDialog(self)
prefDialog.Centre()
prefDialog.Show(True)
def OnLoadSTL(self, e):
dlg=wx.FileDialog(self, "Open file to print", self.lastPath, style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
dlg.SetWildcard("OBJ, STL files (*.stl;*.obj)|*.stl;*.obj")
if dlg.ShowModal() == wx.ID_OK:
self.filename=dlg.GetPath()
configBase.putPreference('lastFile', self.filename)
settings.putPreference('lastFile', self.filename)
if not(os.path.exists(self.filename)):
return
self.lastPath = os.path.split(self.filename)[0]
@ -229,11 +242,6 @@ class mainWindow(configBase.configWindowBase):
self.sizer.Add(spp, (i,0), span=(1,4), flag=wx.EXPAND)
i += 1
self.sizer.Layout()
def updateProfileToControls(self):
"Update the configuration wx controls to show the new configuration settings"
for setting in self.settingControlList:
setting.SetValue(settings.getSetting(setting.configName))
def OnQuit(self, e):
self.Close()

View file

@ -0,0 +1,36 @@
from __future__ import absolute_import
import __init__
import wx, os, platform, types
import ConfigParser
from newui import configBase
class preferencesDialog(configBase.configWindowBase):
def __init__(self, parent):
super(preferencesDialog, self).__init__(title="Preferences")
wx.EVT_CLOSE(self, self.OnClose)
left, right, main = self.CreateConfigPanel(self)
configBase.TitleRow(left, 'Machine settings')
c = configBase.SettingRow(left, 'Steps per E', 'steps_per_e', '0', 'Amount of steps per mm filament extrusion', type = 'preference')
validators.validFloat(c, 0.1)
c = configBase.SettingRow(left, 'Machine width', 'machine_width', '205', 'Size of the machine in mm', type = 'preference')
validators.validFloat(c, 10.0)
c = configBase.SettingRow(left, 'Machine depth', 'machine_depth', '205', 'Size of the machine in mm', type = 'preference')
validators.validFloat(c, 10.0)
c = configBase.SettingRow(left, 'Machine height', 'machine_height', '200', 'Size of the machine in mm', type = 'preference')
validators.validFloat(c, 10.0)
configBase.TitleRow(left, 'Communication settings')
c = configBase.SettingRow(left, 'Serial port', 'serial_port', 'AUTO', 'Serial port to use for communication with the printer', type = 'preference')
c = configBase.SettingRow(left, 'Baudrate', 'serial_baud', '250000', 'Speed of the serial port communication\nNeeds to match your firmware settings', type = 'preference')
self.MakeModal(True)
main.Fit()
self.Fit()
def OnClose(self, e):
self.MakeModal(False)
self.Destroy()

View file

@ -30,38 +30,35 @@ class previewPanel(wx.Panel):
self.init = 0
self.triangleMesh = None
self.gcode = None
self.machineSize = Vector3(210, 210, 200)
self.machineSize = Vector3(float(settings.getPreference('machine_width', '205')), float(settings.getPreference('machine_depth', '205')), float(settings.getPreference('machine_height', '200')))
self.machineCenter = Vector3(0, 0, 0)
tb = wx.ToolBar( self, -1 )
self.ToolBar = tb
tb.SetToolBitmapSize( ( 21, 21 ) )
self.toolbar = wx.ToolBar( self, -1 )
self.toolbar.SetToolBitmapSize( ( 21, 21 ) )
button = wx.Button(tb, -1, "3D", size=(21*2,21))
tb.AddControl(button)
button = wx.Button(self.toolbar, -1, "3D", size=(21*2,21))
self.toolbar.AddControl(button)
self.Bind(wx.EVT_BUTTON, self.On3DClick, button)
button = wx.Button(tb, -1, "Top", size=(21*2,21))
tb.AddControl(button)
button = wx.Button(self.toolbar, -1, "Top", size=(21*2,21))
self.toolbar.AddControl(button)
self.Bind(wx.EVT_BUTTON, self.OnTopClick, button)
self.transparentButton = wx.Button(tb, -1, "T", size=(21,21))
tb.AddControl(self.transparentButton)
self.transparentButton = wx.Button(self.toolbar, -1, "T", size=(21,21))
self.toolbar.AddControl(self.transparentButton)
self.Bind(wx.EVT_BUTTON, self.OnTransparentClick, self.transparentButton)
self.depthComplexityButton = wx.Button(tb, -1, "DC", size=(21*2,21))
tb.AddControl(self.depthComplexityButton)
self.depthComplexityButton = wx.Button(self.toolbar, -1, "DC", size=(21*2,21))
self.toolbar.AddControl(self.depthComplexityButton)
self.Bind(wx.EVT_BUTTON, self.OnDepthComplexityClick, self.depthComplexityButton)
self.layerSpin = wx.SpinCtrl(tb, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS)
tb.AddControl(self.layerSpin)
self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS)
self.toolbar.AddControl(self.layerSpin)
self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin)
self.transparentButton.Show(False)
self.layerSpin.Show(False)
tb.Realize()
self.updateToolbar()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(tb, 0, flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=1)
sizer.Add(self.toolbar, 0, flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=1)
sizer.Add(self.glCanvas, 1, flag=wx.EXPAND)
self.SetSizer(sizer)
@ -97,7 +94,7 @@ class previewPanel(wx.Panel):
self.glCanvas.lineWidth = settings.calculateEdgeWidth(setting)
def updateInfillLineWidth(self, setting):
self.glCanvas.infillLineWidth = settings.getSetting('nozzle_size')
self.glCanvas.infillLineWidth = settings.getProfileSetting('nozzle_size')
def loadModelFile(self, filename):
self.modelFilename = filename
@ -130,9 +127,11 @@ class previewPanel(wx.Panel):
def updateToolbar(self):
self.transparentButton.Show(self.triangleMesh != None)
self.depthComplexityButton.Show(self.triangleMesh != None)
self.layerSpin.Show(self.gcode != None)
if self.gcode != None:
self.layerSpin.SetRange(1, self.gcode.layerCount)
self.toolbar.Realize()
def OnTransparentClick(self, e):
self.glCanvas.renderTransparent = not self.glCanvas.renderTransparent
@ -245,10 +244,10 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glEnd()
glLineWidth(2)
glBegin(GL_LINES)
for i in xrange(0, machineSize.x, 10):
for i in xrange(0, int(machineSize.x), 10):
glVertex3f(i, 0, 0)
glVertex3f(i, machineSize.y, 0)
for i in xrange(0, machineSize.y, 10):
for i in xrange(0, int(machineSize.y), 10):
glVertex3f(0, i, 0)
glVertex3f(machineSize.x, i, 0)
glEnd()
@ -390,19 +389,19 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glStencilFunc(GL_EQUAL, i, 0xFF);
glColor(0, float(i)/10, 0)
glBegin(GL_QUADS)
glVertex3f(-10,-10,-1)
glVertex3f( 10,-10,-1)
glVertex3f( 10, 10,-1)
glVertex3f(-10, 10,-1)
glVertex3f(-1000,-1000,-1)
glVertex3f( 1000,-1000,-1)
glVertex3f( 1000, 1000,-1)
glVertex3f(-1000, 1000,-1)
glEnd()
for i in xrange(1, 20, 2):
glStencilFunc(GL_EQUAL, i, 0xFF);
glColor(float(i)/10, 0, 0)
glBegin(GL_QUADS)
glVertex3f(-10,-10,-1)
glVertex3f( 10,-10,-1)
glVertex3f( 10, 10,-1)
glVertex3f(-10, 10,-1)
glVertex3f(-1000,-1000,-1)
glVertex3f( 1000,-1000,-1)
glVertex3f( 1000, 1000,-1)
glVertex3f(-1000, 1000,-1)
glEnd()
glPopMatrix()

View file

@ -68,7 +68,7 @@ class wallThicknessValidator():
def validate(self):
try:
wallThickness = float(self.setting.GetValue())
nozzleSize = float(settings.getSetting('nozzle_size'))
nozzleSize = float(settings.getProfileSetting('nozzle_size'))
if wallThickness <= nozzleSize * 0.5:
return ERROR, 'Trying to print walls thinner then the half of your nozzle size, this will not produce anything usable'
if wallThickness <= nozzleSize * 0.85: