python3: pep8 all files.

e.g. 4 spaces for identation
using black for this:
https://github.com/ambv/black
This commit is contained in:
Nico Tonnhofer 2018-12-28 20:07:51 +01:00
parent 9b49097ac3
commit bf72cb7f10
35 changed files with 6526 additions and 5803 deletions

View File

@ -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())

View File

@ -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

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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])

View File

@ -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+)")

View File

@ -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()

View File

@ -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()

File diff suppressed because it is too large Load Diff

View File

@ -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]

View File

@ -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])

View File

@ -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

View File

@ -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 = "<none>"
self.heaterNames = [self.heaterNameNone]
self.boardHeaters = []
self.processors = []
self.heaterNameNone = "<none>"
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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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",
]

View File

@ -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]))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"],
}

View File

@ -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)

View File

@ -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:])

View File

@ -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()

View File

@ -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")

View File

@ -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)