From 997df1694e55b2061b1657d804300b106d04ed20 Mon Sep 17 00:00:00 2001 From: deanlee Date: Fri, 14 Mar 2025 15:13:40 +0800 Subject: [PATCH] add flag to auto load a route from the most suitable source --- tools/cabana/cabana.cc | 4 +++- tools/cabana/streams/replaystream.cc | 5 +++-- tools/cabana/streams/replaystream.h | 2 +- tools/lib/logreader.py | 20 +++++++++++++++----- tools/replay/replay.cc | 4 ++-- tools/replay/replay.h | 2 +- tools/replay/route.cc | 23 +++++++++++++++++++++-- tools/replay/route.h | 4 +++- tools/replay/seg_mgr.h | 4 ++-- 9 files changed, 51 insertions(+), 17 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index d140a323e1..6ccbec428e 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -23,6 +23,7 @@ int main(int argc, char *argv[]) { cmd_parser.addHelpOption(); cmd_parser.addPositionalArgument("route", "the drive to replay. find your drives at connect.comma.ai"); cmd_parser.addOption({"demo", "use a demo route instead of providing your own"}); + cmd_parser.addOption({"auto", "auto load a route from the most suitable source"}); cmd_parser.addOption({"qcam", "load qcamera"}); cmd_parser.addOption({"ecam", "load wide road camera"}); cmd_parser.addOption({"dcam", "load driver camera"}); @@ -69,7 +70,8 @@ int main(int argc, char *argv[]) { } if (!route.isEmpty()) { auto replay_stream = std::make_unique(&app); - if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { + bool auto_source = cmd_parser.isSet("auto"); + if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"), replay_flags, auto_source)) { return 0; } stream = replay_stream.release(); diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index ebe478ded7..b8cf1be299 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -7,6 +7,7 @@ #include #include "common/timing.h" +#include "common/util.h" #include "tools/cabana/streams/routes.h" ReplayStream::ReplayStream(QObject *parent) : AbstractStream(parent) { @@ -45,9 +46,9 @@ void ReplayStream::mergeSegments() { } } -bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { +bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags, bool auto_source) { replay.reset(new Replay(route.toStdString(), {"can", "roadEncodeIdx", "driverEncodeIdx", "wideRoadEncodeIdx", "carParams"}, - {}, nullptr, replay_flags, data_dir.toStdString())); + {}, nullptr, replay_flags, data_dir.toStdString(), auto_source)); replay->setSegmentCacheLimit(settings.max_cached_minutes); replay->installEventFilter([this](const Event *event) { return eventFilter(event); }); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index df1f2526a5..d429ed1f95 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -18,7 +18,7 @@ class ReplayStream : public AbstractStream { public: ReplayStream(QObject *parent); void start() override { replay->start(); } - bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); + bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE, bool auto_source = false); bool eventFilter(const Event *event); void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); } bool liveStreaming() const override { return false; } diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 34d3e5ea9f..e354dc8b49 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -6,12 +6,12 @@ import capnp import enum import os import pathlib -import sys import tqdm import urllib.parse import warnings import zstandard as zstd +from argparse import ArgumentParser from collections.abc import Callable, Iterable, Iterator from urllib.parse import parse_qs, urlparse @@ -333,7 +333,17 @@ if __name__ == "__main__": # capnproto <= 0.8.0 throws errors converting byte data to string # below line catches those errors and replaces the bytes with \x__ codecs.register_error("strict", codecs.backslashreplace_errors) - log_path = sys.argv[1] - lr = LogReader(log_path, sort_by_time=True) - for msg in lr: - print(msg) + + parser = ArgumentParser(description="Process a log file and print identifiers or full messages.") + parser.add_argument("log_path", help="Path to the log file") + parser.add_argument( + "--identifiers-only", action="store_true", help="Print only log identifiers instead of full messages" + ) + args = parser.parse_args() + + lr = LogReader(args.log_path, sort_by_time=True) + if args.identifiers_only: + print("\n".join(lr.logreader_identifiers)) + else: + for msg in lr: + print(msg) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 80f586daa6..a8e5cd9d43 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -15,8 +15,8 @@ void notifyEvent(Callback &callback, Args &&...args) { } Replay::Replay(const std::string &route, std::vector allow, std::vector block, - SubMaster *sm, uint32_t flags, const std::string &data_dir) - : sm_(sm), flags_(flags), seg_mgr_(std::make_unique(route, flags, data_dir)) { + SubMaster *sm, uint32_t flags, const std::string &data_dir, bool auto_source) + : sm_(sm), flags_(flags), seg_mgr_(std::make_unique(route, flags, data_dir, auto_source)) { std::signal(SIGUSR1, interrupt_sleep_handler); if (!(flags_ & REPLAY_FLAG_ALL_SERVICES)) { diff --git a/tools/replay/replay.h b/tools/replay/replay.h index 6a2c86ff02..5e868d2427 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -29,7 +29,7 @@ enum REPLAY_FLAGS { class Replay { public: Replay(const std::string &route, std::vector allow, std::vector block, SubMaster *sm = nullptr, - uint32_t flags = REPLAY_FLAG_NONE, const std::string &data_dir = ""); + uint32_t flags = REPLAY_FLAG_NONE, const std::string &data_dir = "", bool auto_source = false); ~Replay(); bool load(); RouteLoadError lastRouteError() const { return route().lastError(); } diff --git a/tools/replay/route.cc b/tools/replay/route.cc index 7731d0daf4..fa359678fb 100644 --- a/tools/replay/route.cc +++ b/tools/replay/route.cc @@ -10,8 +10,11 @@ #include "tools/replay/replay.h" #include "tools/replay/util.h" -Route::Route(const std::string &route, const std::string &data_dir) : data_dir_(data_dir) { - route_ = parseRoute(route); +Route::Route(const std::string &route, const std::string &data_dir, bool auto_source) + : route_string_(route), data_dir_(data_dir), auto_source_(auto_source) { + if (!auto_source) { + route_ = parseRoute(route); + } } RouteIdentifier Route::parseRoute(const std::string &str) { @@ -45,6 +48,22 @@ RouteIdentifier Route::parseRoute(const std::string &str) { bool Route::load() { err_ = RouteLoadError::None; + + if (auto_source_) { + auto cmd = util::string_format("python ../lib/logreader.py \"%s\" --identifiers-only", route_string_.c_str()); + auto output = util::check_output(cmd); + auto log_files = split(output, '\n'); + for (int i = 0; i < log_files.size(); ++i) { + addFileToSegment(i, log_files[i]); + } + route_.begin_segment = 0; + route_.end_segment = log_files.size() - 1; + route_.dongle_id = route_string_; + route_.str = route_string_; + route_.timestamp = ""; + return !segments_.empty(); + } + if (route_.str.empty() || (data_dir_.empty() && route_.dongle_id.empty())) { rInfo("invalid route format"); return false; diff --git a/tools/replay/route.h b/tools/replay/route.h index 1806be5afa..898385ed42 100644 --- a/tools/replay/route.h +++ b/tools/replay/route.h @@ -40,7 +40,7 @@ struct SegmentFile { class Route { public: - Route(const std::string &route, const std::string &data_dir = {}); + Route(const std::string &route, const std::string &data_dir = {}, bool auto_source = false); bool load(); RouteLoadError lastError() const { return err_; } inline const std::string &name() const { return route_.str; } @@ -61,6 +61,8 @@ protected: std::map segments_; std::time_t date_time_; RouteLoadError err_ = RouteLoadError::None; + bool auto_source_ = false; + std::string route_string_; }; class Segment { diff --git a/tools/replay/seg_mgr.h b/tools/replay/seg_mgr.h index 9158e41618..640169749e 100644 --- a/tools/replay/seg_mgr.h +++ b/tools/replay/seg_mgr.h @@ -20,8 +20,8 @@ public: bool isSegmentLoaded(int n) const { return segments.find(n) != segments.end(); } }; - SegmentManager(const std::string &route_name, uint32_t flags, const std::string &data_dir = "") - : flags_(flags), route_(route_name, data_dir), event_data_(std::make_shared()) {} + SegmentManager(const std::string &route_name, uint32_t flags, const std::string &data_dir = "", bool auto_source = false) + : flags_(flags), route_(route_name, data_dir, auto_source), event_data_(std::make_shared()) {} ~SegmentManager(); bool load();