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