chiark / gitweb /
Always use machine size / 2 as machine center and remove the setting. Also fixed...
[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 FirmwareUpgradePage(InfoPage):\r
266         def __init__(self, parent):\r
267                 super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")\r
268                 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
269                 self.AddHiddenSeperator()\r
270                 self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')\r
271                 self.AddHiddenSeperator()\r
272                 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
273                 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')\r
274                 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)\r
275                 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)\r
276                 self.AddHiddenSeperator()\r
277                 self.AddText('Do not upgrade to this firmware if:')\r
278                 self.AddText('* You have an older machine based on ATMega1280')\r
279                 self.AddText('* Have other changes in the firmware')\r
280                 button = self.AddButton('Goto this page for a custom firmware')\r
281                 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)\r
282         \r
283         def AllowNext(self):\r
284                 return False\r
285         \r
286         def OnUpgradeClick(self, e):\r
287                 if firmwareInstall.InstallFirmware():\r
288                         self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
289                 \r
290         def OnSkipClick(self, e):\r
291                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
292         \r
293         def OnUrlClick(self, e):\r
294                 webbrowser.open('http://daid.mine.nu/~daid/marlin_build/')\r
295 \r
296 class UltimakerCheckupPage(InfoPage):\r
297         def __init__(self, parent):\r
298                 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")\r
299 \r
300                 self.checkBitmap = toolbarUtil.getBitmapImage('checkmark.png')\r
301                 self.crossBitmap = toolbarUtil.getBitmapImage('cross.png')\r
302                 self.unknownBitmap = toolbarUtil.getBitmapImage('question.png')\r
303                 self.endStopNoneBitmap = toolbarUtil.getBitmapImage('endstop_none.png')\r
304                 self.endStopXMinBitmap = toolbarUtil.getBitmapImage('endstop_xmin.png')\r
305                 self.endStopXMaxBitmap = toolbarUtil.getBitmapImage('endstop_xmax.png')\r
306                 self.endStopYMinBitmap = toolbarUtil.getBitmapImage('endstop_ymin.png')\r
307                 self.endStopYMaxBitmap = toolbarUtil.getBitmapImage('endstop_ymax.png')\r
308                 self.endStopZMinBitmap = toolbarUtil.getBitmapImage('endstop_zmin.png')\r
309                 self.endStopZMaxBitmap = toolbarUtil.getBitmapImage('endstop_zmax.png')\r
310 \r
311                 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
312                 b1, b2 = self.AddDualButton('Run checks', 'Skip checks')\r
313                 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)\r
314                 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)\r
315                 self.AddSeperator()\r
316                 self.commState = self.AddCheckmark('Communication:', self.unknownBitmap)\r
317                 self.tempState = self.AddCheckmark('Temperature:', self.unknownBitmap)\r
318                 self.stopState = self.AddCheckmark('Endstops:', self.unknownBitmap)\r
319                 self.AddSeperator()\r
320                 self.infoBox = self.AddInfoBox()\r
321                 self.machineState = self.AddText('')\r
322                 self.temperatureLabel = self.AddText('')\r
323                 self.errorLogButton = self.AddButton('Show error log')\r
324                 self.errorLogButton.Show(False)\r
325                 self.AddSeperator()\r
326                 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)\r
327                 self.comm = None\r
328                 self.xMinStop = False\r
329                 self.xMaxStop = False\r
330                 self.yMinStop = False\r
331                 self.yMaxStop = False\r
332                 self.zMinStop = False\r
333                 self.zMaxStop = False\r
334                 \r
335                 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)\r
336 \r
337         def __del__(self):\r
338                 if self.comm != None:\r
339                         self.comm.close()\r
340         \r
341         def AllowNext(self):\r
342                 self.endstopBitmap.Show(False)\r
343                 return False\r
344         \r
345         def OnSkipClick(self, e):\r
346                 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()\r
347         \r
348         def OnCheckClick(self, e = None):\r
349                 self.errorLogButton.Show(False)\r
350                 if self.comm != None:\r
351                         self.comm.close()\r
352                         del self.comm\r
353                         self.comm = None\r
354                         wx.CallAfter(self.OnCheckClick)\r
355                         return\r
356                 self.infoBox.SetInfo('Connecting to machine.')\r
357                 self.infoBox.SetBusyIndicator()\r
358                 self.commState.SetBitmap(self.unknownBitmap)\r
359                 self.tempState.SetBitmap(self.unknownBitmap)\r
360                 self.stopState.SetBitmap(self.unknownBitmap)\r
361                 self.checkupState = 0\r
362                 self.comm = machineCom.MachineCom(callbackObject=self)\r
363         \r
364         def OnErrorLog(self, e):\r
365                 printWindow.LogWindow('\n'.join(self.comm.getLog()))\r
366 \r
367         def mcLog(self, message):\r
368                 pass\r
369 \r
370         def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):\r
371                 if not self.comm.isOperational():\r
372                         return\r
373                 if self.checkupState == 0:\r
374                         self.tempCheckTimeout = 20\r
375                         if temp > 70:\r
376                                 self.checkupState = 1\r
377                                 wx.CallAfter(self.infoBox.SetInfo, 'Cooldown before temperature check.')\r
378                                 self.comm.sendCommand('M104 S0')\r
379                                 self.comm.sendCommand('M104 S0')\r
380                         else:\r
381                                 self.startTemp = temp\r
382                                 self.checkupState = 2\r
383                                 wx.CallAfter(self.infoBox.SetInfo, 'Checking the heater and temperature sensor.')\r
384                                 self.comm.sendCommand('M104 S200')\r
385                                 self.comm.sendCommand('M104 S200')\r
386                 elif self.checkupState == 1:\r
387                         if temp < 60:\r
388                                 self.startTemp = temp\r
389                                 self.checkupState = 2\r
390                                 wx.CallAfter(self.infoBox.SetInfo, 'Checking the heater and temperature sensor.')\r
391                                 self.comm.sendCommand('M104 S200')\r
392                                 self.comm.sendCommand('M104 S200')\r
393                 elif self.checkupState == 2:\r
394                         #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"\r
395                         if temp > self.startTemp + 40:\r
396                                 self.checkupState = 3\r
397                                 wx.CallAfter(self.infoBox.SetAttention, 'Please make sure none of the endstops are pressed.')\r
398                                 wx.CallAfter(self.endstopBitmap.Show, True)\r
399                                 wx.CallAfter(self.Layout)\r
400                                 self.comm.sendCommand('M104 S0')\r
401                                 self.comm.sendCommand('M104 S0')\r
402                                 self.comm.sendCommand('M119')\r
403                                 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)\r
404                         else:\r
405                                 self.tempCheckTimeout -= 1\r
406                                 if self.tempCheckTimeout < 1:\r
407                                         self.checkupState = -1\r
408                                         wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)\r
409                                         wx.CallAfter(self.infoBox.SetError, 'Temperature measurement FAILED!', 'http://wiki.ultimaker.com/Cura/Temperature_measurement_problems')\r
410                                         self.comm.sendCommand('M104 S0')\r
411                                         self.comm.sendCommand('M104 S0')\r
412                 wx.CallAfter(self.temperatureLabel.SetLabel, 'Head temperature: %d' % (temp))\r
413 \r
414         def mcStateChange(self, state):\r
415                 if self.comm == None:\r
416                         return\r
417                 if self.comm.isOperational():\r
418                         wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)\r
419                         wx.CallAfter(self.machineState.SetLabel, 'Communication State: %s' % (self.comm.getStateString()))\r
420                 elif self.comm.isError():\r
421                         wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)\r
422                         wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura/Connection_problems')\r
423                         wx.CallAfter(self.endstopBitmap.Show, False)\r
424                         wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))\r
425                         wx.CallAfter(self.errorLogButton.Show, True)\r
426                         wx.CallAfter(self.Layout)\r
427                 else:\r
428                         wx.CallAfter(self.machineState.SetLabel, 'Communication State: %s' % (self.comm.getStateString()))\r
429         \r
430         def mcMessage(self, message):\r
431                 if self.checkupState >= 3 and self.checkupState < 10 and 'x_min' in message:\r
432                         for data in message.split(' '):\r
433                                 if ':' in data:\r
434                                         tag, value = data.split(':', 2)\r
435                                         if tag == 'x_min':\r
436                                                 self.xMinStop = (value == 'H')\r
437                                         if tag == 'x_max':\r
438                                                 self.xMaxStop = (value == 'H')\r
439                                         if tag == 'y_min':\r
440                                                 self.yMinStop = (value == 'H')\r
441                                         if tag == 'y_max':\r
442                                                 self.yMaxStop = (value == 'H')\r
443                                         if tag == 'z_min':\r
444                                                 self.zMinStop = (value == 'H')\r
445                                         if tag == 'z_max':\r
446                                                 self.zMaxStop = (value == 'H')\r
447                         self.comm.sendCommand('M119')\r
448                         \r
449                         if self.checkupState == 3:\r
450                                 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
451                                         self.checkupState = 4\r
452                                         wx.CallAfter(self.infoBox.SetAttention, 'Please press the right X endstop.')\r
453                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)\r
454                         elif self.checkupState == 4:\r
455                                 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:\r
456                                         self.checkupState = 5\r
457                                         wx.CallAfter(self.infoBox.SetAttention, 'Please press the left X endstop.')\r
458                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)\r
459                         elif self.checkupState == 5:\r
460                                 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:\r
461                                         self.checkupState = 6\r
462                                         wx.CallAfter(self.infoBox.SetAttention, 'Please press the front Y endstop.')\r
463                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)\r
464                         elif self.checkupState == 6:\r
465                                 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:\r
466                                         self.checkupState = 7\r
467                                         wx.CallAfter(self.infoBox.SetAttention, 'Please press the back Y endstop.')\r
468                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)\r
469                         elif self.checkupState == 7:\r
470                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:\r
471                                         self.checkupState = 8\r
472                                         wx.CallAfter(self.infoBox.SetAttention, 'Please press the top Z endstop.')\r
473                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)\r
474                         elif self.checkupState == 8:\r
475                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:\r
476                                         self.checkupState = 9\r
477                                         wx.CallAfter(self.infoBox.SetAttention, 'Please press the bottom Z endstop.')\r
478                                         wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)\r
479                         elif self.checkupState == 9:\r
480                                 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:\r
481                                         self.checkupState = 10\r
482                                         self.comm.close()\r
483                                         wx.CallAfter(self.infoBox.SetInfo, 'Checkup finished')\r
484                                         wx.CallAfter(self.infoBox.SetReadyIndicator)\r
485                                         wx.CallAfter(self.endstopBitmap.Show, False)\r
486                                         wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)\r
487                                         wx.CallAfter(self.OnSkipClick, None)\r
488 \r
489         def mcProgress(self, lineNr):\r
490                 pass\r
491         \r
492         def mcZChange(self, newZ):\r
493                 pass\r
494 \r
495 class UltimakerCalibrationPage(InfoPage):\r
496         def __init__(self, parent):\r
497                 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")\r
498                 \r
499                 self.AddText("Your Ultimaker requires some calibration.")\r
500                 self.AddText("This calibration is needed for a proper extrusion amount.")\r
501                 self.AddSeperator()\r
502                 self.AddText("The following values are needed:")\r
503                 self.AddText("* Diameter of filament")\r
504                 self.AddText("* Number of steps per mm of filament extrusion")\r
505                 self.AddSeperator()\r
506                 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")\r
507                 self.AddSeperator()\r
508                 self.AddText("First we need the diameter of your filament:")\r
509                 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))\r
510                 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
511                 self.AddText("Note: This value can be changed later at any time.")\r
512 \r
513         def StoreData(self):\r
514                 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())\r
515 \r
516 class UltimakerCalibrateStepsPerEPage(InfoPage):\r
517         def __init__(self, parent):\r
518                 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")\r
519 \r
520                 if profile.getPreference('steps_per_e') == '0':\r
521                         profile.putPreference('steps_per_e', '865.888')\r
522                 \r
523                 self.AddText("Calibrating the Steps Per E requires some manual actions.")\r
524                 self.AddText("First remove any filament from your machine.")\r
525                 self.AddText("Next put in your filament so the tip is aligned with the\ntop of the extruder drive.")\r
526                 self.AddText("We'll push the filament 100mm")\r
527                 self.extrudeButton = self.AddButton("Extrude 100mm filament")\r
528                 self.AddText("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)")\r
529                 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton('100', 'Save')\r
530                 self.AddText("This results in the following steps per E:")\r
531                 self.stepsPerEInput = self.AddTextCtrl(profile.getPreference('steps_per_e'))\r
532                 self.AddText("You can repeat these steps to get better calibration.")\r
533                 self.AddSeperator()\r
534                 self.AddText("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")\r
535                 self.heatButton = self.AddButton("Heatup for filament removal")\r
536                 \r
537                 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)\r
538                 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)\r
539                 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)\r
540         \r
541         def OnSaveLengthClick(self, e):\r
542                 currentEValue = float(self.stepsPerEInput.GetValue())\r
543                 realExtrudeLength = float(self.lengthInput.GetValue())\r
544                 newEValue = currentEValue * 100 / realExtrudeLength\r
545                 self.stepsPerEInput.SetValue(str(newEValue))\r
546                 self.lengthInput.SetValue("100")\r
547         \r
548         def OnExtrudeClick(self, e):\r
549                 threading.Thread(target=self.OnExtrudeRun).start()\r
550 \r
551         def OnExtrudeRun(self):\r
552                 self.heatButton.Enable(False)\r
553                 self.extrudeButton.Enable(False)\r
554                 currentEValue = float(self.stepsPerEInput.GetValue())\r
555                 self.comm = machineCom.MachineCom()\r
556                 if not self.comm.isOpen():\r
557                         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
558                         self.heatButton.Enable(True)\r
559                         self.extrudeButton.Enable(True)\r
560                         return\r
561                 while True:\r
562                         line = self.comm.readline()\r
563                         if line == '':\r
564                                 return\r
565                         if 'start' in line:\r
566                                 break\r
567                 #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
568                 time.sleep(3)\r
569                 \r
570                 self.sendGCommand('M302') #Disable cold extrusion protection\r
571                 self.sendGCommand("M92 E%f" % (currentEValue))\r
572                 self.sendGCommand("G92 E0")\r
573                 self.sendGCommand("G1 E100 F600")\r
574                 time.sleep(15)\r
575                 self.comm.close()\r
576                 self.extrudeButton.Enable()\r
577                 self.heatButton.Enable()\r
578 \r
579         def OnHeatClick(self, e):\r
580                 threading.Thread(target=self.OnHeatRun).start()\r
581         \r
582         def OnHeatRun(self):\r
583                 self.heatButton.Enable(False)\r
584                 self.extrudeButton.Enable(False)\r
585                 self.comm = machineCom.MachineCom()\r
586                 if not self.comm.isOpen():\r
587                         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
588                         self.heatButton.Enable(True)\r
589                         self.extrudeButton.Enable(True)\r
590                         return\r
591                 while True:\r
592                         line = self.comm.readline()\r
593                         if line == '':\r
594                                 self.heatButton.Enable(True)\r
595                                 self.extrudeButton.Enable(True)\r
596                                 return\r
597                         if 'start' in line:\r
598                                 break\r
599                 #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
600                 time.sleep(3)\r
601                 \r
602                 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.\r
603                 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
604                 self.sendGCommand('M104 S0')\r
605                 time.sleep(1)\r
606                 self.comm.close()\r
607                 self.heatButton.Enable(True)\r
608                 self.extrudeButton.Enable(True)\r
609         \r
610         def sendGCommand(self, cmd):\r
611                 self.comm.sendCommand(cmd) #Disable cold extrusion protection\r
612                 while True:\r
613                         line = self.comm.readline()\r
614                         if line == '':\r
615                                 return\r
616                         if line.startswith('ok'):\r
617                                 break\r
618         \r
619         def StoreData(self):\r
620                 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())\r
621 \r
622 class configWizard(wx.wizard.Wizard):\r
623         def __init__(self):\r
624                 super(configWizard, self).__init__(None, -1, "Configuration Wizard")\r
625                 \r
626                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)\r
627                 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)\r
628 \r
629                 self.firstInfoPage = FirstInfoPage(self)\r
630                 self.machineSelectPage = MachineSelectPage(self)\r
631                 self.ultimakerFirmwareUpgradePage = FirmwareUpgradePage(self)\r
632                 self.ultimakerCheckupPage = UltimakerCheckupPage(self)\r
633                 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)\r
634                 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)\r
635                 self.repRapInfoPage = RepRapInfoPage(self)\r
636 \r
637                 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)\r
638                 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerFirmwareUpgradePage)\r
639                 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)\r
640                 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.ultimakerCalibrationPage)\r
641                 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)\r
642                 \r
643                 self.FitToPage(self.firstInfoPage)\r
644                 self.GetPageAreaSizer().Add(self.firstInfoPage)\r
645                 \r
646                 self.RunWizard(self.firstInfoPage)\r
647                 self.Destroy()\r
648 \r
649         def OnPageChanging(self, e):\r
650                 e.GetPage().StoreData()\r
651 \r
652         def OnPageChanged(self, e):\r
653                 if e.GetPage().AllowNext():\r
654                         self.FindWindowById(wx.ID_FORWARD).Enable() \r
655                 else:\r
656                         self.FindWindowById(wx.ID_FORWARD).Disable() \r
657                 self.FindWindowById(wx.ID_BACKWARD).Disable() \r