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