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