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) == 'Witbox':
49                 return resources.getPathForFirmware("MarlinWitbox.hex")
50         return None
51
52 class InstallFirmware(wx.Dialog):
53         def __init__(self, parent = None, filename = None, port = None, machineIndex = None):
54                 super(InstallFirmware, self).__init__(parent=parent, title="Firmware install for %s" % (profile.getMachineSetting('machine_name', machineIndex).title()), size=(250, 100))
55                 if port is None:
56                         port = profile.getMachineSetting('serial_port')
57                 if filename is None:
58                         filename = getDefaultFirmware(machineIndex)
59                 if filename is None:
60                         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)
61                         self.Destroy()
62                         return
63                 self._machine_type = profile.getMachineSetting('machine_type', machineIndex)
64                 if self._machine_type == 'reprap':
65                         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)
66
67                 sizer = wx.BoxSizer(wx.VERTICAL)
68
69                 self.progressLabel = wx.StaticText(self, -1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nX\nX')
70                 sizer.Add(self.progressLabel, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
71                 self.progressGauge = wx.Gauge(self, -1)
72                 sizer.Add(self.progressGauge, 0, flag=wx.EXPAND)
73                 self.okButton = wx.Button(self, -1, _("OK"))
74                 self.okButton.Disable()
75                 self.okButton.Bind(wx.EVT_BUTTON, self.OnOk)
76                 sizer.Add(self.okButton, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
77                 self.SetSizer(sizer)
78
79                 self.filename = filename
80                 self.port = port
81
82                 self.Layout()
83                 self.Fit()
84
85                 self.thread = threading.Thread(target=self.OnRun)
86                 self.thread.daemon = True
87                 self.thread.start()
88
89                 self.ShowModal()
90                 self.Destroy()
91                 return
92
93         def OnRun(self):
94                 wx.CallAfter(self.updateLabel, _("Reading firmware..."))
95                 hexFile = intelHex.readHex(self.filename)
96                 wx.CallAfter(self.updateLabel, _("Connecting to machine..."))
97                 programmer = stk500v2.Stk500v2()
98                 programmer.progressCallback = self.OnProgress
99                 if self.port == 'AUTO':
100                         wx.CallAfter(self.updateLabel, _("Please connect the printer to\nyour computer with the USB cable."))
101                         while not programmer.isConnected():
102                                 for self.port in machineCom.serialList(True):
103                                         try:
104                                                 programmer.connect(self.port)
105                                                 break
106                                         except ispBase.IspError:
107                                                 pass
108                                 time.sleep(1)
109                                 if not self:
110                                         #Window destroyed
111                                         return
112                 else:
113                         try:
114                                 programmer.connect(self.port)
115                         except ispBase.IspError:
116                                 pass
117
118                 if not programmer.isConnected():
119                         wx.MessageBox(_("Failed to find machine for firmware upgrade\nIs your machine connected to the PC?"),
120                                                   _("Firmware update"), wx.OK | wx.ICON_ERROR)
121                         wx.CallAfter(self.Close)
122                         return
123
124                 if self._machine_type == 'ultimaker':
125                         if programmer.hasChecksumFunction():
126                                 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+?"))
127                                 programmer.close()
128                                 wx.CallAfter(self.okButton.Enable)
129                                 return
130                 if self._machine_type == 'ultimaker_plus' or self._machine_type == 'ultimaker2':
131                         if not programmer.hasChecksumFunction():
132                                 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?"))
133                                 programmer.close()
134                                 wx.CallAfter(self.okButton.Enable)
135                                 return
136
137                 wx.CallAfter(self.updateLabel, _("Uploading firmware..."))
138                 try:
139                         programmer.programChip(hexFile)
140                         wx.CallAfter(self.updateLabel, _("Done!\nInstalled firmware: %s") % (os.path.basename(self.filename)))
141                 except ispBase.IspError as e:
142                         wx.CallAfter(self.updateLabel, _("Failed to write firmware.\n") + str(e))
143
144                 programmer.close()
145                 wx.CallAfter(self.okButton.Enable)
146
147         def updateLabel(self, text):
148                 self.progressLabel.SetLabel(text)
149                 #self.Layout()
150
151         def OnProgress(self, value, max):
152                 wx.CallAfter(self.progressGauge.SetRange, max)
153                 wx.CallAfter(self.progressGauge.SetValue, value)
154                 taskbar.setProgress(self.GetParent(), value, max)
155
156         def OnOk(self, e):
157                 self.Close()
158                 taskbar.setBusy(self.GetParent(), False)
159
160         def OnClose(self, e):
161                 self.Destroy()
162
163
164 class AutoUpdateFirmware(wx.Dialog):
165         def __init__(self, parent, filename = None, port = None, machineIndex = None):
166                 super(AutoUpdateFirmware, self).__init__(parent=parent, title="Auto Firmware install", size=(250, 500))
167                 if port is None:
168                         port = profile.getMachineSetting('serial_port')
169                 self._serial = None
170
171                 sizer = wx.BoxSizer(wx.VERTICAL)
172
173                 self.progressLabel = wx.StaticText(self, -1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nX\nX')
174                 sizer.Add(self.progressLabel, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
175                 self.progressGauge = wx.Gauge(self, -1)
176                 sizer.Add(self.progressGauge, 0, flag=wx.EXPAND)
177                 self.okButton = wx.Button(self, -1, _("OK"))
178                 self.okButton.Bind(wx.EVT_BUTTON, self.OnOk)
179                 sizer.Add(self.okButton, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
180
181                 f = wx.Font(8, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False)
182                 self._termLog = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_DONTWRAP)
183                 self._termLog.SetFont(f)
184                 self._termLog.SetEditable(0)
185                 self._termLog.SetMinSize((1, 400))
186                 self._termInput = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
187                 self._termInput.SetFont(f)
188                 sizer.Add(self._termLog, 0, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
189                 sizer.Add(self._termInput, 0, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
190
191                 self.Bind(wx.EVT_TEXT_ENTER, self.OnTermEnterLine, self._termInput)
192
193                 self.SetSizer(sizer)
194
195                 self.filename = filename
196                 self.port = port
197
198                 self.Layout()
199                 self.Fit()
200
201                 self.thread = threading.Thread(target=self.OnRun)
202                 self.thread.daemon = True
203                 self.thread.start()
204
205                 self.read_thread = threading.Thread(target=self.OnSerialRead)
206                 self.read_thread.daemon = True
207                 self.read_thread.start()
208
209                 self.ShowModal()
210                 self.Destroy()
211                 return
212
213         def _addTermLog(self, line):
214                 if self._termLog is not None:
215                         if len(self._termLog.GetValue()) > 10000:
216                                 self._termLog.SetValue(self._termLog.GetValue()[-10000:])
217                         self._termLog.SetInsertionPointEnd()
218                         if type(line) != unicode:
219                                 line = unicode(line, 'utf-8', 'replace')
220                         self._termLog.AppendText(line.encode('utf-8', 'replace'))
221
222         def OnTermEnterLine(self, e):
223                 lines = self._termInput.GetValue().split(';')
224                 for line in lines:
225                         if line == '':
226                                 continue
227                         self._addTermLog('> %s\n' % (line))
228                         if self._serial is not None:
229                                 self._serial.write(line + '\n')
230
231         def OnRun(self):
232                 mtime = 0
233                 while bool(self):
234                         new_mtime = os.stat(self.filename).st_mtime
235                         if mtime != new_mtime:
236                                 mtime = new_mtime
237                                 if self._serial is not None:
238                                         self._serial.close()
239                                         self._serial = None
240                                 time.sleep(0.5)
241                                 self.OnInstall()
242                                 try:
243                                         self._serial = serial.Serial(self.port, 250000)
244                                 except:
245                                         pass
246                         time.sleep(0.5)
247
248         def OnSerialRead(self):
249                 while bool(self):
250                         if self._serial is None:
251                                 time.sleep(0.5)
252                         else:
253                                 try:
254                                         line = self._serial.readline()
255                                         wx.CallAfter(self._addTermLog, line)
256                                 except:
257                                         pass
258
259         def OnInstall(self):
260                 wx.CallAfter(self.okButton.Disable)
261                 wx.CallAfter(self.updateLabel, _("Reading firmware..."))
262                 hexFile = intelHex.readHex(self.filename)
263                 wx.CallAfter(self.updateLabel, _("Connecting to machine..."))
264                 programmer = stk500v2.Stk500v2()
265                 programmer.progressCallback = self.OnProgress
266                 if self.port == 'AUTO':
267                         wx.CallAfter(self.updateLabel, _("Please connect the printer to\nyour computer with the USB cable."))
268                         while not programmer.isConnected():
269                                 for self.port in machineCom.serialList(True):
270                                         try:
271                                                 programmer.connect(self.port)
272                                                 break
273                                         except ispBase.IspError:
274                                                 pass
275                                 time.sleep(1)
276                                 if not self:
277                                         #Window destroyed
278                                         return
279                 else:
280                         try:
281                                 programmer.connect(self.port)
282                         except ispBase.IspError:
283                                 pass
284
285                 if not programmer.isConnected():
286                         wx.CallAfter(self.updateLabel, _("Failed to connect to programmer.\n"))
287                         return
288
289                 wx.CallAfter(self.updateLabel, _("Uploading firmware..."))
290                 try:
291                         programmer.programChip(hexFile)
292                         wx.CallAfter(self.updateLabel, _("Done!\nInstalled firmware: %s") % (os.path.basename(self.filename)))
293                 except ispBase.IspError as e:
294                         wx.CallAfter(self.updateLabel, _("Failed to write firmware.\n") + str(e))
295
296                 programmer.close()
297                 wx.CallAfter(self.okButton.Enable)
298
299         def updateLabel(self, text):
300                 self.progressLabel.SetLabel(text)
301                 #self.Layout()
302
303         def OnProgress(self, value, max):
304                 wx.CallAfter(self.progressGauge.SetRange, max)
305                 wx.CallAfter(self.progressGauge.SetValue, value)
306                 taskbar.setProgress(self.GetParent(), value, max)
307
308         def OnOk(self, e):
309                 self.Close()
310                 taskbar.setBusy(self.GetParent(), False)
311
312         def OnClose(self, e):
313                 self.Destroy()
314