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