fix: a re-plan drops the holes it invalidated and restarts the tick they are addressed by
rebuild_locked() replaced the store, so produced() restarted at 0 while the producer's tick_ kept counting: a hole's slot and tick addressing then described a buffer that was gone, forget_holes_before() could not retire it, and a backfill's amend fell outside the ring -- repairing nothing while the hole was still marked repaired, which is the band reporting the opposite of the truth. A re-plan generation is the signal rather than the stride/channel-count guard, which a reconnect with an identical CONFIG leaves unchanged. slot_base_ is left alone: it is relative mode's clock origin and must not walk backwards when the user retypes the window. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
176ef1df9f
commit
8320988d96
4 files changed
+41
No files matched your search
@@ -527,6 +527,25 @@ void Acquisition::on_data(const udps_frame_t* frame) {
|
||||
BufferStore& store = model_.live();
|
||||
const u64 g = part.time_stride;
|
||||
|
||||
// A re-plan replaced the store, so every ring's `produced()` restarted at 0 while `tick_`
|
||||
// kept counting. `backfill_from()` derives a slot index from a hole's `tick_begin`, which is
|
||||
// only an absolute slot index while `tick_ / period == produced()`, so the tick counter has
|
||||
// to restart with the buffer -- otherwise the amend lands outside the ring, repairs nothing,
|
||||
// and the hole is still marked repaired, which is the band saying the opposite of the truth.
|
||||
// The generation is the signal rather than the stride/channel-count comparison below: a
|
||||
// reconnect with an identical CONFIG rebuilds the store leaving both unchanged.
|
||||
// `slot_base_` is deliberately *not* reset -- it is relative mode's clock origin, samples
|
||||
// since the stream began, and relative time must not jump backwards when the user retypes
|
||||
// the window.
|
||||
if (const unsigned gen = model_.plan_generation(); gen != seen_plan_generation_) {
|
||||
seen_plan_generation_ = gen;
|
||||
tick_ = 0;
|
||||
last_tick_ = ~std::uint64_t{0};
|
||||
// Zeroing the stride makes the guard below fire too: the accumulators belong to the group
|
||||
// `tick_` was counting through, so they are stale for the same reason.
|
||||
acc_stride_ = 0;
|
||||
}
|
||||
|
||||
// The filter's groups are `g` long, so a re-plan has to start a fresh group rather than
|
||||
// finish the one it was in with the wrong length.
|
||||
if (acc_stride_ != g || acc_channels_ != channels.size()) {
|
||||
|
||||
Reference in new issue
Block a user