From bf72cb7f10a0f3576b52e192ff8ca897d8636a4f Mon Sep 17 00:00:00 2001 From: Nico Tonnhofer Date: Fri, 28 Dec 2018 20:07:51 +0100 Subject: [PATCH] python3: pep8 all files. e.g. 4 spaces for identation using black for this: https://github.com/ambv/black --- configtool.py | 221 ++--- configtool/accelerationpage.py | 188 +++-- configtool/addheaterdlg.py | 351 ++++---- configtool/addsensordlg.py | 1280 +++++++++++++++-------------- configtool/board.py | 924 +++++++++++---------- configtool/boardpanel.py | 491 ++++++----- configtool/build.py | 831 ++++++++++--------- configtool/calcbelt.py | 513 ++++++------ configtool/calcscrew.py | 517 ++++++------ configtool/communicationspage.py | 87 +- configtool/cpupage.py | 76 +- configtool/data.py | 68 +- configtool/decoration.py | 102 +-- configtool/displaypage.py | 133 +-- configtool/gui.py | 1219 ++++++++++++++------------- configtool/heaterlist.py | 138 ++-- configtool/heaterspage.py | 285 +++---- configtool/mechanicalpage.py | 401 ++++----- configtool/miscellaneouspage.py | 383 ++++----- configtool/page.py | 654 ++++++++------- configtool/pinoutspage.py | 340 ++++---- configtool/printer.py | 561 +++++++------ configtool/printerpanel.py | 432 +++++----- configtool/protectedfiles.py | 35 +- configtool/sensorlist.py | 134 +-- configtool/sensorpage.py | 311 +++---- configtool/settings.py | 205 ++--- configtool/settingsdlg.py | 292 +++---- configtool/thermistor.py | 157 ++-- configtool/thermistorpresets.py | 17 +- configtool/thermistortablefile.py | 410 ++++----- createTemperatureLookup.py | 401 +++++---- extract.py | 2 +- research/planes.py | 130 +-- testcases/parse_datalog.py | 40 +- 35 files changed, 6526 insertions(+), 5803 deletions(-) diff --git a/configtool.py b/configtool.py index 2edc2cf..18cb608 100755 --- a/configtool.py +++ b/configtool.py @@ -14,12 +14,15 @@ from __future__ import print_function import sys import time + if sys.version_info.major >= 3: - print("You are currently running Python3. Python3 is not supported.\n" + print( + "You are currently running Python3. Python3 is not supported.\n" "Please try running with Python2.\n\n" - "It often works to type \"python2 configtool.py\" in the command line.") - time.sleep(10) - sys.exit(-1) + 'It often works to type "python2 configtool.py" in the command line.' + ) + time.sleep(10) + sys.exit(-1) import getopt import os.path @@ -29,92 +32,99 @@ from configtool.settings import Settings from configtool.board import Board from configtool.printer import Printer -cmdFolder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( - inspect.currentframe()))[0])) +cmdFolder = os.path.realpath( + os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0]) +) verbose = 0 settings = None board = None printer = None -def getSettings(arg = None): - global settings - if arg or not settings: - settings = Settings(None, cmdFolder, arg) - settings.verbose = verbose - return settings + +def getSettings(arg=None): + global settings + if arg or not settings: + settings = Settings(None, cmdFolder, arg) + settings.verbose = verbose + return settings + def cmdLoad(arg): - xx, ext = os.path.splitext(arg) - fn = os.path.basename(arg) + xx, ext = os.path.splitext(arg) + fn = os.path.basename(arg) - if ext == ".ini": - settings = getSettings(arg) - if not settings.loaded: - print("Failed to load settings file: %s." % arg) - sys.exit(2) - return + if ext == ".ini": + settings = getSettings(arg) + if not settings.loaded: + print("Failed to load settings file: %s." % arg) + sys.exit(2) + return - if ext == ".h": - if fn.startswith("board."): - global board - board = Board(getSettings()) - ok, fn = board.loadConfigFile(arg) - if not ok: - print("Failed trying to load board file: %s." % fn) - sys.exit(2) - return - elif fn.startswith("printer."): - global printer - printer = Printer(getSettings()) - ok, fn = printer.loadConfigFile(arg) - if not ok: - print("Failed trying to load printer file: %s" % fn) - sys.exit(2) - return + if ext == ".h": + if fn.startswith("board."): + global board + board = Board(getSettings()) + ok, fn = board.loadConfigFile(arg) + if not ok: + print("Failed trying to load board file: %s." % fn) + sys.exit(2) + return + elif fn.startswith("printer."): + global printer + printer = Printer(getSettings()) + ok, fn = printer.loadConfigFile(arg) + if not ok: + print("Failed trying to load printer file: %s" % fn) + sys.exit(2) + return + + print("Unrecognized file: %s." % arg) + print("Expected one of *.ini, board.*.h or printer.*.h.") + sys.exit(2) - print("Unrecognized file: %s." % arg) - print("Expected one of *.ini, board.*.h or printer.*.h.") - sys.exit(2) def cmdSave(arg): - xx, ext = os.path.splitext(arg) - fn = os.path.basename(arg) + xx, ext = os.path.splitext(arg) + fn = os.path.basename(arg) - if ext == ".ini": - if not getSettings(arg).save(arg): - print("Failed to save settings file: %s." % arg) - sys.exit(2) - return + if ext == ".ini": + if not getSettings(arg).save(arg): + print("Failed to save settings file: %s." % arg) + sys.exit(2) + return - if ext == ".h": - if fn.startswith("board."): - global board - if not board.saveConfigFile(arg, None): - print("Failed trying to save board file: %s." % arg) - sys.exit(2) - return - elif fn.startswith("printer."): - global printer - if not printer.saveConfigFile(arg, None): - print("Failed trying to save printer file: %s." % arg) - sys.exit(2) - return + if ext == ".h": + if fn.startswith("board."): + global board + if not board.saveConfigFile(arg, None): + print("Failed trying to save board file: %s." % arg) + sys.exit(2) + return + elif fn.startswith("printer."): + global printer + if not printer.saveConfigFile(arg, None): + print("Failed trying to save printer file: %s." % arg) + sys.exit(2) + return + + print("Unrecognized file: %s." % arg) + print("Expected one of *.ini, board.*.h or printer.*.h.") + sys.exit(2) - print("Unrecognized file: %s." % arg) - print("Expected one of *.ini, board.*.h or printer.*.h.") - sys.exit(2) def cmdShowAll(): - names = {"configtool": getSettings(), "board": board, "printer": printer} - for namespace in names: - if names[namespace]: - values = names[namespace].getValues() - for k in sorted(values): - print("%s.%s: %s" % (namespace, k, str(values[k]))) + names = {"configtool": getSettings(), "board": board, "printer": printer} + for namespace in names: + if names[namespace]: + values = names[namespace].getValues() + for k in sorted(values): + print("%s.%s: %s" % (namespace, k, str(values[k]))) + def cmdHelp(): - print("""Usage: %s [options] + print( + """Usage: %s [options] Running without any options starts the gui (normal operation). Following options are available for command line automation: @@ -137,50 +147,55 @@ Following options are available for command line automation: -a, --show-all Show all loaded variables and values. -q, --quit Quit processing without launching the GUI. -""" % sys.argv[0]) +""" + % sys.argv[0] + ) + def CommandLine(argv): - """ Parse and act on command line arguments. All script automation commands + """ Parse and act on command line arguments. All script automation commands result in sys.exit() (i.e. they do not return from this function). Other options like --debug will return to allow the gui to launch. """ - global settings, verbose + global settings, verbose - try: - opts, args = getopt.getopt(argv, "hvl:as:q", ["help", "verbose", "load=", - "show-all", "save=", "quit"]) - except getopt.GetoptError as err: - print(err) - print("Use '%s --help' to get help with command line options." % - sys.argv[0]) - sys.exit(2) + try: + opts, args = getopt.getopt( + argv, "hvl:as:q", ["help", "verbose", "load=", "show-all", "save=", "quit"] + ) + except getopt.GetoptError as err: + print(err) + print("Use '%s --help' to get help with command line options." % sys.argv[0]) + sys.exit(2) - # Check for HELP first. - for opt, arg in opts: - if opt in ("-h", "--help"): - cmdHelp() - sys.exit() + # Check for HELP first. + for opt, arg in opts: + if opt in ("-h", "--help"): + cmdHelp() + sys.exit() - # Now parse other options. - for opt, arg in opts: - if opt in ("-v", "--verbose"): - verbose += 1 - getSettings() + # Now parse other options. + for opt, arg in opts: + if opt in ("-v", "--verbose"): + verbose += 1 + getSettings() - elif opt in ("-l", "--load"): - cmdLoad(arg) + elif opt in ("-l", "--load"): + cmdLoad(arg) - elif opt in ("-s", "--save"): - cmdSave(arg) + elif opt in ("-s", "--save"): + cmdSave(arg) - elif opt in ("-a", "--show-all"): - cmdShowAll() + elif opt in ("-a", "--show-all"): + cmdShowAll() - elif opt in ("-q", "--quit"): - sys.exit() + elif opt in ("-q", "--quit"): + sys.exit() -if __name__ == '__main__': - CommandLine(sys.argv[1:]) - from configtool.gui import StartGui - StartGui(getSettings()) +if __name__ == "__main__": + CommandLine(sys.argv[1:]) + + from configtool.gui import StartGui + + StartGui(getSettings()) diff --git a/configtool/accelerationpage.py b/configtool/accelerationpage.py index 511c4b2..1fc7338 100644 --- a/configtool/accelerationpage.py +++ b/configtool/accelerationpage.py @@ -1,120 +1,126 @@ - import wx from configtool.page import Page class AccelerationPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.parent = parent - self.id = idPg + def __init__(self, parent, nb, idPg, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.parent = parent + self.id = idPg - self.accTypeKeys = ['ACCELERATION_REPRAP', 'ACCELERATION_RAMPING', - 'ACCELERATION_TEMPORAL'] - self.jerkKeys = ['MAX_JERK_X', 'MAX_JERK_Y', 'MAX_JERK_Z', 'MAX_JERK_E'] + self.accTypeKeys = [ + "ACCELERATION_REPRAP", + "ACCELERATION_RAMPING", + "ACCELERATION_TEMPORAL", + ] + self.jerkKeys = ["MAX_JERK_X", "MAX_JERK_Y", "MAX_JERK_Z", "MAX_JERK_E"] - self.labels = {'ACCELERATION_REPRAP': "RepRap", - 'ACCELERATION_RAMPING': "Ramping", - 'ACCELERATION_TEMPORAL': "Temporal", - 'ACCELERATION': "Acceleration:", - 'LOOKAHEAD': "Look Ahead", - 'MAX_JERK_X': "X:", 'MAX_JERK_Y': "Y:", 'MAX_JERK_Z': "Z:", - 'MAX_JERK_E': "E:"} + self.labels = { + "ACCELERATION_REPRAP": "RepRap", + "ACCELERATION_RAMPING": "Ramping", + "ACCELERATION_TEMPORAL": "Temporal", + "ACCELERATION": "Acceleration:", + "LOOKAHEAD": "Look Ahead", + "MAX_JERK_X": "X:", + "MAX_JERK_Y": "Y:", + "MAX_JERK_Z": "Z:", + "MAX_JERK_E": "E:", + } - sz = wx.GridBagSizer() - sz.Add((20, 40), pos = (0, 0)) - b = wx.StaticBox(self, wx.ID_ANY, "Acceleration Type") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - style = wx.RB_GROUP - for k in self.accTypeKeys: - rb = self.addRadioButton(k, style, self.onAccTypeSelect, b) - style = 0 + sz = wx.GridBagSizer() + sz.Add((20, 40), pos=(0, 0)) + b = wx.StaticBox(self, wx.ID_ANY, "Acceleration Type") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + style = wx.RB_GROUP + for k in self.accTypeKeys: + rb = self.addRadioButton(k, style, self.onAccTypeSelect, b) + style = 0 - sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16) - sbox.Add((5, 5)) + sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16) + sbox.Add((5, 5)) - self.rbNone = wx.RadioButton(self, wx.ID_ANY, "None", style = style) - self.rbNone.SetFont(font) - self.rbNone.SetValue(True) - self.Bind(wx.EVT_RADIOBUTTON, self.onAccTypeSelect, self.rbNone) - sbox.Add(self.rbNone, 1, wx.LEFT + wx.RIGHT, 16) - sbox.Add((5, 5)) - sz.Add(sbox, pos = (1, 1)) + self.rbNone = wx.RadioButton(self, wx.ID_ANY, "None", style=style) + self.rbNone.SetFont(font) + self.rbNone.SetValue(True) + self.Bind(wx.EVT_RADIOBUTTON, self.onAccTypeSelect, self.rbNone) + sbox.Add(self.rbNone, 1, wx.LEFT + wx.RIGHT, 16) + sbox.Add((5, 5)) + sz.Add(sbox, pos=(1, 1)) - b = wx.StaticBox(self, wx.ID_ANY, "Ramping Parameters") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) + b = wx.StaticBox(self, wx.ID_ANY, "Ramping Parameters") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) - k = 'ACCELERATION' - tc = self.addTextCtrl(k, 80, self.onTextCtrlFloat) - self.textControls[k].Enable(False) + k = "ACCELERATION" + tc = self.addTextCtrl(k, 80, self.onTextCtrlFloat) + self.textControls[k].Enable(False) - sbox.Add(tc) - sbox.Add((5, 5)) + sbox.Add(tc) + sbox.Add((5, 5)) - k = 'LOOKAHEAD' - cb = self.addCheckBox(k, self.onCheckBox) - self.checkBoxes[k].Enable(False) + k = "LOOKAHEAD" + cb = self.addCheckBox(k, self.onCheckBox) + self.checkBoxes[k].Enable(False) - sbox.Add(cb, 1, wx.ALIGN_CENTER_HORIZONTAL) - sbox.Add((5, 5)) + sbox.Add(cb, 1, wx.ALIGN_CENTER_HORIZONTAL) + sbox.Add((5, 5)) - sz.Add(sbox, pos = (1, 3)) + sz.Add(sbox, pos=(1, 3)) - b = wx.StaticBox(self, wx.ID_ANY, "Maximum Jerk") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k in self.jerkKeys: - tc = self.addTextCtrl(k, 40, self.onTextCtrlInteger) + b = wx.StaticBox(self, wx.ID_ANY, "Maximum Jerk") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k in self.jerkKeys: + tc = self.addTextCtrl(k, 40, self.onTextCtrlInteger) - sbox.Add(tc) - sbox.Add((5, 5)) + sbox.Add(tc) + sbox.Add((5, 5)) - sz.Add((80, 20), pos = (1, 4)) - sz.Add(sbox, pos = (1, 5)) + sz.Add((80, 20), pos=(1, 4)) + sz.Add(sbox, pos=(1, 5)) - self.SetSizer(sz) - self.enableAll(False) + self.SetSizer(sz) + self.enableAll(False) - def enableAll(self, flag = True): - self.rbNone.Enable(flag) - Page.enableAll(self, flag) + def enableAll(self, flag=True): + self.rbNone.Enable(flag) + Page.enableAll(self, flag) - def onAccTypeSelect(self, evt): - self.assertModified(True) - rb = evt.GetEventObject() - label = rb.GetLabel() + def onAccTypeSelect(self, evt): + self.assertModified(True) + rb = evt.GetEventObject() + label = rb.GetLabel() - if label == self.labels['ACCELERATION_RAMPING']: - ena = True - else: - ena = False + if label == self.labels["ACCELERATION_RAMPING"]: + ena = True + else: + ena = False - self.checkBoxes['LOOKAHEAD'].Enable(ena) - self.textControls['ACCELERATION'].Enable(ena) - evt.Skip() + self.checkBoxes["LOOKAHEAD"].Enable(ena) + self.textControls["ACCELERATION"].Enable(ena) + evt.Skip() - def insertValues(self, cfgValues): - Page.insertValues(self, cfgValues) + def insertValues(self, cfgValues): + Page.insertValues(self, cfgValues) - self.checkBoxes['LOOKAHEAD'].Enable(False) - self.textControls['ACCELERATION'].Enable(False) - for tag in self.accTypeKeys: - if tag in cfgValues.keys() and cfgValues[tag]: - self.radioButtons[tag].SetValue(True) - if tag == 'ACCELERATION_RAMPING': - self.checkBoxes['LOOKAHEAD'].Enable(True) - self.textControls['ACCELERATION'].Enable(True) + self.checkBoxes["LOOKAHEAD"].Enable(False) + self.textControls["ACCELERATION"].Enable(False) + for tag in self.accTypeKeys: + if tag in cfgValues.keys() and cfgValues[tag]: + self.radioButtons[tag].SetValue(True) + if tag == "ACCELERATION_RAMPING": + self.checkBoxes["LOOKAHEAD"].Enable(True) + self.textControls["ACCELERATION"].Enable(True) - def getValues(self): - result = Page.getValues(self) + def getValues(self): + result = Page.getValues(self) - for tag in self.accTypeKeys: - result[tag] = self.radioButtons[tag].GetValue() + for tag in self.accTypeKeys: + result[tag] = self.radioButtons[tag].GetValue() - return result + return result diff --git a/configtool/addheaterdlg.py b/configtool/addheaterdlg.py index af65d2f..e71a241 100644 --- a/configtool/addheaterdlg.py +++ b/configtool/addheaterdlg.py @@ -1,216 +1,229 @@ - import wx from configtool.data import BSIZESMALL, offsetChLabel, offsetTcLabel class AddHeaterDlg(wx.Dialog): - def __init__(self, parent, names, pins, font, - name = "", pin = "", invert = "0", pwm = "1", max_pwm = "100"): - wx.Dialog.__init__(self, parent, wx.ID_ANY, "Add heater", size = (400, 204)) - self.SetFont(font) - self.Bind(wx.EVT_CLOSE, self.onCancel) + def __init__( + self, + parent, + names, + pins, + font, + name="", + pin="", + invert="0", + pwm="1", + max_pwm="100", + ): + wx.Dialog.__init__(self, parent, wx.ID_ANY, "Add heater", size=(400, 204)) + self.SetFont(font) + self.Bind(wx.EVT_CLOSE, self.onCancel) - self.names = names - self.choices = pins + self.names = names + self.choices = pins - self.nameValid = (name != "") - self.maxPWMValid = (max_pwm != "") - self.pwmValid = (pwm != "") + self.nameValid = name != "" + self.maxPWMValid = max_pwm != "" + self.pwmValid = pwm != "" - sz = wx.BoxSizer(wx.VERTICAL) - gsz = wx.GridBagSizer() - gsz.Add((20, 20), pos = (0, 0)) + sz = wx.BoxSizer(wx.VERTICAL) + gsz = wx.GridBagSizer() + gsz.Add((20, 20), pos=(0, 0)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Heater Name:", size = (80, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Heater Name:", size=(80, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.tcName = wx.TextCtrl(self, wx.ID_ANY, name) - self.tcName.SetFont(font) - if not name: - self.tcName.SetBackgroundColour("pink") - self.tcName.Bind(wx.EVT_TEXT, self.onNameEntry) - lsz.Add(self.tcName) - self.tcName.SetToolTip("Enter a unique name for this heater.") + self.tcName = wx.TextCtrl(self, wx.ID_ANY, name) + self.tcName.SetFont(font) + if not name: + self.tcName.SetBackgroundColour("pink") + self.tcName.Bind(wx.EVT_TEXT, self.onNameEntry) + lsz.Add(self.tcName) + self.tcName.SetToolTip("Enter a unique name for this heater.") - gsz.Add(lsz, pos = (1, 1)) + gsz.Add(lsz, pos=(1, 1)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Pin:", size = (80, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText(self, wx.ID_ANY, "Pin:", size=(80, -1), style=wx.ALIGN_RIGHT) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) - self.chPin = wx.Choice(self, wx.ID_ANY, choices = pins) - self.chPin.SetFont(font) - self.chPin.Bind(wx.EVT_CHOICE, self.onChoice) - i = self.chPin.FindString(pin) - if i == wx.NOT_FOUND: - self.chPin.SetSelection(0) - else: - self.chPin.SetSelection(i) - lsz.Add(self.chPin) - self.chPin.SetToolTip("Choose a pin for this heater.") + self.chPin = wx.Choice(self, wx.ID_ANY, choices=pins) + self.chPin.SetFont(font) + self.chPin.Bind(wx.EVT_CHOICE, self.onChoice) + i = self.chPin.FindString(pin) + if i == wx.NOT_FOUND: + self.chPin.SetSelection(0) + else: + self.chPin.SetSelection(i) + lsz.Add(self.chPin) + self.chPin.SetToolTip("Choose a pin for this heater.") - gsz.Add(lsz, pos = (3, 1)) + gsz.Add(lsz, pos=(3, 1)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Max PWM:", size = (80, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Max PWM:", size=(80, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) - self.tcMaxPWM = wx.TextCtrl(self, wx.ID_ANY, max_pwm) - self.tcMaxPWM.SetFont(font) - self.tcMaxPWM.Bind(wx.EVT_TEXT, self.onMaxPWM) - lsz.Add(self.tcMaxPWM) - self.tcMaxPWM.SetToolTip("Enter max. PWM value in [%]. Typically \n" - "between 40 and 100. Standard is 100.\n" - "Valid values 1 to 100.") + self.tcMaxPWM = wx.TextCtrl(self, wx.ID_ANY, max_pwm) + self.tcMaxPWM.SetFont(font) + self.tcMaxPWM.Bind(wx.EVT_TEXT, self.onMaxPWM) + lsz.Add(self.tcMaxPWM) + self.tcMaxPWM.SetToolTip( + "Enter max. PWM value in [%]. Typically \n" + "between 40 and 100. Standard is 100.\n" + "Valid values 1 to 100." + ) - gsz.Add(lsz, pos = (5, 1)) + gsz.Add(lsz, pos=(5, 1)) - self.cbInv = wx.CheckBox(self, wx.ID_ANY, "Invert") - self.cbInv.SetFont(font) - self.cbInv.SetValue(int(invert) != 0) - self.cbInv.SetToolTip("Invert the pin signal.") + self.cbInv = wx.CheckBox(self, wx.ID_ANY, "Invert") + self.cbInv.SetFont(font) + self.cbInv.SetValue(int(invert) != 0) + self.cbInv.SetToolTip("Invert the pin signal.") - gsz.Add(self.cbInv, pos = (3, 3)) + gsz.Add(self.cbInv, pos=(3, 3)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "PWM:", size = (60, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText(self, wx.ID_ANY, "PWM:", size=(60, -1), style=wx.ALIGN_RIGHT) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) - self.tcPwm = wx.TextCtrl(self, wx.ID_ANY, pwm, size=(60, -1)) - self.tcPwm.SetFont(font) - self.tcPwm.Bind(wx.EVT_TEXT, self.onPWM) - lsz.Add(self.tcPwm) - self.tcPwm.SetToolTip("Use Pulse Width Modulation. " - "Hardware PWM if available or " - "Software PWM. When FORCE_SOFTWARE_PWM " - "is set, always software PWM for 1 and " - "hardware PWM for >= 2.") + self.tcPwm = wx.TextCtrl(self, wx.ID_ANY, pwm, size=(60, -1)) + self.tcPwm.SetFont(font) + self.tcPwm.Bind(wx.EVT_TEXT, self.onPWM) + lsz.Add(self.tcPwm) + self.tcPwm.SetToolTip( + "Use Pulse Width Modulation. " + "Hardware PWM if available or " + "Software PWM. When FORCE_SOFTWARE_PWM " + "is set, always software PWM for 1 and " + "hardware PWM for >= 2." + ) - gsz.Add((50, 15), pos = (1, 2)) - gsz.Add(lsz, pos = (1, 3)) - gsz.Add((20, 20), pos = (4, 4)) + gsz.Add((50, 15), pos=(1, 2)) + gsz.Add(lsz, pos=(1, 3)) + gsz.Add((20, 20), pos=(4, 4)) - sz.Add(gsz) - sz.Add((30, 30)) + sz.Add(gsz) + sz.Add((30, 30)) - bsz = wx.BoxSizer(wx.HORIZONTAL) + bsz = wx.BoxSizer(wx.HORIZONTAL) - self.bSave = wx.Button(self, wx.ID_ANY, "Save", size = BSIZESMALL) - self.bSave.SetFont(font) - self.bSave.Bind(wx.EVT_BUTTON, self.onSave) - bsz.Add(self.bSave) + self.bSave = wx.Button(self, wx.ID_ANY, "Save", size=BSIZESMALL) + self.bSave.SetFont(font) + self.bSave.Bind(wx.EVT_BUTTON, self.onSave) + bsz.Add(self.bSave) - bsz.Add(30, 100) + bsz.Add(30, 100) - self.bCancel = wx.Button(self, wx.ID_ANY, "Cancel", size = BSIZESMALL) - self.bCancel.SetFont(font) - self.bCancel.Bind(wx.EVT_BUTTON, self.onCancel) - bsz.Add(self.bCancel) + self.bCancel = wx.Button(self, wx.ID_ANY, "Cancel", size=BSIZESMALL) + self.bCancel.SetFont(font) + self.bCancel.Bind(wx.EVT_BUTTON, self.onCancel) + bsz.Add(self.bCancel) - sz.Add(bsz, flag = wx.ALIGN_CENTER_HORIZONTAL) - sz.Add((10, 10)) - self.SetSizer(sz) + sz.Add(bsz, flag=wx.ALIGN_CENTER_HORIZONTAL) + sz.Add((10, 10)) + self.SetSizer(sz) - self.checkDlgValidity() - self.Fit() + self.checkDlgValidity() + self.Fit() - def onNameEntry(self, evt): - tc = evt.GetEventObject() - w = tc.GetValue().strip() - if w == "": - self.nameValid = False - else: - if w in self.names: - self.nameValid = False - else: - self.nameValid = True + def onNameEntry(self, evt): + tc = evt.GetEventObject() + w = tc.GetValue().strip() + if w == "": + self.nameValid = False + else: + if w in self.names: + self.nameValid = False + else: + self.nameValid = True - if self.nameValid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() + if self.nameValid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() - self.checkDlgValidity() - evt.Skip() + self.checkDlgValidity() + evt.Skip() - def onChoice(self, evt): - pass + def onChoice(self, evt): + pass - def onMaxPWM(self, evt): - tc = evt.GetEventObject() - w = tc.GetValue().strip() - if w == "": - self.maxPWMValid = False - else: - if int(w) > 0 and int(w) <= 100: - self.maxPWMValid = True - else: - self.maxPWMValid = False + def onMaxPWM(self, evt): + tc = evt.GetEventObject() + w = tc.GetValue().strip() + if w == "": + self.maxPWMValid = False + else: + if int(w) > 0 and int(w) <= 100: + self.maxPWMValid = True + else: + self.maxPWMValid = False - if self.maxPWMValid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() + if self.maxPWMValid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() - self.checkDlgValidity() - if evt is not None: - evt.Skip() + self.checkDlgValidity() + if evt is not None: + evt.Skip() - def onPWM(self, evt): - tc = evt.GetEventObject() - w = tc.GetValue().strip() - if w == "": - self.pwmValid = False - else: - if int(w) >= 0: - self.pwmValid = True - else: - self.pwmValid = False + def onPWM(self, evt): + tc = evt.GetEventObject() + w = tc.GetValue().strip() + if w == "": + self.pwmValid = False + else: + if int(w) >= 0: + self.pwmValid = True + else: + self.pwmValid = False - if self.pwmValid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() + if self.pwmValid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() - self.checkDlgValidity() - if evt is not None: - evt.Skip() + self.checkDlgValidity() + if evt is not None: + evt.Skip() - def checkDlgValidity(self): - if (self.nameValid and self.maxPWMValid and self.pwmValid): - self.bSave.Enable(True) - else: - self.bSave.Enable(False) + def checkDlgValidity(self): + if self.nameValid and self.maxPWMValid and self.pwmValid: + self.bSave.Enable(True) + else: + self.bSave.Enable(False) - def getValues(self): - nm = self.tcName.GetValue() - pin = self.choices[self.chPin.GetSelection()] + def getValues(self): + nm = self.tcName.GetValue() + pin = self.choices[self.chPin.GetSelection()] - if self.cbInv.IsChecked(): - invert = "1" - else: - invert = "0" + if self.cbInv.IsChecked(): + invert = "1" + else: + invert = "0" - pwm = self.tcPwm.GetValue() + pwm = self.tcPwm.GetValue() - max_pwm = self.tcMaxPWM.GetValue() + max_pwm = self.tcMaxPWM.GetValue() - return (nm, pin, invert, pwm, max_pwm) + return (nm, pin, invert, pwm, max_pwm) - def onSave(self, evt): - self.EndModal(wx.ID_OK) + def onSave(self, evt): + self.EndModal(wx.ID_OK) - def onCancel(self, evt): - self.EndModal(wx.ID_CANCEL) + def onCancel(self, evt): + self.EndModal(wx.ID_CANCEL) diff --git a/configtool/addsensordlg.py b/configtool/addsensordlg.py index 5102c40..1d3b10b 100644 --- a/configtool/addsensordlg.py +++ b/configtool/addsensordlg.py @@ -1,7 +1,13 @@ - import wx -from configtool.data import (pinNames, BSIZESMALL, sensorTypes, offsetTcLabel, - offsetChLabel, reInteger, reFloat) +from configtool.data import ( + pinNames, + BSIZESMALL, + sensorTypes, + offsetTcLabel, + offsetChLabel, + reInteger, + reFloat, +) from configtool.thermistorpresets import thermistorPresets MODE_NONTHERM = 0 @@ -15,710 +21,772 @@ labelWidth = 160 class AddSensorDlg(wx.Dialog): - def __init__(self, parent, names, pins, heatersPage, font, name = "", - stype = "", pin = "", params = [], modify = False): - if modify: - title = "Modify temperature sensor" - else: - title = "Add temperature sensor" - wx.Dialog.__init__(self, parent, wx.ID_ANY, title, size = (400, 204)) - self.SetFont(font) - self.Bind(wx.EVT_CLOSE, self.onCancel) + def __init__( + self, + parent, + names, + pins, + heatersPage, + font, + name="", + stype="", + pin="", + params=[], + modify=False, + ): + if modify: + title = "Modify temperature sensor" + else: + title = "Add temperature sensor" + wx.Dialog.__init__(self, parent, wx.ID_ANY, title, size=(400, 204)) + self.SetFont(font) + self.Bind(wx.EVT_CLOSE, self.onCancel) - self.names = names - self.choices = pins - self.heatersPage = heatersPage - self.modify = modify + self.names = names + self.choices = pins + self.heatersPage = heatersPage + self.modify = modify - if len(params) == 0: - self.currentMethod = METHOD_BETA - self.currentMode = MODE_NONTHERM - else: - self.currentMode = MODE_THERMISTOR - if len(params) == 4: - self.currentMethod = METHOD_BETA - else: - self.currentMethod = METHOD_SH + if len(params) == 0: + self.currentMethod = METHOD_BETA + self.currentMode = MODE_NONTHERM + else: + self.currentMode = MODE_THERMISTOR + if len(params) == 4: + self.currentMethod = METHOD_BETA + else: + self.currentMethod = METHOD_SH - self.nameValid = False - self.param0Valid = False - self.param1Valid = False - self.param2Valid = False - self.param3Valid = False - self.param4Valid = False - self.param5Valid = False - self.param6Valid = False + self.nameValid = False + self.param0Valid = False + self.param1Valid = False + self.param2Valid = False + self.param3Valid = False + self.param4Valid = False + self.param5Valid = False + self.param6Valid = False - sizer = wx.BoxSizer(wx.VERTICAL) + sizer = wx.BoxSizer(wx.VERTICAL) - hsz = wx.BoxSizer(wx.HORIZONTAL) - hsz.Add((10, 10)) + hsz = wx.BoxSizer(wx.HORIZONTAL) + hsz.Add((10, 10)) - csz = wx.BoxSizer(wx.VERTICAL) - csz.Add((10, 10)) + csz = wx.BoxSizer(wx.VERTICAL) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Heater Name:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Heater Name:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) - nameList = ["noheater"] + self.heatersPage.heaterNames() - for alreadyDefinedName in names: - try: - nameList.remove(alreadyDefinedName) - except: - pass - if modify: - nameList.insert(0, name) + nameList = ["noheater"] + self.heatersPage.heaterNames() + for alreadyDefinedName in names: + try: + nameList.remove(alreadyDefinedName) + except: + pass + if modify: + nameList.insert(0, name) - if len(nameList) == 0: - nameList = [""] - self.nameValid = False - else: - self.nameValid = True + if len(nameList) == 0: + nameList = [""] + self.nameValid = False + else: + self.nameValid = True - self.tcName = wx.Choice(self, wx.ID_ANY, choices = nameList) - self.tcName.SetFont(font) - self.tcName.Bind(wx.EVT_CHOICE, self.onHeaterName) - lsz.Add(self.tcName) - self.tcName.SetToolTip("Choose the name of the corresponding heater. " - "This may require to define that heater " - "first.") - self.tcName.SetSelection(0) + self.tcName = wx.Choice(self, wx.ID_ANY, choices=nameList) + self.tcName.SetFont(font) + self.tcName.Bind(wx.EVT_CHOICE, self.onHeaterName) + lsz.Add(self.tcName) + self.tcName.SetToolTip( + "Choose the name of the corresponding heater. " + "This may require to define that heater " + "first." + ) + self.tcName.SetSelection(0) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Sensor Type:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Sensor Type:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) - sl = sorted(sensorTypes.keys()) + sl = sorted(sensorTypes.keys()) - ch = wx.Choice(self, wx.ID_ANY, choices = sl) - ch.SetFont(font) - ch.Bind(wx.EVT_CHOICE, self.onSensorType) - found = False - for st in sensorTypes.keys(): - if sensorTypes[st] == stype: - i = ch.FindString(st) - if i != wx.NOT_FOUND: - stStart = st - ch.SetSelection(i) - found = True - break + ch = wx.Choice(self, wx.ID_ANY, choices=sl) + ch.SetFont(font) + ch.Bind(wx.EVT_CHOICE, self.onSensorType) + found = False + for st in sensorTypes.keys(): + if sensorTypes[st] == stype: + i = ch.FindString(st) + if i != wx.NOT_FOUND: + stStart = st + ch.SetSelection(i) + found = True + break - if not found: - ch.SetSelection(0) - stStart = sl[0] + if not found: + ch.SetSelection(0) + stStart = sl[0] - self.chType = ch - lsz.Add(ch) + self.chType = ch + lsz.Add(ch) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Pin:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Pin:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) - self.choiceList = pinNames - self.chPin = wx.Choice(self, wx.ID_ANY, choices = pins) - self.chPin.SetFont(font) - self.chPin.Bind(wx.EVT_CHOICE, self.onChoice) - i = self.chPin.FindString(pin) - if i == wx.NOT_FOUND: - self.chPin.SetSelection(0) - else: - self.chPin.SetSelection(i) - lsz.Add(self.chPin) - self.chPin.SetToolTip("Choose a pin name for this sensor.") + self.choiceList = pinNames + self.chPin = wx.Choice(self, wx.ID_ANY, choices=pins) + self.chPin.SetFont(font) + self.chPin.Bind(wx.EVT_CHOICE, self.onChoice) + i = self.chPin.FindString(pin) + if i == wx.NOT_FOUND: + self.chPin.SetSelection(0) + else: + self.chPin.SetSelection(i) + lsz.Add(self.chPin) + self.chPin.SetToolTip("Choose a pin name for this sensor.") - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.label0 = st + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + self.label0 = st - vals = params + ["", "", "", "", "", "", ""] - self.param0 = wx.TextCtrl(self, wx.ID_ANY, vals[0]) - self.param0.SetFont(font) - self.param0.Bind(wx.EVT_TEXT, self.onParam0Entry) - lsz.Add(self.param0) + vals = params + ["", "", "", "", "", "", ""] + self.param0 = wx.TextCtrl(self, wx.ID_ANY, vals[0]) + self.param0.SetFont(font) + self.param0.Bind(wx.EVT_TEXT, self.onParam0Entry) + lsz.Add(self.param0) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.label1 = st + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + self.label1 = st - self.param1 = wx.TextCtrl(self, wx.ID_ANY, vals[1]) - self.param1.SetFont(font) - self.param1.Bind(wx.EVT_TEXT, self.onParam1Entry) - lsz.Add(self.param1) + self.param1 = wx.TextCtrl(self, wx.ID_ANY, vals[1]) + self.param1.SetFont(font) + self.param1.Bind(wx.EVT_TEXT, self.onParam1Entry) + lsz.Add(self.param1) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.label2 = st + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + self.label2 = st - self.param2 = wx.TextCtrl(self, wx.ID_ANY, vals[2]) - self.param2.SetFont(font) - self.param2.Bind(wx.EVT_TEXT, self.onParam2Entry) - lsz.Add(self.param2) + self.param2 = wx.TextCtrl(self, wx.ID_ANY, vals[2]) + self.param2.SetFont(font) + self.param2.Bind(wx.EVT_TEXT, self.onParam2Entry) + lsz.Add(self.param2) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.label3 = st + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + self.label3 = st - self.param3 = wx.TextCtrl(self, wx.ID_ANY, vals[3]) - self.param3.SetFont(font) - self.param3.Bind(wx.EVT_TEXT, self.onParam3Entry) - lsz.Add(self.param3) + self.param3 = wx.TextCtrl(self, wx.ID_ANY, vals[3]) + self.param3.SetFont(font) + self.param3.Bind(wx.EVT_TEXT, self.onParam3Entry) + lsz.Add(self.param3) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.label4 = st + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + self.label4 = st - self.param4 = wx.TextCtrl(self, wx.ID_ANY, vals[4]) - self.param4.SetFont(font) - self.param4.Bind(wx.EVT_TEXT, self.onParam4Entry) - lsz.Add(self.param4) + self.param4 = wx.TextCtrl(self, wx.ID_ANY, vals[4]) + self.param4.SetFont(font) + self.param4.Bind(wx.EVT_TEXT, self.onParam4Entry) + lsz.Add(self.param4) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.label5 = st + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + self.label5 = st - self.param5 = wx.TextCtrl(self, wx.ID_ANY, vals[5]) - self.param5.SetFont(font) - self.param5.Bind(wx.EVT_TEXT, self.onParam5Entry) - lsz.Add(self.param5) + self.param5 = wx.TextCtrl(self, wx.ID_ANY, vals[5]) + self.param5.SetFont(font) + self.param5.Bind(wx.EVT_TEXT, self.onParam5Entry) + lsz.Add(self.param5) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.label6 = st + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + self.label6 = st - self.param6 = wx.TextCtrl(self, wx.ID_ANY, vals[6]) - self.param6.SetFont(font) - self.param6.Bind(wx.EVT_TEXT, self.onParam6Entry) - lsz.Add(self.param6) + self.param6 = wx.TextCtrl(self, wx.ID_ANY, vals[6]) + self.param6.SetFont(font) + self.param6.Bind(wx.EVT_TEXT, self.onParam6Entry) + lsz.Add(self.param6) - csz.Add(lsz) - csz.Add((10, 10)) + csz.Add(lsz) + csz.Add((10, 10)) - csz.Add((10, 10)) + csz.Add((10, 10)) - hsz.Add(csz) - hsz.Add((10, 10)) + hsz.Add(csz) + hsz.Add((10, 10)) - csz = wx.BoxSizer(wx.VERTICAL) - csz.Add((30, 45)) + csz = wx.BoxSizer(wx.VERTICAL) + csz.Add((30, 45)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Presets:", - size = (70, -1), style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Presets:", size=(70, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) - self.thermistorChoices = [""] + sorted(thermistorPresets.keys()) - ch = wx.Choice(self, wx.ID_ANY, choices = self.thermistorChoices) - ch.SetFont(font) - ch.Enable(False) - ch.SetSelection(0) - self.chPresets = ch - ch.Bind(wx.EVT_CHOICE, self.onPresetChoice) - lsz.Add(ch) + self.thermistorChoices = [""] + sorted(thermistorPresets.keys()) + ch = wx.Choice(self, wx.ID_ANY, choices=self.thermistorChoices) + ch.SetFont(font) + ch.Enable(False) + ch.SetSelection(0) + self.chPresets = ch + ch.Bind(wx.EVT_CHOICE, self.onPresetChoice) + lsz.Add(ch) - csz.Add(lsz) - csz.Add((10, 50)) + csz.Add(lsz) + csz.Add((10, 50)) - b = wx.StaticBox(self, wx.ID_ANY, "Temp Table Algorithm") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - style = wx.RB_GROUP - self.rbMethod = [] - for k in MethodLabels: - rb = wx.RadioButton(self, wx.ID_ANY, k, style = style) - rb.SetFont(font) - self.Bind(wx.EVT_RADIOBUTTON, self.onMethodSelect, rb) - self.rbMethod.append(rb) - style = 0 + b = wx.StaticBox(self, wx.ID_ANY, "Temp Table Algorithm") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + style = wx.RB_GROUP + self.rbMethod = [] + for k in MethodLabels: + rb = wx.RadioButton(self, wx.ID_ANY, k, style=style) + rb.SetFont(font) + self.Bind(wx.EVT_RADIOBUTTON, self.onMethodSelect, rb) + self.rbMethod.append(rb) + style = 0 - sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16) - sbox.Add((5, 5)) + sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16) + sbox.Add((5, 5)) - self.rbMethod[self.currentMethod].SetValue(True); - csz.Add(sbox) + self.rbMethod[self.currentMethod].SetValue(True) + csz.Add(sbox) - hsz.Add(csz) - hsz.Add((10, 10)) + hsz.Add(csz) + hsz.Add((10, 10)) - sizer.Add(hsz) + sizer.Add(hsz) - bsz = wx.BoxSizer(wx.HORIZONTAL) + bsz = wx.BoxSizer(wx.HORIZONTAL) - self.bSave = wx.Button(self, wx.ID_ANY, "Save", size = BSIZESMALL) - self.bSave.SetFont(font) - self.bSave.Bind(wx.EVT_BUTTON, self.onSave) - bsz.Add(self.bSave) - self.bSave.Enable(False) + self.bSave = wx.Button(self, wx.ID_ANY, "Save", size=BSIZESMALL) + self.bSave.SetFont(font) + self.bSave.Bind(wx.EVT_BUTTON, self.onSave) + bsz.Add(self.bSave) + self.bSave.Enable(False) - bsz.Add((30, 10)) + bsz.Add((30, 10)) - self.bCancel = wx.Button(self, wx.ID_ANY, "Cancel", size = BSIZESMALL) - self.bCancel.SetFont(font) - self.bCancel.Bind(wx.EVT_BUTTON, self.onCancel) - bsz.Add(self.bCancel) + self.bCancel = wx.Button(self, wx.ID_ANY, "Cancel", size=BSIZESMALL) + self.bCancel.SetFont(font) + self.bCancel.Bind(wx.EVT_BUTTON, self.onCancel) + bsz.Add(self.bCancel) - sizer.Add(bsz, flag = wx.ALIGN_CENTER_HORIZONTAL) - sizer.Add((10, 10)) + sizer.Add(bsz, flag=wx.ALIGN_CENTER_HORIZONTAL) + sizer.Add((10, 10)) - self.SetSizer(sizer) - self.Fit() + self.SetSizer(sizer) + self.Fit() - self.selectSensorType(stStart) - self.validateFields() - - def onHeaterName(self, evt): - s = self.tcName.GetSelection() - label = self.tcName.GetString(s) - if label.startswith("<"): - self.nameValid = False - else: - self.nameValid = True - - evt.Skip() - - def onMethodSelect(self, evt): - rb = evt.GetEventObject() - lbl = rb.GetLabel() - for i in range(len(MethodLabels)): - if lbl == MethodLabels[i]: - self.currentMethod = i - self.setDialogMode() + self.selectSensorType(stStart) self.validateFields() - return - def checkDlgValidity(self): - if (self.nameValid and self.param0Valid and self.param1Valid and - self.param2Valid and self.param3Valid and self.param4Valid and - self.param5Valid and self.param6Valid): - self.bSave.Enable(True) - else: - self.bSave.Enable(False) + def onHeaterName(self, evt): + s = self.tcName.GetSelection() + label = self.tcName.GetString(s) + if label.startswith("<"): + self.nameValid = False + else: + self.nameValid = True - def onTextCtrlInteger(self, tc, rqd): - if not rqd: - return True - w = tc.GetValue().strip() - if w == "": - if rqd: - valid = False - else: - valid = True - else: - m = reInteger.match(w) - if m: - valid = True - else: - valid = False + evt.Skip() - if valid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") + def onMethodSelect(self, evt): + rb = evt.GetEventObject() + lbl = rb.GetLabel() + for i in range(len(MethodLabels)): + if lbl == MethodLabels[i]: + self.currentMethod = i + self.setDialogMode() + self.validateFields() + return - tc.Refresh() - return valid + def checkDlgValidity(self): + if ( + self.nameValid + and self.param0Valid + and self.param1Valid + and self.param2Valid + and self.param3Valid + and self.param4Valid + and self.param5Valid + and self.param6Valid + ): + self.bSave.Enable(True) + else: + self.bSave.Enable(False) - def onTextCtrlFloat(self, tc, rqd): - if not rqd: - return True - w = tc.GetValue().strip() - if w == "": - if rqd: - valid = False - else: - valid = True - else: - m = reFloat.match(w) - if m: - valid = True - else: - valid = False + def onTextCtrlInteger(self, tc, rqd): + if not rqd: + return True + w = tc.GetValue().strip() + if w == "": + if rqd: + valid = False + else: + valid = True + else: + m = reInteger.match(w) + if m: + valid = True + else: + valid = False - if valid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() - return valid + if valid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") - def onParam0Entry(self, evt): - if self.currentMode == MODE_THERMISTOR: - self.param0Valid = self.onTextCtrlInteger(self.param0, True) - self.checkValuesForPreset() - else: - self.param0Valid = True + tc.Refresh() + return valid - self.checkDlgValidity() - if evt is not None: - evt.Skip() + def onTextCtrlFloat(self, tc, rqd): + if not rqd: + return True + w = tc.GetValue().strip() + if w == "": + if rqd: + valid = False + else: + valid = True + else: + m = reFloat.match(w) + if m: + valid = True + else: + valid = False - def onParam1Entry(self, evt): - if self.currentMode == MODE_THERMISTOR: - if self.currentMethod == METHOD_BETA: - self.param1Valid = self.onTextCtrlInteger(self.param1, True) - else: - self.param1Valid = self.onTextCtrlFloat(self.param1, True) - self.checkValuesForPreset() - else: - self.param1Valid = True + if valid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() + return valid - self.checkDlgValidity() - if evt is not None: - evt.Skip() + def onParam0Entry(self, evt): + if self.currentMode == MODE_THERMISTOR: + self.param0Valid = self.onTextCtrlInteger(self.param0, True) + self.checkValuesForPreset() + else: + self.param0Valid = True - def onParam2Entry(self, evt): - if self.currentMode == MODE_THERMISTOR: - self.param2Valid = self.onTextCtrlInteger(self.param2, True) - self.checkValuesForPreset() - else: - self.param2Valid = True + self.checkDlgValidity() + if evt is not None: + evt.Skip() - self.checkDlgValidity() - if evt is not None: - evt.Skip() + def onParam1Entry(self, evt): + if self.currentMode == MODE_THERMISTOR: + if self.currentMethod == METHOD_BETA: + self.param1Valid = self.onTextCtrlInteger(self.param1, True) + else: + self.param1Valid = self.onTextCtrlFloat(self.param1, True) + self.checkValuesForPreset() + else: + self.param1Valid = True - def onParam3Entry(self, evt): - if self.currentMode == MODE_THERMISTOR: - self.param3Valid = self.onTextCtrlFloat(self.param3, True) - self.checkValuesForPreset() - else: - self.param3Valid = True + self.checkDlgValidity() + if evt is not None: + evt.Skip() - self.checkDlgValidity() - if evt is not None: - evt.Skip() + def onParam2Entry(self, evt): + if self.currentMode == MODE_THERMISTOR: + self.param2Valid = self.onTextCtrlInteger(self.param2, True) + self.checkValuesForPreset() + else: + self.param2Valid = True - def onParam4Entry(self, evt): - if self.currentMode == MODE_THERMISTOR: - if self.currentMethod == METHOD_BETA: - self.param4Valid = True - else: - self.param4Valid = self.onTextCtrlInteger(self.param4, True) - self.checkValuesForPreset() - else: - self.param4Valid = True + self.checkDlgValidity() + if evt is not None: + evt.Skip() - self.checkDlgValidity() - if evt is not None: - evt.Skip() + def onParam3Entry(self, evt): + if self.currentMode == MODE_THERMISTOR: + self.param3Valid = self.onTextCtrlFloat(self.param3, True) + self.checkValuesForPreset() + else: + self.param3Valid = True - def onParam5Entry(self, evt): - if self.currentMode == MODE_THERMISTOR: - if self.currentMethod == METHOD_BETA: - self.param5Valid = True - else: - self.param5Valid = self.onTextCtrlFloat(self.param5, True) - self.checkValuesForPreset() - else: - self.param5Valid = True + self.checkDlgValidity() + if evt is not None: + evt.Skip() - self.checkDlgValidity() - if evt is not None: - evt.Skip() + def onParam4Entry(self, evt): + if self.currentMode == MODE_THERMISTOR: + if self.currentMethod == METHOD_BETA: + self.param4Valid = True + else: + self.param4Valid = self.onTextCtrlInteger(self.param4, True) + self.checkValuesForPreset() + else: + self.param4Valid = True - def onParam6Entry(self, evt): - if self.currentMode == MODE_THERMISTOR: - if self.currentMethod == METHOD_BETA: - self.param6Valid = True - else: - self.param6Valid = self.onTextCtrlInteger(self.param6, True) - self.checkValuesForPreset() - else: - self.param6Valid = True + self.checkDlgValidity() + if evt is not None: + evt.Skip() - self.checkDlgValidity() - if evt is not None: - evt.Skip() + def onParam5Entry(self, evt): + if self.currentMode == MODE_THERMISTOR: + if self.currentMethod == METHOD_BETA: + self.param5Valid = True + else: + self.param5Valid = self.onTextCtrlFloat(self.param5, True) + self.checkValuesForPreset() + else: + self.param5Valid = True - def checkValuesForPreset(self): - p = [] - p.append(self.param0.GetValue().strip()) - p.append(self.param1.GetValue().strip()) - p.append(self.param2.GetValue().strip()) - p.append(self.param3.GetValue().strip()) - if self.currentMethod != METHOD_BETA: - p.append(self.param4.GetValue().strip()) - p.append(self.param5.GetValue().strip()) - p.append(self.param6.GetValue().strip()) + self.checkDlgValidity() + if evt is not None: + evt.Skip() - for k in thermistorPresets.keys(): - if p == thermistorPresets[k]: - try: - i = self.thermistorChoices.index(k) - except: - i = 0 - self.chPresets.SetSelection(i) - return + def onParam6Entry(self, evt): + if self.currentMode == MODE_THERMISTOR: + if self.currentMethod == METHOD_BETA: + self.param6Valid = True + else: + self.param6Valid = self.onTextCtrlInteger(self.param6, True) + self.checkValuesForPreset() + else: + self.param6Valid = True - self.chPresets.SetSelection(0) + self.checkDlgValidity() + if evt is not None: + evt.Skip() - def selectSensorType(self, lbl): - if lbl == "Thermistor" or lbl == "MCP3008": - self.currentMode = MODE_THERMISTOR - else: - self.currentMode = MODE_NONTHERM - self.setDialogMode() + def checkValuesForPreset(self): + p = [] + p.append(self.param0.GetValue().strip()) + p.append(self.param1.GetValue().strip()) + p.append(self.param2.GetValue().strip()) + p.append(self.param3.GetValue().strip()) + if self.currentMethod != METHOD_BETA: + p.append(self.param4.GetValue().strip()) + p.append(self.param5.GetValue().strip()) + p.append(self.param6.GetValue().strip()) - def setDialogMode(self): - if self.currentMode == MODE_THERMISTOR: - if self.currentMethod == METHOD_BETA: - self.param0.SetToolTip("Nominal resistance of the thermistor. " - "Typically 10000 ( = 10k) or 100000 " - "( = 100k).") - self.label0.SetLabel("R0:") - self.param1.SetToolTip("Thermistor beta value. Can be found in " - "the datasheet or measured like described " - "in http://reprap.org/wiki/" - "MeasuringThermistorBeta") - self.label1.SetLabel("Beta:") - self.param2.SetToolTip("Resistance value of the secondary " - "resistor. This is not a property of the " - "thermistor, but one of the board. " - "Typical values are 4700 ( = 4k7 ohms) " - "or 1000 ( = 1k ohms).") - self.label2.SetLabel("R2:") - self.param3.SetToolTip("Comparison voltage used by the " - "controller. Usually the same as the " - "controller's supply voltage, 3.3 or 5.0 " - "(volts).") - self.label3.SetLabel("Vadc:") - self.label4.SetLabel("") - self.param4.SetToolTip(None) - self.param4.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param4.Refresh() - self.label5.SetLabel("") - self.param5.SetToolTip(None) - self.param5.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param5.Refresh() - self.label6.SetLabel("") - self.param6.SetToolTip(None) - self.param6.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param6.Refresh() - self.param4.Enable(False) - self.param5.Enable(False) - self.param6.Enable(False) - else: - self.param0.SetToolTip("Reference resistance value.") - self.label0.SetLabel("Rp:") - self.param1.SetToolTip("First data point, temperature at which " - "resistance is equal to R0.") - self.label1.SetLabel("T0:") - self.param2.SetToolTip("Resistance when temperature is T0.") - self.label2.SetLabel("R0:") - self.param3.SetToolTip("Second data point, temperature at which " - "resistance is equal to R1.") - self.label3.SetLabel("T1:") - self.param4.SetToolTip("Resistance when temperature is T1.") - self.label4.SetLabel("R1:") - self.param5.SetToolTip("Third data point, temperature at which " - "resistance is equal to R2.") - self.label5.SetLabel("T2:") - self.param6.SetToolTip("Resistance when temperature is T2.") - self.label6.SetLabel("R2:") - self.param4.Enable(True) - self.param5.Enable(True) - self.param6.Enable(True) + for k in thermistorPresets.keys(): + if p == thermistorPresets[k]: + try: + i = self.thermistorChoices.index(k) + except: + i = 0 + self.chPresets.SetSelection(i) + return - self.label0.SetSize((labelWidth, -1)) - self.label0.SetWindowStyle(wx.ALIGN_RIGHT) - self.label1.SetSize((labelWidth, -1)) - self.label1.SetWindowStyle(wx.ALIGN_RIGHT) - self.label2.SetSize((labelWidth, -1)) - self.label2.SetWindowStyle(wx.ALIGN_RIGHT) - self.label3.SetSize((labelWidth, -1)) - self.label3.SetWindowStyle(wx.ALIGN_RIGHT) - self.label4.SetSize((labelWidth, -1)) - self.label4.SetWindowStyle(wx.ALIGN_RIGHT) - self.label5.SetSize((labelWidth, -1)) - self.label5.SetWindowStyle(wx.ALIGN_RIGHT) - self.label6.SetSize((labelWidth, -1)) - self.label6.SetWindowStyle(wx.ALIGN_RIGHT) + self.chPresets.SetSelection(0) - self.param0.Enable(True); - self.param1.Enable(True); - self.param2.Enable(True); - self.param3.Enable(True); - self.chPresets.Enable(True); - for rb in self.rbMethod: - rb.Enable(True) - else: - self.param0.SetToolTip(None) - self.label0.SetLabel("") - self.param0.SetBackgroundColour( - wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param0.Refresh() + def selectSensorType(self, lbl): + if lbl == "Thermistor" or lbl == "MCP3008": + self.currentMode = MODE_THERMISTOR + else: + self.currentMode = MODE_NONTHERM + self.setDialogMode() - self.param1.SetToolTip(None) - self.label1.SetLabel("") - self.param1.SetBackgroundColour( - wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param1.Refresh() + def setDialogMode(self): + if self.currentMode == MODE_THERMISTOR: + if self.currentMethod == METHOD_BETA: + self.param0.SetToolTip( + "Nominal resistance of the thermistor. " + "Typically 10000 ( = 10k) or 100000 " + "( = 100k)." + ) + self.label0.SetLabel("R0:") + self.param1.SetToolTip( + "Thermistor beta value. Can be found in " + "the datasheet or measured like described " + "in http://reprap.org/wiki/" + "MeasuringThermistorBeta" + ) + self.label1.SetLabel("Beta:") + self.param2.SetToolTip( + "Resistance value of the secondary " + "resistor. This is not a property of the " + "thermistor, but one of the board. " + "Typical values are 4700 ( = 4k7 ohms) " + "or 1000 ( = 1k ohms)." + ) + self.label2.SetLabel("R2:") + self.param3.SetToolTip( + "Comparison voltage used by the " + "controller. Usually the same as the " + "controller's supply voltage, 3.3 or 5.0 " + "(volts)." + ) + self.label3.SetLabel("Vadc:") + self.label4.SetLabel("") + self.param4.SetToolTip(None) + self.param4.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param4.Refresh() + self.label5.SetLabel("") + self.param5.SetToolTip(None) + self.param5.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param5.Refresh() + self.label6.SetLabel("") + self.param6.SetToolTip(None) + self.param6.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param6.Refresh() + self.param4.Enable(False) + self.param5.Enable(False) + self.param6.Enable(False) + else: + self.param0.SetToolTip("Reference resistance value.") + self.label0.SetLabel("Rp:") + self.param1.SetToolTip( + "First data point, temperature at which " + "resistance is equal to R0." + ) + self.label1.SetLabel("T0:") + self.param2.SetToolTip("Resistance when temperature is T0.") + self.label2.SetLabel("R0:") + self.param3.SetToolTip( + "Second data point, temperature at which " + "resistance is equal to R1." + ) + self.label3.SetLabel("T1:") + self.param4.SetToolTip("Resistance when temperature is T1.") + self.label4.SetLabel("R1:") + self.param5.SetToolTip( + "Third data point, temperature at which " + "resistance is equal to R2." + ) + self.label5.SetLabel("T2:") + self.param6.SetToolTip("Resistance when temperature is T2.") + self.label6.SetLabel("R2:") + self.param4.Enable(True) + self.param5.Enable(True) + self.param6.Enable(True) - self.param2.SetToolTip(None) - self.label2.SetLabel("") - self.param2.SetBackgroundColour( - wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param2.Refresh() + self.label0.SetSize((labelWidth, -1)) + self.label0.SetWindowStyle(wx.ALIGN_RIGHT) + self.label1.SetSize((labelWidth, -1)) + self.label1.SetWindowStyle(wx.ALIGN_RIGHT) + self.label2.SetSize((labelWidth, -1)) + self.label2.SetWindowStyle(wx.ALIGN_RIGHT) + self.label3.SetSize((labelWidth, -1)) + self.label3.SetWindowStyle(wx.ALIGN_RIGHT) + self.label4.SetSize((labelWidth, -1)) + self.label4.SetWindowStyle(wx.ALIGN_RIGHT) + self.label5.SetSize((labelWidth, -1)) + self.label5.SetWindowStyle(wx.ALIGN_RIGHT) + self.label6.SetSize((labelWidth, -1)) + self.label6.SetWindowStyle(wx.ALIGN_RIGHT) - self.param3.SetToolTip(None) - self.label3.SetLabel("") - self.param3.SetBackgroundColour( - wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param3.Refresh() + self.param0.Enable(True) + self.param1.Enable(True) + self.param2.Enable(True) + self.param3.Enable(True) + self.chPresets.Enable(True) + for rb in self.rbMethod: + rb.Enable(True) + else: + self.param0.SetToolTip(None) + self.label0.SetLabel("") + self.param0.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param0.Refresh() - self.param4.SetToolTip(None) - self.label4.SetLabel("") - self.param4.SetBackgroundColour( - wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param4.Refresh() + self.param1.SetToolTip(None) + self.label1.SetLabel("") + self.param1.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param1.Refresh() - self.param5.SetToolTip(None) - self.label5.SetLabel("") - self.param5.SetBackgroundColour( - wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param5.Refresh() + self.param2.SetToolTip(None) + self.label2.SetLabel("") + self.param2.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param2.Refresh() - self.param6.SetToolTip(None) - self.label6.SetLabel("") - self.param6.SetBackgroundColour( - wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - self.param6.Refresh() + self.param3.SetToolTip(None) + self.label3.SetLabel("") + self.param3.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param3.Refresh() - self.param0.Enable(False); - self.param1.Enable(False); - self.param2.Enable(False); - self.param3.Enable(False); - self.param4.Enable(False); - self.param5.Enable(False); - self.param6.Enable(False); - self.chPresets.Enable(False); - for rb in self.rbMethod: - rb.Enable(False) + self.param4.SetToolTip(None) + self.label4.SetLabel("") + self.param4.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param4.Refresh() - def onChoice(self, evt): - pass + self.param5.SetToolTip(None) + self.label5.SetLabel("") + self.param5.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param5.Refresh() - def onPresetChoice(self, evt): - ch = evt.GetEventObject() - s = ch.GetSelection() - label = ch.GetString(s) - if s != 0: - self.param0.SetValue(thermistorPresets[label][0]) - self.param1.SetValue(thermistorPresets[label][1]) - self.param2.SetValue(thermistorPresets[label][2]) - self.param3.SetValue(thermistorPresets[label][3]) - if len(thermistorPresets[label]) == 7: - self.param4.SetValue(thermistorPresets[label][4]) - self.param5.SetValue(thermistorPresets[label][5]) - self.param6.SetValue(thermistorPresets[label][6]) - self.currentMethod = METHOD_SH - else: - self.currentMethod = METHOD_BETA - self.rbMethod[self.currentMethod].SetValue(True) - self.setDialogMode() + self.param6.SetToolTip(None) + self.label6.SetLabel("") + self.param6.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + self.param6.Refresh() - self.validateFields() - evt.Skip() + self.param0.Enable(False) + self.param1.Enable(False) + self.param2.Enable(False) + self.param3.Enable(False) + self.param4.Enable(False) + self.param5.Enable(False) + self.param6.Enable(False) + self.chPresets.Enable(False) + for rb in self.rbMethod: + rb.Enable(False) - def onSensorType(self, evt): - ch = evt.GetEventObject() - s = ch.GetSelection() - label = ch.GetString(s) + def onChoice(self, evt): + pass - self.selectSensorType(label) - self.validateFields() - evt.Skip() + def onPresetChoice(self, evt): + ch = evt.GetEventObject() + s = ch.GetSelection() + label = ch.GetString(s) + if s != 0: + self.param0.SetValue(thermistorPresets[label][0]) + self.param1.SetValue(thermistorPresets[label][1]) + self.param2.SetValue(thermistorPresets[label][2]) + self.param3.SetValue(thermistorPresets[label][3]) + if len(thermistorPresets[label]) == 7: + self.param4.SetValue(thermistorPresets[label][4]) + self.param5.SetValue(thermistorPresets[label][5]) + self.param6.SetValue(thermistorPresets[label][6]) + self.currentMethod = METHOD_SH + else: + self.currentMethod = METHOD_BETA + self.rbMethod[self.currentMethod].SetValue(True) + self.setDialogMode() - def validateFields(self): - self.onParam0Entry(None) - self.onParam1Entry(None) - self.onParam2Entry(None) - self.onParam3Entry(None) - self.onParam4Entry(None) - self.onParam5Entry(None) - self.onParam6Entry(None) + self.validateFields() + evt.Skip() - def getValues(self): - nm = self.tcName.GetString(self.tcName.GetSelection()) - pin = self.choices[self.chPin.GetSelection()] - stype = self.chType.GetString(self.chType.GetSelection()) - if self.currentMode == MODE_THERMISTOR: - if self.currentMethod == METHOD_BETA: - addtl = [str(self.param0.GetValue().strip()), - str(self.param1.GetValue().strip()), - str(self.param2.GetValue().strip()), - str(self.param3.GetValue().strip())] - else: - addtl = [str(self.param0.GetValue().strip()), - str(self.param1.GetValue().strip()), - str(self.param2.GetValue().strip()), - str(self.param3.GetValue().strip()), - str(self.param4.GetValue().strip()), - str(self.param5.GetValue().strip()), - str(self.param6.GetValue().strip())] - else: - addtl = None + def onSensorType(self, evt): + ch = evt.GetEventObject() + s = ch.GetSelection() + label = ch.GetString(s) - return (nm, sensorTypes[stype], pin, addtl) + self.selectSensorType(label) + self.validateFields() + evt.Skip() - def onSave(self, evt): - self.EndModal(wx.ID_OK) + def validateFields(self): + self.onParam0Entry(None) + self.onParam1Entry(None) + self.onParam2Entry(None) + self.onParam3Entry(None) + self.onParam4Entry(None) + self.onParam5Entry(None) + self.onParam6Entry(None) - def onCancel(self, evt): - self.EndModal(wx.ID_CANCEL) + def getValues(self): + nm = self.tcName.GetString(self.tcName.GetSelection()) + pin = self.choices[self.chPin.GetSelection()] + stype = self.chType.GetString(self.chType.GetSelection()) + if self.currentMode == MODE_THERMISTOR: + if self.currentMethod == METHOD_BETA: + addtl = [ + str(self.param0.GetValue().strip()), + str(self.param1.GetValue().strip()), + str(self.param2.GetValue().strip()), + str(self.param3.GetValue().strip()), + ] + else: + addtl = [ + str(self.param0.GetValue().strip()), + str(self.param1.GetValue().strip()), + str(self.param2.GetValue().strip()), + str(self.param3.GetValue().strip()), + str(self.param4.GetValue().strip()), + str(self.param5.GetValue().strip()), + str(self.param6.GetValue().strip()), + ] + else: + addtl = None + + return (nm, sensorTypes[stype], pin, addtl) + + def onSave(self, evt): + self.EndModal(wx.ID_OK) + + def onCancel(self, evt): + self.EndModal(wx.ID_CANCEL) diff --git a/configtool/board.py b/configtool/board.py index ba3266b..25ba6cf 100644 --- a/configtool/board.py +++ b/configtool/board.py @@ -4,488 +4,534 @@ import os import re from sys import platform -from configtool.data import (defineValueFormat, - defineBoolFormat, defineHeaterFormat, - reHelpTextStart, reHelpTextEnd, - reStartSensors, reEndSensors, reStartHeaters, - reEndHeaters, reCandHeatPins, reCandThermPins, - reCandProcessors, reCandCPUClocks, reFloatAttr, - reDefine, reDefineBL, reDefQS, reDefQSm, - reDefQSm2, reDefBool, reDefBoolBL, reDefHT, - reDefTS, reDefTT, reSensor, reHeater3, reHeater4, - reHeater5, reTempTable4, reTempTable7) +from configtool.data import ( + defineValueFormat, + defineBoolFormat, + defineHeaterFormat, + reHelpTextStart, + reHelpTextEnd, + reStartSensors, + reEndSensors, + reStartHeaters, + reEndHeaters, + reCandHeatPins, + reCandThermPins, + reCandProcessors, + reCandCPUClocks, + reFloatAttr, + reDefine, + reDefineBL, + reDefQS, + reDefQSm, + reDefQSm2, + reDefBool, + reDefBoolBL, + reDefHT, + reDefTS, + reDefTT, + reSensor, + reHeater3, + reHeater4, + reHeater5, + reTempTable4, + reTempTable7, +) + class Board: - def __init__(self, settings): - self.settings = settings - self.configFile = None - self.cfgDir = os.path.join(self.settings.folder, "configtool") + def __init__(self, settings): + self.settings = settings + self.configFile = None + self.cfgDir = os.path.join(self.settings.folder, "configtool") - self.cfgValues = {} - self.heaters = [] - self.sensors = [] - self.candHeatPins = [] - self.candThermPins = [] + self.cfgValues = {} + self.heaters = [] + self.sensors = [] + self.candHeatPins = [] + self.candThermPins = [] - def getValues(self): - vars = [("sensor." + x[0], x[1:]) for x in self.sensors] - vars += [("heater." + x[0], x[1:]) for x in self.heaters] - vars += [(x, self.cfgValues[x]) for x in self.cfgValues] - return dict(vars) + def getValues(self): + vars = [("sensor." + x[0], x[1:]) for x in self.sensors] + vars += [("heater." + x[0], x[1:]) for x in self.heaters] + vars += [(x, self.cfgValues[x]) for x in self.cfgValues] + return dict(vars) - def getCPUInfo(self): - vF_CPU = None - if 'F_CPU' in self.cfgValues.keys(): - vF_CPU = self.cfgValues['F_CPU'][0] + def getCPUInfo(self): + vF_CPU = None + if "F_CPU" in self.cfgValues.keys(): + vF_CPU = self.cfgValues["F_CPU"][0] - vCPU = None - if 'CPU' in self.cfgValues.keys(): - vCPU = self.cfgValues['CPU'][0] + vCPU = None + if "CPU" in self.cfgValues.keys(): + vCPU = self.cfgValues["CPU"][0] - return vF_CPU, vCPU + return vF_CPU, vCPU - def hasData(self): - return (self.configFile != None) + def hasData(self): + return self.configFile != None - def getFileName(self): - return self.configFile + def getFileName(self): + return self.configFile - def loadConfigFile(self, fn): - cfgFn = os.path.join(self.cfgDir, "board.generic.h") - try: - self.cfgBuffer = list(open(cfgFn)) - except: - return False, cfgFn + def loadConfigFile(self, fn): + cfgFn = os.path.join(self.cfgDir, "board.generic.h") + try: + self.cfgBuffer = list(open(cfgFn)) + except: + return False, cfgFn - try: - self.userBuffer = list(open(fn)) - except: - return False, fn + try: + self.userBuffer = list(open(fn)) + except: + return False, fn - self.configFile = fn + self.configFile = fn - self.sensors = [] - self.heaters = [] - self.candHeatPins = [] - self.candThermPins = [] - self.candProcessors = [] - self.candClocks = [] - self.tempTables = {} - gatheringHelpText = False - helpTextString = "" - helpKey = None + self.sensors = [] + self.heaters = [] + self.candHeatPins = [] + self.candThermPins = [] + self.candProcessors = [] + self.candClocks = [] + self.tempTables = {} + gatheringHelpText = False + helpTextString = "" + helpKey = None - self.cfgValues = {} - self.cfgNames = [] - self.helpText = {} + self.cfgValues = {} + self.cfgNames = [] + self.helpText = {} - prevLines = "" - for ln in self.cfgBuffer: - if gatheringHelpText: - if reHelpTextEnd.match(ln): - gatheringHelpText = False - helpTextString = helpTextString.strip() - # Keep paragraphs with double-newline. - helpTextString = helpTextString.replace("\n\n ", "\n\n") - # Keep indented lines, typically a list. - helpTextString = helpTextString.replace("\n\n ", "\n\n ") - helpTextString = helpTextString.replace("\n ", "\n\n ") - # Remove all other newlines and indents. - helpTextString = helpTextString.replace("\n ", " ") - hk = helpKey.split() - for k in hk: - self.helpText[k] = helpTextString - helpTextString = "" - helpKey = None - continue - else: - helpTextString += ln - continue - - m = reHelpTextStart.match(ln) - if m: - t = m.groups() - gatheringHelpText = True - helpKey = t[0] - continue - - if ln.rstrip().endswith("\\"): - prevLines += ln.rstrip()[:-1] - continue - - if prevLines != "": - ln = prevLines + ln prevLines = "" + for ln in self.cfgBuffer: + if gatheringHelpText: + if reHelpTextEnd.match(ln): + gatheringHelpText = False + helpTextString = helpTextString.strip() + # Keep paragraphs with double-newline. + helpTextString = helpTextString.replace("\n\n ", "\n\n") + # Keep indented lines, typically a list. + helpTextString = helpTextString.replace("\n\n ", "\n\n ") + helpTextString = helpTextString.replace("\n ", "\n\n ") + # Remove all other newlines and indents. + helpTextString = helpTextString.replace("\n ", " ") + hk = helpKey.split() + for k in hk: + self.helpText[k] = helpTextString + helpTextString = "" + helpKey = None + continue + else: + helpTextString += ln + continue - self.parseDefineName(ln) - self.parseDefineValue(ln) + m = reHelpTextStart.match(ln) + if m: + t = m.groups() + gatheringHelpText = True + helpKey = t[0] + continue - # Set all boolean generic configuration items to False, so items not yet - # existing in the user configuration default to disabled. - # - # An alternative would be to allow both, enabled and disabled booleans - # in board.generic.h, which then allows to set an appropriate default for - # each #define. This was tried but conflicted with config file writing code - # below (disabled #defines were reset to the default, even when set - # differently in the GUI), so this would need adjustment, too. - for k in self.cfgValues.keys(): - if isinstance(self.cfgValues[k], bool): - self.cfgValues[k] = False + if ln.rstrip().endswith("\\"): + prevLines += ln.rstrip()[:-1] + continue - # Read the user configuration. This usually overwrites all of the items - # read above, but not those missing in the user configuration, e.g. - # when reading an older config. - gatheringHelpText = False - prevLines = "" - for ln in self.userBuffer: - if gatheringHelpText: - if reHelpTextEnd.match(ln): - gatheringHelpText = False - continue + if prevLines != "": + ln = prevLines + ln + prevLines = "" - if reHelpTextStart.match(ln): - gatheringHelpText = True - continue + self.parseDefineName(ln) + self.parseDefineValue(ln) - if ln.rstrip().endswith("\\"): - prevLines += ln.rstrip()[:-1] - continue + # Set all boolean generic configuration items to False, so items not yet + # existing in the user configuration default to disabled. + # + # An alternative would be to allow both, enabled and disabled booleans + # in board.generic.h, which then allows to set an appropriate default for + # each #define. This was tried but conflicted with config file writing code + # below (disabled #defines were reset to the default, even when set + # differently in the GUI), so this would need adjustment, too. + for k in self.cfgValues.keys(): + if isinstance(self.cfgValues[k], bool): + self.cfgValues[k] = False - if prevLines != "": - ln = prevLines + ln + # Read the user configuration. This usually overwrites all of the items + # read above, but not those missing in the user configuration, e.g. + # when reading an older config. + gatheringHelpText = False prevLines = "" + for ln in self.userBuffer: + if gatheringHelpText: + if reHelpTextEnd.match(ln): + gatheringHelpText = False + continue - if self.parseCandidateValues(ln): - continue + if reHelpTextStart.match(ln): + gatheringHelpText = True + continue - if self.parseDefineValue(ln): - continue + if ln.rstrip().endswith("\\"): + prevLines += ln.rstrip()[:-1] + continue - m = reDefTS.search(ln) - if m: - t = m.groups() - if len(t) == 1: - s = self.parseSensor(t[0]) - if s: - self.sensors.append(s) - continue + if prevLines != "": + ln = prevLines + ln + prevLines = "" - m = reDefHT.search(ln) - if m: - t = m.groups() - if len(t) == 1: - s = self.parseHeater(t[0]) - if s: - self.heaters.append(s) - continue + if self.parseCandidateValues(ln): + continue - # Parsing done. All parsed stuff is now in these arrays and dicts. - if self.settings.verbose >= 2: - print(self.sensors) - print(self.heaters) - print(self.candHeatPins) - print(self.candThermPins) - print(self.candProcessors) - print(self.candClocks) - print(self.tempTables) - print(self.cfgValues) # #defines with a value. - print(self.cfgNames) # Names found in the generic file. - if self.settings.verbose >= 3: - print(self.helpText) + if self.parseDefineValue(ln): + continue - for k in range(len(self.sensors)): - tn = self.sensors[k][0].upper() - if tn in self.tempTables.keys(): - self.sensors[k][3] = self.tempTables[tn] - else: - self.sensors[k][3] = None + m = reDefTS.search(ln) + if m: + t = m.groups() + if len(t) == 1: + s = self.parseSensor(t[0]) + if s: + self.sensors.append(s) + continue - return True, None + m = reDefHT.search(ln) + if m: + t = m.groups() + if len(t) == 1: + s = self.parseHeater(t[0]) + if s: + self.heaters.append(s) + continue - def parseDefineName(self, ln): - m = reDefBool.search(ln) - if m: - t = m.groups() - if len(t) == 1: - self.cfgNames.append(t[0]) - return True + # Parsing done. All parsed stuff is now in these arrays and dicts. + if self.settings.verbose >= 2: + print(self.sensors) + print(self.heaters) + print(self.candHeatPins) + print(self.candThermPins) + print(self.candProcessors) + print(self.candClocks) + print(self.tempTables) + print(self.cfgValues) # #defines with a value. + print(self.cfgNames) # Names found in the generic file. + if self.settings.verbose >= 3: + print(self.helpText) - return False - - def parseDefineValue(self, ln): - m = reDefQS.search(ln) - if m: - t = m.groups() - if len(t) == 2: - m = reDefQSm.search(ln) - if m: - t = m.groups() - tt = re.findall(reDefQSm2, t[1]) - if len(tt) == 1 and (t[0] in self.cfgNames): - self.cfgValues[t[0]] = tt[0], True - return True - elif len(tt) > 1 and (t[0] in self.cfgNames): - self.cfgValues[t[0]] = tt, True - return True - - m = reDefine.search(ln) - if m: - t = m.groups() - if len(t) == 2 and (t[0] in self.cfgNames): - if reDefineBL.search(ln): - self.cfgValues[t[0]] = t[1], True - else: - self.cfgValues[t[0]] = t[1], False - return True - - m = reDefBool.search(ln) - if m: - t = m.groups() - # Accept booleans, but not those for which a value exists already. - # Booleans already existing as values are most likely misconfigured - # manual edits (or result of a bug). - if len(t) == 1 and t[0] in self.cfgNames \ - and not (t[0] in self.cfgValues \ - and isinstance(self.cfgValues[t[0]], tuple)): - if reDefBoolBL.search(ln): - self.cfgValues[t[0]] = True - else: - self.cfgValues[t[0]] = False - return True - - return False - - def parseCandidateValues(self, ln): - m = reCandThermPins.match(ln) - if m: - t = m.groups() - if len(t) == 1: - self.candThermPins.append(t[0]) - return True - - m = reCandHeatPins.match(ln) - if m: - t = m.groups() - if len(t) == 1: - self.candHeatPins.append(t[0]) - return True - - m = reCandProcessors.match(ln) - if m: - t = m.groups() - if len(t) == 1: - self.candProcessors.append(t[0]) - return True - - m = reCandCPUClocks.match(ln) - if m: - t = m.groups() - if len(t) == 1: - self.candClocks.append(t[0]) - return True - - m = reDefTT.match(ln) - if m: - t = m.groups() - if len(t) == 2: - s = self.parseTempTable(t[1]) - if s: - self.tempTables[t[0]] = s - return True - - return False - - def parseSensor(self, s): - m = reSensor.search(s) - if m: - t = m.groups() - if len(t) == 4: - return list(t) - return None - - def parseHeater(self, s): - m = reHeater5.search(s) - if m: - t = m.groups() - if len(t) == 5: - return list(t) - # reHeater4 deprecated, for compatibility with old config files only. - m = reHeater4.search(s) - if m: - t = m.groups() - if len(t) == 4: - t = list(t) - t.insert(5, '100') - return t - # reHeater3 deprecated, for compatibility with old config files only. - m = reHeater3.search(s) - if m: - t = m.groups() - if len(t) == 3: - t = list(t) - t.insert(2, '0') - t.insert(5, '100') - return t - # End of deprecated part. - return None - - def parseTempTable(self, s): - m = reTempTable4.search(s) - if m: - t = m.groups() - if len(t) == 4: - return list(t) - m = reTempTable7.search(s) - if m: - t = m.groups() - if len(t) == 7: - return list(t) - return None - - def saveConfigFile(self, path, values): - if not values: - values = self.cfgValues - - if self.settings.verbose >= 1: - print("Saving board: %s." % path) - if self.settings.verbose >= 2: - print(values) - - fp = file(path, 'w') - self.configFile = path - - skipToSensorEnd = False - skipToHeaterEnd = False - candThermPinsWritten = False - candHeatPinsWritten = False - candProcessorsWritten = False - candCPUClocksWritten = False - - for ln in self.cfgBuffer: - m = reStartSensors.match(ln) - if m: - fp.write(ln) - fp.write("// name type pin " - "additional\n"); - ttString = "\n" - ttString += "// Beta algorithm r0 beta r2 vadc\n" - ttString += "// Steinhart-Hart rp t0 r0 t1 " - ttString += "r1 t2 r2\n" - for s in self.sensors: - sstr = "%-10s%-15s%-7s" % ((s[0] + ","), (s[1] + ","), (s[2] + ",")) - if s[3] is None: - sstr += "0" - else: - sstr += "THERMISTOR_%s" % s[0].upper() - tt = s[3] - if len(tt) == 4: - ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-6s%s)\n" % \ - (s[0].upper(), (tt[0] + ","), (tt[1] + ","), - (tt[2] + ","), tt[3]) + for k in range(len(self.sensors)): + tn = self.sensors[k][0].upper() + if tn in self.tempTables.keys(): + self.sensors[k][3] = self.tempTables[tn] else: - ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-8s%-6s%-8s%-6s%s)\n" % \ - (s[0].upper(), (tt[0] + ","), (tt[1] + ","), - (tt[2] + ","), (tt[3] + ","), (tt[4] + ","), - (tt[5] + ","), tt[6]) - fp.write("DEFINE_TEMP_SENSOR(%s)\n" % sstr) - fp.write(ttString) - skipToSensorEnd = True - continue + self.sensors[k][3] = None - if skipToSensorEnd: - m = reEndSensors.match(ln) + return True, None + + def parseDefineName(self, ln): + m = reDefBool.search(ln) if m: - fp.write(ln) - skipToSensorEnd = False - continue + t = m.groups() + if len(t) == 1: + self.cfgNames.append(t[0]) + return True - m = reStartHeaters.match(ln) - if m: - fp.write(ln) - fp.write("// name pin invert pwm max_pwm\n") - for s in self.heaters: - sstr = "%-10s%-9s%-8s%-7s%s" % ((s[0] + ","), (s[1] + ","), - (s[2] + ","), s[3] + ",", s[4]) - fp.write("DEFINE_HEATER(%s)\n" % sstr) - fp.write("\n") - for s in self.heaters: - fp.write(defineHeaterFormat % (s[0].upper(), s[0])) - skipToHeaterEnd = True - continue + return False - if skipToHeaterEnd: - m = reEndHeaters.match(ln) + def parseDefineValue(self, ln): + m = reDefQS.search(ln) if m: - fp.write(ln) - skipToHeaterEnd = False - continue + t = m.groups() + if len(t) == 2: + m = reDefQSm.search(ln) + if m: + t = m.groups() + tt = re.findall(reDefQSm2, t[1]) + if len(tt) == 1 and (t[0] in self.cfgNames): + self.cfgValues[t[0]] = tt[0], True + return True + elif len(tt) > 1 and (t[0] in self.cfgNames): + self.cfgValues[t[0]] = tt, True + return True - if reCandThermPins.match(ln): - if not candThermPinsWritten: - for pin in self.candThermPins: - fp.write("//#define TEMP_SENSOR_PIN " + pin + "\n") - candThermPinsWritten = True - continue + m = reDefine.search(ln) + if m: + t = m.groups() + if len(t) == 2 and (t[0] in self.cfgNames): + if reDefineBL.search(ln): + self.cfgValues[t[0]] = t[1], True + else: + self.cfgValues[t[0]] = t[1], False + return True - if reCandHeatPins.match(ln): - if not candHeatPinsWritten: - for pin in self.candHeatPins: - fp.write("//#define HEATER_PIN " + pin + "\n") - candHeatPinsWritten = True - continue + m = reDefBool.search(ln) + if m: + t = m.groups() + # Accept booleans, but not those for which a value exists already. + # Booleans already existing as values are most likely misconfigured + # manual edits (or result of a bug). + if ( + len(t) == 1 + and t[0] in self.cfgNames + and not ( + t[0] in self.cfgValues and isinstance(self.cfgValues[t[0]], tuple) + ) + ): + if reDefBoolBL.search(ln): + self.cfgValues[t[0]] = True + else: + self.cfgValues[t[0]] = False + return True - if reCandProcessors.match(ln): - if not candProcessorsWritten: - for pin in self.candProcessors: - fp.write("//#define CPU_TYPE " + pin + "\n") - candProcessorsWritten = True - continue + return False - if reCandCPUClocks.match(ln): - if not candCPUClocksWritten: - for pin in self.candClocks: - fp.write("//#define F_CPU_OPT " + pin + "\n") - candCPUClocksWritten = True - continue + def parseCandidateValues(self, ln): + m = reCandThermPins.match(ln) + if m: + t = m.groups() + if len(t) == 1: + self.candThermPins.append(t[0]) + return True + + m = reCandHeatPins.match(ln) + if m: + t = m.groups() + if len(t) == 1: + self.candHeatPins.append(t[0]) + return True + + m = reCandProcessors.match(ln) + if m: + t = m.groups() + if len(t) == 1: + self.candProcessors.append(t[0]) + return True + + m = reCandCPUClocks.match(ln) + if m: + t = m.groups() + if len(t) == 1: + self.candClocks.append(t[0]) + return True + + m = reDefTT.match(ln) + if m: + t = m.groups() + if len(t) == 2: + s = self.parseTempTable(t[1]) + if s: + self.tempTables[t[0]] = s + return True + + return False + + def parseSensor(self, s): + m = reSensor.search(s) + if m: + t = m.groups() + if len(t) == 4: + return list(t) + return None + + def parseHeater(self, s): + m = reHeater5.search(s) + if m: + t = m.groups() + if len(t) == 5: + return list(t) + # reHeater4 deprecated, for compatibility with old config files only. + m = reHeater4.search(s) + if m: + t = m.groups() + if len(t) == 4: + t = list(t) + t.insert(5, "100") + return t + # reHeater3 deprecated, for compatibility with old config files only. + m = reHeater3.search(s) + if m: + t = m.groups() + if len(t) == 3: + t = list(t) + t.insert(2, "0") + t.insert(5, "100") + return t + # End of deprecated part. + return None + + def parseTempTable(self, s): + m = reTempTable4.search(s) + if m: + t = m.groups() + if len(t) == 4: + return list(t) + m = reTempTable7.search(s) + if m: + t = m.groups() + if len(t) == 7: + return list(t) + return None + + def saveConfigFile(self, path, values): + if not values: + values = self.cfgValues + + if self.settings.verbose >= 1: + print("Saving board: %s." % path) + if self.settings.verbose >= 2: + print(values) + + fp = file(path, "w") + self.configFile = path + + skipToSensorEnd = False + skipToHeaterEnd = False + candThermPinsWritten = False + candHeatPinsWritten = False + candProcessorsWritten = False + candCPUClocksWritten = False + + for ln in self.cfgBuffer: + m = reStartSensors.match(ln) + if m: + fp.write(ln) + fp.write( + "// name type pin " "additional\n" + ) + ttString = "\n" + ttString += "// Beta algorithm r0 beta r2 vadc\n" + ttString += "// Steinhart-Hart rp t0 r0 t1 " + ttString += "r1 t2 r2\n" + for s in self.sensors: + sstr = "%-10s%-15s%-7s" % ((s[0] + ","), (s[1] + ","), (s[2] + ",")) + if s[3] is None: + sstr += "0" + else: + sstr += "THERMISTOR_%s" % s[0].upper() + tt = s[3] + if len(tt) == 4: + ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-6s%s)\n" % ( + s[0].upper(), + (tt[0] + ","), + (tt[1] + ","), + (tt[2] + ","), + tt[3], + ) + else: + ttString += ( + "//TEMP_TABLE %-8s (%-8s%-6s%-8s%-6s%-8s%-6s%s)\n" + % ( + s[0].upper(), + (tt[0] + ","), + (tt[1] + ","), + (tt[2] + ","), + (tt[3] + ","), + (tt[4] + ","), + (tt[5] + ","), + tt[6], + ) + ) + fp.write("DEFINE_TEMP_SENSOR(%s)\n" % sstr) + fp.write(ttString) + skipToSensorEnd = True + continue + + if skipToSensorEnd: + m = reEndSensors.match(ln) + if m: + fp.write(ln) + skipToSensorEnd = False + continue + + m = reStartHeaters.match(ln) + if m: + fp.write(ln) + fp.write("// name pin invert pwm max_pwm\n") + for s in self.heaters: + sstr = "%-10s%-9s%-8s%-7s%s" % ( + (s[0] + ","), + (s[1] + ","), + (s[2] + ","), + s[3] + ",", + s[4], + ) + fp.write("DEFINE_HEATER(%s)\n" % sstr) + fp.write("\n") + for s in self.heaters: + fp.write(defineHeaterFormat % (s[0].upper(), s[0])) + skipToHeaterEnd = True + continue + + if skipToHeaterEnd: + m = reEndHeaters.match(ln) + if m: + fp.write(ln) + skipToHeaterEnd = False + continue + + if reCandThermPins.match(ln): + if not candThermPinsWritten: + for pin in self.candThermPins: + fp.write("//#define TEMP_SENSOR_PIN " + pin + "\n") + candThermPinsWritten = True + continue + + if reCandHeatPins.match(ln): + if not candHeatPinsWritten: + for pin in self.candHeatPins: + fp.write("//#define HEATER_PIN " + pin + "\n") + candHeatPinsWritten = True + continue + + if reCandProcessors.match(ln): + if not candProcessorsWritten: + for pin in self.candProcessors: + fp.write("//#define CPU_TYPE " + pin + "\n") + candProcessorsWritten = True + continue + + if reCandCPUClocks.match(ln): + if not candCPUClocksWritten: + for pin in self.candClocks: + fp.write("//#define F_CPU_OPT " + pin + "\n") + candCPUClocksWritten = True + continue + + m = reDefine.match(ln) + if m: + t = m.groups() + if len(t) == 2 and t[0] in values.keys(): + v = values[t[0]] + self.cfgValues[t[0]] = v + if v[1] == False: + fp.write("//") + fp.write(defineValueFormat % (t[0], v[0])) + else: + if t[0] == "RX_ENABLE_PIN" or t[0] == "TX_ENABLE_PIN": + # Known to be absent in the GUI, also won't be added anytime soon. + fp.write(ln) + else: + print("Value key " + t[0] + " not found in GUI.") + + continue + + m = reDefBoolBL.match(ln) + if m: + t = m.groups() + if len(t) == 1 and t[0] in values.keys(): + v = values[t[0]] + self.cfgValues[t[0]] = v + if v == "" or v == False: + fp.write("//") + fp.write(defineBoolFormat % t[0]) + else: + if t[0] == "MOTHERBOARD": + # Known to be absent in the GUI, also won't be added anytime soon. + fp.write(ln) + else: + print("Boolean key " + t[0] + " not found in GUI.") + + continue - m = reDefine.match(ln) - if m: - t = m.groups() - if len(t) == 2 and t[0] in values.keys(): - v = values[t[0]] - self.cfgValues[t[0]] = v - if v[1] == False: - fp.write("//") - fp.write(defineValueFormat % (t[0], v[0])) - else: - if t[0] == 'RX_ENABLE_PIN' or t[0] == 'TX_ENABLE_PIN': - # Known to be absent in the GUI, also won't be added anytime soon. fp.write(ln) - else: - print("Value key " + t[0] + " not found in GUI.") - continue + fp.close() - m = reDefBoolBL.match(ln) - if m: - t = m.groups() - if len(t) == 1 and t[0] in values.keys(): - v = values[t[0]] - self.cfgValues[t[0]] = v - if v == "" or v == False: - fp.write("//") - fp.write(defineBoolFormat % t[0]) - else: - if t[0] == 'MOTHERBOARD': - # Known to be absent in the GUI, also won't be added anytime soon. - fp.write(ln) - else: - print("Boolean key " + t[0] + " not found in GUI.") - - continue - - fp.write(ln) - - fp.close() - - return True + return True diff --git a/configtool/boardpanel.py b/configtool/boardpanel.py index 2eaa47d..e30a7f2 100644 --- a/configtool/boardpanel.py +++ b/configtool/boardpanel.py @@ -1,20 +1,40 @@ - import os import wx import re from sys import platform from configtool.decoration import Decoration -from configtool.data import (defineValueFormat, - defineBoolFormat, defineHeaterFormat, - reHelpTextStart, reHelpTextEnd, - reStartSensors, reEndSensors, reStartHeaters, - reEndHeaters, reCandHeatPins, reCandThermPins, - reCandProcessors, reCandCPUClocks, reFloatAttr, - reDefine, reDefineBL, reDefQS, reDefQSm, - reDefQSm2, reDefBool, reDefBoolBL, reDefHT, - reDefTS, reDefTT, reSensor, reHeater3, reHeater4, - reTempTable4, reTempTable7) +from configtool.data import ( + defineValueFormat, + defineBoolFormat, + defineHeaterFormat, + reHelpTextStart, + reHelpTextEnd, + reStartSensors, + reEndSensors, + reStartHeaters, + reEndHeaters, + reCandHeatPins, + reCandThermPins, + reCandProcessors, + reCandCPUClocks, + reFloatAttr, + reDefine, + reDefineBL, + reDefQS, + reDefQSm, + reDefQSm2, + reDefBool, + reDefBoolBL, + reDefHT, + reDefTS, + reDefTT, + reSensor, + reHeater3, + reHeater4, + reTempTable4, + reTempTable7, +) from configtool.pinoutspage import PinoutsPage from configtool.displaypage import DisplayPage from configtool.sensorpage import SensorsPage @@ -26,269 +46,302 @@ from configtool.thermistortablefile import generateTempTables from configtool.board import Board + class BoardPanel(wx.Panel): - def __init__(self, parent, nb, settings): - wx.Panel.__init__(self, nb, wx.ID_ANY) - self.parent = parent + def __init__(self, parent, nb, settings): + wx.Panel.__init__(self, nb, wx.ID_ANY) + self.parent = parent - self.deco = Decoration() - self.protFileLoaded = False + self.deco = Decoration() + self.protFileLoaded = False - self.settings = settings + self.settings = settings - self.board = Board(self.settings) + self.board = Board(self.settings) - self.dir = os.path.join(self.settings.folder, "config") + self.dir = os.path.join(self.settings.folder, "config") - self.SetBackgroundColour(self.deco.getBackgroundColour()) - self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground) - sz = wx.BoxSizer(wx.HORIZONTAL) + self.SetBackgroundColour(self.deco.getBackgroundColour()) + self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground) + sz = wx.BoxSizer(wx.HORIZONTAL) - self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21), - style = wx.BK_DEFAULT) - self.nb.SetBackgroundColour(self.deco.getBackgroundColour()) - self.nb.SetFont(self.settings.font) + self.nb = wx.Notebook(self, wx.ID_ANY, size=(21, 21), style=wx.BK_DEFAULT) + self.nb.SetBackgroundColour(self.deco.getBackgroundColour()) + self.nb.SetFont(self.settings.font) - self.pages = [] - self.titles = [] - self.pageModified = [] - self.pageValid = [] + self.pages = [] + self.titles = [] + self.pageModified = [] + self.pageValid = [] - self.pgCpu = self.registerPage(CpuPage, "CPU") - self.pgPins = self.registerPage(PinoutsPage, "Pinouts") - self.pgDisplay = self.registerPage(DisplayPage, "Display") - self.pgHeaters = self.registerPage(HeatersPage, "Heaters") - self.pgSensors = self.registerPage(SensorsPage, "Temperature Sensors", - heatersPage = self.pgHeaters) - self.pgCommunications = self.registerPage(CommunicationsPage, - "Communications") + self.pgCpu = self.registerPage(CpuPage, "CPU") + self.pgPins = self.registerPage(PinoutsPage, "Pinouts") + self.pgDisplay = self.registerPage(DisplayPage, "Display") + self.pgHeaters = self.registerPage(HeatersPage, "Heaters") + self.pgSensors = self.registerPage( + SensorsPage, "Temperature Sensors", heatersPage=self.pgHeaters + ) + self.pgCommunications = self.registerPage(CommunicationsPage, "Communications") - sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5) + sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5) - self.SetSizer(sz) - self.Fit() + self.SetSizer(sz) + self.Fit() - def registerPage(self, klass, label, *args, **kwargs): - page = klass(self, self.nb, len(self.pages), *args, - font = self.settings.font, **kwargs) - self.nb.AddPage(page, label) - self.pages.append(page) - self.titles.append(label) - self.pageModified.append(False) - self.pageValid.append(True) - return page + def registerPage(self, klass, label, *args, **kwargs): + page = klass( + self, self.nb, len(self.pages), *args, font=self.settings.font, **kwargs + ) + self.nb.AddPage(page, label) + self.pages.append(page) + self.titles.append(label) + self.pageModified.append(False) + self.pageValid.append(True) + return page - def getCPUInfo(self): - return self.board.getCPUInfo() + def getCPUInfo(self): + return self.board.getCPUInfo() - def assertModified(self, pg, flag = True): - self.pageModified[pg] = flag - self.modifyTab(pg) + def assertModified(self, pg, flag=True): + self.pageModified[pg] = flag + self.modifyTab(pg) - def isModified(self): - return (True in self.pageModified) + def isModified(self): + return True in self.pageModified - def isValid(self): - return not (False in self.pageValid) + def isValid(self): + return not (False in self.pageValid) - def hasData(self): - return self.board.hasData() + def hasData(self): + return self.board.hasData() - def getFileName(self): - return self.board.getFileName() + def getFileName(self): + return self.board.getFileName() - def assertValid(self, pg, flag = True): - self.pageValid[pg] = flag - self.modifyTab(pg) + def assertValid(self, pg, flag=True): + self.pageValid[pg] = flag + self.modifyTab(pg) - if False in self.pageValid: - self.parent.enableSaveBoard(False, False) - else: - self.parent.enableSaveBoard(not self.protFileLoaded, True) + if False in self.pageValid: + self.parent.enableSaveBoard(False, False) + else: + self.parent.enableSaveBoard(not self.protFileLoaded, True) - def modifyTab(self, pg): - if self.pageModified[pg] and not self.pageValid[pg]: - pfx = "?* " - elif self.pageModified[pg]: - pfx = "* " - elif not self.pageValid[pg]: - pfx = "? " - else: - pfx = "" + def modifyTab(self, pg): + if self.pageModified[pg] and not self.pageValid[pg]: + pfx = "?* " + elif self.pageModified[pg]: + pfx = "* " + elif not self.pageValid[pg]: + pfx = "? " + else: + pfx = "" - self.nb.SetPageText(pg, pfx + self.titles[pg]) - if True in self.pageModified and False in self.pageValid: - pfx = "?* " - elif True in self.pageModified: - pfx = "* " - elif False in self.pageValid: - pfx = "? " - else: - pfx = "" - self.parent.setBoardTabDecor(pfx) + self.nb.SetPageText(pg, pfx + self.titles[pg]) + if True in self.pageModified and False in self.pageValid: + pfx = "?* " + elif True in self.pageModified: + pfx = "* " + elif False in self.pageValid: + pfx = "? " + else: + pfx = "" + self.parent.setBoardTabDecor(pfx) - def setHeaters(self, ht): - self.parent.setHeaters(ht) + def setHeaters(self, ht): + self.parent.setHeaters(ht) - def onClose(self, evt): - if not self.confirmLoseChanges("exit"): - return + def onClose(self, evt): + if not self.confirmLoseChanges("exit"): + return - self.Destroy() + self.Destroy() - def confirmLoseChanges(self, msg): - if True not in self.pageModified: - return True + def confirmLoseChanges(self, msg): + if True not in self.pageModified: + return True - dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n" - "There are changes to your board " - "configuration that will be lost.", - "Changes pending", - wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION) - rc = dlg.ShowModal() - dlg.Destroy() + dlg = wx.MessageDialog( + self, + "Are you sure you want to " + msg + "?\n" + "There are changes to your board " + "configuration 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 + if rc != wx.ID_YES: + return False - return True + return True - def onLoadConfig(self, evt): - if not self.confirmLoseChanges("load a new board configuration"): - return + def onLoadConfig(self, evt): + if not self.confirmLoseChanges("load a new board configuration"): + return - if platform.startswith("darwin"): - # Mac OS X appears to be a bit limited on wildcards. - wildcard = "Board configuration (board.*.h)|*.h" - else: - wildcard = "Board configuration (board.*.h)|board.*.h" + if platform.startswith("darwin"): + # Mac OS X appears to be a bit limited on wildcards. + wildcard = "Board configuration (board.*.h)|*.h" + else: + wildcard = "Board configuration (board.*.h)|board.*.h" - dlg = wx.FileDialog(self, message = "Choose a board config file", - defaultDir = self.dir, defaultFile = "", - wildcard = wildcard, style = wx.FD_OPEN | wx.FD_CHANGE_DIR) + dlg = wx.FileDialog( + self, + message="Choose a board config file", + defaultDir=self.dir, + defaultFile="", + wildcard=wildcard, + style=wx.FD_OPEN | wx.FD_CHANGE_DIR, + ) - path = None - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() + path = None + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() - dlg.Destroy() - if path is None: - return + dlg.Destroy() + if path is None: + return - self.dir = os.path.dirname(path) - rc, efn = self.loadConfigFile(path) + self.dir = os.path.dirname(path) + rc, efn = self.loadConfigFile(path) - if not rc: - dlg = wx.MessageDialog(self, "Unable to process file %s." % efn, - "File error", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return + if not rc: + dlg = wx.MessageDialog( + self, + "Unable to process file %s." % efn, + "File error", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return - def loadConfigFile(self, fn): - ok, file = self.board.loadConfigFile(fn) - if not ok: - return ok, file + def loadConfigFile(self, fn): + ok, file = self.board.loadConfigFile(fn) + if not ok: + return ok, file - if os.path.basename(fn) in protectedFiles: - self.parent.enableSaveBoard(False, True) - self.protFileLoaded = True - else: - self.protFileLoaded = False - self.parent.enableSaveBoard(True, True) + if os.path.basename(fn) in protectedFiles: + self.parent.enableSaveBoard(False, True) + self.protFileLoaded = True + else: + self.protFileLoaded = False + self.parent.enableSaveBoard(True, True) - self.parent.setBoardTabFile(os.path.basename(fn)) - self.pgHeaters.setCandidatePins(self.board.candHeatPins) - self.pgSensors.setCandidatePins(self.board.candThermPins) - self.pgCpu.setCandidateProcessors(self.board.candProcessors) - self.pgCpu.setCandidateClocks(self.board.candClocks) + self.parent.setBoardTabFile(os.path.basename(fn)) + self.pgHeaters.setCandidatePins(self.board.candHeatPins) + self.pgSensors.setCandidatePins(self.board.candThermPins) + self.pgCpu.setCandidateProcessors(self.board.candProcessors) + self.pgCpu.setCandidateClocks(self.board.candClocks) - for pg in self.pages: - pg.insertValues(self.board.cfgValues) - pg.setHelpText(self.board.helpText) + for pg in self.pages: + pg.insertValues(self.board.cfgValues) + pg.setHelpText(self.board.helpText) - self.pgSensors.setSensors(self.board.sensors) - self.pgHeaters.setHeaters(self.board.heaters) + self.pgSensors.setSensors(self.board.sensors) + self.pgHeaters.setHeaters(self.board.heaters) - return True, None + return True, None - def onSaveConfig(self, evt): - path = self.getFileName() - return self.saveConfigFile(path) + def onSaveConfig(self, evt): + path = self.getFileName() + return self.saveConfigFile(path) - def onSaveConfigAs(self, evt): - if platform.startswith("darwin"): - # Mac OS X appears to be a bit limited on wildcards. - wildcard = "Board configuration (board.*.h)|*.h" - else: - wildcard = "Board configuration (board.*.h)|board.*.h" + def onSaveConfigAs(self, evt): + if platform.startswith("darwin"): + # Mac OS X appears to be a bit limited on wildcards. + wildcard = "Board configuration (board.*.h)|*.h" + else: + wildcard = "Board configuration (board.*.h)|board.*.h" - dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir, - defaultFile = "", wildcard = wildcard, - style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) + dlg = wx.FileDialog( + self, + message="Save as ...", + defaultDir=self.dir, + defaultFile="", + wildcard=wildcard, + style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, + ) - val = dlg.ShowModal() + val = dlg.ShowModal() - if val != wx.ID_OK: - dlg.Destroy() - return + if val != wx.ID_OK: + dlg.Destroy() + return - path = dlg.GetPath() - dlg.Destroy() + path = dlg.GetPath() + dlg.Destroy() - rc = self.saveConfigFile(path) - if rc: - self.parent.setBoardTabFile(os.path.basename(path)) - self.protFileLoaded = False - self.parent.enableSaveBoard(True, True) - return rc + rc = self.saveConfigFile(path) + if rc: + self.parent.setBoardTabFile(os.path.basename(path)) + self.protFileLoaded = False + self.parent.enableSaveBoard(True, True) + return rc - def saveConfigFile(self, path): - if os.path.basename(path) in protectedFiles: - dlg = wx.MessageDialog(self, "It's not allowed to overwrite files " - "distributed by Teacup. Choose another name.", - "Protected file error", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False + def saveConfigFile(self, path): + if os.path.basename(path) in protectedFiles: + dlg = wx.MessageDialog( + self, + "It's not allowed to overwrite files " + "distributed by Teacup. Choose another name.", + "Protected file error", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return False - if not os.path.basename(path).startswith("board."): - dlg = wx.MessageDialog(self, "Illegal file name: %s.\n" - "File name must begin with \"board.\"" % path, - "Illegal file name", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False + if not os.path.basename(path).startswith("board."): + dlg = wx.MessageDialog( + self, + "Illegal file name: %s.\n" 'File name must begin with "board."' % path, + "Illegal file name", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return False - values = {} - for pg in self.pages: - v1 = pg.getValues() - for k in v1.keys(): - values[k] = v1[k] + values = {} + for pg in self.pages: + v1 = pg.getValues() + for k in v1.keys(): + values[k] = v1[k] - ext = os.path.splitext(os.path.basename(path))[1] - self.dir = os.path.dirname(path) + ext = os.path.splitext(os.path.basename(path))[1] + self.dir = os.path.dirname(path) - if ext == "": - path += ".h" + if ext == "": + path += ".h" - try: - self.board.saveConfigFile(path, values) - except: - dlg = wx.MessageDialog(self, "Unable to write to file %s." % path, - "File error", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False + try: + self.board.saveConfigFile(path, values) + except: + dlg = wx.MessageDialog( + self, + "Unable to write to file %s." % path, + "File error", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return False - return self.generateTempTables() + return self.generateTempTables() - def generateTempTables(self): - if not generateTempTables(self.board.sensors, self.settings): - dlg = wx.MessageDialog(self, "Error writing to file thermistortable.h.", - "File error", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False + def generateTempTables(self): + if not generateTempTables(self.board.sensors, self.settings): + dlg = wx.MessageDialog( + self, + "Error writing to file thermistortable.h.", + "File error", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return False - return True + return True diff --git a/configtool/build.py b/configtool/build.py index 601a201..f2092a5 100644 --- a/configtool/build.py +++ b/configtool/build.py @@ -1,4 +1,3 @@ - import wx.lib.newevent import thread, shlex, subprocess import os, re @@ -6,7 +5,7 @@ from os.path import isfile, join from sys import platform if platform.startswith("win"): - from _subprocess import STARTF_USESHOWWINDOW + from _subprocess import STARTF_USESHOWWINDOW (scriptEvent, EVT_SCRIPT_UPDATE) = wx.lib.newevent.NewEvent() SCRIPT_RUNNING = 1 @@ -14,447 +13,495 @@ SCRIPT_FINISHED = 2 SCRIPT_CANCELLED = 3 TOOLPATHS_INSIDE_ARDUINO = [ - "hardware/tools/avr/bin/", - "hardware/tools/" # avrdude in Arduino 1.0.x -] + "hardware/tools/avr/bin/", + "hardware/tools/", +] # avrdude in Arduino 1.0.x if platform.startswith("darwin"): - # That's an OS property, the Applicaton Bundle hierarchy. - pathsCopy = TOOLPATHS_INSIDE_ARDUINO - TOOLPATHS_INSIDE_ARDUINO = [] - for path in pathsCopy: - TOOLPATHS_INSIDE_ARDUINO.append("Contents/Resources/Java/" + path) - TOOLPATHS_INSIDE_ARDUINO.append("Contents/Java/" + path) + # That's an OS property, the Applicaton Bundle hierarchy. + pathsCopy = TOOLPATHS_INSIDE_ARDUINO + TOOLPATHS_INSIDE_ARDUINO = [] + for path in pathsCopy: + TOOLPATHS_INSIDE_ARDUINO.append("Contents/Resources/Java/" + path) + TOOLPATHS_INSIDE_ARDUINO.append("Contents/Java/" + path) class ScriptTools: - def __init__(self, settings): - self.settings = settings + def __init__(self, settings): + self.settings = settings - def figureCommandPath(self, baseCommand): - findConf = False - if baseCommand == "avrdude": - findConf = True + def figureCommandPath(self, baseCommand): + findConf = False + if baseCommand == "avrdude": + findConf = True - if platform.startswith("win"): - baseCommand += ".exe" + if platform.startswith("win"): + baseCommand += ".exe" - if self.settings.arduinodir: - cmdpath = self.settings.arduinodir + if self.settings.arduinodir: + cmdpath = self.settings.arduinodir - for pathOption in TOOLPATHS_INSIDE_ARDUINO: - cmdpathTry = cmdpath - for dir in pathOption.split("/"): - cmdpathTry = os.path.join(cmdpathTry, dir) - cmdpathTry = os.path.join(cmdpathTry, baseCommand) - if os.path.exists(cmdpathTry): - cmdpath = "\"" + cmdpathTry + "\"" - break + for pathOption in TOOLPATHS_INSIDE_ARDUINO: + cmdpathTry = cmdpath + for dir in pathOption.split("/"): + cmdpathTry = os.path.join(cmdpathTry, dir) + cmdpathTry = os.path.join(cmdpathTry, baseCommand) + if os.path.exists(cmdpathTry): + cmdpath = '"' + cmdpathTry + '"' + break - if findConf: - confpath = cmdpath.strip("\"") - exepos = confpath.rfind(".exe") - if exepos >= 0: - confpath = confpath[0:exepos] - confpath += ".conf" - if not os.path.exists(confpath): - confpath = os.path.split(confpath)[0] - confpath = os.path.split(confpath)[0] - confpath = os.path.join(confpath, "etc") - confpath = os.path.join(confpath, "avrdude.conf") - if os.path.exists(confpath): - cmdpath += " -C \"" + confpath + "\"" + if findConf: + confpath = cmdpath.strip('"') + exepos = confpath.rfind(".exe") + if exepos >= 0: + confpath = confpath[0:exepos] + confpath += ".conf" + if not os.path.exists(confpath): + confpath = os.path.split(confpath)[0] + confpath = os.path.split(confpath)[0] + confpath = os.path.join(confpath, "etc") + confpath = os.path.join(confpath, "avrdude.conf") + if os.path.exists(confpath): + cmdpath += ' -C "' + confpath + '"' - else: - cmdpath = baseCommand - # No need to search avrdude.conf in this case. + else: + cmdpath = baseCommand + # No need to search avrdude.conf in this case. - return cmdpath + return cmdpath class ScriptThread: - def __init__(self, win, script): - self.win = win - self.running = False - self.cancelled = False - self.script = script + def __init__(self, win, script): + self.win = win + self.running = False + self.cancelled = False + self.script = script - def Start(self): - self.running = True - self.cancelled = False - thread.start_new_thread(self.Run, ()) + def Start(self): + self.running = True + self.cancelled = False + thread.start_new_thread(self.Run, ()) - def Stop(self): - self.cancelled = True + def Stop(self): + self.cancelled = True - def IsRunning(self): - return self.running + def IsRunning(self): + return self.running - def Run(self): - if platform.startswith("win"): - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= STARTF_USESHOWWINDOW - - for cmd in self.script: - evt = scriptEvent(msg = cmd, state = SCRIPT_RUNNING) - wx.PostEvent(self.win, evt) - args = shlex.split(str(cmd)) - try: + def Run(self): if platform.startswith("win"): - p = subprocess.Popen(args, stderr = subprocess.STDOUT, - stdout = subprocess.PIPE, - startupinfo = startupinfo) - else: - p = subprocess.Popen(args, stderr = subprocess.STDOUT, - stdout = subprocess.PIPE) - except: - evt = scriptEvent(msg = "Exception occurred trying to run\n\n%s" % cmd, - state = SCRIPT_CANCELLED) - wx.PostEvent(self.win, evt) - self.running = False - return - obuf = '' - while not self.cancelled: - o = p.stdout.read(1) - if o == '': break - if o == '\r' or o == '\n': - if obuf.strip() != "": - evt = scriptEvent(msg = obuf, state = SCRIPT_RUNNING) + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= STARTF_USESHOWWINDOW + + for cmd in self.script: + evt = scriptEvent(msg=cmd, state=SCRIPT_RUNNING) wx.PostEvent(self.win, evt) - obuf = '' - elif ord(o) < 32: - pass - else: - obuf += o + args = shlex.split(str(cmd)) + try: + if platform.startswith("win"): + p = subprocess.Popen( + args, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + startupinfo=startupinfo, + ) + else: + p = subprocess.Popen( + args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE + ) + except: + evt = scriptEvent( + msg="Exception occurred trying to run\n\n%s" % cmd, + state=SCRIPT_CANCELLED, + ) + wx.PostEvent(self.win, evt) + self.running = False + return + obuf = "" + while not self.cancelled: + o = p.stdout.read(1) + if o == "": + break + if o == "\r" or o == "\n": + if obuf.strip() != "": + evt = scriptEvent(msg=obuf, state=SCRIPT_RUNNING) + wx.PostEvent(self.win, evt) + obuf = "" + elif ord(o) < 32: + pass + else: + obuf += o - if self.cancelled: - evt = scriptEvent(msg = None, state = SCRIPT_CANCELLED) + if self.cancelled: + evt = scriptEvent(msg=None, state=SCRIPT_CANCELLED) + wx.PostEvent(self.win, evt) + p.kill() + self.running = False + p.wait() + return + + rc = p.wait() + if rc != 0: + msg = "RC = " + str(rc) + " - Build terminated" + evt = scriptEvent(msg=msg, state=SCRIPT_CANCELLED) + wx.PostEvent(self.win, evt) + self.running = False + return + + evt = scriptEvent(msg="", state=SCRIPT_RUNNING) + wx.PostEvent(self.win, evt) + + evt = scriptEvent(msg=None, state=SCRIPT_FINISHED) wx.PostEvent(self.win, evt) - p.kill() + self.running = False - p.wait() - return - - rc = p.wait() - if rc != 0: - msg = "RC = " + str(rc) + " - Build terminated" - evt = scriptEvent(msg = msg, state = SCRIPT_CANCELLED) - wx.PostEvent(self.win, evt) - self.running = False - return - - evt = scriptEvent(msg = "", state = SCRIPT_RUNNING) - wx.PostEvent(self.win, evt) - - evt = scriptEvent(msg = None, state = SCRIPT_FINISHED) - wx.PostEvent(self.win, evt) - - self.running = False class Build(wx.Dialog): - def __init__(self, parent, settings, f_cpu, cpu): - wx.Dialog.__init__(self, parent, wx.ID_ANY, "Build teacup", - style = wx.RESIZE_BORDER + wx.DEFAULT_DIALOG_STYLE) - self.settings = settings - self.SetFont(self.settings.font) - self.root = self.settings.folder - self.f_cpu = f_cpu - self.cpu = cpu - self.Bind(wx.EVT_CLOSE, self.onExit) - self.cancelPending = False + def __init__(self, parent, settings, f_cpu, cpu): + wx.Dialog.__init__( + self, + parent, + wx.ID_ANY, + "Build teacup", + style=wx.RESIZE_BORDER + wx.DEFAULT_DIALOG_STYLE, + ) + self.settings = settings + self.SetFont(self.settings.font) + self.root = self.settings.folder + self.f_cpu = f_cpu + self.cpu = cpu + self.Bind(wx.EVT_CLOSE, self.onExit) + self.cancelPending = False - hsz = wx.BoxSizer(wx.HORIZONTAL) - hsz.Add((10, 10)) + hsz = wx.BoxSizer(wx.HORIZONTAL) + hsz.Add((10, 10)) - sz = wx.BoxSizer(wx.VERTICAL) - sz.Add((10, 10)) + sz = wx.BoxSizer(wx.VERTICAL) + sz.Add((10, 10)) - 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 + 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.Add((10, 10)) - hsz.Add(sz, 1, wx.EXPAND) - hsz.Add((10, 10)) + sz.Add((10, 10)) + hsz.Add(sz, 1, wx.EXPAND) + hsz.Add((10, 10)) - self.SetSizer(hsz) + self.SetSizer(hsz) - self.Fit() - builddir = join(self.root, "build") - if not os.path.exists(builddir): - os.makedirs(builddir) - self.log.AppendText("Directory %s created.\n\n" % builddir) + self.Fit() + builddir = join(self.root, "build") + if not os.path.exists(builddir): + os.makedirs(builddir) + self.log.AppendText("Directory %s created.\n\n" % builddir) - self.compile() + self.compile() - def compile(self): - self.generateCompileScript() - if len(self.script) == 0: - self.log.AppendText("Nothing to compile!\n") - self.active = False - else: - self.Bind(EVT_SCRIPT_UPDATE, self.compileUpdate) - self.t = ScriptThread(self, self.script) - self.active = True - self.t.Start() - - def link(self): - self.generateLinkScript() - if len(self.script) == 0: - self.log.AppendText("Nothing to link!\n") - self.active = False - else: - self.Bind(EVT_SCRIPT_UPDATE, self.linkUpdate) - t = ScriptThread(self, self.script) - self.active = True - t.Start() - - def report(self): - self.script = [] - self.reportLines = [] - cmdpath = ScriptTools(self.settings).figureCommandPath("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 = [] - cmdpath = ScriptTools(self.settings).figureCommandPath("avr-gcc") - - cfiles = [f for f in os.listdir(self.root) - if isfile(join(self.root,f)) and f.endswith(".c")] - for f in cfiles: - basename = f[:-2] - ofile = basename + ".o" - alfile = basename + ".al" - opath = "\"" + join(self.root, "build", ofile) + "\"" - alpath = "\"" + join(self.root, "build", alfile) + "\"" - cpath = "\"" + join(self.root, f) + "\"" - - opts = self.settings.cflags - opts = opts.replace("%ALNAME%", alpath) - opts = opts.replace("%F_CPU%", self.f_cpu) - opts = opts.replace("%CPU%", self.cpu) - - cmd = cmdpath + " -c " + opts + " -o " + opath + " " + cpath - self.script.append(cmd) - - def generateLinkScript(self): - self.script = [] - cmdpath = ScriptTools(self.settings).figureCommandPath("avr-gcc") - - # This is ugly: - # Work around a problem of avr-ld.exe coming with Arduino 1.6.4 for - # Windows. Without this it always drops this error message: - # collect2.exe: error: ld returned 5 exit status 255 - # Just enabling verbose messages allows ld.exe to complete without failure. - if platform.startswith("win"): - cmdpath += " -Wl,-V" - - ofiles = ["\"" + join(self.root, "build", f) + "\"" - for f in os.listdir(join(self.root, "build")) - 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) - opts = opts.replace("%CPU%", self.cpu) - cmd = cmdpath + " " + self.settings.ldflags + " " + opts + " -o " + \ - elfpath + " " + opath + " -lm" - self.script.append(cmd) - - cmdpath = ScriptTools(self.settings).figureCommandPath("avr-objcopy") - cmd = cmdpath + " " + self.settings.objcopyflags + " " + elfpath + \ - " " + hexpath - self.script.append(cmd) - - def compileUpdate(self, evt): - if evt.msg is not None: - self.log.AppendText(evt.msg + "\n") - - if evt.state == SCRIPT_RUNNING: - pass - - if evt.state == SCRIPT_CANCELLED: - self.active = False - - if self.cancelPending: - self.EndModal(wx.ID_OK) - - self.log.AppendText("Build terminated abnormally.\n") - - if evt.state == SCRIPT_FINISHED: - self.log.AppendText("Compile completed normally.\n\n") - self.link() - - def linkUpdate(self, evt): - if evt.msg is not None: - self.log.AppendText(evt.msg + "\n") - - if evt.state == SCRIPT_RUNNING: - pass - if evt.state == SCRIPT_CANCELLED: - self.log.AppendText("Link terminated abnormally.\n") - 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) + def compile(self): + self.generateCompileScript() + if len(self.script) == 0: + self.log.AppendText("Nothing to compile!\n") + self.active = False else: - m = reEEProm.search(l) - if m: - self.formatReportLine(m, "EEPROM", 1, 2, 2, 4) + self.Bind(EVT_SCRIPT_UPDATE, self.compileUpdate) + self.t = ScriptThread(self, self.script) + self.active = True + self.t.Start() - def onExit(self, evt): - if self.active: - dlg = wx.MessageDialog(self, "Are you sure you want to cancel building?", - "Build active", - wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION) - rc = dlg.ShowModal() - dlg.Destroy() + def link(self): + self.generateLinkScript() + if len(self.script) == 0: + self.log.AppendText("Nothing to link!\n") + self.active = False + else: + self.Bind(EVT_SCRIPT_UPDATE, self.linkUpdate) + t = ScriptThread(self, self.script) + self.active = True + t.Start() - if rc == wx.ID_YES: - self.cancelPending = True - self.log.AppendText("Cancelling...\n") - self.t.Stop() - return + def report(self): + self.script = [] + self.reportLines = [] + cmdpath = ScriptTools(self.settings).figureCommandPath("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() - self.EndModal(wx.ID_OK) + def generateCompileScript(self): + self.script = [] + cmdpath = ScriptTools(self.settings).figureCommandPath("avr-gcc") + + cfiles = [ + f + for f in os.listdir(self.root) + if isfile(join(self.root, f)) and f.endswith(".c") + ] + for f in cfiles: + basename = f[:-2] + ofile = basename + ".o" + alfile = basename + ".al" + opath = '"' + join(self.root, "build", ofile) + '"' + alpath = '"' + join(self.root, "build", alfile) + '"' + cpath = '"' + join(self.root, f) + '"' + + opts = self.settings.cflags + opts = opts.replace("%ALNAME%", alpath) + opts = opts.replace("%F_CPU%", self.f_cpu) + opts = opts.replace("%CPU%", self.cpu) + + cmd = cmdpath + " -c " + opts + " -o " + opath + " " + cpath + self.script.append(cmd) + + def generateLinkScript(self): + self.script = [] + cmdpath = ScriptTools(self.settings).figureCommandPath("avr-gcc") + + # This is ugly: + # Work around a problem of avr-ld.exe coming with Arduino 1.6.4 for + # Windows. Without this it always drops this error message: + # collect2.exe: error: ld returned 5 exit status 255 + # Just enabling verbose messages allows ld.exe to complete without failure. + if platform.startswith("win"): + cmdpath += " -Wl,-V" + + ofiles = [ + '"' + join(self.root, "build", f) + '"' + for f in os.listdir(join(self.root, "build")) + 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) + opts = opts.replace("%CPU%", self.cpu) + cmd = ( + cmdpath + + " " + + self.settings.ldflags + + " " + + opts + + " -o " + + elfpath + + " " + + opath + + " -lm" + ) + self.script.append(cmd) + + cmdpath = ScriptTools(self.settings).figureCommandPath("avr-objcopy") + cmd = cmdpath + " " + self.settings.objcopyflags + " " + elfpath + " " + hexpath + self.script.append(cmd) + + def compileUpdate(self, evt): + if evt.msg is not None: + self.log.AppendText(evt.msg + "\n") + + if evt.state == SCRIPT_RUNNING: + pass + + if evt.state == SCRIPT_CANCELLED: + self.active = False + + if self.cancelPending: + self.EndModal(wx.ID_OK) + + self.log.AppendText("Build terminated abnormally.\n") + + if evt.state == SCRIPT_FINISHED: + self.log.AppendText("Compile completed normally.\n\n") + self.link() + + def linkUpdate(self, evt): + if evt.msg is not None: + self.log.AppendText(evt.msg + "\n") + + if evt.state == SCRIPT_RUNNING: + pass + if evt.state == SCRIPT_CANCELLED: + self.log.AppendText("Link terminated abnormally.\n") + 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: + dlg = wx.MessageDialog( + self, + "Are you sure you want to cancel building?", + "Build active", + wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION, + ) + rc = dlg.ShowModal() + dlg.Destroy() + + if rc == wx.ID_YES: + self.cancelPending = True + self.log.AppendText("Cancelling...\n") + self.t.Stop() + return + + self.EndModal(wx.ID_OK) class Upload(wx.Dialog): - def __init__(self, parent, settings, f_cpu, cpu): - wx.Dialog.__init__(self, parent, wx.ID_ANY, "Upload teacup", - style = wx.RESIZE_BORDER + wx.DEFAULT_DIALOG_STYLE) - self.settings = settings - self.SetFont(self.settings.font) - self.root = self.settings.folder - self.f_cpu = f_cpu - self.cpu = cpu - self.baud = self.settings.uploadspeed - self.Bind(wx.EVT_CLOSE, self.onExit) - self.cancelPending = False + def __init__(self, parent, settings, f_cpu, cpu): + wx.Dialog.__init__( + self, + parent, + wx.ID_ANY, + "Upload teacup", + style=wx.RESIZE_BORDER + wx.DEFAULT_DIALOG_STYLE, + ) + self.settings = settings + self.SetFont(self.settings.font) + self.root = self.settings.folder + self.f_cpu = f_cpu + self.cpu = cpu + self.baud = self.settings.uploadspeed + self.Bind(wx.EVT_CLOSE, self.onExit) + self.cancelPending = False - hsz = wx.BoxSizer(wx.HORIZONTAL) - hsz.Add((10, 10)) + hsz = wx.BoxSizer(wx.HORIZONTAL) + hsz.Add((10, 10)) - sz = wx.BoxSizer(wx.VERTICAL) - sz.Add((10, 10)) + sz = wx.BoxSizer(wx.VERTICAL) + sz.Add((10, 10)) - 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 + 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.Add((10, 10)) - hsz.Add(sz, 1, wx.EXPAND) - hsz.Add((10, 10)) + sz.Add((10, 10)) + hsz.Add(sz, 1, wx.EXPAND) + hsz.Add((10, 10)) - self.SetSizer(hsz) + self.SetSizer(hsz) - self.Fit() - self.generateUploadScript() - if len(self.script) == 0: - self.log.AppendText("Nothing to upload!\n") - self.active = False - else: - self.Bind(EVT_SCRIPT_UPDATE, self.uploadUpdate) - self.t = ScriptThread(self, self.script) - self.active = True - self.t.Start() + self.Fit() + self.generateUploadScript() + if len(self.script) == 0: + self.log.AppendText("Nothing to upload!\n") + self.active = False + else: + self.Bind(EVT_SCRIPT_UPDATE, self.uploadUpdate) + self.t = ScriptThread(self, self.script) + self.active = True + self.t.Start() - def generateUploadScript(self): - self.script = [] - cmdpath = ScriptTools(self.settings).figureCommandPath("avrdude") - hexpath = "\"" + join(self.root, "teacup.hex") + "\"" + def generateUploadScript(self): + self.script = [] + cmdpath = ScriptTools(self.settings).figureCommandPath("avrdude") + hexpath = '"' + join(self.root, "teacup.hex") + '"' - cmd = cmdpath + " -c %s %s -b %s -p %s -P %s -U flash:w:%s:i" % \ - (self.settings.programmer, self.settings.programflags, self.baud, - self.cpu, self.settings.port, hexpath) - self.script.append(cmd) + cmd = cmdpath + " -c %s %s -b %s -p %s -P %s -U flash:w:%s:i" % ( + self.settings.programmer, + self.settings.programflags, + self.baud, + self.cpu, + self.settings.port, + hexpath, + ) + self.script.append(cmd) - def uploadUpdate(self, evt): - if evt.msg is not None: - self.log.AppendText(evt.msg + "\n") + def uploadUpdate(self, evt): + if evt.msg is not None: + self.log.AppendText(evt.msg + "\n") - if evt.state == SCRIPT_RUNNING: - pass + if evt.state == SCRIPT_RUNNING: + pass - if evt.state == SCRIPT_CANCELLED: - self.active = False + if evt.state == SCRIPT_CANCELLED: + self.active = False + + if self.cancelPending: + self.EndModal(wx.ID_OK) + + self.log.AppendText("Upload terminated abnormally.\n") + + if evt.state == SCRIPT_FINISHED: + self.log.AppendText("Upload completed normally.\n") + self.active = False + + def onExit(self, evt): + if self.active: + dlg = wx.MessageDialog( + self, + "Are you sure you want to cancel upload?", + "Upload active", + wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION, + ) + rc = dlg.ShowModal() + dlg.Destroy() + + if rc == wx.ID_YES: + self.cancelPending = True + self.log.AppendText("Cancelling...\n") + self.t.Stop() + return - if self.cancelPending: self.EndModal(wx.ID_OK) - - self.log.AppendText("Upload terminated abnormally.\n") - - if evt.state == SCRIPT_FINISHED: - self.log.AppendText("Upload completed normally.\n") - self.active = False - - def onExit(self, evt): - if self.active: - dlg = wx.MessageDialog(self, "Are you sure you want to cancel upload?", - "Upload active", - wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION) - rc = dlg.ShowModal() - dlg.Destroy() - - if rc == wx.ID_YES: - self.cancelPending = True - self.log.AppendText("Cancelling...\n") - self.t.Stop() - return - - self.EndModal(wx.ID_OK) diff --git a/configtool/calcbelt.py b/configtool/calcbelt.py index dba2692..b0bc4f4 100644 --- a/configtool/calcbelt.py +++ b/configtool/calcbelt.py @@ -1,296 +1,331 @@ - import wx -from configtool.data import (BSIZESMALL, reFloat, reInteger, offsetChLabel, - offsetTcLabel) +from configtool.data import BSIZESMALL, reFloat, reInteger, offsetChLabel, offsetTcLabel class CalcBelt(wx.Dialog): - def __init__(self, parent, font, cbUse): - wx.Dialog.__init__(self, parent, wx.ID_ANY, - "Steps calculator for belt driven axes", - size = (360, 300)) - self.SetFont(font) - self.Bind(wx.EVT_CLOSE, self.onExit) + def __init__(self, parent, font, cbUse): + wx.Dialog.__init__( + self, + parent, + wx.ID_ANY, + "Steps calculator for belt driven axes", + size=(360, 300), + ) + self.SetFont(font) + self.Bind(wx.EVT_CLOSE, self.onExit) - self.use = cbUse - labelWidth = 130 + self.use = cbUse + labelWidth = 130 - hsz = wx.BoxSizer(wx.HORIZONTAL) - hsz.Add((10, 10)) + hsz = wx.BoxSizer(wx.HORIZONTAL) + hsz.Add((10, 10)) - sz = wx.BoxSizer(wx.VERTICAL) - sz.Add((10, 10)) + sz = wx.BoxSizer(wx.VERTICAL) + sz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Step Angle:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Step Angle:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz.Add((5, 5)) - stepAngles = ["1.8 (200 per revolution)", "0.9 (400 per revolution)", - "7.5 (48 per revolution)"] - self.stepAngleValues = [200, 400, 48] - tc = wx.Choice(self, wx.ID_ANY, choices = stepAngles) - tc.SetFont(font) - tc.SetSelection(0) - tc.Bind(wx.EVT_CHOICE, self.onChoice) - lsz.Add(tc) - tc.SetToolTip("Step angle. Depends on your type of stepper motor.") - self.tcStep = tc + stepAngles = [ + "1.8 (200 per revolution)", + "0.9 (400 per revolution)", + "7.5 (48 per revolution)", + ] + self.stepAngleValues = [200, 400, 48] + tc = wx.Choice(self, wx.ID_ANY, choices=stepAngles) + tc.SetFont(font) + tc.SetSelection(0) + tc.Bind(wx.EVT_CHOICE, self.onChoice) + lsz.Add(tc) + tc.SetToolTip("Step angle. Depends on your type of stepper motor.") + self.tcStep = tc - sz.Add(lsz) - sz.Add((10, 10)) + sz.Add(lsz) + sz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Microstepping:", - size = (labelWidth, -1), style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, + wx.ID_ANY, + "Microstepping:", + size=(labelWidth, -1), + style=wx.ALIGN_RIGHT, + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz.Add((5, 5)) - microStepping = ["1 - full step", "1/2 - half step", "1/4 - quarter step", - "1/8", "1/16", "1/32", "1/64", "1/128"] - self.microSteppingValues = [1, 2, 4, 8, 16, 32, 64, 128] - tc = wx.Choice(self, wx.ID_ANY, choices = microStepping) - tc.SetFont(font) - tc.Bind(wx.EVT_CHOICE, self.onChoice) - tc.SetSelection(4) - lsz.Add(tc) - tc.SetToolTip("Microstepping. Most boards allow to change this by " - "setting jumpers. The value here must match the " - "setting on the board in conjunction with the type " - "of stepper driver chip.") - self.tcMicroStepping = tc + microStepping = [ + "1 - full step", + "1/2 - half step", + "1/4 - quarter step", + "1/8", + "1/16", + "1/32", + "1/64", + "1/128", + ] + self.microSteppingValues = [1, 2, 4, 8, 16, 32, 64, 128] + tc = wx.Choice(self, wx.ID_ANY, choices=microStepping) + tc.SetFont(font) + tc.Bind(wx.EVT_CHOICE, self.onChoice) + tc.SetSelection(4) + lsz.Add(tc) + tc.SetToolTip( + "Microstepping. Most boards allow to change this by " + "setting jumpers. The value here must match the " + "setting on the board in conjunction with the type " + "of stepper driver chip." + ) + self.tcMicroStepping = tc - sz.Add(lsz) - sz.Add((10, 10)) + sz.Add(lsz) + sz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Belt Pitch (in mm):", - size = (labelWidth, -1), style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, + wx.ID_ANY, + "Belt Pitch (in mm):", + size=(labelWidth, -1), + style=wx.ALIGN_RIGHT, + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + lsz.Add((5, 5)) - tc = wx.TextCtrl(self, wx.ID_ANY, "2", style = wx.TE_RIGHT) - tc.SetFont(font) - tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat) - lsz.Add(tc) - tc.SetToolTip("Belt pitch. Distance between two teeth on the belt.") - self.tcBeltPitch = tc + tc = wx.TextCtrl(self, wx.ID_ANY, "2", style=wx.TE_RIGHT) + tc.SetFont(font) + tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat) + lsz.Add(tc) + tc.SetToolTip("Belt pitch. Distance between two teeth on the belt.") + self.tcBeltPitch = tc - lsz.Add((5, 5)) + lsz.Add((5, 5)) - beltPresets = ["-", "2mm Pitch (GT2)", "MXL Pitch (2.03mm)", - "T2.5 (2.5mm)", "3mm Pitch (GT2, HTD)", - "5mm Pitch (T5, GTD, HTD)", "0.2\" XL belt (5.08mm)"] - self.beltPresetValues = [-1, 2.0, 2.03, 2.5, 3.0, 5.0, 5.08] - tc = wx.Choice(self, wx.ID_ANY, choices = beltPresets) - tc.SetFont(font) - tc.SetSelection(0) - tc.Bind(wx.EVT_CHOICE, self.onPresetChoice) - lsz.Add(tc) - tc.SetToolTip("Belt pitch presets.") - self.tcPresets = tc + beltPresets = [ + "-", + "2mm Pitch (GT2)", + "MXL Pitch (2.03mm)", + "T2.5 (2.5mm)", + "3mm Pitch (GT2, HTD)", + "5mm Pitch (T5, GTD, HTD)", + '0.2" XL belt (5.08mm)', + ] + self.beltPresetValues = [-1, 2.0, 2.03, 2.5, 3.0, 5.0, 5.08] + tc = wx.Choice(self, wx.ID_ANY, choices=beltPresets) + tc.SetFont(font) + tc.SetSelection(0) + tc.Bind(wx.EVT_CHOICE, self.onPresetChoice) + lsz.Add(tc) + tc.SetToolTip("Belt pitch presets.") + self.tcPresets = tc - sz.Add(lsz) - sz.Add((10, 10)) + sz.Add(lsz) + sz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Pulley Teeth Count:", - size = (labelWidth, -1), style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, + wx.ID_ANY, + "Pulley Teeth Count:", + size=(labelWidth, -1), + style=wx.ALIGN_RIGHT, + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + lsz.Add((5, 5)) - tc = wx.TextCtrl(self, wx.ID_ANY, "8", style = wx.TE_RIGHT) - tc.SetFont(font) - tc.Bind(wx.EVT_TEXT, self.onTextCtrlInteger) - lsz.Add(tc) - tc.SetToolTip("Pulley teeth count. Count them!") - self.tcPulleyTeeth = tc + tc = wx.TextCtrl(self, wx.ID_ANY, "8", style=wx.TE_RIGHT) + tc.SetFont(font) + tc.Bind(wx.EVT_TEXT, self.onTextCtrlInteger) + lsz.Add(tc) + tc.SetToolTip("Pulley teeth count. Count them!") + self.tcPulleyTeeth = tc - sz.Add(lsz) - sz.Add((30, 30)) + sz.Add(lsz) + sz.Add((30, 30)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Result:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Result:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st) + lsz.Add((5, 5)) - tc = wx.StaticText(self, wx.ID_ANY, "", size = (260, -1), - style = wx.ALIGN_LEFT) - tc.SetFont(font) - lsz.Add(tc) - self.tcResult = tc + tc = wx.StaticText(self, wx.ID_ANY, "", size=(260, -1), style=wx.ALIGN_LEFT) + tc.SetFont(font) + lsz.Add(tc) + self.tcResult = tc - sz.Add(lsz) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Resolution:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st) - lsz.Add((5, 5)) + sz.Add(lsz) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Resolution:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st) + lsz.Add((5, 5)) - tc = wx.StaticText(self, wx.ID_ANY, "", size = (260, -1), - style = wx.ALIGN_LEFT) - tc.SetFont(font) - lsz.Add(tc) - self.tcResolution = tc + tc = wx.StaticText(self, wx.ID_ANY, "", size=(260, -1), style=wx.ALIGN_LEFT) + tc.SetFont(font) + lsz.Add(tc) + self.tcResolution = tc - sz.Add(lsz) + sz.Add(lsz) - sz.Add((20, 20)) + sz.Add((20, 20)) - bsz = wx.BoxSizer(wx.HORIZONTAL) - b = wx.Button(self, wx.ID_ANY, "Use for X", size = BSIZESMALL) - b.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.onUseForX, b) - bsz.Add(b) - self.bUseForX = b - bsz.Add((5, 5)) + bsz = wx.BoxSizer(wx.HORIZONTAL) + b = wx.Button(self, wx.ID_ANY, "Use for X", size=BSIZESMALL) + b.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.onUseForX, b) + bsz.Add(b) + self.bUseForX = b + bsz.Add((5, 5)) - b = wx.Button(self, wx.ID_ANY, "Use for Y", size = BSIZESMALL) - b.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.onUseForY, b) - bsz.Add(b) - self.bUseForY = b - bsz.Add((5, 5)) + b = wx.Button(self, wx.ID_ANY, "Use for Y", size=BSIZESMALL) + b.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.onUseForY, b) + bsz.Add(b) + self.bUseForY = b + bsz.Add((5, 5)) - b = wx.Button(self, wx.ID_ANY, "Use for Z", size = BSIZESMALL) - b.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.onUseForZ, b) - bsz.Add(b) - self.bUseForZ = b - bsz.Add((5, 5)) + b = wx.Button(self, wx.ID_ANY, "Use for Z", size=BSIZESMALL) + b.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.onUseForZ, b) + bsz.Add(b) + self.bUseForZ = b + bsz.Add((5, 5)) - b = wx.Button(self, wx.ID_ANY, "Use for E", size = BSIZESMALL) - b.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.onUseForE, b) - bsz.Add(b) - self.bUseForE = b + b = wx.Button(self, wx.ID_ANY, "Use for E", size=BSIZESMALL) + b.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.onUseForE, b) + bsz.Add(b) + self.bUseForE = b - sz.Add(bsz) - sz.Add((10, 10)) + sz.Add(bsz) + sz.Add((10, 10)) - hsz.Add(sz) - hsz.Add((10, 10)) + hsz.Add(sz) + hsz.Add((10, 10)) - self.enableUseButtons(False) + self.enableUseButtons(False) - self.SetSizer(hsz) + self.SetSizer(hsz) - self.Fit() + self.Fit() - self.calculate() + self.calculate() + def calculate(self): + self.tcResult.SetLabel("") + self.tcResolution.SetLabel("") + self.enableUseButtons(False) + s = self.tcStep.GetSelection() + sv = self.stepAngleValues[s] - def calculate(self): - self.tcResult.SetLabel("") - self.tcResolution.SetLabel("") - self.enableUseButtons(False) - s = self.tcStep.GetSelection() - sv = self.stepAngleValues[s] + try: + bp = float(self.tcBeltPitch.GetValue()) + except: + return - try: - bp = float(self.tcBeltPitch.GetValue()) - except: - return + try: + pt = int(self.tcPulleyTeeth.GetValue()) + except: + return - try: - pt = int(self.tcPulleyTeeth.GetValue()) - except: - return + s = self.tcMicroStepping.GetSelection() + msv = self.microSteppingValues[s] - s = self.tcMicroStepping.GetSelection() - msv = self.microSteppingValues[s] + length = pt * bp + steps = sv * msv - length = pt * bp - steps = sv * msv + resultmm = steps / length + self.result = int(resultmm * 1000.0) - resultmm = steps / length - self.result = int(resultmm * 1000.0) + self.tcResult.SetLabel("%d steps/m (%.3f steps/mm)" % (self.result, resultmm)) + self.tcResolution.SetLabel("%.3f micrometers" % (length / steps * 1000.0)) + self.enableUseButtons(True) - self.tcResult.SetLabel("%d steps/m (%.3f steps/mm)" % - (self.result, resultmm)) - self.tcResolution.SetLabel("%.3f micrometers" % (length / steps * 1000.0)) - self.enableUseButtons(True) + def enableUseButtons(self, flag): + self.bUseForX.Enable(flag) + self.bUseForY.Enable(flag) + self.bUseForZ.Enable(flag) + self.bUseForE.Enable(flag) - def enableUseButtons(self, flag): - self.bUseForX.Enable(flag) - self.bUseForY.Enable(flag) - self.bUseForZ.Enable(flag) - self.bUseForE.Enable(flag) + def onUseForX(self, evt): + self.use("STEPS_PER_M_X", self.result) - def onUseForX(self, evt): - self.use('STEPS_PER_M_X', self.result) + def onUseForY(self, evt): + self.use("STEPS_PER_M_Y", self.result) - def onUseForY(self, evt): - self.use('STEPS_PER_M_Y', self.result) + def onUseForZ(self, evt): + self.use("STEPS_PER_M_Z", self.result) - def onUseForZ(self, evt): - self.use('STEPS_PER_M_Z', self.result) + def onUseForE(self, evt): + self.use("STEPS_PER_M_E", self.result) - def onUseForE(self, evt): - self.use('STEPS_PER_M_E', self.result) + def onPresetChoice(self, evt): + s = self.tcPresets.GetSelection() + sv = self.beltPresetValues[s] + if sv < 0: + return - def onPresetChoice(self, evt): - s = self.tcPresets.GetSelection() - sv = self.beltPresetValues[s] - if sv < 0: - return + s = "%f" % sv + s = s.rstrip("0") + if s[-1] == ".": + s += "0" + self.tcBeltPitch.SetValue(s) - s = "%f" % sv - s = s.rstrip("0") - if s[-1] == ".": - s += "0" - self.tcBeltPitch.SetValue(s) + def onChoice(self, evt): + self.calculate() - def onChoice(self, evt): - self.calculate() + def onTextCtrlInteger(self, evt): + tc = evt.GetEventObject() + w = tc.GetValue().strip() + if w == "": + valid = False + else: + m = reInteger.match(w) + if m: + valid = True + else: + valid = False - def onTextCtrlInteger(self, evt): - tc = evt.GetEventObject() - w = tc.GetValue().strip() - if w == "": - valid = False - else: - m = reInteger.match(w) - if m: - valid = True - else: - valid = False + if valid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() + self.calculate() + evt.Skip() - if valid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() - self.calculate() - evt.Skip() + def onTextCtrlFloat(self, evt): + tc = evt.GetEventObject() + w = tc.GetValue().strip() + if w == "": + valid = False + else: + m = reFloat.match(w) + if m: + valid = True + else: + valid = False - def onTextCtrlFloat(self, evt): - tc = evt.GetEventObject() - w = tc.GetValue().strip() - if w == "": - valid = False - else: - m = reFloat.match(w) - if m: - valid = True - else: - valid = False + if valid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() + self.calculate() + evt.Skip() - if valid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() - self.calculate() - evt.Skip() - - def onExit(self, evt): - self.EndModal(wx.ID_OK) + def onExit(self, evt): + self.EndModal(wx.ID_OK) diff --git a/configtool/calcscrew.py b/configtool/calcscrew.py index 84de198..6dd175e 100644 --- a/configtool/calcscrew.py +++ b/configtool/calcscrew.py @@ -1,296 +1,339 @@ - import wx from configtool.data import BSIZESMALL, reFloat, offsetChLabel, offsetTcLabel class CalcScrew(wx.Dialog): - def __init__(self, parent, font, cbUse): - wx.Dialog.__init__(self, parent, wx.ID_ANY, - "Steps calculator for screw driven axes", - size = (400, 204)) - self.SetFont(font) - self.Bind(wx.EVT_CLOSE, self.onExit) + def __init__(self, parent, font, cbUse): + wx.Dialog.__init__( + self, + parent, + wx.ID_ANY, + "Steps calculator for screw driven axes", + size=(400, 204), + ) + self.SetFont(font) + self.Bind(wx.EVT_CLOSE, self.onExit) - self.use = cbUse - labelWidth = 150 + self.use = cbUse + labelWidth = 150 - hsz = wx.BoxSizer(wx.HORIZONTAL) - hsz.Add((10, 10)) + hsz = wx.BoxSizer(wx.HORIZONTAL) + hsz.Add((10, 10)) - sz = wx.BoxSizer(wx.VERTICAL) - sz.Add((10, 10)) + sz = wx.BoxSizer(wx.VERTICAL) + sz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Step Angle:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Step Angle:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz.Add((5, 5)) - stepAngles = ["1.8 (200 per revolution)", "0.9 (400 per revolution)", - "7.5 (48 per revolution)"] - self.stepAngleValues = [200, 400, 48] - tc = wx.Choice(self, wx.ID_ANY, choices = stepAngles) - tc.SetFont(font) - tc.SetSelection(0) - tc.Bind(wx.EVT_CHOICE, self.onChoice) - lsz.Add(tc) - tc.SetToolTip("Step angle. Depends on your type of stepper motor.") - self.tcStep = tc + stepAngles = [ + "1.8 (200 per revolution)", + "0.9 (400 per revolution)", + "7.5 (48 per revolution)", + ] + self.stepAngleValues = [200, 400, 48] + tc = wx.Choice(self, wx.ID_ANY, choices=stepAngles) + tc.SetFont(font) + tc.SetSelection(0) + tc.Bind(wx.EVT_CHOICE, self.onChoice) + lsz.Add(tc) + tc.SetToolTip("Step angle. Depends on your type of stepper motor.") + self.tcStep = tc - sz.Add(lsz) - sz.Add((10, 10)) + sz.Add(lsz) + sz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Microstepping:", - size = (labelWidth, -1), style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetChLabel) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, + wx.ID_ANY, + "Microstepping:", + size=(labelWidth, -1), + style=wx.ALIGN_RIGHT, + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetChLabel) + lsz.Add((5, 5)) - microStepping = ["1 - full step", "1/2 - half step", "1/4 - quarter step", - "1/8", "1/16", "1/32", "1/64", "1/128"] - self.microSteppingValues = [1, 2, 4, 8, 16, 32, 64, 128] - tc = wx.Choice(self, wx.ID_ANY, choices = microStepping) - tc.SetFont(font) - tc.Bind(wx.EVT_CHOICE, self.onChoice) - tc.SetSelection(4) - lsz.Add(tc) - tc.SetToolTip("Microstepping. Most boards allow to change this by " - "setting jumpers. The value here must match the " - "setting on the board in conjunction with the type " - "of stepper driver chip.") - self.tcMicroStepping = tc + microStepping = [ + "1 - full step", + "1/2 - half step", + "1/4 - quarter step", + "1/8", + "1/16", + "1/32", + "1/64", + "1/128", + ] + self.microSteppingValues = [1, 2, 4, 8, 16, 32, 64, 128] + tc = wx.Choice(self, wx.ID_ANY, choices=microStepping) + tc.SetFont(font) + tc.Bind(wx.EVT_CHOICE, self.onChoice) + tc.SetSelection(4) + lsz.Add(tc) + tc.SetToolTip( + "Microstepping. Most boards allow to change this by " + "setting jumpers. The value here must match the " + "setting on the board in conjunction with the type " + "of stepper driver chip." + ) + self.tcMicroStepping = tc - sz.Add(lsz) - sz.Add((10, 10)) + sz.Add(lsz) + sz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Screw Pitch (mm/rev):", - size = (labelWidth, -1), style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, + wx.ID_ANY, + "Screw Pitch (mm/rev):", + size=(labelWidth, -1), + style=wx.ALIGN_RIGHT, + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + lsz.Add((5, 5)) - tc = wx.TextCtrl(self, wx.ID_ANY, "2", style = wx.TE_RIGHT) - tc.SetFont(font) - tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat) - lsz.Add(tc) - tc.SetToolTip("Screw pitch. Defined by the pitch of the screw.") - self.tcScrewPitch = tc + tc = wx.TextCtrl(self, wx.ID_ANY, "2", style=wx.TE_RIGHT) + tc.SetFont(font) + tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat) + lsz.Add(tc) + tc.SetToolTip("Screw pitch. Defined by the pitch of the screw.") + self.tcScrewPitch = tc - lsz.Add((5, 5)) + lsz.Add((5, 5)) - screwPresets = ["-", "M8 - metric (1.25 mm/rev)", "M6 - metric (1 mm/rev)", - "M5 - metric (0.8 mm/rev)", "12 (12 mm/rev)", - "16 (16 mm/rev)", "25 (25 mm/rev)", - "5/15\"-18 imperial coarse (1.41111 mm/rev)", - "3/16\"-20 imperial (1.270 mm/rev)", - "1/4\"-16 ACME (1.5875 mm/rev)"] - self.screwPresetValues = [-1, 1.25, 1.00, 0.8, 12.0, 16.0, 25.0, 1.41111, - 1.270, 1.5875] - tc = wx.Choice(self, wx.ID_ANY, choices = screwPresets) - tc.SetFont(font) - tc.SetSelection(0) - tc.Bind(wx.EVT_CHOICE, self.onPresetChoice) - lsz.Add(tc) - tc.SetToolTip("Screw pitch presets.") - self.tcPresets = tc + screwPresets = [ + "-", + "M8 - metric (1.25 mm/rev)", + "M6 - metric (1 mm/rev)", + "M5 - metric (0.8 mm/rev)", + "12 (12 mm/rev)", + "16 (16 mm/rev)", + "25 (25 mm/rev)", + '5/15"-18 imperial coarse (1.41111 mm/rev)', + '3/16"-20 imperial (1.270 mm/rev)', + '1/4"-16 ACME (1.5875 mm/rev)', + ] + self.screwPresetValues = [ + -1, + 1.25, + 1.00, + 0.8, + 12.0, + 16.0, + 25.0, + 1.41111, + 1.270, + 1.5875, + ] + tc = wx.Choice(self, wx.ID_ANY, choices=screwPresets) + tc.SetFont(font) + tc.SetSelection(0) + tc.Bind(wx.EVT_CHOICE, self.onPresetChoice) + lsz.Add(tc) + tc.SetToolTip("Screw pitch presets.") + self.tcPresets = tc - sz.Add(lsz) - sz.Add((10, 10)) + sz.Add(lsz) + sz.Add((10, 10)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Gear Ratio:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st, 1, wx.TOP, offsetTcLabel) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Gear Ratio:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st, 1, wx.TOP, offsetTcLabel) + lsz.Add((5, 5)) - tc = wx.TextCtrl(self, wx.ID_ANY, "1", size = (40, -1), style = wx.TE_RIGHT) - tc.SetFont(font) - tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat) - lsz.Add(tc) - tc.SetToolTip("Gear ratio. 1:1 if there is no gear.") - self.tcRatioTop = tc + tc = wx.TextCtrl(self, wx.ID_ANY, "1", size=(40, -1), style=wx.TE_RIGHT) + tc.SetFont(font) + tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat) + lsz.Add(tc) + tc.SetToolTip("Gear ratio. 1:1 if there is no gear.") + self.tcRatioTop = tc - lsz.Add((5, 5)) - st = wx.StaticText(self, wx.ID_ANY, ":") - st.SetFont(font) - lsz.Add(st) - lsz.Add((5, 5)) + lsz.Add((5, 5)) + st = wx.StaticText(self, wx.ID_ANY, ":") + st.SetFont(font) + lsz.Add(st) + lsz.Add((5, 5)) - tc = wx.TextCtrl(self, wx.ID_ANY, "1", size = (40, -1), style = wx.TE_RIGHT) - tc.SetFont(font) - tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat) - lsz.Add(tc) - tc.SetToolTip("Gear ratio. 1:1 if there is no gear.") - self.tcRatioBottom = tc + tc = wx.TextCtrl(self, wx.ID_ANY, "1", size=(40, -1), style=wx.TE_RIGHT) + tc.SetFont(font) + tc.Bind(wx.EVT_TEXT, self.onTextCtrlFloat) + lsz.Add(tc) + tc.SetToolTip("Gear ratio. 1:1 if there is no gear.") + self.tcRatioBottom = tc - sz.Add(lsz) - sz.Add((30, 30)) + sz.Add(lsz) + sz.Add((30, 30)) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Result:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st) - lsz.Add((5, 5)) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Result:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st) + lsz.Add((5, 5)) - tc = wx.StaticText(self, wx.ID_ANY, "", size = (300, -1), - style = wx.ALIGN_LEFT) - tc.SetFont(font) - lsz.Add(tc) - self.tcResult = tc + tc = wx.StaticText(self, wx.ID_ANY, "", size=(300, -1), style=wx.ALIGN_LEFT) + tc.SetFont(font) + lsz.Add(tc) + self.tcResult = tc - sz.Add(lsz) - lsz = wx.BoxSizer(wx.HORIZONTAL) - st = wx.StaticText(self, wx.ID_ANY, "Resolution:", size = (labelWidth, -1), - style = wx.ALIGN_RIGHT) - st.SetFont(font) - lsz.Add(st) - lsz.Add((5, 5)) + sz.Add(lsz) + lsz = wx.BoxSizer(wx.HORIZONTAL) + st = wx.StaticText( + self, wx.ID_ANY, "Resolution:", size=(labelWidth, -1), style=wx.ALIGN_RIGHT + ) + st.SetFont(font) + lsz.Add(st) + lsz.Add((5, 5)) - tc = wx.StaticText(self, wx.ID_ANY, "", size = (300, -1), - style = wx.ALIGN_LEFT) - tc.SetFont(font) - lsz.Add(tc) - self.tcResolution = tc + tc = wx.StaticText(self, wx.ID_ANY, "", size=(300, -1), style=wx.ALIGN_LEFT) + tc.SetFont(font) + lsz.Add(tc) + self.tcResolution = tc - sz.Add(lsz) + sz.Add(lsz) - sz.Add((20, 20)) + sz.Add((20, 20)) - bsz = wx.BoxSizer(wx.HORIZONTAL) - b = wx.Button(self, wx.ID_ANY, "Use for X", size = BSIZESMALL) - b.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.onUseForX, b) - bsz.Add(b) - self.bUseForX = b - bsz.Add((5, 5)) + bsz = wx.BoxSizer(wx.HORIZONTAL) + b = wx.Button(self, wx.ID_ANY, "Use for X", size=BSIZESMALL) + b.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.onUseForX, b) + bsz.Add(b) + self.bUseForX = b + bsz.Add((5, 5)) - b = wx.Button(self, wx.ID_ANY, "Use for Y", size = BSIZESMALL) - b.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.onUseForY, b) - bsz.Add(b) - self.bUseForY = b - bsz.Add((5, 5)) + b = wx.Button(self, wx.ID_ANY, "Use for Y", size=BSIZESMALL) + b.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.onUseForY, b) + bsz.Add(b) + self.bUseForY = b + bsz.Add((5, 5)) - b = wx.Button(self, wx.ID_ANY, "Use for Z", size = BSIZESMALL) - b.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.onUseForZ, b) - bsz.Add(b) - self.bUseForZ = b - bsz.Add((5, 5)) + b = wx.Button(self, wx.ID_ANY, "Use for Z", size=BSIZESMALL) + b.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.onUseForZ, b) + bsz.Add(b) + self.bUseForZ = b + bsz.Add((5, 5)) - b = wx.Button(self, wx.ID_ANY, "Use for E", size = BSIZESMALL) - b.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.onUseForE, b) - bsz.Add(b) - self.bUseForE = b + b = wx.Button(self, wx.ID_ANY, "Use for E", size=BSIZESMALL) + b.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.onUseForE, b) + bsz.Add(b) + self.bUseForE = b - sz.Add(bsz, flag = wx.ALIGN_CENTER_HORIZONTAL) - sz.Add((10, 10)) + sz.Add(bsz, flag=wx.ALIGN_CENTER_HORIZONTAL) + sz.Add((10, 10)) - hsz.Add(sz) - hsz.Add((10, 10)) + hsz.Add(sz) + hsz.Add((10, 10)) - self.enableUseButtons(False) + self.enableUseButtons(False) - self.SetSizer(hsz) + self.SetSizer(hsz) - self.Fit() + self.Fit() - self.calculate() + self.calculate() - def calculate(self): - self.tcResult.SetLabel("") - self.tcResolution.SetLabel("") - self.enableUseButtons(False) - s = self.tcStep.GetSelection() - sv = self.stepAngleValues[s] + def calculate(self): + self.tcResult.SetLabel("") + self.tcResolution.SetLabel("") + self.enableUseButtons(False) + s = self.tcStep.GetSelection() + sv = self.stepAngleValues[s] - try: - sp = float(self.tcScrewPitch.GetValue()) - except: - return + try: + sp = float(self.tcScrewPitch.GetValue()) + except: + return - try: - ratioA = float(self.tcRatioTop.GetValue()) - except: - return + try: + ratioA = float(self.tcRatioTop.GetValue()) + except: + return - try: - ratioB = float(self.tcRatioBottom.GetValue()) - except: - return + try: + ratioB = float(self.tcRatioBottom.GetValue()) + except: + return - s = self.tcMicroStepping.GetSelection() - msv = self.microSteppingValues[s] + s = self.tcMicroStepping.GetSelection() + msv = self.microSteppingValues[s] - ratio = ratioA / ratioB - steps = sv * msv + ratio = ratioA / ratioB + steps = sv * msv - resultmm = steps / sp / ratio - self.result = int(resultmm * 1000.0) + resultmm = steps / sp / ratio + self.result = int(resultmm * 1000.0) - self.tcResult.SetLabel("%d steps/m (%.3f steps/mm)" % - (self.result, resultmm)) - self.tcResolution.SetLabel("%.3f micrometers" % (1.0 / resultmm * 1000.0)) - self.enableUseButtons(True) + self.tcResult.SetLabel("%d steps/m (%.3f steps/mm)" % (self.result, resultmm)) + self.tcResolution.SetLabel("%.3f micrometers" % (1.0 / resultmm * 1000.0)) + self.enableUseButtons(True) - def enableUseButtons(self, flag): - self.bUseForX.Enable(flag) - self.bUseForY.Enable(flag) - self.bUseForZ.Enable(flag) - self.bUseForE.Enable(flag) + def enableUseButtons(self, flag): + self.bUseForX.Enable(flag) + self.bUseForY.Enable(flag) + self.bUseForZ.Enable(flag) + self.bUseForE.Enable(flag) - def onUseForX(self, evt): - self.use('STEPS_PER_M_X', self.result) + def onUseForX(self, evt): + self.use("STEPS_PER_M_X", self.result) - def onUseForY(self, evt): - self.use('STEPS_PER_M_Y', self.result) + def onUseForY(self, evt): + self.use("STEPS_PER_M_Y", self.result) - def onUseForZ(self, evt): - self.use('STEPS_PER_M_Z', self.result) + def onUseForZ(self, evt): + self.use("STEPS_PER_M_Z", self.result) - def onUseForE(self, evt): - self.use('STEPS_PER_M_E', self.result) + def onUseForE(self, evt): + self.use("STEPS_PER_M_E", self.result) - def onPresetChoice(self, evt): - s = self.tcPresets.GetSelection() - sv = self.screwPresetValues[s] - if sv < 0: - return + def onPresetChoice(self, evt): + s = self.tcPresets.GetSelection() + sv = self.screwPresetValues[s] + if sv < 0: + return - s = "%f" % sv - s = s.rstrip("0") - if s[-1] == ".": - s += "0" - self.tcScrewPitch.SetValue(s) + s = "%f" % sv + s = s.rstrip("0") + if s[-1] == ".": + s += "0" + self.tcScrewPitch.SetValue(s) - def onChoice(self, evt): - self.calculate() + def onChoice(self, evt): + self.calculate() - def onTextCtrlFloat(self, evt): - tc = evt.GetEventObject() - w = tc.GetValue().strip() - if w == "": - valid = False - else: - m = reFloat.match(w) - if m: - valid = True - else: - valid = False + def onTextCtrlFloat(self, evt): + tc = evt.GetEventObject() + w = tc.GetValue().strip() + if w == "": + valid = False + else: + m = reFloat.match(w) + if m: + valid = True + else: + valid = False - if valid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() - self.calculate() - evt.Skip() + if valid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() + self.calculate() + evt.Skip() - def onExit(self, evt): - self.EndModal(wx.ID_OK) + def onExit(self, evt): + self.EndModal(wx.ID_OK) diff --git a/configtool/communicationspage.py b/configtool/communicationspage.py index 7bed0ad..8b7d8db 100644 --- a/configtool/communicationspage.py +++ b/configtool/communicationspage.py @@ -1,62 +1,65 @@ - import wx from configtool.page import Page class CommunicationsPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.parent = parent - self.id = idPg - self.defaultBaud = '115200' + def __init__(self, parent, nb, idPg, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.parent = parent + self.id = idPg + self.defaultBaud = "115200" - self.bauds = ['19200', '38400', '57600', '115200', '230400', '250000'] + self.bauds = ["19200", "38400", "57600", "115200", "230400", "250000"] - self.labels = {'XONXOFF': "XON/XOFF Flow Control", 'BAUD': "Baud Rate:", - 'USB_SERIAL': "USB Serial"} + self.labels = { + "XONXOFF": "XON/XOFF Flow Control", + "BAUD": "Baud Rate:", + "USB_SERIAL": "USB Serial", + } - sz = wx.GridBagSizer() - sz.Add((20, 40), pos = (0, 0)) + sz = wx.GridBagSizer() + sz.Add((20, 40), pos=(0, 0)) - k = 'USB_SERIAL' - cb = self.addCheckBox(k, self.onUSBCheckBox) - sz.Add(cb, pos = (1, 1)) + k = "USB_SERIAL" + cb = self.addCheckBox(k, self.onUSBCheckBox) + sz.Add(cb, pos=(1, 1)) - ch = self.addChoice('BAUD', self.bauds, self.bauds.index(self.defaultBaud), - 80, self.onChoice) - sz.Add(ch, pos = (1, 3)) + ch = self.addChoice( + "BAUD", self.bauds, self.bauds.index(self.defaultBaud), 80, self.onChoice + ) + sz.Add(ch, pos=(1, 3)) - cb = self.addCheckBox('XONXOFF', self.onCheckBox) - sz.Add(cb, pos = (3, 3)) + cb = self.addCheckBox("XONXOFF", self.onCheckBox) + sz.Add(cb, pos=(3, 3)) - sz.Add((100, 10), pos = (2, 2)) + sz.Add((100, 10), pos=(2, 2)) - self.SetSizer(sz) - self.enableAll(False) + self.SetSizer(sz) + self.enableAll(False) - def onUSBCheckBox(self, evt): - self.assertModified(True) - f = not self.checkBoxes['USB_SERIAL'].IsChecked() - self.checkBoxes['XONXOFF'].Enable(f) - self.choices['BAUD'].Enable(f) - evt.Skip() + def onUSBCheckBox(self, evt): + self.assertModified(True) + f = not self.checkBoxes["USB_SERIAL"].IsChecked() + self.checkBoxes["XONXOFF"].Enable(f) + self.choices["BAUD"].Enable(f) + evt.Skip() - def insertValues(self, cfgValues): - Page.insertValues(self, cfgValues) + def insertValues(self, cfgValues): + Page.insertValues(self, cfgValues) - k = 'BAUD' - self.setChoice(k, cfgValues, self.defaultBaud) + k = "BAUD" + self.setChoice(k, cfgValues, self.defaultBaud) - if self.checkBoxes['USB_SERIAL'].IsChecked(): - self.checkBoxes['XONXOFF'].Enable(False) - self.choices['BAUD'].Enable(False) + if self.checkBoxes["USB_SERIAL"].IsChecked(): + self.checkBoxes["XONXOFF"].Enable(False) + self.choices["BAUD"].Enable(False) - def getValues(self): - result = Page.getValues(self) + def getValues(self): + result = Page.getValues(self) - if result['USB_SERIAL']: - result['BAUD'] = result['BAUD'][0], False - result['XONXOFF'] = False + if result["USB_SERIAL"]: + result["BAUD"] = result["BAUD"][0], False + result["XONXOFF"] = False - return result + return result diff --git a/configtool/cpupage.py b/configtool/cpupage.py index 6c0fee4..7738f75 100644 --- a/configtool/cpupage.py +++ b/configtool/cpupage.py @@ -1,53 +1,51 @@ - import wx from configtool.page import Page class CpuPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.parent = parent - self.id = idPg + def __init__(self, parent, nb, idPg, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.parent = parent + self.id = idPg - self.labels = {'F_CPU': "CPU Clock Rate:", 'CPU': "Processor Type:"} - self.clocks = [] - self.processors = [] + self.labels = {"F_CPU": "CPU Clock Rate:", "CPU": "Processor Type:"} + self.clocks = [] + self.processors = [] - sz = wx.GridBagSizer() - sz.Add((20, 40), pos = (0, 0)) + sz = wx.GridBagSizer() + sz.Add((20, 40), pos=(0, 0)) - k = 'F_CPU' - ch = self.addChoice(k, self.clocks, 0, 100, self.onChoice, size = (140, -1)) - sz.Add(ch, pos = (1, 1)) - sz.Add((100, 10), pos = (1, 2)) + k = "F_CPU" + ch = self.addChoice(k, self.clocks, 0, 100, self.onChoice, size=(140, -1)) + sz.Add(ch, pos=(1, 1)) + sz.Add((100, 10), pos=(1, 2)) - k = 'CPU' - ch = self.addChoice(k, self.processors, 0, 100, self.onChoice, - size = (140, -1)) - sz.Add(ch, pos = (1, 3)) + k = "CPU" + ch = self.addChoice(k, self.processors, 0, 100, self.onChoice, size=(140, -1)) + sz.Add(ch, pos=(1, 3)) - self.SetSizer(sz) - self.enableAll(False) + self.SetSizer(sz) + self.enableAll(False) - def setCandidateProcessors(self, plist): - k = 'CPU' - self.choices[k].Clear() - for p in plist: - self.choices[k].Append(p) - self.processors = plist + def setCandidateProcessors(self, plist): + k = "CPU" + self.choices[k].Clear() + for p in plist: + self.choices[k].Append(p) + self.processors = plist - def setCandidateClocks(self, clist): - k = 'F_CPU' - self.choices[k].Clear() - for c in clist: - self.choices[k].Append(c) - self.clocks = clist + def setCandidateClocks(self, clist): + k = "F_CPU" + self.choices[k].Clear() + for c in clist: + self.choices[k].Append(c) + self.clocks = clist - def insertValues(self, cfgValues): - Page.insertValues(self, cfgValues) + def insertValues(self, cfgValues): + Page.insertValues(self, cfgValues) - if len(self.clocks) > 0: - self.setChoice('F_CPU', cfgValues, self.clocks[0]) - if len(self.processors) > 0: - self.setChoice('CPU', cfgValues, self.processors[0]) + if len(self.clocks) > 0: + self.setChoice("F_CPU", cfgValues, self.clocks[0]) + if len(self.processors) > 0: + self.setChoice("CPU", cfgValues, self.processors[0]) diff --git a/configtool/data.py b/configtool/data.py index 7c20a40..1e4cd4f 100644 --- a/configtool/data.py +++ b/configtool/data.py @@ -1,47 +1,61 @@ - import re from sys import platform -supportedCPUs = ['ATmega168', 'ATmega328P', 'ATmega644', 'ATmega644P', - 'ATmega644PA', 'ATmega1280', 'ATmega1284', 'ATmega1284P', - 'ATmega2560', 'AT90USB1286'] +supportedCPUs = [ + "ATmega168", + "ATmega328P", + "ATmega644", + "ATmega644P", + "ATmega644PA", + "ATmega1280", + "ATmega1284", + "ATmega1284P", + "ATmega2560", + "AT90USB1286", +] # Note: this is a kludge and works for ATmegas, only. Smaller ATmegas have a # lot fewer pins, so this list provides a lot of clutter for them. ARMs # have entirely different names. The right way would be to fetch pin # names from the compiler environment and/or header files. -pinNames = ["AIO%d" % x for x in range(16)] + \ - ["DIO%d" % x for x in range(64)] + \ - ["P%c%d" % (c, x) for c in range(ord('A'), ord('L') + 1) \ - for x in range(8)] +pinNames = ( + ["AIO%d" % x for x in range(16)] + + ["DIO%d" % x for x in range(64)] + + ["P%c%d" % (c, x) for c in range(ord("A"), ord("L") + 1) for x in range(8)] +) -sensorTypes = {'MAX6675': "TT_MAX6675", 'Thermistor': "TT_THERMISTOR", - 'AD595': "TT_AD595", 'PT100': "TT_PT100", - 'Intercom': "TT_INTERCOM", 'MCP3008': "TT_MCP3008"} +sensorTypes = { + "MAX6675": "TT_MAX6675", + "Thermistor": "TT_THERMISTOR", + "AD595": "TT_AD595", + "PT100": "TT_PT100", + "Intercom": "TT_INTERCOM", + "MCP3008": "TT_MCP3008", +} BSIZE = (100, 60) BSIZESMALL = (90, 30) if platform.startswith("win"): - offsetTcLabel = 4 - offsetChLabel = 4 + offsetTcLabel = 4 + offsetChLabel = 4 else: - offsetTcLabel = 6 - offsetChLabel = 8 + offsetTcLabel = 6 + offsetChLabel = 8 TYPE_GENERAL = 0 TYPE_FLOAT = 1 reDefQSm = re.compile("\s*#define\s+(\S+)\s+(.*)") -reDefQSm2 = re.compile("\s*(\"[^\"]*\")") +reDefQSm2 = re.compile('\s*("[^"]*")') -reInclude = re.compile("^\s*#include\s+\"([^\"]*)") +reInclude = re.compile('^\s*#include\s+"([^"]*)') reFloatAttr = re.compile("/\*\s*float\s*\*/") reDefine = re.compile("\s*#define\s+(\w+)\s+(\S+)") reDefineBL = re.compile("^\s*#define\s+(\w+)\s+(\S+)") -reDefQS = re.compile("\s*#define\s+(\w+)\s+(\"[^\"]*\")") +reDefQS = re.compile('\s*#define\s+(\w+)\s+("[^"]*")') reDefTS = re.compile("\s*(DEFINE_TEMP_SENSOR\\([^)]*\\))") reDefHT = re.compile("\s*(DEFINE_HEATER\\([^)]*\\))") reDefTT = re.compile("^\s*//\s*TEMP_TABLE\s+(\S+)\s+(\\(.*\\))") @@ -64,16 +78,22 @@ reSensor = re.compile(".*\\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\\)") # reHeater3 and reHeater4 deprecated, for compatibility with old config files only. reHeater3 = re.compile(".*\\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\\)") reHeater4 = re.compile(".*\\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\\)") -reHeater5 = re.compile(".*\\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\\)") -reTempTable4 = re.compile(".*\\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d*.?\d*)\s*\\)") -reTempTable7 = re.compile(".*\\(\s*(\d+)\s*,\s*(\d*.?\d*)\s*,\s*(\d+)\s*,\s*(\d*.?\d*)\s*,\s*(\d+)\s*,\s*(\d*.?\d*)\s*,\s*(\d+)\s*\\)") +reHeater5 = re.compile( + ".*\\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\\)" +) +reTempTable4 = re.compile( + ".*\\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d*.?\d*)\s*\\)" +) +reTempTable7 = re.compile( + ".*\\(\s*(\d+)\s*,\s*(\d*.?\d*)\s*,\s*(\d+)\s*,\s*(\d*.?\d*)\s*,\s*(\d+)\s*,\s*(\d*.?\d*)\s*,\s*(\d+)\s*\\)" +) reInteger = re.compile("^\d+U?L?$") reFloat = re.compile("^\d+(\.\d*)?$") -defineValueFormat = "#define %-24s %s\n" -defineBoolFormat = "#define %s\n" -defineHeaterFormat = "#define HEATER_%s HEATER_%s\n" +defineValueFormat = "#define %-24s %s\n" +defineBoolFormat = "#define %s\n" +defineHeaterFormat = "#define HEATER_%s HEATER_%s\n" defineDCExtruderFormat = "#define %-24s HEATER_%s\n" reHomingOpts = re.compile("^\s*//\s*#define\s+HOMING_OPT\s+(\w+)") diff --git a/configtool/decoration.py b/configtool/decoration.py index e258206..f2d4cef 100644 --- a/configtool/decoration.py +++ b/configtool/decoration.py @@ -5,64 +5,66 @@ import os.path class Decoration(object): - def __new__(type, *args): - # Make it a Singleton. - if not '_the_instance' in type.__dict__: - type._the_instance = object.__new__(type) + def __new__(type, *args): + # Make it a Singleton. + if not "_the_instance" in type.__dict__: + type._the_instance = object.__new__(type) - return type._the_instance + return type._the_instance - def __init__(self): - if not '_ready' in dir(self): - self._ready = True - # It's a Singleton. Initialisations go in here. - self.backPic = None - self.backPicOffset = (0, -25) + def __init__(self): + if not "_ready" in dir(self): + self._ready = True + # It's a Singleton. Initialisations go in here. + self.backPic = None + self.backPicOffset = (0, -25) - if not self.backPic: - backPicPath = os.path.join("configtool", "background.png") - if os.path.exists(backPicPath): - backPic = wx.Bitmap(backPicPath) - if backPic.IsOk(): - self.backPic = backPic - else: - print("Background picture %s damaged." % backPicPath) - else: - print("Background picture %s doesn't exist." % backPicPath) + if not self.backPic: + backPicPath = os.path.join("configtool", "background.png") + if os.path.exists(backPicPath): + backPic = wx.Bitmap(backPicPath) + if backPic.IsOk(): + self.backPic = backPic + else: + print("Background picture %s damaged." % backPicPath) + else: + print("Background picture %s doesn't exist." % backPicPath) - def getBackgroundColour(self): - return wx.Colour(237, 237, 237) + def getBackgroundColour(self): + return wx.Colour(237, 237, 237) - # On wxFrames, bind this to wx.EVT_ERASE_BACKGROUND - # On wxPanels, bind this to wx.EVT_PAINT - def onPaintBackground(self, evt): - client = evt.GetEventObject() - topLevel = client.GetTopLevelParent() + # On wxFrames, bind this to wx.EVT_ERASE_BACKGROUND + # On wxPanels, bind this to wx.EVT_PAINT + def onPaintBackground(self, evt): + client = evt.GetEventObject() + topLevel = client.GetTopLevelParent() - try: - dc = evt.GetDC() - except: - dc = wx.PaintDC(client) + try: + dc = evt.GetDC() + except: + dc = wx.PaintDC(client) - if dc: - # Now draw the background picture with pseudo-transparency. This is, - # each background is drawn with the same picture, without transparency, - # and offsetted just right to have all backgrounds in the same position - # relative to the *toplevel* window, not relative to the current - # subwindow as usual. + if dc: + # Now draw the background picture with pseudo-transparency. This is, + # each background is drawn with the same picture, without transparency, + # and offsetted just right to have all backgrounds in the same position + # relative to the *toplevel* window, not relative to the current + # subwindow as usual. - # Align bottom right. - offX, offY = topLevel.GetClientSize() - self.backPic.GetSize() + \ - self.backPicOffset + # Align bottom right. + offX, offY = ( + topLevel.GetClientSize() - self.backPic.GetSize() + self.backPicOffset + ) - if client != topLevel: - # Note: trying to figure this additional offset via various - # .GetScreenPosition() or .GetPosition() or whatever is hopeless. - # Of many many tries only this worked on Linux. - offX, offY = \ - client.ScreenToClient(topLevel.ClientToScreen((offX, offY))) + if client != topLevel: + # Note: trying to figure this additional offset via various + # .GetScreenPosition() or .GetPosition() or whatever is hopeless. + # Of many many tries only this worked on Linux. + offX, offY = client.ScreenToClient( + topLevel.ClientToScreen((offX, offY)) + ) - if self.backPic: - dc.DrawBitmap(self.backPic, offX, offY) + if self.backPic: + dc.DrawBitmap(self.backPic, offX, offY) - evt.Skip() + evt.Skip() diff --git a/configtool/displaypage.py b/configtool/displaypage.py index 46ee0c8..efaeb35 100644 --- a/configtool/displaypage.py +++ b/configtool/displaypage.py @@ -1,4 +1,3 @@ - # coding=utf-8 import wx @@ -6,76 +5,86 @@ from configtool.page import Page class DisplayPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.parent = parent - self.id = idPg + def __init__(self, parent, nb, idPg, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.parent = parent + self.id = idPg - self.labels = {'DISPLAY_BUS': "Display Bus:", - 'DISPLAY_TYPE': "Display Type:", - 'DISPLAY_BUS_4BIT': "Direct with 4 pins", - 'DISPLAY_BUS_8BIT': "Direct with 8 pins", - 'DISPLAY_BUS_I2C': "I²C ( = TWI)", - 'DISPLAY_BUS_SPI': "SPI", - 'DISPLAY_TYPE_SSD1306': "SSD1306 O-LED, 128x32 pixels", - 'DISPLAY_TYPE_HD44780': "HD44780 or 1602A, 16x2 characters", - 'DISPLAY_RS_PIN': "RS pin", - 'DISPLAY_RW_PIN': "R/W pin", - 'DISPLAY_E_PIN': "E pin", - 'DISPLAY_D4_PIN': "D4 pin", - 'DISPLAY_D5_PIN': "D5 pin", - 'DISPLAY_D6_PIN': "D6 pin", - 'DISPLAY_D7_PIN': "D7 pin"} + self.labels = { + "DISPLAY_BUS": "Display Bus:", + "DISPLAY_TYPE": "Display Type:", + "DISPLAY_BUS_4BIT": "Direct with 4 pins", + "DISPLAY_BUS_8BIT": "Direct with 8 pins", + "DISPLAY_BUS_I2C": "I²C ( = TWI)", + "DISPLAY_BUS_SPI": "SPI", + "DISPLAY_TYPE_SSD1306": "SSD1306 O-LED, 128x32 pixels", + "DISPLAY_TYPE_HD44780": "HD44780 or 1602A, 16x2 characters", + "DISPLAY_RS_PIN": "RS pin", + "DISPLAY_RW_PIN": "R/W pin", + "DISPLAY_E_PIN": "E pin", + "DISPLAY_D4_PIN": "D4 pin", + "DISPLAY_D5_PIN": "D5 pin", + "DISPLAY_D6_PIN": "D6 pin", + "DISPLAY_D7_PIN": "D7 pin", + } - sz = wx.GridBagSizer() - sz.Add((20, 40), pos = (0, 0)) + sz = wx.GridBagSizer() + sz.Add((20, 40), pos=(0, 0)) - ch = self.addBoolChoice('DISPLAY_BUS', True, 100, self.onBusChoice, - size = (160, -1)) - sz.Add(ch, pos = (1, 1)) - sz.Add((100, 10), pos = (1, 2)) + ch = self.addBoolChoice( + "DISPLAY_BUS", True, 100, self.onBusChoice, size=(160, -1) + ) + sz.Add(ch, pos=(1, 1)) + sz.Add((100, 10), pos=(1, 2)) - ch = self.addBoolChoice('DISPLAY_TYPE', False, 100, self.onChoice, - size = (240, -1)) - sz.Add(ch, pos = (1, 3)) + ch = self.addBoolChoice( + "DISPLAY_TYPE", False, 100, self.onChoice, size=(240, -1) + ) + sz.Add(ch, pos=(1, 3)) - b = wx.StaticBox(self, wx.ID_ANY, "Direct 4-bit Bus Pins:") - b.SetFont(font) - self.pinbox = wx.StaticBoxSizer(b, wx.VERTICAL) - self.pinbox.Add((5, 5)) - for k in ('DISPLAY_RS_PIN', 'DISPLAY_RW_PIN', 'DISPLAY_E_PIN', - 'DISPLAY_D4_PIN', 'DISPLAY_D5_PIN', 'DISPLAY_D6_PIN', - 'DISPLAY_D7_PIN'): - tc = self.addPinChoice(k, 200) - self.pinbox.Add(tc) - self.pinbox.Add((5, 5)) - sz.Add(self.pinbox, pos = (3, 1)) + b = wx.StaticBox(self, wx.ID_ANY, "Direct 4-bit Bus Pins:") + b.SetFont(font) + self.pinbox = wx.StaticBoxSizer(b, wx.VERTICAL) + self.pinbox.Add((5, 5)) + for k in ( + "DISPLAY_RS_PIN", + "DISPLAY_RW_PIN", + "DISPLAY_E_PIN", + "DISPLAY_D4_PIN", + "DISPLAY_D5_PIN", + "DISPLAY_D6_PIN", + "DISPLAY_D7_PIN", + ): + tc = self.addPinChoice(k, 200) + self.pinbox.Add(tc) + self.pinbox.Add((5, 5)) + sz.Add(self.pinbox, pos=(3, 1)) - self.SetSizer(sz) - self.enableAll(False) + self.SetSizer(sz) + self.enableAll(False) - def onBusChoice(self, evt): - choice = self.boolChoices['DISPLAY_BUS'] - if choice.GetClientData(choice.GetSelection()): - self.boolChoices['DISPLAY_TYPE'].Enable(True) - else: - self.boolChoices['DISPLAY_TYPE'].Enable(False) - self.adjustPinVisibility() + def onBusChoice(self, evt): + choice = self.boolChoices["DISPLAY_BUS"] + if choice.GetClientData(choice.GetSelection()): + self.boolChoices["DISPLAY_TYPE"].Enable(True) + else: + self.boolChoices["DISPLAY_TYPE"].Enable(False) + self.adjustPinVisibility() - Page.onChoice(self, evt) + Page.onChoice(self, evt) - def adjustPinVisibility(self): - visible = False + def adjustPinVisibility(self): + visible = False - choice = self.boolChoices['DISPLAY_BUS'] - if choice.GetSelection() >= 0: - selection = choice.GetClientData(choice.GetSelection()) - if selection == 'DISPLAY_BUS_4BIT': - visible = True + choice = self.boolChoices["DISPLAY_BUS"] + if choice.GetSelection() >= 0: + selection = choice.GetClientData(choice.GetSelection()) + if selection == "DISPLAY_BUS_4BIT": + visible = True - self.pinbox.ShowItems(visible) + self.pinbox.ShowItems(visible) - def insertValues(self, cfgValues): - Page.insertValues(self, cfgValues) - self.adjustPinVisibility() + def insertValues(self, cfgValues): + Page.insertValues(self, cfgValues) + self.adjustPinVisibility() diff --git a/configtool/gui.py b/configtool/gui.py index 1873fc2..b64af22 100644 --- a/configtool/gui.py +++ b/configtool/gui.py @@ -2,6 +2,7 @@ from __future__ import print_function import sys import time + try: import wx if int(wx.__version__[0]) < 4: @@ -16,12 +17,6 @@ except: ) time.sleep(10) sys.exit(-1) -except: - print("ImportError: No module named wx\n\n" - "wxPython is not installed. This program requires wxPython to run.\n" - "See your package manager and/or https://wxpython.org/pages/downloads/.") - time.sleep(10) - sys.exit(-1) import os.path @@ -51,581 +46,651 @@ ID_ABOUT = 1052 class ConfigFrame(wx.Frame): - def __init__(self, settings): - wx.Frame.__init__(self, None, -1, "Teacup Configtool", size = (880, 550)) - self.Bind(wx.EVT_CLOSE, self.onClose) - self.Bind(wx.EVT_SIZE, self.onResize) - - self.deco = Decoration() - - panel = wx.Panel(self, -1) - panel.SetBackgroundColour(self.deco.getBackgroundColour()) - panel.Bind(wx.EVT_PAINT, self.deco.onPaintBackground) - - self.settings = settings - self.settings.app = self - self.settings.font = wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, - wx.FONTWEIGHT_BOLD) - - 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.SetBackgroundColour(self.deco.getBackgroundColour()) - 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() - self.panel = panel - - 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 onResize(self, evt): - self.panel.SetSize(self.GetClientSize()) - self.Refresh() - evt.Skip(); - - 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") - - help_menu = wx.Menu() - - help_menu.Append(ID_HELP, "Help", "Find help.") - self.Bind(wx.EVT_MENU, self.onHelp, id = ID_HELP) - - help_menu.Append(ID_REPORT, "Report problem", - "Report a problem to Teacup maintainers.") - self.Bind(wx.EVT_MENU, self.onReportProblem, id = ID_REPORT) - - help_menu.AppendSeparator() - - help_menu.Append(ID_ABOUT, "About Teacup") - self.Bind(wx.EVT_MENU, self.onAbout, id = ID_ABOUT) - - self.helpMenu = help_menu - - menu_bar.Append(help_menu, "&Help") - - 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(self.settings.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(self.settings.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(self.settings.folder, fn) - try: - cfgBuffer = list(open(path)) - except: - self.message("Unable to process config file %s." % fn, "File error") - return None, None - - 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(self.settings.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(self.settings.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(self.settings.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 - else: - self.pgBoard.generateTempTables() - - pfn = self.pgPrinter.getFileName() - if self.pgPrinter.isModified() and self.pgPrinter.isValid(): - if not self.pgPrinter.saveConfigFile(pfn): - return False - - prefix = self.settings.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 onHelp(self, evt): - self.message("Find help by hovering slowly over the buttons and text " - "fields. Tooltip should appear, explaining things.", - "Find help", style = wx.OK) - - def onReportProblem(self, evt): - import urllib - import webbrowser - import subprocess - from sys import platform - - # Testing allowed URLs up to 32 kB in size. Longer URLs are simply chopped. - mailRecipients ="reply+0004dc756da9f0641af0a3834c580ad5be469f4f6b" \ - "5d4cfc92cf00000001118c958a92a169ce051faa8c@" \ - "reply.github.com,mah@jump-ing.de" - mailSubject = "Teacup problem report" - mailBody = "Please answer these questions before hitting \"send\":\n\n" \ - "What did you try to do?\n\n\n" \ - "What did you expect to happen?\n\n\n" \ - "What happened instead?\n\n\n\n" \ - "To allow developers to help, configuration files are " \ - "attached, with help comments stripped:\n" - - for f in self.pgBoard.getFileName(), self.pgPrinter.getFileName(): - if not f: - mailBody += "\n(no file loaded)\n" - continue - - mailBody += "\n" + os.path.basename(f) + ":\n" - mailBody += "----------------------------------------------\n" - try: - fc = open(f).read() - fc = reHelpText.sub("", fc) - mailBody += fc - except: - mailBody += "(could not read this file)\n" - mailBody += "----------------------------------------------\n" - - url = "mailto:" + urllib.quote(mailRecipients) + \ - "?subject=" + urllib.quote(mailSubject) + \ - "&body=" + urllib.quote(mailBody) - - # This is a work around a bug in gvfs-open coming with (at least) Ubuntu - # 15.04. gvfs-open would open mailto:///user@example.com instead of - # the requested mailto:user@example.com. - if platform.startswith("linux"): - try: - subprocess.check_output(["gvfs-open", "--help"]) - - # Broken gvfs-open exists, so it might be used. - # Try to open the URL directly. - for urlOpener in "thunderbird", "evolution", "firefox", "mozilla", \ - "epiphany", "konqueror", "chromium-browser", \ - "google-chrome": - try: - subprocess.check_output([urlOpener, url], stderr=subprocess.STDOUT) + def __init__(self, settings): + wx.Frame.__init__(self, None, -1, "Teacup Configtool", size=(880, 550)) + self.Bind(wx.EVT_CLOSE, self.onClose) + self.Bind(wx.EVT_SIZE, self.onResize) + + self.deco = Decoration() + + panel = wx.Panel(self, -1) + panel.SetBackgroundColour(self.deco.getBackgroundColour()) + panel.Bind(wx.EVT_PAINT, self.deco.onPaintBackground) + + self.settings = settings + self.settings.app = self + self.settings.font = wx.Font( + 8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD + ) + + 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.SetBackgroundColour(self.deco.getBackgroundColour()) + 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() + self.panel = panel + + 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 - except: - pass - except: - pass - webbrowser.open_new(url) + if not self.pgBoard.confirmLoseChanges("exit"): + return - def onAbout(self, evt): - # Get the contributors' top 10 with something like this: - # export B=experimental - # git log $B | grep "Author:" | sort | uniq | while \ - # read A; do N=$(git log $B | grep "$A" | wc -l); echo "$N $A"; done | \ - # sort -rn - self.message("Teacup Firmware is a 3D Printer and CNC machine controlling " - "firmware with emphasis on performance, efficiency and " - "outstanding quality. What Teacup does, shall it do very well." - "\n\n\n" - "Lots of people hard at work! Top 10 contributors:\n\n" - " Markus Hitter (542 commits)\n" - " Michael Moon (322 commits)\n" - " Phil Hord (55 commits)\n" - " Jeff Bernardis (51 commits)\n" - " Markus Amsler (47 commits)\n" - " David Forrest (27 commits)\n" - " Jim McGee (15 commits)\n" - " Ben Jackson (12 commits)\n" - " Bas Laarhoven (10 commits)\n" - " Stephan Walter (9 commits)\n" - " Roland Brochard (3 commits)\n" - " Jens Ch. Restemeier (3 commits)\n", - "About Teacup", style = wx.OK) + self.Destroy() - def message(self, text, title, style = wx.OK + wx.ICON_ERROR): - dlg = wx.MessageDialog(self, text, title, style) - dlg.ShowModal() - dlg.Destroy() + def onResize(self, evt): + self.panel.SetSize(self.GetClientSize()) + self.Refresh() + evt.Skip() + + 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") + + help_menu = wx.Menu() + + help_menu.Append(ID_HELP, "Help", "Find help.") + self.Bind(wx.EVT_MENU, self.onHelp, id=ID_HELP) + + help_menu.Append( + ID_REPORT, "Report problem", "Report a problem to Teacup maintainers." + ) + self.Bind(wx.EVT_MENU, self.onReportProblem, id=ID_REPORT) + + help_menu.AppendSeparator() + + help_menu.Append(ID_ABOUT, "About Teacup") + self.Bind(wx.EVT_MENU, self.onAbout, id=ID_ABOUT) + + self.helpMenu = help_menu + + menu_bar.Append(help_menu, "&Help") + + 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(self.settings.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(self.settings.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(self.settings.folder, fn) + try: + cfgBuffer = list(open(path)) + except: + self.message("Unable to process config file %s." % fn, "File error") + return None, None + + 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(self.settings.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(self.settings.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(self.settings.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 + else: + self.pgBoard.generateTempTables() + + pfn = self.pgPrinter.getFileName() + if self.pgPrinter.isModified() and self.pgPrinter.isValid(): + if not self.pgPrinter.saveConfigFile(pfn): + return False + + prefix = self.settings.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 onHelp(self, evt): + self.message( + "Find help by hovering slowly over the buttons and text " + "fields. Tooltip should appear, explaining things.", + "Find help", + style=wx.OK, + ) + + def onReportProblem(self, evt): + import urllib + import webbrowser + import subprocess + from sys import platform + + # Testing allowed URLs up to 32 kB in size. Longer URLs are simply chopped. + mailRecipients = ( + "reply+0004dc756da9f0641af0a3834c580ad5be469f4f6b" + "5d4cfc92cf00000001118c958a92a169ce051faa8c@" + "reply.github.com,mah@jump-ing.de" + ) + mailSubject = "Teacup problem report" + mailBody = ( + 'Please answer these questions before hitting "send":\n\n' + "What did you try to do?\n\n\n" + "What did you expect to happen?\n\n\n" + "What happened instead?\n\n\n\n" + "To allow developers to help, configuration files are " + "attached, with help comments stripped:\n" + ) + + for f in self.pgBoard.getFileName(), self.pgPrinter.getFileName(): + if not f: + mailBody += "\n(no file loaded)\n" + continue + + mailBody += "\n" + os.path.basename(f) + ":\n" + mailBody += "----------------------------------------------\n" + try: + fc = open(f).read() + fc = reHelpText.sub("", fc) + mailBody += fc + except: + mailBody += "(could not read this file)\n" + mailBody += "----------------------------------------------\n" + + url = ( + "mailto:" + + urllib.quote(mailRecipients) + + "?subject=" + + urllib.quote(mailSubject) + + "&body=" + + urllib.quote(mailBody) + ) + + # This is a work around a bug in gvfs-open coming with (at least) Ubuntu + # 15.04. gvfs-open would open mailto:///user@example.com instead of + # the requested mailto:user@example.com. + if platform.startswith("linux"): + try: + subprocess.check_output(["gvfs-open", "--help"]) + + # Broken gvfs-open exists, so it might be used. + # Try to open the URL directly. + for urlOpener in ( + "thunderbird", + "evolution", + "firefox", + "mozilla", + "epiphany", + "konqueror", + "chromium-browser", + "google-chrome", + ): + try: + subprocess.check_output( + [urlOpener, url], stderr=subprocess.STDOUT + ) + return + except: + pass + except: + pass + + webbrowser.open_new(url) + + def onAbout(self, evt): + # Get the contributors' top 10 with something like this: + # export B=experimental + # git log $B | grep "Author:" | sort | uniq | while \ + # read A; do N=$(git log $B | grep "$A" | wc -l); echo "$N $A"; done | \ + # sort -rn + self.message( + "Teacup Firmware is a 3D Printer and CNC machine controlling " + "firmware with emphasis on performance, efficiency and " + "outstanding quality. What Teacup does, shall it do very well." + "\n\n\n" + "Lots of people hard at work! Top 10 contributors:\n\n" + " Markus Hitter (542 commits)\n" + " Michael Moon (322 commits)\n" + " Phil Hord (55 commits)\n" + " Jeff Bernardis (51 commits)\n" + " Markus Amsler (47 commits)\n" + " David Forrest (27 commits)\n" + " Jim McGee (15 commits)\n" + " Ben Jackson (12 commits)\n" + " Bas Laarhoven (10 commits)\n" + " Stephan Walter (9 commits)\n" + " Roland Brochard (3 commits)\n" + " Jens Ch. Restemeier (3 commits)\n", + "About Teacup", + style=wx.OK, + ) + + def message(self, text, title, style=wx.OK + wx.ICON_ERROR): + dlg = wx.MessageDialog(self, text, title, style) + dlg.ShowModal() + dlg.Destroy() def StartGui(settings): - app = wx.App(False) - frame = ConfigFrame(settings) - frame.Show(True) - app.MainLoop() + app = wx.App(False) + frame = ConfigFrame(settings) + frame.Show(True) + app.MainLoop() diff --git a/configtool/heaterlist.py b/configtool/heaterlist.py index 75e0c08..555b11a 100644 --- a/configtool/heaterlist.py +++ b/configtool/heaterlist.py @@ -1,87 +1,89 @@ - import wx class HeaterList(wx.ListCtrl): - def __init__(self, parent, font): - self.parent = parent - self.currentItem = None - wx.ListCtrl.__init__(self, parent, wx.ID_ANY, - size = (95 + 75 + 55 + 55 + 95 + 4, 100), - style = wx.LC_REPORT | wx.LC_VIRTUAL | wx.LC_HRULES | - wx.LC_VRULES) - self.SetFont(font) + def __init__(self, parent, font): + self.parent = parent + self.currentItem = None + wx.ListCtrl.__init__( + self, + parent, + wx.ID_ANY, + size=(95 + 75 + 55 + 55 + 95 + 4, 100), + style=wx.LC_REPORT | wx.LC_VIRTUAL | wx.LC_HRULES | wx.LC_VRULES, + ) + self.SetFont(font) - self.valid = [] - self.heaterList = [] + self.valid = [] + self.heaterList = [] - self.InsertColumn(0, "Name") - self.InsertColumn(1, "Pin") - self.InsertColumn(2, "Invert") - self.InsertColumn(3, "PWM") - self.InsertColumn(4, "Max PWM [%]") - self.SetColumnWidth(0, 95) - self.SetColumnWidth(1, 75) - self.SetColumnWidth(2, 55) - self.SetColumnWidth(3, 55) - self.SetColumnWidth(4, 95) + self.InsertColumn(0, "Name") + self.InsertColumn(1, "Pin") + self.InsertColumn(2, "Invert") + self.InsertColumn(3, "PWM") + self.InsertColumn(4, "Max PWM [%]") + self.SetColumnWidth(0, 95) + self.SetColumnWidth(1, 75) + self.SetColumnWidth(2, 55) + self.SetColumnWidth(3, 55) + self.SetColumnWidth(4, 95) - self.SetItemCount(0) + self.SetItemCount(0) - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) - self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected) + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected) - def updateList(self, heaterList): - self.heaterList = heaterList - self.valid = [True] * len(heaterList) - self.currentItem = None - self.parent.setItemSelected(None) - i = self.GetFirstSelected() - while i != -1: - self.Select(i, False) - i = self.GetFirstSelected() + def updateList(self, heaterList): + self.heaterList = heaterList + self.valid = [True] * len(heaterList) + self.currentItem = None + self.parent.setItemSelected(None) + i = self.GetFirstSelected() + while i != -1: + self.Select(i, False) + i = self.GetFirstSelected() - self.SetItemCount(len(heaterList)) + self.SetItemCount(len(heaterList)) - def setRowValidity(self, i, flag = False): - if i < 0 or i >= len(self.heaterList): - return + def setRowValidity(self, i, flag=False): + if i < 0 or i >= len(self.heaterList): + return - self.valid[i] = flag - self.Refresh() + self.valid[i] = flag + self.Refresh() - def setTableValidity(self, flag = False): - for i in range(len(self.heaterList)): - self.setRowValidity(i, flag) + def setTableValidity(self, flag=False): + for i in range(len(self.heaterList)): + self.setRowValidity(i, flag) - def OnItemSelected(self, event): - self.currentItem = event.m_itemIndex - self.parent.setItemSelected(self.currentItem) + def OnItemSelected(self, event): + self.currentItem = event.m_itemIndex + self.parent.setItemSelected(self.currentItem) - def OnItemDeselected(self, event): - self.currentItem = None - self.parent.setItemSelected(None) + def OnItemDeselected(self, event): + self.currentItem = None + self.parent.setItemSelected(None) - def getColumnText(self, index, col): - item = self.GetItem(index, col) - return item.GetText() + def getColumnText(self, index, col): + item = self.GetItem(index, col) + return item.GetText() - def OnGetItemText(self, item, col): - if item < 0 or item >= len(self.heaterList): - return "Error - no heaters." + def OnGetItemText(self, item, col): + if item < 0 or item >= len(self.heaterList): + return "Error - no heaters." - s = self.heaterList[item] + s = self.heaterList[item] - if col == 0: - return s[0] - elif col == 1: - return s[1] - elif col == 2: - if s[2] == "1": - return "True" - else: - return "False" - elif col == 3: - return s[3] - elif col == 4: - return s[4] + if col == 0: + return s[0] + elif col == 1: + return s[1] + elif col == 2: + if s[2] == "1": + return "True" + else: + return "False" + elif col == 3: + return s[3] + elif col == 4: + return s[4] diff --git a/configtool/heaterspage.py b/configtool/heaterspage.py index 9abb8ea..d558c88 100644 --- a/configtool/heaterspage.py +++ b/configtool/heaterspage.py @@ -1,4 +1,3 @@ - import wx from configtool.page import Page from configtool.data import pinNames, BSIZESMALL @@ -7,183 +6,191 @@ from configtool.addheaterdlg import AddHeaterDlg class HeatersPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.parent = parent - self.font = font - self.id = idPg + def __init__(self, parent, nb, idPg, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.parent = parent + self.font = font + self.id = idPg - self.labels = {'FORCE_SOFTWARE_PWM':"Force software PWM"} + self.labels = {"FORCE_SOFTWARE_PWM": "Force software PWM"} - sz = wx.GridBagSizer() - sz.Add((30, 30), pos = (0, 0)) + sz = wx.GridBagSizer() + sz.Add((30, 30), pos=(0, 0)) - self.heaters = [] - self.validPins = pinNames + self.heaters = [] + self.validPins = pinNames - self.lb = HeaterList(self, font) - sz.Add(self.lb, pos = (1, 1)) - sz.Add((20, 20), pos = (1, 2)) + self.lb = HeaterList(self, font) + sz.Add(self.lb, pos=(1, 1)) + sz.Add((20, 20), pos=(1, 2)) - k = 'FORCE_SOFTWARE_PWM' - cb = self.addCheckBox(k, self.onCheckBox) + k = "FORCE_SOFTWARE_PWM" + cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (2, 1)) - sz.Add((20, 20), pos = (2, 2)) + sz.Add(cb, pos=(2, 1)) + sz.Add((20, 20), pos=(2, 2)) - bsz = wx.BoxSizer(wx.VERTICAL) + bsz = wx.BoxSizer(wx.VERTICAL) - self.bAdd = wx.Button(self, wx.ID_ANY, "Add", size = BSIZESMALL) - self.bAdd.SetBackgroundColour(self.deco.getBackgroundColour()) - self.bAdd.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.doAdd, self.bAdd) - self.bAdd.SetToolTip("Add a heater to the configuration.") - bsz.Add(self.bAdd) + self.bAdd = wx.Button(self, wx.ID_ANY, "Add", size=BSIZESMALL) + self.bAdd.SetBackgroundColour(self.deco.getBackgroundColour()) + self.bAdd.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.doAdd, self.bAdd) + self.bAdd.SetToolTip("Add a heater to the configuration.") + bsz.Add(self.bAdd) - bsz.Add((10, 10)) + bsz.Add((10, 10)) - self.bModify = wx.Button(self, wx.ID_ANY, "Modify", size = BSIZESMALL) - self.bModify.SetBackgroundColour(self.deco.getBackgroundColour()) - self.bModify.SetFont(font) - self.bModify.Enable(False) - self.Bind(wx.EVT_BUTTON, self.doModify, self.bModify) - self.bModify.SetToolTip("Modify the selected heater.") - bsz.Add(self.bModify) + self.bModify = wx.Button(self, wx.ID_ANY, "Modify", size=BSIZESMALL) + self.bModify.SetBackgroundColour(self.deco.getBackgroundColour()) + self.bModify.SetFont(font) + self.bModify.Enable(False) + self.Bind(wx.EVT_BUTTON, self.doModify, self.bModify) + self.bModify.SetToolTip("Modify the selected heater.") + bsz.Add(self.bModify) - bsz.Add((10, 10)) + bsz.Add((10, 10)) - self.bDelete = wx.Button(self, wx.ID_ANY, "Delete", size = BSIZESMALL) - self.bDelete.SetBackgroundColour(self.deco.getBackgroundColour()) - self.bDelete.SetFont(font) - self.bDelete.Enable(False) - self.Bind(wx.EVT_BUTTON, self.doDelete, self.bDelete) - self.bDelete.SetToolTip("Remove the selected heater from the " - "configuration.") - bsz.Add(self.bDelete) + self.bDelete = wx.Button(self, wx.ID_ANY, "Delete", size=BSIZESMALL) + self.bDelete.SetBackgroundColour(self.deco.getBackgroundColour()) + self.bDelete.SetFont(font) + self.bDelete.Enable(False) + self.Bind(wx.EVT_BUTTON, self.doDelete, self.bDelete) + self.bDelete.SetToolTip("Remove the selected heater from the " "configuration.") + bsz.Add(self.bDelete) - sz.Add(bsz, pos = (1, 3)) + sz.Add(bsz, pos=(1, 3)) - self.SetSizer(sz) - self.enableAll(False) + self.SetSizer(sz) + self.enableAll(False) - def enableAll(self, flag = True): - self.bAdd.Enable(flag) - Page.enableAll(self, flag) + def enableAll(self, flag=True): + self.bAdd.Enable(flag) + Page.enableAll(self, flag) - def setItemSelected(self, n): - self.selection = n - if n is None: - self.bDelete.Enable(False) - self.bModify.Enable(False) - else: - self.bDelete.Enable(True) - self.bModify.Enable(True) + def setItemSelected(self, n): + self.selection = n + if n is None: + self.bDelete.Enable(False) + self.bModify.Enable(False) + else: + self.bDelete.Enable(True) + self.bModify.Enable(True) - def getFreePins(self): - freePins = [] + self.validPins - usedPins = [] - for s in self.heaters: - usedPins.append(s[1]) + def getFreePins(self): + freePins = [] + self.validPins + usedPins = [] + for s in self.heaters: + usedPins.append(s[1]) - for p in usedPins: - if p in freePins: - freePins.remove(p) + for p in usedPins: + if p in freePins: + freePins.remove(p) - return freePins + return freePins - def doAdd(self, evt): - nm = [] - for s in self.heaters: - nm.append(s[0]) + def doAdd(self, evt): + nm = [] + for s in self.heaters: + nm.append(s[0]) - dlg = AddHeaterDlg(self, nm, self.getFreePins(), self.font) - rc = dlg.ShowModal() - if rc == wx.ID_OK: - ht = dlg.getValues() + dlg = AddHeaterDlg(self, nm, self.getFreePins(), self.font) + rc = dlg.ShowModal() + if rc == wx.ID_OK: + ht = dlg.getValues() - dlg.Destroy() + dlg.Destroy() - if rc != wx.ID_OK: - return + if rc != wx.ID_OK: + return - self.heaters.append(ht) - self.lb.updateList(self.heaters) - self.validateTable() - self.parent.setHeaters(self.heaters) - self.assertModified(True) + self.heaters.append(ht) + self.lb.updateList(self.heaters) + self.validateTable() + self.parent.setHeaters(self.heaters) + self.assertModified(True) - def doModify(self, evt): - if self.selection is None: - return + def doModify(self, evt): + if self.selection is None: + return - nm = [] - for s in self.heaters: - nm.append(s[0]) + nm = [] + for s in self.heaters: + nm.append(s[0]) - h = self.heaters[self.selection] + h = self.heaters[self.selection] - dlg = AddHeaterDlg(self, nm, [h[1]] + self.getFreePins(), self.font, - name = h[0], pin = h[1], invert = h[2], pwm = h[3], max_pwm = h[4]) - rc = dlg.ShowModal() - if rc == wx.ID_OK: - ht = dlg.getValues() + dlg = AddHeaterDlg( + self, + nm, + [h[1]] + self.getFreePins(), + self.font, + name=h[0], + pin=h[1], + invert=h[2], + pwm=h[3], + max_pwm=h[4], + ) + rc = dlg.ShowModal() + if rc == wx.ID_OK: + ht = dlg.getValues() - dlg.Destroy() + dlg.Destroy() - if rc != wx.ID_OK: - return + if rc != wx.ID_OK: + return - self.heaters[self.selection] = ht - self.lb.updateList(self.heaters) - self.validateTable() - self.parent.setHeaters(self.heaters) - self.assertModified(True) + self.heaters[self.selection] = ht + self.lb.updateList(self.heaters) + self.validateTable() + self.parent.setHeaters(self.heaters) + self.assertModified(True) - def doDelete(self, evt): - if self.selection is None: - return + def doDelete(self, evt): + if self.selection is None: + return - self.assertModified(True) + self.assertModified(True) - del self.heaters[self.selection] - self.lb.updateList(self.heaters) - self.validateTable() - self.parent.setHeaters(self.heaters) - self.assertModified(True) + del self.heaters[self.selection] + self.lb.updateList(self.heaters) + self.validateTable() + self.parent.setHeaters(self.heaters) + self.assertModified(True) - def setHeaters(self, heaters): - self.heaters = heaters - self.lb.updateList(self.heaters) - self.validateTable() - self.parent.setHeaters(self.heaters) + def setHeaters(self, heaters): + self.heaters = heaters + self.lb.updateList(self.heaters) + self.validateTable() + self.parent.setHeaters(self.heaters) - def setCandidatePins(self, plist): - if not plist or len(plist) == 0: - self.validPins = pinNames - else: - self.validPins = plist + def setCandidatePins(self, plist): + if not plist or len(plist) == 0: + self.validPins = pinNames + else: + self.validPins = plist - self.validateTable() + self.validateTable() - def heaterNames(self): - heaterNames = [] - for heater in self.heaters: - heaterNames.append(heater[0]) + def heaterNames(self): + heaterNames = [] + for heater in self.heaters: + heaterNames.append(heater[0]) - return heaterNames + return heaterNames - def validateTable(self): - self.lb.setTableValidity(True) - self.setFieldValidity('HEATERLIST', True) - for i in range(len(self.heaters)): - if self.heaters[i][1] not in self.validPins: - self.lb.setRowValidity(i, False) - self.setFieldValidity('HEATERLIST', False) + def validateTable(self): + self.lb.setTableValidity(True) + self.setFieldValidity("HEATERLIST", True) + for i in range(len(self.heaters)): + if self.heaters[i][1] not in self.validPins: + self.lb.setRowValidity(i, False) + self.setFieldValidity("HEATERLIST", False) - def setHelpText(self, ht): - Page.setHelpText(self, ht) + def setHelpText(self, ht): + Page.setHelpText(self, ht) - k = 'DEFINE_HEATER' - if k in ht.keys(): - self.bAdd.SetToolTip(ht[k]) + k = "DEFINE_HEATER" + if k in ht.keys(): + self.bAdd.SetToolTip(ht[k]) diff --git a/configtool/mechanicalpage.py b/configtool/mechanicalpage.py index 5d57637..9ab1904 100644 --- a/configtool/mechanicalpage.py +++ b/configtool/mechanicalpage.py @@ -1,4 +1,3 @@ - import wx from configtool.data import BSIZE from configtool.page import Page @@ -7,238 +6,264 @@ from configtool.calcscrew import CalcScrew class MechanicalPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.id = idPg - self.parent = parent - self.font = font + def __init__(self, parent, nb, idPg, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.id = idPg + self.parent = parent + self.font = font - self.spmKeys = ['STEPS_PER_M_X', 'STEPS_PER_M_Y', 'STEPS_PER_M_Z', - 'STEPS_PER_M_E'] + self.spmKeys = [ + "STEPS_PER_M_X", + "STEPS_PER_M_Y", + "STEPS_PER_M_Z", + "STEPS_PER_M_E", + ] - self.mfrKeys = ['MAXIMUM_FEEDRATE_X', 'MAXIMUM_FEEDRATE_Y', - 'MAXIMUM_FEEDRATE_Z', 'MAXIMUM_FEEDRATE_E'] + self.mfrKeys = [ + "MAXIMUM_FEEDRATE_X", + "MAXIMUM_FEEDRATE_Y", + "MAXIMUM_FEEDRATE_Z", + "MAXIMUM_FEEDRATE_E", + ] - self.msrKeys = ['SEARCH_FEEDRATE_X', 'SEARCH_FEEDRATE_Y', - 'SEARCH_FEEDRATE_Z'] + self.msrKeys = ["SEARCH_FEEDRATE_X", "SEARCH_FEEDRATE_Y", "SEARCH_FEEDRATE_Z"] - self.eclKeys = ['ENDSTOP_CLEARANCE_X', 'ENDSTOP_CLEARANCE_Y', - 'ENDSTOP_CLEARANCE_Z'] + self.eclKeys = [ + "ENDSTOP_CLEARANCE_X", + "ENDSTOP_CLEARANCE_Y", + "ENDSTOP_CLEARANCE_Z", + ] - self.minmaxKeys = ['X_MIN', 'X_MAX', 'Y_MIN', 'Y_MAX', 'Z_MIN', 'Z_MAX'] + self.minmaxKeys = ["X_MIN", "X_MAX", "Y_MIN", "Y_MAX", "Z_MIN", "Z_MAX"] - self.kinematicsKeys = ['KINEMATICS_STRAIGHT', 'KINEMATICS_COREXY'] + self.kinematicsKeys = ["KINEMATICS_STRAIGHT", "KINEMATICS_COREXY"] - self.homingKeys = [('HOMING_STEP1', 2), ('HOMING_STEP2', 2), - ('HOMING_STEP3', 2), ('HOMING_STEP4', 2)] + self.homingKeys = [ + ("HOMING_STEP1", 2), + ("HOMING_STEP2", 2), + ("HOMING_STEP3", 2), + ("HOMING_STEP4", 2), + ] - self.labels = {'STEPS_PER_M_X': "X:", 'STEPS_PER_M_Y': "Y:", - 'STEPS_PER_M_Z': "Z:", 'STEPS_PER_M_E' : "E:", - 'MAXIMUM_FEEDRATE_X': "X:", 'MAXIMUM_FEEDRATE_Y': "Y:", - 'MAXIMUM_FEEDRATE_Z': "Z:", 'MAXIMUM_FEEDRATE_E': "E:", - 'SEARCH_FEEDRATE_X': "X:", 'SEARCH_FEEDRATE_Y': "Y:", - 'SEARCH_FEEDRATE_Z': "Z:", - 'ENDSTOP_CLEARANCE_X': "X:", 'ENDSTOP_CLEARANCE_Y': "Y:", - 'ENDSTOP_CLEARANCE_Z': "Z:", - 'X_MIN': "Min X:", 'X_MAX': "Max X:", 'Y_MIN': "Min Y:", - 'Y_MAX': "Max Y:", 'Z_MIN': "Min Z:", 'Z_MAX': "Max Z:", - 'E_ABSOLUTE': "Absolute E Coordinates", - 'KINEMATICS_STRAIGHT': "Straight", - 'KINEMATICS_COREXY': "CoreXY", - 'HOMING_STEP1': "Step 1:", - 'HOMING_STEP2': "Step 2:", - 'HOMING_STEP3': "Step 3:", - 'HOMING_STEP4': "Step 4:", - 'none': "-", - 'x_negative': "X min", - 'x_positive': "X max", - 'y_negative': "Y min", - 'y_positive': "Y max", - 'z_negative': "Z min", - 'z_positive': "Z max"} + self.labels = { + "STEPS_PER_M_X": "X:", + "STEPS_PER_M_Y": "Y:", + "STEPS_PER_M_Z": "Z:", + "STEPS_PER_M_E": "E:", + "MAXIMUM_FEEDRATE_X": "X:", + "MAXIMUM_FEEDRATE_Y": "Y:", + "MAXIMUM_FEEDRATE_Z": "Z:", + "MAXIMUM_FEEDRATE_E": "E:", + "SEARCH_FEEDRATE_X": "X:", + "SEARCH_FEEDRATE_Y": "Y:", + "SEARCH_FEEDRATE_Z": "Z:", + "ENDSTOP_CLEARANCE_X": "X:", + "ENDSTOP_CLEARANCE_Y": "Y:", + "ENDSTOP_CLEARANCE_Z": "Z:", + "X_MIN": "Min X:", + "X_MAX": "Max X:", + "Y_MIN": "Min Y:", + "Y_MAX": "Max Y:", + "Z_MIN": "Min Z:", + "Z_MAX": "Max Z:", + "E_ABSOLUTE": "Absolute E Coordinates", + "KINEMATICS_STRAIGHT": "Straight", + "KINEMATICS_COREXY": "CoreXY", + "HOMING_STEP1": "Step 1:", + "HOMING_STEP2": "Step 2:", + "HOMING_STEP3": "Step 3:", + "HOMING_STEP4": "Step 4:", + "none": "-", + "x_negative": "X min", + "x_positive": "X max", + "y_negative": "Y min", + "y_positive": "Y max", + "z_negative": "Z min", + "z_positive": "Z max", + } - labelWidth = 40; - labelWidthHoming = 60; + labelWidth = 40 + labelWidthHoming = 60 - sz = wx.GridBagSizer() - sz.Add((10, 10), pos = (0, 0)) - sz.Add((90, 10), pos = (0, 4)) + sz = wx.GridBagSizer() + sz.Add((10, 10), pos=(0, 0)) + sz.Add((90, 10), pos=(0, 4)) - b = wx.StaticBox(self, wx.ID_ANY, "Steps Per Meter") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k in self.spmKeys: - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sbox.Add(tc) - sbox.Add((5, 5)) + b = wx.StaticBox(self, wx.ID_ANY, "Steps Per Meter") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k in self.spmKeys: + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sbox.Add(tc) + sbox.Add((5, 5)) - sz.Add(sbox, pos = (1, 1)) + sz.Add(sbox, pos=(1, 1)) - b = wx.StaticBox(self, wx.ID_ANY, "Maximum Feedrate") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k in self.mfrKeys: - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sbox.Add(tc) - sbox.Add((5, 5)) + b = wx.StaticBox(self, wx.ID_ANY, "Maximum Feedrate") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k in self.mfrKeys: + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sbox.Add(tc) + sbox.Add((5, 5)) - sz.Add(sbox, pos = (1, 5)) + sz.Add(sbox, pos=(1, 5)) - b = wx.StaticBox(self, wx.ID_ANY, "Search Feedrate") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k in self.msrKeys: - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sbox.Add(tc) - sbox.Add((5, 5)) + b = wx.StaticBox(self, wx.ID_ANY, "Search Feedrate") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k in self.msrKeys: + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sbox.Add(tc) + sbox.Add((5, 5)) - sz.Add(sbox, pos = (1, 7)) + sz.Add(sbox, pos=(1, 7)) - b = wx.StaticBox(self, wx.ID_ANY, "Endstop Clearance") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k in self.eclKeys: - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sbox.Add(tc) - sbox.Add((5, 5)) + b = wx.StaticBox(self, wx.ID_ANY, "Endstop Clearance") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k in self.eclKeys: + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sbox.Add(tc) + sbox.Add((5, 5)) - sz.Add(sbox, pos = (3, 5)) + sz.Add(sbox, pos=(3, 5)) - b = wx.StaticBox(self, wx.ID_ANY, "Travel Limits") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k in self.minmaxKeys: - tc = self.addTextCtrl(k, labelWidth + 20, self.onTextCtrlFloat) - sbox.Add(tc) - sbox.Add((5, 5)) + b = wx.StaticBox(self, wx.ID_ANY, "Travel Limits") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k in self.minmaxKeys: + tc = self.addTextCtrl(k, labelWidth + 20, self.onTextCtrlFloat) + sbox.Add(tc) + sbox.Add((5, 5)) - sz.Add(sbox, pos = (3, 7)) + sz.Add(sbox, pos=(3, 7)) - vsz = wx.BoxSizer(wx.VERTICAL) + vsz = wx.BoxSizer(wx.VERTICAL) - b = wx.StaticBox(self, wx.ID_ANY, "Kinematics") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - style = wx.RB_GROUP - for k in self.kinematicsKeys: - rb = self.addRadioButton(k, style, self.onKinematicsSelect, b) - style = 0 + b = wx.StaticBox(self, wx.ID_ANY, "Kinematics") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + style = wx.RB_GROUP + for k in self.kinematicsKeys: + rb = self.addRadioButton(k, style, self.onKinematicsSelect, b) + style = 0 - sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16) - sbox.Add((5, 5)) + sbox.Add(rb, 1, wx.LEFT + wx.RIGHT, 16) + sbox.Add((5, 5)) - vsz.Add(sbox, 1, wx.LEFT, 10) + vsz.Add(sbox, 1, wx.LEFT, 10) - cb = self.addCheckBox('E_ABSOLUTE', self.onCheckBox) + cb = self.addCheckBox("E_ABSOLUTE", self.onCheckBox) - vsz.Add(cb, 1, wx.LEFT, 10) + vsz.Add(cb, 1, wx.LEFT, 10) - sz.Add(vsz, pos = (3, 1)) + sz.Add(vsz, pos=(3, 1)) - bsz = wx.BoxSizer(wx.VERTICAL) - b = wx.Button(self, wx.ID_ANY, "Calculate\nBelt Driven", size = BSIZE) - b.SetBackgroundColour(self.deco.getBackgroundColour()) - b.SetFont(font) - b.SetToolTip("Open the calculator for axes that are belt-driven.") - self.Bind(wx.EVT_BUTTON, self.onCalcBelt, b) - self.bCalcBelt = b + bsz = wx.BoxSizer(wx.VERTICAL) + b = wx.Button(self, wx.ID_ANY, "Calculate\nBelt Driven", size=BSIZE) + b.SetBackgroundColour(self.deco.getBackgroundColour()) + b.SetFont(font) + b.SetToolTip("Open the calculator for axes that are belt-driven.") + self.Bind(wx.EVT_BUTTON, self.onCalcBelt, b) + self.bCalcBelt = b - bsz.Add(b, 1, wx.ALL, 5) - b = wx.Button(self, wx.ID_ANY, "Calculate\nScrew Driven", size = BSIZE) - b.SetBackgroundColour(self.deco.getBackgroundColour()) - b.SetFont(font) - bsz.Add(b, 1, wx.ALL, 5) - b.SetToolTip("Open the calculator for axes that are screw-driven.") - self.Bind(wx.EVT_BUTTON, self.onCalcScrew, b) - self.bCalcScrew = b + bsz.Add(b, 1, wx.ALL, 5) + b = wx.Button(self, wx.ID_ANY, "Calculate\nScrew Driven", size=BSIZE) + b.SetBackgroundColour(self.deco.getBackgroundColour()) + b.SetFont(font) + bsz.Add(b, 1, wx.ALL, 5) + b.SetToolTip("Open the calculator for axes that are screw-driven.") + self.Bind(wx.EVT_BUTTON, self.onCalcScrew, b) + self.bCalcScrew = b - sz.Add(bsz, pos = (1, 3)) + sz.Add(bsz, pos=(1, 3)) - b = wx.StaticBox(self, wx.ID_ANY, "Homing Order") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k, ctype in self.homingKeys: - if ctype == 2: - tc = self.addChoice(k, [], 0, labelWidthHoming, self.onChoice) - sbox.Add(tc) - sbox.Add((5, 5)) - sz.Add(sbox, pos = (3, 3)) + b = wx.StaticBox(self, wx.ID_ANY, "Homing Order") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k, ctype in self.homingKeys: + if ctype == 2: + tc = self.addChoice(k, [], 0, labelWidthHoming, self.onChoice) + sbox.Add(tc) + sbox.Add((5, 5)) + sz.Add(sbox, pos=(3, 3)) - self.enableAll(False) - self.SetSizer(sz) + self.enableAll(False) + self.SetSizer(sz) - def enableAll(self, flag = True): - self.bCalcBelt.Enable(flag) - self.bCalcScrew.Enable(flag) - Page.enableAll(self, flag) + def enableAll(self, flag=True): + self.bCalcBelt.Enable(flag) + self.bCalcScrew.Enable(flag) + Page.enableAll(self, flag) - def onKinematicsSelect(self, evt): - self.assertModified(True) - evt.Skip() + def onKinematicsSelect(self, evt): + self.assertModified(True) + evt.Skip() - def onCalcBelt(self, evt): - dlg = CalcBelt(self, self.font, self.cbCalcBelt) - dlg.ShowModal() - dlg.Destroy() + def onCalcBelt(self, evt): + dlg = CalcBelt(self, self.font, self.cbCalcBelt) + dlg.ShowModal() + dlg.Destroy() - def cbCalcBelt(self, field, value): - s = "%d" % value - self.textControls[field].SetValue(s) + def cbCalcBelt(self, field, value): + s = "%d" % value + self.textControls[field].SetValue(s) - def onCalcScrew(self, evt): - dlg = CalcScrew(self, self.font, self.cbCalcScrew) - dlg.ShowModal() - dlg.Destroy() + def onCalcScrew(self, evt): + dlg = CalcScrew(self, self.font, self.cbCalcScrew) + dlg.ShowModal() + dlg.Destroy() - def cbCalcScrew(self, field, value): - s = "%d" % value - self.textControls[field].SetValue(s) + def cbCalcScrew(self, field, value): + s = "%d" % value + self.textControls[field].SetValue(s) - def setHelpText(self, ht): - Page.setHelpText(self, ht) - if 'KINEMATICS' in ht.keys(): - for k in self.kinematicsKeys: - self.radioButtons[k].SetToolTip(ht['KINEMATICS']) + def setHelpText(self, ht): + Page.setHelpText(self, ht) + if "KINEMATICS" in ht.keys(): + for k in self.kinematicsKeys: + self.radioButtons[k].SetToolTip(ht["KINEMATICS"]) - def prepareHomingValues(self, name, i, cfgValues): - self.choices[name].Clear() - for p in cfgValues['HOMING_OPTS']: - self.choices[name].Append(self.labels[p]) - i = cfgValues['HOMING_OPTS'].index(cfgValues[name]) - self.choices[name].SetSelection(i) + def prepareHomingValues(self, name, i, cfgValues): + self.choices[name].Clear() + for p in cfgValues["HOMING_OPTS"]: + self.choices[name].Append(self.labels[p]) + i = cfgValues["HOMING_OPTS"].index(cfgValues[name]) + self.choices[name].SetSelection(i) - def insertValues(self, cfgValues): - Page.insertValues(self, cfgValues) + def insertValues(self, cfgValues): + Page.insertValues(self, cfgValues) - self.prepareHomingValues('HOMING_STEP1', 0, cfgValues) - self.prepareHomingValues('HOMING_STEP2', 1, cfgValues) - self.prepareHomingValues('HOMING_STEP3', 2, cfgValues) - self.prepareHomingValues('HOMING_STEP4', 3, cfgValues) + self.prepareHomingValues("HOMING_STEP1", 0, cfgValues) + self.prepareHomingValues("HOMING_STEP2", 1, cfgValues) + self.prepareHomingValues("HOMING_STEP3", 2, cfgValues) + self.prepareHomingValues("HOMING_STEP4", 3, cfgValues) - for tag in self.kinematicsKeys: - if tag in cfgValues.keys() and cfgValues[tag]: - self.radioButtons[tag].SetValue(True) + for tag in self.kinematicsKeys: + if tag in cfgValues.keys() and cfgValues[tag]: + self.radioButtons[tag].SetValue(True) - def getHomingValue(self, name, result): - return (self.labels.keys()[self.labels.values().index(result[name][0])], True) + def getHomingValue(self, name, result): + return (self.labels.keys()[self.labels.values().index(result[name][0])], True) - def getValues(self): - result = Page.getValues(self) + def getValues(self): + result = Page.getValues(self) - for tag in self.kinematicsKeys: - result[tag] = self.radioButtons[tag].GetValue() + for tag in self.kinematicsKeys: + result[tag] = self.radioButtons[tag].GetValue() - result['HOMING_STEP1'] = self.getHomingValue('HOMING_STEP1', result) - result['HOMING_STEP2'] = self.getHomingValue('HOMING_STEP2', result) - result['HOMING_STEP3'] = self.getHomingValue('HOMING_STEP3', result) - result['HOMING_STEP4'] = self.getHomingValue('HOMING_STEP4', result) + result["HOMING_STEP1"] = self.getHomingValue("HOMING_STEP1", result) + result["HOMING_STEP2"] = self.getHomingValue("HOMING_STEP2", result) + result["HOMING_STEP3"] = self.getHomingValue("HOMING_STEP3", result) + result["HOMING_STEP4"] = self.getHomingValue("HOMING_STEP4", result) - return result + return result diff --git a/configtool/miscellaneouspage.py b/configtool/miscellaneouspage.py index 5f517ad..98f9c4e 100644 --- a/configtool/miscellaneouspage.py +++ b/configtool/miscellaneouspage.py @@ -1,233 +1,240 @@ - import wx from configtool.page import Page from configtool.data import reFloat class MiscellaneousPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.parent = parent - self.id = idPg - self.font = font + def __init__(self, parent, nb, idPg, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.parent = parent + self.id = idPg + self.font = font - self.labels = {'USE_INTERNAL_PULLUPS': "Use Internal Pullups", - 'BED_LEVELING': "Enable dynamic bed leveling", - 'Z_AUTODISABLE': "Z Autodisable", - 'EECONFIG': "Enable EEPROM Storage", - 'BANG_BANG': "Enable", - 'BANG_BANG_ON': "On PWM Level:", - 'BANG_BANG_OFF': "Off PWM Level:", - 'REPORT_TARGET_TEMPS': "Report Target Temperatures", - 'MOVEBUFFER_SIZE': "Movebuffer Size:", - 'DC_EXTRUDER': "Heater:", 'DC_EXTRUDER_PWM': "PWM:", - 'USE_WATCHDOG': "Use the Watchdog Timer", - 'TH_COUNT': "Temperature History Size:", - 'FAST_PWM': "Fast PWM", - 'ENDSTOP_STEPS': "Endstop Steps:", - 'PID_SCALE': "PID Scaling Factor:", - 'TEMP_HYSTERESIS': "Temperature Hysteresis:", - 'TEMP_RESIDENCY_TIME': "Temperature Residency Time:", - 'TEMP_EWMA': "Temperature EWMA:", - 'HEATER_SANITY_CHECK': "Heater Sanity Check"} + self.labels = { + "USE_INTERNAL_PULLUPS": "Use Internal Pullups", + "BED_LEVELING": "Enable dynamic bed leveling", + "Z_AUTODISABLE": "Z Autodisable", + "EECONFIG": "Enable EEPROM Storage", + "BANG_BANG": "Enable", + "BANG_BANG_ON": "On PWM Level:", + "BANG_BANG_OFF": "Off PWM Level:", + "REPORT_TARGET_TEMPS": "Report Target Temperatures", + "MOVEBUFFER_SIZE": "Movebuffer Size:", + "DC_EXTRUDER": "Heater:", + "DC_EXTRUDER_PWM": "PWM:", + "USE_WATCHDOG": "Use the Watchdog Timer", + "TH_COUNT": "Temperature History Size:", + "FAST_PWM": "Fast PWM", + "ENDSTOP_STEPS": "Endstop Steps:", + "PID_SCALE": "PID Scaling Factor:", + "TEMP_HYSTERESIS": "Temperature Hysteresis:", + "TEMP_RESIDENCY_TIME": "Temperature Residency Time:", + "TEMP_EWMA": "Temperature EWMA:", + "HEATER_SANITY_CHECK": "Heater Sanity Check", + } - self.heaterNameNone = "" - self.heaterNames = [self.heaterNameNone] - self.boardHeaters = [] - self.processors = [] + self.heaterNameNone = "" + self.heaterNames = [self.heaterNameNone] + self.boardHeaters = [] + self.processors = [] - sz = wx.GridBagSizer() - sz.Add((20, 40), pos = (0, 0)) - sz.Add((40, 40), pos = (0, 2)) - sz.Add((40, 40), pos = (0, 4)) - sz.Add((20, 30), pos = (1, 0)) - sz.Add((20, 30), pos = (2, 0)) - sz.Add((20, 30), pos = (3, 0)) - sz.Add((20, 30), pos = (4, 0)) - sz.Add((20, 30), pos = (5, 0)) - sz.Add((20, 30), pos = (6, 0)) - sz.Add((20, 30), pos = (7, 0)) - sz.Add((20, 30), pos = (8, 0)) + sz = wx.GridBagSizer() + sz.Add((20, 40), pos=(0, 0)) + sz.Add((40, 40), pos=(0, 2)) + sz.Add((40, 40), pos=(0, 4)) + sz.Add((20, 30), pos=(1, 0)) + sz.Add((20, 30), pos=(2, 0)) + sz.Add((20, 30), pos=(3, 0)) + sz.Add((20, 30), pos=(4, 0)) + sz.Add((20, 30), pos=(5, 0)) + sz.Add((20, 30), pos=(6, 0)) + sz.Add((20, 30), pos=(7, 0)) + sz.Add((20, 30), pos=(8, 0)) - labelWidth = 140 + labelWidth = 140 - k = 'EECONFIG' - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (1, 1)) + k = "EECONFIG" + cb = self.addCheckBox(k, self.onCheckBox) + sz.Add(cb, pos=(1, 1)) - k = 'USE_INTERNAL_PULLUPS' - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (2, 1)) + k = "USE_INTERNAL_PULLUPS" + cb = self.addCheckBox(k, self.onCheckBox) + sz.Add(cb, pos=(2, 1)) - k = 'USE_WATCHDOG' - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (3, 1)) + k = "USE_WATCHDOG" + cb = self.addCheckBox(k, self.onCheckBox) + sz.Add(cb, pos=(3, 1)) - k = 'FAST_PWM' - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (4, 1)) + k = "FAST_PWM" + cb = self.addCheckBox(k, self.onCheckBox) + sz.Add(cb, pos=(4, 1)) - k = 'HEATER_SANITY_CHECK' - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (5, 1)) + k = "HEATER_SANITY_CHECK" + cb = self.addCheckBox(k, self.onCheckBox) + sz.Add(cb, pos=(5, 1)) - k = 'REPORT_TARGET_TEMPS' - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (6, 1)) + k = "REPORT_TARGET_TEMPS" + cb = self.addCheckBox(k, self.onCheckBox) + sz.Add(cb, pos=(6, 1)) - k = 'Z_AUTODISABLE' - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (7, 1)) + k = "Z_AUTODISABLE" + cb = self.addCheckBox(k, self.onCheckBox) + sz.Add(cb, pos=(7, 1)) - k = 'BED_LEVELING' - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (8, 1)) + k = "BED_LEVELING" + cb = self.addCheckBox(k, self.onCheckBox) + sz.Add(cb, pos=(8, 1)) - b = wx.StaticBox(self, wx.ID_ANY, "BANG BANG Bed Control") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) + b = wx.StaticBox(self, wx.ID_ANY, "BANG BANG Bed Control") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) - k = 'BANG_BANG' - cb = self.addCheckBox(k, self.onCheckBox) - sbox.Add(cb, 1, wx.LEFT, 60) - sbox.Add((5, 20)) + k = "BANG_BANG" + cb = self.addCheckBox(k, self.onCheckBox) + sbox.Add(cb, 1, wx.LEFT, 60) + sbox.Add((5, 20)) - k = 'BANG_BANG_ON' - tc = self.addTextCtrl(k, 100, self.onTextCtrlInteger) - sbox.Add(tc) - sbox.Add((5, 5)) + k = "BANG_BANG_ON" + tc = self.addTextCtrl(k, 100, self.onTextCtrlInteger) + sbox.Add(tc) + sbox.Add((5, 5)) - k = 'BANG_BANG_OFF' - tc = self.addTextCtrl(k, 100, self.onTextCtrlInteger) - sbox.Add(tc) - sbox.Add((5, 5)) + k = "BANG_BANG_OFF" + tc = self.addTextCtrl(k, 100, self.onTextCtrlInteger) + sbox.Add(tc) + sbox.Add((5, 5)) - sz.Add(sbox, pos = (1, 3), span = (5, 1), flag = wx.ALIGN_CENTER_HORIZONTAL) + sz.Add(sbox, pos=(1, 3), span=(5, 1), flag=wx.ALIGN_CENTER_HORIZONTAL) - b = wx.StaticBox(self, wx.ID_ANY, "DC Motor Extruder") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) + b = wx.StaticBox(self, wx.ID_ANY, "DC Motor Extruder") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) - k = 'DC_EXTRUDER' - ch = self.addChoice(k, self.heaterNames, 0, 60, self.onChoice) - sbox.Add(ch) - sbox.Add((5, 5)) + k = "DC_EXTRUDER" + ch = self.addChoice(k, self.heaterNames, 0, 60, self.onChoice) + sbox.Add(ch) + sbox.Add((5, 5)) - k = 'DC_EXTRUDER_PWM' - tc = self.addTextCtrl(k, 60, self.onTextCtrlInteger) - sbox.Add(tc) - sbox.Add((5, 5)) + k = "DC_EXTRUDER_PWM" + tc = self.addTextCtrl(k, 60, self.onTextCtrlInteger) + sbox.Add(tc) + sbox.Add((5, 5)) - sz.Add(sbox, pos = (6, 3), span=(3, 1), flag = wx.ALIGN_CENTER_HORIZONTAL) + sz.Add(sbox, pos=(6, 3), span=(3, 1), flag=wx.ALIGN_CENTER_HORIZONTAL) - labelWidth = 190; + labelWidth = 190 - k = 'MOVEBUFFER_SIZE' - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sz.Add(tc, pos = (1, 5)) + k = "MOVEBUFFER_SIZE" + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sz.Add(tc, pos=(1, 5)) - k = 'TH_COUNT' - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sz.Add(tc, pos = (2, 5)) + k = "TH_COUNT" + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sz.Add(tc, pos=(2, 5)) - k = 'ENDSTOP_STEPS' - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sz.Add(tc, pos = (3, 5)) + k = "ENDSTOP_STEPS" + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sz.Add(tc, pos=(3, 5)) - k = 'PID_SCALE' - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sz.Add(tc, pos = (4, 5)) + k = "PID_SCALE" + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sz.Add(tc, pos=(4, 5)) - k = 'TEMP_HYSTERESIS' - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sz.Add(tc, pos = (6, 5)) + k = "TEMP_HYSTERESIS" + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sz.Add(tc, pos=(6, 5)) - k = 'TEMP_RESIDENCY_TIME' - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sz.Add(tc, pos = (7, 5)) + k = "TEMP_RESIDENCY_TIME" + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sz.Add(tc, pos=(7, 5)) - k = 'TEMP_EWMA' - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) - sz.Add(tc, pos = (8, 5)) + k = "TEMP_EWMA" + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlInteger) + sz.Add(tc, pos=(8, 5)) - self.SetSizer(sz) - self.enableAll(False) + self.SetSizer(sz) + self.enableAll(False) - def setHeaters(self, hlist): - k = 'DC_EXTRUDER' - v = self.choices[k].GetSelection() - currentChoice = self.heaterNames[v] - self.boardHeaters = [s[0] for s in hlist] - self.heaterNames = [self.heaterNameNone] + self.boardHeaters - self.choices[k].Clear() - self.choices[k].SetFont(self.font) - for h in self.heaterNames: - self.choices[k].Append(h) + def setHeaters(self, hlist): + k = "DC_EXTRUDER" + v = self.choices[k].GetSelection() + currentChoice = self.heaterNames[v] + self.boardHeaters = [s[0] for s in hlist] + self.heaterNames = [self.heaterNameNone] + self.boardHeaters + self.choices[k].Clear() + self.choices[k].SetFont(self.font) + for h in self.heaterNames: + self.choices[k].Append(h) - try: - v = self.heaterNames.index(currentChoice) - except: - v = 0 - dlg = wx.MessageDialog(self, - "Printer: Miscellaneous tab:\nDC Extruder heater " - "\"%s\" not defined for this board. Please check." - % currentChoice, "Warning", - wx.OK + wx.ICON_WARNING) + try: + v = self.heaterNames.index(currentChoice) + except: + v = 0 + dlg = wx.MessageDialog( + self, + "Printer: Miscellaneous tab:\nDC Extruder heater " + '"%s" not defined for this board. Please check.' % currentChoice, + "Warning", + wx.OK + wx.ICON_WARNING, + ) - dlg.ShowModal() - dlg.Destroy() + dlg.ShowModal() + dlg.Destroy() - self.choices[k].SetSelection(v) + self.choices[k].SetSelection(v) - def setOriginalHeater(self, h): - k = 'DC_EXTRUDER' - if h and h.startswith("HEATER_"): - hname = h[len("HEATER_"):] - else: - hname = h - if hname and len(self.boardHeaters) != 0: - if hname not in self.boardHeaters: - dlg = wx.MessageDialog(self, - "Printer: Miscellaneous tab:\nDC Extruder " - "heater \"%s\" not defined for this board. " - "Please check." - % hname, "Warning", wx.OK + wx.ICON_WARNING) + def setOriginalHeater(self, h): + k = "DC_EXTRUDER" + if h and h.startswith("HEATER_"): + hname = h[len("HEATER_") :] + else: + hname = h + if hname and len(self.boardHeaters) != 0: + if hname not in self.boardHeaters: + dlg = wx.MessageDialog( + self, + "Printer: Miscellaneous tab:\nDC Extruder " + 'heater "%s" not defined for this board. ' + "Please check." % hname, + "Warning", + wx.OK + wx.ICON_WARNING, + ) - dlg.ShowModal() - dlg.Destroy() - self.heaterNames = [self.heaterNameNone] + self.boardHeaters - else: - self.heaterNames = [self.heaterNameNone] - if hname and hname != self.heaterNameNone: - self.heaterNames.append(hname) - self.choices[k].Clear() - self.choices[k].SetFont(self.font) - for ht in self.heaterNames: - self.choices[k].Append(ht) - if hname: - try: - v = self.heaterNames.index(hname) - except: - v = 0 - else: - v = 0 - self.choices[k].SetSelection(v) + dlg.ShowModal() + dlg.Destroy() + self.heaterNames = [self.heaterNameNone] + self.boardHeaters + else: + self.heaterNames = [self.heaterNameNone] + if hname and hname != self.heaterNameNone: + self.heaterNames.append(hname) + self.choices[k].Clear() + self.choices[k].SetFont(self.font) + for ht in self.heaterNames: + self.choices[k].Append(ht) + if hname: + try: + v = self.heaterNames.index(hname) + except: + v = 0 + else: + v = 0 + self.choices[k].SetSelection(v) - def getValues(self): - result = Page.getValues(self) + def getValues(self): + result = Page.getValues(self) - k = 'DC_EXTRUDER' - s = self.choices[k].GetSelection() - v = self.choices[k].GetString(s) - if v == self.heaterNameNone: - if k in self.choicesOriginal.keys(): - result[k] = self.choicesOriginal[k][0], False - else: - result[k] = "", False - else: - result[k] = "HEATER_%s" % v, True + k = "DC_EXTRUDER" + s = self.choices[k].GetSelection() + v = self.choices[k].GetString(s) + if v == self.heaterNameNone: + if k in self.choicesOriginal.keys(): + result[k] = self.choicesOriginal[k][0], False + else: + result[k] = "", False + else: + result[k] = "HEATER_%s" % v, True - return result + return result diff --git a/configtool/page.py b/configtool/page.py index 5daf22c..f6fc4f7 100644 --- a/configtool/page.py +++ b/configtool/page.py @@ -3,352 +3,370 @@ from __future__ import print_function import wx from configtool.decoration import Decoration -from configtool.data import (reInteger, reFloat, offsetChLabel, offsetTcLabel, - pinNames) +from configtool.data import reInteger, reFloat, offsetChLabel, offsetTcLabel, pinNames class Page: - def __init__(self, font): - self.modified = False - self.valid = True - self.fieldValid = {} - self.textControls = {} - self.textControlsOriginal = {} - self.checkBoxes = {} - self.radioButtons = {} - self.radioButtonBoxes = {} - self.choices = {} - self.choicesOriginal = {} - self.boolChoices = {} - self.deco = Decoration() - self.font = font + def __init__(self, font): + self.modified = False + self.valid = True + self.fieldValid = {} + self.textControls = {} + self.textControlsOriginal = {} + self.checkBoxes = {} + self.radioButtons = {} + self.radioButtonBoxes = {} + self.choices = {} + self.choicesOriginal = {} + self.boolChoices = {} + self.deco = Decoration() + self.font = font - self.SetBackgroundColour(self.deco.getBackgroundColour()) - self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground) + self.SetBackgroundColour(self.deco.getBackgroundColour()) + self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground) - def enableAll(self, flag = True): - for c in self.textControls.keys(): - self.textControls[c].Enable(flag) - for c in self.checkBoxes.keys(): - self.checkBoxes[c].Enable(flag) - for c in self.radioButtons.keys(): - self.radioButtons[c].Enable(flag) - for c in self.choices.keys(): - self.choices[c].Enable(flag) + def enableAll(self, flag=True): + for c in self.textControls.keys(): + self.textControls[c].Enable(flag) + for c in self.checkBoxes.keys(): + self.checkBoxes[c].Enable(flag) + for c in self.radioButtons.keys(): + self.radioButtons[c].Enable(flag) + for c in self.choices.keys(): + self.choices[c].Enable(flag) - def addTextCtrl(self, name, labelWidth, validator): - 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, 1, wx.TOP, offsetTcLabel) + def addTextCtrl(self, name, labelWidth, validator): + 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, 1, wx.TOP, offsetTcLabel) - tc = wx.TextCtrl(self, wx.ID_ANY, "", style = wx.TE_RIGHT, name = name) - tc.SetFont(self.font) - self.fieldValid[name] = True - tc.Bind(wx.EVT_TEXT, validator) - self.textControls[name] = tc - lsz.Add(tc) + tc = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_RIGHT, name=name) + tc.SetFont(self.font) + self.fieldValid[name] = True + tc.Bind(wx.EVT_TEXT, validator) + self.textControls[name] = tc + lsz.Add(tc) - return lsz + return lsz - def addCheckBox(self, name, validator): - if name in self.labels.keys(): - lbl = self.labels[name] - else: - lbl = name - cb = wx.CheckBox(self, wx.ID_ANY, lbl) - cb.SetFont(self.font) - cb.Bind(wx.EVT_CHECKBOX, validator) - self.checkBoxes[name] = cb - - return cb - - def addRadioButton(self, name, style, validator, sbox = None): - rb = wx.RadioButton(self, wx.ID_ANY, self.labels[name], style = style) - rb.SetFont(self.font) - self.Bind(wx.EVT_RADIOBUTTON, validator, rb) - self.radioButtons[name] = rb - if sbox is not None: - self.radioButtonBoxes[name] = sbox - - return rb - - 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, 1, wx.TOP, offsetChLabel) - - ch = wx.Choice(self, wx.ID_ANY, choices = choices, size = size, name = name) - ch.SetBackgroundColour(self.deco.getBackgroundColour()) - ch.SetFont(self.font) - ch.Bind(wx.EVT_CHOICE, validator) - ch.SetSelection(selection) - lsz.Add(ch) - self.choices[name] = ch - - return lsz - - def addPinChoice(self, name, labelWidth): - 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, 1, wx.TOP, offsetChLabel) - - ch = wx.Choice(self, wx.ID_ANY, name = name, style = wx.CB_SORT) - ch.SetBackgroundColour(self.deco.getBackgroundColour()) - ch.SetFont(self.font) - ch.AppendItems(["-"] + pinNames) - ch.Bind(wx.EVT_CHOICE, self.onChoice) - self.choices[name] = ch - lsz.Add(ch) - - return lsz - - # addChoice handles #defines with value, this handles choices for - # sets of boolean #defines. - def addBoolChoice(self, name, allowBlank, 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, 1, wx.TOP, offsetChLabel) - - ch = wx.Choice(self, wx.ID_ANY, size = size, name = name) - ch.SetBackgroundColour(self.deco.getBackgroundColour()) - ch.SetFont(self.font) - ch.Bind(wx.EVT_CHOICE, validator) - - if allowBlank: - ch.Append("(none)") - ch.SetSelection(0) - - lsz.Add(ch) - self.boolChoices[name] = ch - - return lsz - - def setChoice(self, name, cfgValues, default): - if name in cfgValues.keys() and cfgValues[name][1] == True: - bv = cfgValues[name][0] - else: - bv = default - - s = self.choices[name].FindString(bv) - if s < 0: - s = self.choices[name].FindString(default) - if s < 0: - s = 0 - - self.choices[name].SetSelection(s) - - def onTextCtrlInteger(self, evt): - self.assertModified(True) - tc = evt.GetEventObject() - name = tc.GetName() - w = tc.GetValue().strip() - if w == "": - valid = True - else: - m = reInteger.match(w) - if m: - valid = True - else: - valid = False - - self.setFieldValidity(name, valid) - - if valid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() - evt.Skip() - - def onTextCtrlFloat(self, evt): - self.assertModified(True) - tc = evt.GetEventObject() - name = tc.GetName() - w = tc.GetValue().strip() - if w == "": - valid = True - else: - m = reFloat.match(w) - if m: - valid = True - else: - valid = False - - self.setFieldValidity(name, valid) - - if valid: - tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - else: - tc.SetBackgroundColour("pink") - tc.Refresh() - evt.Skip() - - def onTextCtrlPin(self, evt): - self.assertModified(True) - tc = evt.GetEventObject() - self.validatePin(tc) - evt.Skip() - - def onTextCtrl(self, evt): - self.assertModified(True) - evt.Skip() - - def onChoice(self, evt): - self.assertModified(True) - evt.Skip() - - def onCheckBox(self, evt): - self.assertModified(True) - evt.Skip() - - def setHelpText(self, ht): - for k in self.textControls.keys(): - if k in ht.keys(): - self.textControls[k].SetToolTip(ht[k]) - - for k in self.checkBoxes.keys(): - if k in ht.keys(): - self.checkBoxes[k].SetToolTip(ht[k]) - - for k in self.radioButtons.keys(): - if k in ht.keys(): - self.radioButtons[k].SetToolTip(ht[k]) - if k in self.radioButtonBoxes.keys(): - self.radioButtonBoxes[k].SetToolTip(ht[k]) - - for k in self.choices.keys(): - if k in ht.keys(): - self.choices[k].SetToolTip(ht[k]) - - for k in self.boolChoices.keys(): - for candidate in ht.keys(): - if candidate.startswith(k): - self.boolChoices[k].SetToolTip(ht[candidate]) - break - - def insertValues(self, cfgValues): - self.assertValid(True) - self.enableAll(True) - for k in self.fieldValid.keys(): - self.fieldValid[k] = True - - for k in self.checkBoxes.keys(): - if k in cfgValues.keys() and cfgValues[k]: - self.checkBoxes[k].SetValue(True) - else: - self.checkBoxes[k].SetValue(False) - - for k in self.textControls.keys(): - if k in cfgValues.keys(): - self.textControlsOriginal[k] = cfgValues[k] - if cfgValues[k][1] == True: - self.textControls[k].SetValue(str(cfgValues[k][0])) + def addCheckBox(self, name, validator): + if name in self.labels.keys(): + lbl = self.labels[name] else: - self.textControls[k].SetValue("") - else: - print("Key " + k + " not found in config data.") + lbl = name + cb = wx.CheckBox(self, wx.ID_ANY, lbl) + cb.SetFont(self.font) + cb.Bind(wx.EVT_CHECKBOX, validator) + self.checkBoxes[name] = cb - for k in self.choices.keys(): - if k in cfgValues.keys(): - self.choicesOriginal[k] = cfgValues[k] - self.setChoice(k, cfgValues, "-") - else: - print("Key " + k + " not found in config data.") + return cb - for k in self.boolChoices.keys(): - choice = self.boolChoices[k] + def addRadioButton(self, name, style, validator, sbox=None): + rb = wx.RadioButton(self, wx.ID_ANY, self.labels[name], style=style) + rb.SetFont(self.font) + self.Bind(wx.EVT_RADIOBUTTON, validator, rb) + self.radioButtons[name] = rb + if sbox is not None: + self.radioButtonBoxes[name] = sbox - # Remove items left behind from the previous configuration. - while (choice.GetCount() and - not choice.GetString(choice.GetCount() - 1).startswith('(')): - choice.Delete(choice.GetCount() - 1) + return rb - # Add items found in this configuration. - for cfg in cfgValues.keys(): - if cfg.startswith(k): - if cfg in self.labels.keys(): - choice.Append(self.labels[cfg]) - else: - choice.Append(cfg) + 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, 1, wx.TOP, offsetChLabel) - # As we want to write the configuration name later, not the user - # friendly string, we store the configuration name as client data. - n = choice.GetCount() - 1 - choice.SetClientData(n, cfg) + ch = wx.Choice(self, wx.ID_ANY, choices=choices, size=size, name=name) + ch.SetBackgroundColour(self.deco.getBackgroundColour()) + ch.SetFont(self.font) + ch.Bind(wx.EVT_CHOICE, validator) + ch.SetSelection(selection) + lsz.Add(ch) + self.choices[name] = ch - if cfgValues[cfg]: - choice.SetSelection(n) + return lsz - self.assertModified(False) + def addPinChoice(self, name, labelWidth): + 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, 1, wx.TOP, offsetChLabel) - def getValues(self): - self.assertModified(False) - result = {} + ch = wx.Choice(self, wx.ID_ANY, name=name, style=wx.CB_SORT) + ch.SetBackgroundColour(self.deco.getBackgroundColour()) + ch.SetFont(self.font) + ch.AppendItems(["-"] + pinNames) + ch.Bind(wx.EVT_CHOICE, self.onChoice) + self.choices[name] = ch + lsz.Add(ch) - for k in self.checkBoxes.keys(): - cb = self.checkBoxes[k] - result[k] = cb.IsChecked() + return lsz - for k in self.textControls.keys(): - v = self.textControls[k].GetValue() - if v == "": - if k in self.textControlsOriginal.keys(): - result[k] = self.textControlsOriginal[k][0], False + # addChoice handles #defines with value, this handles choices for + # sets of boolean #defines. + def addBoolChoice(self, name, allowBlank, 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, 1, wx.TOP, offsetChLabel) + + ch = wx.Choice(self, wx.ID_ANY, size=size, name=name) + ch.SetBackgroundColour(self.deco.getBackgroundColour()) + ch.SetFont(self.font) + ch.Bind(wx.EVT_CHOICE, validator) + + if allowBlank: + ch.Append("(none)") + ch.SetSelection(0) + + lsz.Add(ch) + self.boolChoices[name] = ch + + return lsz + + def setChoice(self, name, cfgValues, default): + if name in cfgValues.keys() and cfgValues[name][1] == True: + bv = cfgValues[name][0] else: - result[k] = "", False - else: - result[k] = v, True + bv = default - for k in self.radioButtons.keys(): - result[k] = self.radioButtons[k].GetValue(), True + s = self.choices[name].FindString(bv) + if s < 0: + s = self.choices[name].FindString(default) + if s < 0: + s = 0 - for k in self.choices.keys(): - v = self.choices[k].GetSelection() - s = self.choices[k].GetString(v) - if s == "-": - if k in self.choicesOriginal.keys(): - result[k] = self.choicesOriginal[k][0], False + self.choices[name].SetSelection(s) + + def onTextCtrlInteger(self, evt): + self.assertModified(True) + tc = evt.GetEventObject() + name = tc.GetName() + w = tc.GetValue().strip() + if w == "": + valid = True else: - result[k] = "", False - else: - result[k] = s, True + m = reInteger.match(w) + if m: + valid = True + else: + valid = False - for k in self.boolChoices.keys(): - choice = self.boolChoices[k] - for i in range(choice.GetCount()): - s = choice.GetClientData(i) - if s: - result[s] = (i == choice.GetSelection()) + self.setFieldValidity(name, valid) - return result + if valid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() + evt.Skip() - def assertModified(self, flag): - if flag != self.modified: - self.parent.assertModified(self.id, flag) - self.modified = flag + def onTextCtrlFloat(self, evt): + self.assertModified(True) + tc = evt.GetEventObject() + name = tc.GetName() + w = tc.GetValue().strip() + if w == "": + valid = True + else: + m = reFloat.match(w) + if m: + valid = True + else: + valid = False - def setFieldValidity(self, name, flag): - self.fieldValid[name] = flag + self.setFieldValidity(name, valid) - pgValid = True - for k in self.fieldValid.keys(): - if not self.fieldValid[k]: - pgValid = False - break + if valid: + tc.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) + else: + tc.SetBackgroundColour("pink") + tc.Refresh() + evt.Skip() - self.assertValid(pgValid) + def onTextCtrlPin(self, evt): + self.assertModified(True) + tc = evt.GetEventObject() + self.validatePin(tc) + evt.Skip() - def assertValid(self, flag): - if flag != self.valid: - self.parent.assertValid(self.id, flag) - self.valid = flag + def onTextCtrl(self, evt): + self.assertModified(True) + evt.Skip() + + def onChoice(self, evt): + self.assertModified(True) + evt.Skip() + + def onCheckBox(self, evt): + self.assertModified(True) + evt.Skip() + + def setHelpText(self, ht): + for k in self.textControls.keys(): + if k in ht.keys(): + self.textControls[k].SetToolTip(ht[k]) + + for k in self.checkBoxes.keys(): + if k in ht.keys(): + self.checkBoxes[k].SetToolTip(ht[k]) + + for k in self.radioButtons.keys(): + if k in ht.keys(): + self.radioButtons[k].SetToolTip(ht[k]) + if k in self.radioButtonBoxes.keys(): + self.radioButtonBoxes[k].SetToolTip(ht[k]) + + for k in self.choices.keys(): + if k in ht.keys(): + self.choices[k].SetToolTip(ht[k]) + + for k in self.boolChoices.keys(): + for candidate in ht.keys(): + if candidate.startswith(k): + self.boolChoices[k].SetToolTip(ht[candidate]) + break + + def insertValues(self, cfgValues): + self.assertValid(True) + self.enableAll(True) + for k in self.fieldValid.keys(): + self.fieldValid[k] = True + + for k in self.checkBoxes.keys(): + if k in cfgValues.keys() and cfgValues[k]: + self.checkBoxes[k].SetValue(True) + else: + self.checkBoxes[k].SetValue(False) + + for k in self.textControls.keys(): + if k in cfgValues.keys(): + self.textControlsOriginal[k] = cfgValues[k] + if cfgValues[k][1] == True: + self.textControls[k].SetValue(str(cfgValues[k][0])) + else: + self.textControls[k].SetValue("") + else: + print("Key " + k + " not found in config data.") + + for k in self.choices.keys(): + if k in cfgValues.keys(): + self.choicesOriginal[k] = cfgValues[k] + self.setChoice(k, cfgValues, "-") + else: + print("Key " + k + " not found in config data.") + + for k in self.boolChoices.keys(): + choice = self.boolChoices[k] + + # Remove items left behind from the previous configuration. + while choice.GetCount() and not choice.GetString( + choice.GetCount() - 1 + ).startswith("("): + choice.Delete(choice.GetCount() - 1) + + # Add items found in this configuration. + for cfg in cfgValues.keys(): + if cfg.startswith(k): + if cfg in self.labels.keys(): + choice.Append(self.labels[cfg]) + else: + choice.Append(cfg) + + # As we want to write the configuration name later, not the user + # friendly string, we store the configuration name as client data. + n = choice.GetCount() - 1 + choice.SetClientData(n, cfg) + + if cfgValues[cfg]: + choice.SetSelection(n) + + self.assertModified(False) + + def getValues(self): + self.assertModified(False) + result = {} + + for k in self.checkBoxes.keys(): + cb = self.checkBoxes[k] + result[k] = cb.IsChecked() + + for k in self.textControls.keys(): + v = self.textControls[k].GetValue() + if v == "": + if k in self.textControlsOriginal.keys(): + result[k] = self.textControlsOriginal[k][0], False + else: + result[k] = "", False + else: + result[k] = v, True + + for k in self.radioButtons.keys(): + result[k] = self.radioButtons[k].GetValue(), True + + for k in self.choices.keys(): + v = self.choices[k].GetSelection() + s = self.choices[k].GetString(v) + if s == "-": + if k in self.choicesOriginal.keys(): + result[k] = self.choicesOriginal[k][0], False + else: + result[k] = "", False + else: + result[k] = s, True + + for k in self.boolChoices.keys(): + choice = self.boolChoices[k] + for i in range(choice.GetCount()): + s = choice.GetClientData(i) + if s: + result[s] = i == choice.GetSelection() + + return result + + def assertModified(self, flag): + if flag != self.modified: + self.parent.assertModified(self.id, flag) + self.modified = flag + + def setFieldValidity(self, name, flag): + self.fieldValid[name] = flag + + pgValid = True + for k in self.fieldValid.keys(): + if not self.fieldValid[k]: + pgValid = False + break + + self.assertValid(pgValid) + + def assertValid(self, flag): + if flag != self.valid: + self.parent.assertValid(self.id, flag) + self.valid = flag diff --git a/configtool/pinoutspage.py b/configtool/pinoutspage.py index 4c2e631..8b1b0cc 100644 --- a/configtool/pinoutspage.py +++ b/configtool/pinoutspage.py @@ -1,183 +1,211 @@ - import wx from configtool.page import Page class PinoutsPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.parent = parent - self.id = idPg + def __init__(self, parent, nb, idPg, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.parent = parent + self.id = idPg - pinXkeys = [('X_STEP_PIN', 2), ('X_DIR_PIN', 2), ('X_MIN_PIN', 2), - ('X_MAX_PIN', 2), ('X_ENABLE_PIN', 2), ('X_INVERT_DIR', 1), - ('X_INVERT_MIN', 1), ('X_INVERT_MAX', 1), - ('X_INVERT_ENABLE', 1)] - pinYkeys = [('Y_STEP_PIN', 2), ('Y_DIR_PIN', 2), ('Y_MIN_PIN', 2), - ('Y_MAX_PIN', 2), ('Y_ENABLE_PIN', 2), ('Y_INVERT_DIR', 1), - ('Y_INVERT_MIN', 1), ('Y_INVERT_MAX', 1), - ('Y_INVERT_ENABLE', 1)] - pinZkeys = [('Z_STEP_PIN', 2), ('Z_DIR_PIN', 2), ('Z_MIN_PIN', 2), - ('Z_MAX_PIN', 2), ('Z_ENABLE_PIN', 2), ('Z_INVERT_DIR', 1), - ('Z_INVERT_MIN', 1), ('Z_INVERT_MAX', 1), - ('Z_INVERT_ENABLE', 1)] - pinEkeys = [('E_STEP_PIN', 2), ('E_DIR_PIN', 2), ('E_ENABLE_PIN', 2), - ('E_INVERT_DIR', 1), ('E_INVERT_ENABLE', 1)] + pinXkeys = [ + ("X_STEP_PIN", 2), + ("X_DIR_PIN", 2), + ("X_MIN_PIN", 2), + ("X_MAX_PIN", 2), + ("X_ENABLE_PIN", 2), + ("X_INVERT_DIR", 1), + ("X_INVERT_MIN", 1), + ("X_INVERT_MAX", 1), + ("X_INVERT_ENABLE", 1), + ] + pinYkeys = [ + ("Y_STEP_PIN", 2), + ("Y_DIR_PIN", 2), + ("Y_MIN_PIN", 2), + ("Y_MAX_PIN", 2), + ("Y_ENABLE_PIN", 2), + ("Y_INVERT_DIR", 1), + ("Y_INVERT_MIN", 1), + ("Y_INVERT_MAX", 1), + ("Y_INVERT_ENABLE", 1), + ] + pinZkeys = [ + ("Z_STEP_PIN", 2), + ("Z_DIR_PIN", 2), + ("Z_MIN_PIN", 2), + ("Z_MAX_PIN", 2), + ("Z_ENABLE_PIN", 2), + ("Z_INVERT_DIR", 1), + ("Z_INVERT_MIN", 1), + ("Z_INVERT_MAX", 1), + ("Z_INVERT_ENABLE", 1), + ] + pinEkeys = [ + ("E_STEP_PIN", 2), + ("E_DIR_PIN", 2), + ("E_ENABLE_PIN", 2), + ("E_INVERT_DIR", 1), + ("E_INVERT_ENABLE", 1), + ] - self.labels = {'X_STEP_PIN': "Step Pin:", 'X_DIR_PIN': "Direction Pin:", - 'X_MIN_PIN': "Minimum Pin:", 'X_MAX_PIN': "Maximum Pin:", - 'X_ENABLE_PIN': "Enable Pin:", - 'X_INVERT_DIR': "Invert Direction", - 'X_INVERT_MIN': "Invert Minimum", - 'X_INVERT_MAX': "Invert Maximum", - 'X_INVERT_ENABLE': "Invert Enable", + self.labels = { + "X_STEP_PIN": "Step Pin:", + "X_DIR_PIN": "Direction Pin:", + "X_MIN_PIN": "Minimum Pin:", + "X_MAX_PIN": "Maximum Pin:", + "X_ENABLE_PIN": "Enable Pin:", + "X_INVERT_DIR": "Invert Direction", + "X_INVERT_MIN": "Invert Minimum", + "X_INVERT_MAX": "Invert Maximum", + "X_INVERT_ENABLE": "Invert Enable", + "Y_STEP_PIN": "Step Pin:", + "Y_DIR_PIN": "Direction Pin:", + "Y_MIN_PIN": "Minimum Pin:", + "Y_MAX_PIN": "Maximum Pin:", + "Y_ENABLE_PIN": "Enable Pin:", + "Y_INVERT_DIR": "Invert Direction", + "Y_INVERT_MIN": "Invert Minimum", + "Y_INVERT_MAX": "Invert Maximum", + "Y_INVERT_ENABLE": "Invert Enable", + "Z_STEP_PIN": "Step Pin:", + "Z_DIR_PIN": "Direction Pin:", + "Z_MIN_PIN": "Minimum Pin:", + "Z_MAX_PIN": "Maximum Pin:", + "Z_ENABLE_PIN": "Enable Pin:", + "Z_INVERT_DIR": "Invert Direction", + "Z_INVERT_MIN": "Invert Minimum", + "Z_INVERT_MAX": "Invert Maximum", + "Z_INVERT_ENABLE": "Invert Enable", + "E_STEP_PIN": "Step Pin:", + "E_DIR_PIN": "Direction Pin:", + "E_ENABLE_PIN": "Enable Pin:", + "E_INVERT_DIR": "Invert Direction", + "E_INVERT_ENABLE": "Invert Enable", + "PS_ON_PIN": "PSU On Pin:", + "PS_INVERT_ON": "Invert PSU On Pin", + "PS_MOSFET_PIN": "PSU MOSFET Pin:", + "STEPPER_ENABLE_PIN": "Stepper Enable Pin:", + "STEPPER_INVERT_ENABLE": "Stepper Invert Enable", + "SD_CARD_SELECT_PIN": "SD Card Pin:", + "DEBUG_LED_PIN": "Debug LED Pin:", + } - 'Y_STEP_PIN': "Step Pin:", 'Y_DIR_PIN': "Direction Pin:", - 'Y_MIN_PIN': "Minimum Pin:", 'Y_MAX_PIN': "Maximum Pin:", - 'Y_ENABLE_PIN': "Enable Pin:", - 'Y_INVERT_DIR': "Invert Direction", - 'Y_INVERT_MIN': "Invert Minimum", - 'Y_INVERT_MAX': "Invert Maximum", - 'Y_INVERT_ENABLE': "Invert Enable", + labelWidth = 120 - 'Z_STEP_PIN': "Step Pin:", 'Z_DIR_PIN': "Direction Pin:", - 'Z_MIN_PIN': "Minimum Pin:", 'Z_MAX_PIN': "Maximum Pin:", - 'Z_ENABLE_PIN': "Enable Pin:", - 'Z_INVERT_DIR': "Invert Direction", - 'Z_INVERT_MIN': "Invert Minimum", - 'Z_INVERT_MAX': "Invert Maximum", - 'Z_INVERT_ENABLE': "Invert Enable", + sz = wx.GridBagSizer() + sz.Add((10, 10), pos=(0, 0)) - 'E_STEP_PIN': "Step Pin:", 'E_DIR_PIN': "Direction Pin:", - 'E_ENABLE_PIN': "Enable Pin:", - 'E_INVERT_DIR': "Invert Direction", - 'E_INVERT_ENABLE': "Invert Enable", + b = wx.StaticBox(self, wx.ID_ANY, "X Axis") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k, ctype in pinXkeys: + if ctype == 0: + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin) + sbox.Add(tc) + elif ctype == 2: + tc = self.addPinChoice(k, labelWidth) + sbox.Add(tc) + else: + cb = self.addCheckBox(k, self.onCheckBox) + sbox.Add(cb, 1, wx.LEFT, 30) - 'PS_ON_PIN': "PSU On Pin:", - 'PS_INVERT_ON': "Invert PSU On Pin", - 'PS_MOSFET_PIN': "PSU MOSFET Pin:", + sbox.Add((5, 5)) - 'STEPPER_ENABLE_PIN': "Stepper Enable Pin:", - 'STEPPER_INVERT_ENABLE': "Stepper Invert Enable", + sz.Add(sbox, pos=(1, 1)) - 'SD_CARD_SELECT_PIN': "SD Card Pin:", - 'DEBUG_LED_PIN': "Debug LED Pin:"} + b = wx.StaticBox(self, wx.ID_ANY, "Y Axis") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k, ctype in pinYkeys: + if ctype == 0: + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin) + sbox.Add(tc) + elif ctype == 2: + tc = self.addPinChoice(k, labelWidth) + sbox.Add(tc) + else: + cb = self.addCheckBox(k, self.onCheckBox) + sbox.Add(cb, 1, wx.LEFT, 30) - labelWidth = 120 + sbox.Add((5, 5)) - sz = wx.GridBagSizer() - sz.Add((10, 10), pos = (0, 0)) + sz.Add(sbox, pos=(1, 3)) - b = wx.StaticBox(self, wx.ID_ANY, "X Axis") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k, ctype in pinXkeys: - if ctype == 0: - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin) - sbox.Add(tc) - elif ctype == 2: - tc = self.addPinChoice(k, labelWidth) - sbox.Add(tc) - else: + b = wx.StaticBox(self, wx.ID_ANY, "Z Axis") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k, ctype in pinZkeys: + if ctype == 0: + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin) + sbox.Add(tc) + elif ctype == 2: + tc = self.addPinChoice(k, labelWidth) + sbox.Add(tc) + else: + cb = self.addCheckBox(k, self.onCheckBox) + sbox.Add(cb, 1, wx.LEFT, 30) + + sbox.Add((5, 5)) + + sz.Add(sbox, pos=(1, 5)) + + b = wx.StaticBox(self, wx.ID_ANY, "E Axis") + b.SetFont(font) + sbox = wx.StaticBoxSizer(b, wx.VERTICAL) + sbox.Add((5, 5)) + for k, ctype in pinEkeys: + if ctype == 0: + tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin) + sbox.Add(tc) + elif ctype == 2: + tc = self.addPinChoice(k, labelWidth) + sbox.Add(tc) + else: + cb = self.addCheckBox(k, self.onCheckBox) + sbox.Add(cb, 1, wx.LEFT, 30) + + sbox.Add((5, 5)) + + sz.Add(sbox, pos=(1, 7)) + + k = "STEPPER_ENABLE_PIN" + tc = self.addPinChoice(k, labelWidth + 20) + sz.Add(tc, pos=(3, 1)) + + sz.Add((10, 10), pos=(4, 1)) + + k = "STEPPER_INVERT_ENABLE" cb = self.addCheckBox(k, self.onCheckBox) - sbox.Add(cb, 1, wx.LEFT, 30) + sz.Add(cb, pos=(5, 1), flag=wx.ALIGN_CENTER_HORIZONTAL) - sbox.Add((5, 5)) - - sz.Add(sbox, pos = (1, 1)) - - b = wx.StaticBox(self, wx.ID_ANY, "Y Axis") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k, ctype in pinYkeys: - if ctype == 0: - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin) - sbox.Add(tc) - elif ctype == 2: + k = "PS_ON_PIN" tc = self.addPinChoice(k, labelWidth) - sbox.Add(tc) - else: + sz.Add(tc, pos=(3, 3)) + + k = "PS_INVERT_ON" cb = self.addCheckBox(k, self.onCheckBox) - sbox.Add(cb, 1, wx.LEFT, 30) + sz.Add(cb, pos=(5, 3), flag=wx.ALIGN_CENTER_HORIZONTAL) - sbox.Add((5, 5)) - - sz.Add(sbox, pos = (1, 3)) - - b = wx.StaticBox(self, wx.ID_ANY, "Z Axis") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k, ctype in pinZkeys: - if ctype == 0: - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin) - sbox.Add(tc) - elif ctype == 2: + k = "PS_MOSFET_PIN" tc = self.addPinChoice(k, labelWidth) - sbox.Add(tc) - else: - cb = self.addCheckBox(k, self.onCheckBox) - sbox.Add(cb, 1, wx.LEFT, 30) + sz.Add(tc, pos=(7, 3)) - sbox.Add((5, 5)) - - sz.Add(sbox, pos = (1, 5)) - - b = wx.StaticBox(self, wx.ID_ANY, "E Axis") - b.SetFont(font) - sbox = wx.StaticBoxSizer(b, wx.VERTICAL) - sbox.Add((5, 5)) - for k, ctype in pinEkeys: - if ctype == 0: - tc = self.addTextCtrl(k, labelWidth, self.onTextCtrlPin) - sbox.Add(tc) - elif ctype == 2: + k = "SD_CARD_SELECT_PIN" tc = self.addPinChoice(k, labelWidth) - sbox.Add(tc) - else: - cb = self.addCheckBox(k, self.onCheckBox) - sbox.Add(cb, 1, wx.LEFT, 30) + sz.Add(tc, pos=(3, 7)) - sbox.Add((5, 5)) + k = "DEBUG_LED_PIN" + tc = self.addPinChoice(k, labelWidth) + sz.Add(tc, pos=(5, 7)) - sz.Add(sbox, pos = (1, 7)) + self.SetSizer(sz) + self.enableAll(False) - k = "STEPPER_ENABLE_PIN" - tc = self.addPinChoice(k, labelWidth + 20) - sz.Add(tc, pos = (3, 1)) - - sz.Add((10, 10), pos = (4, 1)) - - k = "STEPPER_INVERT_ENABLE" - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (5, 1), flag = wx.ALIGN_CENTER_HORIZONTAL) - - k = "PS_ON_PIN" - tc = self.addPinChoice(k, labelWidth) - sz.Add(tc, pos = (3, 3)) - - k = "PS_INVERT_ON" - cb = self.addCheckBox(k, self.onCheckBox) - sz.Add(cb, pos = (5, 3), flag = wx.ALIGN_CENTER_HORIZONTAL) - - k = "PS_MOSFET_PIN" - tc = self.addPinChoice(k, labelWidth) - sz.Add(tc, pos = (7, 3)) - - k = "SD_CARD_SELECT_PIN" - tc = self.addPinChoice(k, labelWidth) - sz.Add(tc, pos = (3, 7)) - - k = "DEBUG_LED_PIN" - tc = self.addPinChoice(k, labelWidth) - sz.Add(tc, pos = (5, 7)) - - self.SetSizer(sz) - self.enableAll(False) - - def onChoice(self, evt): - self.assertModified(True) - evt.Skip() + def onChoice(self, evt): + self.assertModified(True) + evt.Skip() diff --git a/configtool/printer.py b/configtool/printer.py index 06a822b..37e8480 100644 --- a/configtool/printer.py +++ b/configtool/printer.py @@ -4,314 +4,333 @@ import os import re from sys import platform -from configtool.data import (defineValueFormat, defineBoolFormat, - reHelpTextStart, reHelpTextEnd, - reDefine, reDefineBL, reDefQS, reDefQSm, - reDefQSm2, reDefBool, reDefBoolBL, - reHomingOpts, reStartHoming, reEndHoming, - reDefHoming, reHoming4) +from configtool.data import ( + defineValueFormat, + defineBoolFormat, + reHelpTextStart, + reHelpTextEnd, + reDefine, + reDefineBL, + reDefQS, + reDefQSm, + reDefQSm2, + reDefBool, + reDefBoolBL, + reHomingOpts, + reStartHoming, + reEndHoming, + reDefHoming, + reHoming4, +) + class Printer: - def __init__(self, settings): - self.configFile = None + def __init__(self, settings): + self.configFile = None - self.cfgValues = {} - self.settings = settings - self.cfgDir = os.path.join(self.settings.folder, "configtool") + self.cfgValues = {} + self.settings = settings + self.cfgDir = os.path.join(self.settings.folder, "configtool") - def getValues(self): - vars = [(x, self.cfgValues[x]) for x in self.cfgValues] - return dict(vars) + def getValues(self): + vars = [(x, self.cfgValues[x]) for x in self.cfgValues] + return dict(vars) - def hasData(self): - return (self.configFile != None) + def hasData(self): + return self.configFile != None - def getFileName(self): - return self.configFile + def getFileName(self): + return self.configFile - def loadConfigFile(self, fn): - cfgFn = os.path.join(self.cfgDir, "printer.generic.h") - try: - self.cfgBuffer = list(open(cfgFn)) - except: - return False, cfgFn + def loadConfigFile(self, fn): + cfgFn = os.path.join(self.cfgDir, "printer.generic.h") + try: + self.cfgBuffer = list(open(cfgFn)) + except: + return False, cfgFn - try: - self.userBuffer = list(open(fn)) - except: - return False, fn + try: + self.userBuffer = list(open(fn)) + except: + return False, fn - self.configFile = fn + self.configFile = fn - gatheringHelpText = False - helpTextString = "" - helpKey = None + gatheringHelpText = False + helpTextString = "" + helpKey = None - self.cfgValues = {} - self.cfgNames = [] - self.helpText = {} + self.cfgValues = {} + self.cfgNames = [] + self.helpText = {} - prevLines = "" - for ln in self.cfgBuffer: - if gatheringHelpText: - if reHelpTextEnd.match(ln): - gatheringHelpText = False - helpTextString = helpTextString.strip() - # Keep paragraphs with double-newline. - helpTextString = helpTextString.replace("\n\n ", "\n\n") - # Keep indented lines, typically a list. - helpTextString = helpTextString.replace("\n\n ", "\n\n ") - helpTextString = helpTextString.replace("\n ", "\n\n ") - # Remove all other newlines and indents. - helpTextString = helpTextString.replace("\n ", " ") - hk = helpKey.split() - for k in hk: - self.helpText[k] = helpTextString - helpTextString = "" - helpKey = None - continue - else: - helpTextString += ln - continue - - m = reHelpTextStart.match(ln) - if m: - t = m.groups() - gatheringHelpText = True - helpKey = t[0] - continue - - if ln.rstrip().endswith("\\"): - prevLines += ln.rstrip()[:-1] - continue - - if prevLines != "": - ln = prevLines + ln prevLines = "" + for ln in self.cfgBuffer: + if gatheringHelpText: + if reHelpTextEnd.match(ln): + gatheringHelpText = False + helpTextString = helpTextString.strip() + # Keep paragraphs with double-newline. + helpTextString = helpTextString.replace("\n\n ", "\n\n") + # Keep indented lines, typically a list. + helpTextString = helpTextString.replace("\n\n ", "\n\n ") + helpTextString = helpTextString.replace("\n ", "\n\n ") + # Remove all other newlines and indents. + helpTextString = helpTextString.replace("\n ", " ") + hk = helpKey.split() + for k in hk: + self.helpText[k] = helpTextString + helpTextString = "" + helpKey = None + continue + else: + helpTextString += ln + continue - if self.parseCandidateValues(ln): - continue + m = reHelpTextStart.match(ln) + if m: + t = m.groups() + gatheringHelpText = True + helpKey = t[0] + continue - if self.parseHoming(ln): - continue + if ln.rstrip().endswith("\\"): + prevLines += ln.rstrip()[:-1] + continue - self.parseDefineName(ln) - self.parseDefineValue(ln) + if prevLines != "": + ln = prevLines + ln + prevLines = "" - # Set all boolean generic configuration items to False, so items not yet - # existing in the user configuration default to disabled. - for k in self.cfgValues.keys(): - if isinstance(self.cfgValues[k], bool): - self.cfgValues[k] = False + if self.parseCandidateValues(ln): + continue - # Read the user configuration. This usually overwrites all of the items - # read above, but not those missing in the user configuration, e.g. - # when reading an older config. - gatheringHelpText = False - prevLines = "" - for ln in self.userBuffer: - if gatheringHelpText: - if reHelpTextEnd.match(ln): - gatheringHelpText = False - continue + if self.parseHoming(ln): + continue - if reHelpTextStart.match(ln): - gatheringHelpText = True - continue + self.parseDefineName(ln) + self.parseDefineValue(ln) - if ln.rstrip().endswith("\\"): - prevLines += ln.rstrip()[:-1] - continue + # Set all boolean generic configuration items to False, so items not yet + # existing in the user configuration default to disabled. + for k in self.cfgValues.keys(): + if isinstance(self.cfgValues[k], bool): + self.cfgValues[k] = False - if prevLines != "": - ln = prevLines + ln + # Read the user configuration. This usually overwrites all of the items + # read above, but not those missing in the user configuration, e.g. + # when reading an older config. + gatheringHelpText = False prevLines = "" + for ln in self.userBuffer: + if gatheringHelpText: + if reHelpTextEnd.match(ln): + gatheringHelpText = False + continue - if self.parseCandidateValues(ln): - continue + if reHelpTextStart.match(ln): + gatheringHelpText = True + continue - if self.parseHoming(ln): - continue + if ln.rstrip().endswith("\\"): + prevLines += ln.rstrip()[:-1] + continue - self.parseDefineValue(ln) + if prevLines != "": + ln = prevLines + ln + prevLines = "" - # Parsing done. All parsed stuff is now in these array and dicts. - if self.settings.verbose >= 2: - print(self.cfgValues) # #defines with a value. - print(self.cfgNames) # Names found in the generic file. - if self.settings.verbose >= 3: - print(self.helpText) + if self.parseCandidateValues(ln): + continue - return True, None + if self.parseHoming(ln): + continue - def parseDefineName(self, ln): - m = reDefBool.search(ln) - if m: - t = m.groups() - if len(t) == 1: - self.cfgNames.append(t[0]) - return True + self.parseDefineValue(ln) - return False + # Parsing done. All parsed stuff is now in these array and dicts. + if self.settings.verbose >= 2: + print(self.cfgValues) # #defines with a value. + print(self.cfgNames) # Names found in the generic file. + if self.settings.verbose >= 3: + print(self.helpText) - def parseCandidateValues(self, ln): - m = reHomingOpts.match(ln) - if m: - t = m.groups() - if len(t) == 1: - if 'HOMING_OPTS' in self.cfgValues: - if t[0] not in self.cfgValues['HOMING_OPTS']: - self.cfgValues['HOMING_OPTS'].append(t[0]) - else: - self.cfgValues['HOMING_OPTS'] = [t[0]] - return True + return True, None - def parseHoming(self, ln): - m = reDefHoming.search(ln) - if m: - t = m.groups() - if len(t) == 1: - n = reHoming4.search(t[0]) - if n: - u = n.groups() - if len(u) == 4: - t2 = [] - for x in u: - t2.append(x) - - self.cfgValues['HOMING_STEP1'] = t2[0] - self.cfgValues['HOMING_STEP2'] = t2[1] - self.cfgValues['HOMING_STEP3'] = t2[2] - self.cfgValues['HOMING_STEP4'] = t2[3] - - return True - return None - return True - - def parseDefineValue(self, ln): - m = reDefQS.search(ln) - if m: - t = m.groups() - if len(t) == 2: - m = reDefQSm.search(ln) + def parseDefineName(self, ln): + m = reDefBool.search(ln) if m: - t = m.groups() - tt = re.findall(reDefQSm2, t[1]) - if len(tt) == 1 and (t[0] in self.cfgNames): - self.cfgValues[t[0]] = tt[0], True - return True - elif len(tt) > 1 and (t[0] in self.cfgNames): - self.cfgValues[t[0]] = tt, True + t = m.groups() + if len(t) == 1: + self.cfgNames.append(t[0]) return True - m = reDefine.search(ln) - if m: - t = m.groups() - if len(t) == 2 and (t[0] in self.cfgNames): - if reDefineBL.search(ln): - self.cfgValues[t[0]] = t[1], True - else: - self.cfgValues[t[0]] = t[1], False - return True + return False - m = reDefBool.search(ln) - if m: - t = m.groups() - # Accept booleans, but not those for which a value exists already. - # Booleans already existing as values are most likely misconfigured - # manual edits (or result of a bug). - if len(t) == 1 and t[0] in self.cfgNames \ - and not (t[0] in self.cfgValues \ - and isinstance(self.cfgValues[t[0]], tuple)): - if reDefBoolBL.search(ln): - self.cfgValues[t[0]] = True - else: - self.cfgValues[t[0]] = False - return True - - return False - - def saveConfigFile(self, path, values): - if not values: - values = self.cfgValues - - if self.settings.verbose >= 1: - print("Saving printer: %s." % path) - if self.settings.verbose >= 2: - print(values) - - fp = file(path, 'w') - self.configFile = path - - skipToHomingEnd = False - - for ln in self.cfgBuffer: - m = reStartHoming.match(ln) - if m: - fp.write(ln) - sstr = "%s, %s, %s, %s" % ((values['HOMING_STEP1']), - (values['HOMING_STEP2']), - (values['HOMING_STEP3']), - (values['HOMING_STEP4'])) - fp.write("DEFINE_HOMING(%s)\n" % sstr) - skipToHomingEnd = True - continue - - if skipToHomingEnd: - m = reEndHoming.match(ln) + def parseCandidateValues(self, ln): + m = reHomingOpts.match(ln) if m: - fp.write(ln) - skipToHomingEnd = False - continue + t = m.groups() + if len(t) == 1: + if "HOMING_OPTS" in self.cfgValues: + if t[0] not in self.cfgValues["HOMING_OPTS"]: + self.cfgValues["HOMING_OPTS"].append(t[0]) + else: + self.cfgValues["HOMING_OPTS"] = [t[0]] + return True + + def parseHoming(self, ln): + m = reDefHoming.search(ln) + if m: + t = m.groups() + if len(t) == 1: + n = reHoming4.search(t[0]) + if n: + u = n.groups() + if len(u) == 4: + t2 = [] + for x in u: + t2.append(x) + + self.cfgValues["HOMING_STEP1"] = t2[0] + self.cfgValues["HOMING_STEP2"] = t2[1] + self.cfgValues["HOMING_STEP3"] = t2[2] + self.cfgValues["HOMING_STEP4"] = t2[3] + + return True + return None + return True + + def parseDefineValue(self, ln): + m = reDefQS.search(ln) + if m: + t = m.groups() + if len(t) == 2: + m = reDefQSm.search(ln) + if m: + t = m.groups() + tt = re.findall(reDefQSm2, t[1]) + if len(tt) == 1 and (t[0] in self.cfgNames): + self.cfgValues[t[0]] = tt[0], True + return True + elif len(tt) > 1 and (t[0] in self.cfgNames): + self.cfgValues[t[0]] = tt, True + return True + + m = reDefine.search(ln) + if m: + t = m.groups() + if len(t) == 2 and (t[0] in self.cfgNames): + if reDefineBL.search(ln): + self.cfgValues[t[0]] = t[1], True + else: + self.cfgValues[t[0]] = t[1], False + return True + + m = reDefBool.search(ln) + if m: + t = m.groups() + # Accept booleans, but not those for which a value exists already. + # Booleans already existing as values are most likely misconfigured + # manual edits (or result of a bug). + if ( + len(t) == 1 + and t[0] in self.cfgNames + and not ( + t[0] in self.cfgValues and isinstance(self.cfgValues[t[0]], tuple) + ) + ): + if reDefBoolBL.search(ln): + self.cfgValues[t[0]] = True + else: + self.cfgValues[t[0]] = False + return True + + return False + + def saveConfigFile(self, path, values): + if not values: + values = self.cfgValues + + if self.settings.verbose >= 1: + print("Saving printer: %s." % path) + if self.settings.verbose >= 2: + print(values) + + fp = file(path, "w") + self.configFile = path + + skipToHomingEnd = False + + for ln in self.cfgBuffer: + m = reStartHoming.match(ln) + if m: + fp.write(ln) + sstr = "%s, %s, %s, %s" % ( + (values["HOMING_STEP1"]), + (values["HOMING_STEP2"]), + (values["HOMING_STEP3"]), + (values["HOMING_STEP4"]), + ) + fp.write("DEFINE_HOMING(%s)\n" % sstr) + skipToHomingEnd = True + continue + + if skipToHomingEnd: + m = reEndHoming.match(ln) + if m: + fp.write(ln) + skipToHomingEnd = False + continue + + m = reDefine.match(ln) + if m: + t = m.groups() + if len(t) == 2 and t[0] in values.keys(): + v = values[t[0]] + self.cfgValues[t[0]] = v + if v[1] == False: + fp.write("//") + fp.write(defineValueFormat % (t[0], v[0])) + else: + if t[0] == "CANNED_CYCLE": + # Known to be absent in the GUI. Worse, this value is replaced + # by the one in the metadata file. + # + # TODO: make value reading above recognize wether this value is + # commented out or not. Reading the value its self works + # already. Hint: it's the rule using reDefQS, reDefQSm, etc. + # + # TODO: add a multiline text field in the GUI to deal with this. + # + # TODO: write this value out properly. In /* comments */, if + # disabled. + # + # TODO: currently, the lines beyond the ones with the #define are + # treated like arbitrary comments. Having the former TODOs + # done, this will lead to duplicates. + fp.write(ln) + else: + print("Value key " + t[0] + " not found in GUI.") + + continue + + m = reDefBoolBL.match(ln) + if m: + t = m.groups() + if len(t) == 1 and t[0] in values.keys(): + v = values[t[0]] + self.cfgValues[t[0]] = v + if v == "" or v == False: + fp.write("//") + fp.write(defineBoolFormat % t[0]) + else: + print("Boolean key " + t[0] + " not found in GUI.") + + continue - m = reDefine.match(ln) - if m: - t = m.groups() - if len(t) == 2 and t[0] in values.keys(): - v = values[t[0]] - self.cfgValues[t[0]] = v - if v[1] == False: - fp.write("//") - fp.write(defineValueFormat % (t[0], v[0])) - else: - if t[0] == 'CANNED_CYCLE': - # Known to be absent in the GUI. Worse, this value is replaced - # by the one in the metadata file. - # - # TODO: make value reading above recognize wether this value is - # commented out or not. Reading the value its self works - # already. Hint: it's the rule using reDefQS, reDefQSm, etc. - # - # TODO: add a multiline text field in the GUI to deal with this. - # - # TODO: write this value out properly. In /* comments */, if - # disabled. - # - # TODO: currently, the lines beyond the ones with the #define are - # treated like arbitrary comments. Having the former TODOs - # done, this will lead to duplicates. fp.write(ln) - else: - print("Value key " + t[0] + " not found in GUI.") - continue + fp.close() - m = reDefBoolBL.match(ln) - if m: - t = m.groups() - if len(t) == 1 and t[0] in values.keys(): - v = values[t[0]] - self.cfgValues[t[0]] = v - if v == "" or v == False: - fp.write("//") - fp.write(defineBoolFormat % t[0]) - else: - print("Boolean key " + t[0] + " not found in GUI.") - - continue - - fp.write(ln) - - fp.close() - - return True + return True diff --git a/configtool/printerpanel.py b/configtool/printerpanel.py index 6b4eebe..95e97a9 100644 --- a/configtool/printerpanel.py +++ b/configtool/printerpanel.py @@ -1,14 +1,22 @@ - import os import wx import re from sys import platform from configtool.decoration import Decoration -from configtool.data import (defineValueFormat, defineBoolFormat, - reHelpTextStart, reHelpTextEnd, - reDefine, reDefineBL, reDefQS, reDefQSm, - reDefQSm2, reDefBool, reDefBoolBL) +from configtool.data import ( + defineValueFormat, + defineBoolFormat, + reHelpTextStart, + reHelpTextEnd, + reDefine, + reDefineBL, + reDefQS, + reDefQSm, + reDefQSm2, + reDefBool, + reDefBoolBL, +) from configtool.mechanicalpage import MechanicalPage from configtool.accelerationpage import AccelerationPage from configtool.miscellaneouspage import MiscellaneousPage @@ -17,249 +25,277 @@ from configtool.printer import Printer class PrinterPanel(wx.Panel): - def __init__(self, parent, nb, settings): - wx.Panel.__init__(self, nb, wx.ID_ANY) - self.parent = parent + def __init__(self, parent, nb, settings): + wx.Panel.__init__(self, nb, wx.ID_ANY) + self.parent = parent - self.deco = Decoration() - self.protFileLoaded = False + self.deco = Decoration() + self.protFileLoaded = False - self.settings = settings + self.settings = settings - self.printer = Printer(self.settings) + self.printer = Printer(self.settings) - self.dir = os.path.join(self.settings.folder, "config") + self.dir = os.path.join(self.settings.folder, "config") - self.SetBackgroundColour(self.deco.getBackgroundColour()) - self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground) - sz = wx.BoxSizer(wx.HORIZONTAL) + self.SetBackgroundColour(self.deco.getBackgroundColour()) + self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground) + sz = wx.BoxSizer(wx.HORIZONTAL) - self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21), - style = wx.BK_DEFAULT) - self.nb.SetBackgroundColour(self.deco.getBackgroundColour()) - self.nb.SetFont(self.settings.font) + self.nb = wx.Notebook(self, wx.ID_ANY, size=(21, 21), style=wx.BK_DEFAULT) + self.nb.SetBackgroundColour(self.deco.getBackgroundColour()) + self.nb.SetFont(self.settings.font) - self.pages = [] - self.titles = [] - self.pageModified = [] - self.pageValid = [] + self.pages = [] + self.titles = [] + self.pageModified = [] + self.pageValid = [] - self.pgMech = self.registerPage(MechanicalPage, "Mechanical") - self.pgAcc = self.registerPage(AccelerationPage, "Acceleration") - self.pgMiscellaneous = self.registerPage(MiscellaneousPage, - "Miscellaneous") + self.pgMech = self.registerPage(MechanicalPage, "Mechanical") + self.pgAcc = self.registerPage(AccelerationPage, "Acceleration") + self.pgMiscellaneous = self.registerPage(MiscellaneousPage, "Miscellaneous") - sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5) + sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5) - self.SetSizer(sz) - self.Fit() + self.SetSizer(sz) + self.Fit() - def registerPage(self, klass, label, *args, **kwargs): - page = klass(self, self.nb, len(self.pages), *args, - font = self.settings.font, **kwargs) - self.nb.AddPage(page, label) - self.pages.append(page) - self.titles.append(label) - self.pageModified.append(False) - self.pageValid.append(True) - return page + def registerPage(self, klass, label, *args, **kwargs): + page = klass( + self, self.nb, len(self.pages), *args, font=self.settings.font, **kwargs + ) + self.nb.AddPage(page, label) + self.pages.append(page) + self.titles.append(label) + self.pageModified.append(False) + self.pageValid.append(True) + return page - def assertModified(self, pg, flag = True): - self.pageModified[pg] = flag - self.modifyTab(pg) + def assertModified(self, pg, flag=True): + self.pageModified[pg] = flag + self.modifyTab(pg) - def isModified(self): - return (True in self.pageModified) + def isModified(self): + return True in self.pageModified - def isValid(self): - return not (False in self.pageValid) + def isValid(self): + return not (False in self.pageValid) - def hasData(self): - return self.printer.hasData() + def hasData(self): + return self.printer.hasData() - def getFileName(self): - return self.printer.configFile + def getFileName(self): + return self.printer.configFile - def assertValid(self, pg, flag = True): - self.pageValid[pg] = flag - self.modifyTab(pg) + def assertValid(self, pg, flag=True): + self.pageValid[pg] = flag + self.modifyTab(pg) - if False in self.pageValid: - self.parent.enableSavePrinter(False, False) - else: - self.parent.enableSavePrinter(not self.protFileLoaded, True) + if False in self.pageValid: + self.parent.enableSavePrinter(False, False) + else: + self.parent.enableSavePrinter(not self.protFileLoaded, True) - def modifyTab(self, pg): - if self.pageModified[pg] and not self.pageValid[pg]: - pfx = "?* " - elif self.pageModified[pg]: - pfx = "* " - elif not self.pageValid[pg]: - pfx = "? " - else: - pfx = "" + def modifyTab(self, pg): + if self.pageModified[pg] and not self.pageValid[pg]: + pfx = "?* " + elif self.pageModified[pg]: + pfx = "* " + elif not self.pageValid[pg]: + pfx = "? " + else: + pfx = "" - self.nb.SetPageText(pg, pfx + self.titles[pg]) - if True in self.pageModified and False in self.pageValid: - pfx = "?* " - elif True in self.pageModified: - pfx = "* " - elif False in self.pageValid: - pfx = "? " - else: - pfx = "" - self.parent.setPrinterTabDecor(pfx) + self.nb.SetPageText(pg, pfx + self.titles[pg]) + if True in self.pageModified and False in self.pageValid: + pfx = "?* " + elif True in self.pageModified: + pfx = "* " + elif False in self.pageValid: + pfx = "? " + else: + pfx = "" + self.parent.setPrinterTabDecor(pfx) - def setHeaters(self, ht): - return self.pgMiscellaneous.setHeaters(ht) + def setHeaters(self, ht): + return self.pgMiscellaneous.setHeaters(ht) - def onClose(self, evt): - if not self.confirmLoseChanges("exit"): - return + def onClose(self, evt): + if not self.confirmLoseChanges("exit"): + return - self.Destroy() + self.Destroy() - def confirmLoseChanges(self, msg): - if True not in self.pageModified: - return True + def confirmLoseChanges(self, msg): + if True not in self.pageModified: + return True - dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n" - "There are changes to your printer " - "configuration that will be lost.", - "Changes pending", - wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION) - rc = dlg.ShowModal() - dlg.Destroy() + dlg = wx.MessageDialog( + self, + "Are you sure you want to " + msg + "?\n" + "There are changes to your printer " + "configuration 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 + if rc != wx.ID_YES: + return False - return True + return True - def onLoadConfig(self, evt): - if not self.confirmLoseChanges("load a new printer configuration"): - return + def onLoadConfig(self, evt): + if not self.confirmLoseChanges("load a new printer configuration"): + return - if platform.startswith("darwin"): - # Mac OS X appears to be a bit limited on wildcards. - wildcard = "Printer configuration (printer.*.h)|*.h" - else: - wildcard = "Printer configuration (printer.*.h)|printer.*.h" + if platform.startswith("darwin"): + # Mac OS X appears to be a bit limited on wildcards. + wildcard = "Printer configuration (printer.*.h)|*.h" + else: + wildcard = "Printer configuration (printer.*.h)|printer.*.h" - dlg = wx.FileDialog(self, message = "Choose a printer config file", - defaultDir = self.dir, defaultFile = "", - wildcard = wildcard, style = wx.FD_OPEN | wx.FD_CHANGE_DIR) + dlg = wx.FileDialog( + self, + message="Choose a printer config file", + defaultDir=self.dir, + defaultFile="", + wildcard=wildcard, + style=wx.FD_OPEN | wx.FD_CHANGE_DIR, + ) - path = None - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() + path = None + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() - dlg.Destroy() - if path is None: - return + dlg.Destroy() + if path is None: + return - self.dir = os.path.dirname(path) - rc, efn = self.loadConfigFile(path) + self.dir = os.path.dirname(path) + rc, efn = self.loadConfigFile(path) - if not rc: - dlg = wx.MessageDialog(self, "Unable to process file %s." % efn, - "File error", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return + if not rc: + dlg = wx.MessageDialog( + self, + "Unable to process file %s." % efn, + "File error", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return - def loadConfigFile(self, fn): - ok, file = self.printer.loadConfigFile(fn) - if not ok: - return ok, file + def loadConfigFile(self, fn): + ok, file = self.printer.loadConfigFile(fn) + if not ok: + return ok, file - if os.path.basename(fn) in protectedFiles: - self.parent.enableSavePrinter(False, True) - self.protFileLoaded = True - else: - self.protFileLoaded = False - self.parent.enableSavePrinter(True, True) - self.parent.setPrinterTabFile(os.path.basename(fn)) + if os.path.basename(fn) in protectedFiles: + self.parent.enableSavePrinter(False, True) + self.protFileLoaded = True + else: + self.protFileLoaded = False + self.parent.enableSavePrinter(True, True) + self.parent.setPrinterTabFile(os.path.basename(fn)) - for pg in self.pages: - pg.insertValues(self.printer.cfgValues) - pg.setHelpText(self.printer.helpText) + for pg in self.pages: + pg.insertValues(self.printer.cfgValues) + pg.setHelpText(self.printer.helpText) - k = 'DC_EXTRUDER' - if k in self.printer.cfgValues.keys() and self.printer.cfgValues[k][1] == True: - self.pgMiscellaneous.setOriginalHeater(self.printer.cfgValues[k][0]) - else: - self.pgMiscellaneous.setOriginalHeater(None) + k = "DC_EXTRUDER" + if k in self.printer.cfgValues.keys() and self.printer.cfgValues[k][1] == True: + self.pgMiscellaneous.setOriginalHeater(self.printer.cfgValues[k][0]) + else: + self.pgMiscellaneous.setOriginalHeater(None) - return True, None + return True, None - def onSaveConfig(self, evt): - path = self.getFileName() - return self.saveConfigFile(path) + def onSaveConfig(self, evt): + path = self.getFileName() + return self.saveConfigFile(path) - def onSaveConfigAs(self, evt): - if platform.startswith("darwin"): - # Mac OS X appears to be a bit limited on wildcards. - wildcard = "Printer configuration (printer.*.h)|*.h" - else: - wildcard = "Printer configuration (printer.*.h)|printer.*.h" + def onSaveConfigAs(self, evt): + if platform.startswith("darwin"): + # Mac OS X appears to be a bit limited on wildcards. + wildcard = "Printer configuration (printer.*.h)|*.h" + else: + wildcard = "Printer configuration (printer.*.h)|printer.*.h" - dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir, - defaultFile = "", wildcard = wildcard, - style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) + dlg = wx.FileDialog( + self, + message="Save as ...", + defaultDir=self.dir, + defaultFile="", + wildcard=wildcard, + style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, + ) - val = dlg.ShowModal() + val = dlg.ShowModal() - if val != wx.ID_OK: - dlg.Destroy() - return + if val != wx.ID_OK: + dlg.Destroy() + return - path = dlg.GetPath() - dlg.Destroy() + path = dlg.GetPath() + dlg.Destroy() - rc = self.saveConfigFile(path) - if rc: - self.parent.setPrinterTabFile(os.path.basename(path)) - self.protFileLoaded = False - self.parent.enableSavePrinter(True, True) - return rc + rc = self.saveConfigFile(path) + if rc: + self.parent.setPrinterTabFile(os.path.basename(path)) + self.protFileLoaded = False + self.parent.enableSavePrinter(True, True) + return rc - def saveConfigFile(self, path): - if os.path.basename(path) in protectedFiles: - dlg = wx.MessageDialog(self, "It's not allowed to overwrite files " - "distributed by Teacup. Choose another name.", - "Protected file error", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False + def saveConfigFile(self, path): + if os.path.basename(path) in protectedFiles: + dlg = wx.MessageDialog( + self, + "It's not allowed to overwrite files " + "distributed by Teacup. Choose another name.", + "Protected file error", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return False - if not os.path.basename(path).startswith("printer."): - dlg = wx.MessageDialog(self, "Illegal file name: %s.\n" - "File name must begin with \"printer.\"" % path, - "Illegal file name", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False + if not os.path.basename(path).startswith("printer."): + dlg = wx.MessageDialog( + self, + "Illegal file name: %s.\n" + 'File name must begin with "printer."' % path, + "Illegal file name", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return False - values = {} - for pg in self.pages: - v1 = pg.getValues() - for k in v1.keys(): - values[k] = v1[k] + values = {} + for pg in self.pages: + v1 = pg.getValues() + for k in v1.keys(): + values[k] = v1[k] - ext = os.path.splitext(os.path.basename(path))[1] - self.dir = os.path.dirname(path) + ext = os.path.splitext(os.path.basename(path))[1] + self.dir = os.path.dirname(path) - if ext == "": - path += ".h" + if ext == "": + path += ".h" - try: - self.printer.saveConfigFile(path, values) - except: - dlg = wx.MessageDialog(self, "Unable to write to file %s." % path, - "File error", wx.OK + wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False + try: + self.printer.saveConfigFile(path, values) + except: + dlg = wx.MessageDialog( + self, + "Unable to write to file %s." % path, + "File error", + wx.OK + wx.ICON_ERROR, + ) + dlg.ShowModal() + dlg.Destroy() + return False - return True + return True diff --git a/configtool/protectedfiles.py b/configtool/protectedfiles.py index bf75884..ebcc9b0 100644 --- a/configtool/protectedfiles.py +++ b/configtool/protectedfiles.py @@ -1,20 +1,19 @@ - protectedFiles = [ - "board.3drag.h", - "board.gen3.h", - "board.gen6.h", - "board.gen7-arm.h", - "board.gen7-v1.1-v1.3.h", - "board.gen7-v1.4.h", - "board.nanoheart-v1.0.h", - "board.ramps-v1.2.h", - "board.ramps-v1.3.h", - "board.rumba.h", - "board.sanguinololu-v1.1.h", - "board.sanguinololu-v1.2.h", - "board.sanguish.h", - "board.teensy-v2.0.h", - "board.teensy++-v2.0.h", - "printer.mendel.h", - "printer.wolfstrap.h" + "board.3drag.h", + "board.gen3.h", + "board.gen6.h", + "board.gen7-arm.h", + "board.gen7-v1.1-v1.3.h", + "board.gen7-v1.4.h", + "board.nanoheart-v1.0.h", + "board.ramps-v1.2.h", + "board.ramps-v1.3.h", + "board.rumba.h", + "board.sanguinololu-v1.1.h", + "board.sanguinololu-v1.2.h", + "board.sanguish.h", + "board.teensy-v2.0.h", + "board.teensy++-v2.0.h", + "printer.mendel.h", + "printer.wolfstrap.h", ] diff --git a/configtool/sensorlist.py b/configtool/sensorlist.py index d09360c..91f124d 100644 --- a/configtool/sensorlist.py +++ b/configtool/sensorlist.py @@ -1,86 +1,88 @@ - import wx class SensorList(wx.ListCtrl): - def __init__(self, parent, font): - self.parent = parent - self.currentItem = None - wx.ListCtrl.__init__(self, parent, wx.ID_ANY, - size = (105 + 105 + 55 + 280 + 4, 100), - style = wx.LC_REPORT | wx.LC_VIRTUAL | - wx.LC_HRULES | wx.LC_VRULES) + def __init__(self, parent, font): + self.parent = parent + self.currentItem = None + wx.ListCtrl.__init__( + self, + parent, + wx.ID_ANY, + size=(105 + 105 + 55 + 280 + 4, 100), + style=wx.LC_REPORT | wx.LC_VIRTUAL | wx.LC_HRULES | wx.LC_VRULES, + ) - self.SetFont(font) + self.SetFont(font) - self.valid = [] - self.sensorList = [] + self.valid = [] + self.sensorList = [] - self.InsertColumn(0, "Name") - self.InsertColumn(1, "Sensor Type") - self.InsertColumn(2, "Pin") - self.InsertColumn(3, "Additional") - self.SetColumnWidth(0, 105) - self.SetColumnWidth(1, 105) - self.SetColumnWidth(2, 55) - self.SetColumnWidth(3, 280) + self.InsertColumn(0, "Name") + self.InsertColumn(1, "Sensor Type") + self.InsertColumn(2, "Pin") + self.InsertColumn(3, "Additional") + self.SetColumnWidth(0, 105) + self.SetColumnWidth(1, 105) + self.SetColumnWidth(2, 55) + self.SetColumnWidth(3, 280) - self.SetItemCount(0) + self.SetItemCount(0) - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) - self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected) + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected) - def updateList(self, sensorList): - self.sensorList = sensorList - self.valid = [True] * len(sensorList) - self.currentItem = None - self.parent.setItemSelected(None) - i = self.GetFirstSelected() - while i != -1: - self.Select(i, False) - i = self.GetFirstSelected() + def updateList(self, sensorList): + self.sensorList = sensorList + self.valid = [True] * len(sensorList) + self.currentItem = None + self.parent.setItemSelected(None) + i = self.GetFirstSelected() + while i != -1: + self.Select(i, False) + i = self.GetFirstSelected() - self.SetItemCount(len(sensorList)) + self.SetItemCount(len(sensorList)) - def setRowValidity(self, i, flag = False): - if i < 0 or i >= len(self.sensorList): - return + def setRowValidity(self, i, flag=False): + if i < 0 or i >= len(self.sensorList): + return - self.valid[i] = flag - self.Refresh() + self.valid[i] = flag + self.Refresh() - def setTableValidity(self, flag = False): - for i in range(len(self.sensorList)): - self.setRowValidity(i, flag) + def setTableValidity(self, flag=False): + for i in range(len(self.sensorList)): + self.setRowValidity(i, flag) - def OnItemSelected(self, event): - self.currentItem = event.m_itemIndex - self.parent.setItemSelected(self.currentItem) + def OnItemSelected(self, event): + self.currentItem = event.m_itemIndex + self.parent.setItemSelected(self.currentItem) - def OnItemDeselected(self, event): - self.currentItem = None - self.parent.setItemSelected(None) + def OnItemDeselected(self, event): + self.currentItem = None + self.parent.setItemSelected(None) - def getColumnText(self, index, col): - item = self.GetItem(index, col) - return item.GetText() + def getColumnText(self, index, col): + item = self.GetItem(index, col) + return item.GetText() - def OnGetItemText(self, item, col): - if item < 0 or item >= len(self.sensorList): - return "Error - no sensors" + def OnGetItemText(self, item, col): + if item < 0 or item >= len(self.sensorList): + return "Error - no sensors" - s = self.sensorList[item] + s = self.sensorList[item] - if col == 0: - return s[0] - elif col == 1: - return s[1] - elif col == 2: - return s[2] - elif len(s) == 3: - return "" - else: - if s[3] is None: - return "" - else: - return "[%s]" % (", ".join(s[3])) + if col == 0: + return s[0] + elif col == 1: + return s[1] + elif col == 2: + return s[2] + elif len(s) == 3: + return "" + else: + if s[3] is None: + return "" + else: + return "[%s]" % (", ".join(s[3])) diff --git a/configtool/sensorpage.py b/configtool/sensorpage.py index aae2c2c..ffe5daa 100644 --- a/configtool/sensorpage.py +++ b/configtool/sensorpage.py @@ -8,191 +8,208 @@ from .addsensordlg import AddSensorDlg class SensorsPage(wx.Panel, Page): - def __init__(self, parent, nb, idPg, heatersPage, font): - wx.Panel.__init__(self, nb, wx.ID_ANY) - Page.__init__(self, font) - self.parent = parent - self.heatersPage = heatersPage - self.font = font - self.id = idPg + def __init__(self, parent, nb, idPg, heatersPage, font): + wx.Panel.__init__(self, nb, wx.ID_ANY) + Page.__init__(self, font) + self.parent = parent + self.heatersPage = heatersPage + self.font = font + self.id = idPg - self.sensorTypeKeys = {'TT_MAX6675': 'TEMP_MAX6675', - 'TT_THERMISTOR': 'TEMP_THERMISTOR', - 'TT_AD595': 'TEMP_AD595', 'TT_PT100': 'TEMP_PT100', - 'TT_INTERCOM': 'TEMP_INTERCOM', - 'TT_MCP3008': 'TEMP_MCP3008'} - self.labels = {'TEMP_MAX6675': "MAX6675", 'TEMP_THERMISTOR': "Thermistor", - 'TEMP_AD595': "AD595", 'TEMP_PT100': "PT100", - 'TEMP_INTERCOM': "Intercom", - 'TEMP_MCP3008': 'MCP3008', - 'MCP3008_SELECT_PIN': "MCP3008 CS Pin:"} + self.sensorTypeKeys = { + "TT_MAX6675": "TEMP_MAX6675", + "TT_THERMISTOR": "TEMP_THERMISTOR", + "TT_AD595": "TEMP_AD595", + "TT_PT100": "TEMP_PT100", + "TT_INTERCOM": "TEMP_INTERCOM", + "TT_MCP3008": "TEMP_MCP3008", + } + self.labels = { + "TEMP_MAX6675": "MAX6675", + "TEMP_THERMISTOR": "Thermistor", + "TEMP_AD595": "AD595", + "TEMP_PT100": "PT100", + "TEMP_INTERCOM": "Intercom", + "TEMP_MCP3008": "MCP3008", + "MCP3008_SELECT_PIN": "MCP3008 CS Pin:", + } - self.validPins = pinNames - labelWidth = 120 + self.validPins = pinNames + labelWidth = 120 - sz = wx.GridBagSizer() - sz.Add((10, 10), pos = (0, 0)) + sz = wx.GridBagSizer() + sz.Add((10, 10), pos=(0, 0)) - self.sensors = [] + self.sensors = [] - self.lb = SensorList(self, font) - sz.Add(self.lb, pos = (1, 1)) - sz.Add((20, 20), pos = (1, 2)) + self.lb = SensorList(self, font) + sz.Add(self.lb, pos=(1, 1)) + sz.Add((20, 20), pos=(1, 2)) - bsz = wx.BoxSizer(wx.VERTICAL) - self.bAdd = wx.Button(self, wx.ID_ANY, "Add", size = BSIZESMALL) - self.bAdd.SetBackgroundColour(self.deco.getBackgroundColour()) - self.bAdd.SetFont(font) - self.Bind(wx.EVT_BUTTON, self.doAdd, self.bAdd) - self.bAdd.Enable(False) - self.bAdd.SetToolTip("Add a sensor to the configuration.") + bsz = wx.BoxSizer(wx.VERTICAL) + self.bAdd = wx.Button(self, wx.ID_ANY, "Add", size=BSIZESMALL) + self.bAdd.SetBackgroundColour(self.deco.getBackgroundColour()) + self.bAdd.SetFont(font) + self.Bind(wx.EVT_BUTTON, self.doAdd, self.bAdd) + self.bAdd.Enable(False) + self.bAdd.SetToolTip("Add a sensor to the configuration.") - bsz.Add(self.bAdd) + bsz.Add(self.bAdd) - bsz.Add((10, 10)) - self.bModify = wx.Button(self, wx.ID_ANY, "Modify", size = BSIZESMALL) - self.bModify.SetBackgroundColour(self.deco.getBackgroundColour()) - self.bModify.SetFont(font) - self.bModify.Enable(False) - self.Bind(wx.EVT_BUTTON, self.doModify, self.bModify) - bsz.Add(self.bModify) - self.bModify.SetToolTip("Modify the selected temperature sensor.") + bsz.Add((10, 10)) + self.bModify = wx.Button(self, wx.ID_ANY, "Modify", size=BSIZESMALL) + self.bModify.SetBackgroundColour(self.deco.getBackgroundColour()) + self.bModify.SetFont(font) + self.bModify.Enable(False) + self.Bind(wx.EVT_BUTTON, self.doModify, self.bModify) + bsz.Add(self.bModify) + self.bModify.SetToolTip("Modify the selected temperature sensor.") - bsz.Add((10, 10)) - self.bDelete = wx.Button(self, wx.ID_ANY, "Delete", size = BSIZESMALL) - self.bDelete.SetBackgroundColour(self.deco.getBackgroundColour()) - self.bDelete.SetFont(font) - self.bDelete.Enable(False) - self.Bind(wx.EVT_BUTTON, self.doDelete, self.bDelete) - bsz.Add(self.bDelete) - self.bDelete.SetToolTip("Remove the selected temperature sensor " - "from the configuration.") + bsz.Add((10, 10)) + self.bDelete = wx.Button(self, wx.ID_ANY, "Delete", size=BSIZESMALL) + self.bDelete.SetBackgroundColour(self.deco.getBackgroundColour()) + self.bDelete.SetFont(font) + self.bDelete.Enable(False) + self.Bind(wx.EVT_BUTTON, self.doDelete, self.bDelete) + bsz.Add(self.bDelete) + self.bDelete.SetToolTip( + "Remove the selected temperature sensor " "from the configuration." + ) - sz.Add(bsz, pos = (1, 3)) + sz.Add(bsz, pos=(1, 3)) - k = "MCP3008_SELECT_PIN" - tc = self.addPinChoice(k, labelWidth) - sz.Add(tc, pos = (2, 1)) + k = "MCP3008_SELECT_PIN" + tc = self.addPinChoice(k, labelWidth) + sz.Add(tc, pos=(2, 1)) - self.SetSizer(sz) - self.enableAll(False) + self.SetSizer(sz) + self.enableAll(False) - def setItemSelected(self, n): - self.selection = n - if n is None: - self.bDelete.Enable(False) - self.bModify.Enable(False) - else: - self.bDelete.Enable(True) - self.bModify.Enable(True) + def setItemSelected(self, n): + self.selection = n + if n is None: + self.bDelete.Enable(False) + self.bModify.Enable(False) + else: + self.bDelete.Enable(True) + self.bModify.Enable(True) - def doAdd(self, evt): - nm = [] - for s in self.sensors: - nm.append(s[0]) + def doAdd(self, evt): + nm = [] + for s in self.sensors: + nm.append(s[0]) - dlg = AddSensorDlg(self, nm, self.validPins, self.heatersPage, self.font) - rc = dlg.ShowModal() - if rc == wx.ID_OK: - tt = dlg.getValues() + dlg = AddSensorDlg(self, nm, self.validPins, self.heatersPage, self.font) + rc = dlg.ShowModal() + if rc == wx.ID_OK: + tt = dlg.getValues() - dlg.Destroy() + dlg.Destroy() - if rc != wx.ID_OK: - return + if rc != wx.ID_OK: + return - self.sensors.append(tt) - self.lb.updateList(self.sensors) - self.validateTable() - self.assertModified(True) + self.sensors.append(tt) + self.lb.updateList(self.sensors) + self.validateTable() + self.assertModified(True) - def doModify(self, evt): - if self.selection is None: - return - nm = [] - for s in self.sensors: - nm.append(s[0]) + def doModify(self, evt): + if self.selection is None: + return + nm = [] + for s in self.sensors: + nm.append(s[0]) - s = self.sensors[self.selection] - if s[3] is None: - params = [] - else: - params = s[3] + s = self.sensors[self.selection] + if s[3] is None: + params = [] + else: + params = s[3] - dlg = AddSensorDlg(self, nm, self.validPins, self.heatersPage, self.font, - name = s[0], stype = s[1], pin = s[2], - params = params, modify = True) - rc = dlg.ShowModal() - if rc == wx.ID_OK: - tt = dlg.getValues() + dlg = AddSensorDlg( + self, + nm, + self.validPins, + self.heatersPage, + self.font, + name=s[0], + stype=s[1], + pin=s[2], + params=params, + modify=True, + ) + rc = dlg.ShowModal() + if rc == wx.ID_OK: + tt = dlg.getValues() - dlg.Destroy() + dlg.Destroy() - if rc != wx.ID_OK: - return + if rc != wx.ID_OK: + return - self.assertModified(True) + self.assertModified(True) - self.sensors[self.selection] = tt - self.lb.updateList(self.sensors) - self.validateTable() - self.assertModified(True) + self.sensors[self.selection] = tt + self.lb.updateList(self.sensors) + self.validateTable() + self.assertModified(True) - def doDelete(self, evt): - if self.selection is None: - return + def doDelete(self, evt): + if self.selection is None: + return - self.assertModified(True) + self.assertModified(True) - del self.sensors[self.selection] - self.lb.updateList(self.sensors) - self.validateTable() - self.assertModified(True) + del self.sensors[self.selection] + self.lb.updateList(self.sensors) + self.validateTable() + self.assertModified(True) - def insertValues(self, cfgValues): - Page.insertValues(self, cfgValues) + def insertValues(self, cfgValues): + Page.insertValues(self, cfgValues) - self.bAdd.Enable(True) + self.bAdd.Enable(True) - def setSensors(self, sensors): - self.sensors = sensors - self.lb.updateList(self.sensors) - self.validateTable() + def setSensors(self, sensors): + self.sensors = sensors + self.lb.updateList(self.sensors) + self.validateTable() - def setCandidatePins(self, plist): - if not plist or len(plist) == 0: - self.validPins = pinNames - else: - self.validPins = plist + def setCandidatePins(self, plist): + if not plist or len(plist) == 0: + self.validPins = pinNames + else: + self.validPins = plist - self.validateTable() + self.validateTable() - def validateTable(self): - self.lb.setTableValidity(True) - self.setFieldValidity('SENSORLIST', True) - for i in range(len(self.sensors)): - if self.sensors[i][2] not in self.validPins: - self.lb.setRowValidity(i, False) - self.setFieldValidity('SENSORLIST', False) + def validateTable(self): + self.lb.setTableValidity(True) + self.setFieldValidity("SENSORLIST", True) + for i in range(len(self.sensors)): + if self.sensors[i][2] not in self.validPins: + self.lb.setRowValidity(i, False) + self.setFieldValidity("SENSORLIST", False) - def setHelpText(self, ht): - Page.setHelpText(self, ht) + def setHelpText(self, ht): + Page.setHelpText(self, ht) - k = 'DEFINE_TEMP_SENSOR' - if k in ht.keys(): - self.bAdd.SetToolTip(ht[k]) + k = "DEFINE_TEMP_SENSOR" + if k in ht.keys(): + self.bAdd.SetToolTip(ht[k]) - def getValues(self): - result = Page.getValues(self) + def getValues(self): + result = Page.getValues(self) - values = {} - for k in self.sensorTypeKeys.values(): - values[k] = False + values = {} + for k in self.sensorTypeKeys.values(): + values[k] = False - for s in self.sensors: - values[self.sensorTypeKeys[s[1]]] = True + for s in self.sensors: + values[self.sensorTypeKeys[s[1]]] = True - for v in values.keys(): - result[v] = values[v] + for v in values.keys(): + result[v] = values[v] - return result + return result diff --git a/configtool/settings.py b/configtool/settings.py index b902a46..5025b4c 100644 --- a/configtool/settings.py +++ b/configtool/settings.py @@ -9,121 +9,122 @@ DEFAULT_INIFILE = "configtool.default.ini" class Settings: - def __init__(self, app, folder, ini=None): - self.app = app - self.folder = folder - self.inifile = os.path.join(folder, INIFILE) - self.section = "configtool" + def __init__(self, app, folder, ini=None): + self.app = app + self.folder = folder + self.inifile = os.path.join(folder, INIFILE) + self.section = "configtool" - self.arduinodir = "" - self.cflags = "" - self.ldflags = "" - self.objcopyflags = "" - self.programmer = "wiring" - self.programflags = "" - self.port = "/dev/ttyACM0" - self.uploadspeed = 38400 + self.arduinodir = "" + self.cflags = "" + self.ldflags = "" + self.objcopyflags = "" + self.programmer = "wiring" + self.programflags = "" + self.port = "/dev/ttyACM0" + self.uploadspeed = 38400 - self.t0 = 25; - self.r1 = 0; - self.numTemps = 25 - self.maxAdc = 1023 - self.minAdc = 1 + self.t0 = 25 + self.r1 = 0 + self.numTemps = 25 + self.maxAdc = 1023 + self.minAdc = 1 - # Runtime settings - self.verbose = 0 + # Runtime settings + self.verbose = 0 - self.cfg = ConfigParser.ConfigParser() - self.cfg.optionxform = str + self.cfg = ConfigParser.ConfigParser() + self.cfg.optionxform = str - self.loaded = self.readConfig(ini) + self.loaded = self.readConfig(ini) - def readConfig(self, ini): - if ini: - if not self.cfg.read(ini): - return False - else: - if not self.cfg.read(self.inifile): - if not self.cfg.read(os.path.join(self.folder, DEFAULT_INIFILE)): - print ("Neither of settings files %s or %s exist. Using default values." - % (INIFILE, DEFAULT_INIFILE)) - return False - - if self.cfg.has_section(self.section): - for opt, value in self.cfg.items(self.section): - value = value.replace('\n', ' ') - if opt == "arduinodir": - self.arduinodir = value - elif opt == "cflags": - self.cflags = value - elif opt == "ldflags": - self.ldflags = value - elif opt == "programmer": - self.programmer = value - elif opt == "port": - self.port = value - elif opt == "objcopyflags": - self.objcopyflags = value - elif opt == "programflags": - self.programflags = value - elif opt == "t0": - self.t0 = value - elif opt == "r1": - self.r1 = value - elif opt == "numtemps": - self.numTemps = value - elif opt == "maxadc": - self.maxAdc = value - elif opt == "minadc": - self.minAdc = value - elif opt == "uploadspeed": - self.uploadspeed = value + def readConfig(self, ini): + if ini: + if not self.cfg.read(ini): + return False else: - print("Unknown %s option: %s - ignoring." % (self.section, opt)) - else: - print("Missing %s section - assuming defaults." % self.section) - return False + if not self.cfg.read(self.inifile): + if not self.cfg.read(os.path.join(self.folder, DEFAULT_INIFILE)): + print( + "Neither of settings files %s or %s exist. Using default values." + % (INIFILE, DEFAULT_INIFILE) + ) + return False - return True + if self.cfg.has_section(self.section): + for opt, value in self.cfg.items(self.section): + value = value.replace("\n", " ") + if opt == "arduinodir": + self.arduinodir = value + elif opt == "cflags": + self.cflags = value + elif opt == "ldflags": + self.ldflags = value + elif opt == "programmer": + self.programmer = value + elif opt == "port": + self.port = value + elif opt == "objcopyflags": + self.objcopyflags = value + elif opt == "programflags": + self.programflags = value + elif opt == "t0": + self.t0 = value + elif opt == "r1": + self.r1 = value + elif opt == "numtemps": + self.numTemps = value + elif opt == "maxadc": + self.maxAdc = value + elif opt == "minadc": + self.minAdc = value + elif opt == "uploadspeed": + self.uploadspeed = value + else: + print("Unknown %s option: %s - ignoring." % (self.section, opt)) + else: + print("Missing %s section - assuming defaults." % self.section) + return False - def getValues(self): - return { - "arduinodir": str(self.arduinodir), - "cflags": str(self.cflags), - "ldflags": str(self.ldflags), - "objcopyflags": str(self.objcopyflags), - "programmer": str(self.programmer), - "port": str(self.port), - "t0": str(self.t0), - "r1": str(self.r1), - "numtemps": str(self.numTemps), - "maxadc": str(self.maxAdc), - "minadc": str(self.minAdc), - "uploadspeed": str(self.uploadspeed) - } + return True - def saveSettings(self, inifile = None): - if not inifile: - inifile = self.inifile + def getValues(self): + return { + "arduinodir": str(self.arduinodir), + "cflags": str(self.cflags), + "ldflags": str(self.ldflags), + "objcopyflags": str(self.objcopyflags), + "programmer": str(self.programmer), + "port": str(self.port), + "t0": str(self.t0), + "r1": str(self.r1), + "numtemps": str(self.numTemps), + "maxadc": str(self.maxAdc), + "minadc": str(self.minAdc), + "uploadspeed": str(self.uploadspeed), + } - self.section = "configtool" - try: - self.cfg.add_section(self.section) - except ConfigParser.DuplicateSectionError: - pass + def saveSettings(self, inifile=None): + if not inifile: + inifile = self.inifile - values = self.getValues() - for k in values.keys(): - self.cfg.set(self.section, k, values[k]) + self.section = "configtool" + try: + self.cfg.add_section(self.section) + except ConfigParser.DuplicateSectionError: + pass - try: - cfp = open(inifile, 'wb') - except: - print("Unable to open settings file %s for writing." % inifile) - return False + values = self.getValues() + for k in values.keys(): + self.cfg.set(self.section, k, values[k]) - self.cfg.write(cfp) - cfp.close() + try: + cfp = open(inifile, "wb") + except: + print("Unable to open settings file %s for writing." % inifile) + return False - return True + self.cfg.write(cfp) + cfp.close() + return True diff --git a/configtool/settingsdlg.py b/configtool/settingsdlg.py index 6521849..433a4bf 100644 --- a/configtool/settingsdlg.py +++ b/configtool/settingsdlg.py @@ -1,11 +1,10 @@ - import wx from configtool.data import BSIZESMALL, offsetTcLabel ARDUINODIR = 0 CFLAGS = 1 LDFLAGS = 2 -OBJCOPYFLAGS= 3 +OBJCOPYFLAGS = 3 PROGRAMMER = 4 PROGRAMFLAGS = 5 PORT = 6 @@ -18,168 +17,183 @@ R1 = 12 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 + 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.modified = False - self.Bind(wx.EVT_CLOSE, self.onExit) + self.Bind(wx.EVT_CLOSE, self.onExit) - htArdDir = "Path to the Arduino IDE folder. Configtool will figure the " \ - "details on where to find avr-gcc and avrdude inside there." \ - "\n\nIf empty, the system wide installed tools will be used." - htCFlags = "Flags passed into the avr-gcc compiler. These flags can " \ - "have 3 different variables embedded within them:" \ - "\n\n %F_CPU% will be replaced by the value of the CPU " \ - "Clock Rate." \ - "\n\n %CPU% will be replaced by the value of the CPU. " \ - "\n\n %ALNAME% is the name of the source file being " \ - "compiled with the .c extension replaced by .al.\n\n" \ - "Note: the flag -save-temps=obj does not appear to be a " \ - "valid flag for some compiler versions. Omit the \"=obj\", " \ - "omit the flag entirely, or simply ignore the related warnings." - htLDFlags = "Flags passed to avr-gcc to be passed on to the linker." - htObjCopy = "Flags passed to avr-objcopy." - htProgrammer = "The programmer type - passed to avrdude." - htProgramFlags = "Extra flags passed to avrdude." - htPort = "The port to which the controller is connected. Typically a " \ - "path starting with /dev/... on Linux or Mac OS X, or some " \ - "COM... on Windows." - htSpeed = "The baud rate with which to communicate with the bootloader." - htNumTemps = "The number of entries generated for the thermistor tables. " \ - "Higher numbers slightly increase temperature reading " \ - "accuracy, but also cost binary size. Default is 25." - htMinAdc = "The minimum ADC value returned by the thermistor. Typically 0." - htMaxAdc = "The maximum ADC value returned by the thermistor. " \ - "Typically 1023 (maximum of 10-bit ADCs)." - htT0 = "The T0 value used for thermistor table calculation. Typically 25." - htR1 = "The R1 value used for thermistor table calculation. Typically 0." + htArdDir = ( + "Path to the Arduino IDE folder. Configtool will figure the " + "details on where to find avr-gcc and avrdude inside there." + "\n\nIf empty, the system wide installed tools will be used." + ) + htCFlags = ( + "Flags passed into the avr-gcc compiler. These flags can " + "have 3 different variables embedded within them:" + "\n\n %F_CPU% will be replaced by the value of the CPU " + "Clock Rate." + "\n\n %CPU% will be replaced by the value of the CPU. " + "\n\n %ALNAME% is the name of the source file being " + "compiled with the .c extension replaced by .al.\n\n" + "Note: the flag -save-temps=obj does not appear to be a " + 'valid flag for some compiler versions. Omit the "=obj", ' + "omit the flag entirely, or simply ignore the related warnings." + ) + htLDFlags = "Flags passed to avr-gcc to be passed on to the linker." + htObjCopy = "Flags passed to avr-objcopy." + htProgrammer = "The programmer type - passed to avrdude." + htProgramFlags = "Extra flags passed to avrdude." + htPort = ( + "The port to which the controller is connected. Typically a " + "path starting with /dev/... on Linux or Mac OS X, or some " + "COM... on Windows." + ) + htSpeed = "The baud rate with which to communicate with the bootloader." + htNumTemps = ( + "The number of entries generated for the thermistor tables. " + "Higher numbers slightly increase temperature reading " + "accuracy, but also cost binary size. Default is 25." + ) + htMinAdc = "The minimum ADC value returned by the thermistor. Typically 0." + htMaxAdc = ( + "The maximum ADC value returned by the thermistor. " + "Typically 1023 (maximum of 10-bit ADCs)." + ) + htT0 = "The T0 value used for thermistor table calculation. Typically 25." + htR1 = "The R1 value used for thermistor table calculation. Typically 0." - # This table MUST be in the same order as the constants defined at - # the top of this file. - self.fields = [["Arduino Directory", settings.arduinodir, htArdDir], - ["C Compiler Flags", settings.cflags, htCFlags], - ["LD Flags", settings.ldflags, htLDFlags], - ["Object Copy Flags", settings.objcopyflags, htObjCopy], - ["AVR Programmer", settings.programmer, htProgrammer], - ["AVR Upload Flags", settings.programflags, htProgramFlags], - ["Port", settings.port, htPort], - ["Upload Speed", settings.uploadspeed, htSpeed], - ["Number of Temps", settings.numTemps, htNumTemps], - ["Minimum ADC value", settings.minAdc, htMinAdc], - ["Maximum ADC value", settings.maxAdc, htMaxAdc], - ["T0", settings.t0, htT0], - ["R1", settings.r1, htR1]] + # This table MUST be in the same order as the constants defined at + # the top of this file. + self.fields = [ + ["Arduino Directory", settings.arduinodir, htArdDir], + ["C Compiler Flags", settings.cflags, htCFlags], + ["LD Flags", settings.ldflags, htLDFlags], + ["Object Copy Flags", settings.objcopyflags, htObjCopy], + ["AVR Programmer", settings.programmer, htProgrammer], + ["AVR Upload Flags", settings.programflags, htProgramFlags], + ["Port", settings.port, htPort], + ["Upload Speed", settings.uploadspeed, htSpeed], + ["Number of Temps", settings.numTemps, htNumTemps], + ["Minimum ADC value", settings.minAdc, htMinAdc], + ["Maximum ADC value", settings.maxAdc, htMaxAdc], + ["T0", settings.t0, htT0], + ["R1", settings.r1, htR1], + ] - self.teList = [] + self.teList = [] - hsz = wx.BoxSizer(wx.HORIZONTAL) - hsz.Add((10, 10)) + hsz = wx.BoxSizer(wx.HORIZONTAL) + hsz.Add((10, 10)) - sz = wx.BoxSizer(wx.VERTICAL) - sz.Add((10, 10)) + sz = wx.BoxSizer(wx.VERTICAL) + sz.Add((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, 1, wx.TOP, offsetTcLabel) + 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, 1, wx.TOP, offsetTcLabel) - lsz.Add((8, 8)) + lsz.Add((8, 8)) - te = wx.TextCtrl(self, wx.ID_ANY, f[1], size = (600, -1)) - te.Bind(wx.EVT_TEXT, self.onTextCtrl) - te.SetToolTip(f[2]) - lsz.Add(te) - self.teList.append(te) + te = wx.TextCtrl(self, wx.ID_ANY, f[1], size=(600, -1)) + te.Bind(wx.EVT_TEXT, self.onTextCtrl) + te.SetToolTip(f[2]) + lsz.Add(te) + self.teList.append(te) - sz.Add(lsz) - sz.Add((10, 10)) + sz.Add(lsz) + sz.Add((10, 10)) - sz.Add((20, 20)) + sz.Add((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.Add((5, 5)) + 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.Add((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 + 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.Add((10, 10)) + sz.Add(bsz, 1, wx.ALIGN_CENTER_HORIZONTAL) + sz.Add((10, 10)) - hsz.Add(sz) - hsz.Add((10, 10)) + hsz.Add(sz) + hsz.Add((10, 10)) - self.SetSizer(hsz) - self.setModified(False) + self.SetSizer(hsz) + self.setModified(False) - self.Fit() + 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 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 onTextCtrl(self, evt): + self.setModified(True) + evt.Skip() - def onSave(self, evt): - self.saveValues() - self.EndModal(wx.ID_OK) + def onSave(self, evt): + self.saveValues() + self.EndModal(wx.ID_OK) - def saveValues(self): - self.settings.arduinodir = self.teList[ARDUINODIR].GetValue() - self.settings.cflags = self.teList[CFLAGS].GetValue() - self.settings.ldflags = self.teList[LDFLAGS].GetValue() - self.settings.objcopyflags = self.teList[OBJCOPYFLAGS].GetValue() - self.settings.programmer = self.teList[PROGRAMMER].GetValue() - self.settings.programflags = self.teList[PROGRAMFLAGS].GetValue() - self.settings.port = self.teList[PORT].GetValue() - self.settings.uploadspeed = self.teList[UPLOADSPEED].GetValue() - self.settings.numTemps = self.teList[NUMTEMPS].GetValue() - self.settings.minAdc = self.teList[MINADC].GetValue() - self.settings.maxAdc = self.teList[MAXADC].GetValue() - self.settings.t0 = self.teList[T0].GetValue() - self.settings.r1 = self.teList[R1].GetValue() + def saveValues(self): + self.settings.arduinodir = self.teList[ARDUINODIR].GetValue() + self.settings.cflags = self.teList[CFLAGS].GetValue() + self.settings.ldflags = self.teList[LDFLAGS].GetValue() + self.settings.objcopyflags = self.teList[OBJCOPYFLAGS].GetValue() + self.settings.programmer = self.teList[PROGRAMMER].GetValue() + self.settings.programflags = self.teList[PROGRAMFLAGS].GetValue() + self.settings.port = self.teList[PORT].GetValue() + self.settings.uploadspeed = self.teList[UPLOADSPEED].GetValue() + self.settings.numTemps = self.teList[NUMTEMPS].GetValue() + self.settings.minAdc = self.teList[MINADC].GetValue() + self.settings.maxAdc = self.teList[MAXADC].GetValue() + self.settings.t0 = self.teList[T0].GetValue() + self.settings.r1 = self.teList[R1].GetValue() - self.settings.saveSettings() + self.settings.saveSettings() - def onExit(self, evt): - if not self.confirmLoseChanges("exit"): - return - self.EndModal(wx.ID_EXIT) + 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 + 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() + 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 + if rc != wx.ID_YES: + return False - return True + return True diff --git a/configtool/thermistor.py b/configtool/thermistor.py index 964444f..191608d 100644 --- a/configtool/thermistor.py +++ b/configtool/thermistor.py @@ -5,95 +5,100 @@ import sys class SHThermistor: - def __init__(self, rp, t0, r0, t1, r1, t2, r2): - self.rp = rp + def __init__(self, rp, t0, r0, t1, r1, t2, r2): + self.rp = rp - self.paramsOK = True - try: - T0 = t0 + 273.15; T1 = t1 + 273.15; T2 = t2 + 273.15 - a0 = log(r0); a1 = log(r1); a2 = log(r2) - z = a0 - a1 - y = a0 - a2 - x = 1 / T0 - 1 / T1 - w = 1 / T0 - 1 / T2 - v = a0 ** 3 - a1 ** 3 - u = a0 ** 3 - a2 ** 3 + self.paramsOK = True + try: + T0 = t0 + 273.15 + T1 = t1 + 273.15 + T2 = t2 + 273.15 + a0 = log(r0) + a1 = log(r1) + a2 = log(r2) + z = a0 - a1 + y = a0 - a2 + x = 1 / T0 - 1 / T1 + w = 1 / T0 - 1 / T2 + v = a0 ** 3 - a1 ** 3 + u = a0 ** 3 - a2 ** 3 - self.C = (x - z * w / y) / (v - z * u / y) - self.B = (x - self.C * v) / z - self.A = 1 / T0 - self.C * a0 ** 3 - self.B * a0 - except: - self.paramsOK = False + self.C = (x - z * w / y) / (v - z * u / y) + self.B = (x - self.C * v) / z + self.A = 1 / T0 - self.C * a0 ** 3 - self.B * a0 + except: + self.paramsOK = False - def setting(self, t): - if not self.paramsOK: - return None, None + def setting(self, t): + if not self.paramsOK: + return None, None - try: - T = t + 273.15 - y = (self.A - 1/T) / self.C - x = ((self.B / (3 * self.C)) ** 3 + (y ** 2) / 4) ** 0.5 - r = exp((x - y / 2) ** (1.0/3) - (x + y / 2) ** (1.0/3)) - return self.adc(r), r - except: - return None, None + try: + T = t + 273.15 + y = (self.A - 1 / T) / self.C + x = ((self.B / (3 * self.C)) ** 3 + (y ** 2) / 4) ** 0.5 + r = exp((x - y / 2) ** (1.0 / 3) - (x + y / 2) ** (1.0 / 3)) + return self.adc(r), r + except: + return None, None - def temp(self, adc): - r = self.adcInv(adc) - t = (1.0 / (self.A + self.B * log(r) + self.C * (log(r) ** 3))) - 273.15; - return t + def temp(self, adc): + r = self.adcInv(adc) + t = (1.0 / (self.A + self.B * log(r) + self.C * (log(r) ** 3))) - 273.15 + return t - def adc(self, r): - return 1023.0 * r / (r + self.rp) + def adc(self, r): + return 1023.0 * r / (r + self.rp) + + def adcInv(self, adc): + return (self.rp * adc) / (1023.0 - adc) - def adcInv(self, adc): - return (self.rp * adc)/(1023.0 - adc) class BetaThermistor: - def __init__(self, r0, t0, beta, r1, r2, vadc): - self.paramsOK = True + def __init__(self, r0, t0, beta, r1, r2, vadc): + self.paramsOK = True - try: - self.r0 = r0 - self.t0 = t0 + 273.15 - self.beta = beta - self.vadc = vadc - self.k = r0 * exp(-beta / self.t0) + try: + self.r0 = r0 + self.t0 = t0 + 273.15 + self.beta = beta + self.vadc = vadc + self.k = r0 * exp(-beta / self.t0) - if r1 > 0: - self.vs = r1 * self.vadc / (r1 + r2) - self.rs = r1 * r2 / (r1 + r2) - else: - self.vs = self.vadc - self.rs = r2 - except: - self.paramsOK = False + if r1 > 0: + self.vs = r1 * self.vadc / (r1 + r2) + self.rs = r1 * r2 / (r1 + r2) + else: + self.vs = self.vadc + self.rs = r2 + except: + self.paramsOK = False - def temp(self, adc): - v = adc * self.vadc / 1024 - if (self.vs - v): - r = self.rs * v / (self.vs - v) - else: - r = self.r0 * 10 - try: - return (self.beta / log(r / self.k)) - 273.15 - except: - print("// error for ADC = {adc}, {v}, {r}".format(adc = adc, v = v, r = r)) - return None + def temp(self, adc): + v = adc * self.vadc / 1024 + if self.vs - v: + r = self.rs * v / (self.vs - v) + else: + r = self.r0 * 10 + try: + return (self.beta / log(r / self.k)) - 273.15 + except: + print("// error for ADC = {adc}, {v}, {r}".format(adc=adc, v=v, r=r)) + return None - def resistance(self, t): - return self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) + def resistance(self, t): + return self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) - def setting(self, t): - if not self.paramsOK: - return None, None + def setting(self, t): + if not self.paramsOK: + return None, None - try: - r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) - v = self.vs * r / (self.rs + r) - return round(v / self.vadc * 1024), r - except: - return None, None + try: + r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) + v = self.vs * r / (self.rs + r) + return round(v / self.vadc * 1024), r + except: + return None, None - def adcInv(self, adc): - return (adc * self.vadc)/1024.0 + def adcInv(self, adc): + return (adc * self.vadc) / 1024.0 diff --git a/configtool/thermistorpresets.py b/configtool/thermistorpresets.py index b296eea..07f8472 100644 --- a/configtool/thermistorpresets.py +++ b/configtool/thermistorpresets.py @@ -1,4 +1,3 @@ - # Define thermistor presets. These can either be defined to use the # beta argorithm by specifying 4 parameters: # R0, beta, Rp, Vadc @@ -7,12 +6,12 @@ # Rp, T0, R0, T1, R1, T2, R2 # thermistorPresets = { - "RS 10K": ['10000', '3480', '1600', '5.0'], - "RRRF 10K": ['10000', '3964', '1600', '5.0'], - "ATC Semitec 104GT-2": ['100000', '4267', '4700', '5.0'], - "EPCOS 100K (B57560G1104F)": ['100000', '4092', '4700', '5.0'], - "EPCOS 100K (B5754061104)": ['100000', '4066', '4700', '5.0'], - "EPCOS 100K (B57560G104F)": ['100000', '4036', '4700', '5.0'], - "Honeywell 100K": ['100000', '3974', '4700', '5.0'], - "RRRF 100K": ['100000', '3960', '4700', '5.0'], + "RS 10K": ["10000", "3480", "1600", "5.0"], + "RRRF 10K": ["10000", "3964", "1600", "5.0"], + "ATC Semitec 104GT-2": ["100000", "4267", "4700", "5.0"], + "EPCOS 100K (B57560G1104F)": ["100000", "4092", "4700", "5.0"], + "EPCOS 100K (B5754061104)": ["100000", "4066", "4700", "5.0"], + "EPCOS 100K (B57560G104F)": ["100000", "4036", "4700", "5.0"], + "Honeywell 100K": ["100000", "3974", "4700", "5.0"], + "RRRF 100K": ["100000", "3960", "4700", "5.0"], } diff --git a/configtool/thermistortablefile.py b/configtool/thermistortablefile.py index 2cffc19..848f5f1 100644 --- a/configtool/thermistortablefile.py +++ b/configtool/thermistortablefile.py @@ -5,233 +5,275 @@ from .thermistor import SHThermistor, BetaThermistor class ThermistorTableFile: - def __init__(self, folder): - self.error = False - fn = os.path.join(folder, "thermistortable.h") - try: - self.fp = open(fn, 'wb') - except: - self.error = True + def __init__(self, folder): + self.error = False + fn = os.path.join(folder, "thermistortable.h") + try: + self.fp = open(fn, "wb") + except: + self.error = True - def close(self): - self.fp.close() + def close(self): + self.fp.close() + + def output(self, text): + self.fp.write(text + "\n") - def output(self, text): - self.fp.write(text + "\n") def paramsEqual(p1, p2): - for i in range(len(p1)): - if p1[i] != p2[i]: - return False + for i in range(len(p1)): + if p1[i] != p2[i]: + return False - return True - -def generateTempTables(sensors, settings): - ofp = ThermistorTableFile(settings.folder) - if ofp.error: - return False - - N = int(settings.numTemps) - - tl = [] - for sensor in sensors: - if sensor[3] is not None: - found = False - for t in tl: - if paramsEqual(t[0], sensor[3]): - t[1].append(sensor[0].upper()) - found = True - if not found: - tl.append((sensor[3], [sensor[0].upper()])) - - ofp.output(""); - ofp.output("/**"); - ofp.output(" This file was autogenerated when saving a board with"); - ofp.output(" Teacup's Configtool. You can edit it, but the next board"); - ofp.output(" save operation in Configtool will overwrite it without"); - ofp.output(" asking."); - ofp.output("*/"); - ofp.output(""); - - ofp.output("#define NUMTABLES %d" % len(tl)) - ofp.output("#define NUMTEMPS %d" % N) - ofp.output(""); - - for i in range(len(tl)): - for n in tl[i][1]: - ofp.output("#define THERMISTOR_%s %d" % (n, i)) - ofp.output(""); - - if len(tl) == 0 or N == 0: - ofp.close(); return True - ofp.output("const uint16_t PROGMEM temptable[NUMTABLES][NUMTEMPS][3] = {") - tcount = 0 - for tn in tl: - tcount += 1 - finalTable = tcount == len(tl) - if len(tn[0]) == 4: - BetaTable(ofp, tn[0], tn[1], settings, finalTable) - elif len(tn[0]) == 7: - SteinhartHartTable(ofp, tn[0], tn[1], settings, finalTable) - else: - pass +def generateTempTables(sensors, settings): + ofp = ThermistorTableFile(settings.folder) + if ofp.error: + return False + + N = int(settings.numTemps) + + tl = [] + for sensor in sensors: + if sensor[3] is not None: + found = False + for t in tl: + if paramsEqual(t[0], sensor[3]): + t[1].append(sensor[0].upper()) + found = True + if not found: + tl.append((sensor[3], [sensor[0].upper()])) + + ofp.output("") + ofp.output("/**") + ofp.output(" This file was autogenerated when saving a board with") + ofp.output(" Teacup's Configtool. You can edit it, but the next board") + ofp.output(" save operation in Configtool will overwrite it without") + ofp.output(" asking.") + ofp.output("*/") + ofp.output("") + + ofp.output("#define NUMTABLES %d" % len(tl)) + ofp.output("#define NUMTEMPS %d" % N) + ofp.output("") + + for i in range(len(tl)): + for n in tl[i][1]: + ofp.output("#define THERMISTOR_%s %d" % (n, i)) + ofp.output("") + + if len(tl) == 0 or N == 0: + ofp.close() + return True + + ofp.output("const uint16_t PROGMEM temptable[NUMTABLES][NUMTEMPS][3] = {") + + tcount = 0 + for tn in tl: + tcount += 1 + finalTable = tcount == len(tl) + if len(tn[0]) == 4: + BetaTable(ofp, tn[0], tn[1], settings, finalTable) + elif len(tn[0]) == 7: + SteinhartHartTable(ofp, tn[0], tn[1], settings, finalTable) + else: + pass + + ofp.output("};") + ofp.close() + return True - ofp.output("};") - ofp.close() - return True def BetaTable(ofp, params, names, settings, finalTable): - r0 = params[0] - beta = params[1] - r2 = params[2] - vadc = float(params[3]) - ofp.output(" // %s temp table using Beta algorithm with parameters:" % - (", ".join(names))) - ofp.output((" // R0 = %s, T0 = %s, R1 = %s, R2 = %s, beta = %s, " - "maxadc = %s") % (r0, settings.t0, settings.r1, r2, - beta, settings.maxAdc)) - ofp.output(" {") + r0 = params[0] + beta = params[1] + r2 = params[2] + vadc = float(params[3]) + ofp.output( + " // %s temp table using Beta algorithm with parameters:" % (", ".join(names)) + ) + ofp.output( + (" // R0 = %s, T0 = %s, R1 = %s, R2 = %s, beta = %s, " "maxadc = %s") + % (r0, settings.t0, settings.r1, r2, beta, settings.maxAdc) + ) + ofp.output(" {") - thrm = BetaThermistor(int(r0), int(settings.t0), int(beta), int(settings.r1), - int(r2), vadc) + thrm = BetaThermistor( + int(r0), int(settings.t0), int(beta), int(settings.r1), int(r2), vadc + ) - hiadc = thrm.setting(0)[0] - N = int(settings.numTemps) + hiadc = thrm.setting(0)[0] + N = int(settings.numTemps) - samples = optimizeTempTable(thrm, N, hiadc) + samples = optimizeTempTable(thrm, N, hiadc) - prev = samples[0] - for i in samples: - t = thrm.temp(i) - if t is None: - ofp.output("// ERROR CALCULATING THERMISTOR VALUES AT ADC %d" % i) - continue + prev = samples[0] + for i in samples: + t = thrm.temp(i) + if t is None: + ofp.output("// ERROR CALCULATING THERMISTOR VALUES AT ADC %d" % i) + continue - v = thrm.adcInv(i) - r = thrm.resistance(t) + v = thrm.adcInv(i) + r = thrm.resistance(t) - vTherm = i * vadc / 1024 - ptherm = vTherm * vTherm / r + vTherm = i * vadc / 1024 + ptherm = vTherm * vTherm / r - if i == max(samples): - c = " " + if i == max(samples): + c = " " + else: + c = "," + + delta = (t - thrm.temp(prev)) / (prev - i) if i != prev else 0 + ostr = ( + " {%4s, %5s, %5s}%s // %4d C, %6.0f ohms, %0.3f V," + " %0.2f mW, m = %6.3f" + ) % ( + i, + int(t * 4), + int(delta * 4 * 256), + c, + int(t), + int(round(r)), + vTherm, + ptherm * 1000, + delta, + ) + ofp.output(ostr) + prev = i + + if finalTable: + ofp.output(" }") else: - c = "," + ofp.output(" },") - delta = (t - thrm.temp(prev)) / (prev - i) if i != prev else 0 - ostr = (" {%4s, %5s, %5s}%s // %4d C, %6.0f ohms, %0.3f V," - " %0.2f mW, m = %6.3f") % (i, int(t * 4), int(delta * 4 * 256), c, - int(t), int(round(r)), vTherm, ptherm * 1000, delta) - ofp.output(ostr) - prev = i - - if finalTable: - ofp.output(" }") - else: - ofp.output(" },") def SteinhartHartTable(ofp, params, names, settings, finalTable): - ofp.output((" // %s temp table using Steinhart-Hart algorithm with " - "parameters:") % (", ".join(names))) - ofp.output((" // Rp = %s, T0 = %s, R0 = %s, T1 = %s, R1 = %s, " - "T2 = %s, R2 = %s") % - (params[0], params[1], params[2], params[3], params[4], params[5], - params[6])) - ofp.output(" {") + ofp.output( + (" // %s temp table using Steinhart-Hart algorithm with " "parameters:") + % (", ".join(names)) + ) + ofp.output( + (" // Rp = %s, T0 = %s, R0 = %s, T1 = %s, R1 = %s, " "T2 = %s, R2 = %s") + % (params[0], params[1], params[2], params[3], params[4], params[5], params[6]) + ) + ofp.output(" {") - thrm = SHThermistor(int(params[0]), float(params[1]), int(params[2]), - float(params[3]), int(params[4]), float(params[5]), - int(params[6])) + thrm = SHThermistor( + int(params[0]), + float(params[1]), + int(params[2]), + float(params[3]), + int(params[4]), + float(params[5]), + int(params[6]), + ) - hiadc = thrm.setting(0)[0] - N = int(settings.numTemps) + hiadc = thrm.setting(0)[0] + N = int(settings.numTemps) - samples = optimizeTempTable(thrm, N, hiadc) + samples = optimizeTempTable(thrm, N, hiadc) - prev = samples[0] - for i in samples: - t = thrm.temp(i) - if t is None: - ofp.output("// ERROR CALCULATING THERMISTOR VALUES AT ADC %d" % i) - continue + prev = samples[0] + for i in samples: + t = thrm.temp(i) + if t is None: + ofp.output("// ERROR CALCULATING THERMISTOR VALUES AT ADC %d" % i) + continue - r = int(thrm.adcInv(i)) + r = int(thrm.adcInv(i)) - if i == max(samples): - c = " " + if i == max(samples): + c = " " + else: + c = "," + + delta = (t - thrm.temp(prev)) / (prev - i) if i != prev else 0 + ofp.output( + " {%4d, %5d, %5d}%s // %4d C, %6d ohms, m = %6.3f" + % (i, int(t * 4), int(delta * 4 * 256), c, int(t), int(round(r)), delta) + ) + prev = i + + if finalTable: + ofp.output(" }") else: - c = "," + ofp.output(" },") - delta = (t - thrm.temp(prev)) / (prev - i) if i != prev else 0 - ofp.output(" {%4d, %5d, %5d}%s // %4d C, %6d ohms, m = %6.3f" % - (i, int(t * 4), int(delta * 4 * 256), c, int(t), int(round(r)), - delta)) - prev = i - - if finalTable: - ofp.output(" }") - else: - ofp.output(" },") def optimizeTempTable(thrm, length, hiadc): - # This is a variation of the Ramer-Douglas-Peucker algorithm, see - # https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm - # - # It works like this: - # - # - Calculate all (1024) ideal values. - # - Keep only the ones in the interesting range (0..500C). - # - Insert the two extremes into our sample list. - # - Calculate the linear approximation of the remaining values. - # - Insert the correct value for the "most-wrong" estimation into our - # sample list. - # - Repeat until "N" values are chosen as requested. + # This is a variation of the Ramer-Douglas-Peucker algorithm, see + # https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm + # + # It works like this: + # + # - Calculate all (1024) ideal values. + # - Keep only the ones in the interesting range (0..500C). + # - Insert the two extremes into our sample list. + # - Calculate the linear approximation of the remaining values. + # - Insert the correct value for the "most-wrong" estimation into our + # sample list. + # - Repeat until "N" values are chosen as requested. - # Calculate actual temps for all ADC values. - actual = dict([(x, thrm.temp(1.0 * x)) for x in range(1, int(hiadc + 1))]) + # Calculate actual temps for all ADC values. + actual = dict([(x, thrm.temp(1.0 * x)) for x in range(1, int(hiadc + 1))]) - # Limit ADC range to 0C to 500C. - MIN_TEMP = 0 - MAX_TEMP = 500 - actual = dict([(adc, actual[adc]) for adc in actual - if actual[adc] <= MAX_TEMP and actual[adc] >= MIN_TEMP]) + # Limit ADC range to 0C to 500C. + MIN_TEMP = 0 + MAX_TEMP = 500 + actual = dict( + [ + (adc, actual[adc]) + for adc in actual + if actual[adc] <= MAX_TEMP and actual[adc] >= MIN_TEMP + ] + ) - # Build a lookup table starting with the extremes. - A = min(actual) - B = max(actual) - lookup = dict([(x, actual[x]) for x in [A, B]]) - error = dict({}) - while len(lookup) < length: - error.update(dict([(x, abs(actual[x] - LinearTableEstimate(lookup, x))) - for x in range(A + 1, B)])) + # Build a lookup table starting with the extremes. + A = min(actual) + B = max(actual) + lookup = dict([(x, actual[x]) for x in [A, B]]) + error = dict({}) + while len(lookup) < length: + error.update( + dict( + [ + (x, abs(actual[x] - LinearTableEstimate(lookup, x))) + for x in range(A + 1, B) + ] + ) + ) - # Correct the most-wrong lookup value. - next = max(error, key = error.get) - lookup[next] = actual[next] + # Correct the most-wrong lookup value. + next = max(error, key=error.get) + lookup[next] = actual[next] - # Prepare to update the error range. - A = before(lookup, next) - B = after(lookup, next) + # Prepare to update the error range. + A = before(lookup, next) + B = after(lookup, next) + + return sorted(lookup) - return sorted(lookup) def after(lookup, value): - return min([x for x in lookup.keys() if x > value]) + return min([x for x in lookup.keys() if x > value]) + def before(lookup, value): - return max([x for x in lookup.keys() if x < value]) + return max([x for x in lookup.keys() if x < value]) + def LinearTableEstimate(lookup, value): - if value in lookup: - return lookup[value] + if value in lookup: + return lookup[value] - # Estimate result with linear estimation algorithm. - x0 = before(lookup, value) - x1 = after(lookup, value) - y0 = lookup[x0] - y1 = lookup[x1] - return ((value - x0) * y1 + (x1 - value) * y0) / (x1 - x0) + # Estimate result with linear estimation algorithm. + x0 = before(lookup, value) + x1 = after(lookup, value) + y0 = lookup[x0] + y1 = lookup[x1] + return ((value - x0) * y1 + (x1 - value) * y0) / (x1 - x0) diff --git a/createTemperatureLookup.py b/createTemperatureLookup.py index d726982..44ada79 100755 --- a/createTemperatureLookup.py +++ b/createTemperatureLookup.py @@ -5,14 +5,14 @@ # on a microcontroller # based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html # Modified Thu 10 Feb 2011 02:02:28 PM MST jgilmore for 5D_on_arduino firmware -# temps are now in 14.2 fixed point notation (i.e. measured in quarter-degrees) -# temps are not permitted to be negative (BUG:may result in numtemps fewer than requested) -# bugfix: --num-temps command line option works. -# 2012-11-08, DaveX: Modified to add --vcc=, --min_adc=, --mult and to print per-ADC comments +# temps are now in 14.2 fixed point notation (i.e. measured in quarter-degrees) +# temps are not permitted to be negative (BUG:may result in numtemps fewer than requested) +# bugfix: --num-temps command line option works. +# 2012-11-08, DaveX: Modified to add --vcc=, --min_adc=, --mult and to print per-ADC comments """Thermistor Value Lookup Table Generator -Generates lookup to temperature values for use in a microcontroller in C format based on: +Generates lookup to temperature values for use in a microcontroller in C format based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html The main use is for Arduino programs that read data from the circuit board described here: @@ -21,15 +21,15 @@ The main use is for Arduino programs that read data from the circuit board descr Usage: python createTemperatureLookup.py [options] Options: - -h, --help show this help - --r0=... thermistor rating where # is the ohm rating of the thermistor at t0 (eg: 10K = 10000) - --t0=... thermistor temp rating where # is the temperature in Celsuis to get r0 (from your datasheet) - --beta=... thermistor beta rating. see http://reprap.org/bin/view/Main/MeasuringThermistorBeta - --r1=... R1 rating where # is the ohm rating of R1 (eg: 10K = 10000) - --r2=... R2 rating where # is the ohm rating of R2 (eg: 10K = 10000) - --num-temps=... the number of temperature points to calculate (default: 20) - --max-adc=... the max ADC reading to use. if you use R1, it limits the top value for the thermistor circuit, and thus the possible range of ADC values - --min-adc=... the minimum ADC reading to use. + -h, --help show this help + --r0=... thermistor rating where # is the ohm rating of the thermistor at t0 (eg: 10K = 10000) + --t0=... thermistor temp rating where # is the temperature in Celsuis to get r0 (from your datasheet) + --beta=... thermistor beta rating. see http://reprap.org/bin/view/Main/MeasuringThermistorBeta + --r1=... R1 rating where # is the ohm rating of R1 (eg: 10K = 10000) + --r2=... R2 rating where # is the ohm rating of R2 (eg: 10K = 10000) + --num-temps=... the number of temperature points to calculate (default: 20) + --max-adc=... the max ADC reading to use. if you use R1, it limits the top value for the thermistor circuit, and thus the possible range of ADC values + --min-adc=... the minimum ADC reading to use. --vadc=... ADC reference voltage (high leg of R2) same as Vcc --vcc=... Voltage divider supply (high leg of R2) Unused --table Format data as one of an array of tables @@ -43,171 +43,246 @@ from math import * import sys import getopt + class Thermistor: - "Class to do the thermistor maths" - def __init__(self, r0, t0, beta, r1, r2,vcc,vadc): - self.r0 = r0 # stated resistance, e.g. 10K - self.t0 = t0 + 273.15 # temperature at stated resistance, e.g. 25C - self.beta = beta # stated beta, e.g. 3500 - self.vadc = vadc # ADC reference - self.vcc = vcc # supply voltage to potential divider - self.k = r0 * exp(-beta / self.t0) # constant part of calculation + "Class to do the thermistor maths" - if r1 > 0: - self.vs = r1 * self.vadc / (r1 + r2) # effective bias voltage - self.rs = r1 * r2 / (r1 + r2) # effective bias impedance - else: - self.vs = self.vadc # effective bias voltage - self.rs = r2 # effective bias impedance + def __init__(self, r0, t0, beta, r1, r2, vcc, vadc): + self.r0 = r0 # stated resistance, e.g. 10K + self.t0 = t0 + 273.15 # temperature at stated resistance, e.g. 25C + self.beta = beta # stated beta, e.g. 3500 + self.vadc = vadc # ADC reference + self.vcc = vcc # supply voltage to potential divider + self.k = r0 * exp(-beta / self.t0) # constant part of calculation - def temp(self,adc): - "Convert ADC reading into a temperature in Celcius" - v = adc * self.vadc / 1024 # convert the 10 bit ADC value to a voltage - if (self.vs - v): # can be zero due to accuracy limitations - r = self.rs * v / (self.vs - v) # resistance of thermistor - else: - r = self.r0 * 10 # dummy value - try: - return (self.beta / log(r / self.k)) - 273.15 # temperature - except: - print("// error for ADC={adc}, {v},{r}".format(adc=adc, v=v,r=r)) - return 0 + if r1 > 0: + self.vs = r1 * self.vadc / (r1 + r2) # effective bias voltage + self.rs = r1 * r2 / (r1 + r2) # effective bias impedance + else: + self.vs = self.vadc # effective bias voltage + self.rs = r2 # effective bias impedance - def resistance(self, t): - "Convert a temperature into a thermistor resistance" - return self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) # resistance of the thermistor + def temp(self, adc): + "Convert ADC reading into a temperature in Celcius" + v = adc * self.vadc / 1024 # convert the 10 bit ADC value to a voltage + if self.vs - v: # can be zero due to accuracy limitations + r = self.rs * v / (self.vs - v) # resistance of thermistor + else: + r = self.r0 * 10 # dummy value + try: + return (self.beta / log(r / self.k)) - 273.15 # temperature + except: + print("// error for ADC={adc}, {v},{r}".format(adc=adc, v=v, r=r)) + return 0 + + def resistance(self, t): + "Convert a temperature into a thermistor resistance" + return self.r0 * exp( + self.beta * (1 / (t + 273.15) - 1 / self.t0) + ) # resistance of the thermistor + + def setting(self, t): + "Convert a temperature into a ADC value" + r = self.r0 * exp( + self.beta * (1 / (t + 273.15) - 1 / self.t0) + ) # resistance of the thermistor + v = self.vs * r / (self.rs + r) # the voltage at the potential divider + return round(v / self.vadc * 1024) # the ADC reading - def setting(self, t): - "Convert a temperature into a ADC value" - r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) # resistance of the thermistor - v = self.vs * r / (self.rs + r) # the voltage at the potential divider - return round(v / self.vadc * 1024) # the ADC reading def main(argv): - r0 = 10000; - t0 = 25; - beta = 3947; - r1 = 680; - r2 = 1600; - num_temps = int(20); - max_adc = int(1023); - min_adc = int(1); - vadc=5.0 - vcc=5.0 - mult=4 - table=False + r0 = 10000 + t0 = 25 + beta = 3947 + r1 = 680 + r2 = 1600 + num_temps = int(20) + max_adc = int(1023) + min_adc = int(1) + vadc = 5.0 + vcc = 5.0 + mult = 4 + table = False - try: - opts, args = getopt.getopt(argv, "h", ["help", "r0=", "t0=", "beta=", "r1=", - "r2=", "max-adc=", "min-adc=", - "num-temps=", "vcc=", "vadc=", - "multiplier=", "table"]) - except getopt.GetoptError: - usage() - sys.exit(2) + try: + opts, args = getopt.getopt( + argv, + "h", + [ + "help", + "r0=", + "t0=", + "beta=", + "r1=", + "r2=", + "max-adc=", + "min-adc=", + "num-temps=", + "vcc=", + "vadc=", + "multiplier=", + "table", + ], + ) + except getopt.GetoptError: + usage() + sys.exit(2) - for opt, arg in opts: - if opt in ("-h", "--help"): - usage() - sys.exit() - elif opt == "--r0": - r0 = int(arg) - elif opt == "--t0": - t0 = int(arg) - elif opt == "--beta": - beta = int(arg) - elif opt == "--r1": - r1 = int(arg) - elif opt == "--r2": - r2 = int(arg) - elif opt == "--max-adc": - max_adc = int(arg) - elif opt == "--min-adc": - min_adc = int(arg) - elif opt == "--num-temps": - num_temps = int(arg) - elif opt == "--vadc": - vadc = float(arg) - elif opt == "--vcc": - vcc = float(arg) - elif opt == "--multiplier": - mult = float(arg) - elif opt == "--table": - table = True - if r1: - max_adc = int(1023. * r1 / (r1 + r2)) - else: - max_adc = 1023 + for opt, arg in opts: + if opt in ("-h", "--help"): + usage() + sys.exit() + elif opt == "--r0": + r0 = int(arg) + elif opt == "--t0": + t0 = int(arg) + elif opt == "--beta": + beta = int(arg) + elif opt == "--r1": + r1 = int(arg) + elif opt == "--r2": + r2 = int(arg) + elif opt == "--max-adc": + max_adc = int(arg) + elif opt == "--min-adc": + min_adc = int(arg) + elif opt == "--num-temps": + num_temps = int(arg) + elif opt == "--vadc": + vadc = float(arg) + elif opt == "--vcc": + vcc = float(arg) + elif opt == "--multiplier": + mult = float(arg) + elif opt == "--table": + table = True + if r1: + max_adc = int(1023.0 * r1 / (r1 + r2)) + else: + max_adc = 1023 - increment = int((max_adc-min_adc)/(num_temps-1)); - t = Thermistor(r0, t0, beta, r1, r2, vcc, vadc) + increment = int((max_adc - min_adc) / (num_temps - 1)) + t = Thermistor(r0, t0, beta, r1, r2, vcc, vadc) - adcs = range(min_adc, max_adc, increment); - adcs.append(max_adc) -# adcs = [1, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 130, 150, 190, 220, 250, 300] + adcs = range(min_adc, max_adc, increment) + adcs.append(max_adc) + # adcs = [1, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 130, 150, 190, 220, 250, 300] - #Chop of negative temperatures (as we're using a unsigned 16-bit value for temp) - for i in range(0,len(adcs)): - if int(t.temp(adcs[i])*mult) < 0: - adcs=adcs[0:i+1] - #Replace this with the ADC reading for 0C - adcs[i]=int(t.setting(0)) - #If the closes ADC reading to 0C is negative, convert to next highest ADC reading - if int(t.temp(adcs[i])*mult)<0: - adcs[i] -=1 - break - print("// Thermistor lookup table for RepRap Temperature Sensor Boards (http://reprap.org/wiki/Temperature_Sensor_2_0)") - print("// Made with createTemperatureLookup.py (https://github.com/traumflug/Teacup_Firmware/blob/master/createTemperatureLookup.py)") - print("// (patched per https://github.com/drf5n/Teacup_Firmware/blob/Gen7/createTemperatureLookup.py)") - print("// default thermistor lookup table") - print("// You may be able to improve the accuracy of this table in various ways.") - print("// 1. Measure the actual resistance of the resistor. It's \"nominally\" 4.7K, but that's ± 5%.") - print("// 2. Measure the actual beta of your thermistor:http://reprap.org/wiki/MeasuringThermistorBeta") - print("// 3. Generate more table entries than you need, then trim down the ones in uninteresting ranges.") - print("// In either case you'll have to regenerate this table, which requires python, which is difficult to install on windows.") - print("// Since you'll have to do some testing to determine the correct temperature for your application anyway, you") - print("// may decide that the effort isn't worth it. Who cares if it's reporting the \"right\" temperature as long as it's") - print("// keeping the temperature steady enough to print, right?") - print("// Temp*%s table from https://github.com/drf5n/Teacup_Firmware/blob/Gen7/createTemperatureLookup.py" %mult) - print("// ./createTemperatureLookup.py --r0=%s --t0=%s --r1=%s --r2=%s --beta=%s --max-adc=%s --min-adc=%s --multiplier=%s --vadc=%s" % ( - r0, t0, r1, r2, beta, max_adc, min_adc, mult, vadc)) - print("// r0: %s" % (r0)) - print("// t0: %s" % (t0)) - print("// r1: %s (parallel with rTherm)" % (r1)) - print("// r2: %s (series with rTherm)" % (r2)) - print("// beta: %s" % (beta)) - print("// min adc: %s at %s V" % (min_adc, min_adc*t.vadc/1024)) - print("// max adc: %s at %s V" % (max_adc, max_adc*t.vadc/1024)) - print("// ADC counts from {min} to {max} by {x}".format(min=min_adc, max=max_adc, x=increment)) - if table == True: - print("// #define NUMTABLES 1 // These three lines open the temptable[NUMTABLES]... array") - print("// #define NUMTEMPS %s // ... " % (len(adcs))) - print("// uint16_t temptable[NUMTABLES][NUMTEMPS][2] PROGMEM = { // ...") - print("{ //" + " Table 0 chunk for B={b}, R0={r0}, R1={r1}, R2={r2}, Vref={v}".format(par="{",b=beta,r0=r0,r1=r1,r2=r2,v=vadc)) - else: - print("#define NUMTEMPS %s " % (len(adcs))) - print("const uint16_t temptable[NUMTEMPS][2] PROGMEM = {") - print("// {ADC, temp*%s }, // temp Rtherm Vtherm resolution power" % (mult)) + # Chop of negative temperatures (as we're using a unsigned 16-bit value for temp) + for i in range(0, len(adcs)): + if int(t.temp(adcs[i]) * mult) < 0: + adcs = adcs[0 : i + 1] + # Replace this with the ADC reading for 0C + adcs[i] = int(t.setting(0)) + # If the closes ADC reading to 0C is negative, convert to next highest ADC reading + if int(t.temp(adcs[i]) * mult) < 0: + adcs[i] -= 1 + break + print( + "// Thermistor lookup table for RepRap Temperature Sensor Boards (http://reprap.org/wiki/Temperature_Sensor_2_0)" + ) + print( + "// Made with createTemperatureLookup.py (https://github.com/traumflug/Teacup_Firmware/blob/master/createTemperatureLookup.py)" + ) + print( + "// (patched per https://github.com/drf5n/Teacup_Firmware/blob/Gen7/createTemperatureLookup.py)" + ) + print("// default thermistor lookup table") + print("// You may be able to improve the accuracy of this table in various ways.") + print( + "// 1. Measure the actual resistance of the resistor. It's \"nominally\" 4.7K, but that's ± 5%." + ) + print( + "// 2. Measure the actual beta of your thermistor:http://reprap.org/wiki/MeasuringThermistorBeta" + ) + print( + "// 3. Generate more table entries than you need, then trim down the ones in uninteresting ranges." + ) + print( + "// In either case you'll have to regenerate this table, which requires python, which is difficult to install on windows." + ) + print( + "// Since you'll have to do some testing to determine the correct temperature for your application anyway, you" + ) + print( + "// may decide that the effort isn't worth it. Who cares if it's reporting the \"right\" temperature as long as it's" + ) + print("// keeping the temperature steady enough to print, right?") + print( + "// Temp*%s table from https://github.com/drf5n/Teacup_Firmware/blob/Gen7/createTemperatureLookup.py" + % mult + ) + print( + "// ./createTemperatureLookup.py --r0=%s --t0=%s --r1=%s --r2=%s --beta=%s --max-adc=%s --min-adc=%s --multiplier=%s --vadc=%s" + % (r0, t0, r1, r2, beta, max_adc, min_adc, mult, vadc) + ) + print("// r0: %s" % (r0)) + print("// t0: %s" % (t0)) + print("// r1: %s (parallel with rTherm)" % (r1)) + print("// r2: %s (series with rTherm)" % (r2)) + print("// beta: %s" % (beta)) + print("// min adc: %s at %s V" % (min_adc, min_adc * t.vadc / 1024)) + print("// max adc: %s at %s V" % (max_adc, max_adc * t.vadc / 1024)) + print( + "// ADC counts from {min} to {max} by {x}".format( + min=min_adc, max=max_adc, x=increment + ) + ) + if table == True: + print( + "// #define NUMTABLES 1 // These three lines open the temptable[NUMTABLES]... array" + ) + print("// #define NUMTEMPS %s // ... " % (len(adcs))) + print("// uint16_t temptable[NUMTABLES][NUMTEMPS][2] PROGMEM = { // ...") + print( + "{ //" + + " Table 0 chunk for B={b}, R0={r0}, R1={r1}, R2={r2}, Vref={v}".format( + par="{", b=beta, r0=r0, r1=r1, r2=r2, v=vadc + ) + ) + else: + print("#define NUMTEMPS %s " % (len(adcs))) + print("const uint16_t temptable[NUMTEMPS][2] PROGMEM = {") + print( + "// {ADC, temp*%s }, // temp Rtherm Vtherm resolution power" + % (mult) + ) + + counter = 0 + for adc in adcs: + counter = counter + 1 + degC = t.temp(adc) + resistance = t.resistance(t.temp(adc)) + vTherm = adc * t.vadc / 1024 + ptherm = vTherm * vTherm / resistance + resolution = ( + t.temp(adc - 1) - t.temp(adc) if adc > 1 else t.temp(adc) - t.temp(adc + 1) + ) + sep = "," if counter != len(adcs) else " " + print( + " {%4s, %6s}%s // %7.2f C, %7.0f Ohm, %0.3f V, %0.2f C/count, %0.2fmW" + % ( + adc, + int(t.temp(adc) * mult), + sep, + degC, + resistance, + vTherm, + resolution, + ptherm * 1000, + ) + ) + if table == False: + print("};") + else: + print("}, // remove comma for last table chunk") + print("// }; // Closure for the temptable[NUMTABLES] array") - counter = 0 - for adc in adcs: - counter = counter +1 - degC=t.temp(adc) - resistance=t.resistance(t.temp(adc)) - vTherm= adc*t.vadc/1024 - ptherm= vTherm*vTherm/resistance - resolution = ( t.temp(adc-1)-t.temp(adc) if adc>1 else t.temp(adc) -t.temp(adc+1)) - sep = (',' if counter != len(adcs) else ' ') - print(" {%4s, %6s}%s // %7.2f C, %7.0f Ohm, %0.3f V, %0.2f C/count, %0.2fmW" % (adc, int(t.temp(adc)*mult), sep,degC, resistance,vTherm,resolution,ptherm*1000)) - if table == False: - print("};") - else: - print('}, // remove comma for last table chunk') - print("// }; // Closure for the temptable[NUMTABLES] array") def usage(): print(__doc__) + if __name__ == "__main__": - main(sys.argv[1:]) + main(sys.argv[1:]) diff --git a/extract.py b/extract.py index 80d4e17..a053995 100644 --- a/extract.py +++ b/extract.py @@ -12,6 +12,6 @@ doc = open("gcode_doc.txt", "wt") for line in f.readlines(): m = re_comment.match(line) if m: - doc.write(m.group(1) + "\n") + doc.write(m.group(1) + "\n") f.close() doc.close() diff --git a/research/planes.py b/research/planes.py index 621a80a..c09cf22 100644 --- a/research/planes.py +++ b/research/planes.py @@ -9,100 +9,102 @@ # Translate a point relative to some origin from __future__ import print_function + + def translate(point, origin): - return tuple([a-b for a,b in zip(point, origin)]) + return tuple([a - b for a, b in zip(point, origin)]) + # Given two points in 3d space, define a vector def vector(p1, p2): - return tuple([b-a for a,b in zip(p1,p2)]) + return tuple([b - a for a, b in zip(p1, p2)]) + # Given two vectors in a plane, find the normal vector def normal(u, v): - # A normal vector is the cross-product of two coplanar vectors - return tuple([ - u[1]*v[2] - u[2]*v[1], - u[2]*v[0] - u[0]*v[2], - u[0]*v[1] - u[1]*v[0] - ]) + # A normal vector is the cross-product of two coplanar vectors + return tuple( + [ + u[1] * v[2] - u[2] * v[1], + u[2] * v[0] - u[0] * v[2], + u[0] * v[1] - u[1] * v[0], + ] + ) + def plane_from_three_points(P, Q, R): - u = vector(P, Q) - v = vector(P, R) - n = normal(u, v) + u = vector(P, Q) + v = vector(P, R) + n = normal(u, v) - # Find the coefficients - (A,B,C) = n + # Find the coefficients + (A, B, C) = n - # The equation of the plane is thus Ax+By+Cz+K=0. - # Solve for K to get the final coefficient - (x,y,z) = P - K = -(A*x + B*y + C*z) + # The equation of the plane is thus Ax+By+Cz+K=0. + # Solve for K to get the final coefficient + (x, y, z) = P + K = -(A * x + B * y + C * z) + + return (A, B, C, K) - return (A, B, C, K) # find the Z offset for any x,y # z = -(Ax + By + K) / C -def calcz(x, y, plane, translation=(0,0,0)): - (A,B,C,K) = plane +def calcz(x, y, plane, translation=(0, 0, 0)): + (A, B, C, K) = plane (tx, ty, tz) = translation - return -(A*(x-tx) + B*(y-ty) + K) / C + tz + return -(A * (x - tx) + B * (y - ty) + K) / C + tz # Verify a point is on this plane def validate(plane, point): - (A, B, C, K) = plane - (x, y, z) = point - return z == calcz(x, y, plane) + (A, B, C, K) = plane + (x, y, z) = point + return z == calcz(x, y, plane) def verify_plane(points): - print(' ', '\n '.join([str(p) for p in points])) + print(" ", "\n ".join([str(p) for p in points])) - plane = plane_from_three_points( *points) - print('Plane coordinates: ', plane) + plane = plane_from_three_points(*points) + print("Plane coordinates: ", plane) - if plane[2] == 0: - print(' Error: points are colinear') - return - - valid = True - for p in points: - if not validate(plane, p): - print("Failed: sample point not on plane, ", p) - valid = False - print("Validation:", "Failed" if not valid else "Passed") + if plane[2] == 0: + print(" Error: points are colinear") + return + valid = True + for p in points: + if not validate(plane, p): + print("Failed: sample point not on plane, ", p) + valid = False + print("Validation:", "Failed" if not valid else "Passed") samples = [ - # canonical example - [ (1,-2,0), (4,-2,-2), (4,1,4) ], - - # three colinear points (infinite planes) - [ (2,2,2), (4,4,4), (10,10,10) ], - - # Extreme tilt example in mm - [ (57,123,-5), (200,0,35), (0,207,2) ], - - # Some more examples in um - [ (0, 0, 1300), (200000, 200000, 3500), (0, 150000, -1000) ], - [ (20000, 20000, -300), (220000, 120000, -1700), (120000, 220000, -700) ], - - # some example in tenths of mm - [ (200, 200, -300), (2200, 1200, -1700), (1200, 2200, -700) ], - - [ (20000, 20000 , -300 ), (220000, 120000 , -1700 ), (120000, 220000 , -700 ) ], - [ (200, 200, -300 ), (2200, 1200, -1700 ), (1200, 2200, -700 ) ] + # canonical example + [(1, -2, 0), (4, -2, -2), (4, 1, 4)], + # three colinear points (infinite planes) + [(2, 2, 2), (4, 4, 4), (10, 10, 10)], + # Extreme tilt example in mm + [(57, 123, -5), (200, 0, 35), (0, 207, 2)], + # Some more examples in um + [(0, 0, 1300), (200000, 200000, 3500), (0, 150000, -1000)], + [(20000, 20000, -300), (220000, 120000, -1700), (120000, 220000, -700)], + # some example in tenths of mm + [(200, 200, -300), (2200, 1200, -1700), (1200, 2200, -700)], + [(20000, 20000, -300), (220000, 120000, -1700), (120000, 220000, -700)], + [(200, 200, -300), (2200, 1200, -1700), (1200, 2200, -700)], ] for points in samples: - verify_plane(points) + verify_plane(points) - print("====[Translated]=========") - # Translate plane to origin at P (simplifies by removing K coefficient) - # A*x' + B*y' + C*z' = 0 - P = points[0] - T = translate((0,0,0), P) - xpoints = [translate(p, P) for p in points] - verify_plane(xpoints) - print("=========================\n") + print("====[Translated]=========") + # Translate plane to origin at P (simplifies by removing K coefficient) + # A*x' + B*y' + C*z' = 0 + P = points[0] + T = translate((0, 0, 0), P) + xpoints = [translate(p, P) for p in points] + verify_plane(xpoints) + print("=========================\n") diff --git a/testcases/parse_datalog.py b/testcases/parse_datalog.py index 2c2e5d9..5834ae6 100644 --- a/testcases/parse_datalog.py +++ b/testcases/parse_datalog.py @@ -9,30 +9,32 @@ diff_list = list() pseudo_print = list() -#define STEPS_PER_M_X 40000 -#define STEPS_PER_M_Y 40000 -#define STEPS_PER_M_Z 320000 +# define STEPS_PER_M_X 40000 +# define STEPS_PER_M_Y 40000 +# define STEPS_PER_M_Z 320000 + def parse_stepper_position(line): s_line = line.split() - - X = float(s_line[1]) / 40. # X-axis - Y = float(s_line[2]) / 40. # Y-axis - Z = float(s_line[3]) / 320. # Z-axis + + X = float(s_line[1]) / 40.0 # X-axis + Y = float(s_line[2]) / 40.0 # Y-axis + Z = float(s_line[3]) / 320.0 # Z-axis return X, Y, Z - + def parse_m114_position(line): - s_line = line.split(',') - + s_line = line.split(",") + X = float(s_line[0][4:]) Y = float(s_line[1][2:]) Z = float(s_line[2][2:]) - + return X, Y, Z -with open(in_file, 'r') as file: + +with open(in_file, "r") as file: start_with_line = 50 found_m114 = False @@ -43,22 +45,22 @@ with open(in_file, 'r') as file: found_m114 = False x1, y1, z1 = parse_m114_position(line) x = x2 - x1 - diff_list.append('{}\t\t\t{}\t\t\t{}\t\t\t{}\n'.format(i, x1, x2, x)) - pseudo_print.append('{}\t\t\t{}\t\t\t{}\n'.format(x2, y2, z2)) + diff_list.append("{}\t\t\t{}\t\t\t{}\t\t\t{}\n".format(i, x1, x2, x)) + pseudo_print.append("{}\t\t\t{}\t\t\t{}\n".format(x2, y2, z2)) - if line[0] == '#': - if line[2:6] == 'M114': + if line[0] == "#": + if line[2:6] == "M114": found_m114 = True # find the line with stepping positions before the M114 # print(linecache.getline(in_file, i)) - for x in range(i - 1, i-20, -1): + for x in range(i - 1, i - 20, -1): pre_m114_line = linecache.getline(in_file, x) if len(pre_m114_line.split()) == 21: break x2, y2, z2 = parse_stepper_position(pre_m114_line) -with open(out_file, 'w') as file: +with open(out_file, "w") as file: file.writelines(diff_list) -with open(pp_file, 'w') as file: +with open(pp_file, "w") as file: file.writelines(pseudo_print)