refactor(track-core): remove app-facing track adapters
Keep track-core focused on portable track state, scheme runtime, PID runtime, memory strip, and render planning. Remove the ESP-IDF/nanopb Track adapter headers and sources from the submodule so app/protobuf ownership can live in a separate firmware component. The standalone CMake and Python binding surface remains unchanged, including the emulator-facing APIs.
This commit is contained in:
@@ -1,121 +0,0 @@
|
||||
#include "app_track_decoder.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace app::track {
|
||||
namespace {
|
||||
|
||||
track_core::Color to_core(const Color &color) {
|
||||
return {
|
||||
color.inner.r,
|
||||
color.inner.g,
|
||||
color.inner.b,
|
||||
};
|
||||
}
|
||||
|
||||
error_t from_core(track_core::TrackError error) {
|
||||
switch (error) {
|
||||
case track_core::TrackError::ok:
|
||||
return ESP_OK;
|
||||
case track_core::TrackError::invalid_arg:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
case track_core::TrackError::invalid_size:
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
case track_core::TrackError::invalid_state:
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
case track_core::TrackError::not_supported:
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
case track_core::TrackError::range:
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TrackSchemeDecoder TrackSchemeDecoder::from_proto(const proto_type &proto) {
|
||||
TrackSchemeDecoder scheme;
|
||||
scheme.id = proto.id;
|
||||
if (proto.has_color) {
|
||||
scheme.color = Color::from_proto(proto.color);
|
||||
} else {
|
||||
scheme.color = Color::white();
|
||||
}
|
||||
auto data = std::span<const uint8_t>(proto.data.bytes, proto.data.size);
|
||||
std::ranges::copy(data, std::back_inserter(scheme.binary));
|
||||
return scheme;
|
||||
}
|
||||
|
||||
TrackSchemeDecoder::proto_type TrackSchemeDecoder::to_proto() const {
|
||||
proto_type proto = track_app_TrackScheme_init_default;
|
||||
proto.id = id;
|
||||
proto.has_color = true;
|
||||
proto.color = color.to_proto();
|
||||
const auto data = std::span<uint8_t>(proto.data.bytes);
|
||||
const auto count = std::min(data.size(), binary.size());
|
||||
std::ranges::copy(binary.begin(), binary.begin() + static_cast<std::ptrdiff_t>(count), data.begin());
|
||||
proto.data.size = count;
|
||||
return proto;
|
||||
}
|
||||
|
||||
expected<track_core::DecodedScheme, error_t> TrackSchemeDecoder::decode_core() const {
|
||||
using ue = unexpected<error_t>;
|
||||
if (binary.empty()) {
|
||||
return ue{ESP_ERR_INVALID_ARG};
|
||||
}
|
||||
|
||||
const auto decoded = track_core::decode_scheme(id, to_core(color), binary);
|
||||
if (!decoded) {
|
||||
return ue{from_core(decoded.error())};
|
||||
}
|
||||
return *decoded;
|
||||
}
|
||||
|
||||
TrackSchemeMgr::Add TrackSchemeMgr::Add::from_proto(const proto_type &proto) {
|
||||
Add add;
|
||||
assert(proto.has_scheme);
|
||||
add.scheme_decoder = TrackSchemeDecoder::from_proto(proto.scheme);
|
||||
return add;
|
||||
}
|
||||
|
||||
TrackSchemeMgr::Add::proto_type TrackSchemeMgr::Add::to_proto() const {
|
||||
proto_type proto = track_app_TrackSchemeMgrAdd_init_default;
|
||||
proto.has_scheme = true;
|
||||
proto.scheme = scheme_decoder.to_proto();
|
||||
return proto;
|
||||
}
|
||||
|
||||
TrackSchemeMgr TrackSchemeMgr::from_proto(const proto_type &proto) {
|
||||
TrackSchemeMgr mgmt;
|
||||
switch (proto.which_msg) {
|
||||
case track_app_TrackSchemeMgr_add_tag:
|
||||
mgmt.choice = Add::from_proto(proto.msg.add);
|
||||
break;
|
||||
case track_app_TrackSchemeMgr_clear_tag:
|
||||
mgmt.choice = Clear{};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return mgmt;
|
||||
}
|
||||
|
||||
TrackSchemeMgr::proto_type TrackSchemeMgr::to_proto() const {
|
||||
proto_type proto = track_app_TrackSchemeMgr_init_default;
|
||||
std::visit(app::utils::overloads{
|
||||
[](Unknown) {},
|
||||
[&](const Add &add) {
|
||||
proto.which_msg = track_app_TrackSchemeMgr_add_tag;
|
||||
proto.msg.add = add.to_proto();
|
||||
},
|
||||
[&](Clear) {
|
||||
proto.which_msg = track_app_TrackSchemeMgr_clear_tag;
|
||||
proto.msg.clear = track_app_TrackSchemeMgrClear_init_default;
|
||||
}},
|
||||
choice);
|
||||
return proto;
|
||||
}
|
||||
|
||||
} // namespace app::track
|
||||
@@ -1,177 +0,0 @@
|
||||
#include "app_track_drawer.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#include "track_core/render.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
track_core::Color to_core(const app::track::Color &color) {
|
||||
return {
|
||||
color.inner.r,
|
||||
color.inner.g,
|
||||
color.inner.b,
|
||||
};
|
||||
}
|
||||
|
||||
app::track::Color from_core(const track_core::Color &color) {
|
||||
return {
|
||||
color.r,
|
||||
color.g,
|
||||
color.b,
|
||||
};
|
||||
}
|
||||
|
||||
track_core::TrackDrawKind to_core(track_app_TrackDrawKind draw_kind) {
|
||||
switch (draw_kind) {
|
||||
case track_app_TrackDrawKind_CIRCULAR:
|
||||
return track_core::TrackDrawKind::circular;
|
||||
case track_app_TrackDrawKind_LINEAR:
|
||||
return track_core::TrackDrawKind::linear;
|
||||
}
|
||||
return track_core::TrackDrawKind::circular;
|
||||
}
|
||||
|
||||
track_core::SchemeKind to_core(app::track::SchemeKind kind) {
|
||||
switch (kind) {
|
||||
case track_app_TrackSchemeKind_SPEED_INPUT_MILEAGE_SEGMENTED_TIME_FREE:
|
||||
return track_core::SchemeKind::speed_input_mileage_segmented_time_free;
|
||||
case track_app_TrackSchemeKind_MILEAGE_INPUT_TIME_SEGMENTED_SPEED_FREE:
|
||||
return track_core::SchemeKind::mileage_input_time_segmented_speed_free;
|
||||
case track_app_TrackSchemeKind_SPEED_INPUT_TIME_SEGMENTED_MILEAGE_FREE:
|
||||
return track_core::SchemeKind::speed_input_time_segmented_mileage_free;
|
||||
case track_app_TrackSchemeKind_REPEATED_SPEED_INPUT_MILEAGE_SEGMENTATION_INPUT_TIME_SEGMENTED:
|
||||
return track_core::SchemeKind::repeated_speed_input_mileage_segmentation_input_time_segmented;
|
||||
}
|
||||
return track_core::SchemeKind::speed_input_time_segmented_mileage_free;
|
||||
}
|
||||
|
||||
track_core::TrackState to_core(app::track::TrackState state) {
|
||||
switch (state) {
|
||||
case track_app_TrackState_STOP:
|
||||
return track_core::TrackState::stop;
|
||||
case track_app_TrackState_RUN:
|
||||
return track_core::TrackState::run;
|
||||
case track_app_TrackState_TEST_DISPLAY:
|
||||
return track_core::TrackState::test_display;
|
||||
}
|
||||
return track_core::TrackState::stop;
|
||||
}
|
||||
|
||||
track_core::TrackConfig to_core(const app::track::TrackConfig &config) {
|
||||
return {
|
||||
.draw_kind = to_core(config.draw_kind),
|
||||
.line_length_m = config.line_length_m,
|
||||
.active_line_length_m = config.active_line_length_m,
|
||||
.head_offset_m = config.head_offset_m,
|
||||
.line_leds_num = config.line_leds_num,
|
||||
};
|
||||
}
|
||||
|
||||
track_core::TrackInfo to_core(const app::track::TrackInfo &info) {
|
||||
return {
|
||||
.kind = to_core(info.kind),
|
||||
.color = to_core(info.color),
|
||||
.id = info.id,
|
||||
.is_running = info.is_running,
|
||||
.num_segments = info.num_segments,
|
||||
};
|
||||
}
|
||||
|
||||
track_core::TrackReport to_core(const app::track::report &report) {
|
||||
return {
|
||||
.id = report.id,
|
||||
.state = to_core(report.state),
|
||||
.mileage_m = report.mileage_m,
|
||||
.speed_m_s = report.speed_m_s,
|
||||
.time_elapsed_ms = report.time_elapsed_ms,
|
||||
};
|
||||
}
|
||||
|
||||
track_core::TrackError to_core(error_t error) {
|
||||
if (error == ESP_OK) {
|
||||
return track_core::TrackError::ok;
|
||||
}
|
||||
return track_core::TrackError::invalid_state;
|
||||
}
|
||||
|
||||
app::strip::StripView *strip_from_context(void *context) {
|
||||
return static_cast<app::strip::StripView *>(context);
|
||||
}
|
||||
|
||||
track_core::TrackError strip_clear(void *context) {
|
||||
auto *strip = strip_from_context(context);
|
||||
if (strip == nullptr) {
|
||||
return track_core::TrackError::invalid_arg;
|
||||
}
|
||||
return to_core((*strip)->clear());
|
||||
}
|
||||
|
||||
track_core::TrackError strip_fill(
|
||||
void *context,
|
||||
std::uint16_t start_led,
|
||||
std::uint16_t led_count,
|
||||
track_core::Color color) {
|
||||
auto *strip = strip_from_context(context);
|
||||
if (strip == nullptr) {
|
||||
return track_core::TrackError::invalid_arg;
|
||||
}
|
||||
return to_core((*strip)->fill(start_led, led_count, static_cast<std::uint32_t>(from_core(color))));
|
||||
}
|
||||
|
||||
track_core::TrackError strip_show(void *context) {
|
||||
auto *strip = strip_from_context(context);
|
||||
if (strip == nullptr) {
|
||||
return track_core::TrackError::invalid_arg;
|
||||
}
|
||||
return to_core((*strip)->show());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace app::track {
|
||||
|
||||
void TrackRenderPlan::add_fill(uint16_t start_led, uint16_t led_count, Color color) {
|
||||
if (led_count == 0) {
|
||||
return;
|
||||
}
|
||||
assert(span_count < spans.size() && "TrackRenderPlan capacity exceeded");
|
||||
spans[span_count++] = TrackRenderSpan{
|
||||
.start_led = start_led,
|
||||
.led_count = led_count,
|
||||
.color = color,
|
||||
};
|
||||
}
|
||||
|
||||
TrackRenderPlan make_track_render_plan(const TrackConfig &config, const TrackInfo &info, const report &rep) {
|
||||
const auto core_plan = track_core::make_track_render_plan(
|
||||
to_core(config),
|
||||
to_core(info),
|
||||
to_core(rep));
|
||||
|
||||
TrackRenderPlan plan{};
|
||||
for (size_t i = 0; i < core_plan.span_count; ++i) {
|
||||
const auto &span = core_plan.spans[i];
|
||||
plan.add_fill(span.start_led, span.led_count, from_core(span.color));
|
||||
}
|
||||
return plan;
|
||||
}
|
||||
|
||||
void apply_render_plan(app::strip::StripView strip, const TrackRenderPlan &plan) {
|
||||
for (size_t i = 0; i < plan.span_count; ++i) {
|
||||
const auto &span = plan.spans[i];
|
||||
strip->fill(span.start_led, span.led_count, span.color);
|
||||
}
|
||||
}
|
||||
|
||||
track_core::TrackRenderSink make_track_render_sink(app::strip::StripView &strip) {
|
||||
return track_core::TrackRenderSink{
|
||||
.context = &strip,
|
||||
.clear = strip_clear,
|
||||
.fill = strip_fill,
|
||||
.show = strip_show,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace app::track
|
||||
@@ -1,107 +0,0 @@
|
||||
#include "app_track_model.hpp"
|
||||
#include "app_track.pb.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
namespace {
|
||||
app::track::config_getter global_config_getter{nullptr};
|
||||
constexpr auto TAG = "app::track";
|
||||
}
|
||||
|
||||
namespace app::track {
|
||||
const char *to_str(TrackState status) {
|
||||
using enum TrackState;
|
||||
switch (status) {
|
||||
case track_app_TrackState_STOP:
|
||||
return "STOP";
|
||||
case track_app_TrackState_RUN:
|
||||
return "RUN";
|
||||
case track_app_TrackState_TEST_DISPLAY:
|
||||
return "TEST_DISPLAY";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
const char *to_str(TrackControllerMode mode) {
|
||||
switch (mode) {
|
||||
case track_app_TrackControllerMode_SCHEME:
|
||||
return "SCHEME";
|
||||
case track_app_TrackControllerMode_PID_HR:
|
||||
return "PID_HR";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
const char *to_str(TrackPidStageKind kind) {
|
||||
switch (kind) {
|
||||
case track_app_TrackPidStageKind_NONE:
|
||||
return "NONE";
|
||||
case track_app_TrackPidStageKind_CONSTANT:
|
||||
return "CONSTANT";
|
||||
case track_app_TrackPidStageKind_PID:
|
||||
return "PID";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
const char *to_str(track_app_TrackDrawKind draw_kind) {
|
||||
switch (draw_kind) {
|
||||
case track_app_TrackDrawKind_CIRCULAR:
|
||||
return "CIRCULAR";
|
||||
case track_app_TrackDrawKind_LINEAR:
|
||||
return "LINEAR";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
const char *to_str(AccelerationProfile profile) {
|
||||
switch (profile) {
|
||||
case track_app_TrackAccelerationProfile_SMOOTH:
|
||||
return "SMOOTH";
|
||||
case track_app_TrackAccelerationProfile_INSTANT:
|
||||
return "INSTANT";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
void set_global_config_getter(config_getter getter) {
|
||||
global_config_getter = std::move(getter);
|
||||
}
|
||||
|
||||
const TrackConfig &global_config() {
|
||||
if (not global_config_getter) {
|
||||
static const auto DEFAULT_CONFIG = TrackConfig::Default();
|
||||
ESP_LOGW(TAG, "unset global config getter");
|
||||
return DEFAULT_CONFIG;
|
||||
}
|
||||
return global_config_getter();
|
||||
}
|
||||
|
||||
void TrackConfig::log(const char *tag, esp_log_level_t level) const {
|
||||
ESP_LOG_LEVEL(level, tag,
|
||||
"TrackConfig{.draw_kind=%s, "
|
||||
".line_length_m=%.2f, "
|
||||
".active_line_length_m=%.2f, "
|
||||
".head_offset_m=%.2f, "
|
||||
".line_leds_num=%" PRIu16
|
||||
"}",
|
||||
to_str(draw_kind),
|
||||
line_length_m,
|
||||
active_line_length_m,
|
||||
head_offset_m,
|
||||
line_leds_num);
|
||||
}
|
||||
|
||||
void TrackStateReportCollection::log(const char *tag, esp_log_level_t level) const {
|
||||
for (size_t i = 0; i < states.size(); ++i) {
|
||||
const auto &report = states[i];
|
||||
ESP_LOG_LEVEL(level, tag,
|
||||
"[%zu] Report{.id=%" PRIu8 ", .state=%s, .mileage_m=%.2f, .speed_m_s=%.2f, .time_elapsed_ms=%" PRIu32 "}",
|
||||
i,
|
||||
report.id,
|
||||
to_str(report.state),
|
||||
report.mileage_m,
|
||||
report.speed_m_s,
|
||||
report.time_elapsed_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user