add flag to auto load a route from the most suitable source

pull/34863/head
deanlee 1 month ago
parent 049193b178
commit 997df1694e
  1. 4
      tools/cabana/cabana.cc
  2. 5
      tools/cabana/streams/replaystream.cc
  3. 2
      tools/cabana/streams/replaystream.h
  4. 16
      tools/lib/logreader.py
  5. 4
      tools/replay/replay.cc
  6. 2
      tools/replay/replay.h
  7. 21
      tools/replay/route.cc
  8. 4
      tools/replay/route.h
  9. 4
      tools/replay/seg_mgr.h

@ -23,6 +23,7 @@ int main(int argc, char *argv[]) {
cmd_parser.addHelpOption(); cmd_parser.addHelpOption();
cmd_parser.addPositionalArgument("route", "the drive to replay. find your drives at connect.comma.ai"); 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({"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({"qcam", "load qcamera"});
cmd_parser.addOption({"ecam", "load wide road camera"}); cmd_parser.addOption({"ecam", "load wide road camera"});
cmd_parser.addOption({"dcam", "load driver camera"}); cmd_parser.addOption({"dcam", "load driver camera"});
@ -69,7 +70,8 @@ int main(int argc, char *argv[]) {
} }
if (!route.isEmpty()) { if (!route.isEmpty()) {
auto replay_stream = std::make_unique<ReplayStream>(&app); auto replay_stream = std::make_unique<ReplayStream>(&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; return 0;
} }
stream = replay_stream.release(); stream = replay_stream.release();

@ -7,6 +7,7 @@
#include <QPushButton> #include <QPushButton>
#include "common/timing.h" #include "common/timing.h"
#include "common/util.h"
#include "tools/cabana/streams/routes.h" #include "tools/cabana/streams/routes.h"
ReplayStream::ReplayStream(QObject *parent) : AbstractStream(parent) { 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"}, 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->setSegmentCacheLimit(settings.max_cached_minutes);
replay->installEventFilter([this](const Event *event) { return eventFilter(event); }); replay->installEventFilter([this](const Event *event) { return eventFilter(event); });

@ -18,7 +18,7 @@ class ReplayStream : public AbstractStream {
public: public:
ReplayStream(QObject *parent); ReplayStream(QObject *parent);
void start() override { replay->start(); } 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); bool eventFilter(const Event *event);
void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); } void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); }
bool liveStreaming() const override { return false; } bool liveStreaming() const override { return false; }

@ -6,12 +6,12 @@ import capnp
import enum import enum
import os import os
import pathlib import pathlib
import sys
import tqdm import tqdm
import urllib.parse import urllib.parse
import warnings import warnings
import zstandard as zstd import zstandard as zstd
from argparse import ArgumentParser
from collections.abc import Callable, Iterable, Iterator from collections.abc import Callable, Iterable, Iterator
from urllib.parse import parse_qs, urlparse 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 # capnproto <= 0.8.0 throws errors converting byte data to string
# below line catches those errors and replaces the bytes with \x__ # below line catches those errors and replaces the bytes with \x__
codecs.register_error("strict", codecs.backslashreplace_errors) codecs.register_error("strict", codecs.backslashreplace_errors)
log_path = sys.argv[1]
lr = LogReader(log_path, sort_by_time=True) 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: for msg in lr:
print(msg) print(msg)

@ -15,8 +15,8 @@ void notifyEvent(Callback &callback, Args &&...args) {
} }
Replay::Replay(const std::string &route, std::vector<std::string> allow, std::vector<std::string> block, Replay::Replay(const std::string &route, std::vector<std::string> allow, std::vector<std::string> block,
SubMaster *sm, uint32_t flags, const std::string &data_dir) SubMaster *sm, uint32_t flags, const std::string &data_dir, bool auto_source)
: sm_(sm), flags_(flags), seg_mgr_(std::make_unique<SegmentManager>(route, flags, data_dir)) { : sm_(sm), flags_(flags), seg_mgr_(std::make_unique<SegmentManager>(route, flags, data_dir, auto_source)) {
std::signal(SIGUSR1, interrupt_sleep_handler); std::signal(SIGUSR1, interrupt_sleep_handler);
if (!(flags_ & REPLAY_FLAG_ALL_SERVICES)) { if (!(flags_ & REPLAY_FLAG_ALL_SERVICES)) {

@ -29,7 +29,7 @@ enum REPLAY_FLAGS {
class Replay { class Replay {
public: public:
Replay(const std::string &route, std::vector<std::string> allow, std::vector<std::string> block, SubMaster *sm = nullptr, Replay(const std::string &route, std::vector<std::string> allow, std::vector<std::string> 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(); ~Replay();
bool load(); bool load();
RouteLoadError lastRouteError() const { return route().lastError(); } RouteLoadError lastRouteError() const { return route().lastError(); }

@ -10,9 +10,12 @@
#include "tools/replay/replay.h" #include "tools/replay/replay.h"
#include "tools/replay/util.h" #include "tools/replay/util.h"
Route::Route(const std::string &route, const std::string &data_dir) : data_dir_(data_dir) { 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); route_ = parseRoute(route);
} }
}
RouteIdentifier Route::parseRoute(const std::string &str) { RouteIdentifier Route::parseRoute(const std::string &str) {
RouteIdentifier identifier = {}; RouteIdentifier identifier = {};
@ -45,6 +48,22 @@ RouteIdentifier Route::parseRoute(const std::string &str) {
bool Route::load() { bool Route::load() {
err_ = RouteLoadError::None; 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())) { if (route_.str.empty() || (data_dir_.empty() && route_.dongle_id.empty())) {
rInfo("invalid route format"); rInfo("invalid route format");
return false; return false;

@ -40,7 +40,7 @@ struct SegmentFile {
class Route { class Route {
public: 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(); bool load();
RouteLoadError lastError() const { return err_; } RouteLoadError lastError() const { return err_; }
inline const std::string &name() const { return route_.str; } inline const std::string &name() const { return route_.str; }
@ -61,6 +61,8 @@ protected:
std::map<int, SegmentFile> segments_; std::map<int, SegmentFile> segments_;
std::time_t date_time_; std::time_t date_time_;
RouteLoadError err_ = RouteLoadError::None; RouteLoadError err_ = RouteLoadError::None;
bool auto_source_ = false;
std::string route_string_;
}; };
class Segment { class Segment {

@ -20,8 +20,8 @@ public:
bool isSegmentLoaded(int n) const { return segments.find(n) != segments.end(); } 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 = "") 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), event_data_(std::make_shared<EventData>()) {} : flags_(flags), route_(route_name, data_dir, auto_source), event_data_(std::make_shared<EventData>()) {}
~SegmentManager(); ~SegmentManager();
bool load(); bool load();

Loading…
Cancel
Save