Import LinuxCNC source tree

This commit is contained in:
Wang Dequan
2026-08-20 06:17:39 +08:00
commit 2c814634c3
9429 changed files with 10556013 additions and 0 deletions

7
lib/python/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
nf.py
lcnc_realtime.py
gscreen
gmoccapy/
stepconf/
pncconf/
pyui/

135
lib/python/bitfile.py Normal file
View 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
View 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:

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

File diff suppressed because it is too large Load Diff

1035
lib/python/common/iniinfo.py Normal file

File diff suppressed because it is too large Load Diff

145
lib/python/common/logger.py Executable file
View 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

View 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.

View 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)
#----------------------------------------------------------------------

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View 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
```

View File

@@ -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">&lt;b&gt;Servo Thread Test&lt;/b&gt;</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">&lt;b&gt;NIC test&lt;/b&gt;</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">&lt;b&gt;Packet&lt;/b&gt;</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>

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Some files were not shown because too many files have changed in this diff Show More