diff --git a/klippy/extras/force_move.py b/klippy/extras/force_move.py index 0be0eb9b..54b07d59 100644 --- a/klippy/extras/force_move.py +++ b/klippy/extras/force_move.py @@ -85,14 +85,13 @@ class ForceMove: self.trapq_append(self.trapq, print_time, accel_t, cruise_t, accel_t, 0., 0., 0., axis_r, 0., 0., 0., cruise_v, accel) print_time = print_time + accel_t + cruise_t + accel_t - stepper.generate_steps(print_time) - self.trapq_finalize_moves(self.trapq, print_time + 99999.9, - print_time + 99999.9) - stepper.set_trapq(prev_trapq) - stepper.set_stepper_kinematics(prev_sk) toolhead.note_mcu_movequeue_activity(print_time) toolhead.dwell(accel_t + cruise_t + accel_t) toolhead.flush_step_generation() + stepper.set_trapq(prev_trapq) + stepper.set_stepper_kinematics(prev_sk) + self.trapq_finalize_moves(self.trapq, print_time + 99999.9, + print_time + 99999.9) def _lookup_stepper(self, gcmd): name = gcmd.get('STEPPER') if name not in self.steppers: diff --git a/klippy/extras/manual_stepper.py b/klippy/extras/manual_stepper.py index 5a8949b9..03816b5c 100644 --- a/klippy/extras/manual_stepper.py +++ b/klippy/extras/manual_stepper.py @@ -76,7 +76,6 @@ class ManualStepper: self.sync_print_time() self.next_cmd_time = self._submit_move(self.next_cmd_time, movepos, speed, accel) - self.rail.generate_steps(self.next_cmd_time) self.trapq_finalize_moves(self.trapq, self.next_cmd_time + 99999.9, self.next_cmd_time + 99999.9) toolhead = self.printer.lookup_object('toolhead') @@ -138,7 +137,6 @@ class ManualStepper: raise gcmd.error("Must unregister axis first") # Unregister toolhead.remove_extra_axis(self) - toolhead.unregister_step_generator(self.rail.generate_steps) self.axis_gcode_id = None return if (len(gcode_axis) != 1 or not gcode_axis.isupper() @@ -155,7 +153,6 @@ class ManualStepper: self.gaxis_limit_velocity = limit_velocity self.gaxis_limit_accel = limit_accel toolhead.add_extra_axis(self, self.get_position()[0]) - toolhead.register_step_generator(self.rail.generate_steps) def process_move(self, print_time, move, ea_index): axis_r = move.axes_r[ea_index] start_pos = move.start_pos[ea_index] @@ -208,7 +205,7 @@ class ManualStepper: speed, self.homing_accel) # Drip updates to motors toolhead = self.printer.lookup_object('toolhead') - toolhead.drip_update_time(maxtime, drip_completion, self.steppers) + toolhead.drip_update_time(maxtime, drip_completion) # Clear trapq of any remaining parts of movement reactor = self.printer.get_reactor() self.trapq_finalize_moves(self.trapq, reactor.NEVER, 0) diff --git a/klippy/extras/motion_queuing.py b/klippy/extras/motion_queuing.py new file mode 100644 index 00000000..4b5bd017 --- /dev/null +++ b/klippy/extras/motion_queuing.py @@ -0,0 +1,19 @@ +# Helper code for low-level motion queuing and flushing +# +# Copyright (C) 2025 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. +import logging + +class PrinterMotionQueuing: + def __init__(self, config): + self.printer = config.get_printer() + self.steppers = [] + def register_stepper(self, config, stepper): + self.steppers.append(stepper) + def flush_motion_queues(self, must_flush_time, max_step_gen_time): + for stepper in self.steppers: + stepper.generate_steps(max_step_gen_time) + +def load_config(config): + return PrinterMotionQueuing(config) diff --git a/klippy/kinematics/cartesian.py b/klippy/kinematics/cartesian.py index f9030275..edd9c1a0 100644 --- a/klippy/kinematics/cartesian.py +++ b/klippy/kinematics/cartesian.py @@ -36,7 +36,6 @@ class CartKinematics: 'safe_distance', None, minval=0.)) for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks max_velocity, max_accel = toolhead.get_max_velocity() self.max_z_velocity = config.getfloat('max_z_velocity', max_velocity, diff --git a/klippy/kinematics/corexy.py b/klippy/kinematics/corexy.py index d68f8854..f940c57f 100644 --- a/klippy/kinematics/corexy.py +++ b/klippy/kinematics/corexy.py @@ -20,7 +20,6 @@ class CoreXYKinematics: self.rails[2].setup_itersolve('cartesian_stepper_alloc', b'z') for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks max_velocity, max_accel = toolhead.get_max_velocity() self.max_z_velocity = config.getfloat( diff --git a/klippy/kinematics/corexz.py b/klippy/kinematics/corexz.py index 8d3e027c..d4a0eb35 100644 --- a/klippy/kinematics/corexz.py +++ b/klippy/kinematics/corexz.py @@ -20,7 +20,6 @@ class CoreXZKinematics: self.rails[2].setup_itersolve('corexz_stepper_alloc', b'-') for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks max_velocity, max_accel = toolhead.get_max_velocity() self.max_z_velocity = config.getfloat( diff --git a/klippy/kinematics/delta.py b/klippy/kinematics/delta.py index aa244a8f..5ec4d54c 100644 --- a/klippy/kinematics/delta.py +++ b/klippy/kinematics/delta.py @@ -52,7 +52,6 @@ class DeltaKinematics: r.setup_itersolve('delta_stepper_alloc', a, t[0], t[1]) for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks self.need_home = True self.limit_xy2 = -1. diff --git a/klippy/kinematics/deltesian.py b/klippy/kinematics/deltesian.py index 54b013a5..a62a58bd 100644 --- a/klippy/kinematics/deltesian.py +++ b/klippy/kinematics/deltesian.py @@ -40,7 +40,6 @@ class DeltesianKinematics: self.rails[2].setup_itersolve('cartesian_stepper_alloc', b'y') for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) self.limits = [(1.0, -1.0)] * 3 # X axis limits min_angle = config.getfloat('min_angle', MIN_ANGLE, diff --git a/klippy/kinematics/extruder.py b/klippy/kinematics/extruder.py index 58ccdbec..e3e375bc 100644 --- a/klippy/kinematics/extruder.py +++ b/klippy/kinematics/extruder.py @@ -39,8 +39,6 @@ class ExtruderStepper: self.name, self.cmd_SYNC_EXTRUDER_MOTION, desc=self.cmd_SYNC_EXTRUDER_MOTION_help) def _handle_connect(self): - toolhead = self.printer.lookup_object('toolhead') - toolhead.register_step_generator(self.stepper.generate_steps) self._set_pressure_advance(self.config_pa, self.config_smooth_time) def get_status(self, eventtime): return {'pressure_advance': self.pressure_advance, diff --git a/klippy/kinematics/generic_cartesian.py b/klippy/kinematics/generic_cartesian.py index b8cabb77..49e16eec 100644 --- a/klippy/kinematics/generic_cartesian.py +++ b/klippy/kinematics/generic_cartesian.py @@ -108,7 +108,6 @@ class GenericCartesianKinematics: self._load_kinematics(config) for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) self.dc_module = None if self.dc_carriages: pcs = [dc.get_dual_carriage() for dc in self.dc_carriages] diff --git a/klippy/kinematics/hybrid_corexy.py b/klippy/kinematics/hybrid_corexy.py index fd2621d5..22884b93 100644 --- a/klippy/kinematics/hybrid_corexy.py +++ b/klippy/kinematics/hybrid_corexy.py @@ -39,7 +39,6 @@ class HybridCoreXYKinematics: 'safe_distance', None, minval=0.)) for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks max_velocity, max_accel = toolhead.get_max_velocity() self.max_z_velocity = config.getfloat( diff --git a/klippy/kinematics/hybrid_corexz.py b/klippy/kinematics/hybrid_corexz.py index b9699982..1cd646e2 100644 --- a/klippy/kinematics/hybrid_corexz.py +++ b/klippy/kinematics/hybrid_corexz.py @@ -39,7 +39,6 @@ class HybridCoreXZKinematics: 'safe_distance', None, minval=0.)) for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks max_velocity, max_accel = toolhead.get_max_velocity() self.max_z_velocity = config.getfloat( diff --git a/klippy/kinematics/polar.py b/klippy/kinematics/polar.py index ffa15d83..2e467d50 100644 --- a/klippy/kinematics/polar.py +++ b/klippy/kinematics/polar.py @@ -21,7 +21,6 @@ class PolarKinematics: for s in r.get_steppers() ] for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks max_velocity, max_accel = toolhead.get_max_velocity() self.max_z_velocity = config.getfloat( diff --git a/klippy/kinematics/rotary_delta.py b/klippy/kinematics/rotary_delta.py index 732a89a8..42b0a706 100644 --- a/klippy/kinematics/rotary_delta.py +++ b/klippy/kinematics/rotary_delta.py @@ -52,7 +52,6 @@ class RotaryDeltaKinematics: math.radians(a), ua, la) for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks self.need_home = True self.limit_xy2 = -1. diff --git a/klippy/kinematics/winch.py b/klippy/kinematics/winch.py index 47bc6855..2fa06ef2 100644 --- a/klippy/kinematics/winch.py +++ b/klippy/kinematics/winch.py @@ -21,7 +21,6 @@ class WinchKinematics: self.anchors.append(a) s.setup_itersolve('winch_stepper_alloc', *a) s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) # Setup boundary checks acoords = list(zip(*self.anchors)) self.axes_min = toolhead.Coord(*[min(a) for a in acoords], e=0.) diff --git a/klippy/stepper.py b/klippy/stepper.py index 86a92358..5ba76a5b 100644 --- a/klippy/stepper.py +++ b/klippy/stepper.py @@ -273,7 +273,8 @@ def PrinterStepper(config, units_in_radians=False): rotation_dist, steps_per_rotation, step_pulse_duration, units_in_radians) # Register with helper modules - for mname in ['stepper_enable', 'force_move', 'motion_report']: + mods = ['stepper_enable', 'force_move', 'motion_report', 'motion_queuing'] + for mname in mods: m = printer.load_object(config, mname) m.register_stepper(config, mcu_stepper) return mcu_stepper @@ -442,9 +443,6 @@ class GenericPrinterRail: def setup_itersolve(self, alloc_func, *params): for stepper in self.steppers: stepper.setup_itersolve(alloc_func, *params) - def generate_steps(self, flush_time): - for stepper in self.steppers: - stepper.generate_steps(flush_time) def set_trapq(self, trapq): for stepper in self.steppers: stepper.set_trapq(trapq) diff --git a/klippy/toolhead.py b/klippy/toolhead.py index bddba4c7..3b9c0e8e 100644 --- a/klippy/toolhead.py +++ b/klippy/toolhead.py @@ -251,7 +251,7 @@ class ToolHead: self.trapq_append = ffi_lib.trapq_append self.trapq_finalize_moves = ffi_lib.trapq_finalize_moves # Motion flushing - self.step_generators = [] + self.motion_queuing = self.printer.load_object(config, 'motion_queuing') self.flush_trapqs = [self.trapq] # Create kinematics class gcode = self.printer.lookup_object('gcode') @@ -280,8 +280,7 @@ class ToolHead: sg_flush_want = min(flush_time + STEPCOMPRESS_FLUSH_TIME, self.print_time - self.kin_flush_delay) sg_flush_time = max(sg_flush_want, flush_time) - for sg in self.step_generators: - sg(sg_flush_time) + self.motion_queuing.flush_motion_queues(flush_time, sg_flush_time) self.min_restart_time = max(self.min_restart_time, sg_flush_time) # Free trapq entries that are no longer needed clear_history_time = self.clear_history_time @@ -517,7 +516,7 @@ class ToolHead: def get_extra_axes(self): return [None, None, None] + self.extra_axes # Homing "drip move" handling - def drip_update_time(self, next_print_time, drip_completion, addstepper=()): + def drip_update_time(self, next_print_time, drip_completion): # Transition from "NeedPrime"/"Priming"/main state to "Drip" state self.special_queuing_state = "Drip" self.need_check_pause = self.reactor.NEVER @@ -539,8 +538,6 @@ class ToolHead: continue npt = min(self.print_time + DRIP_SEGMENT_TIME, next_print_time) self.note_mcu_movequeue_activity(npt + self.kin_flush_delay) - for stepper in addstepper: - stepper.generate_steps(npt) self._advance_move_time(npt) # Exit "Drip" state self.reactor.update_timer(self.flush_timer, self.reactor.NOW) @@ -617,11 +614,6 @@ class ToolHead: return self.kin def get_trapq(self): return self.trapq - def register_step_generator(self, handler): - self.step_generators.append(handler) - def unregister_step_generator(self, handler): - if handler in self.step_generators: - self.step_generators.remove(handler) def note_step_generation_scan_time(self, delay, old_delay=0.): self.flush_step_generation() if old_delay: