1005e50be0
Move scheme and PID training runtime behavior into the pure track_core layer and expose render sinks for injected strip application. Add ESP compatibility adapters, Python bindings/test scaffolding, and in-memory render support so app_track_bt can consume core render and runtime logic without duplicating it. Cover circular/linear rendering boundaries, all scheme runtime types, scheme render_to parity, PID sample de-duplication, speed suppression, and live tuning in track-core tests.
111 lines
2.6 KiB
C++
111 lines
2.6 KiB
C++
#include "track_core/memory_strip.hpp"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace track_core {
|
|
namespace {
|
|
|
|
MemoryStrip *memory_strip_from_context(void *context) {
|
|
return static_cast<MemoryStrip *>(context);
|
|
}
|
|
|
|
TrackError memory_strip_clear(void *context) {
|
|
auto *strip = memory_strip_from_context(context);
|
|
if (strip == nullptr) {
|
|
return TrackError::invalid_arg;
|
|
}
|
|
return strip->clear();
|
|
}
|
|
|
|
TrackError memory_strip_fill(
|
|
void *context,
|
|
std::uint16_t start_led,
|
|
std::uint16_t led_count,
|
|
Color color) {
|
|
auto *strip = memory_strip_from_context(context);
|
|
if (strip == nullptr) {
|
|
return TrackError::invalid_arg;
|
|
}
|
|
return strip->fill(start_led, led_count, color);
|
|
}
|
|
|
|
TrackError memory_strip_show(void *context) {
|
|
auto *strip = memory_strip_from_context(context);
|
|
if (strip == nullptr) {
|
|
return TrackError::invalid_arg;
|
|
}
|
|
return strip->show();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
MemoryStrip::MemoryStrip(std::size_t led_count)
|
|
: pixels_(led_count, Color::black()) {}
|
|
|
|
TrackError MemoryStrip::begin() {
|
|
if (pixels_.empty()) {
|
|
return TrackError::invalid_size;
|
|
}
|
|
begun_ = true;
|
|
return TrackError::ok;
|
|
}
|
|
|
|
TrackError MemoryStrip::clear() {
|
|
std::ranges::fill(pixels_, Color::black());
|
|
return TrackError::ok;
|
|
}
|
|
|
|
TrackError MemoryStrip::fill(std::size_t start, std::size_t count, Color color) {
|
|
if (count == 0) {
|
|
return TrackError::ok;
|
|
}
|
|
if (start >= pixels_.size()) {
|
|
return TrackError::range;
|
|
}
|
|
|
|
const auto available = pixels_.size() - start;
|
|
const auto length = std::min(count, available);
|
|
std::fill_n(pixels_.begin() + static_cast<std::ptrdiff_t>(start), length, color);
|
|
return TrackError::ok;
|
|
}
|
|
|
|
TrackError MemoryStrip::show() {
|
|
++frame_sequence_;
|
|
return TrackError::ok;
|
|
}
|
|
|
|
TrackError MemoryStrip::set_leds_count(std::size_t count) {
|
|
if (count == 0) {
|
|
return TrackError::invalid_arg;
|
|
}
|
|
pixels_.assign(count, Color::black());
|
|
return TrackError::ok;
|
|
}
|
|
|
|
std::size_t MemoryStrip::leds_count() const {
|
|
return pixels_.size();
|
|
}
|
|
|
|
std::uint64_t MemoryStrip::frame_sequence() const {
|
|
return frame_sequence_;
|
|
}
|
|
|
|
std::span<const Color> MemoryStrip::pixels() const {
|
|
return pixels_;
|
|
}
|
|
|
|
TrackError apply_render_plan(MemoryStrip &strip, const TrackRenderPlan &plan) {
|
|
return apply_render_plan(make_memory_strip_sink(strip), plan);
|
|
}
|
|
|
|
TrackRenderSink make_memory_strip_sink(MemoryStrip &strip) {
|
|
return TrackRenderSink{
|
|
.context = &strip,
|
|
.clear = memory_strip_clear,
|
|
.fill = memory_strip_fill,
|
|
.show = memory_strip_show,
|
|
};
|
|
}
|
|
|
|
} // namespace track_core
|