Import LinuxCNC source tree
7
lib/python/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
nf.py
|
||||
lcnc_realtime.py
|
||||
gscreen
|
||||
gmoccapy/
|
||||
stepconf/
|
||||
pncconf/
|
||||
pyui/
|
||||
135
lib/python/bitfile.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# Copyright 2007 Jeff Epler <jepler@unpythonic.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
#
|
||||
# Info about Xilinx bitfiles:
|
||||
#
|
||||
# The format consists of several variable length chunks, preceded by what
|
||||
# seems to be a constant header (a magic number).
|
||||
#
|
||||
# After the header, each "chunk" consists of a one byte "tag", a two or
|
||||
# four byte length, and "length" bytes of data (the body).
|
||||
#
|
||||
# In some chunks, the body is a zero terminated printable string. In
|
||||
# others it is a blob of binary data. The file format doesn't care.
|
||||
#
|
||||
# Standard Xilinx files use 5 chunks: 'a' through 'd' are zero-terminated
|
||||
# strings with information about the file. 'e' is a large binary blob
|
||||
# with the actual bitstream in it. Xilinx uses 2 byte lengths for chunks
|
||||
# 'a' thru 'd', and 4 bytes for chunk 'e'. This library allows other
|
||||
# chunks, and assume that all have 4 byte lengths, except 'a' thru 'd'.
|
||||
#
|
||||
import struct
|
||||
|
||||
class BitFile:
|
||||
MAXCHUNKS = 50
|
||||
SMALLCHUNKS = "abcd"
|
||||
MAGIC = "\x00\x09" \
|
||||
"\x0f\xf0\x0f\xf0" \
|
||||
"\x0f\xf0\x0f\xf0" \
|
||||
"\x00\x00\x01"
|
||||
ORDER = "abcde"
|
||||
|
||||
def __init__(self, chunks={}):
|
||||
self.chunks = dict(chunks)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.chunks[item]
|
||||
def __setitem__(self, item, value):
|
||||
self.chunks[item] = value
|
||||
def __delitem__(self, item):
|
||||
del self.chunks[item]
|
||||
|
||||
def chunkorder(self, xxx_todo_changeme):
|
||||
(tag, value) = xxx_todo_changeme
|
||||
if tag in self.ORDER:
|
||||
return self.ORDER.index(tag)
|
||||
return 256 + ord(tag)
|
||||
|
||||
@classmethod
|
||||
def fromstring(cls, data):
|
||||
if not data.startswith(cls.MAGIC):
|
||||
raise ValueError("data does not start with the magic number")
|
||||
i = len(cls.MAGIC)
|
||||
chunks = {}
|
||||
while i < len(data):
|
||||
tag = data[i]
|
||||
if tag in cls.SMALLCHUNKS:
|
||||
chunksize = struct.unpack(">H", data[i+1:i+3])[0]
|
||||
i = i + 3
|
||||
else:
|
||||
chunksize = struct.unpack(">I", data[i+1:i+5])[0]
|
||||
i = i + 5
|
||||
chunkdata = data[i:i+chunksize]
|
||||
if tag in chunks:
|
||||
raise ValueError("bitfile has chunk %r more than once" % tag)
|
||||
chunks[tag] = chunkdata
|
||||
i = i + chunksize
|
||||
return cls(chunks)
|
||||
|
||||
@classmethod
|
||||
def fromfile(cls, file):
|
||||
return cls.fromstring(file.read())
|
||||
|
||||
@classmethod
|
||||
def fromfilename(cls, filename):
|
||||
return cls.fromstring(open(filename, "rb").read())
|
||||
|
||||
def tostring(self):
|
||||
result = self.MAGIC
|
||||
for tag, chunkdata in sorted(list(self.chunks.items()), key=self.chunkorder):
|
||||
if len(tag) != 1:
|
||||
raise ValueError("Tag %r must be a length-1 string" % tag)
|
||||
result = result + tag
|
||||
if tag in self.SMALLCHUNKS:
|
||||
result += struct.pack(">H", len(chunkdata))
|
||||
else:
|
||||
result += struct.pack(">I", len(chunkdata))
|
||||
result += chunkdata
|
||||
|
||||
return result
|
||||
|
||||
def tofile(self, file):
|
||||
return file.write(self.tostring())
|
||||
|
||||
def tofilename(self, filename):
|
||||
return open(filename, "wb").write(self.tostring())
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
c = BitFile()
|
||||
c['a'] = "hello world"
|
||||
c['e'] = "goodbye"
|
||||
c['A'] = "shazam"
|
||||
s = c.tostring()
|
||||
print((repr(s)))
|
||||
d = BitFile.fromstring(s)
|
||||
print((d.chunks))
|
||||
assert d.tostring() == s
|
||||
|
||||
for bitfile in sys.argv[1:]:
|
||||
bits = open(bitfile, "rb").read()
|
||||
c = BitFile.fromstring(bits)
|
||||
for k, v in sorted(c.chunks.items()):
|
||||
if k in 'abcd':
|
||||
print((k, v))
|
||||
else:
|
||||
print((k, len(v)))
|
||||
newbits = c.tostring()
|
||||
assert bits == newbits # Assuming the original is in canonical order!
|
||||
print()
|
||||
486
lib/python/bwidget.py
Normal file
@@ -0,0 +1,486 @@
|
||||
# Copyright 2004, 2005, 2006 Jeff Epler <jepler@unpythonic.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
"""Wrapper for BWidget family of widgets"""
|
||||
|
||||
__author__ = "Jeff Epler <jepler AT unpy DOT net>"
|
||||
|
||||
__all__ = """
|
||||
Entry Label Button ArrowButton ProgressBar ScrollView Separator
|
||||
|
||||
MainFrame LabelFrame TitleFrame PanelFrame ScrolledWindow ScrollableFrame
|
||||
PanedWindow ButtonBox PagesManager NoteBook Dialog StatusBar
|
||||
|
||||
LabelEntry ComboBox SpinBox Tree ListBox MessageDialog ProgressDialog
|
||||
PasswordDialog SelectFont SelectColor SelectColorMenu
|
||||
|
||||
CASCADE CHECKBUTTON COMMAND RADIOBUTTON SEPARATOR STATUS PROGRESSION
|
||||
""".split()
|
||||
|
||||
import sys, types
|
||||
import tkinter
|
||||
|
||||
def returnswidget(f):
|
||||
def w(self, *args, **kw):
|
||||
r = f(self, *args, **kw)
|
||||
return self.nametowidget(str(r))
|
||||
w.__doc__ = f.__doc__
|
||||
return w
|
||||
|
||||
def makeswidget(f, t):
|
||||
def w(self, *args, **kw):
|
||||
r = str(f(self, *args, **kw))
|
||||
try:
|
||||
return self.nametowidget(r)
|
||||
except KeyError:
|
||||
return makewidget(self, t, str(r))
|
||||
w.__doc__ = f.__doc__
|
||||
return w
|
||||
|
||||
def nametowidget(self, name):
|
||||
"""Return the Tkinter instance of a widget identified by
|
||||
its Tcl name NAME."""
|
||||
w = self
|
||||
if name[0] == '.':
|
||||
w = w._root()
|
||||
name = name[1:]
|
||||
while name:
|
||||
i = name.find('.')
|
||||
if i >= 0:
|
||||
name, tail = name[:i], name[i+1:]
|
||||
else:
|
||||
tail = ''
|
||||
while tail:
|
||||
try:
|
||||
w.children[name]
|
||||
except KeyError:
|
||||
j = tail.find('.')
|
||||
if j >= 0:
|
||||
name, tail = name + "." + tail[:j], tail[j+1:]
|
||||
else:
|
||||
name, tail = name + "." + tail, ''
|
||||
else:
|
||||
break
|
||||
w = w.children[name]
|
||||
name = tail
|
||||
return w
|
||||
|
||||
tkinter.Misc.nametowidget = nametowidget
|
||||
|
||||
def makewidget(master, klass, path):
|
||||
path = str(path)
|
||||
self = klass()
|
||||
self._name = path[len(master._w)+1:]
|
||||
self._w = path
|
||||
self.children = {}
|
||||
master.children[self._name] = self
|
||||
self.master = master
|
||||
self.tk = master.tk
|
||||
return self
|
||||
|
||||
class BWidget:
|
||||
def _require(self, master):
|
||||
master.tk.call("package", "require", "BWidget")
|
||||
def __init__(self, master, cnf={}, **kw):
|
||||
self._require(master)
|
||||
tkinter.Widget.__init__(self, master, self.__class__.__name__, cnf, kw)
|
||||
|
||||
# Simple Widgets
|
||||
class Entry(BWidget, tkinter.Entry):
|
||||
def invoke(self):
|
||||
return self.tk.call(self._w, "invoke")
|
||||
|
||||
class Label(BWidget, tkinter.Label):
|
||||
def setfocus(self):
|
||||
return self.tk.call(self._w, "setfocus")
|
||||
|
||||
class Button(BWidget, tkinter.Button): pass
|
||||
|
||||
class ArrowButton(BWidget, tkinter.Button): pass
|
||||
|
||||
class ProgressBar(BWidget, tkinter.Widget): pass
|
||||
|
||||
class ScrollView(BWidget, tkinter.Widget): pass
|
||||
|
||||
class Separator(BWidget, tkinter.Widget): pass
|
||||
|
||||
# Manager Widgets
|
||||
|
||||
class _Frame:
|
||||
def getframe(self):
|
||||
return self.tk.call(self._w, "getframe")
|
||||
getframe = makeswidget(getframe, tkinter.Frame)
|
||||
|
||||
class _Items:
|
||||
def itemcget(self, index, option):
|
||||
return self.tk.call(self._w, "itemcget", index, '-' + option)
|
||||
|
||||
def itemconfigure(self, index, cnf=None, **kw):
|
||||
return self._configure(('itemconfigure', index), cnf, kw)
|
||||
|
||||
CASCADE="cascade"
|
||||
CHECKBUTTON="checkbutton"
|
||||
COMMAND="command"
|
||||
RADIOBUTTON="radiobutton"
|
||||
SEPARATOR="separator"
|
||||
STATUS = "status"
|
||||
PROGRESSION = "progression"
|
||||
|
||||
class MainFrame(BWidget, _Frame, tkinter.Widget):
|
||||
def addindicator(self, **kw):
|
||||
return self.tk.call(self._w, "addindicator", *self._options(kw))
|
||||
addindicator = makeswidget(addindicator, Label)
|
||||
|
||||
def getindicator(self, i):
|
||||
return self.tk.call(self._w, "getindicator", i)
|
||||
getindicator = returnswidget(getindicator)
|
||||
|
||||
def getmenu(self):
|
||||
return self.tk.call(self._w, "getmenu")
|
||||
getmenu = returnswidget(getmenu)
|
||||
|
||||
def setmenustate(self, tag, state):
|
||||
return self.tk.call(self._w, "setmenustate", tag, state)
|
||||
|
||||
def showstatusbar(self, name):
|
||||
return self.tk.call(self._w, "showstatusbar", name)
|
||||
|
||||
def showtoolbar(self, index, bool_):
|
||||
return self.tk.call(self._w, "showtoolbar", index, bool_)
|
||||
|
||||
class LabelFrame(BWidget, _Frame, tkinter.Widget):
|
||||
def align(self, others):
|
||||
return self.tk.call("LabelFrame::align", self, *others)
|
||||
|
||||
class TitleFrame(BWidget, _Frame, tkinter.Frame): pass
|
||||
|
||||
class PanelFrame(BWidget, tkinter.Frame): pass
|
||||
|
||||
class ScrolledWindow(BWidget, _Frame, tkinter.Frame):
|
||||
def setwidget(self, child):
|
||||
return self.tk.call(self._w, "setwidget", child)
|
||||
|
||||
class ScrollableFrame(BWidget, _Frame, tkinter.Frame):
|
||||
def see(self, w, vert=None, horiz=None):
|
||||
if vert is None and horiz is None:
|
||||
return self.tk.call(self._w, "see", w)
|
||||
return self.tk.call(self._w, "see", w, vert, horiz)
|
||||
|
||||
def xview(self, *args):
|
||||
return self.tk.call(self._w, "xview", *args)
|
||||
|
||||
def yview(self, *args):
|
||||
return self.tk.call(self._w, "yview", *args)
|
||||
|
||||
class PanedWindow(BWidget, tkinter.Frame):
|
||||
def add(self, **kw):
|
||||
return self.tk.call(self._w, "add", *self._options(kw))
|
||||
add = makeswidget(add, tkinter.Frame)
|
||||
|
||||
def getframe(self, index):
|
||||
return self.tk.call(self._w, "getframe", index)
|
||||
getframe = makeswidget(getframe, tkinter.Frame)
|
||||
|
||||
class ButtonBox(BWidget, _Items, tkinter.Frame):
|
||||
def add(self, **kw):
|
||||
return self.tk.call(self._w, "add", *self._options(kw))
|
||||
add = makeswidget(add, Button)
|
||||
|
||||
def delete(self, index):
|
||||
self.tk.call(self._w, "delete", index)
|
||||
|
||||
def index(self, item):
|
||||
self.tk.call(self._w, "index", item)
|
||||
|
||||
def insert(self, index, *kw):
|
||||
return self.tk.call(self._w, "insert", index, *self._options(kw))
|
||||
insert = makeswidget(insert, Button)
|
||||
|
||||
def invoke(self, index):
|
||||
return self.tk.call(self._w, "invoke", index)
|
||||
|
||||
def setfocus(self, index):
|
||||
return self.tk.call(self._w, "setfocus", index)
|
||||
|
||||
class PagesManager(BWidget, tkinter.Frame):
|
||||
def add(self, page):
|
||||
return self.tk.call(self._w, "add", page)
|
||||
add = makeswidget(add, tkinter.Frame)
|
||||
|
||||
def compute_size(self):
|
||||
return self.tk.call(self._w, "compute_size")
|
||||
|
||||
def delete(self, page):
|
||||
return self.tk.call(self._w, "delete", page)
|
||||
|
||||
def getframe(self, page):
|
||||
return self.tk.call(self._w, "getframe", page)
|
||||
getframe = makeswidget(getframe, tkinter.Frame)
|
||||
|
||||
def pages(self, *args):
|
||||
return self.tk.call(self._w, "pages", *args)
|
||||
|
||||
def raise_page(self, page=None):
|
||||
if page is None:
|
||||
return self.tk.call(self._w, "raise")
|
||||
return self.tk.call(self._w, "raise", page)
|
||||
|
||||
class NoteBook(PagesManager, _Items):
|
||||
def bindtabs(self, event, script):
|
||||
return self.tk.call(self._w, "bindtabs", event, script)
|
||||
|
||||
def delete(self, page, destroyframe=True):
|
||||
return self.tk.call(self._w, "delete", page, destroyframe)
|
||||
|
||||
def insert(self, index, page, **kw):
|
||||
return self.tk.call(self._w, "insert", index, page, *self._options(kw))
|
||||
insert = makeswidget(insert, tkinter.Frame)
|
||||
|
||||
def move(self, page, index):
|
||||
return self.tk.call(self._w, "move", page, index)
|
||||
|
||||
def see(self, page):
|
||||
return self.tk.call(self._w, "see", page)
|
||||
|
||||
def raise_page(self, page=None):
|
||||
if page is None:
|
||||
return self.tk.call(self._w, "raise")
|
||||
else:
|
||||
return self.tk.call(self._w, "raise", page)
|
||||
|
||||
class Dialog(ButtonBox, tkinter.BaseWidget, _Frame):
|
||||
def draw(self, focus=None):
|
||||
if focus is None:
|
||||
return self.tk.call(self, "draw")
|
||||
return self.tk.call(self._w, "draw", focus)
|
||||
|
||||
def enddialog(self):
|
||||
return self.tk.call(self._w, "enddialog")
|
||||
|
||||
def withdraw(self):
|
||||
return self.tk.call(self._w, "withdraw")
|
||||
|
||||
class StatusBar(BWidget): pass
|
||||
|
||||
class LabelEntry(Entry): pass
|
||||
|
||||
class ComboBox(Entry):
|
||||
def bind_entry(self, *args):
|
||||
return self.tk.call(self._w, "bind", *args)
|
||||
|
||||
def getlistbox(self):
|
||||
r = str(self.tk.call(self._w, "getlistbox"))
|
||||
try:
|
||||
return self.nametowidget(r)
|
||||
except KeyError:
|
||||
c = self.tk.call("winfo", "class", r)
|
||||
if c == "ListBox":
|
||||
return makewidget(self, ListBox, r)
|
||||
else:
|
||||
return makewidget(self, tkinter.Listbox, r)
|
||||
|
||||
def getvalue(self):
|
||||
return self.tk.call(self._w, "getvalue")
|
||||
|
||||
def post(self):
|
||||
return self.tk.call(self._w, "post")
|
||||
|
||||
def setvalue(self, index):
|
||||
return self.tk.call(self._w, "setvalue", index)
|
||||
|
||||
def unpost(self):
|
||||
return self.tk.call(self._w, "unpost")
|
||||
|
||||
class SpinBox(Entry):
|
||||
def bind_entry(self, *args):
|
||||
return self.tk.call(self._w, "bind", *args)
|
||||
|
||||
def setvalue(self, index):
|
||||
return self.tk.call(self._w, "setvalue", index)
|
||||
|
||||
def getvalue(self):
|
||||
return self.tk.call(self._w, "getvalue")
|
||||
|
||||
class Tree(BWidget, tkinter.Widget, _Items):
|
||||
def bind_image(self, event, script):
|
||||
return self.tk.call(self._w, "bindImage", event, script)
|
||||
|
||||
def bind_text(self, event, script):
|
||||
return self.tk.call(self._w, "bindText", event, script)
|
||||
|
||||
def closetree(self, node):
|
||||
return self.tk.call(self._w, "closetree", node)
|
||||
|
||||
def delete(self, arg, *args):
|
||||
return self.tk.call(self._w, "delete", arg, *args)
|
||||
|
||||
def edit(self, node, text, *args):
|
||||
"edit(self, node, text, verifycmd=None, clickres=None, select=None)"
|
||||
return self.tk.call(self._w, "edit", node, text, *args)
|
||||
|
||||
def exists(self, node):
|
||||
return self.tk.call(self._w, "exists", node)
|
||||
|
||||
def index(self, node):
|
||||
return self.tk.call(self._w, "index", node)
|
||||
|
||||
def insert(self, index, parent, node="#auto", **kw):
|
||||
return self.tk.call(self._w, "insert", index, parent, node,
|
||||
*self._options(kw))
|
||||
|
||||
def move(self, parent, node, index):
|
||||
return self.tk.call(self._w, "move", parent, node, index)
|
||||
|
||||
def nodes(self, node, *args):
|
||||
return self.tk.call(self._w, "nodes", *args)
|
||||
|
||||
def opentree(self, node, recurse=True):
|
||||
return self.tk.call(self._w, "opentree", node, recurse)
|
||||
|
||||
def parent(self, node):
|
||||
return self.tk.call(self._w, "parent", node)
|
||||
|
||||
def reorder(self, node, neworder):
|
||||
return self.tk.call(self._w, "reorder", node, neworder)
|
||||
|
||||
def see(self, node):
|
||||
return self.tk.call(self._w, "see", node)
|
||||
|
||||
def selection_add(self, *args):
|
||||
return self.tk.call(self._w, "selection", "add", *args)
|
||||
|
||||
def selection_clear(self):
|
||||
return self.tl.call(self._w, "selection", "clear")
|
||||
|
||||
def selection_get(self):
|
||||
return self.tl.call(self._w, "selection", "get")
|
||||
|
||||
def selection_includes(self, node):
|
||||
return self.tl.call(self._w, "selection", "includes")
|
||||
|
||||
def selection_remove(self, *args):
|
||||
return self.tk.call(self._w, "selection", "remove", *args)
|
||||
|
||||
def selection_set(self, *args):
|
||||
return self.tk.call(self._w, "selection", "set", *args)
|
||||
|
||||
def selection_toggle(self, *args):
|
||||
return self.tk.call(self._w, "selection", "toggle", *args)
|
||||
|
||||
def toggle(self, node):
|
||||
return self.tk.call(self._w, "toggle", node)
|
||||
|
||||
def visible(self, node):
|
||||
return self.tk.call(self._w, "visible", node)
|
||||
|
||||
def xview(self, *args):
|
||||
return self.tk.call(self.xview, *args)
|
||||
|
||||
def yview(self, *args):
|
||||
return self.tk.call(self.yview, *args)
|
||||
|
||||
class ListBox(BWidget, tkinter.Widget, _Items):
|
||||
def bind_image(self, event, script):
|
||||
return self.tk.call(self._w, "bindImage", event, script)
|
||||
|
||||
def bind_text(self, event, script):
|
||||
return self.tk.call(self._w, "bindText", event, script)
|
||||
|
||||
def delete(self, arg, *args):
|
||||
return self.tk.call(self._w, "delete", arg, *args)
|
||||
|
||||
def edit(self, item, text, *args):
|
||||
"edit(self, item, text, verifycmd=None, clickres=None, select=None)"
|
||||
return self.tk.call(self._w, "edit", item, text, *args)
|
||||
|
||||
def exists(self, item):
|
||||
return self.tk.call(self._w, "exists", item)
|
||||
|
||||
def index(self, item):
|
||||
return self.tk.call(self._w, "index", item)
|
||||
|
||||
def insert(self, index, item="#auto", **kw):
|
||||
return self.tk.call(self._w, "insert", parent, item,
|
||||
*self._options(kw))
|
||||
|
||||
def items(self, item, *args):
|
||||
return self.tk.call(self._w, "items", *args)
|
||||
|
||||
def move(self, parent, item, index):
|
||||
return self.tk.call(self._w, "move", parent, item, index)
|
||||
|
||||
def reorder(self, node, neworder):
|
||||
return self.tk.call(self._w, "reorder", node, neworder)
|
||||
|
||||
def see(self, node):
|
||||
return self.tk.call(self._w, "see", node)
|
||||
|
||||
def selection_add(self, *args):
|
||||
return self.tk.call(self._w, "selection", "add", *args)
|
||||
|
||||
def selection_clear(self):
|
||||
return self.tl.call(self._w, "selection", "clear")
|
||||
|
||||
def selection_get(self):
|
||||
return self.tl.call(self._w, "selection", "get")
|
||||
|
||||
def selection_includes(self, node):
|
||||
return self.tl.call(self._w, "selection", "includes")
|
||||
|
||||
def selection_remove(self, *args):
|
||||
return self.tk.call(self._w, "selection", "remove", *args)
|
||||
|
||||
def selection_set(self, *args):
|
||||
return self.tk.call(self._w, "selection", "set", *args)
|
||||
|
||||
def selection_toggle(self, *args):
|
||||
return self.tk.call(self._w, "selection", "toggle", *args)
|
||||
|
||||
def xview(self, *args):
|
||||
return self.tk.call(self.xview, *args)
|
||||
|
||||
def yview(self, *args):
|
||||
return self.tk.call(self.yview, *args)
|
||||
|
||||
class MessageDialog(Dialog):
|
||||
def __init__(self, master, cnf={}, **kw):
|
||||
self._require(master)
|
||||
tkinter.Widget.__init__(self, master, "MessageDlg", cnf, kw)
|
||||
|
||||
class ProgressDialog(Dialog):
|
||||
def __init__(self, master, cnf={}, **kw):
|
||||
self._require(master)
|
||||
tkinter.Widget.__init__(self, master, "ProgressDlg", cnf, kw)
|
||||
|
||||
class PasswordDialog(Dialog):
|
||||
def __init__(self, master, cnf={}, **kw):
|
||||
self._require(master)
|
||||
tkinter.Widget.__init__(self, master, "PasswdDlg", cnf, kw)
|
||||
|
||||
class SelectFont(Dialog): pass
|
||||
class SelectColor(Dialog):
|
||||
def setcolor(self, index, color):
|
||||
self.tk.call("SelectColor::setcolor", index, color)
|
||||
|
||||
def SelectColorMenu(master, *args, **kw):
|
||||
i = id([])
|
||||
if master._w=='.':
|
||||
w = '.' + name
|
||||
else:
|
||||
w = master._w + '.' + name
|
||||
return master.tk.call("SelectColor::menu", args, *master._options(kw))
|
||||
|
||||
# vim:ts=8:sts=4:et:
|
||||
213
lib/python/common/colored_formatter.py
Executable file
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2017 Kurt Jacobson
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import re
|
||||
from copy import copy
|
||||
from logging import Formatter
|
||||
|
||||
PREFIX = '\033['
|
||||
SUFFIX = '\033[0m'
|
||||
|
||||
COLORS = {
|
||||
'black': 30,
|
||||
'red': 31,
|
||||
'green': 32,
|
||||
'yellow': 33,
|
||||
'blue': 34,
|
||||
'magenta': 35,
|
||||
'cyan': 36,
|
||||
'white': 37,
|
||||
'bgred': 41,
|
||||
'bggreen': 42,
|
||||
'bgyellow': 43,
|
||||
'bggrey': 100
|
||||
}
|
||||
|
||||
MAPPING = {
|
||||
'VERBOSE': 'bggrey',
|
||||
'DEBUG': 'blue',
|
||||
'INFO': 'cyan',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'bgred',
|
||||
}
|
||||
|
||||
KEY_SET = set(list(COLORS))
|
||||
|
||||
# Returns `text` wrapped in ASCII escape codes to produce `color`
|
||||
def COLORIZE(text, color=None):
|
||||
seq = COLORS.get(color, 37) # default to white
|
||||
return '{0}{1}m{2}{3}'.format(PREFIX, seq, text, SUFFIX)
|
||||
|
||||
# Returns `text` wrapped in Qt Richtext Html codes to produce `color`
|
||||
def QTCOLORIZE(text, color=None):
|
||||
if color in('bgred','bggreen','bgyellow','bggrey'):
|
||||
color = color.replace('bg','')
|
||||
return f'<span style="background-color: {color};">{text}</span>'
|
||||
return f'<font color="{color}">{text}</font>'
|
||||
|
||||
# Matches only the first `color<text>` occurrence
|
||||
# ^(.*?)<([^)]+)>
|
||||
|
||||
# Matches all `color<text>` occurrences, both take the same number of steps
|
||||
# ([^<\s]+)<([^>]+)>
|
||||
# (\w+)<([^>]+)>
|
||||
|
||||
RE = re.compile(r'(\w+)<([^>]+)>')
|
||||
|
||||
|
||||
class ColoredFormatter(Formatter):
|
||||
|
||||
def __init__(self, pattern, pass_clean=True):
|
||||
self.pass_clean = pass_clean
|
||||
Formatter.__init__(self, pattern)
|
||||
|
||||
# Override the Formatter's format method to add ASCII colors
|
||||
# to the levelname and any marked words in the log message.
|
||||
def format(self, record):
|
||||
colored_record = copy(record)
|
||||
|
||||
# Add colors to levelname
|
||||
levelname = colored_record.levelname
|
||||
color = MAPPING.get(levelname, 'white')
|
||||
colored_record.levelname = COLORIZE(levelname, color)
|
||||
|
||||
# Add colors to tagged message text
|
||||
msg = colored_record.getMessage()
|
||||
plain_msg, color_msg = self.color_words(msg)
|
||||
# if next logger will colorize too
|
||||
# then don't clean color codes from msg
|
||||
if self.pass_clean:
|
||||
record.msg = plain_msg
|
||||
colored_record.msg = color_msg
|
||||
|
||||
return Formatter.format(self, colored_record)
|
||||
|
||||
# Replace `color<message>` in the log message with ASCII codes to colorize
|
||||
# the word or phrase in the terminal log handler. Also return a cleaned
|
||||
# version of the message with the tags removed for use by the file handler.
|
||||
def color_words(self, raw_msg):
|
||||
# Function to handle color replacement
|
||||
def color_handler(match):
|
||||
group = match.group(0) # The whole thing: <red>hello
|
||||
color = match.group(1) # Group 1: red
|
||||
word = match.group(2) # Group 2: hello
|
||||
|
||||
if color in KEY_SET: # must be one of the color key words
|
||||
return COLORIZE(word, color)
|
||||
return group # If color is invalid, just return the word without tags
|
||||
|
||||
# Function to handle plain text (stripping tags)
|
||||
def plain_handler(match):
|
||||
return match.group(2) # Just return the word part
|
||||
|
||||
# Perform both replacements in one pass each
|
||||
color_msg = RE.sub(color_handler, raw_msg)
|
||||
plain_msg = RE.sub(plain_handler, raw_msg)
|
||||
|
||||
return plain_msg, color_msg
|
||||
|
||||
class QtColoredFormatter(Formatter):
|
||||
|
||||
def __init__(self, pattern, pass_clean=True):
|
||||
self.pass_clean = pass_clean
|
||||
Formatter.__init__(self, pattern)
|
||||
|
||||
# Override the Formatter's format method to add ASCII colors
|
||||
# to the levelname and any marked words in the log message.
|
||||
def format(self, record):
|
||||
colored_record = copy(record)
|
||||
|
||||
# Add colors to levelname
|
||||
levelname = colored_record.levelname
|
||||
color = MAPPING.get(levelname, 'white')
|
||||
colored_record.levelname = QTCOLORIZE(levelname, color)
|
||||
|
||||
# Add colors to tagged message text
|
||||
msg = colored_record.getMessage()
|
||||
plain_msg, color_msg = self.qtcolor_words(msg)
|
||||
# if next logger will colorize too
|
||||
# then don't clean color codes from msg
|
||||
if self.pass_clean:
|
||||
record.msg = plain_msg
|
||||
colored_record.msg = color_msg
|
||||
|
||||
return Formatter.format(self, colored_record)
|
||||
|
||||
# Replace `color<message>` in the log message with Html codes to colorize
|
||||
def qtcolor_words(self, raw_msg):
|
||||
# Function to handle color replacement
|
||||
def color_handler(match):
|
||||
group = match.group(0) # The whole thing: <red>hello
|
||||
color = match.group(1) # Group 1: red
|
||||
word = match.group(2) # Group 2: hello
|
||||
|
||||
if color in KEY_SET: # must be one of the color key words
|
||||
return QTCOLORIZE(word, color)
|
||||
return group # If color is invalid, just return the word without tags
|
||||
|
||||
# Function to handle plain text (stripping tags)
|
||||
def plain_handler(match):
|
||||
return match.group(2) # Just return the word part
|
||||
|
||||
# Perform both replacements in one pass each
|
||||
color_msg = RE.sub(color_handler, raw_msg)
|
||||
plain_msg = RE.sub(plain_handler, raw_msg)
|
||||
|
||||
return plain_msg, color_msg
|
||||
|
||||
# ----------------------- E X A M P L E -----------------------
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
import logging
|
||||
|
||||
# Create logger
|
||||
log = logging.getLogger(__name__)
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
# Add console handler
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.DEBUG)
|
||||
cf = ColoredFormatter("[%(name)s][%(levelname)s] %(message)s (%(filename)s:%(lineno)d)")
|
||||
ch.setFormatter(cf)
|
||||
log.addHandler(ch)
|
||||
|
||||
# Add file handler
|
||||
fh = logging.FileHandler('demo.log')
|
||||
fh.setLevel(logging.DEBUG)
|
||||
ff = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
fh.setFormatter(ff)
|
||||
log.addHandler(fh)
|
||||
|
||||
# Log some stuff
|
||||
log.debug("Logging demo has green<STARTED>")
|
||||
log.info("Logging to yellow<demo.log> in the script dir")
|
||||
log.warning("This is my last warning, red<take heed>")
|
||||
log.error("This is an error")
|
||||
log.critical("He's dead, Jim")
|
||||
|
||||
# Example exception logging
|
||||
try:
|
||||
print(False + "True")
|
||||
except Exception as e:
|
||||
log.debug('That did not work!', exc_info=e)
|
||||
1518
lib/python/common/hal_glib.py
Normal file
1035
lib/python/common/iniinfo.py
Normal file
145
lib/python/common/logger.py
Executable file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Common GUI Logging Module
|
||||
# Provides a consistent and easy to use logging facility. Log messages printed
|
||||
# to the terminal will be colorized for easy identification of log level.
|
||||
#
|
||||
# Copyright (c) 2017 Kurt Jacobson
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
|
||||
import os
|
||||
import logging
|
||||
from linuxcnc import ini
|
||||
|
||||
# For convenience import log levels so we don't need to import
|
||||
# logging to set the log level within other modules.
|
||||
from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL
|
||||
|
||||
# add a new verbose level
|
||||
VERBOSE = 5
|
||||
logging.VERBOSE = 5
|
||||
logging.addLevelName(logging.VERBOSE, "VERBOSE")
|
||||
|
||||
|
||||
# add a custom log level function
|
||||
def verbose(self, message, *args, **kws):
|
||||
if self.isEnabledFor(VERBOSE):
|
||||
# Yes, logger takes its '*args' as 'args'.
|
||||
self._log(logging.VERBOSE, message, args, **kws)
|
||||
|
||||
# add the custom log level to the library (class patch)
|
||||
logging.Logger.verbose = verbose
|
||||
logging.Logger.VERBOSE = VERBOSE
|
||||
|
||||
# Our custom colorizing formatters for the terminal/file handler
|
||||
from .colored_formatter import ColoredFormatter, QtColoredFormatter
|
||||
|
||||
# Global name of the base logger
|
||||
BASE_LOGGER_NAME = None
|
||||
BASE_LOGGER_FILE = None
|
||||
|
||||
# Define the log message formats
|
||||
TERM_FORMAT = '[%(name)s][%(levelname)s] %(message)s (%(filename)s:%(lineno)d)'
|
||||
FILE_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
QTFILE_FORMAT = '%(levelname)s - %(message)s (%(filename)s:%(lineno)d)<br>'
|
||||
|
||||
# Get logger for module based on module.__name__
|
||||
def getLogger(name):
|
||||
if BASE_LOGGER_NAME is None:
|
||||
initBaseLogger('DEFAULT')
|
||||
name = '{0}.{1}'.format(BASE_LOGGER_NAME, name.upper())
|
||||
return logging.getLogger(name)
|
||||
|
||||
|
||||
# Set global logging level
|
||||
def setGlobalLevel(level):
|
||||
base_log = logging.getLogger(BASE_LOGGER_NAME)
|
||||
base_log.setLevel(level)
|
||||
|
||||
|
||||
# Initialize the base logger
|
||||
def initBaseLogger(name, log_file=None, log_level=DEBUG, logToFile=False):
|
||||
|
||||
global BASE_LOGGER_NAME
|
||||
BASE_LOGGER_NAME = name
|
||||
|
||||
if not log_file:
|
||||
log_file = getLogFile(name)
|
||||
|
||||
global BASE_LOGGER_FILE
|
||||
BASE_LOGGER_FILE = log_file
|
||||
|
||||
# Clear the previous sessions log file
|
||||
with open(log_file, 'w') as fh:
|
||||
pass
|
||||
|
||||
# Create base logger
|
||||
base_log = logging.getLogger(BASE_LOGGER_NAME)
|
||||
base_log.setLevel(log_level)
|
||||
|
||||
# Add console handler
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.VERBOSE)
|
||||
# is this a Qtvcp logger?
|
||||
Qt = bool( 'qt' in name.lower())
|
||||
cf = ColoredFormatter(TERM_FORMAT, pass_clean = not Qt)
|
||||
ch.setFormatter(cf)
|
||||
base_log.addHandler(ch)
|
||||
|
||||
# Add file handler
|
||||
if logToFile:
|
||||
fh = logging.FileHandler(log_file)
|
||||
fh.setLevel(logging.VERBOSE)
|
||||
# if Qtvcp, use Qt Rich text colors
|
||||
# else use plain text
|
||||
if Qt:
|
||||
ff = QtColoredFormatter(QTFILE_FORMAT)
|
||||
else:
|
||||
ff = logging.Formatter(FILE_FORMAT)
|
||||
fh.setFormatter(ff)
|
||||
base_log.addHandler(fh)
|
||||
|
||||
# Get logger for logger
|
||||
log = getLogger(__name__)
|
||||
if logToFile:
|
||||
base_log.info('Logging to: yellow<{}>'.format(log_file))
|
||||
|
||||
return base_log
|
||||
|
||||
|
||||
# Attempt to find the log file specified INI [DISPLAY] LOG_FILE,
|
||||
# failing that log to $HOME/<base_log_name>.log
|
||||
def getLogFile(name):
|
||||
|
||||
# Default log file to use if not specified in INI
|
||||
log_file = os.path.expanduser('~/{}.log').format(name.lower())
|
||||
|
||||
# LinuxCNC may not be running, so use get() to avoid a KeyError
|
||||
ini_file = os.environ.get('INI_FILE_NAME')
|
||||
config_dir = os.environ.get('CONFIG_DIR')
|
||||
|
||||
if ini_file:
|
||||
lcnc_ini = ini(ini_file)
|
||||
path = lcnc_ini.find('DISPLAY', 'LOG_FILE')
|
||||
if path:
|
||||
if path.startswith('~'):
|
||||
# Path is relative to $HOME
|
||||
log_file = os.path.expanduser(path)
|
||||
elif not os.path.isabs(path):
|
||||
# Assume intended path is relative to the INI file
|
||||
log_file = os.path.join(config_dir, path)
|
||||
else:
|
||||
# It must be an absolute path then
|
||||
log_file = os.path.realpath(path)
|
||||
|
||||
return log_file
|
||||
8
lib/python/gladevcp/READ_ME
Normal file
@@ -0,0 +1,8 @@
|
||||
To use gladevcp in a run in place environment just source scripts/rip-environment
|
||||
and it will set all paths.
|
||||
|
||||
For package installations the required files will be placed in the
|
||||
/usr/share/glade system folder.
|
||||
|
||||
When using gladevcp widgets in python programs you need to import
|
||||
gladevcp.makepins.
|
||||
70
lib/python/gladevcp/__init__.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from .hal_pythonplugin import *
|
||||
|
||||
try:
|
||||
import importlib
|
||||
support_aux_apps = True
|
||||
except:
|
||||
support_aux_apps = False
|
||||
print("\n")
|
||||
print("Gladevcp: Cannot import importlib")
|
||||
print(" Auxiliary Gladevcp apps not available\n")
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Support auxiliary gladevcp apps
|
||||
import os,sys,glob,subprocess
|
||||
|
||||
def excluded_filename(fname):
|
||||
exclude_list = ["install","setup"]
|
||||
for e in exclude_list:
|
||||
if e in fname: return True
|
||||
return False
|
||||
|
||||
if support_aux_apps:
|
||||
#----------------------------------------------------------------------
|
||||
modnames = []
|
||||
#----------------------------------------------------------------------
|
||||
# Auxiliary gladevcp apps specified by environmental variable
|
||||
gladevcp_user_extras = os.getenv('GLADEVCP_EXTRAS')
|
||||
if gladevcp_user_extras is not None:
|
||||
print("gladevcp: GLADEVCP_EXTRAS:",gladevcp_user_extras)
|
||||
for extradir in gladevcp_user_extras.split(":"):
|
||||
for fname in glob.glob(extradir + "/*.py"):
|
||||
if excluded_filename(fname):
|
||||
print("gladevcp: excluded filename:",fname)
|
||||
continue
|
||||
modname = os.path.basename(fname).split(".")[0]
|
||||
if modname in modnames:
|
||||
print("gladevcp: rejecting duplicate:",fname)
|
||||
continue
|
||||
modnames.append(modname)
|
||||
sys.path.insert(0,extradir) # prepend
|
||||
importlib.import_module(modname)
|
||||
print("gladevcp: importing:",fname)
|
||||
#----------------------------------------------------------------------
|
||||
# Auxiliary gladevcp apps may be installed in a known location
|
||||
# location defined by the substitution item LINUXCNC_AUX_GLADEVCP.
|
||||
# The location is available from the script linuxcnc_var
|
||||
# (this script should always be in PATH for both RIP builds and
|
||||
# deb installs of LinuxCNC)
|
||||
s = subprocess.Popen(['linuxcnc_var','LINUXCNC_AUX_GLADEVCP']
|
||||
,stdout=subprocess.PIPE
|
||||
,stderr=subprocess.PIPE
|
||||
)
|
||||
p,e = s.communicate()
|
||||
gladevcp_aux_apps_dir = p.strip().decode() # remove trailing \n
|
||||
for auxdir in glob.glob(gladevcp_aux_apps_dir + "/*"):
|
||||
print("gladevcp: auxiliary dir:",auxdir)
|
||||
for fname in glob.glob(auxdir + "/*.py"):
|
||||
if excluded_filename(fname):
|
||||
print("gladevcp: excluded filename:",fname)
|
||||
continue
|
||||
modname = os.path.basename(fname).split(".")[0]
|
||||
if modname in modnames:
|
||||
print("gladevcp: rejecting duplicate:",fname)
|
||||
continue
|
||||
modnames.append(modname)
|
||||
sys.path.insert(0,auxdir) # prepend
|
||||
importlib.import_module(modname)
|
||||
print("gladevcp: importing:",fname)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
@@ -0,0 +1,15 @@
|
||||
# Modification of Probe Screen application by Serguei Glavatski (c) 2015
|
||||
This modification moved the icons from one window to containers with switchable vertical tabs. The goal of this modification is to minimize the window.
|
||||
The modification was made by zz912.
|
||||
|
||||
|
||||
**Actual version and manual:**
|
||||
- [https://vers.ge/en/blog/useful-articles/probe-screen-v28](https://vers.ge/en/blog/useful-articles/probe-screen-v28)
|
||||
- [https://github.com/verser-git/probe_screen_v2.9](https://github.com/verser-git/probe_screen_v2.9)
|
||||
|
||||
---
|
||||
|
||||
### Load with gladevcp command:
|
||||
```bash
|
||||
gladevcp gtk_little_probe
|
||||
```
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 800 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 736 B |
|
After Width: | Height: | Size: 656 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 774 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1006 B |
|
After Width: | Height: | Size: 1020 B |
|
After Width: | Height: | Size: 945 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
26
lib/python/gladevcp/builtin-panels/gtk_mesa_tests/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# GTK Mesa tests screen
|
||||
Embedded panel for PC and Mesa tests by zz912
|
||||
|
||||
This screen allows the user to verify whether they have a suitable and well-tuned PC for their Mesa card.
|
||||
|
||||
Based on the design of Mesa Configuration Tool II
|
||||
https://github.com/jethornton/mesact
|
||||
Copyright (c) 2022 jethornton
|
||||
|
||||
---
|
||||
|
||||
### Load with gladevcp command:
|
||||
```bash
|
||||
gladevcp gtk_mesa_tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Modification INI file for embedded panel in Gmoccapy:
|
||||
```ini
|
||||
EMBED_TAB_NAME = Mesa PC
|
||||
EMBED_TAB_LOCATION = ntb_setup
|
||||
EMBED_TAB_COMMAND = gladevcp -x {XID} gtk_mesa_tests
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,936 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.40.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.24"/>
|
||||
<object class="GtkAdjustment" id="adj_read_tmax">
|
||||
<property name="upper">1000000000000</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="adj_servo_thread_period">
|
||||
<property name="upper">1000000000000</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="adj_servo_thread_period_nic">
|
||||
<property name="upper">1000000000000</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="adj_servo_thread_tmax">
|
||||
<property name="upper">1000000000000</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="adj_write_tmax">
|
||||
<property name="upper">1000000000000</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="window1">
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkNotebook" id="ntb_tests">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box_servothread">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<!-- n-columns=3 n-rows=3 -->
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="label" translatable="yes">Servo Thread</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="sbtn_servo_thread_tmax">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="width-chars">10</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">adj_servo_thread_tmax</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="label" translatable="yes">Servo Thread</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_servo_thread_tmax">
|
||||
<property name="label" translatable="yes"> Get tmax</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_servo_thread_tmax_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_servo_thread_period">
|
||||
<property name="label" translatable="yes">Get period</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_servo_thread_period_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="sbtn_servo_thread_period">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="width-chars">10</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">adj_servo_thread_period</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_calc_servo">
|
||||
<property name="label" translatable="yes">Calculate</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_calc_servo_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="lbl_result_servo">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">%</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Under 70% is good, over 70% try
|
||||
increasing Thread Period</property>
|
||||
<property name="justify">center</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes"><b>Servo Thread Test</b></property>
|
||||
<property name="use-markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">The Default Packet Time Timeout
|
||||
is 80% of the Servo Thread Period</property>
|
||||
<property name="justify">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="textview_servo">
|
||||
<property name="name">textview_servo</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="wrap-mode">word</property>
|
||||
<property name="accepts-tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="lbl_servothread">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Servo Thread</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box_nic">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<!-- n-columns=3 n-rows=5 -->
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_read_tmax">
|
||||
<property name="label" translatable="yes">Get read.tmax</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_read_tmax_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_write_tmax">
|
||||
<property name="label" translatable="yes">Get write.tmax</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_write_tmax_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_nic_calculate">
|
||||
<property name="label" translatable="yes">Calculate</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_nic_calculate_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_servo_thread_period_nic">
|
||||
<property name="label" translatable="yes">Get period</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_servo_thread_period_nic_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">Packet Time is in units of servo thread period.
|
||||
If the Packet Time is greater than 50%
|
||||
try increasing the thread period.</property>
|
||||
<property name="justify">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">4</property>
|
||||
<property name="width">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="sbtn_read_tmax">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="width-chars">10</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">adj_read_tmax</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="sbtn_write_tmax">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="width-chars">10</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">adj_write_tmax</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="sbtn_servo_thread_period_nic">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="width-chars">10</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">adj_servo_thread_period_nic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="lbl_result_nic">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">%</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="label" translatable="yes">Servo Thread</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes"><b>NIC test</b></property>
|
||||
<property name="use-markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_packet_error">
|
||||
<property name="label" translatable="yes">Get Packet error</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_packet_error_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="lbl_packet_error">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Click on Get packet error</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label-xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">The ideal state is when the packet error is 0</property>
|
||||
<property name="justify">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes"><b>Packet</b></property>
|
||||
<property name="use-markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="textview_nic">
|
||||
<property name="name">textview_nic</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="wrap-mode">word</property>
|
||||
<property name="accepts-tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="lbl_nic">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">NIC</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box_pc">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="textview_pc_info">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="wrap-mode">word</property>
|
||||
<property name="accepts-tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_mb_info">
|
||||
<property name="label" translatable="yes">Motherboard Info</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_mb_info_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_cpu_info">
|
||||
<property name="label" translatable="yes">CPU Info</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_cpu_info_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_nic_info">
|
||||
<property name="label" translatable="yes">NIC Info</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_nic_info_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_copy">
|
||||
<property name="label" translatable="yes">Copy</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_copy_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="lbl_pc">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">PC info</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box_ip">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="textview_ip_info">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="wrap-mode">word</property>
|
||||
<property name="accepts-tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btn_ip_nic">
|
||||
<property name="label" translatable="yes">IP and NIC Info</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<signal name="released" handler="on_btn_ip_nic_released" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="lbl_ip">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">IP info</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
<property name="tab-fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,450 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
GTK Mesa tests screen
|
||||
|
||||
Embedded panel for PC and Mesa tests by zz912
|
||||
|
||||
Based on the design of Mesa Configuration Tool II
|
||||
https://github.com/jethornton/mesact
|
||||
Copyright (c) 2022 jethornton
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any laforter version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
"""
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('Gdk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
|
||||
import subprocess # Used to run external system commands and capture their output
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
|
||||
class MesaTests:
|
||||
def __init__(self, halcomp,builder,useropts):
|
||||
self.builder = builder
|
||||
self.password = None # cache for sudo password
|
||||
|
||||
textview_servo = self.builder.get_object("textview_servo")
|
||||
buffer_servo = textview_servo.get_buffer()
|
||||
buffer_servo.connect("changed", self.on_textbuffer_changed)
|
||||
|
||||
textview_nic = self.builder.get_object("textview_nic")
|
||||
buffer_nic = textview_nic.get_buffer()
|
||||
buffer_nic.connect("changed", self.on_textbuffer_changed)
|
||||
|
||||
|
||||
def ask_sudo_password(self, gtkbutton):
|
||||
"""
|
||||
Show a simple dialog asking for the sudo password.
|
||||
Returns the password string or None if cancelled.
|
||||
"""
|
||||
parent = gtkbutton.get_toplevel()
|
||||
|
||||
dialog = Gtk.Dialog(
|
||||
title="sudo password",
|
||||
transient_for=parent,
|
||||
modal=True,
|
||||
)
|
||||
|
||||
# Set dialog default size (width x height)
|
||||
dialog.set_default_size(300, 100)
|
||||
|
||||
# Center dialog buttons horizontally
|
||||
action_area = dialog.get_action_area()
|
||||
action_area.set_halign(Gtk.Align.CENTER)
|
||||
|
||||
# Add dialog buttons
|
||||
dialog.add_button("_OK", Gtk.ResponseType.OK)
|
||||
dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL)
|
||||
|
||||
# Get the dialog content area
|
||||
box = dialog.get_content_area()
|
||||
box.set_spacing(10)
|
||||
|
||||
# Create UI elements
|
||||
label = Gtk.Label(label="Please enter sudo password:")
|
||||
label.set_halign(Gtk.Align.START) # Align label to the left
|
||||
entry = Gtk.Entry()
|
||||
entry.set_visibility(False) # Hide text (password mode)
|
||||
entry.set_activates_default(True) # Enter key triggers default button
|
||||
|
||||
# Pack UI elements into the dialog
|
||||
box.add(label)
|
||||
box.add(entry)
|
||||
box.show_all()
|
||||
|
||||
dialog.set_default_response(Gtk.ResponseType.OK)
|
||||
response = dialog.run()
|
||||
|
||||
password = None
|
||||
if response == Gtk.ResponseType.OK:
|
||||
password = entry.get_text()
|
||||
|
||||
dialog.destroy()
|
||||
return password or None
|
||||
|
||||
def on_btn_ip_nic_released(self, gtkbutton):
|
||||
ip = subprocess.check_output(['ip', '-br', 'addr', 'show'], text=True)
|
||||
|
||||
textview = self.builder.get_object("textview_ip_info")
|
||||
buffer = textview.get_buffer()
|
||||
buffer.set_text(ip)
|
||||
|
||||
def on_btn_mb_info_released(self, gtkbutton):
|
||||
# Get / cache sudo password
|
||||
if not self.password:
|
||||
self.password = self.ask_sudo_password(gtkbutton)
|
||||
|
||||
# Get the TextView for output
|
||||
textview = self.builder.get_object("textview_pc_info")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
if self.password is None:
|
||||
buffer.set_text("Operation cancelled. No password provided.")
|
||||
return
|
||||
|
||||
try:
|
||||
# Run dmidecode -t 2 with sudo
|
||||
p = Popen(
|
||||
['sudo', '-S', 'dmidecode', '-t', '2'],
|
||||
stdin=PIPE,
|
||||
stdout=PIPE,
|
||||
stderr=PIPE,
|
||||
text=True,
|
||||
)
|
||||
|
||||
stdout, stderr = p.communicate(self.password + '\n')
|
||||
|
||||
if p.returncode == 0:
|
||||
output = stdout
|
||||
else:
|
||||
output = stderr
|
||||
|
||||
result_text = f"Return Code: {p.returncode}\n{output}"
|
||||
buffer.set_text(result_text)
|
||||
|
||||
except Exception as e:
|
||||
buffer.set_text(f"Error running dmidecode:\n{e}")
|
||||
|
||||
def on_btn_cpu_info_released(self, gtkbutton):
|
||||
result = subprocess.check_output("lscpu",shell=True, text=True)
|
||||
|
||||
textview = self.builder.get_object("textview_pc_info")
|
||||
buffer = textview.get_buffer()
|
||||
buffer.set_text(result)
|
||||
|
||||
def on_btn_nic_info_released(self, gtkbutton):
|
||||
result = subprocess.check_output("lspci | grep -i 'ethernet'",shell=True, text=True)
|
||||
|
||||
textview = self.builder.get_object("textview_pc_info")
|
||||
buffer = textview.get_buffer()
|
||||
buffer.set_text(result)
|
||||
|
||||
def on_btn_copy_released(self, gtkbutton):
|
||||
"""
|
||||
Copy the content of textview_pc_info to the system clipboard
|
||||
and replace the content with a confirmation message.
|
||||
"""
|
||||
# Get the TextView and its buffer
|
||||
textview = self.builder.get_object("textview_pc_info")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
# Read current text from the buffer
|
||||
start_iter = buffer.get_start_iter()
|
||||
end_iter = buffer.get_end_iter()
|
||||
text = buffer.get_text(start_iter, end_iter, True)
|
||||
|
||||
# Access the system clipboard
|
||||
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
||||
|
||||
# Set clipboard text
|
||||
clipboard.set_text(text, -1)
|
||||
|
||||
# Replace TextView content with notification message
|
||||
buffer.set_text("Output copied to clipboard")
|
||||
|
||||
def on_btn_servo_thread_tmax_released(self, gtkbutton):
|
||||
result = subprocess.check_output("halcmd show param servo-thread.tmax",shell=True, text=True)
|
||||
|
||||
# Remove empty lines
|
||||
result = "\n".join(
|
||||
line for line in result.splitlines()
|
||||
if line.strip() # keeps only non-empty lines
|
||||
)
|
||||
|
||||
textview = self.builder.get_object("textview_servo")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), result)
|
||||
|
||||
value = None
|
||||
for line in result.splitlines():
|
||||
line = line.strip()
|
||||
if line.endswith("servo-thread.tmax"):
|
||||
parts = line.split()
|
||||
value = int(parts[3]) # 4. column is Value
|
||||
break
|
||||
|
||||
spin_thread_tmax = self.builder.get_object("sbtn_servo_thread_tmax")
|
||||
spin_thread_tmax.set_value(value)
|
||||
|
||||
def on_btn_servo_thread_period_released(self, combo):
|
||||
result = subprocess.check_output("halcmd show thread servo-thread",shell=True, text=True)
|
||||
|
||||
# Remove empty lines
|
||||
result = "\n".join(
|
||||
line for line in result.splitlines()
|
||||
if line.strip() # keeps only non-empty lines
|
||||
)
|
||||
|
||||
textview = self.builder.get_object("textview_servo")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), result)
|
||||
|
||||
value = None
|
||||
for line in result.splitlines():
|
||||
line = line.strip()
|
||||
if "servo-thread" in line:
|
||||
parts = line.split()
|
||||
value = int(parts[0]) # 1. column is Value
|
||||
break
|
||||
|
||||
spin_thread_period = self.builder.get_object("sbtn_servo_thread_period")
|
||||
spin_thread_period.set_value(value)
|
||||
|
||||
def on_btn_calc_servo_released(self, gtkbutton):
|
||||
# Get UI objects
|
||||
textview = self.builder.get_object("textview_servo")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
spin_thread_tmax = self.builder.get_object("sbtn_servo_thread_tmax")
|
||||
t_max = spin_thread_tmax.get_value()
|
||||
|
||||
spin_thread_period = self.builder.get_object("sbtn_servo_thread_period")
|
||||
period = spin_thread_period.get_value()
|
||||
|
||||
label_result = self.builder.get_object("lbl_result_servo")
|
||||
|
||||
# Conditions
|
||||
if t_max <= 0:
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), "Servo Thread tmax must be greater than 0")
|
||||
return
|
||||
|
||||
if period <= 0:
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), "Servo Thread period must be greater than 0")
|
||||
return
|
||||
|
||||
# Calculation
|
||||
result = t_max / period * 100
|
||||
label_result.set_text(f'{result:.0f}%')
|
||||
|
||||
|
||||
def on_btn_read_tmax_released(self, gtkbutton):
|
||||
result = subprocess.check_output("halcmd show param hm2*read.tmax",shell=True, text=True)
|
||||
|
||||
# Remove empty lines
|
||||
result = "\n".join(
|
||||
line for line in result.splitlines()
|
||||
if line.strip() # keeps only non-empty lines
|
||||
)
|
||||
|
||||
textview = self.builder.get_object("textview_nic")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), result)
|
||||
|
||||
value = None
|
||||
for line in result.splitlines():
|
||||
line = line.strip()
|
||||
if "read.tmax" in line:
|
||||
parts = line.split()
|
||||
value = int(parts[3]) # 4. column is Value
|
||||
break
|
||||
|
||||
spin_thread_period = self.builder.get_object("sbtn_read_tmax")
|
||||
spin_thread_period.set_value(value)
|
||||
|
||||
def on_btn_write_tmax_released(self, gtkbutton):
|
||||
result = subprocess.check_output("halcmd show param hm2*write.tmax",shell=True, text=True)
|
||||
|
||||
# Remove empty lines
|
||||
result = "\n".join(
|
||||
line for line in result.splitlines()
|
||||
if line.strip() # keeps only non-empty lines
|
||||
)
|
||||
|
||||
textview = self.builder.get_object("textview_nic")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), result)
|
||||
|
||||
value = None
|
||||
for line in result.splitlines():
|
||||
line = line.strip()
|
||||
if "write.tmax" in line:
|
||||
parts = line.split()
|
||||
value = int(parts[3]) # 4. column is Value
|
||||
break
|
||||
|
||||
spin_thread_period = self.builder.get_object("sbtn_write_tmax")
|
||||
spin_thread_period.set_value(value)
|
||||
|
||||
def on_btn_servo_thread_period_nic_released(self, combo):
|
||||
result = subprocess.check_output("halcmd show thread servo-thread",shell=True, text=True)
|
||||
|
||||
# Remove empty lines
|
||||
result = "\n".join(
|
||||
line for line in result.splitlines()
|
||||
if line.strip() # keeps only non-empty lines
|
||||
)
|
||||
|
||||
textview = self.builder.get_object("textview_nic")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), result)
|
||||
|
||||
value = None
|
||||
for line in result.splitlines():
|
||||
line = line.strip()
|
||||
if "servo-thread" in line:
|
||||
parts = line.split()
|
||||
value = int(parts[0]) # 1. column is Value
|
||||
break
|
||||
|
||||
spin_thread_period = self.builder.get_object("sbtn_servo_thread_period_nic")
|
||||
spin_thread_period.set_value(value)
|
||||
|
||||
def on_btn_nic_calculate_released(self, gtkbutton):
|
||||
# Get UI objects
|
||||
textview = self.builder.get_object("textview_nic")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
spin_read_tmax = self.builder.get_object("sbtn_read_tmax")
|
||||
read_tmax = spin_read_tmax.get_value()
|
||||
|
||||
spin_write_tmax = self.builder.get_object("sbtn_write_tmax")
|
||||
write_tmax = spin_write_tmax.get_value()
|
||||
|
||||
spin_thread_period = self.builder.get_object("sbtn_servo_thread_period_nic")
|
||||
period = spin_thread_period.get_value()
|
||||
|
||||
label_result = self.builder.get_object("lbl_result_nic")
|
||||
|
||||
# Conditions
|
||||
if read_tmax <= 0:
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), "Parameter read.tmax must be greater than 0")
|
||||
return
|
||||
|
||||
if write_tmax <= 0:
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), "Parameter write.tmax must be greater than 0")
|
||||
return
|
||||
|
||||
if period <= 0:
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), "Servo Thread period must be greater than 0")
|
||||
return
|
||||
|
||||
# Calculation
|
||||
rw_tmax = read_tmax + write_tmax
|
||||
result = rw_tmax / period * 100
|
||||
label_result.set_text(f'{result:.0f}%')
|
||||
|
||||
def on_btn_packet_error_released(self, gtkbutton):
|
||||
result = subprocess.check_output("halcmd show pin hm2*packet-error-total",shell=True, text=True)
|
||||
|
||||
# Remove empty lines
|
||||
result = "\n".join(
|
||||
line for line in result.splitlines()
|
||||
if line.strip() # keeps only non-empty lines
|
||||
)
|
||||
|
||||
textview = self.builder.get_object("textview_nic")
|
||||
buffer = textview.get_buffer()
|
||||
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert(buffer.get_end_iter(), "\n\n")
|
||||
buffer.insert(buffer.get_end_iter(), result)
|
||||
|
||||
value = None
|
||||
for line in result.splitlines():
|
||||
line = line.strip()
|
||||
if "packet-error-total" in line:
|
||||
parts = line.split()
|
||||
value = int(parts[3],16) # 4. column is Value
|
||||
break
|
||||
|
||||
label_packet = self.builder.get_object("lbl_packet_error")
|
||||
label_packet.set_text(str(value))
|
||||
|
||||
# Automatic scroll for both text views
|
||||
def on_textbuffer_changed(self, buffer):
|
||||
# Get both textviews and their buffers
|
||||
textview_servo = self.builder.get_object("textview_servo")
|
||||
buffer_servo = textview_servo.get_buffer()
|
||||
|
||||
textview_nic = self.builder.get_object("textview_nic")
|
||||
buffer_nic = textview_nic.get_buffer()
|
||||
|
||||
# Decide which textview this buffer belongs to
|
||||
if buffer is buffer_servo:
|
||||
textview = textview_servo
|
||||
attr_name = "end_mark_servo"
|
||||
elif buffer is buffer_nic:
|
||||
textview = textview_nic
|
||||
attr_name = "end_mark_nic"
|
||||
else:
|
||||
# Unknown buffer, do nothing
|
||||
return
|
||||
|
||||
end_iter = buffer.get_end_iter()
|
||||
|
||||
# Get existing mark or create a new one lazily
|
||||
mark = getattr(self, attr_name, None)
|
||||
if mark is None:
|
||||
mark = buffer.create_mark(attr_name, end_iter, False)
|
||||
setattr(self, attr_name, mark)
|
||||
|
||||
# Move mark to the end
|
||||
buffer.move_mark(mark, end_iter)
|
||||
|
||||
# Scroll to the bottom
|
||||
textview.scroll_to_mark(
|
||||
mark,
|
||||
0.0, # within_margin
|
||||
True, # use_align
|
||||
0.0, # xalign
|
||||
1.0 # yalign
|
||||
)
|
||||
|
||||
def get_handlers(halcomp,builder,useropts):
|
||||
return [MesaTests(halcomp,builder,useropts)]
|
||||
@@ -0,0 +1,14 @@
|
||||
# Probe Screen application by Serguei Glavatski
|
||||
|
||||
Old version from 2015. This older version has **less functionality**, but it **takes up less space on the screen**, which can be useful on smaller displays.
|
||||
|
||||
**Actual version and manual:**
|
||||
- [https://vers.ge/en/blog/useful-articles/probe-screen-v28](https://vers.ge/en/blog/useful-articles/probe-screen-v28)
|
||||
- [https://github.com/verser-git/probe_screen_v2.9](https://github.com/verser-git/probe_screen_v2.9)
|
||||
|
||||
---
|
||||
|
||||
### Load with gladevcp command:
|
||||
```bash
|
||||
gladevcp gtk_verser_probe
|
||||
```
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 800 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 736 B |
|
After Width: | Height: | Size: 656 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |