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