1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
10 from Cura.avr_isp import stk500v2
11 from Cura.avr_isp import ispBase
12 from Cura.avr_isp import intelHex
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
19 def getDefaultFirmware(machineIndex = None):
20 machine_type = profile.getMachineSetting('machine_type', machineIndex)
21 extruders = profile.getMachineSettingFloat('extruder_amount', machineIndex)
22 heated_bed = profile.getMachineSetting('has_heated_bed', machineIndex) == 'True'
24 if sys.platform.startswith('linux'):
26 if machine_type == 'ultimaker':
27 name = 'MarlinUltimaker'
32 name += '-%d' % (baudrate)
35 return resources.getPathForFirmware(name + '.hex')
37 if machine_type == 'ultimaker_plus':
38 name = 'MarlinUltimaker-UMOP-%d' % (baudrate)
43 return resources.getPathForFirmware(name + '.hex')
45 if machine_type == 'ultimaker2':
49 return resources.getPathForFirmware("MarlinUltimaker2-dual.hex")
50 return resources.getPathForFirmware("MarlinUltimaker2.hex")
51 if machine_type == 'lulzbot_mini':
52 return resources.getPathForFirmware("Mini_SingleV2_2014Q4.hex")
53 if machine_type == 'lulzbot_mini_flexy':
54 return resources.getPathForFirmware("Mini_FlexyV2_2014Q4.hex")
55 if machine_type == 'lulzbot_TAZ_4_SingleV1' or machine_type == 'lulzbot_TAZ_5_Single_V1':
56 return resources.getPathForFirmware("TAZ4-5_SingleV1_2014Q1.hex")
57 if machine_type == 'lulzbot_TAZ_4_05nozzle' or machine_type == 'lulzbot_TAZ_5_05nozzle' or \
58 machine_type == 'lulzbot_TAZ_4_035nozzle' or machine_type == 'lulzbot_TAZ_5_035nozzle':
59 return resources.getPathForFirmware("TAZ4-5_SingleV2_2015Q1.hex")
60 if machine_type == 'lulzbot_TAZ_4_FlexystruderV1' or machine_type == 'lulzbot_TAZ_5_FlexystruderV1':
61 return resources.getPathForFirmware("TAZ4-5_FlexystrderV1_2015Q3.hex")
62 if machine_type == 'lulzbot_TAZ_4_FlexystruderV2' or machine_type == 'lulzbot_TAZ_5_FlexystruderV2':
63 return resources.getPathForFirmware("TAZ4-5_FlexystrderV2_2015Q3.hex")
64 if machine_type == 'lulzbot_TAZ_4_DuallyV1' or machine_type == 'lulzbot_TAZ_5_DuallyV1':
65 return resources.getPathForFirmware("TAZ4-5_Dual-Extruder_V1_2015Q3.hex")
66 if machine_type == 'lulzbot_TAZ_4_DuallyV2' or machine_type == 'lulzbot_TAZ_5_DuallyV2':
67 return resources.getPathForFirmware("TAZ4-5_Dual-Extruder_V2_2015Q3.hex")
68 if machine_type == 'lulzbot_TAZ_4_FlexyDuallyV1' or machine_type == 'lulzbot_TAZ_5_FlexyDuallyV1':
69 return resources.getPathForFirmware("TAZ4-5_FlexyDually-V1_2015Q3.hex")
70 if machine_type == 'lulzbot_TAZ_4_FlexyDuallyV2' or machine_type == 'lulzbot_TAZ_5_FlexyDuallyV2':
71 return resources.getPathForFirmware("TAZ4-5_FlexyDually-V2_2015Q3.hex")
72 if machine_type == 'ultimaker2go':
73 return resources.getPathForFirmware("MarlinUltimaker2go.hex")
74 if machine_type == 'ultimaker2extended':
78 return resources.getPathForFirmware("MarlinUltimaker2extended-dual.hex")
79 return resources.getPathForFirmware("MarlinUltimaker2extended.hex")
80 if machine_type == 'Witbox':
81 return resources.getPathForFirmware("MarlinWitbox.hex")
84 def InstallFirmware(parent = None, filename = None, port = None, machineIndex = None):
85 dlg = InstallFirmwareDialog(parent, filename, port, machineIndex)
90 class InstallFirmwareDialog(wx.Dialog):
91 def __init__(self, parent = None, filename = None, port = None, machineIndex = None):
92 super(InstallFirmwareDialog, self).__init__(parent=parent, title=_("Firmware install for %s") % (profile.getMachineName(machineIndex).title()), size=(250, 100))
94 port = profile.getMachineSetting('serial_port')
96 filename = getDefaultFirmware(machineIndex)
98 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)
101 self._machine_type = profile.getMachineSetting('machine_type', machineIndex)
102 if self._machine_type == 'reprap':
103 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)
105 sizer = wx.BoxSizer(wx.VERTICAL)
107 self.progressLabel = wx.StaticText(self, -1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nX\nX')
108 sizer.Add(self.progressLabel, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
109 self.progressGauge = wx.Gauge(self, -1)
110 sizer.Add(self.progressGauge, 0, flag=wx.EXPAND)
111 self.okButton = wx.Button(self, -1, _("OK"))
112 self.okButton.Disable()
113 self.okButton.Bind(wx.EVT_BUTTON, self.OnOk)
114 sizer.Add(self.okButton, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
117 self.filename = filename
126 self.thread = threading.Thread(target=self.OnRun)
127 self.thread.daemon = True
134 wx.CallAfter(self.updateLabel, _("Reading firmware..."))
135 hexFile = intelHex.readHex(self.filename)
136 wx.CallAfter(self.updateLabel, _("Connecting to machine..."))
137 programmer = stk500v2.Stk500v2()
138 programmer.progressCallback = self.OnProgress
139 if self.port == 'AUTO':
140 wx.CallAfter(self.updateLabel, _("Please connect the printer to\nyour computer with the USB cable."))
141 while not programmer.isConnected():
142 for self.port in machineCom.serialList(True):
144 programmer.connect(self.port)
146 except ispBase.IspError:
154 programmer.connect(self.port)
155 except ispBase.IspError:
158 if not programmer.isConnected():
159 wx.MessageBox(_("Failed to find machine for firmware upgrade\nIs your machine connected to the PC?"),
160 _("Firmware update"), wx.OK | wx.ICON_ERROR)
161 wx.CallAfter(self.Close)
164 if self._machine_type == 'ultimaker':
165 if programmer.hasChecksumFunction():
166 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+?"))
168 wx.CallAfter(self.okButton.Enable)
170 if self._machine_type == 'ultimaker_plus' or self._machine_type == 'ultimaker2':
171 if not programmer.hasChecksumFunction():
172 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?"))
174 wx.CallAfter(self.okButton.Enable)
177 wx.CallAfter(self.updateLabel, _("Uploading firmware..."))
179 programmer.programChip(hexFile)
181 wx.CallAfter(self.updateLabel, _("Done!\nInstalled firmware: %s") % (os.path.basename(self.filename)))
182 except ispBase.IspError as e:
183 wx.CallAfter(self.updateLabel, _("Failed to write firmware.\n") + str(e))
186 wx.CallAfter(self.okButton.Enable)
188 def updateLabel(self, text):
189 self.progressLabel.SetLabel(text)
192 def OnProgress(self, value, max):
194 wx.CallAfter(self.progressGauge.SetRange, max)
195 wx.CallAfter(self.progressGauge.SetValue, value)
196 taskbar.setProgress(self.GetParent(), value, max)
200 taskbar.setBusy(self.GetParent(), False)
202 def OnClose(self, e):
206 class AutoUpdateFirmware(wx.Dialog):
207 def __init__(self, parent, filename = None, port = None, machineIndex = None):
208 super(AutoUpdateFirmware, self).__init__(parent=parent, title=_("Auto Firmware install"), size=(250, 500))
210 port = profile.getMachineSetting('serial_port')
213 sizer = wx.BoxSizer(wx.VERTICAL)
215 self.progressLabel = wx.StaticText(self, -1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nX\nX')
216 sizer.Add(self.progressLabel, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
217 self.progressGauge = wx.Gauge(self, -1)
218 sizer.Add(self.progressGauge, 0, flag=wx.EXPAND)
219 self.okButton = wx.Button(self, -1, _("OK"))
220 self.okButton.Bind(wx.EVT_BUTTON, self.OnOk)
221 sizer.Add(self.okButton, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
223 f = wx.Font(8, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False)
224 self._termLog = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_DONTWRAP)
225 self._termLog.SetFont(f)
226 self._termLog.SetEditable(0)
227 self._termLog.SetMinSize((1, 400))
228 self._termInput = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
229 self._termInput.SetFont(f)
230 sizer.Add(self._termLog, 0, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
231 sizer.Add(self._termInput, 0, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
233 self.Bind(wx.EVT_TEXT_ENTER, self.OnTermEnterLine, self._termInput)
237 self.filename = filename
243 self.thread = threading.Thread(target=self.OnRun)
244 self.thread.daemon = True
247 self.read_thread = threading.Thread(target=self.OnSerialRead)
248 self.read_thread.daemon = True
249 self.read_thread.start()
255 def _addTermLog(self, line):
256 if self._termLog is not None:
257 if len(self._termLog.GetValue()) > 10000:
258 self._termLog.SetValue(self._termLog.GetValue()[-10000:])
259 self._termLog.SetInsertionPointEnd()
260 if type(line) != unicode:
261 line = unicode(line, 'utf-8', 'replace')
262 self._termLog.AppendText(line.encode('utf-8', 'replace'))
264 def OnTermEnterLine(self, e):
265 lines = self._termInput.GetValue().split(';')
269 self._addTermLog('> %s\n' % (line))
270 if self._serial is not None:
271 self._serial.write(line + '\n')
276 new_mtime = os.stat(self.filename).st_mtime
277 if mtime != new_mtime:
279 if self._serial is not None:
285 self._serial = serial.Serial(self.port, 115200)
290 def OnSerialRead(self):
292 if self._serial is None:
296 line = self._serial.readline()
297 wx.CallAfter(self._addTermLog, line)
302 wx.CallAfter(self.okButton.Disable)
303 wx.CallAfter(self.updateLabel, _("Reading firmware..."))
304 hexFile = intelHex.readHex(self.filename)
305 wx.CallAfter(self.updateLabel, _("Connecting to machine..."))
306 programmer = stk500v2.Stk500v2()
307 programmer.progressCallback = self.OnProgress
308 if self.port == 'AUTO':
309 wx.CallAfter(self.updateLabel, _("Please connect the printer to\nyour computer with the USB cable."))
310 while not programmer.isConnected():
311 for self.port in machineCom.serialList(True):
313 programmer.connect(self.port)
315 except ispBase.IspError:
323 programmer.connect(self.port)
324 except ispBase.IspError:
327 if not programmer.isConnected():
328 wx.CallAfter(self.updateLabel, _("Failed to connect to programmer.\n"))
331 wx.CallAfter(self.updateLabel, _("Uploading firmware..."))
333 programmer.programChip(hexFile)
334 wx.CallAfter(self.updateLabel, _("Done!\nInstalled firmware: %s") % (os.path.basename(self.filename)))
335 except ispBase.IspError as e:
336 wx.CallAfter(self.updateLabel, _("Failed to write firmware.\n") + str(e))
339 wx.CallAfter(self.okButton.Enable)
341 def updateLabel(self, text):
342 self.progressLabel.SetLabel(text)
345 def OnProgress(self, value, max):
346 wx.CallAfter(self.progressGauge.SetRange, max)
347 wx.CallAfter(self.progressGauge.SetValue, value)
348 taskbar.setProgress(self.GetParent(), value, max)
352 taskbar.setBusy(self.GetParent(), False)
354 def OnClose(self, e):