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