steppersync: Add new steppersyncmgr_gen_steps() function

Generate and flush all the steppersync instances from a single
steppersyncmgr_gen_steps() call.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor
2025-09-18 15:31:44 -04:00
parent bd747872c3
commit f21cca049f
4 changed files with 63 additions and 74 deletions

View File

@@ -63,16 +63,13 @@ defs_stepcompress = """
defs_steppersync = """
void steppersync_set_time(struct steppersync *ss
, double time_offset, double mcu_freq);
void steppersync_history_expire(struct steppersync *ss, uint64_t end_clock);
void steppersync_start_gen_steps(struct steppersync *ss
, double gen_steps_time, uint64_t flush_clock);
int32_t steppersync_finalize_gen_steps(struct steppersync *ss
, uint64_t flush_clock);
struct steppersyncmgr *steppersyncmgr_alloc(void);
void steppersyncmgr_free(struct steppersyncmgr *ssm);
struct steppersync *steppersyncmgr_alloc_steppersync(
struct steppersyncmgr *ssm, struct serialqueue *sq
, struct stepcompress **sc_list, int sc_num, int move_num);
int32_t steppersyncmgr_gen_steps(struct steppersyncmgr *ssm
, double flush_time, double gen_steps_time, double clear_history_time);
"""
defs_itersolve = """

View File

@@ -33,6 +33,8 @@ struct steppersync {
// Storage for associated stepcompress objects
struct stepcompress **sc_list;
int sc_num;
// Convert from time to clock
struct clock_estimate ce;
// Storage for list of pending move clocks
uint64_t *move_clocks;
int num_move_clocks;
@@ -76,6 +78,7 @@ void __visible
steppersync_set_time(struct steppersync *ss, double time_offset
, double mcu_freq)
{
clock_fill(&ss->ce, mcu_freq, time_offset, 0, 0);
int i;
for (i=0; i<ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i];
@@ -83,17 +86,6 @@ steppersync_set_time(struct steppersync *ss, double time_offset
}
}
// Expire the stepcompress history before the given clock time
void __visible
steppersync_history_expire(struct steppersync *ss, uint64_t end_clock)
{
int i;
for (i = 0; i < ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i];
stepcompress_history_expire(sc, end_clock);
}
}
// Implement a binary heap algorithm to track when the next available
// 'struct move' in the mcu will be available
static void
@@ -165,36 +157,6 @@ steppersync_flush(struct steppersync *ss, uint64_t move_clock)
serialqueue_send_batch(ss->sq, ss->cq, &msgs);
}
// Start generating steps in stepcompress objects
void __visible
steppersync_start_gen_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];
stepcompress_start_gen_steps(sc, gen_steps_time, flush_clock);
}
}
// Finalize step generation and flush
int32_t __visible
steppersync_finalize_gen_steps(struct steppersync *ss, uint64_t flush_clock)
{
int i;
int32_t res = 0;
for (i=0; i<ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i];
int32_t ret = stepcompress_finalize_gen_steps(sc);
if (ret)
res = ret;
}
if (res)
return res;
steppersync_flush(ss, flush_clock);
return 0;
}
/****************************************************************
* StepperSyncMgr - manage a list of steppersync
@@ -239,3 +201,47 @@ steppersyncmgr_alloc_steppersync(
list_add_tail(&ss->ssm_node, &ssm->ss_list);
return ss;
}
// Generate and flush steps
int32_t __visible
steppersyncmgr_gen_steps(struct steppersyncmgr *ssm, double flush_time
, double gen_steps_time, double clear_history_time)
{
struct steppersync *ss;
// Start step generation threads
list_for_each_entry(ss, &ssm->ss_list, ssm_node) {
uint64_t flush_clock = clock_from_time(&ss->ce, flush_time);
int i;
for (i=0; i<ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i];
stepcompress_start_gen_steps(sc, gen_steps_time, flush_clock);
}
}
// Wait for step generation threads to complete
int32_t res = 0;
list_for_each_entry(ss, &ssm->ss_list, ssm_node) {
int i;
for (i=0; i<ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i];
int32_t ret = stepcompress_finalize_gen_steps(sc);
if (ret)
res = ret;
}
if (res)
continue;
uint64_t flush_clock = clock_from_time(&ss->ce, flush_time);
steppersync_flush(ss, flush_clock);
}
if (res)
return res;
// Clear history
list_for_each_entry(ss, &ssm->ss_list, ssm_node) {
uint64_t end_clock = clock_from_time(&ss->ce, clear_history_time);
int i;
for (i = 0; i < ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i];
stepcompress_history_expire(sc, end_clock);
}
}
return 0;
}

View File

@@ -6,11 +6,6 @@
struct steppersync;
void steppersync_set_time(struct steppersync *ss, double time_offset
, double mcu_freq);
void steppersync_history_expire(struct steppersync *ss, uint64_t end_clock);
void steppersync_start_gen_steps(struct steppersync *ss, double gen_steps_time
, uint64_t flush_clock);
int32_t steppersync_finalize_gen_steps(struct steppersync *ss
, uint64_t flush_clock);
struct steppersyncmgr *steppersyncmgr_alloc(void);
void steppersyncmgr_free(struct steppersyncmgr *ssm);
@@ -18,5 +13,8 @@ struct serialqueue;
struct steppersync *steppersyncmgr_alloc_steppersync(
struct steppersyncmgr *ssm, struct serialqueue *sq
, struct stepcompress **sc_list, int sc_num, int move_num);
int32_t steppersyncmgr_gen_steps(struct steppersyncmgr *ssm, double flush_time
, double gen_steps_time
, double clear_history_time);
#endif // steppersync.h

View File

@@ -33,10 +33,7 @@ class PrinterMotionQueuing:
ffi_lib.steppersyncmgr_free)
self.stepcompress = []
self.steppersyncs = []
self.steppersync_start_gen_steps = ffi_lib.steppersync_start_gen_steps
self.steppersync_finalize_gen_steps = \
ffi_lib.steppersync_finalize_gen_steps
self.steppersync_history_expire = ffi_lib.steppersync_history_expire
self.steppersyncmgr_gen_steps = ffi_lib.steppersyncmgr_gen_steps
# History expiration
self.clear_history_time = 0.
# Flush notification callbacks
@@ -101,7 +98,7 @@ class PrinterMotionQueuing:
ffi_lib.steppersync_set_time(ss, offset, freq)
# Calculate history expiration
est_print_time = self.mcu.estimated_print_time(eventtime)
self.clear_history_time = est_print_time - MOVE_HISTORY_EXPIRE
self.clear_history_time = max(0., est_print_time - MOVE_HISTORY_EXPIRE)
return False, ""
# Flush notification callbacks
def register_flush_callback(self, callback, can_add_trapq=False):
@@ -142,31 +139,22 @@ class PrinterMotionQueuing:
# Invoke flush callbacks (if any)
for cb in self.flush_callbacks:
cb(flush_time, step_gen_time)
# Generate stepper movement and transmit
for mcu, ss in self.steppersyncs:
clock = max(0, mcu.print_time_to_clock(flush_time))
self.steppersync_start_gen_steps(ss, step_gen_time, clock)
for mcu, ss in self.steppersyncs:
clock = max(0, mcu.print_time_to_clock(flush_time))
ret = self.steppersync_finalize_gen_steps(ss, clock)
if ret:
raise mcu.error("Internal error in MCU '%s' stepcompress"
% (mcu.get_name(),))
self.last_flush_time = flush_time
self.last_step_gen_time = step_gen_time
# Determine maximum history to keep
trapq_free_time = step_gen_time - self.kin_flush_delay
clear_history_time = self.clear_history_time
if not self.can_pause:
clear_history_time = trapq_free_time - MOVE_HISTORY_EXPIRE
# Move processed trapq moves to history list, and expire old history
clear_history_time = max(0., trapq_free_time - MOVE_HISTORY_EXPIRE)
# Generate stepper movement and transmit
ret = self.steppersyncmgr_gen_steps(self.steppersyncmgr, flush_time,
step_gen_time, clear_history_time)
if ret:
raise self.mcu.error("Internal error in stepcompress")
self.last_flush_time = flush_time
self.last_step_gen_time = step_gen_time
# Move processed trapq entries to history list, and expire old history
for trapq in self.trapqs:
self.trapq_finalize_moves(trapq, trapq_free_time,
clear_history_time)
# Clean up old history entries in stepcompress objects
for mcu, ss in self.steppersyncs:
clock = max(0, mcu.print_time_to_clock(clear_history_time))
self.steppersync_history_expire(ss, clock)
def _await_flush_time(self, want_flush_time):
while 1:
if self.last_flush_time >= want_flush_time or not self.can_pause: