cabana: refactor message id from QString to struct (#27352)

* cabana: refactor message id from QString to struct

* fix tabbar

* fix findsimilarbits

* optimize hash function

* cleanup sorting

* use in updateLastMsgsTo
old-commit-hash: 5078c91805
beeps
Willem Melching 2 years ago committed by GitHub
parent 5128ca0dd9
commit c9a2d19596
  1. 12
      tools/cabana/binaryview.cc
  2. 8
      tools/cabana/binaryview.h
  3. 27
      tools/cabana/chartswidget.cc
  4. 28
      tools/cabana/chartswidget.h
  5. 18
      tools/cabana/commands.cc
  6. 20
      tools/cabana/commands.h
  7. 34
      tools/cabana/dbcmanager.cc
  8. 44
      tools/cabana/dbcmanager.h
  9. 51
      tools/cabana/detailwidget.cc
  10. 9
      tools/cabana/detailwidget.h
  11. 17
      tools/cabana/historylog.cc
  12. 8
      tools/cabana/historylog.h
  13. 22
      tools/cabana/messageswidget.cc
  14. 14
      tools/cabana/messageswidget.h
  15. 10
      tools/cabana/signaledit.cc
  16. 12
      tools/cabana/signaledit.h
  17. 19
      tools/cabana/streams/abstractstream.cc
  18. 17
      tools/cabana/streams/abstractstream.h
  19. 8
      tools/cabana/tools/findsimilarbits.cc
  20. 4
      tools/cabana/tools/findsimilarbits.h

@ -94,7 +94,7 @@ void BinaryView::addShortcuts() {
QObject::connect(shortcut_plot_c, &QShortcut::activated, shortcut_plot, &QShortcut::activated); QObject::connect(shortcut_plot_c, &QShortcut::activated, shortcut_plot, &QShortcut::activated);
QObject::connect(shortcut_plot, &QShortcut::activated, [=]{ QObject::connect(shortcut_plot, &QShortcut::activated, [=]{
if (hovered_sig != nullptr) { if (hovered_sig != nullptr) {
emit showChart(model->msg_id, hovered_sig, true, false); emit showChart(*model->msg_id, hovered_sig, true, false);
} }
}); });
} }
@ -189,14 +189,14 @@ void BinaryView::leaveEvent(QEvent *event) {
QTableView::leaveEvent(event); QTableView::leaveEvent(event);
} }
void BinaryView::setMessage(const QString &message_id) { void BinaryView::setMessage(const MessageId &message_id) {
model->msg_id = message_id; model->msg_id = message_id;
verticalScrollBar()->setValue(0); verticalScrollBar()->setValue(0);
refresh(); refresh();
} }
void BinaryView::refresh() { void BinaryView::refresh() {
if (model->msg_id.isEmpty()) return; if (!model->msg_id) return;
clearSelection(); clearSelection();
anchor_index = QModelIndex(); anchor_index = QModelIndex();
@ -231,7 +231,7 @@ std::tuple<int, int, bool> BinaryView::getSelection(QModelIndex index) {
void BinaryViewModel::refresh() { void BinaryViewModel::refresh() {
beginResetModel(); beginResetModel();
items.clear(); items.clear();
if ((dbc_msg = dbc()->msg(msg_id))) { if ((dbc_msg = dbc()->msg(*msg_id))) {
row_count = dbc_msg->size; row_count = dbc_msg->size;
items.resize(row_count * column_count); items.resize(row_count * column_count);
for (auto sig : dbc_msg->getSignals()) { for (auto sig : dbc_msg->getSignals()) {
@ -250,7 +250,7 @@ void BinaryViewModel::refresh() {
} }
} }
} else { } else {
row_count = can->lastMessage(msg_id).dat.size(); row_count = can->lastMessage(*msg_id).dat.size();
items.resize(row_count * column_count); items.resize(row_count * column_count);
} }
endResetModel(); endResetModel();
@ -259,7 +259,7 @@ void BinaryViewModel::refresh() {
void BinaryViewModel::updateState() { void BinaryViewModel::updateState() {
auto prev_items = items; auto prev_items = items;
const auto &last_msg = can->lastMessage(msg_id); const auto &last_msg = can->lastMessage(*msg_id);
const auto &binary = last_msg.dat; const auto &binary = last_msg.dat;
// data size may changed. // data size may changed.

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <optional>
#include <QApplication> #include <QApplication>
#include <QList> #include <QList>
#include <QSet> #include <QSet>
@ -46,7 +48,7 @@ public:
}; };
std::vector<Item> items; std::vector<Item> items;
QString msg_id; std::optional<MessageId> msg_id;
const DBCMsg *dbc_msg = nullptr; const DBCMsg *dbc_msg = nullptr;
int row_count = 0; int row_count = 0;
const int column_count = 9; const int column_count = 9;
@ -57,7 +59,7 @@ class BinaryView : public QTableView {
public: public:
BinaryView(QWidget *parent = nullptr); BinaryView(QWidget *parent = nullptr);
void setMessage(const QString &message_id); void setMessage(const MessageId &message_id);
void highlight(const Signal *sig); void highlight(const Signal *sig);
QSet<const Signal*> getOverlappingSignals() const; QSet<const Signal*> getOverlappingSignals() const;
inline void updateState() { model->updateState(); } inline void updateState() { model->updateState(); }
@ -70,7 +72,7 @@ signals:
void resizeSignal(const Signal *sig, int from, int size); void resizeSignal(const Signal *sig, int from, int size);
void removeSignal(const Signal *sig); void removeSignal(const Signal *sig);
void editSignal(const Signal *origin_s, Signal &s); void editSignal(const Signal *origin_s, Signal &s);
void showChart(const QString &name, const Signal *sig, bool show, bool merge); void showChart(const MessageId &id, const Signal *sig, bool show, bool merge);
private: private:
void addShortcuts(); void addShortcuts();

@ -181,7 +181,7 @@ void ChartsWidget::settingChanged() {
} }
} }
ChartView *ChartsWidget::findChart(const QString &id, const Signal *sig) { ChartView *ChartsWidget::findChart(const MessageId &id, const Signal *sig) {
for (auto c : charts) for (auto c : charts)
if (c->hasSeries(id, sig)) return c; if (c->hasSeries(id, sig)) return c;
return nullptr; return nullptr;
@ -204,7 +204,7 @@ ChartView *ChartsWidget::createChart() {
return chart; return chart;
} }
void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bool merge) { void ChartsWidget::showChart(const MessageId &id, const Signal *sig, bool show, bool merge) {
setUpdatesEnabled(false); setUpdatesEnabled(false);
ChartView *chart = findChart(id, sig); ChartView *chart = findChart(id, sig);
if (show && !chart) { if (show && !chart) {
@ -363,19 +363,18 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove); QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove);
} }
void ChartView::addSeries(const QString &msg_id, const Signal *sig) { void ChartView::addSeries(const MessageId &msg_id, const Signal *sig) {
if (hasSeries(msg_id, sig)) return; if (hasSeries(msg_id, sig)) return;
QXYSeries *series = createSeries(series_type, getColor(sig)); QXYSeries *series = createSeries(series_type, getColor(sig));
auto [source, address] = DBCManager::parseId(msg_id); sigs.push_back({.msg_id = msg_id, .sig = sig, .series = series});
sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series});
updateTitle(); updateTitle();
updateSeries(sig); updateSeries(sig);
updateSeriesPoints(); updateSeriesPoints();
emit seriesAdded(msg_id, sig); emit seriesAdded(msg_id, sig);
} }
bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const { bool ChartView::hasSeries(const MessageId &msg_id, const Signal *sig) const {
return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; });
} }
@ -409,7 +408,7 @@ void ChartView::signalUpdated(const Signal *sig) {
} }
void ChartView::msgUpdated(uint32_t address) { void ChartView::msgUpdated(uint32_t address) {
if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; })) if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.msg_id.address == address; }))
updateTitle(); updateTitle();
} }
@ -455,7 +454,7 @@ void ChartView::updateTitle() {
} }
for (auto &s : sigs) { for (auto &s : sigs) {
auto decoration = s.series->isVisible() ? "none" : "line-through"; auto decoration = s.series->isVisible() ? "none" : "line-through";
s.series->setName(QString("<span style=\"text-decoration:%1\"><b>%2</b> <font color=\"gray\">%3 %4</font></span>").arg(decoration, s.sig->name.c_str(), msgName(s.msg_id), s.msg_id)); s.series->setName(QString("<span style=\"text-decoration:%1\"><b>%2</b> <font color=\"gray\">%3 %4</font></span>").arg(decoration, s.sig->name.c_str(), msgName(s.msg_id), s.msg_id.toString()));
} }
} }
@ -517,7 +516,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector<Event *> *even
for (auto it = chunk.first; it != chunk.second; ++it) { for (auto it = chunk.first; it != chunk.second; ++it) {
if ((*it)->which == cereal::Event::Which::CAN) { if ((*it)->which == cereal::Event::Which::CAN) {
for (const auto &c : (*it)->event.getCan()) { for (const auto &c : (*it)->event.getCan()) {
if (s.address == c.getAddress() && s.source == c.getSrc()) { if (s.msg_id.address == c.getAddress() && s.msg_id.source == c.getSrc()) {
auto dat = c.getDat(); auto dat = c.getDat();
double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *s.sig); double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *s.sig);
double ts = ((*it)->mono_time / (double)1e9) - route_start_time; // seconds double ts = ((*it)->mono_time / (double)1e9) - route_start_time; // seconds
@ -847,7 +846,7 @@ SeriesSelector::SeriesSelector(QString title, QWidget *parent) : QDialog(parent)
for (auto it = can->can_msgs.cbegin(); it != can->can_msgs.cend(); ++it) { for (auto it = can->can_msgs.cbegin(); it != can->can_msgs.cend(); ++it) {
if (auto m = dbc()->msg(it.key())) { if (auto m = dbc()->msg(it.key())) {
msgs_combo->addItem(QString("%1 (%2)").arg(m->name).arg(it.key()), it.key()); msgs_combo->addItem(QString("%1 (%2)").arg(m->name).arg(it.key().toString()), QVariant::fromValue(it.key()));
} }
} }
msgs_combo->model()->sort(0); msgs_combo->model()->sort(0);
@ -872,7 +871,7 @@ void SeriesSelector::add(QListWidgetItem *item) {
void SeriesSelector::remove(QListWidgetItem *item) { void SeriesSelector::remove(QListWidgetItem *item) {
auto it = (ListItem *)item; auto it = (ListItem *)item;
if (it->msg_id == msgs_combo->currentData().toString()) { if (it->msg_id == msgs_combo->currentData().value<MessageId>()) {
addItemToList(available_list, it->msg_id, it->sig); addItemToList(available_list, it->msg_id, it->sig);
} }
delete item; delete item;
@ -881,7 +880,7 @@ void SeriesSelector::remove(QListWidgetItem *item) {
void SeriesSelector::updateAvailableList(int index) { void SeriesSelector::updateAvailableList(int index) {
if (index == -1) return; if (index == -1) return;
available_list->clear(); available_list->clear();
QString msg_id = msgs_combo->itemData(index).toString(); MessageId msg_id = msgs_combo->itemData(index).value<MessageId>();
auto selected_items = seletedItems(); auto selected_items = seletedItems();
for (auto &[name, s] : dbc()->msg(msg_id)->sigs) { for (auto &[name, s] : dbc()->msg(msg_id)->sigs) {
bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig=&s](auto it) { return it->msg_id == msg_id && it->sig == sig; }); bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig=&s](auto it) { return it->msg_id == msg_id && it->sig == sig; });
@ -891,9 +890,9 @@ void SeriesSelector::updateAvailableList(int index) {
} }
} }
void SeriesSelector::addItemToList(QListWidget *parent, const QString id, const Signal *sig, bool show_msg_name) { void SeriesSelector::addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name) {
QString text = QString("<span style=\"color:%0;\">■ </span> %1").arg(getColor(sig).name(), sig->name.c_str()); QString text = QString("<span style=\"color:%0;\">■ </span> %1").arg(getColor(sig).name(), sig->name.c_str());
if (show_msg_name) text += QString(" <font color=\"gray\">%0 %1</font>").arg(msgName(id), id); if (show_msg_name) text += QString(" <font color=\"gray\">%0 %1</font>").arg(msgName(id), id.toString());
QLabel *label = new QLabel(text); QLabel *label = new QLabel(text);
label->setContentsMargins(5, 0, 5, 0); label->setContentsMargins(5, 0, 5, 0);

@ -25,17 +25,15 @@ class ChartView : public QChartView {
public: public:
ChartView(QWidget *parent = nullptr); ChartView(QWidget *parent = nullptr);
void addSeries(const QString &msg_id, const Signal *sig); void addSeries(const MessageId &msg_id, const Signal *sig);
bool hasSeries(const QString &msg_id, const Signal *sig) const; bool hasSeries(const MessageId &msg_id, const Signal *sig) const;
void updateSeries(const Signal *sig = nullptr, const std::vector<Event*> *events = nullptr, bool clear = true); void updateSeries(const Signal *sig = nullptr, const std::vector<Event*> *events = nullptr, bool clear = true);
void updatePlot(double cur, double min, double max); void updatePlot(double cur, double min, double max);
void setSeriesType(QAbstractSeries::SeriesType type); void setSeriesType(QAbstractSeries::SeriesType type);
void updatePlotArea(int left); void updatePlotArea(int left);
struct SigItem { struct SigItem {
QString msg_id; MessageId msg_id;
uint8_t source = 0;
uint32_t address = 0;
const Signal *sig = nullptr; const Signal *sig = nullptr;
QXYSeries *series = nullptr; QXYSeries *series = nullptr;
QVector<QPointF> vals; QVector<QPointF> vals;
@ -43,8 +41,8 @@ public:
}; };
signals: signals:
void seriesRemoved(const QString &id, const Signal *sig); void seriesRemoved(const MessageId &id, const Signal *sig);
void seriesAdded(const QString &id, const Signal *sig); void seriesAdded(const MessageId &id, const Signal *sig);
void zoomIn(double min, double max); void zoomIn(double min, double max);
void zoomReset(); void zoomReset();
void remove(); void remove();
@ -55,7 +53,7 @@ private slots:
void signalUpdated(const Signal *sig); void signalUpdated(const Signal *sig);
void manageSeries(); void manageSeries();
void handleMarkerClicked(); void handleMarkerClicked();
void msgRemoved(uint32_t address) { removeIf([=](auto &s) { return s.address == address; }); } void msgRemoved(uint32_t address) { removeIf([=](auto &s) { return s.msg_id.address == address; }); }
void signalRemoved(const Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } void signalRemoved(const Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); }
private: private:
@ -99,8 +97,8 @@ class ChartsWidget : public QWidget {
public: public:
ChartsWidget(QWidget *parent = nullptr); ChartsWidget(QWidget *parent = nullptr);
void showChart(const QString &id, const Signal *sig, bool show, bool merge); void showChart(const MessageId &id, const Signal *sig, bool show, bool merge);
inline bool hasSignal(const QString &id, const Signal *sig) { return findChart(id, sig) != nullptr; } inline bool hasSignal(const MessageId &id, const Signal *sig) { return findChart(id, sig) != nullptr; }
public slots: public slots:
void setColumnCount(int n); void setColumnCount(int n);
@ -126,7 +124,7 @@ private:
void updateLayout(); void updateLayout();
void settingChanged(); void settingChanged();
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;
ChartView *findChart(const QString &id, const Signal *sig); ChartView *findChart(const MessageId &id, const Signal *sig);
QLabel *title_label; QLabel *title_label;
QLabel *range_lb; QLabel *range_lb;
@ -152,18 +150,18 @@ private:
class SeriesSelector : public QDialog { class SeriesSelector : public QDialog {
public: public:
struct ListItem : public QListWidgetItem { struct ListItem : public QListWidgetItem {
ListItem(const QString &msg_id, const Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {} ListItem(const MessageId &msg_id, const Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {}
QString msg_id; MessageId msg_id;
const Signal *sig; const Signal *sig;
}; };
SeriesSelector(QString title, QWidget *parent); SeriesSelector(QString title, QWidget *parent);
QList<ListItem *> seletedItems(); QList<ListItem *> seletedItems();
inline void addSelected(const QString &id, const Signal *sig) { addItemToList(selected_list, id, sig, true); } inline void addSelected(const MessageId &id, const Signal *sig) { addItemToList(selected_list, id, sig, true); }
private: private:
void updateAvailableList(int index); void updateAvailableList(int index);
void addItemToList(QListWidget *parent, const QString id, const Signal *sig, bool show_msg_name = false); void addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name = false);
void add(QListWidgetItem *item); void add(QListWidgetItem *item);
void remove(QListWidgetItem *item); void remove(QListWidgetItem *item);

@ -4,13 +4,13 @@
// EditMsgCommand // EditMsgCommand
EditMsgCommand::EditMsgCommand(const QString &id, const QString &title, int size, QUndoCommand *parent) EditMsgCommand::EditMsgCommand(const MessageId &id, const QString &title, int size, QUndoCommand *parent)
: id(id), new_title(title), new_size(size), QUndoCommand(parent) { : id(id), new_title(title), new_size(size), QUndoCommand(parent) {
if (auto msg = dbc()->msg(id)) { if (auto msg = dbc()->msg(id)) {
old_title = msg->name; old_title = msg->name;
old_size = msg->size; old_size = msg->size;
} }
setText(QObject::tr("Edit message %1:%2").arg(DBCManager::parseId(id).second).arg(title)); setText(QObject::tr("Edit message %1:%2").arg(id.address).arg(title));
} }
void EditMsgCommand::undo() { void EditMsgCommand::undo() {
@ -26,10 +26,10 @@ void EditMsgCommand::redo() {
// RemoveMsgCommand // RemoveMsgCommand
RemoveMsgCommand::RemoveMsgCommand(const QString &id, QUndoCommand *parent) : id(id), QUndoCommand(parent) { RemoveMsgCommand::RemoveMsgCommand(const MessageId &id, QUndoCommand *parent) : id(id), QUndoCommand(parent) {
if (auto msg = dbc()->msg(id)) { if (auto msg = dbc()->msg(id)) {
message = *msg; message = *msg;
setText(QObject::tr("Remove message %1:%2").arg(DBCManager::parseId(id).second).arg(message.name)); setText(QObject::tr("Remove message %1:%2").arg(id.address).arg(message.name));
} }
} }
@ -48,9 +48,9 @@ void RemoveMsgCommand::redo() {
// AddSigCommand // AddSigCommand
AddSigCommand::AddSigCommand(const QString &id, const Signal &sig, QUndoCommand *parent) AddSigCommand::AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent)
: id(id), signal(sig), QUndoCommand(parent) { : id(id), signal(sig), QUndoCommand(parent) {
setText(QObject::tr("Add signal %1 to %2").arg(sig.name.c_str()).arg(DBCManager::parseId(id).second)); setText(QObject::tr("Add signal %1 to %2").arg(sig.name.c_str()).arg(id.address));
} }
void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name.c_str()); } void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name.c_str()); }
@ -58,9 +58,9 @@ void AddSigCommand::redo() { dbc()->addSignal(id, signal); }
// RemoveSigCommand // RemoveSigCommand
RemoveSigCommand::RemoveSigCommand(const QString &id, const Signal *sig, QUndoCommand *parent) RemoveSigCommand::RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent)
: id(id), signal(*sig), QUndoCommand(parent) { : id(id), signal(*sig), QUndoCommand(parent) {
setText(QObject::tr("Remove signal %1 from %2").arg(signal.name.c_str()).arg(DBCManager::parseId(id).second)); setText(QObject::tr("Remove signal %1 from %2").arg(signal.name.c_str()).arg(id.address));
} }
void RemoveSigCommand::undo() { dbc()->addSignal(id, signal); } void RemoveSigCommand::undo() { dbc()->addSignal(id, signal); }
@ -68,7 +68,7 @@ void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name.c_str()); }
// EditSignalCommand // EditSignalCommand
EditSignalCommand::EditSignalCommand(const QString &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent) EditSignalCommand::EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent)
: id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) { : id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) {
setText(QObject::tr("Edit signal %1").arg(old_signal.name.c_str())); setText(QObject::tr("Edit signal %1").arg(old_signal.name.c_str()));
} }

@ -7,57 +7,57 @@
class EditMsgCommand : public QUndoCommand { class EditMsgCommand : public QUndoCommand {
public: public:
EditMsgCommand(const QString &id, const QString &title, int size, QUndoCommand *parent = nullptr); EditMsgCommand(const MessageId &id, const QString &title, int size, QUndoCommand *parent = nullptr);
void undo() override; void undo() override;
void redo() override; void redo() override;
private: private:
const QString id; const MessageId id;
QString old_title, new_title; QString old_title, new_title;
int old_size = 0, new_size = 0; int old_size = 0, new_size = 0;
}; };
class RemoveMsgCommand : public QUndoCommand { class RemoveMsgCommand : public QUndoCommand {
public: public:
RemoveMsgCommand(const QString &id, QUndoCommand *parent = nullptr); RemoveMsgCommand(const MessageId &id, QUndoCommand *parent = nullptr);
void undo() override; void undo() override;
void redo() override; void redo() override;
private: private:
const QString id; const MessageId id;
DBCMsg message; DBCMsg message;
}; };
class AddSigCommand : public QUndoCommand { class AddSigCommand : public QUndoCommand {
public: public:
AddSigCommand(const QString &id, const Signal &sig, QUndoCommand *parent = nullptr); AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent = nullptr);
void undo() override; void undo() override;
void redo() override; void redo() override;
private: private:
const QString id; const MessageId id;
Signal signal = {}; Signal signal = {};
}; };
class RemoveSigCommand : public QUndoCommand { class RemoveSigCommand : public QUndoCommand {
public: public:
RemoveSigCommand(const QString &id, const Signal *sig, QUndoCommand *parent = nullptr); RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent = nullptr);
void undo() override; void undo() override;
void redo() override; void redo() override;
private: private:
const QString id; const MessageId id;
Signal signal = {}; Signal signal = {};
}; };
class EditSignalCommand : public QUndoCommand { class EditSignalCommand : public QUndoCommand {
public: public:
EditSignalCommand(const QString &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent = nullptr); EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent = nullptr);
void undo() override; void undo() override;
void redo() override; void redo() override;
private: private:
const QString id; const MessageId id;
Signal old_signal = {}; Signal old_signal = {};
Signal new_signal = {}; Signal new_signal = {};
}; };

@ -4,6 +4,10 @@
#include <sstream> #include <sstream>
#include <QVector> #include <QVector>
uint qHash(const MessageId &item) {
return qHash(item.source) ^ qHash(item.address);
}
DBCManager::DBCManager(QObject *parent) : QObject(parent) {} DBCManager::DBCManager(QObject *parent) : QObject(parent) {}
DBCManager::~DBCManager() {} DBCManager::~DBCManager() {}
@ -56,29 +60,27 @@ QString DBCManager::generateDBC() {
return dbc_string; return dbc_string;
} }
void DBCManager::updateMsg(const QString &id, const QString &name, uint32_t size) { void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size) {
auto [_, address] = parseId(id); auto &m = msgs[id.address];
auto &m = msgs[address];
m.name = name; m.name = name;
m.size = size; m.size = size;
emit msgUpdated(address); emit msgUpdated(id.address);
} }
void DBCManager::removeMsg(const QString &id) { void DBCManager::removeMsg(const MessageId &id) {
uint32_t address = parseId(id).second; msgs.erase(id.address);
msgs.erase(address); emit msgRemoved(id.address);
emit msgRemoved(address);
} }
void DBCManager::addSignal(const QString &id, const Signal &sig) { void DBCManager::addSignal(const MessageId &id, const Signal &sig) {
if (auto m = const_cast<DBCMsg *>(msg(id))) { if (auto m = const_cast<DBCMsg *>(msg(id.address))) {
auto &s = m->sigs[sig.name.c_str()]; auto &s = m->sigs[sig.name.c_str()];
s = sig; s = sig;
emit signalAdded(parseId(id).second, &s); emit signalAdded(id.address, &s);
} }
} }
void DBCManager::updateSignal(const QString &id, const QString &sig_name, const Signal &sig) { void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig) {
if (auto m = const_cast<DBCMsg *>(msg(id))) { if (auto m = const_cast<DBCMsg *>(msg(id))) {
// change key name // change key name
QString new_name = QString::fromStdString(sig.name); QString new_name = QString::fromStdString(sig.name);
@ -91,7 +93,7 @@ void DBCManager::updateSignal(const QString &id, const QString &sig_name, const
} }
} }
void DBCManager::removeSignal(const QString &id, const QString &sig_name) { void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) {
if (auto m = const_cast<DBCMsg *>(msg(id))) { if (auto m = const_cast<DBCMsg *>(msg(id))) {
auto it = m->sigs.find(sig_name); auto it = m->sigs.find(sig_name);
if (it != m->sigs.end()) { if (it != m->sigs.end()) {
@ -101,12 +103,6 @@ void DBCManager::removeSignal(const QString &id, const QString &sig_name) {
} }
} }
std::pair<uint8_t, uint32_t> DBCManager::parseId(const QString &id) {
const auto list = id.split(':');
if (list.size() != 2) return {0, 0};
return {list[0].toInt(), list[1].toUInt(nullptr, 16)};
}
DBCManager *dbc() { DBCManager *dbc() {
static DBCManager dbc_manager(nullptr); static DBCManager dbc_manager(nullptr);
return &dbc_manager; return &dbc_manager;

@ -5,6 +5,35 @@
#include <QString> #include <QString>
#include "opendbc/can/common_dbc.h" #include "opendbc/can/common_dbc.h"
struct MessageId {
uint8_t source;
uint32_t address;
QString toString() const {
return QString("%1:%2").arg(source).arg(address, 1, 16);
}
bool operator==(const MessageId &other) const {
return source == other.source && address == other.address;
}
bool operator!=(const MessageId &other) const {
return !(*this == other);
}
bool operator<(const MessageId &other) const {
return std::pair{source, address} < std::pair{other.source, other.address};
}
bool operator>(const MessageId &other) const {
return std::pair{source, address} > std::pair{other.source, other.address};
}
};
Q_DECLARE_METATYPE(MessageId);
uint qHash(const MessageId &item);
struct DBCMsg { struct DBCMsg {
QString name; QString name;
uint32_t size; uint32_t size;
@ -24,17 +53,16 @@ public:
void open(const QString &dbc_file_name); void open(const QString &dbc_file_name);
bool open(const QString &name, const QString &content, QString *error = nullptr); bool open(const QString &name, const QString &content, QString *error = nullptr);
QString generateDBC(); QString generateDBC();
void addSignal(const QString &id, const Signal &sig); void addSignal(const MessageId &id, const Signal &sig);
void updateSignal(const QString &id, const QString &sig_name, const Signal &sig); void updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig);
void removeSignal(const QString &id, const QString &sig_name); void removeSignal(const MessageId &id, const QString &sig_name);
static std::pair<uint8_t, uint32_t> parseId(const QString &id);
inline static std::vector<std::string> allDBCNames() { return get_dbc_names(); } inline static std::vector<std::string> allDBCNames() { return get_dbc_names(); }
inline QString name() const { return dbc ? dbc->name.c_str() : ""; } inline QString name() const { return dbc ? dbc->name.c_str() : ""; }
void updateMsg(const QString &id, const QString &name, uint32_t size); void updateMsg(const MessageId &id, const QString &name, uint32_t size);
void removeMsg(const QString &id); void removeMsg(const MessageId &id);
inline const std::map<uint32_t, DBCMsg> &messages() const { return msgs; } inline const std::map<uint32_t, DBCMsg> &messages() const { return msgs; }
inline const DBCMsg *msg(const QString &id) const { return msg(parseId(id).second); } inline const DBCMsg *msg(const MessageId &id) const { return msg(id.address); }
inline const DBCMsg *msg(uint32_t address) const { inline const DBCMsg *msg(uint32_t address) const {
auto it = msgs.find(address); auto it = msgs.find(address);
return it != msgs.end() ? &it->second : nullptr; return it != msgs.end() ? &it->second : nullptr;
@ -65,7 +93,7 @@ int bigEndianBitIndex(int index);
void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size); void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size);
std::pair<int, int> getSignalRange(const Signal *s); std::pair<int, int> getSignalRange(const Signal *s);
DBCManager *dbc(); DBCManager *dbc();
inline QString msgName(const QString &id) { inline QString msgName(const MessageId &id) {
auto msg = dbc()->msg(id); auto msg = dbc()->msg(id);
return msg ? msg->name : UNTITLED; return msg ? msg->name : UNTITLED;
} }

@ -85,11 +85,15 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &DetailWidget::refresh); QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &DetailWidget::refresh);
QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu); QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu);
QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) {
if (index != -1 && tabbar->tabText(index) != msg_id) { if (index != -1) {
setMessage(tabbar->tabText(index)); setMessage(tabbar_ids[index]);
} }
}); });
QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); QObject::connect(tabbar, &QTabBar::tabCloseRequested, [this](int index) {
tabbar_ids.removeAt(index);
tabbar->removeTab(index);
assert(tabbar_ids.size() == tabbar->count());
});
QObject::connect(charts, &ChartsWidget::seriesChanged, signal_view, &SignalView::updateChartState); QObject::connect(charts, &ChartsWidget::seriesChanged, signal_view, &SignalView::updateChartState);
} }
@ -108,29 +112,32 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) {
} }
void DetailWidget::removeAll() { void DetailWidget::removeAll() {
msg_id = ""; msg_id = std::nullopt;
tabbar->blockSignals(true); tabbar->blockSignals(true);
while (tabbar->count() > 0) { while (tabbar->count() > 0) {
tabbar->removeTab(0); tabbar->removeTab(0);
} }
tabbar_ids.clear();
tabbar->blockSignals(false); tabbar->blockSignals(false);
stacked_layout->setCurrentIndex(0); stacked_layout->setCurrentIndex(0);
} }
void DetailWidget::setMessage(const QString &message_id) { void DetailWidget::setMessage(const MessageId &message_id) {
msg_id = message_id; msg_id = message_id;
int index = tabbar->count() - 1; int index = tabbar_ids.indexOf(*msg_id);
for (/**/; index >= 0 && tabbar->tabText(index) != msg_id; --index) { /**/ }
if (index == -1) { if (index == -1) {
index = tabbar->addTab(message_id); tabbar_ids.append(*msg_id);
index = tabbar->addTab(message_id.toString());
tabbar->setTabToolTip(index, msgName(message_id)); tabbar->setTabToolTip(index, msgName(message_id));
} }
assert(tabbar->count() == tabbar_ids.size());
setUpdatesEnabled(false); setUpdatesEnabled(false);
signal_view->setMessage(msg_id); signal_view->setMessage(*msg_id);
binary_view->setMessage(msg_id); binary_view->setMessage(*msg_id);
history_log->setMessage(msg_id); history_log->setMessage(*msg_id);
stacked_layout->setCurrentIndex(1); stacked_layout->setCurrentIndex(1);
tabbar->setCurrentIndex(index); tabbar->setCurrentIndex(index);
@ -141,12 +148,12 @@ void DetailWidget::setMessage(const QString &message_id) {
} }
void DetailWidget::refresh() { void DetailWidget::refresh() {
if (msg_id.isEmpty()) return; if (!msg_id) return;
QStringList warnings; QStringList warnings;
const DBCMsg *msg = dbc()->msg(msg_id); const DBCMsg *msg = dbc()->msg(*msg_id);
if (msg) { if (msg) {
if (msg->size != can->lastMessage(msg_id).dat.size()) { if (msg->size != can->lastMessage(*msg_id).dat.size()) {
warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size));
} }
for (auto s : binary_view->getOverlappingSignals()) { for (auto s : binary_view->getOverlappingSignals()) {
@ -156,7 +163,7 @@ void DetailWidget::refresh() {
warnings.push_back(tr("Drag-Select in binary view to create new signal.")); warnings.push_back(tr("Drag-Select in binary view to create new signal."));
} }
remove_msg_act->setEnabled(msg != nullptr); remove_msg_act->setEnabled(msg != nullptr);
name_label->setText(msgName(msg_id)); name_label->setText(msgName(*msg_id));
if (!warnings.isEmpty()) { if (!warnings.isEmpty()) {
warning_label->setText(warnings.join('\n')); warning_label->setText(warnings.join('\n'));
@ -165,9 +172,9 @@ void DetailWidget::refresh() {
warning_widget->setVisible(!warnings.isEmpty()); warning_widget->setVisible(!warnings.isEmpty());
} }
void DetailWidget::updateState(const QHash<QString, CanData> *msgs) { void DetailWidget::updateState(const QHash<MessageId, CanData> *msgs) {
time_label->setText(QString::number(can->currentSec(), 'f', 3)); time_label->setText(QString::number(can->currentSec(), 'f', 3));
if (msg_id.isEmpty() || (msgs && !msgs->contains(msg_id))) if (!msg_id || (msgs && !msgs->contains(*msg_id)))
return; return;
if (tab_widget->currentIndex() == 0) if (tab_widget->currentIndex() == 0)
@ -177,24 +184,24 @@ void DetailWidget::updateState(const QHash<QString, CanData> *msgs) {
} }
void DetailWidget::editMsg() { void DetailWidget::editMsg() {
QString id = msg_id; MessageId id = *msg_id;
auto msg = dbc()->msg(id); auto msg = dbc()->msg(id);
int size = msg ? msg->size : can->lastMessage(id).dat.size(); int size = msg ? msg->size : can->lastMessage(id).dat.size();
EditMessageDialog dlg(id, msgName(id), size, this); EditMessageDialog dlg(id, msgName(id), size, this);
if (dlg.exec()) { if (dlg.exec()) {
UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text(), dlg.size_spin->value())); UndoStack::push(new EditMsgCommand(*msg_id, dlg.name_edit->text(), dlg.size_spin->value()));
} }
} }
void DetailWidget::removeMsg() { void DetailWidget::removeMsg() {
UndoStack::push(new RemoveMsgCommand(msg_id)); UndoStack::push(new RemoveMsgCommand(*msg_id));
} }
// EditMessageDialog // EditMessageDialog
EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent) EditMessageDialog::EditMessageDialog(const MessageId &msg_id, const QString &title, int size, QWidget *parent)
: original_name(title), QDialog(parent) { : original_name(title), QDialog(parent) {
setWindowTitle(tr("Edit message: %1").arg(msg_id)); setWindowTitle(tr("Edit message: %1").arg(msg_id.toString()));
QFormLayout *form_layout = new QFormLayout(this); QFormLayout *form_layout = new QFormLayout(this);
form_layout->addRow("", error_label = new QLabel); form_layout->addRow("", error_label = new QLabel);

@ -14,7 +14,7 @@
class EditMessageDialog : public QDialog { class EditMessageDialog : public QDialog {
public: public:
EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent); EditMessageDialog(const MessageId &msg_id, const QString &title, int size, QWidget *parent);
void validateName(const QString &text); void validateName(const QString &text);
QString original_name; QString original_name;
@ -34,7 +34,7 @@ class DetailWidget : public QWidget {
public: public:
DetailWidget(ChartsWidget *charts, QWidget *parent); DetailWidget(ChartsWidget *charts, QWidget *parent);
void setMessage(const QString &message_id); void setMessage(const MessageId &message_id);
void refresh(); void refresh();
void removeAll(); void removeAll();
QSize minimumSizeHint() const override { return binary_view->minimumSizeHint(); } QSize minimumSizeHint() const override { return binary_view->minimumSizeHint(); }
@ -43,13 +43,14 @@ private:
void showTabBarContextMenu(const QPoint &pt); void showTabBarContextMenu(const QPoint &pt);
void editMsg(); void editMsg();
void removeMsg(); void removeMsg();
void updateState(const QHash<QString, CanData> * msgs = nullptr); void updateState(const QHash<MessageId, CanData> * msgs = nullptr);
QString msg_id; std::optional<MessageId> msg_id;
QLabel *time_label, *warning_icon, *warning_label; QLabel *time_label, *warning_icon, *warning_label;
ElidedLabel *name_label; ElidedLabel *name_label;
QWidget *warning_widget; QWidget *warning_widget;
QTabBar *tabbar; QTabBar *tabbar;
QList<MessageId> tabbar_ids;
QTabWidget *tab_widget; QTabWidget *tab_widget;
QAction *remove_msg_act; QAction *remove_msg_act;
LogsWidget *history_log; LogsWidget *history_log;

@ -22,14 +22,14 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const {
return {}; return {};
} }
void HistoryLogModel::setMessage(const QString &message_id) { void HistoryLogModel::setMessage(const MessageId &message_id) {
msg_id = message_id; msg_id = message_id;
} }
void HistoryLogModel::refresh() { void HistoryLogModel::refresh() {
beginResetModel(); beginResetModel();
sigs.clear(); sigs.clear();
if (auto dbc_msg = dbc()->msg(msg_id)) { if (auto dbc_msg = dbc()->msg(*msg_id)) {
sigs = dbc_msg->getSignals(); sigs = dbc_msg->getSignals();
} }
last_fetch_time = 0; last_fetch_time = 0;
@ -78,8 +78,8 @@ void HistoryLogModel::setFilter(int sig_idx, const QString &value, std::function
} }
void HistoryLogModel::updateState() { void HistoryLogModel::updateState() {
if (!msg_id.isEmpty()) { if (msg_id) {
uint64_t current_time = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9 + 1; uint64_t current_time = (can->lastMessage(*msg_id).ts + can->routeStartTime()) * 1e9 + 1;
auto new_msgs = dynamic_mode ? fetchData(current_time, last_fetch_time) : fetchData(0); auto new_msgs = dynamic_mode ? fetchData(current_time, last_fetch_time) : fetchData(0);
if (!new_msgs.empty()) { if (!new_msgs.empty()) {
beginInsertRows({}, 0, new_msgs.size() - 1); beginInsertRows({}, 0, new_msgs.size() - 1);
@ -106,12 +106,11 @@ void HistoryLogModel::fetchMore(const QModelIndex &parent) {
template <class InputIt> template <class InputIt>
std::deque<HistoryLogModel::Message> HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) { std::deque<HistoryLogModel::Message> HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) {
std::deque<HistoryLogModel::Message> msgs; std::deque<HistoryLogModel::Message> msgs;
const auto [src, address] = DBCManager::parseId(msg_id);
QVector<double> values(sigs.size()); QVector<double> values(sigs.size());
for (auto it = first; it != last && (*it)->mono_time > min_time; ++it) { for (auto it = first; it != last && (*it)->mono_time > min_time; ++it) {
if ((*it)->which == cereal::Event::Which::CAN) { if ((*it)->which == cereal::Event::Which::CAN) {
for (const auto &c : (*it)->event.getCan()) { for (const auto &c : (*it)->event.getCan()) {
if (address == c.getAddress() && src == c.getSrc()) { if (msg_id->address == c.getAddress() && msg_id->source == c.getSrc()) {
const auto dat = c.getDat(); const auto dat = c.getDat();
for (int i = 0; i < sigs.size(); ++i) { for (int i = 0; i < sigs.size(); ++i) {
values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *(sigs[i])); values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *(sigs[i]));
@ -136,7 +135,7 @@ template std::deque<HistoryLogModel::Message> HistoryLogModel::fetchData<>(std::
std::deque<HistoryLogModel::Message> HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) { std::deque<HistoryLogModel::Message> HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) {
auto events = can->events(); auto events = can->events();
const auto freq = can->lastMessage(msg_id).freq; const auto freq = can->lastMessage(*msg_id).freq;
const bool update_colors = !display_signals_mode || sigs.empty(); const bool update_colors = !display_signals_mode || sigs.empty();
if (dynamic_mode) { if (dynamic_mode) {
@ -241,13 +240,13 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) {
QObject::connect(can, &AbstractStream::eventsMerged, model, &HistoryLogModel::segmentsMerged); QObject::connect(can, &AbstractStream::eventsMerged, model, &HistoryLogModel::segmentsMerged);
} }
void LogsWidget::setMessage(const QString &message_id) { void LogsWidget::setMessage(const MessageId &message_id) {
model->setMessage(message_id); model->setMessage(message_id);
refresh(); refresh();
} }
void LogsWidget::refresh() { void LogsWidget::refresh() {
if (model->msg_id.isEmpty()) return; if (!model->msg_id) return;
model->setFilter(0, "", nullptr); model->setFilter(0, "", nullptr);
model->refresh(); model->refresh();

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <deque> #include <deque>
#include <optional>
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox> #include <QComboBox>
#include <QHeaderView> #include <QHeaderView>
@ -22,7 +24,7 @@ class HistoryLogModel : public QAbstractTableModel {
public: public:
HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) {} HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) {}
void setMessage(const QString &message_id); void setMessage(const MessageId &message_id);
void updateState(); void updateState();
void setFilter(int sig_idx, const QString &value, std::function<bool(double, double)> cmp); void setFilter(int sig_idx, const QString &value, std::function<bool(double, double)> cmp);
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
@ -52,7 +54,7 @@ public:
std::deque<HistoryLogModel::Message> fetchData(InputIt first, InputIt last, uint64_t min_time); std::deque<HistoryLogModel::Message> fetchData(InputIt first, InputIt last, uint64_t min_time);
std::deque<Message> fetchData(uint64_t from_time, uint64_t min_time = 0); std::deque<Message> fetchData(uint64_t from_time, uint64_t min_time = 0);
QString msg_id; std::optional<MessageId> msg_id;
ChangeTracker hex_colors; ChangeTracker hex_colors;
bool has_more_data = true; bool has_more_data = true;
const int batch_size = 50; const int batch_size = 50;
@ -71,7 +73,7 @@ class LogsWidget : public QWidget {
public: public:
LogsWidget(QWidget *parent); LogsWidget(QWidget *parent);
void setMessage(const QString &message_id); void setMessage(const MessageId &message_id);
void updateState() {if (dynamic_mode->isChecked()) model->updateState(); } void updateState() {if (dynamic_mode->isChecked()) model->updateState(); }
void showEvent(QShowEvent *event) override { if (dynamic_mode->isChecked()) model->refresh(); } void showEvent(QShowEvent *event) override { if (dynamic_mode->isChecked()) model->refresh(); }

@ -46,12 +46,12 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) {
QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages);
QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages);
QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages);
QObject::connect(model, &MessageListModel::modelReset, [this]() { selectMessage(current_msg_id); }); QObject::connect(model, &MessageListModel::modelReset, [this]() { selectMessage(*current_msg_id); });
QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex &current, const QModelIndex &previous) { QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex &current, const QModelIndex &previous) {
if (current.isValid() && current.row() < model->msgs.size()) { if (current.isValid() && current.row() < model->msgs.size()) {
if (model->msgs[current.row()] != current_msg_id) { if (model->msgs[current.row()] != *current_msg_id) {
current_msg_id = model->msgs[current.row()]; current_msg_id = model->msgs[current.row()];
emit msgSelectionChanged(current_msg_id); emit msgSelectionChanged(*current_msg_id);
} }
} }
}); });
@ -67,7 +67,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) {
updateSuppressedButtons(); updateSuppressedButtons();
} }
void MessagesWidget::selectMessage(const QString &msg_id) { void MessagesWidget::selectMessage(const MessageId &msg_id) {
if (int row = model->msgs.indexOf(msg_id); row != -1) { if (int row = model->msgs.indexOf(msg_id); row != -1) {
table_widget->selectionModel()->setCurrentIndex(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); table_widget->selectionModel()->setCurrentIndex(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
} }
@ -86,7 +86,7 @@ void MessagesWidget::updateSuppressedButtons() {
void MessagesWidget::reset() { void MessagesWidget::reset() {
model->reset(); model->reset();
filter->clear(); filter->clear();
current_msg_id = ""; current_msg_id = std::nullopt;
updateSuppressedButtons(); updateSuppressedButtons();
} }
@ -106,7 +106,7 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
switch (index.column()) { switch (index.column()) {
case 0: return msgName(id); case 0: return msgName(id);
case 1: return id; case 1: return id.toString(); // TODO: put source and address in separate columns
case 2: return can_data.freq; case 2: return can_data.freq;
case 3: return can_data.count; case 3: return can_data.count;
case 4: return toHex(can_data.dat); case 4: return toHex(can_data.dat);
@ -128,9 +128,9 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const {
} }
void MessageListModel::setFilterString(const QString &string) { void MessageListModel::setFilterString(const QString &string) {
auto contains = [](const QString &id, const QString &txt) { auto contains = [](const MessageId &id, const QString &txt) {
auto cs = Qt::CaseInsensitive; auto cs = Qt::CaseInsensitive;
if (id.contains(txt, cs) || msgName(id).contains(txt, cs)) return true; if (id.toString().contains(txt, cs) || msgName(id).contains(txt, cs)) return true;
// Search by signal name // Search by signal name
if (const auto msg = dbc()->msg(id)) { if (const auto msg = dbc()->msg(id)) {
for (auto &signal : msg->getSignals()) { for (auto &signal : msg->getSignals()) {
@ -160,9 +160,7 @@ void MessageListModel::sortMessages() {
}); });
} else if (sort_column == 1) { } else if (sort_column == 1) {
std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) {
auto ll = DBCManager::parseId(l); return sort_order == Qt::AscendingOrder ? l < r : l > r;
auto rr = DBCManager::parseId(r);
return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr;
}); });
} else if (sort_column == 2) { } else if (sort_column == 2) {
std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) {
@ -180,7 +178,7 @@ void MessageListModel::sortMessages() {
endResetModel(); endResetModel();
} }
void MessageListModel::msgsReceived(const QHash<QString, CanData> *new_msgs) { void MessageListModel::msgsReceived(const QHash<MessageId, CanData> *new_msgs) {
int prev_row_count = msgs.size(); int prev_row_count = msgs.size();
if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) { if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) {
msgs = can->can_msgs.keys(); msgs = can->can_msgs.keys();

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <optional>
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QHeaderView> #include <QHeaderView>
#include <QLineEdit> #include <QLineEdit>
@ -20,13 +22,13 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); }
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
void setFilterString(const QString &string); void setFilterString(const QString &string);
void msgsReceived(const QHash<QString, CanData> *new_msgs = nullptr); void msgsReceived(const QHash<MessageId, CanData> *new_msgs = nullptr);
void sortMessages(); void sortMessages();
void suppress(); void suppress();
void clearSuppress(); void clearSuppress();
void reset(); void reset();
QStringList msgs; QList<MessageId> msgs;
QSet<std::pair<QString, int>> suppressed_bytes; QSet<std::pair<MessageId, int>> suppressed_bytes;
private: private:
QString filter_str; QString filter_str;
@ -39,18 +41,18 @@ class MessagesWidget : public QWidget {
public: public:
MessagesWidget(QWidget *parent); MessagesWidget(QWidget *parent);
void selectMessage(const QString &message_id); void selectMessage(const MessageId &message_id);
QByteArray saveHeaderState() const { return table_widget->horizontalHeader()->saveState(); } QByteArray saveHeaderState() const { return table_widget->horizontalHeader()->saveState(); }
bool restoreHeaderState(const QByteArray &state) const { return table_widget->horizontalHeader()->restoreState(state); } bool restoreHeaderState(const QByteArray &state) const { return table_widget->horizontalHeader()->restoreState(state); }
void updateSuppressedButtons(); void updateSuppressedButtons();
void reset(); void reset();
signals: signals:
void msgSelectionChanged(const QString &message_id); void msgSelectionChanged(const MessageId &message_id);
protected: protected:
QTableView *table_widget; QTableView *table_widget;
QString current_msg_id; std::optional<MessageId> current_msg_id;
QLineEdit *filter; QLineEdit *filter;
MessageListModel *model; MessageListModel *model;
QPushButton *suppress_add; QPushButton *suppress_add;

@ -31,7 +31,7 @@ void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const Sign
} }
} }
void SignalModel::setMessage(const QString &id) { void SignalModel::setMessage(const MessageId &id) {
msg_id = id; msg_id = id;
filter_str = ""; filter_str = "";
refresh(); refresh();
@ -56,7 +56,7 @@ void SignalModel::refresh() {
endResetModel(); endResetModel();
} }
void SignalModel::updateState(const QHash<QString, CanData> *msgs) { void SignalModel::updateState(const QHash<MessageId, CanData> *msgs) {
if (!msgs || (msgs->contains(msg_id))) { if (!msgs || (msgs->contains(msg_id))) {
auto &dat = can->lastMessage(msg_id).dat; auto &dat = can->lastMessage(msg_id).dat;
int row = 0; int row = 0;
@ -230,13 +230,13 @@ void SignalModel::removeSignal(const Signal *sig) {
} }
void SignalModel::handleMsgChanged(uint32_t address) { void SignalModel::handleMsgChanged(uint32_t address) {
if (address == DBCManager::parseId(msg_id).second) { if (address == msg_id.address) {
refresh(); refresh();
} }
} }
void SignalModel::handleSignalAdded(uint32_t address, const Signal *sig) { void SignalModel::handleSignalAdded(uint32_t address, const Signal *sig) {
if (address == DBCManager::parseId(msg_id).second) { if (address == msg_id.address) {
int i = 0; int i = 0;
for (; i < root->children.size(); ++i) { for (; i < root->children.size(); ++i) {
if (sig->start_bit < root->children[i]->sig->start_bit) break; if (sig->start_bit < root->children[i]->sig->start_bit) break;
@ -367,7 +367,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts),
QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { expandSignal(sig); }); QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { expandSignal(sig); });
} }
void SignalView::setMessage(const QString &id) { void SignalView::setMessage(const MessageId &id) {
msg_id = id; msg_id = id;
filter_edit->clear(); filter_edit->clear();
model->setMessage(id); model->setMessage(id);

@ -37,7 +37,7 @@ public:
QModelIndex parent(const QModelIndex &index) const override; QModelIndex parent(const QModelIndex &index) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override; Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
void setMessage(const QString &id); void setMessage(const MessageId &id);
void setFilter(const QString &txt); void setFilter(const QString &txt);
void addSignal(int start_bit, int size, bool little_endian); void addSignal(int start_bit, int size, bool little_endian);
bool saveSignal(const Signal *origin_s, Signal &s); bool saveSignal(const Signal *origin_s, Signal &s);
@ -54,9 +54,9 @@ private:
void handleSignalRemoved(const Signal *sig); void handleSignalRemoved(const Signal *sig);
void handleMsgChanged(uint32_t address); void handleMsgChanged(uint32_t address);
void refresh(); void refresh();
void updateState(const QHash<QString, CanData> *msgs); void updateState(const QHash<MessageId, CanData> *msgs);
QString msg_id; MessageId msg_id;
QString filter_str; QString filter_str;
std::unique_ptr<Item> root; std::unique_ptr<Item> root;
friend class SignalView; friend class SignalView;
@ -76,7 +76,7 @@ class SignalView : public QWidget {
public: public:
SignalView(ChartsWidget *charts, QWidget *parent); SignalView(ChartsWidget *charts, QWidget *parent);
void setMessage(const QString &id); void setMessage(const MessageId &id);
void signalHovered(const Signal *sig); void signalHovered(const Signal *sig);
void updateChartState(); void updateChartState();
void expandSignal(const Signal *sig); void expandSignal(const Signal *sig);
@ -85,13 +85,13 @@ public:
signals: signals:
void highlight(const Signal *sig); void highlight(const Signal *sig);
void showChart(const QString &name, const Signal *sig, bool show, bool merge); void showChart(const MessageId &id, const Signal *sig, bool show, bool merge);
private: private:
void rowsChanged(); void rowsChanged();
void leaveEvent(QEvent *event); void leaveEvent(QEvent *event);
QString msg_id; MessageId msg_id;
QTreeView *tree; QTreeView *tree;
QLineEdit *filter_edit; QLineEdit *filter_edit;
ChartsWidget *charts; ChartsWidget *charts;

@ -4,12 +4,12 @@ AbstractStream *can = nullptr;
AbstractStream::AbstractStream(QObject *parent, bool is_live_streaming) : is_live_streaming(is_live_streaming), QObject(parent) { AbstractStream::AbstractStream(QObject *parent, bool is_live_streaming) : is_live_streaming(is_live_streaming), QObject(parent) {
can = this; can = this;
new_msgs = std::make_unique<QHash<QString, CanData>>(); new_msgs = std::make_unique<QHash<MessageId, CanData>>();
QObject::connect(this, &AbstractStream::received, this, &AbstractStream::process, Qt::QueuedConnection); QObject::connect(this, &AbstractStream::received, this, &AbstractStream::process, Qt::QueuedConnection);
QObject::connect(this, &AbstractStream::seekedTo, this, &AbstractStream::updateLastMsgsTo); QObject::connect(this, &AbstractStream::seekedTo, this, &AbstractStream::updateLastMsgsTo);
} }
void AbstractStream::process(QHash<QString, CanData> *messages) { void AbstractStream::process(QHash<MessageId, CanData> *messages) {
for (auto it = messages->begin(); it != messages->end(); ++it) { for (auto it = messages->begin(); it != messages->end(); ++it) {
can_msgs[it.key()] = it.value(); can_msgs[it.key()] = it.value();
} }
@ -25,7 +25,7 @@ bool AbstractStream::updateEvent(const Event *event) {
if (event->which == cereal::Event::Which::CAN) { if (event->which == cereal::Event::Which::CAN) {
double current_sec = event->mono_time / 1e9 - routeStartTime(); double current_sec = event->mono_time / 1e9 - routeStartTime();
for (const auto &c : event->event.getCan()) { for (const auto &c : event->event.getCan()) {
QString id = QString("%1:%2").arg(c.getSrc()).arg(c.getAddress(), 1, 16); MessageId id = {.source = c.getSrc(), .address = c.getAddress()};
CanData &data = (*new_msgs)[id]; CanData &data = (*new_msgs)[id];
data.ts = current_sec; data.ts = current_sec;
data.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); data.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size());
@ -44,21 +44,21 @@ bool AbstractStream::updateEvent(const Event *event) {
prev_update_ts = ts; prev_update_ts = ts;
// use pointer to avoid data copy in queued connection. // use pointer to avoid data copy in queued connection.
emit received(new_msgs.release()); emit received(new_msgs.release());
new_msgs.reset(new QHash<QString, CanData>); new_msgs.reset(new QHash<MessageId, CanData>);
new_msgs->reserve(100); new_msgs->reserve(100);
} }
} }
return true; return true;
} }
const CanData &AbstractStream::lastMessage(const QString &id) { const CanData &AbstractStream::lastMessage(const MessageId &id) {
static CanData empty_data; static CanData empty_data;
auto it = can_msgs.find(id); auto it = can_msgs.find(id);
return it != can_msgs.end() ? it.value() : empty_data; return it != can_msgs.end() ? it.value() : empty_data;
} }
void AbstractStream::updateLastMsgsTo(double sec) { void AbstractStream::updateLastMsgsTo(double sec) {
QHash<std::pair<uint8_t, uint32_t>, CanData> last_msgs; // Much faster than QHash<String, CanData> QHash<MessageId, CanData> last_msgs;
last_msgs.reserve(can_msgs.size()); last_msgs.reserve(can_msgs.size());
double route_start_time = routeStartTime(); double route_start_time = routeStartTime();
uint64_t last_ts = (sec + route_start_time) * 1e9; uint64_t last_ts = (sec + route_start_time) * 1e9;
@ -66,7 +66,7 @@ void AbstractStream::updateLastMsgsTo(double sec) {
for (auto it = last; it != events()->rend(); ++it) { for (auto it = last; it != events()->rend(); ++it) {
if ((*it)->which == cereal::Event::Which::CAN) { if ((*it)->which == cereal::Event::Which::CAN) {
for (const auto &c : (*it)->event.getCan()) { for (const auto &c : (*it)->event.getCan()) {
auto &m = last_msgs[{c.getSrc(), c.getAddress()}]; auto &m = last_msgs[{.source = c.getSrc(), .address = c.getAddress()}];
if (++m.count == 1) { if (++m.count == 1) {
m.ts = ((*it)->mono_time / 1e9) - route_start_time; m.ts = ((*it)->mono_time / 1e9) - route_start_time;
m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size());
@ -87,9 +87,8 @@ void AbstractStream::updateLastMsgsTo(double sec) {
counters.clear(); counters.clear();
can_msgs.clear(); can_msgs.clear();
for (auto it = last_msgs.cbegin(); it != last_msgs.cend(); ++it) { for (auto it = last_msgs.cbegin(); it != last_msgs.cend(); ++it) {
QString msg_id = QString("%1:%2").arg(it.key().first).arg(it.key().second, 1, 16); can_msgs[it.key()] = it.value();
can_msgs[msg_id] = it.value(); counters[it.key()] = it.value().count;
counters[msg_id] = it.value().count;
} }
emit updated(); emit updated();
emit msgsReceived(&can_msgs); emit msgsReceived(&can_msgs);

@ -5,6 +5,7 @@
#include <QColor> #include <QColor>
#include <QHash> #include <QHash>
#include "tools/cabana/dbcmanager.h"
#include "tools/cabana/settings.h" #include "tools/cabana/settings.h"
#include "tools/cabana/util.h" #include "tools/cabana/util.h"
#include "tools/replay/replay.h" #include "tools/replay/replay.h"
@ -33,7 +34,7 @@ public:
virtual double routeStartTime() const { return 0; } virtual double routeStartTime() const { return 0; }
virtual double currentSec() const = 0; virtual double currentSec() const = 0;
virtual QDateTime currentDateTime() const { return {}; } virtual QDateTime currentDateTime() const { return {}; }
virtual const CanData &lastMessage(const QString &id); virtual const CanData &lastMessage(const MessageId &id);
virtual VisionStreamType visionStreamType() const { return VISION_STREAM_ROAD; } virtual VisionStreamType visionStreamType() const { return VISION_STREAM_ROAD; }
virtual const Route *route() const { return nullptr; } virtual const Route *route() const { return nullptr; }
virtual const std::vector<Event *> *events() const = 0; virtual const std::vector<Event *> *events() const = 0;
@ -49,22 +50,22 @@ signals:
void streamStarted(); void streamStarted();
void eventsMerged(); void eventsMerged();
void updated(); void updated();
void msgsReceived(const QHash<QString, CanData> *); void msgsReceived(const QHash<MessageId, CanData> *);
void received(QHash<QString, CanData> *); void received(QHash<MessageId, CanData> *);
public: public:
QHash<QString, CanData> can_msgs; QHash<MessageId, CanData> can_msgs;
protected: protected:
void process(QHash<QString, CanData> *); void process(QHash<MessageId, CanData> *);
bool updateEvent(const Event *event); bool updateEvent(const Event *event);
void updateLastMsgsTo(double sec); void updateLastMsgsTo(double sec);
bool is_live_streaming = false; bool is_live_streaming = false;
std::atomic<bool> processing = false; std::atomic<bool> processing = false;
QHash<QString, uint32_t> counters; QHash<MessageId, uint32_t> counters;
std::unique_ptr<QHash<QString, CanData>> new_msgs; std::unique_ptr<QHash<MessageId, CanData>> new_msgs;
QHash<QString, ChangeTracker> change_trackers; QHash<MessageId, ChangeTracker> change_trackers;
}; };
// A global pointer referring to the unique AbstractStream object // A global pointer referring to the unique AbstractStream object

@ -20,10 +20,10 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi
bus_combo = new QComboBox(this); bus_combo = new QComboBox(this);
QSet<uint8_t> bus_set; QSet<uint8_t> bus_set;
for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) {
bus_set << DBCManager::parseId(it.key()).first; bus_set << it.key().source;
} }
for (uint8_t bus : bus_set) { for (uint8_t bus : bus_set) {
bus_combo->addItem(QString::number(bus)); bus_combo->addItem(QString::number(bus), bus);
} }
bus_combo->model()->sort(0); bus_combo->model()->sort(0);
bus_combo->setCurrentIndex(0); bus_combo->setCurrentIndex(0);
@ -69,9 +69,11 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi
setMinimumSize({700, 500}); setMinimumSize({700, 500});
QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find); QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find);
QObject::connect(table, &QTableWidget::doubleClicked, [this](const QModelIndex &index) { QObject::connect(table, &QTableWidget::doubleClicked, [this](const QModelIndex &index) {
if (index.isValid()) { if (index.isValid()) {
emit openMessage(bus_combo->currentText() + ":" + table->item(index.row(), 0)->text()); MessageId msg_id = {.source = (uint8_t)bus_combo->currentData().toUInt(), .address = table->item(index.row(), 0)->text().toUInt(0, 16)};
emit openMessage(msg_id);
} }
}); });
} }

@ -6,6 +6,8 @@
#include <QSpinBox> #include <QSpinBox>
#include <QTableWidget> #include <QTableWidget>
#include "tools/cabana/dbcmanager.h"
class FindSimilarBitsDlg : public QDialog { class FindSimilarBitsDlg : public QDialog {
Q_OBJECT Q_OBJECT
@ -13,7 +15,7 @@ public:
FindSimilarBitsDlg(QWidget *parent); FindSimilarBitsDlg(QWidget *parent);
signals: signals:
void openMessage(const QString &msg_id); void openMessage(const MessageId &msg_id);
private: private:
struct mismatched_struct { struct mismatched_struct {

Loading…
Cancel
Save