cabana: add button to suppress highlighted bytes (#27131)

pull/27193/head
Willem Melching 2 years ago committed by GitHub
parent 9ece098098
commit e3c202b4a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      tools/cabana/historylog.cc
  2. 2
      tools/cabana/historylog.h
  3. 65
      tools/cabana/messageswidget.cc
  4. 10
      tools/cabana/messageswidget.h
  5. 6
      tools/cabana/streams/abstractstream.cc
  6. 1
      tools/cabana/streams/abstractstream.h
  7. 7
      tools/cabana/util.cc
  8. 13
      tools/cabana/util.h

@ -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); return show_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data);
} else if (role == Qt::UserRole && index.column() == 1 && !show_signals) { } else if (role == Qt::UserRole && index.column() == 1 && !show_signals) {
return HexColors::toVariantList(m.colors); return ChangeTracker::toVariantList(m.colors);
} }
return {}; return {};
} }
@ -142,7 +142,8 @@ std::deque<HistoryLogModel::Message> HistoryLogModel::fetchData(uint64_t from_ti
auto msgs = fetchData(first, events->rend(), min_time); auto msgs = fetchData(first, events->rend(), min_time);
if (update_colors && min_time > 0) { if (update_colors && min_time > 0) {
for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { 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; return msgs;
@ -152,7 +153,8 @@ std::deque<HistoryLogModel::Message> HistoryLogModel::fetchData(uint64_t from_ti
auto msgs = fetchData(first, events->end(), 0); auto msgs = fetchData(first, events->end(), 0);
if (update_colors) { if (update_colors) {
for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { 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; return msgs;

@ -53,7 +53,7 @@ public:
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; QString msg_id;
HexColors 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;
int filter_sig_idx = -1; int filter_sig_idx = -1;

@ -1,10 +1,12 @@
#include "tools/cabana/messageswidget.h" #include "tools/cabana/messageswidget.h"
#include <QApplication>
#include <QFontDatabase> #include <QFontDatabase>
#include <QHBoxLayout>
#include <QLineEdit> #include <QLineEdit>
#include <QVBoxLayout>
#include <QPainter> #include <QPainter>
#include <QApplication> #include <QPushButton>
#include <QVBoxLayout>
#include "tools/cabana/dbcmanager.h" #include "tools/cabana/dbcmanager.h"
@ -28,9 +30,16 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) {
table_widget->sortByColumn(0, Qt::AscendingOrder); table_widget->sortByColumn(0, Qt::AscendingOrder);
table_widget->horizontalHeader()->setStretchLastSection(true); table_widget->horizontalHeader()->setStretchLastSection(true);
table_widget->verticalHeader()->hide(); table_widget->verticalHeader()->hide();
main_layout->addWidget(table_widget); 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 // signals/slots
QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString);
QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived); 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) { 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 // MessageListModel
QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { 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); case 4: return toHex(can_data.dat);
} }
} else if (role == Qt::UserRole && index.column() == 4) { } else if (role == Qt::UserRole && index.column() == 4) {
return HexColors::toVariantList(can_data.colors); QList<QVariant> 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 {}; return {};
} }
@ -157,3 +196,21 @@ void MessageListModel::sort(int column, Qt::SortOrder order) {
sortMessages(); 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();
}

@ -2,8 +2,9 @@
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QHeaderView> #include <QHeaderView>
#include <QTableView> #include <QSet>
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QTableView>
#include "tools/cabana/streams/abstractstream.h" #include "tools/cabana/streams/abstractstream.h"
@ -20,7 +21,10 @@ public:
void setFilterString(const QString &string); void setFilterString(const QString &string);
void msgsReceived(const QHash<QString, CanData> *new_msgs = nullptr); void msgsReceived(const QHash<QString, CanData> *new_msgs = nullptr);
void sortMessages(); void sortMessages();
void suppress();
void clearSuppress();
QStringList msgs; QStringList msgs;
QSet<std::pair<QString, int>> suppressed_bytes;
private: private:
QString filter_str; QString filter_str;
@ -36,6 +40,7 @@ public:
void selectMessage(const QString &message_id); void selectMessage(const QString &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();
signals: signals:
void msgSelectionChanged(const QString &message_id); void msgSelectionChanged(const QString &message_id);
@ -44,4 +49,7 @@ protected:
QTableView *table_widget; QTableView *table_widget;
QString current_msg_id; QString current_msg_id;
MessageListModel *model; MessageListModel *model;
QPushButton *suppress_add;
QPushButton *suppress_clear;
}; };

@ -19,7 +19,7 @@ void AbstractStream::process(QHash<QString, CanData> *messages) {
bool AbstractStream::updateEvent(const Event *event) { bool AbstractStream::updateEvent(const Event *event) {
static std::unique_ptr new_msgs = std::make_unique<QHash<QString, CanData>>(); static std::unique_ptr new_msgs = std::make_unique<QHash<QString, CanData>>();
static QHash<QString, HexColors> hex_colors; static QHash<QString, ChangeTracker> change_trackers;
static double prev_update_ts = 0; static double prev_update_ts = 0;
if (event->which == cereal::Event::Which::CAN) { 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) { if (double delta = (current_sec - counters_begin_sec); delta > 0) {
data.freq = data.count / delta; 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(); double ts = millis_since_boot();

@ -17,6 +17,7 @@ struct CanData {
uint32_t freq = 0; uint32_t freq = 0;
QByteArray dat; QByteArray dat;
QVector<QColor> colors; QVector<QColor> colors;
QVector<double> last_change_t;
}; };
class AbstractStream : public QObject { class AbstractStream : public QObject {

@ -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); return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2);
} }
const QVector<QColor> &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()) { if (prev_dat.size() != dat.size()) {
colors.resize(dat.size()); colors.resize(dat.size());
last_change_t.resize(dat.size()); last_change_t.resize(dat.size());
@ -45,16 +45,15 @@ const QVector<QColor> &HexColors::compute(const QByteArray &dat, double ts, uint
} }
prev_dat = dat; prev_dat = dat;
return colors;
} }
void HexColors::clear() { void ChangeTracker::clear() {
prev_dat.clear(); prev_dat.clear();
last_change_t.clear(); last_change_t.clear();
colors.clear(); colors.clear();
} }
QList<QVariant> HexColors::toVariantList(const QVector<QColor> &colors) { QList<QVariant> ChangeTracker::toVariantList(const QVector<QColor> &colors) {
QList<QVariant> ret; QList<QVariant> ret;
ret.reserve(colors.size()); ret.reserve(colors.size());
for (auto &c : colors) ret.append(c); for (auto &c : colors) ret.append(c);

@ -7,19 +7,20 @@
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QVector> #include <QVector>
class HexColors { class ChangeTracker {
public: public:
const QVector<QColor> &compute(const QByteArray &dat, double ts, uint32_t freq); void compute(const QByteArray &dat, double ts, uint32_t freq);
static QList<QVariant> toVariantList(const QVector<QColor> &colors); static QList<QVariant> toVariantList(const QVector<QColor> &colors);
void clear(); void clear();
QVector<double> last_change_t;
QVector<QColor> colors;
private: private:
const int periodic_threshold = 10; const int periodic_threshold = 10;
const int start_alpha = 128; const int start_alpha = 128;
const float fade_time = 2.0; const float fade_time = 2.0;
QByteArray prev_dat; QByteArray prev_dat;
QVector<double> last_change_t;
QVector<QColor> colors;
}; };
class MessageBytesDelegate : public QStyledItemDelegate { class MessageBytesDelegate : public QStyledItemDelegate {

Loading…
Cancel
Save