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