linuxcnc/lib/python/gladevcp/hal_gremlin.py
CMorley 97f8cb071c grenlin/gladevcp -add ability to get gcode properties from loaded file.
This code was missing from gremlin and pulled from qt5_graphics
hal_gremlin will now pass the gcode properties thru GStat messages
A screen just needs to connect to the GStat message 'graphics-gcode-properties'
2023-01-14 14:30:24 -08:00

288 lines
13 KiB
Python

#!/usr/bin/env python3
# vim: sts=4 sw=4 et
# GladeVcp Widgets
#
# Copyright (c) 2010 Pavel Shramov <shramov@mexmat.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.
#
# 2014 Steffen Noack
# add property 'mouse_btn_mode'
# 0 = default: left rotate, middle move, right zoom
# 1 = left zoom, middle move, right rotate
# 2 = left move, middle rotate, right zoom
# 3 = left zoom, middle rotate, right move
# 4 = left move, middle zoom, right rotate
# 5 = left rotate, middle zoom, right move
# 2015 Moses McKnight introduced mode 6
# 6 = left move, middle zoom, right zoom (no rotate - for 2D plasma machines or lathes)
import gi
gi.require_version("Gtk","3.0")
from gi.repository import Gtk
from gi.repository import GObject
import os
import linuxcnc
import gremlin
import rs274.glcanon
import gcode
if __name__ == "__main__":
from hal_actions import _EMC_ActionBase
else:
from .hal_actions import _EMC_ActionBase
from hal_glib import GStat
def get_linuxcnc_ini_file():
"""find LinuxCNC INI file with pgrep"""
import subprocess
ps = subprocess.Popen('ps -C linuxcncsvr --no-header -o args'.split(),
stdout=subprocess.PIPE
)
p,e = ps.communicate()
if ps.returncode:
print(_('\nhal_gremlin: cannot find INI file\n'))
return None
ans = p.split()[p.split().index('-ini')+1]
return ans
class HAL_Gremlin(gremlin.Gremlin, _EMC_ActionBase):
__gtype_name__ = "HAL_Gremlin"
__gsignals__ = {
'line-clicked': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_INT,)),
'gcode_error': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (GObject.TYPE_STRING,)),
}
__gproperties__ = {
'view' : ( GObject.TYPE_STRING, 'View type', 'Default view: p, x, y, y2, z, z2',
'p', GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'enable_dro' : ( GObject.TYPE_BOOLEAN, 'Enable DRO', 'Show DRO on graphics',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'metric_units' : ( GObject.TYPE_BOOLEAN, 'Use Metric Units', 'Show DRO in metric or imperial units',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'use_relative' : ( GObject.TYPE_BOOLEAN, 'Show Relative', 'Show DRO relative to active system or machine origin',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'use_commanded' : ( GObject.TYPE_BOOLEAN, 'Show Commanded', 'Show commanded or actual position',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_extents_option' : ( GObject.TYPE_BOOLEAN, 'Show Extents', 'Show machine extents',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_limits' : ( GObject.TYPE_BOOLEAN, 'Show limits', 'Show machine limits',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_live_plot' : ( GObject.TYPE_BOOLEAN, 'Show live plot', 'Show machine plot',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_velocity' : ( GObject.TYPE_BOOLEAN, 'Show tool speed', 'Show tool velocity',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_program' : ( GObject.TYPE_BOOLEAN, 'Show program', 'Show program',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_rapids' : ( GObject.TYPE_BOOLEAN, 'Show rapids', 'Show rapid moves',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_tool' : ( GObject.TYPE_BOOLEAN, 'Show tool', 'Show tool',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_dtg' : ( GObject.TYPE_BOOLEAN, 'Show DTG', 'Show Distance To Go',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'show_lathe_radius' : ( GObject.TYPE_BOOLEAN, 'Show Lathe Radius', 'Show X axis in Radius',
False, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'grid_size' : ( GObject.TYPE_FLOAT, 'Grid Size', 'Grid Size',
0, 100, 0, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'use_joints_mode' : ( GObject.TYPE_BOOLEAN, 'Use joints mode', 'Use joints mode',
False, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'use_default_controls' : ( GObject.TYPE_BOOLEAN, 'Use Default Mouse Controls', 'Use Default Mouse Controls',
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
'mouse_btn_mode' : ( GObject.TYPE_INT, 'Mouse Button Mode',
('Mousebutton assignment, l means left, m middle, r right \n'
'0 = default: l-rotate, m-move, r-zoom \n'
'1 = l-zoom, m-move, r-rotate\n'
'2 = l-move, m-rotate, r-zoom\n'
'3 = l-zoom, m-rotate, r-move\n'
'4 = l-move, m-zoom, r-rotate\n'
'5 = l-rotate, m-zoom, r-move\n'
'6 = l-move, m-zoom, r-zoom'),
0, 6, 0, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
}
__gproperties = __gproperties__
def __init__(self, *a, **kw):
GObject.GObject.__init__(self)
ini_filename = os.environ.get('INI_FILE_NAME')
if ini_filename is None:
ini_filename = get_linuxcnc_ini_file()
if ini_filename is not None:
os.putenv('INI_FILE_NAME',ini_filename)
os.environ['INI_FILE_NAME'] = ini_filename
os.chdir(os.path.dirname(ini_filename))
inifile = linuxcnc.ini(ini_filename)
gremlin.Gremlin.__init__(self, inifile)
self._reload_filename = None
self.gstat = GStat()
self.gstat.connect('file-loaded', self.fileloaded)
self.gstat.connect('reload-display', self.reloadfile)
self.init_glcanondraw(
trajcoordinates=self.inifile.find('TRAJ','COORDINATES'),
kinsmodule=self.inifile.find('KINS','KINEMATICS'))
self.show()
def reloadfile(self,w):
try:
self.fileloaded(None,self._reload_filename)
except:
pass
self.gstat.emit('graphics-gcode-properties',self.gcode_properties)
def fileloaded(self,w,f):
self._reload_filename=f
try:
self._load(f)
except AttributeError as detail:
#AttributeError: 'NoneType' object has no attribute 'gl_end'
print('hal_gremlin: continuing after',detail)
self.gstat.emit('graphics-gcode-properties',self.gcode_properties)
print(self.gcode_properties)
def do_get_property(self, property):
name = property.name.replace('-', '_')
if name == 'view':
return self.current_view
elif name in list(self.__gproperties.keys()):
return getattr(self, name)
else:
raise AttributeError('unknown property %s' % property.name)
def do_set_property(self, property, value):
name = property.name.replace('-', '_')
if name == 'view':
view = value.lower()
if self.lathe_option:
if view not in ['p','y','y2']:
return False
elif view not in ['p', 'x', 'y', 'z', 'z2']:
return False
self.current_view = view
if self.initialised:
self.set_current_view()
elif name == 'enable_dro':
self.enable_dro = value
elif name == 'metric_units':
self.metric_units = value
elif name in list(self.__gproperties.keys()):
setattr(self, name, value)
else:
raise AttributeError('unknown property %s' % property.name)
self.queue_draw()
return True
# This overrides glcannon.py method so we can change the DRO
def dro_format(self,s,spd,dtg,limit,homed,positions,axisdtg,g5x_offset,g92_offset,tlo_offset):
if self.metric_units:
format = "% 6s:% 9.3f"
if self.show_dtg:
droformat = " " + format + " DTG %1s:% 9.3f"
else:
droformat = " " + format
offsetformat = "% 5s %1s:% 9.3f G92 %1s:% 9.3f"
rotformat = "% 5s %1s:% 9.3f"
else:
format = "% 6s:% 9.4f"
if self.show_dtg:
droformat = " " + format + " DTG %1s:% 9.4f"
else:
droformat = " " + format
offsetformat = "% 5s %1s:% 9.4f G92 %1s:% 9.4f"
rotformat = "% 5s %1s:% 9.4f"
diaformat = " " + format
posstrs = []
droposstrs = []
for i in range(9):
a = "XYZABCUVW"[i]
if s.axis_mask & (1<<i):
posstrs.append(format % (a, positions[i]))
if self.show_dtg:
droposstrs.append(droformat % (a, positions[i], a, axisdtg[i]))
else:
droposstrs.append(droformat % (a, positions[i]))
droposstrs.append("")
for i in range(9):
index = s.g5x_index
if index<7:
label = "G5%d" % (index+3)
else:
label = "G59.%d" % (index-6)
a = "XYZABCUVW"[i]
if s.axis_mask & (1<<i):
droposstrs.append(offsetformat % (label, a, g5x_offset[i], a, g92_offset[i]))
droposstrs.append(rotformat % (label, 'R', s.rotation_xy))
droposstrs.append("")
for i in range(9):
a = "XYZABCUVW"[i]
if s.axis_mask & (1<<i):
droposstrs.append(rotformat % ("TLO", a, tlo_offset[i]))
# if its a lathe only show radius or diameter as per property
if self.is_lathe():
posstrs[0] = ""
if self.show_lathe_radius:
posstrs.insert(1, format % ("Rad", positions[0]))
else:
posstrs.insert(1, format % ("Dia", positions[0]*2.0))
droposstrs[0] = ""
if self.show_dtg:
if self.show_lathe_radius:
droposstrs.insert(1, droformat % ("Rad", positions[0], "R", axisdtg[0]))
else:
droposstrs.insert(1, droformat % ("Dia", positions[0]*2.0, "D", axisdtg[0]*2.0))
else:
if self.show_lathe_radius:
droposstrs.insert(1, droformat % ("Rad", positions[0]))
else:
droposstrs.insert(1, diaformat % ("Dia", positions[0]*2.0))
if self.show_velocity:
posstrs.append(format % ("Vel", spd))
pos=0
for i in range(9):
if s.axis_mask & (1<<i): pos +=1
if self.is_lathe:
pos +=1
droposstrs.insert(pos, " " + format % ("Vel", spd))
if self.show_dtg:
posstrs.append(format % ("DTG", dtg))
return limit, homed, posstrs, droposstrs
# Override gremlin's / glcannon.py function so we can emit a GObject signal
def update_highlight_variable(self,line):
self.highlight_line = line
if line == None:
line = -1
self.emit('line-clicked', line)
def realize(self, widget):
gremlin.Gremlin.realize(self, widget)
@rs274.glcanon.with_context
def _load(self, filename):
return self.load(filename)
def report_gcode_error(self, result, seq, filename):
error_str = gcode.strerror(result)
errortext = "G-Code error in " + os.path.basename(filename) + "\n" + "Near line " \
+ str(seq) + " of\n" + filename + "\n" + error_str + "\n"
print(errortext)
self.emit("gcode-error", errortext)