You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
3.3 KiB
96 lines
3.3 KiB
#include "tools/cabana/canmessages.h"
|
|
#include "tools/cabana/dbcmanager.h"
|
|
|
|
CANMessages *can = nullptr;
|
|
|
|
CANMessages::CANMessages(QObject *parent) : QObject(parent) {
|
|
can = this;
|
|
QObject::connect(this, &CANMessages::received, this, &CANMessages::process, Qt::QueuedConnection);
|
|
QObject::connect(&settings, &Settings::changed, this, &CANMessages::settingChanged);
|
|
}
|
|
|
|
CANMessages::~CANMessages() {
|
|
replay->stop();
|
|
}
|
|
|
|
static bool event_filter(const Event *e, void *opaque) {
|
|
CANMessages *c = (CANMessages *)opaque;
|
|
return c->eventFilter(e);
|
|
}
|
|
|
|
bool CANMessages::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) {
|
|
replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this);
|
|
replay->setSegmentCacheLimit(settings.cached_segment_limit);
|
|
replay->installEventFilter(event_filter, this);
|
|
QObject::connect(replay, &Replay::seekedTo, this, &CANMessages::seekedTo);
|
|
QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged);
|
|
QObject::connect(replay, &Replay::streamStarted, this, &CANMessages::streamStarted);
|
|
if (replay->load()) {
|
|
const auto &segments = replay->route()->segments();
|
|
if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) {
|
|
qWarning() << "no rlogs in route" << route;
|
|
return false;
|
|
}
|
|
replay->start();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CANMessages::process(QHash<QString, CanData> *messages) {
|
|
for (auto it = messages->begin(); it != messages->end(); ++it) {
|
|
can_msgs[it.key()] = it.value();
|
|
}
|
|
emit updated();
|
|
emit msgsReceived(messages);
|
|
delete messages;
|
|
processing = false;
|
|
}
|
|
|
|
bool CANMessages::eventFilter(const Event *event) {
|
|
static std::unique_ptr new_msgs = std::make_unique<QHash<QString, CanData>>();
|
|
static double prev_update_ts = 0;
|
|
|
|
if (event->which == cereal::Event::Which::CAN) {
|
|
double current_sec = replay->currentSeconds();
|
|
if (counters_begin_sec == 0 || counters_begin_sec >= current_sec) {
|
|
new_msgs->clear();
|
|
counters.clear();
|
|
counters_begin_sec = current_sec;
|
|
}
|
|
|
|
auto can_events = event->event.getCan();
|
|
for (const auto &c : can_events) {
|
|
QString id = QString("%1:%2").arg(c.getSrc()).arg(c.getAddress(), 1, 16);
|
|
CanData &data = (*new_msgs)[id];
|
|
data.ts = current_sec;
|
|
data.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size());
|
|
data.count = ++counters[id];
|
|
if (double delta = (current_sec - counters_begin_sec); delta > 0) {
|
|
data.freq = data.count / delta;
|
|
}
|
|
}
|
|
|
|
double ts = millis_since_boot();
|
|
if ((ts - prev_update_ts) > (1000.0 / settings.fps) && !processing && !new_msgs->isEmpty()) {
|
|
// delay posting CAN message if UI thread is busy
|
|
processing = true;
|
|
prev_update_ts = ts;
|
|
// use pointer to avoid data copy in queued connection.
|
|
emit received(new_msgs.release());
|
|
new_msgs.reset(new QHash<QString, CanData>);
|
|
new_msgs->reserve(100);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CANMessages::seekTo(double ts) {
|
|
replay->seekTo(std::max(double(0), ts), false);
|
|
counters_begin_sec = 0;
|
|
emit updated();
|
|
}
|
|
|
|
void CANMessages::settingChanged() {
|
|
replay->setSegmentCacheLimit(settings.cached_segment_limit);
|
|
}
|
|
|