stepcompress: Remove "queue append" abstraction

The queue_append system predates the iterative solver - it was useful
when many different kinematic functions directly added steps to the
step compression queues.  With the iterative solver being the only
source of step generation, it is simpler to directly add steps from
the iterative solver code.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2020-02-24 21:59:39 -05:00
parent d6c2e24f4c
commit bc6c3ba92f
3 changed files with 35 additions and 88 deletions

View File

@ -1,6 +1,6 @@
// Iterative solver for kinematic moves
//
// Copyright (C) 2018-2019 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2018-2020 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
@ -59,15 +59,12 @@ static int32_t
itersolve_gen_steps_range(struct stepper_kinematics *sk, struct move *m
, double move_start, double move_end)
{
struct stepcompress *sc = sk->sc;
sk_calc_callback calc_position_cb = sk->calc_position_cb;
double half_step = .5 * sk->step_dist;
double mcu_freq = stepcompress_get_mcu_freq(sc);
double start = move_start - m->print_time, end = move_end - m->print_time;
struct timepos last = { start, sk->commanded_pos }, low = last, high = last;
double seek_time_delta = 0.000100;
int sdir = stepcompress_get_step_dir(sc);
struct queue_append qa = queue_append_start(sc, m->print_time, .5);
int sdir = stepcompress_get_step_dir(sk->sc);
for (;;) {
// Determine if next step is in forward or reverse direction
double dist = high.position - last.position;
@ -101,16 +98,13 @@ itersolve_gen_steps_range(struct stepper_kinematics *sk, struct move *m
high.position = calc_position_cb(sk, m, high.time);
continue;
}
int ret = queue_append_set_next_step_dir(&qa, next_sdir);
if (ret)
return ret;
sdir = next_sdir;
}
// Find step
double target = last.position + (sdir ? half_step : -half_step);
struct timepos next = itersolve_find_step(sk, m, low, high, target);
// Add step at given time
int ret = queue_append(&qa, next.time * mcu_freq);
int ret = stepcompress_append(sk->sc, sdir, m->print_time, next.time);
if (ret)
return ret;
seek_time_delta = next.time - last.time;
@ -123,7 +117,6 @@ itersolve_gen_steps_range(struct stepper_kinematics *sk, struct move *m
// The high range is no longer valid - recalculate it
goto seek_new_high_range;
}
queue_append_finish(qa);
sk->commanded_pos = last.position;
if (sk->post_cb)
sk->post_cb(sk);

View File

@ -1,9 +1,9 @@
// Stepper pulse schedule compression
//
// Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2016-2020 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
//
// The goal of this code is to take a series of scheduled stepper
// pulse times and compress them into a handful of commands that can
// be efficiently transmitted and executed on a microcontroller (mcu).
@ -32,7 +32,7 @@ struct stepcompress {
uint32_t *queue, *queue_end, *queue_pos, *queue_next;
// Internal tracking
uint32_t max_error;
double mcu_time_offset, mcu_freq;
double mcu_time_offset, mcu_freq, last_step_print_time;
// Message generation
uint64_t last_step_clock;
struct list_head msg_queue;
@ -261,6 +261,14 @@ stepcompress_free(struct stepcompress *sc)
free(sc);
}
// Determine the "print time" of the last_step_clock
static void
calc_last_step_print_time(struct stepcompress *sc)
{
double lsc = sc->last_step_clock;
sc->last_step_print_time = sc->mcu_time_offset + (lsc - .5) / sc->mcu_freq;
}
// Convert previously scheduled steps into commands for the mcu
static int
stepcompress_flush(struct stepcompress *sc, uint64_t move_clock)
@ -289,6 +297,7 @@ stepcompress_flush(struct stepcompress *sc, uint64_t move_clock)
}
sc->queue_pos += move.count;
}
calc_last_step_print_time(sc);
return 0;
}
@ -304,6 +313,7 @@ stepcompress_flush_far(struct stepcompress *sc, uint64_t abs_step_clock)
qm->min_clock = sc->last_step_clock;
sc->last_step_clock = qm->req_clock = abs_step_clock;
list_add_tail(&qm->node, &sc->msg_queue);
calc_last_step_print_time(sc);
return 0;
}
@ -335,6 +345,7 @@ stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock)
return ret;
sc->last_step_clock = last_step_clock;
sc->sdir = -1;
calc_last_step_print_time(sc);
return 0;
}
@ -359,12 +370,7 @@ stepcompress_set_time(struct stepcompress *sc
{
sc->mcu_time_offset = time_offset;
sc->mcu_freq = mcu_freq;
}
double
stepcompress_get_mcu_freq(struct stepcompress *sc)
{
return sc->mcu_freq;
calc_last_step_print_time(sc);
}
uint32_t
@ -379,33 +385,10 @@ stepcompress_get_step_dir(struct stepcompress *sc)
return sc->sdir;
}
/****************************************************************
* Queue management
****************************************************************/
// Maximium clock delta between messages in the queue
#define CLOCK_DIFF_MAX (3<<28)
// Create a cursor for inserting clock times into the queue
inline struct queue_append
queue_append_start(struct stepcompress *sc, double print_time, double adjust)
{
double print_clock = (print_time - sc->mcu_time_offset) * sc->mcu_freq;
return (struct queue_append) {
.sc = sc, .qnext = sc->queue_next, .qend = sc->queue_end,
.last_step_clock_32 = sc->last_step_clock,
.clock_offset = (print_clock - (double)sc->last_step_clock) + adjust };
}
// Finalize a cursor created with queue_append_start()
inline void
queue_append_finish(struct queue_append qa)
{
qa.sc->queue_next = qa.qnext;
}
// Slow path for queue_append()
// Slow path for stepcompress_append()
static int
queue_append_slow(struct stepcompress *sc, double rel_sc)
{
@ -453,42 +436,23 @@ queue_append_slow(struct stepcompress *sc, double rel_sc)
return 0;
}
// Add a clock time to the queue (flushing the queue if needed)
// Add a step time to the queue (flushing the queue if needed)
inline int
queue_append(struct queue_append *qa, double step_clock)
stepcompress_append(struct stepcompress *sc, int sdir
, double print_time, double step_time)
{
double rel_sc = step_clock + qa->clock_offset;
if (likely(!(qa->qnext >= qa->qend || rel_sc >= (double)CLOCK_DIFF_MAX))) {
*qa->qnext++ = qa->last_step_clock_32 + (uint32_t)rel_sc;
return 0;
if (unlikely(sdir != sc->sdir)) {
int ret = set_next_step_dir(sc, sdir);
if (ret)
return ret;
}
// Call queue_append_slow() to handle queue expansion and integer overflow
struct stepcompress *sc = qa->sc;
uint64_t old_last_step_clock = sc->last_step_clock;
sc->queue_next = qa->qnext;
int ret = queue_append_slow(sc, rel_sc);
if (ret)
return ret;
qa->qnext = sc->queue_next;
qa->qend = sc->queue_end;
qa->last_step_clock_32 = sc->last_step_clock;
qa->clock_offset -= sc->last_step_clock - old_last_step_clock;
return 0;
}
inline int
queue_append_set_next_step_dir(struct queue_append *qa, int sdir)
{
struct stepcompress *sc = qa->sc;
uint64_t old_last_step_clock = sc->last_step_clock;
sc->queue_next = qa->qnext;
int ret = set_next_step_dir(sc, sdir);
if (ret)
return ret;
qa->qnext = sc->queue_next;
qa->qend = sc->queue_end;
qa->last_step_clock_32 = sc->last_step_clock;
qa->clock_offset -= sc->last_step_clock - old_last_step_clock;
double offset = print_time - sc->last_step_print_time;
double rel_sc = (step_time + offset) * sc->mcu_freq;
if (unlikely(sc->queue_next >= sc->queue_end
|| rel_sc >= (double)CLOCK_DIFF_MAX))
// Slow path to handle queue expansion and integer overflow
return queue_append_slow(sc, rel_sc);
*sc->queue_next++ = (uint32_t)sc->last_step_clock + (uint32_t)rel_sc;
return 0;
}

View File

@ -12,20 +12,10 @@ void stepcompress_fill(struct stepcompress *sc, uint32_t max_error
void stepcompress_free(struct stepcompress *sc);
int stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock);
int stepcompress_queue_msg(struct stepcompress *sc, uint32_t *data, int len);
double stepcompress_get_mcu_freq(struct stepcompress *sc);
uint32_t stepcompress_get_oid(struct stepcompress *sc);
int stepcompress_get_step_dir(struct stepcompress *sc);
struct queue_append {
struct stepcompress *sc;
uint32_t *qnext, *qend, last_step_clock_32;
double clock_offset;
};
struct queue_append queue_append_start(
struct stepcompress *sc, double print_time, double adjust);
void queue_append_finish(struct queue_append qa);
int queue_append(struct queue_append *qa, double step_clock);
int queue_append_set_next_step_dir(struct queue_append *qa, int sdir);
int stepcompress_append(struct stepcompress *sc, int sdir
, double print_time, double step_time);
struct serialqueue;
struct steppersync *steppersync_alloc(