steppersync: Introduce new 'struct syncemitter'

Create a new 'struct syncemitter' for each object that can generate
messages for a 'struct steppersync' and store in a regular linked
list.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor
2025-09-18 19:43:00 -04:00
parent a29cfc1701
commit d831d66c11
5 changed files with 111 additions and 74 deletions

View File

@@ -36,13 +36,11 @@ defs_stepcompress = """
int step_count, interval, add;
};
struct stepcompress *stepcompress_alloc(char name[16]);
void stepcompress_fill(struct stepcompress *sc, uint32_t oid
, uint32_t max_error, int32_t queue_step_msgtag
, int32_t set_next_step_dir_msgtag);
void stepcompress_set_invert_sdir(struct stepcompress *sc
, uint32_t invert_sdir);
void stepcompress_free(struct stepcompress *sc);
int stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock);
int stepcompress_set_last_position(struct stepcompress *sc
, uint64_t clock, int64_t last_position);
@@ -62,13 +60,17 @@ defs_stepcompress = """
"""
defs_steppersync = """
struct stepcompress *syncemitter_get_stepcompress(struct syncemitter *se);
struct syncemitter *steppersync_alloc_syncemitter(struct steppersync *ss
, char name[16], int alloc_stepcompress);
void steppersync_setup_movequeue(struct steppersync *ss
, struct serialqueue *sq, int move_num);
void steppersync_set_time(struct steppersync *ss
, double time_offset, double mcu_freq);
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);
struct steppersyncmgr *ssm);
int32_t steppersyncmgr_gen_steps(struct steppersyncmgr *ssm
, double flush_time, double gen_steps_time, double clear_history_time);
"""

View File

@@ -257,7 +257,7 @@ static int sc_thread_alloc(struct stepcompress *sc, char name[16]);
static void sc_thread_free(struct stepcompress *sc);
// Allocate a new 'stepcompress' object
struct stepcompress * __visible
struct stepcompress *
stepcompress_alloc(char name[16])
{
struct stepcompress *sc = malloc(sizeof(*sc));
@@ -310,7 +310,7 @@ stepcompress_history_expire(struct stepcompress *sc, uint64_t end_clock)
}
// Free memory associated with a 'stepcompress' object
void __visible
void
stepcompress_free(struct stepcompress *sc)
{
if (!sc)

View File

@@ -20,6 +20,24 @@
#include "steppersync.h" // steppersync_alloc
/****************************************************************
* SyncEmitter - message generation for each stepper
****************************************************************/
struct syncemitter {
// List node for storage in steppersync list
struct list_node ss_node;
// Step compression and generation
struct stepcompress *sc;
};
struct stepcompress * __visible
syncemitter_get_stepcompress(struct syncemitter *se)
{
return se->sc;
}
/****************************************************************
* StepperSync - sort move queue for a micro-controller
****************************************************************/
@@ -30,9 +48,8 @@ struct steppersync {
// Serial port
struct serialqueue *sq;
struct command_queue *cq;
// Storage for associated stepcompress objects
struct stepcompress **sc_list;
int sc_num;
// The syncemitters that generate messages on this mcu
struct list_head se_list;
// Convert from time to clock
struct clock_estimate ce;
// Storage for list of pending move clocks
@@ -40,37 +57,33 @@ struct steppersync {
int num_move_clocks;
};
// Allocate a new 'steppersync' object
static struct steppersync *
steppersync_alloc(struct serialqueue *sq, struct stepcompress **sc_list
, int sc_num, int move_num)
// Allocate a new syncemitter instance
struct syncemitter * __visible
steppersync_alloc_syncemitter(struct steppersync *ss, char name[16]
, int alloc_stepcompress)
{
struct steppersync *ss = malloc(sizeof(*ss));
memset(ss, 0, sizeof(*ss));
struct syncemitter *se = malloc(sizeof(*se));
memset(se, 0, sizeof(*se));
list_add_tail(&se->ss_node, &ss->se_list);
if (alloc_stepcompress)
se->sc = stepcompress_alloc(name);
return se;
}
// Fill information on mcu move queue
void __visible
steppersync_setup_movequeue(struct steppersync *ss, struct serialqueue *sq
, int move_num)
{
serialqueue_free_commandqueue(ss->cq);
free(ss->move_clocks);
ss->sq = sq;
ss->cq = serialqueue_alloc_commandqueue();
ss->sc_list = malloc(sizeof(*sc_list)*sc_num);
memcpy(ss->sc_list, sc_list, sizeof(*sc_list)*sc_num);
ss->sc_num = sc_num;
ss->move_clocks = malloc(sizeof(*ss->move_clocks)*move_num);
memset(ss->move_clocks, 0, sizeof(*ss->move_clocks)*move_num);
ss->num_move_clocks = move_num;
return ss;
}
// Free memory associated with a 'steppersync' object
static void
steppersync_free(struct steppersync *ss)
{
if (!ss)
return;
free(ss->sc_list);
free(ss->move_clocks);
serialqueue_free_commandqueue(ss->cq);
free(ss);
}
// Set the conversion rate of 'print_time' to mcu clock
@@ -79,10 +92,10 @@ 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];
stepcompress_set_time(sc, time_offset, mcu_freq);
struct syncemitter *se;
list_for_each_entry(se, &ss->se_list, ss_node) {
if (se->sc)
stepcompress_set_time(se->sc, time_offset, mcu_freq);
}
}
@@ -122,10 +135,9 @@ steppersync_flush(struct steppersync *ss, uint64_t move_clock)
// Find message with lowest reqclock
uint64_t req_clock = MAX_CLOCK;
struct queue_message *qm = NULL;
int i;
for (i=0; i<ss->sc_num; i++) {
struct stepcompress *sc = ss->sc_list[i];
struct list_head *sc_mq = stepcompress_get_msg_queue(sc);
struct syncemitter *se;
list_for_each_entry(se, &ss->se_list, ss_node) {
struct list_head *sc_mq = stepcompress_get_msg_queue(se->sc);
if (!list_empty(sc_mq)) {
struct queue_message *m = list_first_entry(
sc_mq, struct queue_message, node);
@@ -186,18 +198,27 @@ steppersyncmgr_free(struct steppersyncmgr *ssm)
struct steppersync *ss = list_first_entry(
&ssm->ss_list, struct steppersync, ssm_node);
list_del(&ss->ssm_node);
steppersync_free(ss);
free(ss->move_clocks);
serialqueue_free_commandqueue(ss->cq);
while (!list_empty(&ss->se_list)) {
struct syncemitter *se = list_first_entry(
&ss->se_list, struct syncemitter, ss_node);
list_del(&se->ss_node);
stepcompress_free(se->sc);
free(se);
}
free(ss);
}
free(ssm);
}
// Allocate a new 'steppersync' object
struct steppersync * __visible
steppersyncmgr_alloc_steppersync(
struct steppersyncmgr *ssm, struct serialqueue *sq
, struct stepcompress **sc_list, int sc_num, int move_num)
steppersyncmgr_alloc_steppersync(struct steppersyncmgr *ssm)
{
struct steppersync *ss = steppersync_alloc(sq, sc_list, sc_num, move_num);
struct steppersync *ss = malloc(sizeof(*ss));
memset(ss, 0, sizeof(*ss));
list_init(&ss->se_list);
list_add_tail(&ss->ssm_node, &ssm->ss_list);
return ss;
}
@@ -211,19 +232,21 @@ steppersyncmgr_gen_steps(struct steppersyncmgr *ssm, double flush_time
// 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);
struct syncemitter *se;
list_for_each_entry(se, &ss->se_list, ss_node) {
if (!se->sc)
continue;
stepcompress_start_gen_steps(se->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);
struct syncemitter *se;
list_for_each_entry(se, &ss->se_list, ss_node) {
if (!se->sc)
continue;
int32_t ret = stepcompress_finalize_gen_steps(se->sc);
if (ret)
res = ret;
}
@@ -237,10 +260,11 @@ steppersyncmgr_gen_steps(struct steppersyncmgr *ssm, double flush_time
// 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);
struct syncemitter *se;
list_for_each_entry(se, &ss->se_list, ss_node) {
if (!se->sc)
continue;
stepcompress_history_expire(se->sc, end_clock);
}
}
return 0;

View File

@@ -3,7 +3,14 @@
#include <stdint.h> // uint64_t
struct syncemitter;
struct stepcompress *syncemitter_get_stepcompress(struct syncemitter *se);
struct steppersync;
struct syncemitter *steppersync_alloc_syncemitter(
struct steppersync *ss, char name[16], int alloc_stepcompress);
void steppersync_setup_movequeue(struct steppersync *ss, struct serialqueue *sq
, int move_num);
void steppersync_set_time(struct steppersync *ss, double time_offset
, double mcu_freq);
@@ -11,8 +18,7 @@ struct steppersyncmgr *steppersyncmgr_alloc(void);
void steppersyncmgr_free(struct steppersyncmgr *ssm);
struct serialqueue;
struct steppersync *steppersyncmgr_alloc_steppersync(
struct steppersyncmgr *ssm, struct serialqueue *sq
, struct stepcompress **sc_list, int sc_num, int move_num);
struct steppersyncmgr *ssm);
int32_t steppersyncmgr_gen_steps(struct steppersyncmgr *ssm, double flush_time
, double gen_steps_time
, double clear_history_time);

View File

@@ -31,7 +31,7 @@ class PrinterMotionQueuing:
# C steppersync tracking
self.steppersyncmgr = ffi_main.gc(ffi_lib.steppersyncmgr_alloc(),
ffi_lib.steppersyncmgr_free)
self.stepcompress = []
self.syncemitters = []
self.steppersyncs = []
self.steppersyncmgr_gen_steps = ffi_lib.steppersyncmgr_gen_steps
# History expiration
@@ -69,24 +69,26 @@ class PrinterMotionQueuing:
ffi_main, ffi_lib = chelper.get_ffi()
return ffi_lib.trapq_append
# C steppersync tracking
def _lookup_steppersync(self, mcu):
for ss_mcu, ss in self.steppersyncs:
if ss_mcu is mcu:
return ss
ffi_main, ffi_lib = chelper.get_ffi()
ss = ffi_lib.steppersyncmgr_alloc_steppersync(self.steppersyncmgr)
self.steppersyncs.append((mcu, ss))
return ss
def allocate_stepcompress(self, mcu, name):
name = name.encode("utf-8")[:15]
ss = self._lookup_steppersync(mcu)
ffi_main, ffi_lib = chelper.get_ffi()
sc = ffi_main.gc(ffi_lib.stepcompress_alloc(name),
ffi_lib.stepcompress_free)
self.stepcompress.append((mcu, sc))
return sc
se = ffi_lib.steppersync_alloc_syncemitter(ss, name, True)
self.syncemitters.append(se)
return ffi_lib.syncemitter_get_stepcompress(se)
def setup_mcu_movequeue(self, mcu, serialqueue, move_count):
# Setup steppersync object for the mcu's main movequeue
stepqueues = []
for sc_mcu, sc in self.stepcompress:
if sc_mcu is mcu:
stepqueues.append(sc)
ffi_main, ffi_lib = chelper.get_ffi()
ss = ffi_lib.steppersyncmgr_alloc_steppersync(
self.steppersyncmgr, serialqueue, stepqueues, len(stepqueues),
move_count)
self.steppersyncs.append((mcu, ss))
ss = self._lookup_steppersync(mcu)
ffi_lib.steppersync_setup_movequeue(ss, serialqueue, move_count)
mcu_freq = float(mcu.seconds_to_clock(1.))
ffi_lib.steppersync_set_time(ss, 0., mcu_freq)
def stats(self, eventtime):
@@ -117,7 +119,10 @@ class PrinterMotionQueuing:
def check_step_generation_scan_windows(self):
ffi_main, ffi_lib = chelper.get_ffi()
kin_flush_delay = SDS_CHECK_TIME
for mcu, sc in self.stepcompress:
for se in self.syncemitters:
sc = ffi_lib.syncemitter_get_stepcompress(se)
if sc == ffi_main.NULL:
continue
sk = ffi_lib.stepcompress_get_stepper_kinematics(sc)
if sk == ffi_main.NULL:
continue