Teacup_Firmware/configtool.py

487 lines
14 KiB
Python
Executable File

#!/usr/bin/env python
import wx
import os.path
import inspect
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(
inspect.currentframe()))[0]))
from configtool.settings import Settings, SettingsDlg
from configtool.printerpanel import PrinterPanel
from configtool.boardpanel import BoardPanel
from configtool.build import Build, Upload
from configtool.data import reInclude
ID_LOAD_PRINTER = 1000
ID_SAVE_PRINTER = 1001
ID_SAVE_PRINTER_AS = 1002
ID_LOAD_BOARD = 1010
ID_SAVE_BOARD = 1011
ID_SAVE_BOARD_AS = 1012
ID_LOAD_CONFIG = 1020
ID_SAVE_CONFIG = 1021
ID_BUILD = 1030
ID_UPLOAD = 1031
ID_SETTINGS = 1040
class ConfigFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Teacup Configtool", size = (880, 550))
self.Bind(wx.EVT_CLOSE, self.onClose)
panel = wx.Panel(self, -1)
self.settings = Settings(self, cmd_folder)
self.settings.font = wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_BOLD)
self.settings.folder = cmd_folder
self.heaters = []
self.savePrtEna = False
self.saveBrdEna = False
self.protPrtFile = False
self.protBrdFile = False
sz = wx.BoxSizer(wx.HORIZONTAL)
self.nb = wx.Notebook(panel, wx.ID_ANY, size = (880, 550),
style = wx.BK_DEFAULT)
self.nb.SetFont(self.settings.font)
self.printerFileName = None
self.printerTabDecor = ""
self.printerBaseText = "Printer"
self.pgPrinter = PrinterPanel(self, self.nb, self.settings)
self.nb.AddPage(self.pgPrinter, self.printerBaseText)
self.boardFileName = None
self.boardTabDecor = ""
self.boardBaseText = "Board"
self.pgBoard = BoardPanel(self, self.nb, self.settings)
self.nb.AddPage(self.pgBoard, self.boardBaseText)
panel.Fit()
sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
self.SetSizer(sz)
self.makeMenu()
def onClose(self, evt):
if not self.pgPrinter.confirmLoseChanges("exit"):
return
if not self.pgBoard.confirmLoseChanges("exit"):
return
self.Destroy()
def setPrinterTabFile(self, fn):
self.printerFileName = fn
self.updatePrinterTab()
def setPrinterTabDecor(self, prefix):
self.printerTabDecor = prefix
self.updatePrinterTab()
def updatePrinterTab(self):
txt = self.printerTabDecor + self.printerBaseText
if self.printerFileName:
txt += " <%s>" % self.printerFileName
self.nb.SetPageText(0, txt)
def setBoardTabFile(self, fn):
self.boardFileName = fn
self.updateBoardTab()
def setBoardTabDecor(self, prefix):
self.boardTabDecor = prefix
self.updateBoardTab()
def updateBoardTab(self):
txt = self.boardTabDecor + self.boardBaseText
if self.boardFileName:
txt += " <%s>" % self.boardFileName
self.nb.SetPageText(1, txt)
def setHeaters(self, ht):
self.heaters = ht
self.pgPrinter.setHeaters(ht)
def makeMenu(self):
file_menu = wx.Menu()
file_menu.Append(ID_LOAD_CONFIG, "Load config.h",
"Load config.h and its named printer and board files.")
self.Bind(wx.EVT_MENU, self.onLoadConfig, id = ID_LOAD_CONFIG)
file_menu.Enable(ID_LOAD_CONFIG, False)
file_menu.Append(ID_SAVE_CONFIG, "Save config.h", "Save config.h file.")
self.Bind(wx.EVT_MENU, self.onSaveConfig, id = ID_SAVE_CONFIG)
file_menu.Enable(ID_SAVE_CONFIG, False)
file_menu.AppendSeparator()
file_menu.Append(ID_LOAD_PRINTER, "Load printer",
"Load a printer configuration file.")
self.Bind(wx.EVT_MENU, self.pgPrinter.onLoadConfig, id = ID_LOAD_PRINTER)
file_menu.Append(ID_SAVE_PRINTER, "Save printer",
"Save printer configuration.")
self.Bind(wx.EVT_MENU, self.onSavePrinterConfig, id = ID_SAVE_PRINTER)
file_menu.Enable(ID_SAVE_PRINTER, False)
file_menu.Append(ID_SAVE_PRINTER_AS, "Save printer as...",
"Save printer configuration to a new file.")
self.Bind(wx.EVT_MENU, self.onSavePrinterConfigAs, id = ID_SAVE_PRINTER_AS)
file_menu.Enable(ID_SAVE_PRINTER_AS, False)
file_menu.AppendSeparator()
file_menu.Append(ID_LOAD_BOARD, "Load board",
"Load a board configuration file.")
self.Bind(wx.EVT_MENU, self.pgBoard.onLoadConfig, id = ID_LOAD_BOARD)
file_menu.Append(ID_SAVE_BOARD, "Save board", "Save board configuration.")
self.Bind(wx.EVT_MENU, self.onSaveBoardConfig, id = ID_SAVE_BOARD)
file_menu.Enable(ID_SAVE_BOARD, False)
file_menu.Append(ID_SAVE_BOARD_AS, "Save board as...",
"Save board configuration to a new file.")
self.Bind(wx.EVT_MENU, self.onSaveBoardConfigAs, id = ID_SAVE_BOARD_AS)
file_menu.Enable(ID_SAVE_BOARD_AS, False)
file_menu.AppendSeparator()
file_menu.Append(wx.ID_EXIT, "E&xit", "Exit the application.")
self.Bind(wx.EVT_MENU, self.onClose, id = wx.ID_EXIT)
self.fileMenu = file_menu
menu_bar = wx.MenuBar()
menu_bar.Append(file_menu, "&File")
edit_menu = wx.Menu()
edit_menu.Append(ID_SETTINGS, "Settings", "Change settings.")
self.Bind(wx.EVT_MENU, self.onEditSettings, id = ID_SETTINGS)
self.editMenu = edit_menu
menu_bar.Append(edit_menu, "&Edit")
build_menu = wx.Menu()
build_menu.Append(ID_BUILD, "Build", "Build the executable.")
self.Bind(wx.EVT_MENU, self.onBuild, id = ID_BUILD)
build_menu.Append(ID_UPLOAD, "Upload", "Upload the executable.")
self.Bind(wx.EVT_MENU, self.onUpload, id = ID_UPLOAD)
self.buildMenu = build_menu
menu_bar.Append(build_menu, "&Build")
self.SetMenuBar(menu_bar)
loadFlag = self.checkEnableLoadConfig()
self.checkEnableUpload()
if loadFlag:
self.loadConfigFile("config.h")
def onSaveBoardConfig(self, evt):
rc = self.pgBoard.onSaveConfig(evt)
if rc:
self.checkEnableLoadConfig()
return rc
def onSaveBoardConfigAs(self, evt):
rc = self.pgBoard.onSaveConfigAs(evt)
if rc:
self.checkEnableLoadConfig()
return rc
def onSavePrinterConfig(self, evt):
rc = self.pgPrinter.onSaveConfig(evt)
if rc:
self.checkEnableLoadConfig()
return rc
def onSavePrinterConfigAs(self, evt):
rc = self.pgPrinter.onSaveConfigAs(evt)
if rc:
self.checkEnableLoadConfig()
return rc
def checkEnableLoadConfig(self):
fn = os.path.join(cmd_folder, "config.h")
if os.path.isfile(fn):
self.fileMenu.Enable(ID_LOAD_CONFIG, True)
self.buildMenu.Enable(ID_BUILD, True)
return True
else:
self.fileMenu.Enable(ID_LOAD_CONFIG, False)
self.buildMenu.Enable(ID_BUILD, False)
return False
def checkEnableUpload(self):
fn = os.path.join(cmd_folder, "teacup.hex")
if os.path.isfile(fn):
self.buildMenu.Enable(ID_UPLOAD, True)
else:
self.buildMenu.Enable(ID_UPLOAD, False)
def enableSavePrinter(self, saveFlag, saveAsFlag):
self.fileMenu.Enable(ID_SAVE_PRINTER, saveFlag)
self.fileMenu.Enable(ID_SAVE_PRINTER_AS, saveAsFlag)
self.savePrtEna = saveAsFlag
self.protPrtFile = not saveFlag
if self.savePrtEna and self.saveBrdEna:
self.enableSaveConfig(True)
else:
self.enableSaveConfig(False)
def enableSaveBoard(self, saveFlag, saveAsFlag):
self.fileMenu.Enable(ID_SAVE_BOARD, saveFlag)
self.fileMenu.Enable(ID_SAVE_BOARD_AS, saveAsFlag)
self.saveBrdEna = saveAsFlag
self.protBrdFile = not saveFlag
if self.savePrtEna and self.saveBrdEna:
self.enableSaveConfig(True)
else:
self.enableSaveConfig(False)
def enableSaveConfig(self, flag):
self.fileMenu.Enable(ID_SAVE_CONFIG, flag)
def onLoadConfig(self, evt):
self.loadConfigFile("config.h")
def loadConfigFile(self, fn):
if not self.pgPrinter.confirmLoseChanges("load config"):
return False
if not self.pgBoard.confirmLoseChanges("load config"):
return False
pfile, bfile = self.getConfigFileNames(fn)
if not pfile:
self.message("Config file did not contain a printer file "
"include statement.", "Config error")
return False
else:
if not self.pgPrinter.loadConfigFile(pfile):
self.message("There was a problem loading the printer config file:\n%s"
% pfile, "Config error")
return False
if not bfile:
self.message("Config file did not contain a board file "
"include statement.", "Config error")
return False
else:
if not self.pgBoard.loadConfigFile(bfile):
self.message("There was a problem loading the board config file:\n%s"
% bfile, "Config error")
return False
return True
def getConfigFileNames(self, fn):
pfile = None
bfile = None
path = os.path.join(cmd_folder, fn)
try:
cfgBuffer = list(open(path))
except:
self.message("Unable to process config file %s." % fn, "File error")
return
for ln in cfgBuffer:
if not ln.lstrip().startswith("#include"):
continue
m = reInclude.search(ln)
if m:
t = m.groups()
if len(t) == 1:
if "printer." in t[0]:
if pfile:
self.message("Multiple printer file include statements.\n"
"Ignoring %s." % ln, "Config error",
wx.OK + wx.ICON_WARNING)
else:
pfile = os.path.join(cmd_folder, t[0])
elif "board." in t[0]:
if bfile:
self.message("Multiple board file include statements.\n"
"Ignoring %s." % ln, "Config error",
wx.OK + wx.ICON_WARNING)
else:
bfile = os.path.join(cmd_folder, t[0])
else:
self.message("Unable to parse include statement:\n%s" % ln,
"Config error")
return pfile, bfile
def onSaveConfig(self, evt):
fn = os.path.join(cmd_folder, "config.h")
try:
fp = open(fn, 'w')
except:
self.message("Unable to open config.h for output.", "File error")
return False
bfn = self.pgBoard.getFileName()
if self.pgBoard.isModified() and self.pgBoard.isValid():
if not self.pgBoard.saveConfigFile(bfn):
return False
pfn = self.pgPrinter.getFileName()
if self.pgPrinter.isModified() and self.pgPrinter.isValid():
if not self.pgPrinter.saveConfigFile(pfn):
return False
prefix = cmd_folder + os.path.sep
lpfx = len(prefix)
if bfn.startswith(prefix):
rbfn = bfn[lpfx:]
else:
rbfn = bfn
if pfn.startswith(prefix):
rpfn = pfn[lpfx:]
else:
rpfn = pfn
fp.write("\n")
fp.write("// Configuration for controller board.\n")
fp.write("#include \"%s\"\n" % rbfn)
fp.write("\n")
fp.write("// Configuration for printer board.\n")
fp.write("#include \"%s\"\n" % rpfn)
fp.close()
self.checkEnableLoadConfig()
return True
def onBuild(self, evt):
self.onBuildorUpload(True)
def onUpload(self, evt):
self.onBuildorUpload(False)
def onBuildorUpload(self, buildFlag):
if not (self.pgPrinter.hasData() or self.pgBoard.hasData()):
dlg = wx.MessageDialog(self, "Data needs to be loaded. "
"Click Yes to load config.h.",
"Data missing",
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
rc = dlg.ShowModal()
dlg.Destroy()
if rc != wx.ID_YES:
return
self.loadConfigFile("config.h")
else:
if self.pgPrinter.isModified():
dlg = wx.MessageDialog(self, "Printer data needs to be saved. Click "
"Yes to save printer configuration.",
"Changes pending",
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
rc = dlg.ShowModal()
dlg.Destroy()
if rc != wx.ID_YES:
return
if self.protPrtFile:
rc = self.onSavePrinterConfigAs(None)
else:
rc = self.onSavePrinterConfig(None)
if not rc:
return
if self.pgBoard.isModified():
dlg = wx.MessageDialog(self, "Board data needs to be saved. Click "
"Yes to save board configuration.",
"Changes pending",
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
rc = dlg.ShowModal()
dlg.Destroy()
if rc != wx.ID_YES:
return
if self.protBrdFile:
rc = self.onSaveBoardConfigAs(None)
else:
rc = self.onSaveBoardConfig(None)
if not rc:
return
if not self.verifyConfigLoaded():
dlg = wx.MessageDialog(self, "Loaded configuration does not match the "
"config.h file. Click Yes to save config.h.",
"Configuration changed",
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
rc = dlg.ShowModal()
dlg.Destroy()
if rc != wx.ID_YES:
return
if not self.onSaveConfig(None):
return
f_cpu, cpu = self.pgBoard.getCPUInfo()
if not cpu:
dlg = wx.MessageDialog(self, "Unable to determine CPU type.",
"CPU type error", wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
return
if not f_cpu:
dlg = wx.MessageDialog(self, "Unable to determine CPU clock rate.",
"CPU clock rate error", wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
return
if buildFlag:
dlg = Build(self, self.settings, f_cpu, cpu)
dlg.ShowModal()
dlg.Destroy()
self.checkEnableUpload()
else:
dlg = Upload(self, self.settings, f_cpu, cpu)
dlg.ShowModal()
dlg.Destroy()
def verifyConfigLoaded(self):
pfile, bfile = self.getConfigFileNames("config.h")
lpfile = self.pgPrinter.getFileName()
lbfile = self.pgBoard.getFileName()
return ((pfile == lpfile) and (bfile == lbfile))
def onEditSettings(self, evt):
dlg = SettingsDlg(self, self.settings)
rc = dlg.ShowModal()
dlg.Destroy()
def message(self, text, title, style = wx.OK + wx.ICON_ERROR):
dlg = wx.MessageDialog(self, text, title, style)
dlg.ShowModal()
dlg.Destroy()
if __name__ == '__main__':
app = wx.App(False)
frame = ConfigFrame()
frame.Show(True)
app.MainLoop()