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