Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[unreleased]
- Enhancement: Add right-click menu option to clear resume-at-line setting
- Enhancement: Display collet information in the manual toolchange popup, when using S1-S6 parameter for M6 toolchanges
- Enhancement: Display of the parsed line during file playback to visualize the lookahead buffer
- Fixed: The 4th axis probing sequence for the z offset calibration (M469.5) was not passing pin diameter input through to the machine
- Fixed: Viewing Gcode would cause an app crash when not connected to a machine

Expand Down
2 changes: 2 additions & 0 deletions carveracontroller/CNC.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,15 @@ class CNC:
"cutter" : "",
"tlo" : 0.0,
"target_tool": -1,
"target_collet_type": 0,
"program" : "M0",
"spindle" : "M5",
"coolant" : "M9",

"playedlines": 0,
"playedpercent": 0,
"playedseconds": 0,
"parsedlines": -1,

"atc_state": 0,

Expand Down
9 changes: 8 additions & 1 deletion carveracontroller/Controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -1239,10 +1239,15 @@ def parseBracketAngle(self, line,):
CNC.vars["target_tool"] = int(d['T'][2])
else:
CNC.vars["target_tool"] = -1
if len(d['T']) > 3:
CNC.vars["target_collet_type"] = int(d['T'][3])
else:
CNC.vars["target_collet_type"] = 0
else:
CNC.vars["tool"] = -1
CNC.vars["tlo"] = 0.0
CNC.vars["target_tool"] = -1
CNC.vars["target_collet_type"] = 0
if 'W' in d:
CNC.vars["wpvoltage"] = float(d['W'][0])
if 'L' in d:
Expand All @@ -1257,11 +1262,13 @@ def parseBracketAngle(self, line,):
CNC.vars["playedseconds"] = int(d['P'][2])
if len(d['P']) >= 4:
CNC.vars["is_playing"] = int(d['P'][3])
if len(d['P']) >= 5:
CNC.vars["parsedlines"] = int(d['P'][4])
else:
# not playing file
CNC.vars["playedlines"] = -1
CNC.vars["is_playing"] = 0

CNC.vars["parsedlines"] = -1
if 'A' in d:
CNC.vars["atc_state"] = int(d['A'][0])
else:
Expand Down
55 changes: 45 additions & 10 deletions carveracontroller/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def _do_update_line_highlighting(self, dt):
if current_pos and len(current_pos) > 1:
line_number = current_pos[1]
if line_number > 0 and hasattr(app.root, 'gcode_rv'):
app.root.gcode_rv.set_selected_line(line_number)
app.root.gcode_rv.set_selected_line_and_parsed_line(line_number, -1)

def on_value(self, instance, value):
"""Called when the slider value changes (both programmatically and manually)"""
Expand Down Expand Up @@ -2034,6 +2034,7 @@ class GCodeRow(RecycleDataViewBehavior, BoxLayout):
"""Single row in GCodeRV: line number, optional resume-flag icon, gcode text."""
index = None
selected = BooleanProperty(False)
parsed = BooleanProperty(False)
selectable = BooleanProperty(True)
line_no = NumericProperty(0)
text = StringProperty('')
Expand Down Expand Up @@ -2473,6 +2474,7 @@ class GCodeRV(RecycleView):
scroll_time = 0
old_selected_line = 0
new_selected_line = 0
new_parsed_line = 0

def __init__(self, **kwargs):
super(GCodeRV, self).__init__(**kwargs)
Expand All @@ -2483,22 +2485,39 @@ def on_scroll_stop(self, touch):



def set_selected_line(self, line):
def set_selected_line_and_parsed_line(self, line, parsed_line):
app = App.get_running_app()
aiming_page = int(line / MAX_LOAD_LINES) + (0 if line % MAX_LOAD_LINES == 0 else 1)
if aiming_page != app.curr_page:
app.root.load_page(aiming_page)
line = line % MAX_LOAD_LINES

aiming_page_parsed = int(parsed_line / MAX_LOAD_LINES) + (0 if parsed_line % MAX_LOAD_LINES == 0 else 1)
if aiming_page_parsed == aiming_page:
parsed_line = parsed_line % MAX_LOAD_LINES
else:
parsed_line = 0

if self.data_length > 0 and line < self.data_length:
page_lines = len(self.view_adapter.views)
self.new_selected_line = line - 1
if parsed_line > 0:
self.new_parsed_line = parsed_line - 1
else:
self.new_parsed_line = -1

# Schedule all UI attribute updates for the next frame to avoid re-entry loops
def update_selection_ui(dt):
for key in self.view_adapter.views:
view = self.view_adapter.views[key]
if view and hasattr(view, 'selected') and view.selected is not None:
view.selected = False
if view and hasattr(view, 'parsed') and view.parsed is not None:
view.parsed = False
if self.new_parsed_line >= 0:
new_parsed_line = self.view_adapter.get_visible_view(self.new_parsed_line)
if new_parsed_line:
new_parsed_line.parsed = True
new_line = self.view_adapter.get_visible_view(self.new_selected_line)
if new_line:
new_line.selected = True
Expand Down Expand Up @@ -3784,6 +3803,8 @@ def open_tool_confirm_popup(self):
if self.confirm_popup.showing:
return
target_tool = str(CNC.vars['target_tool'])
target_collet_type = CNC.vars['target_collet_type']
target_collet_type_text = ["Undefined","3mm", "1/8\"", "4mm", "6mm", "1/4\"","8mm"]
if CNC.vars['target_tool'] == 0:
target_tool = 'Probe'
elif CNC.vars['target_tool'] == 8888:
Expand All @@ -3796,8 +3817,12 @@ def open_tool_confirm_popup(self):
#target is valid tool
if CNC.vars['target_tool'] != -1:
if CNC.vars['tool'] == -1:
self.confirm_popup.lb_title.text = tr._('Manual toolchange')
self.confirm_popup.lb_content.text = tr._('Insert tool: ') + '%s\n' % (target_tool) + tr._(' Then press \' Confirm\' or main button to clamp.\n')
if target_collet_type == 0:
self.confirm_popup.lb_title.text = tr._('Manual toolchange')
self.confirm_popup.lb_content.text = tr._('Insert tool: ') + '%s\n' % (target_tool) + tr._('Then press \' Confirm\' or main button to clamp.\n')
else:
self.confirm_popup.lb_title.text = tr._('Manual toolchange')
self.confirm_popup.lb_content.text = tr._('Change to collet: ') + '%s\n' % (target_collet_type_text[target_collet_type]) + tr._('Insert tool: ') + '%s\n' % (target_tool) + tr._('Then press \' Confirm\' or main button to clamp.\n')
else:
self.confirm_popup.lb_title.text = tr._('Manual toolchange')
self.confirm_popup.lb_content.text = tr._('When the tool is clamped press \' Confirm\' or main button to proceed.\nKeep your hands off the spindle unless you are willing to lose a finger!')
Expand All @@ -3806,8 +3831,12 @@ def open_tool_confirm_popup(self):
self.confirm_popup.lb_title.text = tr._('Hold tool')
self.confirm_popup.lb_content.text = tr._('Please hold the current tool and press \' Confirm\' or main button to proceed')
else:
self.confirm_popup.lb_title.text = tr._('Open clamp')
self.confirm_popup.lb_content.text = tr._('When the collet is empty press \' Confirm\' or main button to proceed')
if target_collet_type == 0:
self.confirm_popup.lb_title.text = tr._('Confirm empty')
self.confirm_popup.lb_content.text = tr._('When the collet is empty press \' Confirm\' or main button to proceed')
else:
self.confirm_popup.lb_title.text = tr._('Confirm empty')
self.confirm_popup.lb_content.text = tr._('Change to collet: ') + '%s\n' % (target_collet_type_text[target_collet_type]) + tr._('When the collet is changed and empty press \' Confirm\' or main button to proceed')
else:
self.confirm_popup.lb_title.text = tr._('Changing Tool')
self.confirm_popup.lb_content.text = tr._('Please change to tool: ') + '%s\n' % (target_tool) + tr._('Then press \' Confirm\' or main button to proceed')
Expand Down Expand Up @@ -5061,6 +5090,7 @@ def updateStatus(self, *args):
self.wpb_leveling.value = 0
self.wpb_play.value = 0
self.progress_info = ""
self.parsed_lines = 0
# Stop smooth progress updates
if self._progress_smooth_clock is not None:
self._progress_smooth_clock.cancel()
Expand All @@ -5078,11 +5108,12 @@ def updateStatus(self, *args):
self.progress_info = tr._(' No Remote File Selected') + last_job_elapsed
else:
app.playing = True
if self.played_lines != CNC.vars["playedlines"]:
if self.played_lines != CNC.vars["playedlines"] or self.parsed_lines != CNC.vars["parsedlines"]:
self.played_lines = CNC.vars["playedlines"]
self.parsed_lines = CNC.vars["parsedlines"]
self.wpb_play.value = CNC.vars["playedpercent"]
if (app.selected_remote_filename != '' or app.selected_local_filename != '') and self.selected_file_line_count > 0:
self.gcode_rv.set_selected_line(self.played_lines)
self.gcode_rv.set_selected_line_and_parsed_line(self.played_lines, self.parsed_lines)
self.gcode_viewer.set_distance_by_lineidx(self.played_lines, 0.5)
remaining_sec = self.gcode_viewer.get_remaining_time_by_lineidx(self.played_lines, 0.5)
if remaining_sec is not None and remaining_sec >= 0:
Expand Down Expand Up @@ -5282,7 +5313,7 @@ def moveLineIndex(self, up = True):
self.test_line = self.test_line + 1
if self.test_line == 0:
self.test_line = 1
self.gcode_rv.set_selected_line(self.test_line - 1)
self.gcode_rv.set_selected_line_and_parsed_line(self.test_line - 1, -1)

def execCallback(self, line):
logger.info(f"MDI Sent: {line}")
Expand Down Expand Up @@ -5878,7 +5909,11 @@ def gcode_play_call_back(self, distance, line_number):
if getattr(self, '_skip_next_set_selected_line_from_callback', False):
self._skip_next_set_selected_line_from_callback = False
elif line_number > 0 and hasattr(self, 'gcode_rv'):
self.gcode_rv.set_selected_line(line_number)
if CNC.vars.get('is_playing', 0) == 1:
parsed = CNC.vars.get('parsedlines', 0)
self.gcode_rv.set_selected_line_and_parsed_line(line_number, parsed)
else:
self.gcode_rv.set_selected_line_and_parsed_line(line_number, -1)

# -----------------------------------------------------------------------
def gcode_play_over_call_back(self):
Expand Down
6 changes: 6 additions & 0 deletions carveracontroller/makera.kv
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@
Rectangle:
pos: self.pos
size: self.size
# Parsed-line marker: cyan left border when this row is the parsed line
Color:
rgba: (0, 0.6, 0.85, 1) if self.parsed else (0, 0, 0, 0)
Rectangle:
pos: self.pos
size: (dp(3), self.height) if self.parsed else (0, 0)
Label:
size_hint_x: None
width: dp(72)
Expand Down
Loading