From e3c202b4a2d79f6843aa54ec9a1ef81e39da2731 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 2 Feb 2023 22:16:09 +0100 Subject: [PATCH] cabana: add button to suppress highlighted bytes (#27131) --- tools/cabana/historylog.cc | 8 ++-- tools/cabana/historylog.h | 2 +- tools/cabana/messageswidget.cc | 65 ++++++++++++++++++++++++-- tools/cabana/messageswidget.h | 10 +++- tools/cabana/streams/abstractstream.cc | 6 ++- tools/cabana/streams/abstractstream.h | 1 + tools/cabana/util.cc | 7 ++- tools/cabana/util.h | 13 +++--- 8 files changed, 91 insertions(+), 21 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 830390f4a8..ab5c6cbbe0 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -17,7 +17,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { } return show_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); } else if (role == Qt::UserRole && index.column() == 1 && !show_signals) { - return HexColors::toVariantList(m.colors); + return ChangeTracker::toVariantList(m.colors); } return {}; } @@ -142,7 +142,8 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti auto msgs = fetchData(first, events->rend(), min_time); if (update_colors && min_time > 0) { for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { - it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + it->colors = hex_colors.colors; } } return msgs; @@ -152,7 +153,8 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti auto msgs = fetchData(first, events->end(), 0); if (update_colors) { for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { - it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + it->colors = hex_colors.colors; } } return msgs; diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index bc2e0e3914..2458fc1c31 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -53,7 +53,7 @@ public: std::deque fetchData(uint64_t from_time, uint64_t min_time = 0); QString msg_id; - HexColors hex_colors; + ChangeTracker hex_colors; bool has_more_data = true; const int batch_size = 50; int filter_sig_idx = -1; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 9011ce0a4d..64f56ae73f 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -1,10 +1,12 @@ #include "tools/cabana/messageswidget.h" +#include #include +#include #include -#include #include -#include +#include +#include #include "tools/cabana/dbcmanager.h" @@ -28,9 +30,16 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { table_widget->sortByColumn(0, Qt::AscendingOrder); table_widget->horizontalHeader()->setStretchLastSection(true); table_widget->verticalHeader()->hide(); - main_layout->addWidget(table_widget); + // suppress + QHBoxLayout *suppress_layout = new QHBoxLayout(); + suppress_add = new QPushButton("Suppress Highlighted"); + suppress_clear = new QPushButton(); + suppress_layout->addWidget(suppress_add); + suppress_layout->addWidget(suppress_clear); + main_layout->addLayout(suppress_layout); + // signals/slots QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived); @@ -46,6 +55,16 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { } } }); + QObject::connect(suppress_add, &QPushButton::clicked, [=]() { + model->suppress(); + updateSuppressedButtons(); + }); + QObject::connect(suppress_clear, &QPushButton::clicked, [=]() { + model->clearSuppress(); + updateSuppressedButtons(); + }); + + updateSuppressedButtons(); } void MessagesWidget::selectMessage(const QString &msg_id) { @@ -54,6 +73,17 @@ void MessagesWidget::selectMessage(const QString &msg_id) { } } +void MessagesWidget::updateSuppressedButtons() { + if (model->suppressed_bytes.empty()) { + suppress_clear->setEnabled(false); + suppress_clear->setText("Clear Suppressed"); + } else { + suppress_clear->setEnabled(true); + suppress_clear->setText(QString("Clear Suppressed (%1)").arg(model->suppressed_bytes.size())); + } +} + + // MessageListModel QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -75,7 +105,16 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { case 4: return toHex(can_data.dat); } } else if (role == Qt::UserRole && index.column() == 4) { - return HexColors::toVariantList(can_data.colors); + QList colors; + for (int i = 0; i < can_data.dat.size(); i++){ + if (suppressed_bytes.contains({id, i})) { + colors.append(QColor(255, 255, 255, 0)); + } else { + colors.append(can_data.colors[i]); + } + } + return colors; + } return {}; } @@ -157,3 +196,21 @@ void MessageListModel::sort(int column, Qt::SortOrder order) { sortMessages(); } } + +void MessageListModel::suppress() { + const double cur_ts = can->currentSec(); + + for (auto &id : msgs) { + auto &can_data = can->lastMessage(id); + for (int i = 0; i < can_data.dat.size(); i++) { + const double dt = cur_ts - can_data.last_change_t[i]; + if (dt < 2.0) { + suppressed_bytes.insert({id, i}); + } + } + } +} + +void MessageListModel::clearSuppress() { + suppressed_bytes.clear(); +} diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 69fdd26170..1927faa646 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -2,8 +2,9 @@ #include #include -#include +#include #include +#include #include "tools/cabana/streams/abstractstream.h" @@ -20,7 +21,10 @@ public: void setFilterString(const QString &string); void msgsReceived(const QHash *new_msgs = nullptr); void sortMessages(); + void suppress(); + void clearSuppress(); QStringList msgs; + QSet> suppressed_bytes; private: QString filter_str; @@ -36,6 +40,7 @@ public: void selectMessage(const QString &message_id); QByteArray saveHeaderState() const { return table_widget->horizontalHeader()->saveState(); } bool restoreHeaderState(const QByteArray &state) const { return table_widget->horizontalHeader()->restoreState(state); } + void updateSuppressedButtons(); signals: void msgSelectionChanged(const QString &message_id); @@ -44,4 +49,7 @@ protected: QTableView *table_widget; QString current_msg_id; MessageListModel *model; + QPushButton *suppress_add; + QPushButton *suppress_clear; + }; diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index b188c41826..308e5556c6 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -19,7 +19,7 @@ void AbstractStream::process(QHash *messages) { bool AbstractStream::updateEvent(const Event *event) { static std::unique_ptr new_msgs = std::make_unique>(); - static QHash hex_colors; + static QHash change_trackers; static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { @@ -42,7 +42,9 @@ bool AbstractStream::updateEvent(const Event *event) { if (double delta = (current_sec - counters_begin_sec); delta > 0) { data.freq = data.count / delta; } - data.colors = hex_colors[id].compute(data.dat, data.ts, data.freq); + change_trackers[id].compute(data.dat, data.ts, data.freq); + data.colors = change_trackers[id].colors; + data.last_change_t = change_trackers[id].last_change_t; } double ts = millis_since_boot(); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 9a0187da5e..e16e11a14b 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -17,6 +17,7 @@ struct CanData { uint32_t freq = 0; QByteArray dat; QVector colors; + QVector last_change_t; }; class AbstractStream : public QObject { diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 699aa7dc01..f9d19dfda3 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -10,7 +10,7 @@ static QColor blend(QColor a, QColor b) { return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); } -const QVector &HexColors::compute(const QByteArray &dat, double ts, uint32_t freq) { +void ChangeTracker::compute(const QByteArray &dat, double ts, uint32_t freq) { if (prev_dat.size() != dat.size()) { colors.resize(dat.size()); last_change_t.resize(dat.size()); @@ -45,16 +45,15 @@ const QVector &HexColors::compute(const QByteArray &dat, double ts, uint } prev_dat = dat; - return colors; } -void HexColors::clear() { +void ChangeTracker::clear() { prev_dat.clear(); last_change_t.clear(); colors.clear(); } -QList HexColors::toVariantList(const QVector &colors) { +QList ChangeTracker::toVariantList(const QVector &colors) { QList ret; ret.reserve(colors.size()); for (auto &c : colors) ret.append(c); diff --git a/tools/cabana/util.h b/tools/cabana/util.h index a598726bb6..b76652f4b0 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -7,19 +7,20 @@ #include #include -class HexColors { +class ChangeTracker { public: - const QVector &compute(const QByteArray &dat, double ts, uint32_t freq); - static QList toVariantList(const QVector &colors); - void clear(); + void compute(const QByteArray &dat, double ts, uint32_t freq); + static QList toVariantList(const QVector &colors); + void clear(); + + QVector last_change_t; + QVector colors; private: const int periodic_threshold = 10; const int start_alpha = 128; const float fade_time = 2.0; QByteArray prev_dat; - QVector last_change_t; - QVector colors; }; class MessageBytesDelegate : public QStyledItemDelegate {