chiark / gitweb /
Add raft airgap setting. Add new machine menu option to machine menu.
[cura.git] / Cura / gui / firmwareInstall.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2
3 import os
4 import wx
5 import threading
6 import sys
7 import time
8 import serial
9
10 from Cura.avr_isp import stk500v2
11 from Cura.avr_isp import ispBase
12 from Cura.avr_isp import intelHex
13
14 from Cura.gui.util import taskbar
15 from Cura.util import machineCom
16 from Cura.util import profile
17 from Cura.util import resources
18
19 def getDefaultFirmware(machineIndex = None):
20         if profile.getMachineSetting('machine_type', machineIndex) == 'ultimaker':
21                 name = 'MarlinUltimaker'
22                 if profile.getMachineSettingFloat('extruder_amount', machineIndex) > 2:
23                         return None
24                 if profile.getMachineSetting('has_heated_bed', machineIndex) == 'True':
25                         name += '-HBK'
26                 if sys.platform.startswith('linux'):
27                         name += '-115200'
28                 else:
29                         name += '-250000'
30                 if profile.getMachineSettingFloat('extruder_amount', machineIndex) > 1:
31                         name += '-dual'
32                 return resources.getPathForFirmware(name + '.hex')
33
34         if profile.getMachineSetting('machine_type', machineIndex) == 'ultimaker_plus':
35                 name = 'MarlinUltimaker-UMOP'
36                 if profile.getMachineSettingFloat('extruder_amount', machineIndex) > 2:
37                         return None
38                 if sys.platform.startswith('linux'):
39                         name += '-115200'
40                 else:
41                         name += '-250000'
42                 if profile.getMachineSettingFloat('extruder_amount', machineIndex) > 1:
43                         name += '-dual'
44                 return resources.getPathForFirmware(name + '.hex')
45
46         if profile.getMachineSetting('machine_type', machineIndex) == 'ultimaker2':
47                 return resources.getPathForFirmware("MarlinUltimaker2.hex")
48         if profile.getMachineSetting('machine_type', machineIndex) == 'lulzbot_mini':
49                 return resources.getPathForFirmware("marlin_mini_2014Q4.hex")
50         if profile.getMachineSetting('machine_type', machineIndex) == 'Witbox':
51                 return resources.getPathForFirmware("MarlinWitbox.hex")
52         return None
53
54 class InstallFirmware(wx.Dialog):
55         def __init__(self, parent = None, filename = None, port = None, machineIndex = None):
56                 super(InstallFirmware, self).__init__(parent=parent, title=_("Firmware install for %s") % (profile.getMachineSetting('machine_name', machineIndex).title()), size=(250, 100))
57                 if port is None:
58                         port = profile.getMachineSetting('serial_port')
59                 if filename is None:
60                         filename = getDefaultFirmware(machineIndex)
61                 if filename is None:
62                         wx.MessageBox(_("I am sorry, but Cura does not ship with a default firmware for your machine configuration."), _("Firmware update"), wx.OK | wx.ICON_ERROR)
63                         self.Destroy()
64                         return
65                 self._machine_type = profile.getMachineSetting('machine_type', machineIndex)
66                 if self._machine_type == 'reprap':
67                         wx.MessageBox(_("Cura only supports firmware updates for ATMega2560 based hardware.\nSo updating your RepRap with Cura might or might not work."), _("Firmware update"), wx.OK | wx.ICON_INFORMATION)
68
69                 sizer = wx.BoxSizer(wx.VERTICAL)
70
71                 self.progressLabel = wx.StaticText(self, -1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nX\nX')
72                 sizer.Add(self.progressLabel, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
73                 self.progressGauge = wx.Gauge(self, -1)
74                 sizer.Add(self.progressGauge, 0, flag=wx.EXPAND)
75                 self.okButton = wx.Button(self, -1, _("OK"))
76                 self.okButton.Disable()
77                 self.okButton.Bind(wx.EVT_BUTTON, self.OnOk)
78                 sizer.Add(self.okButton, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
79                 self.SetSizer(sizer)
80
81                 self.filename = filename
82                 self.port = port
83
84                 self.Layout()
85                 self.Fit()
86
87                 self.thread = threading.Thread(target=self.OnRun)
88                 self.thread.daemon = True
89                 self.thread.start()
90
91                 self.ShowModal()
92                 self.Destroy()
93                 return
94
95         def OnRun(self):
96                 wx.CallAfter(self.updateLabel, _("Reading firmware..."))
97                 hexFile = intelHex.readHex(self.filename)
98                 wx.CallAfter(self.updateLabel, _("Connecting to machine..."))
99                 programmer = stk500v2.Stk500v2()
100                 programmer.progressCallback = self.OnProgress
101                 if self.port == 'AUTO':
102                         wx.CallAfter(self.updateLabel, _("Please connect the printer to\nyour computer with the USB cable."))
103                         while not programmer.isConnected():
104                                 for self.port in machineCom.serialList(True):
105                                         try:
106                                                 programmer.connect(self.port)
107                                                 break
108                                         except ispBase.IspError:
109                                                 pass
110                                 time.sleep(1)
111                                 if not self:
112                                         #Window destroyed
113                                         return
114                 else:
115                         try:
116                                 programmer.connect(self.port)
117                         except ispBase.IspError:
118                                 pass
119
120                 if not programmer.isConnected():
121                         wx.MessageBox(_("Failed to find machine for firmware upgrade\nIs your machine connected to the PC?"),
122                                                   _("Firmware update"), wx.OK | wx.ICON_ERROR)
123                         wx.CallAfter(self.Close)
124                         return
125
126                 if self._machine_type == 'ultimaker':
127                         if programmer.hasChecksumFunction():
128                                 wx.CallAfter(self.updateLabel, _("Failed to install firmware:\nThis firmware is not compatible with this machine.\nTrying to install UMO firmware on an UM2 or UMO+?"))
129                                 programmer.close()
130                                 wx.CallAfter(self.okButton.Enable)
131                                 return
132                 if self._machine_type == 'ultimaker_plus' or self._machine_type == 'ultimaker2':
133                         if not programmer.hasChecksumFunction():
134                                 wx.CallAfter(self.updateLabel, _("Failed to install firmware:\nThis firmware is not compatible with this machine.\nTrying to install UM2 or UMO+ firmware on an UMO?"))
135                                 programmer.close()
136                                 wx.CallAfter(self.okButton.Enable)
137                                 return
138
139                 wx.CallAfter(self.updateLabel, _("Uploading firmware..."))
140                 try:
141                         programmer.programChip(hexFile)
142                         wx.CallAfter(self.updateLabel, _("Done!\nInstalled firmware: %s") % (os.path.basename(self.filename)))
143                 except ispBase.IspError as e:
144                         wx.CallAfter(self.updateLabel, _("Failed to write firmware.\n") + str(e))
145
146                 programmer.close()
147                 wx.CallAfter(self.okButton.Enable)
148
149         def updateLabel(self, text):
150                 self.progressLabel.SetLabel(text)
151                 #self.Layout()
152
153         def OnProgress(self, value, max):
154                 wx.CallAfter(self.progressGauge.SetRange, max)
155                 wx.CallAfter(self.progressGauge.SetValue, value)
156                 taskbar.setProgress(self.GetParent(), value, max)
157
158         def OnOk(self, e):
159                 self.Close()
160                 taskbar.setBusy(self.GetParent(), False)
161
162         def OnClose(self, e):
163                 self.Destroy()
164
165
166 class AutoUpdateFirmware(wx.Dialog):
167         def __init__(self, parent, filename = None, port = None, machineIndex = None):
168                 super(AutoUpdateFirmware, self).__init__(parent=parent, title=_("Auto Firmware install"), size=(250, 500))
169                 if port is None:
170                         port = profile.getMachineSetting('serial_port')
171                 self._serial = None
172
173                 sizer = wx.BoxSizer(wx.VERTICAL)
174
175                 self.progressLabel = wx.StaticText(self, -1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nX\nX')
176                 sizer.Add(self.progressLabel, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
177                 self.progressGauge = wx.Gauge(self, -1)
178                 sizer.Add(self.progressGauge, 0, flag=wx.EXPAND)
179                 self.okButton = wx.Button(self, -1, _("OK"))
180                 self.okButton.Bind(wx.EVT_BUTTON, self.OnOk)
181                 sizer.Add(self.okButton, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
182
183                 f = wx.Font(8, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False)
184                 self._termLog = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_DONTWRAP)
185                 self._termLog.SetFont(f)
186                 self._termLog.SetEditable(0)
187                 self._termLog.SetMinSize((1, 400))
188                 self._termInput = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
189                 self._termInput.SetFont(f)
190                 sizer.Add(self._termLog, 0, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
191                 sizer.Add(self._termInput, 0, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
192
193                 self.Bind(wx.EVT_TEXT_ENTER, self.OnTermEnterLine, self._termInput)
194
195                 self.SetSizer(sizer)
196
197                 self.filename = filename
198                 self.port = port
199
200                 self.Layout()
201                 self.Fit()
202
203                 self.thread = threading.Thread(target=self.OnRun)
204                 self.thread.daemon = True
205                 self.thread.start()
206
207                 self.read_thread = threading.Thread(target=self.OnSerialRead)
208                 self.read_thread.daemon = True
209                 self.read_thread.start()
210
211                 self.ShowModal()
212                 self.Destroy()
213                 return
214
215         def _addTermLog(self, line):
216                 if self._termLog is not None:
217                         if len(self._termLog.GetValue()) > 10000:
218                                 self._termLog.SetValue(self._termLog.GetValue()[-10000:])
219                         self._termLog.SetInsertionPointEnd()
220                         if type(line) != unicode:
221                                 line = unicode(line, 'utf-8', 'replace')
222                         self._termLog.AppendText(line.encode('utf-8', 'replace'))
223
224         def OnTermEnterLine(self, e):
225                 lines = self._termInput.GetValue().split(';')
226                 for line in lines:
227                         if line == '':
228                                 continue
229                         self._addTermLog('> %s\n' % (line))
230                         if self._serial is not None:
231                                 self._serial.write(line + '\n')
232
233         def OnRun(self):
234                 mtime = 0
235                 while bool(self):
236                         new_mtime = os.stat(self.filename).st_mtime
237                         if mtime != new_mtime:
238                                 mtime = new_mtime
239                                 if self._serial is not None:
240                                         self._serial.close()
241                                         self._serial = None
242                                 time.sleep(0.5)
243                                 self.OnInstall()
244                                 try:
245                                         self._serial = serial.Serial(self.port, 250000)
246                                 except:
247                                         pass
248                         time.sleep(0.5)
249
250         def OnSerialRead(self):
251                 while bool(self):
252                         if self._serial is None:
253                                 time.sleep(0.5)
254                         else:
255                                 try:
256                                         line = self._serial.readline()
257                                         wx.CallAfter(self._addTermLog, line)
258                                 except:
259                                         pass
260
261         def OnInstall(self):
262                 wx.CallAfter(self.okButton.Disable)
263                 wx.CallAfter(self.updateLabel, _("Reading firmware..."))
264                 hexFile = intelHex.readHex(self.filename)
265                 wx.CallAfter(self.updateLabel, _("Connecting to machine..."))
266                 programmer = stk500v2.Stk500v2()
267                 programmer.progressCallback = self.OnProgress
268                 if self.port == 'AUTO':
269                         wx.CallAfter(self.updateLabel, _("Please connect the printer to\nyour computer with the USB cable."))
270                         while not programmer.isConnected():
271                                 for self.port in machineCom.serialList(True):
272                                         try:
273                                                 programmer.connect(self.port)
274                                                 break
275                                         except ispBase.IspError:
276                                                 pass
277                                 time.sleep(1)
278                                 if not self:
279                                         #Window destroyed
280                                         return
281                 else:
282                         try:
283                                 programmer.connect(self.port)
284                         except ispBase.IspError:
285                                 pass
286
287                 if not programmer.isConnected():
288                         wx.CallAfter(self.updateLabel, _("Failed to connect to programmer.\n"))
289                         return
290
291                 wx.CallAfter(self.updateLabel, _("Uploading firmware..."))
292                 try:
293                         programmer.programChip(hexFile)
294                         wx.CallAfter(self.updateLabel, _("Done!\nInstalled firmware: %s") % (os.path.basename(self.filename)))
295                 except ispBase.IspError as e:
296                         wx.CallAfter(self.updateLabel, _("Failed to write firmware.\n") + str(e))
297
298                 programmer.close()
299                 wx.CallAfter(self.okButton.Enable)
300
301         def updateLabel(self, text):
302                 self.progressLabel.SetLabel(text)
303                 #self.Layout()
304
305         def OnProgress(self, value, max):
306                 wx.CallAfter(self.progressGauge.SetRange, max)
307                 wx.CallAfter(self.progressGauge.SetValue, value)
308                 taskbar.setProgress(self.GetParent(), value, max)
309
310         def OnOk(self, e):
311                 self.Close()
312                 taskbar.setBusy(self.GetParent(), False)
313
314         def OnClose(self, e):
315                 self.Destroy()
316