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