chiark / gitweb /
Large update to the config wizard, new style machine check (unfinished)
[cura.git] / Cura / gui / configWizard.py
1 from __future__ import absolute_import\r
2 import __init__\r
3 \r
4 import wx, os, platform, types, webbrowser, threading, time, re\r
5 import wx.wizard\r
6 \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
11 \r
12 class InfoPage(wx.wizard.WizardPageSimple):\r
13         def __init__(self, parent, title):\r
14                 wx.wizard.WizardPageSimple.__init__(self, parent)\r
15 \r
16                 sizer = wx.GridBagSizer(5, 5)\r
17                 self.sizer = sizer\r
18                 self.SetSizer(sizer)\r
19 \r
20                 title = wx.StaticText(self, -1, title)\r
21                 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))\r
22                 sizer.Add(title, pos=(0, 0), span=(1,2), flag=wx.ALIGN_CENTRE|wx.ALL)\r
23                 sizer.Add(wx.StaticLine(self, -1), pos=(1,0), span=(1,2), flag=wx.EXPAND|wx.ALL)\r
24                 sizer.AddGrowableCol(1)\r
25                 \r
26                 self.rowNr = 2\r
27         \r
28         def AddText(self,info):\r
29                 text = wx.StaticText(self, -1, info)\r
30                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT|wx.RIGHT)\r
31                 self.rowNr += 1\r
32                 return text\r
33         \r
34         def AddSeperator(self):\r
35                 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1,2), flag=wx.EXPAND|wx.ALL)\r
36                 self.rowNr += 1\r
37         \r
38         def AddHiddenSeperator(self):\r
39                 self.AddText('')\r
40         \r
41         def AddRadioButton(self, label, style = 0):\r
42                 radio = wx.RadioButton(self, -1, label, style=style)\r
43                 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1,2), flag=wx.EXPAND|wx.ALL)\r
44                 self.rowNr += 1\r
45                 return radio\r
46 \r
47         def AddCheckbox(self, label, checked = False):\r
48                 check = wx.CheckBox(self, -1)\r
49                 text = wx.StaticText(self, -1, label)\r
50                 check.SetValue(checked)\r
51                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT|wx.RIGHT)\r
52                 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1,2), flag=wx.ALL)\r
53                 self.rowNr += 1\r
54                 return check\r
55         \r
56         def AddButton(self, label):\r
57                 button = wx.Button(self, -1, label)\r
58                 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT)\r
59                 self.rowNr += 1\r
60                 return button\r
61         \r
62         def AddDualButton(self, label1, label2):\r
63                 button1 = wx.Button(self, -1, label1)\r
64                 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)\r
65                 button2 = wx.Button(self, -1, label2)\r
66                 self.GetSizer().Add(button2, pos=(self.rowNr, 1))\r
67                 self.rowNr += 1\r
68                 return button1, button2\r
69         \r
70         def AddTextCtrl(self, value):\r
71                 ret = wx.TextCtrl(self, -1, value)\r
72                 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT)\r
73                 self.rowNr += 1\r
74                 return ret\r
75 \r
76         def AddLabelTextCtrl(self, info, value):\r
77                 text = wx.StaticText(self, -1, info)\r
78                 ret = wx.TextCtrl(self, -1, value)\r
79                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT)\r
80                 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1,1), flag=wx.LEFT)\r
81                 self.rowNr += 1\r
82                 return ret\r
83         \r
84         def AddTextCtrlButton(self, value, buttonText):\r
85                 text = wx.TextCtrl(self, -1, value)\r
86                 button = wx.Button(self, -1, buttonText)\r
87                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT)\r
88                 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1,1), flag=wx.LEFT)\r
89                 self.rowNr += 1\r
90                 return text, button\r
91 \r
92         def AddCheckmark(self, label, bitmap):\r
93                 check = wx.StaticBitmap(self, -1, bitmap)\r
94                 text = wx.StaticText(self, -1, label)\r
95                 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT|wx.RIGHT)\r
96                 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1,2), flag=wx.ALL)\r
97                 self.rowNr += 1\r
98                 return check\r
99                 \r
100         def AllowNext(self):\r
101                 return True\r
102         \r
103         def StoreData(self):\r
104                 pass\r
105 \r
106 class FirstInfoPage(InfoPage):\r
107         def __init__(self, parent):\r
108                 super(FirstInfoPage, self).__init__(parent, "First time run wizard")\r
109                 self.AddText('Welcome, and thanks for trying Cura!')\r
110                 self.AddSeperator()\r
111                 self.AddText('This wizard will help you with the following steps:')\r
112                 self.AddText('* Configure Cura for your machine')\r
113                 self.AddText('* Upgrade your firmware')\r
114                 self.AddText('* Check if your machine is working safely')\r
115                 #self.AddText('* Calibrate your machine')\r
116                 #self.AddText('* Do your first print')\r
117 \r
118 class RepRapInfoPage(InfoPage):\r
119         def __init__(self, parent):\r
120                 super(RepRapInfoPage, self).__init__(parent, "RepRap information")\r
121                 self.AddText('RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them.')\r
122                 self.AddText('If you like a default profile for your machine added,\nthen make an issue on github.')\r
123                 self.AddSeperator()\r
124                 self.AddText('You will have to manually install Marlin or Sprinter firmware.')\r
125                 self.AddSeperator()\r
126                 self.machineWidth = self.AddLabelTextCtrl('Machine width (mm)', '80')\r
127                 self.machineDepth = self.AddLabelTextCtrl('Machine depth (mm)', '80')\r
128                 self.machineHeight = self.AddLabelTextCtrl('Machine height (mm)', '60')\r
129                 self.nozzleSize = self.AddLabelTextCtrl('Nozzle size (mm)', '0.5')\r
130                 self.heatedBed = self.AddCheckbox('Heated bed')\r
131 \r
132         def StoreData(self):\r
133                 profile.putPreference('machine_width', self.machineWidth.GetValue())\r
134                 profile.putPreference('machine_depth', self.machineDepth.GetValue())\r
135                 profile.putPreference('machine_height', self.machineHeight.GetValue())\r
136                 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())\r
137                 profile.putProfileSetting('machine_center_x', profile.getPreferenceFloat('machine_width') / 2)\r
138                 profile.putProfileSetting('machine_center_y', profile.getPreferenceFloat('machine_depth') / 2)\r
139                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)\r
140                 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))\r
141 \r
142 class MachineSelectPage(InfoPage):\r
143         def __init__(self, parent):\r
144                 super(MachineSelectPage, self).__init__(parent, "Select your machine")\r
145                 self.AddText('What kind of machine do you have:')\r
146 \r
147                 self.UltimakerRadio = self.AddRadioButton("Ultimaker", style=wx.RB_GROUP)\r
148                 self.UltimakerRadio.SetValue(True)\r
149                 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)\r
150                 self.OtherRadio = self.AddRadioButton("Other (Ex: RepRap)")\r
151                 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)\r
152                 \r
153         def OnUltimakerSelect(self, e):\r
154                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)\r
155                 \r
156         def OnOtherSelect(self, e):\r
157                 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)\r
158         \r
159         def StoreData(self):\r
160                 if self.UltimakerRadio.GetValue():\r
161                         profile.putPreference('machine_width', '205')\r
162                         profile.putPreference('machine_depth', '205')\r
163                         profile.putPreference('machine_height', '200')\r
164                         profile.putPreference('machine_type', 'ultimaker')\r
165                         profile.putProfileSetting('nozzle_size', '0.4')\r
166                         profile.putProfileSetting('machine_center_x', '100')\r
167                         profile.putProfileSetting('machine_center_y', '100')\r
168                 else:\r
169                         profile.putPreference('machine_width', '80')\r
170                         profile.putPreference('machine_depth', '80')\r
171                         profile.putPreference('machine_height', '60')\r
172                         profile.putPreference('machine_type', 'reprap')\r
173                         profile.putProfileSetting('nozzle_size', '0.5')\r
174                         profile.putProfileSetting('machine_center_x', '40')\r
175                         profile.putProfileSetting('machine_center_y', '40')\r
176                 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)\r
177 \r
178 class FirmwareUpgradePage(InfoPage):\r
179         def __init__(self, parent):\r
180                 super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")\r
181                 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
182                 self.AddHiddenSeperator()\r
183                 self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')\r
184                 self.AddHiddenSeperator()\r
185                 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
186                 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')\r
187                 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)\r
188                 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)\r
189                 self.AddHiddenSeperator()\r
190                 self.AddText('Do not upgrade to this firmware if:')\r
191                 self.AddText('* You have an older machine based on ATMega1280')\r
192                 self.AddText('* Have other changes in the firmware')\r
193                 button = self.AddButton('Goto this page for a custom firmware')\r
194                 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)\r
195         \r
196         def AllowNext(self):\r
197                 return False\r
198         \r
199         def OnUpgradeClick(self, e):\r
200                 if firmwareInstall.InstallFirmware():\r
201                         self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
202                 \r
203         def OnSkipClick(self, e):\r
204                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
205         \r
206         def OnUrlClick(self, e):\r
207                 webbrowser.open('http://daid.mine.nu/~daid/marlin_build/')\r
208 \r
209 class UltimakerCheckupPage(InfoPage):\r
210         def __init__(self, parent):\r
211                 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")\r
212                 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
213                 b1, b2 = self.AddDualButton('Run checks', 'Skip checks')\r
214                 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)\r
215                 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)\r
216                 self.AddSeperator()\r
217                 self.checkBitmap = toolbarUtil.getBitmapImage('checkmark.png')\r
218                 self.crossBitmap = toolbarUtil.getBitmapImage('cross.png')\r
219                 self.unknownBitmap = toolbarUtil.getBitmapImage('question.png')\r
220                 self.commState = self.AddCheckmark('Communication:', self.unknownBitmap)\r
221                 self.tempState = self.AddCheckmark('Temperature:', self.unknownBitmap)\r
222                 self.stopState = self.AddCheckmark('Endstops:', self.unknownBitmap)\r
223                 self.AddSeperator()\r
224                 self.checkState = self.AddText('')\r
225                 self.machineState = self.AddText('')\r
226                 self.temperatureLabel = self.AddText('')\r
227                 self.comm = None\r
228                 self.xMinStop = False\r
229                 self.xMaxStop = False\r
230                 self.yMinStop = False\r
231                 self.yMaxStop = False\r
232                 self.zMinStop = False\r
233                 self.zMaxStop = False\r
234 \r
235         def AllowNext(self):\r
236                 return False\r
237         \r
238         def OnSkipClick(self, e):\r
239                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
240         \r
241         def OnCheckClick(self, e):\r
242                 if self.comm != None:\r
243                         self.comm.close()\r
244                         del self.comm\r
245                 wx.CallAfter(self.checkState.SetLabel, 'Connecting to machine.')\r
246                 self.commState.SetBitmap(self.unknownBitmap)\r
247                 self.tempState.SetBitmap(self.unknownBitmap)\r
248                 self.stopState.SetBitmap(self.unknownBitmap)\r
249                 self.checkupState = 0\r
250                 self.comm = machineCom.MachineCom(callbackObject=self)\r
251 \r
252         def mcLog(self, message):\r
253                 print message\r
254 \r
255         def mcTempUpdate(self, temp, bedTemp):\r
256                 if self.checkupState == 0:\r
257                         self.tempCheckTimeout = 20\r
258                         if temp > 70:\r
259                                 self.checkupState = 1\r
260                                 wx.CallAfter(self.checkState.SetLabel, 'Cooldown before temperature check.')\r
261                                 self.comm.sendCommand('M104 S0')\r
262                                 self.comm.sendCommand('M104 S0')\r
263                         else:\r
264                                 self.startTemp = temp\r
265                                 self.checkupState = 2\r
266                                 wx.CallAfter(self.checkState.SetLabel, 'Checking the heater and temperature sensor.')\r
267                                 self.comm.sendCommand('M104 S200')\r
268                                 self.comm.sendCommand('M104 S200')\r
269                 elif self.checkupState == 1:\r
270                         if temp < 60:\r
271                                 self.startTemp = temp\r
272                                 self.checkupState = 2\r
273                                 wx.CallAfter(self.checkState.SetLabel, 'Checking the heater and temperature sensor.')\r
274                                 self.comm.sendCommand('M104 S200')\r
275                                 self.comm.sendCommand('M104 S200')\r
276                 elif self.checkupState == 2:\r
277                         if temp > self.startTemp:# + 40:\r
278                                 self.checkupState = 3\r
279                                 wx.CallAfter(self.checkState.SetLabel, 'Testing the endstops...')\r
280                                 self.comm.sendCommand('M104 S0')\r
281                                 self.comm.sendCommand('M104 S0')\r
282                                 self.comm.sendCommand('M119')\r
283                                 self.tempState.SetBitmap(self.checkBitmap)\r
284                         else:\r
285                                 self.tempCheckTimeout -= 1\r
286                                 if self.tempCheckTimeout < 1:\r
287                                         self.checkupState = -1\r
288                                         self.tempState.SetBitmap(self.crossBitmap)\r
289                                         wx.CallAfter(self.checkState.SetLabel, 'Temperature measurement FAILED!')\r
290                                         self.comm.sendCommand('M104 S0')\r
291                                         self.comm.sendCommand('M104 S0')\r
292                 wx.CallAfter(self.temperatureLabel.SetLabel, 'Head temperature: %d' % (temp))\r
293 \r
294         def mcStateChange(self, state):\r
295                 if self.comm.isOperational():\r
296                         self.commState.SetBitmap(self.checkBitmap)\r
297                 elif self.comm.isError():\r
298                         self.commState.SetBitmap(self.crossBitmap)\r
299                 wx.CallAfter(self.machineState.SetLabel, 'Communication State: %s' % (self.comm.getStateString()))\r
300         \r
301         def mcMessage(self, message):\r
302                 if self.checkupState >= 3 and 'x_min' in message:\r
303                         for data in message.split(' '):\r
304                                 if ':' in data:\r
305                                         tag, value = data.split(':', 2)\r
306                                         if tag == 'x_min':\r
307                                                 self.xMinStop = (value == 'H')\r
308                                         if tag == 'x_max':\r
309                                                 self.xMaxStop = (value == 'H')\r
310                                         if tag == 'y_min':\r
311                                                 self.yMinStop = (value == 'H')\r
312                                         if tag == 'y_max':\r
313                                                 self.yMaxStop = (value == 'H')\r
314                                         if tag == 'z_min':\r
315                                                 self.zMinStop = (value == 'H')\r
316                                         if tag == 'z_max':\r
317                                                 self.zMaxStop = (value == 'H')\r
318                         self.comm.sendCommand('M119')\r
319 \r
320         def mcProgress(self, lineNr):\r
321                 pass\r
322         \r
323         def mcZChange(self, newZ):\r
324                 pass\r
325 \r
326 class UltimakerCalibrationPage(InfoPage):\r
327         def __init__(self, parent):\r
328                 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")\r
329                 \r
330                 self.AddText("Your Ultimaker requires some calibration.")\r
331                 self.AddText("This calibration is needed for a proper extrusion amount.")\r
332                 self.AddSeperator()\r
333                 self.AddText("The following values are needed:")\r
334                 self.AddText("* Diameter of filament")\r
335                 self.AddText("* Number of steps per mm of filament extrusion")\r
336                 self.AddSeperator()\r
337                 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")\r
338                 self.AddSeperator()\r
339                 self.AddText("First we need the diameter of your filament:")\r
340                 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))\r
341                 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
342                 self.AddText("Note: This value can be changed later at any time.")\r
343 \r
344         def StoreData(self):\r
345                 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())\r
346 \r
347 class UltimakerCalibrateStepsPerEPage(InfoPage):\r
348         def __init__(self, parent):\r
349                 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")\r
350 \r
351                 if profile.getPreference('steps_per_e') == '0':\r
352                         profile.putPreference('steps_per_e', '865.888')\r
353                 \r
354                 self.AddText("Calibrating the Steps Per E requires some manual actions.")\r
355                 self.AddText("First remove any filament from your machine.")\r
356                 self.AddText("Next put in your filament so the tip is aligned with the\ntop of the extruder drive.")\r
357                 self.AddText("We'll push the filament 100mm")\r
358                 self.extrudeButton = self.AddButton("Extrude 100mm filament")\r
359                 self.AddText("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)")\r
360                 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton('100', 'Save')\r
361                 self.AddText("This results in the following steps per E:")\r
362                 self.stepsPerEInput = self.AddTextCtrl(profile.getPreference('steps_per_e'))\r
363                 self.AddText("You can repeat these steps to get better calibration.")\r
364                 self.AddSeperator()\r
365                 self.AddText("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")\r
366                 self.heatButton = self.AddButton("Heatup for filament removal")\r
367                 \r
368                 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)\r
369                 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)\r
370                 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)\r
371         \r
372         def OnSaveLengthClick(self, e):\r
373                 currentEValue = float(self.stepsPerEInput.GetValue())\r
374                 realExtrudeLength = float(self.lengthInput.GetValue())\r
375                 newEValue = currentEValue * 100 / realExtrudeLength\r
376                 self.stepsPerEInput.SetValue(str(newEValue))\r
377                 self.lengthInput.SetValue("100")\r
378         \r
379         def OnExtrudeClick(self, e):\r
380                 threading.Thread(target=self.OnExtrudeRun).start()\r
381 \r
382         def OnExtrudeRun(self):\r
383                 self.heatButton.Enable(False)\r
384                 self.extrudeButton.Enable(False)\r
385                 currentEValue = float(self.stepsPerEInput.GetValue())\r
386                 self.comm = machineCom.MachineCom()\r
387                 if not self.comm.isOpen():\r
388                         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
389                         self.heatButton.Enable(True)\r
390                         self.extrudeButton.Enable(True)\r
391                         return\r
392                 while True:\r
393                         line = self.comm.readline()\r
394                         if line == '':\r
395                                 return\r
396                         if 'start' in line:\r
397                                 break\r
398                 #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
399                 time.sleep(3)\r
400                 \r
401                 self.sendGCommand('M302') #Disable cold extrusion protection\r
402                 self.sendGCommand("M92 E%f" % (currentEValue))\r
403                 self.sendGCommand("G92 E0")\r
404                 self.sendGCommand("G1 E100 F600")\r
405                 time.sleep(15)\r
406                 self.comm.close()\r
407                 self.extrudeButton.Enable()\r
408                 self.heatButton.Enable()\r
409 \r
410         def OnHeatClick(self, e):\r
411                 threading.Thread(target=self.OnHeatRun).start()\r
412         \r
413         def OnHeatRun(self):\r
414                 self.heatButton.Enable(False)\r
415                 self.extrudeButton.Enable(False)\r
416                 self.comm = machineCom.MachineCom()\r
417                 if not self.comm.isOpen():\r
418                         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
419                         self.heatButton.Enable(True)\r
420                         self.extrudeButton.Enable(True)\r
421                         return\r
422                 while True:\r
423                         line = self.comm.readline()\r
424                         if line == '':\r
425                                 self.heatButton.Enable(True)\r
426                                 self.extrudeButton.Enable(True)\r
427                                 return\r
428                         if 'start' in line:\r
429                                 break\r
430                 #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
431                 time.sleep(3)\r
432                 \r
433                 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.\r
434                 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
435                 self.sendGCommand('M104 S0')\r
436                 time.sleep(1)\r
437                 self.comm.close()\r
438                 self.heatButton.Enable(True)\r
439                 self.extrudeButton.Enable(True)\r
440         \r
441         def sendGCommand(self, cmd):\r
442                 self.comm.sendCommand(cmd) #Disable cold extrusion protection\r
443                 while True:\r
444                         line = self.comm.readline()\r
445                         if line == '':\r
446                                 return\r
447                         if line.startswith('ok'):\r
448                                 break\r
449         \r
450         def StoreData(self):\r
451                 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())\r
452 \r
453 class configWizard(wx.wizard.Wizard):\r
454         def __init__(self):\r
455                 super(configWizard, self).__init__(None, -1, "Configuration Wizard")\r
456                 \r
457                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)\r
458                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)\r
459 \r
460                 self.firstInfoPage = FirstInfoPage(self)\r
461                 self.machineSelectPage = MachineSelectPage(self)\r
462                 self.ultimakerFirmwareUpgradePage = FirmwareUpgradePage(self)\r
463                 self.ultimakerCheckupPage = UltimakerCheckupPage(self)\r
464                 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)\r
465                 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)\r
466                 self.repRapInfoPage = RepRapInfoPage(self)\r
467 \r
468                 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)\r
469                 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerFirmwareUpgradePage)\r
470                 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)\r
471                 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.ultimakerCalibrationPage)\r
472                 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)\r
473                 \r
474                 self.FitToPage(self.firstInfoPage)\r
475                 self.GetPageAreaSizer().Add(self.firstInfoPage)\r
476                 \r
477                 self.RunWizard(self.firstInfoPage)\r
478                 self.Destroy()\r
479 \r
480         def OnPageChanging(self, e):\r
481                 e.GetPage().StoreData()\r
482 \r
483         def OnPageChanged(self, e):\r
484                 if e.GetPage().AllowNext():\r
485                         self.FindWindowById(wx.ID_FORWARD).Enable() \r
486                 else:\r
487                         self.FindWindowById(wx.ID_FORWARD).Disable() \r
488                 self.FindWindowById(wx.ID_BACKWARD).Disable() \r