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