From 9985c3936d001719afea5c085ffad3413db80800 Mon Sep 17 00:00:00 2001 From: jbernardis Date: Sun, 25 Jan 2015 20:17:32 -0500 Subject: [PATCH] Configtool: many changes. 1) If variables are missing from .h files, they are added. 2) Settings file now modifiable from within the program. 3) A few cosmetic fixes. --- config.py | 36 +++++++-- configtool.default.ini | 3 +- configtool/boardpanel.py | 49 +++++++++++- configtool/build.py | 70 +++++++++++++++- configtool/cpupage.py | 5 +- configtool/mechanicalpage.py | 6 ++ configtool/page.py | 5 +- configtool/printerpanel.py | 48 ++++++++++- configtool/settings.py | 150 +++++++++++++++++++++++++++++++++++ 9 files changed, 353 insertions(+), 19 deletions(-) diff --git a/config.py b/config.py index 305b011..7adaffb 100755 --- a/config.py +++ b/config.py @@ -7,7 +7,7 @@ import inspect cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe()))[0])) -from configtool.settings import Settings +from configtool.settings import Settings, SettingsDlg from configtool.printerpanel import PrinterPanel from configtool.boardpanel import BoardPanel from configtool.build import Build, Upload @@ -24,6 +24,7 @@ ID_LOAD_DEFAULT = 1021 ID_SAVE_CONFIG = 1022 ID_BUILD = 1030 ID_UPLOAD = 1031 +ID_SETTINGS = 1040 class ConfigFrame(wx.Frame): @@ -180,6 +181,15 @@ class ConfigFrame(wx.Frame): menu_bar.Append(build_menu, "&Build") + 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") + self.SetMenuBar(menu_bar) self.checkEnableLoadConfig() self.checkEnableUpload() @@ -260,16 +270,18 @@ class ConfigFrame(wx.Frame): if not pfile: self.message("Config file did not contain a printer file " "include statement.", "Config error") - return + else: + if not self.pgPrinter.loadConfigFile(pfile): + self.message("There was a problem loading the printer config file:\n%s" + % pfile, "Config error") if not bfile: self.message("Config file did not contain a board file " "include statement.", "Config error") - return - - self.pgPrinter.loadConfigFile(pfile) - - self.pgBoard.loadConfigFile(bfile) + else: + if not self.pgBoard.loadConfigFile(bfile): + self.message("There was a problem loading the board config file:\n%s" + % bfile, "Config error") def getConfigFileNames(self, fn): pfile = None @@ -454,6 +466,16 @@ class ConfigFrame(wx.Frame): return ((pfile == lpfile) and (bfile == lbfile)) + def onEditSettings(self, evt): + dlg = SettingsDlg(self, self.settings) + rc = dlg.ShowModal() + dlg.Destroy() + if rc != wx.ID_OK: + return + + m = "configtool.default.ini successfully saved.\n" + self.message(m, "Save settings success", wx.OK + wx.ICON_INFORMATION) + def message(self, text, title, style = wx.OK + wx.ICON_ERROR): dlg = wx.MessageDialog(self, text, title, style) dlg.ShowModal() diff --git a/configtool.default.ini b/configtool.default.ini index 5409825..3ca67f4 100644 --- a/configtool.default.ini +++ b/configtool.default.ini @@ -4,7 +4,8 @@ # Where to find the arduino tools (avr-gcc, avrdude, etc). This is only used # for windows. For linux it is assumed that the tools are available through # the normal PATH. -arduinodir = C:/Program Files (x86)/Arduino/hardware/tools/avr/bin +#arduinodir = C:/Program Files (x86)/Arduino/hardware/tools/avr/bin +arduinodir = # Flags passed into the avr-gcc compiler. These flags can have 3 different # variabled embedded within them: diff --git a/configtool/boardpanel.py b/configtool/boardpanel.py index a20529e..139c0af 100644 --- a/configtool/boardpanel.py +++ b/configtool/boardpanel.py @@ -410,6 +410,8 @@ class BoardPanel(wx.Panel): if self.saveConfigFile(path): dlg = wx.MessageDialog(self, "File %s successfully written." % path, "Save successful", wx.OK + wx.ICON_INFORMATION) + self.parent.setBoardTabFile(os.path.basename(path)) + else: dlg = wx.MessageDialog(self, "Unable to write to file %s." % path, "File error", wx.OK + wx.ICON_ERROR) @@ -431,6 +433,7 @@ class BoardPanel(wx.Panel): self.configFile = path values = {} + labelFound = [] for pg in self.pages: v1 = pg.getValues() @@ -482,8 +485,10 @@ class BoardPanel(wx.Panel): if len(t) == 2: if t[0] in values.keys() and values[t[0]] != "": fp.write(defineValueFormat % (t[0], values[t[0]])) + labelFound.append(t[0]) elif t[0] in values.keys(): fp.write("//" + ln) + labelFound.append(t[0]) else: fp.write(ln) continue @@ -494,8 +499,10 @@ class BoardPanel(wx.Panel): if len(t) == 1: if t[0] in values.keys() and values[t[0]]: fp.write(defineBoolFormat % t[0]) + labelFound.append(t[0]) elif t[0] in values.keys(): fp.write("//" + ln) + labelFound.append(t[0]) else: fp.write(ln) continue @@ -506,6 +513,10 @@ class BoardPanel(wx.Panel): if len(t) == 2: if t[0] in values.keys() and values[t[0]] != "": fp.write(defineValueFormat % (t[0], values[t[0]])) + labelFound.append(t[0]) + elif t[0] in values.keys(): + fp.write(ln) + labelFound.append(t[0]) else: fp.write(ln) continue @@ -516,14 +527,48 @@ class BoardPanel(wx.Panel): if len(t) == 1: if t[0] in values.keys() and values[t[0]]: fp.write(defineBoolFormat % t[0]) + labelFound.append(t[0]) + elif t[0] in values.keys(): + fp.write(ln) + labelFound.append(t[0]) else: fp.write(ln) continue fp.write(ln) + for k in labelFound: + del values[k] + + newLabels = "" + for k in values.keys(): + if newLabels == "": + newLabels = k + else: + newLabels += ", " + k + self.addNewDefine(fp, k, values[k]) + + if newLabels != "": + dlg = wx.MessageDialog(self, "New Defines added to board config:\n" + + newLabels, "New Defines", + wx.OK + wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + fp.close() - self.parent.setBoardTabFile(os.path.basename(path)) - return True + + def addNewDefine(self, fp, key, val): + fp.write("\n") + fp.write("/** \\def %s\n" % key) + fp.write(" Add help text here.\n") + fp.write("*/\n") + if val == True: + fp.write(defineBoolFormat % key) + elif val == False: + fp.write("//#define %s\n" % key) + elif val == "": + fp.write("//#define %s\n" % key) + else: + fp.write(defineValueFormat % (key, val)) diff --git a/configtool/build.py b/configtool/build.py index 94750be..3033e95 100644 --- a/configtool/build.py +++ b/configtool/build.py @@ -1,8 +1,7 @@ -import wx import wx.lib.newevent import thread, shlex, subprocess -import os +import os, re from os.path import isfile, join from sys import platform @@ -115,6 +114,9 @@ class Build(wx.Dialog): tc = wx.TextCtrl(self, wx.ID_ANY, size = (900, 300), style = wx.TE_READONLY + wx.TE_MULTILINE) sz.Add(tc, 1, wx.EXPAND) + f = wx.Font(8, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, + wx.FONTWEIGHT_BOLD) + tc.SetFont(f) self.log = tc sz.AddSpacer((10, 10)) @@ -153,6 +155,21 @@ class Build(wx.Dialog): self.active = True t.Start() + def report(self): + self.script = [] + self.reportLines = [] + if platform == "win32": + cmdpath = "\"" + join(self.settings.arduinodir, "avr-objdump") + "\"" + else: + cmdpath = "avr-objdump" + elfpath = "\"" + join(self.root, "build", "teacup.elf") + "\"" + cmd = cmdpath + " -h " + elfpath + self.script.append(cmd) + self.Bind(EVT_SCRIPT_UPDATE, self.reportUpdate) + t = ScriptThread(self, self.script) + self.active = True + t.Start() + def generateCompileScript(self): self.script = [] if platform == "win32": @@ -189,6 +206,7 @@ class Build(wx.Dialog): if isfile(join(self.root, "build", f)) and f.endswith(".o")] opath = " ".join(ofiles) elfpath = "\"" + join(self.root, "build", "teacup.elf") + "\"" + hexpath = "\"" + join(self.root, "teacup.hex") + "\"" opts = self.settings.cflags opts = opts.replace("%ALNAME%", "teacup.elf") opts = opts.replace("%F_CPU%", self.f_cpu) @@ -202,7 +220,7 @@ class Build(wx.Dialog): else: cmdpath = "avr-objcopy" cmd = cmdpath + " " + self.settings.objcopyflags + " " + elfpath + \ - " teacup.hex" + " " + hexpath self.script.append(cmd) def compileUpdate(self, evt): @@ -229,7 +247,50 @@ class Build(wx.Dialog): self.active = False if evt.state == SCRIPT_FINISHED: self.log.AppendText("Link completed normally.\n") + self.report() + + def reportUpdate(self, evt): + if evt.state == SCRIPT_RUNNING: + if evt.msg is not None: + self.reportLines.append(evt.msg) + if evt.state == SCRIPT_CANCELLED: + self.log.AppendText(evt.msg + "\n") + self.log.AppendText("Report terminated abnormally.\n") self.active = False + if evt.state == SCRIPT_FINISHED: + self.formatReport() + self.log.AppendText("\nBuild completed normally.\n") + self.active = False + + def formatReportLine(self, m, name, v168, v328, v644, v1280): + t = m.groups() + v = int(t[0], 16) + self.log.AppendText(("%12s : %6d bytes %6.2f%% %6.2f%%" + " %6.2f%% %6.2f%%\n") % + (name, v, v / float(v168 * 1024) * 100.0, + v / float(v328 * 1024) * 100.0, + v / float(v644 * 1024) * 100.0, + v / float(v1280 * 1024) * 100.0)) + + def formatReport(self): + reText = re.compile("\.text\s+([0-9a-f]+)") + reBss = re.compile("\.bss\s+([0-9a-f]+)") + reEEProm = re.compile("\.eeprom\s+([0-9a-f]+)") + + self.log.AppendText("\n ATmega... '168 '328(P)" + " '644(P) '1280\n") + for l in self.reportLines: + m = reText.search(l) + if m: + self.formatReportLine(m, "FLASH", 14, 30, 62, 126) + else: + m = reBss.search(l) + if m: + self.formatReportLine(m, "RAM", 1, 2, 4, 8) + else: + m = reEEProm.search(l) + if m: + self.formatReportLine(m, "EEPROM", 1, 2, 2, 4) def onExit(self, evt): if self.active: @@ -259,6 +320,9 @@ class Upload(wx.Dialog): tc = wx.TextCtrl(self, wx.ID_ANY, size = (900, 300), style = wx.TE_READONLY + wx.TE_MULTILINE) sz.Add(tc, 1, wx.EXPAND) + f = wx.Font(8, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, + wx.FONTWEIGHT_BOLD) + tc.SetFont(f) self.log = tc sz.AddSpacer((10, 10)) diff --git a/configtool/cpupage.py b/configtool/cpupage.py index 947b18e..98e1c6a 100644 --- a/configtool/cpupage.py +++ b/configtool/cpupage.py @@ -18,12 +18,13 @@ class CpuPage(wx.Panel, Page): sz.AddSpacer((20, 40), pos = (0, 0)) k = 'F_CPU' - ch = self.addChoice(k, self.clocks, 0, 100, self.onChoice) + ch = self.addChoice(k, self.clocks, 0, 100, self.onChoice, size = (140, -1)) sz.Add(ch, pos = (1, 1)) sz.AddSpacer((100, 10), pos = (1, 2)) k = 'CPU' - ch = self.addChoice(k, self.processors, 0, 100, self.onChoice) + ch = self.addChoice(k, self.processors, 0, 100, self.onChoice, + size = (140, -1)) sz.Add(ch, pos = (1, 3)) self.SetSizer(sz) diff --git a/configtool/mechanicalpage.py b/configtool/mechanicalpage.py index 3a4e118..2cb64a0 100644 --- a/configtool/mechanicalpage.py +++ b/configtool/mechanicalpage.py @@ -216,4 +216,10 @@ class MechanicalPage(wx.Panel, Page): result['KINEMATICS'] = tag break + for tag in self.kinematicsKeys: + try: + del result[tag] + except: + pass + return result diff --git a/configtool/page.py b/configtool/page.py index 1762f79..443bd37 100644 --- a/configtool/page.py +++ b/configtool/page.py @@ -62,14 +62,15 @@ class Page: return rb - def addChoice(self, name, choices, selection, labelWidth, validator): + def addChoice(self, name, choices, selection, labelWidth, validator, + size = (-1, -1)): lsz = wx.BoxSizer(wx.HORIZONTAL) st = wx.StaticText(self, wx.ID_ANY, self.labels[name], size = (labelWidth, -1), style = wx.ALIGN_RIGHT) st.SetFont(self.font) lsz.Add(st) - ch = wx.Choice(self, wx.ID_ANY, choices = choices, name = name) + ch = wx.Choice(self, wx.ID_ANY, choices = choices, size = size, name = name) ch.SetFont(self.font) ch.Bind(wx.EVT_CHOICE, validator) ch.SetSelection(selection) diff --git a/configtool/printerpanel.py b/configtool/printerpanel.py index 79179f6..1919732 100644 --- a/configtool/printerpanel.py +++ b/configtool/printerpanel.py @@ -6,8 +6,7 @@ import re from configtool.data import (defineValueFormat, defineBoolFormat, reCommDefBL, reCommDefBoolBL, reHelpTextStart, reHelpTextEnd, reDefine, reDefineBL, reDefQS, reDefQSm, - reDefQSm2, reDefBool, reDefBoolBL, reFloatAttr, - TYPE_FLOAT, TYPE_GENERAL) + reDefQSm2, reDefBool, reDefBoolBL) from configtool.mechanicalpage import MechanicalPage from configtool.accelerationpage import AccelerationPage from configtool.miscellaneouspage import MiscellaneousPage @@ -313,6 +312,7 @@ class PrinterPanel(wx.Panel): self.configFile = path values = {} + labelFound = [] for pg in self.pages: v1 = pg.getValues() @@ -326,8 +326,10 @@ class PrinterPanel(wx.Panel): if len(t) == 2: if t[0] in values.keys() and values[t[0]] != "": fp.write(defineValueFormat % (t[0], values[t[0]])) + labelFound.append(t[0]) elif t[0] in values.keys(): fp.write("//" + ln) + labelFound.append(t[0]) else: fp.write(ln) continue @@ -338,8 +340,10 @@ class PrinterPanel(wx.Panel): if len(t) == 1: if t[0] in values.keys() and values[t[0]]: fp.write(defineBoolFormat % t[0]) + labelFound.append(t[0]) elif t[0] in values.keys(): fp.write("//" + ln) + labelFound.append(t[0]) else: fp.write(ln) continue @@ -350,6 +354,10 @@ class PrinterPanel(wx.Panel): if len(t) == 2: if t[0] in values.keys() and values[t[0]] != "": fp.write(defineValueFormat % (t[0], values[t[0]])) + labelFound.append(t[0]) + elif t[0] in values.keys(): + fp.write(ln) + labelFound.append(t[0]) else: fp.write(ln) continue @@ -360,12 +368,48 @@ class PrinterPanel(wx.Panel): if len(t) == 1: if t[0] in values.keys() and values[t[0]]: fp.write(defineBoolFormat % t[0]) + labelFound.append(t[0]) + elif t[0] in values.keys(): + fp.write(ln) + labelFound.append(t[0]) else: fp.write(ln) continue fp.write(ln) + for k in labelFound: + del values[k] + + newLabels = "" + for k in values.keys(): + if newLabels == "": + newLabels = k + else: + newLabels += ", " + k + self.addNewDefine(fp, k, values[k]) + + if newLabels != "": + dlg = wx.MessageDialog(self, "New defines added to printer config:\n" + + newLabels, "New defines", + wx.OK + wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + fp.close() return True + + def addNewDefine(self, fp, key, val): + fp.write("\n") + fp.write("/** \\def %s\n" % key) + fp.write(" Add help text here.\n") + fp.write("*/\n") + if val == True: + fp.write(defineBoolFormat % key) + elif val == False: + fp.write("//#define %s\n" % key) + elif val == "": + fp.write("//#define %s\n" % key) + else: + fp.write(defineValueFormat % (key, val)) diff --git a/configtool/settings.py b/configtool/settings.py index 252112c..556e65b 100644 --- a/configtool/settings.py +++ b/configtool/settings.py @@ -1,6 +1,8 @@ import ConfigParser import os +import wx +from configtool.data import BSIZESMALL INIFILE = "configtool.default.ini" @@ -45,3 +47,151 @@ class Settings: print "Unknown %s option: %s - ignoring." % (self.section, opt) else: print "Missing %s section - assuming defaults." % self.section + + def saveSettings(self): + self.section = "configtool" + try: + self.cfg.add_section(self.section) + except ConfigParser.DuplicateSectionError: + pass + + self.cfg.set(self.section, "arduinodir", str(self.arduinodir)) + self.cfg.set(self.section, "cflags", str(self.cflags)) + self.cfg.set(self.section, "ldflags", str(self.ldflags)) + self.cfg.set(self.section, "objcopyflags", str(self.objcopyflags)) + self.cfg.set(self.section, "programmer", str(self.programmer)) + self.cfg.set(self.section, "port", str(self.port)) + + try: + cfp = open(self.inifile, 'wb') + except: + print "Unable to open settings file %s for writing." % self.inifile + return + self.cfg.write(cfp) + cfp.close() + + +ARDUINODIR = 0 +CFLAGS = 1 +LDFLAGS = 2 +OBJCOPYFLAGS= 3 +PROGRAMMER = 4 +PORT = 5 + +class SettingsDlg(wx.Dialog): + def __init__(self, parent, settings): + wx.Dialog.__init__(self, parent, wx.ID_ANY, "Modify settings", + size = (500, 300)) + self.SetFont(settings.font) + self.settings = settings + + self.modified = False + + self.Bind(wx.EVT_CLOSE, self.onExit) + + self.fields = [["Arduino Directory", settings.arduinodir, None], + ["C Compiler Flags", settings.cflags, None], + ["LD Flags", settings.ldflags, None], + ["Object Copy Flags", settings.objcopyflags, None], + ["AVR Programmer", settings.programmer, None], + ["Port", settings.port, None]] + + hsz = wx.BoxSizer(wx.HORIZONTAL) + hsz.AddSpacer((10, 10)) + + sz = wx.BoxSizer(wx.VERTICAL) + sz.AddSpacer((10, 10)) + + labelWidth = 140 + for f in self.fields: + lsz = wx.BoxSizer(wx.HORIZONTAL) + t = wx.StaticText(self, wx.ID_ANY, f[0], size = (labelWidth, -1), + style = wx.ALIGN_RIGHT) + t.SetFont(settings.font) + lsz.Add(t) + + lsz.AddSpacer((8, 8)) + + te = wx.TextCtrl(self, wx.ID_ANY, f[1], size = (600, -1)) + te.Bind(wx.EVT_TEXT, self.onTextCtrl) + lsz.Add(te) + f[2] = te + + sz.Add(lsz) + sz.AddSpacer((10, 10)) + + sz.AddSpacer((20, 20)) + + bsz = wx.BoxSizer(wx.HORIZONTAL) + b = wx.Button(self, wx.ID_ANY, "Save", size = BSIZESMALL) + b.SetFont(settings.font) + self.Bind(wx.EVT_BUTTON, self.onSave, b) + bsz.Add(b) + self.bSave = b + bsz.AddSpacer((5, 5)) + + b = wx.Button(self, wx.ID_ANY, "Exit", size = BSIZESMALL) + b.SetFont(settings.font) + self.Bind(wx.EVT_BUTTON, self.onExit, b) + bsz.Add(b) + self.bExit = b + + sz.Add(bsz, 1, wx.ALIGN_CENTER_HORIZONTAL) + sz.AddSpacer((10, 10)) + + hsz.Add(sz) + hsz.AddSpacer((10, 10)) + + self.SetSizer(hsz) + self.setModified(False) + + self.Fit() + + def setModified(self, flag): + self.modified = flag + if flag: + self.bSave.Enable(True) + self.bExit.SetLabel("Cancel") + else: + self.bSave.Enable(False) + self.bExit.SetLabel("Exit") + + def onTextCtrl(self, evt): + self.setModified(True) + evt.Skip() + + def onSave(self, evt): + self.saveValues() + self.EndModal(wx.ID_OK) + + def saveValues(self): + self.settings.arduinodir = self.fields[ARDUINODIR][2].GetValue() + self.settings.cflags = self.fields[CFLAGS][2].GetValue() + self.settings.ldflags = self.fields[LDFLAGS][2].GetValue() + self.settings.objcopyflags = self.fields[OBJCOPYFLAGS][2].GetValue() + self.settings.programmer = self.fields[PROGRAMMER][2].GetValue() + self.settings.port = self.fields[PORT][2].GetValue() + + self.settings.saveSettings() + + def onExit(self, evt): + if not self.confirmLoseChanges("exit"): + return + self.EndModal(wx.ID_EXIT) + + def confirmLoseChanges(self, msg): + if not self.modified: + return True + + dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n" + "There are changes to your settings that " + "will be lost.", + "Changes pending", + wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION) + rc = dlg.ShowModal() + dlg.Destroy() + + if rc != wx.ID_YES: + return False + + return True