1 from __future__ import absolute_import
\r
4 import wx, os, platform, types, webbrowser, threading, time, re
\r
7 from gui import firmwareInstall
\r
8 from gui import toolbarUtil
\r
9 from util import machineCom
\r
10 from util import profile
\r
12 class InfoBox(wx.Panel):
\r
13 def __init__(self, parent):
\r
14 super(InfoBox, self).__init__(parent)
\r
15 self.SetBackgroundColour('#FFFF80')
\r
17 self.sizer = wx.GridBagSizer(5, 5)
\r
18 self.SetSizer(self.sizer)
\r
20 self.attentionBitmap = toolbarUtil.getBitmapImage('attention.png')
\r
21 self.errorBitmap = toolbarUtil.getBitmapImage('error.png')
\r
22 self.readyBitmap = toolbarUtil.getBitmapImage('ready.png')
\r
23 self.busyBitmap = [toolbarUtil.getBitmapImage('busy-0.png'), toolbarUtil.getBitmapImage('busy-1.png'), toolbarUtil.getBitmapImage('busy-2.png'), toolbarUtil.getBitmapImage('busy-3.png')]
\r
25 self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
\r
26 self.text = wx.StaticText(self, -1, '')
\r
27 self.sizer.Add(self.bitmap, pos=(0,0), flag=wx.ALL, border=5)
\r
28 self.sizer.Add(self.text, pos=(0,1), flag=wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL, border=5)
\r
30 self.busyState = None
\r
31 self.timer = wx.Timer(self)
\r
32 self.Bind(wx.EVT_TIMER, self.doBusyUpdate, self.timer)
\r
33 self.timer.Start(100)
\r
35 def SetInfo(self, info):
\r
36 self.SetBackgroundColour('#FFFF80')
\r
37 self.text.SetLabel(info)
\r
40 def SetError(self, info):
\r
41 self.SetBackgroundColour('#FF8080')
\r
42 self.text.SetLabel(info)
\r
43 self.SetErrorIndicator()
\r
46 def SetAttention(self, info):
\r
47 self.SetBackgroundColour('#FFFF80')
\r
48 self.text.SetLabel(info)
\r
49 self.SetAttentionIndicator()
\r
52 def SetBusyIndicator(self):
\r
54 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
\r
56 def doBusyUpdate(self, e):
\r
57 if self.busyState == None:
\r
60 if self.busyState >= len(self.busyBitmap):
\r
62 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
\r
64 def SetReadyIndicator(self):
\r
65 self.busyState = None
\r
66 self.bitmap.SetBitmap(self.readyBitmap)
\r
68 def SetErrorIndicator(self):
\r
69 self.busyState = None
\r
70 self.bitmap.SetBitmap(self.errorBitmap)
\r
72 def SetAttentionIndicator(self):
\r
73 self.busyState = None
\r
74 self.bitmap.SetBitmap(self.attentionBitmap)
\r
76 class InfoPage(wx.wizard.WizardPageSimple):
\r
77 def __init__(self, parent, title):
\r
78 wx.wizard.WizardPageSimple.__init__(self, parent)
\r
80 sizer = wx.GridBagSizer(5, 5)
\r
82 self.SetSizer(sizer)
\r
84 title = wx.StaticText(self, -1, title)
\r
85 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
\r
86 sizer.Add(title, pos=(0, 0), span=(1,2), flag=wx.ALIGN_CENTRE|wx.ALL)
\r
87 sizer.Add(wx.StaticLine(self, -1), pos=(1,0), span=(1,2), flag=wx.EXPAND|wx.ALL)
\r
88 sizer.AddGrowableCol(1)
\r
92 def AddText(self,info):
\r
93 text = wx.StaticText(self, -1, info)
\r
94 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT|wx.RIGHT)
\r
98 def AddSeperator(self):
\r
99 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1,2), flag=wx.EXPAND|wx.ALL)
\r
102 def AddHiddenSeperator(self):
\r
105 def AddInfoBox(self):
\r
106 infoBox = InfoBox(self)
\r
107 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT|wx.RIGHT|wx.EXPAND)
\r
111 def AddRadioButton(self, label, style = 0):
\r
112 radio = wx.RadioButton(self, -1, label, style=style)
\r
113 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1,2), flag=wx.EXPAND|wx.ALL)
\r
117 def AddCheckbox(self, label, checked = False):
\r
118 check = wx.CheckBox(self, -1)
\r
119 text = wx.StaticText(self, -1, label)
\r
120 check.SetValue(checked)
\r
121 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT|wx.RIGHT)
\r
122 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1,2), flag=wx.ALL)
\r
126 def AddButton(self, label):
\r
127 button = wx.Button(self, -1, label)
\r
128 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT)
\r
132 def AddDualButton(self, label1, label2):
\r
133 button1 = wx.Button(self, -1, label1)
\r
134 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
\r
135 button2 = wx.Button(self, -1, label2)
\r
136 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
\r
138 return button1, button2
\r
140 def AddTextCtrl(self, value):
\r
141 ret = wx.TextCtrl(self, -1, value)
\r
142 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT)
\r
146 def AddLabelTextCtrl(self, info, value):
\r
147 text = wx.StaticText(self, -1, info)
\r
148 ret = wx.TextCtrl(self, -1, value)
\r
149 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT)
\r
150 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1,1), flag=wx.LEFT)
\r
154 def AddTextCtrlButton(self, value, buttonText):
\r
155 text = wx.TextCtrl(self, -1, value)
\r
156 button = wx.Button(self, -1, buttonText)
\r
157 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT)
\r
158 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1,1), flag=wx.LEFT)
\r
160 return text, button
\r
162 def AddBitmap(self, bitmap):
\r
163 bitmap = wx.StaticBitmap(self, -1, bitmap)
\r
164 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT|wx.RIGHT)
\r
168 def AddCheckmark(self, label, bitmap):
\r
169 check = wx.StaticBitmap(self, -1, bitmap)
\r
170 text = wx.StaticText(self, -1, label)
\r
171 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT|wx.RIGHT)
\r
172 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1,1), flag=wx.ALL)
\r
176 def AllowNext(self):
\r
179 def StoreData(self):
\r
182 class FirstInfoPage(InfoPage):
\r
183 def __init__(self, parent):
\r
184 super(FirstInfoPage, self).__init__(parent, "First time run wizard")
\r
185 self.AddText('Welcome, and thanks for trying Cura!')
\r
186 self.AddSeperator()
\r
187 self.AddText('This wizard will help you with the following steps:')
\r
188 self.AddText('* Configure Cura for your machine')
\r
189 self.AddText('* Upgrade your firmware')
\r
190 self.AddText('* Check if your machine is working safely')
\r
191 #self.AddText('* Calibrate your machine')
\r
192 #self.AddText('* Do your first print')
\r
194 class RepRapInfoPage(InfoPage):
\r
195 def __init__(self, parent):
\r
196 super(RepRapInfoPage, self).__init__(parent, "RepRap information")
\r
197 self.AddText('RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them.')
\r
198 self.AddText('If you like a default profile for your machine added,\nthen make an issue on github.')
\r
199 self.AddSeperator()
\r
200 self.AddText('You will have to manually install Marlin or Sprinter firmware.')
\r
201 self.AddSeperator()
\r
202 self.machineWidth = self.AddLabelTextCtrl('Machine width (mm)', '80')
\r
203 self.machineDepth = self.AddLabelTextCtrl('Machine depth (mm)', '80')
\r
204 self.machineHeight = self.AddLabelTextCtrl('Machine height (mm)', '60')
\r
205 self.nozzleSize = self.AddLabelTextCtrl('Nozzle size (mm)', '0.5')
\r
206 self.heatedBed = self.AddCheckbox('Heated bed')
\r
208 def StoreData(self):
\r
209 profile.putPreference('machine_width', self.machineWidth.GetValue())
\r
210 profile.putPreference('machine_depth', self.machineDepth.GetValue())
\r
211 profile.putPreference('machine_height', self.machineHeight.GetValue())
\r
212 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
\r
213 profile.putProfileSetting('machine_center_x', profile.getPreferenceFloat('machine_width') / 2)
\r
214 profile.putProfileSetting('machine_center_y', profile.getPreferenceFloat('machine_depth') / 2)
\r
215 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
\r
216 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
\r
218 class MachineSelectPage(InfoPage):
\r
219 def __init__(self, parent):
\r
220 super(MachineSelectPage, self).__init__(parent, "Select your machine")
\r
221 self.AddText('What kind of machine do you have:')
\r
223 self.UltimakerRadio = self.AddRadioButton("Ultimaker", style=wx.RB_GROUP)
\r
224 self.UltimakerRadio.SetValue(True)
\r
225 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
\r
226 self.OtherRadio = self.AddRadioButton("Other (Ex: RepRap)")
\r
227 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
\r
229 def OnUltimakerSelect(self, e):
\r
230 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
\r
232 def OnOtherSelect(self, e):
\r
233 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)
\r
235 def StoreData(self):
\r
236 if self.UltimakerRadio.GetValue():
\r
237 profile.putPreference('machine_width', '205')
\r
238 profile.putPreference('machine_depth', '205')
\r
239 profile.putPreference('machine_height', '200')
\r
240 profile.putPreference('machine_type', 'ultimaker')
\r
241 profile.putProfileSetting('nozzle_size', '0.4')
\r
242 profile.putProfileSetting('machine_center_x', '100')
\r
243 profile.putProfileSetting('machine_center_y', '100')
\r
245 profile.putPreference('machine_width', '80')
\r
246 profile.putPreference('machine_depth', '80')
\r
247 profile.putPreference('machine_height', '60')
\r
248 profile.putPreference('machine_type', 'reprap')
\r
249 profile.putPreference('startMode', 'Normal')
\r
250 profile.putProfileSetting('nozzle_size', '0.5')
\r
251 profile.putProfileSetting('machine_center_x', '40')
\r
252 profile.putProfileSetting('machine_center_y', '40')
\r
253 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
\r
255 class FirmwareUpgradePage(InfoPage):
\r
256 def __init__(self, parent):
\r
257 super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")
\r
258 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.')
\r
259 self.AddHiddenSeperator()
\r
260 self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')
\r
261 self.AddHiddenSeperator()
\r
262 self.AddText('Cura requires these new features and thus\nyour firmware will most likely need to be upgraded.\nYou will get the chance to do so now.')
\r
263 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
\r
264 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
\r
265 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
\r
266 self.AddHiddenSeperator()
\r
267 self.AddText('Do not upgrade to this firmware if:')
\r
268 self.AddText('* You have an older machine based on ATMega1280')
\r
269 self.AddText('* Have other changes in the firmware')
\r
270 button = self.AddButton('Goto this page for a custom firmware')
\r
271 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
\r
273 def AllowNext(self):
\r
276 def OnUpgradeClick(self, e):
\r
277 if firmwareInstall.InstallFirmware():
\r
278 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
\r
280 def OnSkipClick(self, e):
\r
281 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
\r
283 def OnUrlClick(self, e):
\r
284 webbrowser.open('http://daid.mine.nu/~daid/marlin_build/')
\r
286 class UltimakerCheckupPage(InfoPage):
\r
287 def __init__(self, parent):
\r
288 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
\r
290 self.checkBitmap = toolbarUtil.getBitmapImage('checkmark.png')
\r
291 self.crossBitmap = toolbarUtil.getBitmapImage('cross.png')
\r
292 self.unknownBitmap = toolbarUtil.getBitmapImage('question.png')
\r
293 self.endStopNoneBitmap = toolbarUtil.getBitmapImage('endstop_none.png')
\r
294 self.endStopXMinBitmap = toolbarUtil.getBitmapImage('endstop_xmin.png')
\r
295 self.endStopXMaxBitmap = toolbarUtil.getBitmapImage('endstop_xmax.png')
\r
296 self.endStopYMinBitmap = toolbarUtil.getBitmapImage('endstop_ymin.png')
\r
297 self.endStopYMaxBitmap = toolbarUtil.getBitmapImage('endstop_ymax.png')
\r
298 self.endStopZMinBitmap = toolbarUtil.getBitmapImage('endstop_zmin.png')
\r
299 self.endStopZMaxBitmap = toolbarUtil.getBitmapImage('endstop_zmax.png')
\r
301 self.AddText('It is a good idea to do a few sanity checks now on your Ultimaker.\nYou can skip these if you know your machine is functional.')
\r
302 b1, b2 = self.AddDualButton('Run checks', 'Skip checks')
\r
303 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
\r
304 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
\r
305 self.AddSeperator()
\r
306 self.commState = self.AddCheckmark('Communication:', self.unknownBitmap)
\r
307 self.tempState = self.AddCheckmark('Temperature:', self.unknownBitmap)
\r
308 self.stopState = self.AddCheckmark('Endstops:', self.unknownBitmap)
\r
309 self.AddSeperator()
\r
310 self.infoBox = self.AddInfoBox()
\r
311 self.machineState = self.AddText('')
\r
312 self.temperatureLabel = self.AddText('')
\r
313 self.AddSeperator()
\r
314 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
\r
316 self.xMinStop = False
\r
317 self.xMaxStop = False
\r
318 self.yMinStop = False
\r
319 self.yMaxStop = False
\r
320 self.zMinStop = False
\r
321 self.zMaxStop = False
\r
324 if self.comm != None:
\r
327 def AllowNext(self):
\r
328 self.endstopBitmap.Show(False)
\r
331 def OnSkipClick(self, e):
\r
332 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
\r
334 def OnCheckClick(self, e = None):
\r
335 if self.comm != None:
\r
339 wx.CallAfter(self.OnCheckClick)
\r
341 self.infoBox.SetInfo('Connecting to machine.')
\r
342 self.infoBox.SetBusyIndicator()
\r
343 self.commState.SetBitmap(self.unknownBitmap)
\r
344 self.tempState.SetBitmap(self.unknownBitmap)
\r
345 self.stopState.SetBitmap(self.unknownBitmap)
\r
346 self.checkupState = 0
\r
347 self.comm = machineCom.MachineCom(callbackObject=self)
\r
349 def mcLog(self, message):
\r
352 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
\r
353 if not self.comm.isOperational():
\r
355 if self.checkupState == 0:
\r
356 self.tempCheckTimeout = 20
\r
358 self.checkupState = 1
\r
359 wx.CallAfter(self.infoBox.SetInfo, 'Cooldown before temperature check.')
\r
360 self.comm.sendCommand('M104 S0')
\r
361 self.comm.sendCommand('M104 S0')
\r
363 self.startTemp = temp
\r
364 self.checkupState = 2
\r
365 wx.CallAfter(self.infoBox.SetInfo, 'Checking the heater and temperature sensor.')
\r
366 self.comm.sendCommand('M104 S200')
\r
367 self.comm.sendCommand('M104 S200')
\r
368 elif self.checkupState == 1:
\r
370 self.startTemp = temp
\r
371 self.checkupState = 2
\r
372 wx.CallAfter(self.infoBox.SetInfo, 'Checking the heater and temperature sensor.')
\r
373 self.comm.sendCommand('M104 S200')
\r
374 self.comm.sendCommand('M104 S200')
\r
375 elif self.checkupState == 2:
\r
376 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
\r
377 if temp > self.startTemp + 40:
\r
378 self.checkupState = 3
\r
379 wx.CallAfter(self.infoBox.SetAttention, 'Please make sure none of the endstops are pressed.')
\r
380 wx.CallAfter(self.endstopBitmap.Show, True)
\r
381 wx.CallAfter(self.Layout)
\r
382 self.comm.sendCommand('M104 S0')
\r
383 self.comm.sendCommand('M104 S0')
\r
384 self.comm.sendCommand('M119')
\r
385 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
\r
387 self.tempCheckTimeout -= 1
\r
388 if self.tempCheckTimeout < 1:
\r
389 self.checkupState = -1
\r
390 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
\r
391 wx.CallAfter(self.infoBox.SetError, 'Temperature measurement FAILED!')
\r
392 self.comm.sendCommand('M104 S0')
\r
393 self.comm.sendCommand('M104 S0')
\r
394 wx.CallAfter(self.temperatureLabel.SetLabel, 'Head temperature: %d' % (temp))
\r
396 def mcStateChange(self, state):
\r
397 if self.comm == None:
\r
399 if self.comm.isOperational():
\r
400 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
\r
401 elif self.comm.isError():
\r
402 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
\r
403 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.')
\r
404 wx.CallAfter(self.endstopBitmap.Show, False)
\r
405 wx.CallAfter(self.machineState.SetLabel, 'Communication State: %s' % (self.comm.getStateString()))
\r
407 def mcMessage(self, message):
\r
408 if self.checkupState >= 3 and self.checkupState < 10 and 'x_min' in message:
\r
409 for data in message.split(' '):
\r
411 tag, value = data.split(':', 2)
\r
413 self.xMinStop = (value == 'H')
\r
415 self.xMaxStop = (value == 'H')
\r
417 self.yMinStop = (value == 'H')
\r
419 self.yMaxStop = (value == 'H')
\r
421 self.zMinStop = (value == 'H')
\r
423 self.zMaxStop = (value == 'H')
\r
424 self.comm.sendCommand('M119')
\r
426 if self.checkupState == 3:
\r
427 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
428 self.checkupState = 4
\r
429 wx.CallAfter(self.infoBox.SetAttention, 'Please press the right X endstop.')
\r
430 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
\r
431 elif self.checkupState == 4:
\r
432 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
433 self.checkupState = 5
\r
434 wx.CallAfter(self.infoBox.SetAttention, 'Please press the left X endstop.')
\r
435 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
\r
436 elif self.checkupState == 5:
\r
437 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
438 self.checkupState = 6
\r
439 wx.CallAfter(self.infoBox.SetAttention, 'Please press the front Y endstop.')
\r
440 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
\r
441 elif self.checkupState == 6:
\r
442 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
443 self.checkupState = 7
\r
444 wx.CallAfter(self.infoBox.SetAttention, 'Please press the back Y endstop.')
\r
445 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
\r
446 elif self.checkupState == 7:
\r
447 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
448 self.checkupState = 8
\r
449 wx.CallAfter(self.infoBox.SetAttention, 'Please press the top Z endstop.')
\r
450 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
\r
451 elif self.checkupState == 8:
\r
452 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
\r
453 self.checkupState = 9
\r
454 wx.CallAfter(self.infoBox.SetAttention, 'Please press the bottom Z endstop.')
\r
455 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
\r
456 elif self.checkupState == 9:
\r
457 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
\r
458 self.checkupState = 10
\r
460 wx.CallAfter(self.infoBox.SetInfo, 'Checkup finished')
\r
461 wx.CallAfter(self.infoBox.SetReadyIndicator)
\r
462 wx.CallAfter(self.endstopBitmap.Show, False)
\r
463 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
\r
464 wx.CallAfter(self.OnSkipClick, None)
\r
466 def mcProgress(self, lineNr):
\r
469 def mcZChange(self, newZ):
\r
472 class UltimakerCalibrationPage(InfoPage):
\r
473 def __init__(self, parent):
\r
474 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
\r
476 self.AddText("Your Ultimaker requires some calibration.")
\r
477 self.AddText("This calibration is needed for a proper extrusion amount.")
\r
478 self.AddSeperator()
\r
479 self.AddText("The following values are needed:")
\r
480 self.AddText("* Diameter of filament")
\r
481 self.AddText("* Number of steps per mm of filament extrusion")
\r
482 self.AddSeperator()
\r
483 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
\r
484 self.AddSeperator()
\r
485 self.AddText("First we need the diameter of your filament:")
\r
486 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
\r
487 self.AddText("If you do not own digital Calipers that can measure\nat least 2 digits then use 2.89mm.\nWhich is the average diameter of most filament.")
\r
488 self.AddText("Note: This value can be changed later at any time.")
\r
490 def StoreData(self):
\r
491 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
\r
493 class UltimakerCalibrateStepsPerEPage(InfoPage):
\r
494 def __init__(self, parent):
\r
495 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
\r
497 if profile.getPreference('steps_per_e') == '0':
\r
498 profile.putPreference('steps_per_e', '865.888')
\r
500 self.AddText("Calibrating the Steps Per E requires some manual actions.")
\r
501 self.AddText("First remove any filament from your machine.")
\r
502 self.AddText("Next put in your filament so the tip is aligned with the\ntop of the extruder drive.")
\r
503 self.AddText("We'll push the filament 100mm")
\r
504 self.extrudeButton = self.AddButton("Extrude 100mm filament")
\r
505 self.AddText("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)")
\r
506 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton('100', 'Save')
\r
507 self.AddText("This results in the following steps per E:")
\r
508 self.stepsPerEInput = self.AddTextCtrl(profile.getPreference('steps_per_e'))
\r
509 self.AddText("You can repeat these steps to get better calibration.")
\r
510 self.AddSeperator()
\r
511 self.AddText("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")
\r
512 self.heatButton = self.AddButton("Heatup for filament removal")
\r
514 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
\r
515 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
\r
516 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
\r
518 def OnSaveLengthClick(self, e):
\r
519 currentEValue = float(self.stepsPerEInput.GetValue())
\r
520 realExtrudeLength = float(self.lengthInput.GetValue())
\r
521 newEValue = currentEValue * 100 / realExtrudeLength
\r
522 self.stepsPerEInput.SetValue(str(newEValue))
\r
523 self.lengthInput.SetValue("100")
\r
525 def OnExtrudeClick(self, e):
\r
526 threading.Thread(target=self.OnExtrudeRun).start()
\r
528 def OnExtrudeRun(self):
\r
529 self.heatButton.Enable(False)
\r
530 self.extrudeButton.Enable(False)
\r
531 currentEValue = float(self.stepsPerEInput.GetValue())
\r
532 self.comm = machineCom.MachineCom()
\r
533 if not self.comm.isOpen():
\r
534 wx.MessageBox("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable", 'Printer error', wx.OK | wx.ICON_INFORMATION)
\r
535 self.heatButton.Enable(True)
\r
536 self.extrudeButton.Enable(True)
\r
539 line = self.comm.readline()
\r
542 if 'start' in line:
\r
544 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
\r
547 self.sendGCommand('M302') #Disable cold extrusion protection
\r
548 self.sendGCommand("M92 E%f" % (currentEValue))
\r
549 self.sendGCommand("G92 E0")
\r
550 self.sendGCommand("G1 E100 F600")
\r
553 self.extrudeButton.Enable()
\r
554 self.heatButton.Enable()
\r
556 def OnHeatClick(self, e):
\r
557 threading.Thread(target=self.OnHeatRun).start()
\r
559 def OnHeatRun(self):
\r
560 self.heatButton.Enable(False)
\r
561 self.extrudeButton.Enable(False)
\r
562 self.comm = machineCom.MachineCom()
\r
563 if not self.comm.isOpen():
\r
564 wx.MessageBox("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable", 'Printer error', wx.OK | wx.ICON_INFORMATION)
\r
565 self.heatButton.Enable(True)
\r
566 self.extrudeButton.Enable(True)
\r
569 line = self.comm.readline()
\r
571 self.heatButton.Enable(True)
\r
572 self.extrudeButton.Enable(True)
\r
574 if 'start' in line:
\r
576 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
\r
579 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
\r
580 wx.MessageBox('Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)', 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
\r
581 self.sendGCommand('M104 S0')
\r
584 self.heatButton.Enable(True)
\r
585 self.extrudeButton.Enable(True)
\r
587 def sendGCommand(self, cmd):
\r
588 self.comm.sendCommand(cmd) #Disable cold extrusion protection
\r
590 line = self.comm.readline()
\r
593 if line.startswith('ok'):
\r
596 def StoreData(self):
\r
597 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
\r
599 class configWizard(wx.wizard.Wizard):
\r
600 def __init__(self):
\r
601 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
\r
603 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
\r
604 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
\r
606 self.firstInfoPage = FirstInfoPage(self)
\r
607 self.machineSelectPage = MachineSelectPage(self)
\r
608 self.ultimakerFirmwareUpgradePage = FirmwareUpgradePage(self)
\r
609 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
\r
610 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
\r
611 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
\r
612 self.repRapInfoPage = RepRapInfoPage(self)
\r
614 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
\r
615 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerFirmwareUpgradePage)
\r
616 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
\r
617 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.ultimakerCalibrationPage)
\r
618 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
\r
620 self.FitToPage(self.firstInfoPage)
\r
621 self.GetPageAreaSizer().Add(self.firstInfoPage)
\r
623 self.RunWizard(self.firstInfoPage)
\r
626 def OnPageChanging(self, e):
\r
627 e.GetPage().StoreData()
\r
629 def OnPageChanged(self, e):
\r
630 if e.GetPage().AllowNext():
\r
631 self.FindWindowById(wx.ID_FORWARD).Enable()
\r
633 self.FindWindowById(wx.ID_FORWARD).Disable()
\r
634 self.FindWindowById(wx.ID_BACKWARD).Disable()
\r