stepcompress: Store a reference to 'struct stepper_kinematics'

Support storing a reference to 'struct stepper_kinematics' in 'struct
stepcompress' and support globally generating steps via the
steppersync mechanism.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2025-08-05 17:51:59 -04:00
parent dd4cc8eb4c
commit 2919f37343
8 changed files with 67 additions and 29 deletions

View File

@ -54,6 +54,8 @@ defs_stepcompress = """
int stepcompress_extract_old(struct stepcompress *sc int stepcompress_extract_old(struct stepcompress *sc
, struct pull_history_steps *p, int max , struct pull_history_steps *p, int max
, uint64_t start_clock, uint64_t end_clock); , uint64_t start_clock, uint64_t end_clock);
void stepcompress_set_stepper_kinematics(struct stepcompress *sc
, struct stepper_kinematics *sk);
""" """
defs_steppersync = """ defs_steppersync = """
@ -62,13 +64,13 @@ defs_steppersync = """
void steppersync_free(struct steppersync *ss); void steppersync_free(struct steppersync *ss);
void steppersync_set_time(struct steppersync *ss void steppersync_set_time(struct steppersync *ss
, double time_offset, double mcu_freq); , double time_offset, double mcu_freq);
int32_t steppersync_generate_steps(struct steppersync *ss
, double gen_steps_time, uint64_t flush_clock);
void steppersync_history_expire(struct steppersync *ss, uint64_t end_clock); void steppersync_history_expire(struct steppersync *ss, uint64_t end_clock);
int steppersync_flush(struct steppersync *ss, uint64_t move_clock); int steppersync_flush(struct steppersync *ss, uint64_t move_clock);
""" """
defs_itersolve = """ defs_itersolve = """
int32_t itersolve_generate_steps(struct stepper_kinematics *sk
, struct stepcompress *sc, double flush_time);
double itersolve_check_active(struct stepper_kinematics *sk double itersolve_check_active(struct stepper_kinematics *sk
, double flush_time); , double flush_time);
int32_t itersolve_is_active_axis(struct stepper_kinematics *sk, char axis); int32_t itersolve_is_active_axis(struct stepper_kinematics *sk, char axis);

View File

@ -143,7 +143,7 @@ check_active(struct stepper_kinematics *sk, struct move *m)
} }
// Generate step times for a range of moves on the trapq // Generate step times for a range of moves on the trapq
int32_t __visible int32_t
itersolve_generate_steps(struct stepper_kinematics *sk, struct stepcompress *sc itersolve_generate_steps(struct stepper_kinematics *sk, struct stepcompress *sc
, double flush_time) , double flush_time)
{ {

View File

@ -21,6 +21,7 @@
#include <stdlib.h> // malloc #include <stdlib.h> // malloc
#include <string.h> // memset #include <string.h> // memset
#include "compiler.h" // DIV_ROUND_UP #include "compiler.h" // DIV_ROUND_UP
#include "itersolve.h" // itersolve_generate_steps
#include "pyhelper.h" // errorf #include "pyhelper.h" // errorf
#include "serialqueue.h" // struct queue_message #include "serialqueue.h" // struct queue_message
#include "stepcompress.h" // stepcompress_alloc #include "stepcompress.h" // stepcompress_alloc
@ -46,6 +47,8 @@ struct stepcompress {
// History tracking // History tracking
int64_t last_position; int64_t last_position;
struct list_head history_list; struct list_head history_list;
// Itersolve reference
struct stepper_kinematics *sk;
}; };
struct step_move { struct step_move {
@ -538,7 +541,7 @@ stepcompress_commit(struct stepcompress *sc)
} }
// Flush pending steps // Flush pending steps
int static int
stepcompress_flush(struct stepcompress *sc, uint64_t move_clock) stepcompress_flush(struct stepcompress *sc, uint64_t move_clock)
{ {
if (sc->next_step_clock && move_clock >= sc->next_step_clock) { if (sc->next_step_clock && move_clock >= sc->next_step_clock) {
@ -662,3 +665,26 @@ stepcompress_extract_old(struct stepcompress *sc, struct pull_history_steps *p
} }
return res; return res;
} }
// Store a reference to stepper_kinematics
void __visible
stepcompress_set_stepper_kinematics(struct stepcompress *sc
, struct stepper_kinematics *sk)
{
sc->sk = sk;
}
// Generate steps (via itersolve) and flush
int32_t
stepcompress_generate_steps(struct stepcompress *sc, double gen_steps_time
, uint64_t flush_clock)
{
if (!sc->sk)
return 0;
// Generate steps
int32_t ret = itersolve_generate_steps(sc->sk, sc, gen_steps_time);
if (ret)
return ret;
// Flush steps
return stepcompress_flush(sc, flush_clock);
}

View File

@ -27,7 +27,6 @@ void stepcompress_set_time(struct stepcompress *sc
int stepcompress_append(struct stepcompress *sc, int sdir int stepcompress_append(struct stepcompress *sc, int sdir
, double print_time, double step_time); , double print_time, double step_time);
int stepcompress_commit(struct stepcompress *sc); int stepcompress_commit(struct stepcompress *sc);
int stepcompress_flush(struct stepcompress *sc, uint64_t move_clock);
int stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock); int stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock);
int stepcompress_set_last_position(struct stepcompress *sc, uint64_t clock int stepcompress_set_last_position(struct stepcompress *sc, uint64_t clock
, int64_t last_position); , int64_t last_position);
@ -39,5 +38,11 @@ int stepcompress_queue_mq_msg(struct stepcompress *sc, uint64_t req_clock
int stepcompress_extract_old(struct stepcompress *sc int stepcompress_extract_old(struct stepcompress *sc
, struct pull_history_steps *p, int max , struct pull_history_steps *p, int max
, uint64_t start_clock, uint64_t end_clock); , uint64_t start_clock, uint64_t end_clock);
struct stepper_kinematics;
void stepcompress_set_stepper_kinematics(struct stepcompress *sc
, struct stepper_kinematics *sk);
int32_t stepcompress_generate_steps(struct stepcompress *sc
, double gen_steps_time
, uint64_t flush_clock);
#endif // stepcompress.h #endif // stepcompress.h

View File

@ -76,6 +76,22 @@ steppersync_set_time(struct steppersync *ss, double time_offset
} }
} }
// Generate steps and flush stepcompress objects
int32_t __visible
steppersync_generate_steps(struct steppersync *ss, double gen_steps_time
, uint64_t flush_clock)
{
int i;
for (i=0; i<ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i];
int32_t ret = stepcompress_generate_steps(sc, gen_steps_time
, flush_clock);
if (ret)
return ret;
}
return 0;
}
// Expire the stepcompress history before the given clock time // Expire the stepcompress history before the given clock time
void __visible void __visible
steppersync_history_expire(struct steppersync *ss, uint64_t end_clock) steppersync_history_expire(struct steppersync *ss, uint64_t end_clock)
@ -116,14 +132,6 @@ heap_replace(struct steppersync *ss, uint64_t req_clock)
int __visible int __visible
steppersync_flush(struct steppersync *ss, uint64_t move_clock) steppersync_flush(struct steppersync *ss, uint64_t move_clock)
{ {
// Flush each stepcompress to the specified move_clock
int i;
for (i=0; i<ss->sc_num; i++) {
int ret = stepcompress_flush(ss->sc_list[i], move_clock);
if (ret)
return ret;
}
// Order commands by the reqclock of each pending command // Order commands by the reqclock of each pending command
struct list_head msgs; struct list_head msgs;
list_init(&msgs); list_init(&msgs);
@ -131,6 +139,7 @@ steppersync_flush(struct steppersync *ss, uint64_t move_clock)
// Find message with lowest reqclock // Find message with lowest reqclock
uint64_t req_clock = MAX_CLOCK; uint64_t req_clock = MAX_CLOCK;
struct queue_message *qm = NULL; struct queue_message *qm = NULL;
int i;
for (i=0; i<ss->sc_num; i++) { for (i=0; i<ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i]; struct stepcompress *sc = ss->sc_list[i];
struct list_head *sc_mq = stepcompress_get_msg_queue(sc); struct list_head *sc_mq = stepcompress_get_msg_queue(sc);

View File

@ -10,6 +10,8 @@ struct steppersync *steppersync_alloc(
void steppersync_free(struct steppersync *ss); void steppersync_free(struct steppersync *ss);
void steppersync_set_time(struct steppersync *ss, double time_offset void steppersync_set_time(struct steppersync *ss, double time_offset
, double mcu_freq); , double mcu_freq);
int32_t steppersync_generate_steps(struct steppersync *ss, double gen_steps_time
, uint64_t flush_clock);
void steppersync_history_expire(struct steppersync *ss, uint64_t end_clock); void steppersync_history_expire(struct steppersync *ss, uint64_t end_clock);
int steppersync_flush(struct steppersync *ss, uint64_t move_clock); int steppersync_flush(struct steppersync *ss, uint64_t move_clock);

View File

@ -11,13 +11,13 @@ MOVE_HISTORY_EXPIRE = 30.
class PrinterMotionQueuing: class PrinterMotionQueuing:
def __init__(self, config): def __init__(self, config):
self.printer = config.get_printer() self.printer = config.get_printer()
self.steppers = []
self.trapqs = [] self.trapqs = []
self.stepcompress = [] self.stepcompress = []
self.steppersyncs = [] self.steppersyncs = []
self.flush_callbacks = [] self.flush_callbacks = []
ffi_main, ffi_lib = chelper.get_ffi() ffi_main, ffi_lib = chelper.get_ffi()
self.trapq_finalize_moves = ffi_lib.trapq_finalize_moves self.trapq_finalize_moves = ffi_lib.trapq_finalize_moves
self.steppersync_generate_steps = ffi_lib.steppersync_generate_steps
self.steppersync_flush = ffi_lib.steppersync_flush self.steppersync_flush = ffi_lib.steppersync_flush
self.steppersync_history_expire = ffi_lib.steppersync_history_expire self.steppersync_history_expire = ffi_lib.steppersync_history_expire
self.clear_history_time = 0. self.clear_history_time = 0.
@ -46,8 +46,6 @@ class PrinterMotionQueuing:
ffi_lib.steppersync_free) ffi_lib.steppersync_free)
self.steppersyncs.append((mcu, ss)) self.steppersyncs.append((mcu, ss))
return ss return ss
def register_stepper(self, config, stepper):
self.steppers.append(stepper)
def register_flush_callback(self, callback): def register_flush_callback(self, callback):
self.flush_callbacks.append(callback) self.flush_callbacks.append(callback)
def unregister_flush_callback(self, callback): def unregister_flush_callback(self, callback):
@ -59,12 +57,14 @@ class PrinterMotionQueuing:
# Invoke flush callbacks (if any) # Invoke flush callbacks (if any)
for cb in self.flush_callbacks: for cb in self.flush_callbacks:
cb(must_flush_time, max_step_gen_time) cb(must_flush_time, max_step_gen_time)
# Generate itersolve steps
for stepper in self.steppers:
stepper.generate_steps(max_step_gen_time)
# Flush steps from stepcompress and steppersync
for mcu, ss in self.steppersyncs: for mcu, ss in self.steppersyncs:
clock = max(0, mcu.print_time_to_clock(must_flush_time)) clock = max(0, mcu.print_time_to_clock(must_flush_time))
# Generate steps
ret = self.steppersync_generate_steps(ss, max_step_gen_time, clock)
if ret:
raise mcu.error("Internal error in MCU '%s' stepcompress"
% (mcu.get_name(),))
# Flush steps from steppersync
ret = self.steppersync_flush(ss, clock) ret = self.steppersync_flush(ss, clock)
if ret: if ret:
raise mcu.error("Internal error in MCU '%s' stepcompress" raise mcu.error("Internal error in MCU '%s' stepcompress"

View File

@ -48,7 +48,6 @@ class MCU_stepper:
ffi_main, ffi_lib = chelper.get_ffi() ffi_main, ffi_lib = chelper.get_ffi()
ffi_lib.stepcompress_set_invert_sdir(self._stepqueue, self._invert_dir) ffi_lib.stepcompress_set_invert_sdir(self._stepqueue, self._invert_dir)
self._stepper_kinematics = None self._stepper_kinematics = None
self._itersolve_generate_steps = ffi_lib.itersolve_generate_steps
self._itersolve_check_active = ffi_lib.itersolve_check_active self._itersolve_check_active = ffi_lib.itersolve_check_active
self._trapq = ffi_main.NULL self._trapq = ffi_main.NULL
printer.register_event_handler('klippy:connect', printer.register_event_handler('klippy:connect',
@ -192,6 +191,8 @@ class MCU_stepper:
if old_sk is not None: if old_sk is not None:
mcu_pos = self.get_mcu_position() mcu_pos = self.get_mcu_position()
self._stepper_kinematics = sk self._stepper_kinematics = sk
ffi_main, ffi_lib = chelper.get_ffi()
ffi_lib.stepcompress_set_stepper_kinematics(self._stepqueue, sk);
self.set_trapq(self._trapq) self.set_trapq(self._trapq)
self._set_mcu_position(mcu_pos) self._set_mcu_position(mcu_pos)
return old_sk return old_sk
@ -253,12 +254,6 @@ class MCU_stepper:
# Invoke callbacks # Invoke callbacks
for cb in cbs: for cb in cbs:
cb(ret) cb(ret)
def generate_steps(self, flush_time):
# Generate steps
sk = self._stepper_kinematics
ret = self._itersolve_generate_steps(sk, self._stepqueue, flush_time)
if ret:
raise error("Internal error in stepcompress")
def is_active_axis(self, axis): def is_active_axis(self, axis):
ffi_main, ffi_lib = chelper.get_ffi() ffi_main, ffi_lib = chelper.get_ffi()
a = axis.encode() a = axis.encode()
@ -281,8 +276,7 @@ def PrinterStepper(config, units_in_radians=False):
rotation_dist, steps_per_rotation, rotation_dist, steps_per_rotation,
step_pulse_duration, units_in_radians) step_pulse_duration, units_in_radians)
# Register with helper modules # Register with helper modules
mods = ['stepper_enable', 'force_move', 'motion_report', 'motion_queuing'] for mname in ['stepper_enable', 'force_move', 'motion_report']:
for mname in mods:
m = printer.load_object(config, mname) m = printer.load_object(config, mname)
m.register_stepper(config, mcu_stepper) m.register_stepper(config, mcu_stepper)
return mcu_stepper return mcu_stepper