import threading
import sys
import time
+import serial
from Cura.avr_isp import stk500v2
from Cura.avr_isp import ispBase
from Cura.util import resources
def getDefaultFirmware(machineIndex = None):
- if profile.getMachineSetting('machine_type', machineIndex) == 'ultimaker':
+ firmwareDict = {
+ 'ultimaker2go':"MarlinUltimaker2go.hex",
+ 'Witbox':"MarlinWitbox.hex",
+ 'lulzbot_mini': "Mini-Single-or-Flexystruder-LBHexagon-2015Q2.hex",
+ 'lulzbot_mini_flexystruder': "Mini-Single-or-Flexystruder-LBHexagon-2015Q2.hex",
+ 'lulzbot_TAZ_4_SingleV1': "Taz4-5-Single-or-Flexystruder-Budaschnozzle-2014Q3.hex",
+ 'lulzbot_TAZ_5_SingleV1': "Taz4-5-Single-or-Flexystruder-Budaschnozzle-2014Q3.hex",
+ 'lulzbot_TAZ_4_05nozzle': "Taz4-Single-Extruder-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_5_05nozzle': "Taz5-Single-Extruder-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_4_035nozzle': "Taz4-Single-Extruder-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_5_035nozzle': "Taz5-Single-Extruder-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_4_FlexystruderV1': "Taz4-5-Single-or-Flexystruder-Budaschnozzle-2014Q3.hex",
+ 'lulzbot_TAZ_5_FlexystruderV1': "Taz4-5-Single-or-Flexystruder-Budaschnozzle-2014Q3.hex",
+ 'lulzbot_TAZ_4_FlexystruderV2': "Taz4-5-Flexystruder-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_5_FlexystruderV2': "Taz4-5-Flexystruder-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_4_DualV1': "Taz4-5-Dual-or-FlexyDually-Budaschnozzle-2015Q1.hex",
+ 'lulzbot_TAZ_5_DualV1': "Taz4-5-Dual-or-FlexyDually-Budaschnozzle-2015Q1.hex",
+ 'lulzbot_TAZ_4_DualV2': "Taz4-5-Dual-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_5_DualV2': "Taz4-5-Dual-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_4_FlexyDuallyV1': "Taz4-5-Dual-or-FlexyDually-Budaschnozzle-2015Q1.hex",
+ 'lulzbot_TAZ_5_FlexyDuallyV1': "Taz4-5-Dual-or-FlexyDually-Budaschnozzle-2015Q1.hex",
+ 'lulzbot_TAZ_4_FlexyDuallyV2': "Taz4-5-FlexyDually-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_5_FlexyDuallyV2': "Taz4-5-FlexyDually-LBHexagon-2015Q3.hex",
+ 'lulzbot_TAZ_6_SingleTilapia': "Taz6-Single-Tilapia-2015-Q4.hex"
+ }
+ machine_type = profile.getMachineSetting('machine_type', machineIndex)
+ extruders = profile.getMachineSettingFloat('extruder_amount', machineIndex)
+ heated_bed = profile.getMachineSetting('has_heated_bed', machineIndex) == 'True'
+ baudrate = 250000
+ if sys.platform.startswith('linux'):
+ baudrate = 115200
+ if machine_type == 'ultimaker':
name = 'MarlinUltimaker'
- if profile.getMachineSettingFloat('extruder_amount', machineIndex) > 2:
+ if extruders > 2:
return None
- if profile.getMachineSetting('has_heated_bed', machineIndex) == 'True':
+ if heated_bed:
name += '-HBK'
- if sys.platform.startswith('linux'):
- name += '-115200'
- else:
- name += '-250000'
- if profile.getMachineSettingFloat('extruder_amount', machineIndex) > 1:
+ name += '-%d' % (baudrate)
+ if extruders > 1:
name += '-dual'
return resources.getPathForFirmware(name + '.hex')
- if profile.getMachineSetting('machine_type', machineIndex) == 'ultimaker_plus':
- name = 'MarlinUltimaker-UMOP'
- if profile.getMachineSettingFloat('extruder_amount', machineIndex) > 2:
+ if machine_type == 'ultimaker_plus':
+ name = 'MarlinUltimaker-UMOP-%d' % (baudrate)
+ if extruders > 2:
return None
- if sys.platform.startswith('linux'):
- name += '-115200'
- else:
- name += '-250000'
- if profile.getMachineSettingFloat('extruder_amount', machineIndex) > 1:
+ if extruders > 1:
name += '-dual'
return resources.getPathForFirmware(name + '.hex')
-
- if profile.getMachineSetting('machine_type', machineIndex) == 'ultimaker2':
+ if machine_type == 'ultimaker2':
+ if extruders > 2:
+ return None
+ if extruders > 1:
+ return resources.getPathForFirmware("MarlinUltimaker2-dual.hex")
return resources.getPathForFirmware("MarlinUltimaker2.hex")
- if profile.getMachineSetting('machine_type', machineIndex) == 'lulzbot_mini':
- return resources.getPathForFirmware("marlin_mini_2014Q4.hex")
- if profile.getMachineSetting('machine_type', machineIndex) == 'Witbox':
- return resources.getPathForFirmware("MarlinWitbox.hex")
+ if machine_type == 'ultimaker2extended':
+ if extruders > 2:
+ return None
+ if extruders > 1:
+ return resources.getPathForFirmware("MarlinUltimaker2extended-dual.hex")
+ return resources.getPathForFirmware("MarlinUltimaker2extended.hex")
+ if firmwareDict.has_key(machine_type):
+ return resources.getPathForFirmware(firmwareDict[machine_type])
return None
-class InstallFirmware(wx.Dialog):
+def InstallFirmware(parent = None, filename = None, port = None, machineIndex = None):
+ dlg = InstallFirmwareDialog(parent, filename, port, machineIndex)
+ result = dlg.Run()
+ dlg.Destroy()
+ return result
+
+class InstallFirmwareDialog(wx.Dialog):
def __init__(self, parent = None, filename = None, port = None, machineIndex = None):
- super(InstallFirmware, self).__init__(parent=parent, title=_("Firmware install for %s") % (profile.getMachineSetting('machine_name', machineIndex).title()), size=(250, 100))
+ super(InstallFirmwareDialog, self).__init__(parent=parent, title=_("Firmware install for %s") % (profile.getMachineName(machineIndex).title()), size=(250, 100))
if port is None:
port = profile.getMachineSetting('serial_port')
if filename is None:
filename = getDefaultFirmware(machineIndex)
- if filename is None:
- 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)
- self.Destroy()
- return
self._machine_type = profile.getMachineSetting('machine_type', machineIndex)
if self._machine_type == 'reprap':
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)
self.Layout()
self.Fit()
+ self.success = False
+ self.show_connect_dialog = False
+ def Run(self):
+ if self.filename is None:
+ 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)
+ return False
+ self.success = False
self.thread = threading.Thread(target=self.OnRun)
self.thread.daemon = True
self.thread.start()
self.ShowModal()
- self.Destroy()
- return
+ # Creating a MessageBox in a separate thread while main thread is locked inside a ShowModal
+ # will cause Python to crash with X errors. So we need to show the dialog here instead
+ if self.show_connect_dialog:
+ wx.MessageBox(_("Failed to find machine for firmware upgrade\nIs your machine connected to the PC?"),
+ _("Firmware update"), wx.OK | wx.ICON_ERROR)
+ return self.success
def OnRun(self):
wx.CallAfter(self.updateLabel, _("Reading firmware..."))
programmer = stk500v2.Stk500v2()
programmer.progressCallback = self.OnProgress
if self.port == 'AUTO':
- wx.CallAfter(self.updateLabel, _("Please connect the printer to\nyour computer with the USB cable."))
+ wx.CallAfter(self.updateLabel, _("Please connect the printer to your\ncomputer with a USB cable and power it on."))
while not programmer.isConnected():
for self.port in machineCom.serialList(True):
try:
programmer.connect(self.port)
break
except ispBase.IspError:
- pass
+ programmer.close()
time.sleep(1)
if not self:
#Window destroyed
try:
programmer.connect(self.port)
except ispBase.IspError:
- pass
+ programmer.close()
+ if not self:
+ #Window destroyed
+ return
if not programmer.isConnected():
- wx.MessageBox(_("Failed to find machine for firmware upgrade\nIs your machine connected to the PC?"),
- _("Firmware update"), wx.OK | wx.ICON_ERROR)
+ self.show_connect_dialog = True
wx.CallAfter(self.Close)
return
wx.CallAfter(self.updateLabel, _("Uploading firmware..."))
try:
programmer.programChip(hexFile)
+ self.success = True
wx.CallAfter(self.updateLabel, _("Done!\nInstalled firmware: %s") % (os.path.basename(self.filename)))
except ispBase.IspError as e:
wx.CallAfter(self.updateLabel, _("Failed to write firmware.\n") + str(e))
def updateLabel(self, text):
self.progressLabel.SetLabel(text)
- #self.Layout()
+ self.Layout()
def OnProgress(self, value, max):
- wx.CallAfter(self.progressGauge.SetRange, max)
- wx.CallAfter(self.progressGauge.SetValue, value)
- taskbar.setProgress(self.GetParent(), value, max)
+ if self:
+ wx.CallAfter(self.progressGauge.SetRange, max)
+ wx.CallAfter(self.progressGauge.SetValue, value)
+ taskbar.setProgress(self.GetParent(), value, max)
def OnOk(self, e):
self.Close()
class AutoUpdateFirmware(wx.Dialog):
def __init__(self, parent, filename = None, port = None, machineIndex = None):
- super(AutoUpdateFirmware, self).__init__(parent=parent, title=_("Auto Firmware install"), size=(250, 100))
+ super(AutoUpdateFirmware, self).__init__(parent=parent, title=_("Auto Firmware install"), size=(250, 500))
if port is None:
port = profile.getMachineSetting('serial_port')
+ self._serial = None
sizer = wx.BoxSizer(wx.VERTICAL)
self.okButton = wx.Button(self, -1, _("OK"))
self.okButton.Bind(wx.EVT_BUTTON, self.OnOk)
sizer.Add(self.okButton, 0, flag=wx.ALIGN_CENTER|wx.ALL, border=5)
+
+ f = wx.Font(8, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False)
+ self._termLog = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_DONTWRAP)
+ self._termLog.SetFont(f)
+ self._termLog.SetEditable(0)
+ self._termLog.SetMinSize((1, 400))
+ self._termInput = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
+ self._termInput.SetFont(f)
+ sizer.Add(self._termLog, 0, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
+ sizer.Add(self._termInput, 0, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
+
+ self.Bind(wx.EVT_TEXT_ENTER, self.OnTermEnterLine, self._termInput)
+
self.SetSizer(sizer)
self.filename = filename
self.thread.daemon = True
self.thread.start()
+ self.read_thread = threading.Thread(target=self.OnSerialRead)
+ self.read_thread.daemon = True
+ self.read_thread.start()
+
self.ShowModal()
self.Destroy()
return
+ def _addTermLog(self, line):
+ if self._termLog is not None:
+ if len(self._termLog.GetValue()) > 10000:
+ self._termLog.SetValue(self._termLog.GetValue()[-10000:])
+ self._termLog.SetInsertionPointEnd()
+ if type(line) != unicode:
+ line = unicode(line, 'utf-8', 'replace')
+ self._termLog.AppendText(line.encode('utf-8', 'replace'))
+
+ def OnTermEnterLine(self, e):
+ lines = self._termInput.GetValue().split(';')
+ for line in lines:
+ if line == '':
+ continue
+ self._addTermLog('> %s\n' % (line))
+ if self._serial is not None:
+ self._serial.write(line + '\n')
+
def OnRun(self):
mtime = 0
while bool(self):
new_mtime = os.stat(self.filename).st_mtime
if mtime != new_mtime:
mtime = new_mtime
+ if self._serial is not None:
+ self._serial.close()
+ self._serial = None
time.sleep(0.5)
self.OnInstall()
+ try:
+ self._serial = serial.Serial(self.port, 115200)
+ except:
+ pass
time.sleep(0.5)
+ def OnSerialRead(self):
+ while bool(self):
+ if self._serial is None:
+ time.sleep(0.5)
+ else:
+ try:
+ line = self._serial.readline()
+ wx.CallAfter(self._addTermLog, line)
+ except:
+ pass
+
def OnInstall(self):
wx.CallAfter(self.okButton.Disable)
wx.CallAfter(self.updateLabel, _("Reading firmware..."))
programmer = stk500v2.Stk500v2()
programmer.progressCallback = self.OnProgress
if self.port == 'AUTO':
- wx.CallAfter(self.updateLabel, _("Please connect the printer to\nyour computer with the USB cable."))
+ wx.CallAfter(self.updateLabel, _("Please connect the printer to your\ncomputer with a USB cable and power it on."))
while not programmer.isConnected():
for self.port in machineCom.serialList(True):
try:
def updateLabel(self, text):
self.progressLabel.SetLabel(text)
- #self.Layout()
+ self.Layout()
def OnProgress(self, value, max):
wx.CallAfter(self.progressGauge.SetRange, max)