From 6ccaa89961faac52a04c97c8edb25f62e83ae9aa Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 29 Dec 2022 08:51:02 +0800 Subject: [PATCH] Cabana: add tool to find similar bits (#26834) * find similar bits * set window title old-commit-hash: 65509669b676bad41d57443454dbea8ffbc1c8f7 --- tools/cabana/SConscript | 2 +- tools/cabana/mainwin.cc | 8 ++ tools/cabana/mainwin.h | 2 + tools/cabana/tools/findsimilarbits.cc | 115 ++++++++++++++++++++++++++ tools/cabana/tools/findsimilarbits.h | 23 ++++++ 5 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 tools/cabana/tools/findsimilarbits.cc create mode 100644 tools/cabana/tools/findsimilarbits.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 52fe9e346d..718e2e50af 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -18,7 +18,7 @@ cabana_env = qt_env.Clone() prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', - 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) + 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if GetOption('test'): diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index f14d522c20..4ae53223a8 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -133,6 +133,9 @@ void MainWindow::createActions() { commands_act->setDefaultWidget(undo_view); commands_menu->addAction(commands_act); + QMenu *tools_menu = menuBar()->addMenu(tr("&Tools")); + tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); + QMenu *help_menu = menuBar()->addMenu(tr("&Help")); help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } @@ -283,3 +286,8 @@ void MainWindow::setOption() { SettingsDlg dlg(this); dlg.exec(); } + +void MainWindow::findSimilarBits() { + FindSimilarBitsDlg dlg(this); + dlg.exec(); +} diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 17c513d809..5d3ba470a1 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -11,6 +11,7 @@ #include "tools/cabana/detailwidget.h" #include "tools/cabana/messageswidget.h" #include "tools/cabana/videowidget.h" +#include "tools/cabana/tools/findsimilarbits.h" class MainWindow : public QMainWindow { Q_OBJECT @@ -41,6 +42,7 @@ protected: void DBCFileChanged(); void updateDownloadProgress(uint64_t cur, uint64_t total, bool success); void setOption(); + void findSimilarBits(); VideoWidget *video_widget; MessagesWidget *messages_widget; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc new file mode 100644 index 0000000000..5fa5bcf7b8 --- /dev/null +++ b/tools/cabana/tools/findsimilarbits.cc @@ -0,0 +1,115 @@ +#include "tools/cabana/tools/findsimilarbits.h" + +#include +#include +#include +#include +#include +#include + +#include "tools/cabana/canmessages.h" +#include "tools/cabana/dbcmanager.h" + +FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent) { + setWindowTitle(tr("Find similar bits")); + QVBoxLayout *main_layout = new QVBoxLayout(this); + + QHBoxLayout *form_layout = new QHBoxLayout(); + bus_combo = new QComboBox(this); + QSet bus_set; + for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + bus_set << DBCManager::parseId(it.key()).first; + } + for (uint8_t bus : bus_set) { + bus_combo->addItem(QString::number(bus)); + } + bus_combo->model()->sort(0); + bus_combo->setCurrentIndex(0); + form_layout->addWidget(new QLabel("Bus")); + form_layout->addWidget(bus_combo); + + bit_combo = new QComboBox(this); + bit_combo->addItems({"0", "1"}); + bit_combo->setCurrentIndex(1); + form_layout->addWidget(new QLabel("Bit")); + form_layout->addWidget(bit_combo); + + min_msgs = new QLineEdit(this); + min_msgs->setValidator(new QIntValidator(this)); + min_msgs->setText("100"); + form_layout->addWidget(new QLabel("Min msg count")); + form_layout->addWidget(min_msgs); + search_btn = new QPushButton(tr("&Find"), this); + form_layout->addWidget(search_btn); + form_layout->addStretch(1); + main_layout->addLayout(form_layout); + + table = new QTableWidget(this); + table->setEditTriggers(QAbstractItemView::NoEditTriggers); + table->horizontalHeader()->setStretchLastSection(true); + main_layout->addWidget(table); + + setMinimumSize({700, 500}); + QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find); +} + +void FindSimilarBitsDlg::find() { + search_btn->setEnabled(false); + table->clear(); + auto msg_mismatched = calcBits(bus_combo->currentText().toUInt(), bit_combo->currentIndex(), min_msgs->text().toInt()); + table->setRowCount(msg_mismatched.size()); + table->setColumnCount(6); + table->setHorizontalHeaderLabels({"address", "byte idx", "bit idx", "mismatches", "total", "perc%"}); + for (int i = 0; i < msg_mismatched.size(); ++i) { + auto &m = msg_mismatched[i]; + table->setItem(i, 0, new QTableWidgetItem(QString("%1").arg(m.address, 1, 16))); + table->setItem(i, 1, new QTableWidgetItem(QString::number(m.byte_idx))); + table->setItem(i, 2, new QTableWidgetItem(QString::number(m.bit_idx))); + table->setItem(i, 3, new QTableWidgetItem(QString::number(m.mismatches))); + table->setItem(i, 4, new QTableWidgetItem(QString::number(m.total))); + table->setItem(i, 5, new QTableWidgetItem(QString::number(m.perc))); + } + search_btn->setEnabled(true); +} + +QList FindSimilarBitsDlg::calcBits(uint8_t bus, int bit_to_find, int min_msgs_cnt) { + QHash> mismatches; + QHash msg_count; + auto events = can->events(); + for (auto e : *events) { + if (e->which == cereal::Event::Which::CAN) { + for (const auto &c : e->event.getCan()) { + if (c.getSrc() == bus) { + uint32_t address = c.getAddress(); + ++msg_count[address]; + auto &mismatched = mismatches[address]; + const auto dat = c.getDat(); + if (mismatched.size() < dat.size() * 8) { + mismatched.resize(dat.size() * 8); + } + for (int i = 0; i < dat.size(); ++i) { + for (int j = 0; j < 8; ++j) { + int bit = ((dat[i] >> (7 - j)) & 1) != 0; + mismatched[i * 8 + j] += (bit != bit_to_find); + } + } + } + } + } + } + + QList result; + result.reserve(mismatches.size()); + for (auto it = mismatches.begin(); it != mismatches.end(); ++it) { + if (auto cnt = msg_count[it.key()]; cnt > min_msgs_cnt) { + auto &mismatched = it.value(); + for (int i = 0; i < mismatched.size(); ++i) { + if (uint32_t perc = (mismatched[i] / (double)cnt) * 100; perc < 50) { + result.push_back({it.key(), (uint32_t)i / 8, (uint32_t)i % 8, mismatched[i], cnt, perc}); + } + } + } + } + std::sort(result.begin(), result.end(), [](auto &l, auto &r) { return l.perc > r.perc; }); + return result; +} diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h new file mode 100644 index 0000000000..79db4a1c69 --- /dev/null +++ b/tools/cabana/tools/findsimilarbits.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include + +class FindSimilarBitsDlg : public QDialog { +public: + FindSimilarBitsDlg(QWidget *parent); + +private: + struct mismatched_struct { + uint32_t address, byte_idx, bit_idx, mismatches, total, perc; + }; + QList calcBits(uint8_t bus, int bit_to_find, int min_msgs_cnt); + void find(); + + QTableWidget *table; + QComboBox *bus_combo, *bit_combo; + QPushButton *search_btn; + QLineEdit *min_msgs; +};