#include "tools/cabana/tools/findsimilarbits.h" #include #include #include #include #include #include #include #include #include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::WindowFlags() | Qt::Window) { setWindowTitle(tr("Find similar bits")); setAttribute(Qt::WA_DeleteOnClose); QVBoxLayout *main_layout = new QVBoxLayout(this); QHBoxLayout *src_layout = new QHBoxLayout(); src_bus_combo = new QComboBox(this); find_bus_combo = new QComboBox(this); for (auto cb : {src_bus_combo, find_bus_combo}) { for (uint8_t bus : can->sources) { cb->addItem(QString::number(bus), bus); } } msg_cb = new QComboBox(this); // TODO: update when src_bus_combo changes for (auto &[address, msg] : dbc()->getMessages(-1)) { msg_cb->addItem(msg.name, address); } msg_cb->model()->sort(0); msg_cb->setCurrentIndex(0); byte_idx_sb = new QSpinBox(this); byte_idx_sb->setFixedWidth(50); byte_idx_sb->setRange(0, 63); bit_idx_sb = new QSpinBox(this); bit_idx_sb->setFixedWidth(50); bit_idx_sb->setRange(0, 7); src_layout->addWidget(new QLabel(tr("Bus"))); src_layout->addWidget(src_bus_combo); src_layout->addWidget(msg_cb); src_layout->addWidget(new QLabel(tr("Byte Index"))); src_layout->addWidget(byte_idx_sb); src_layout->addWidget(new QLabel(tr("Bit Index"))); src_layout->addWidget(bit_idx_sb); src_layout->addStretch(0); QHBoxLayout *find_layout = new QHBoxLayout(); find_layout->addWidget(new QLabel(tr("Bus"))); find_layout->addWidget(find_bus_combo); find_layout->addWidget(new QLabel(tr("Equal"))); equal_combo = new QComboBox(this); equal_combo->addItems({"Yes", "No"}); find_layout->addWidget(equal_combo); min_msgs = new QLineEdit(this); min_msgs->setValidator(new QIntValidator(this)); min_msgs->setText("100"); find_layout->addWidget(new QLabel(tr("Min msg count"))); find_layout->addWidget(min_msgs); search_btn = new QPushButton(tr("&Find"), this); find_layout->addWidget(search_btn); find_layout->addStretch(0); QGridLayout *grid_layout = new QGridLayout(); grid_layout->addWidget(new QLabel("Find From:"), 0, 0); grid_layout->addLayout(src_layout, 0, 1); grid_layout->addWidget(new QLabel("Find In:"), 1, 0); grid_layout->addLayout(find_layout, 1, 1); main_layout->addLayout(grid_layout); table = new QTableWidget(this); table->setSelectionBehavior(QAbstractItemView::SelectRows); table->setSelectionMode(QAbstractItemView::SingleSelection); table->setEditTriggers(QAbstractItemView::NoEditTriggers); table->horizontalHeader()->setStretchLastSection(true); main_layout->addWidget(table); setMinimumSize({700, 500}); QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find); QObject::connect(table, &QTableWidget::doubleClicked, [this](const QModelIndex &index) { if (index.isValid()) { MessageId msg_id = {.source = (uint8_t)find_bus_combo->currentData().toUInt(), .address = table->item(index.row(), 0)->text().toUInt(0, 16)}; emit openMessage(msg_id); } }); } void FindSimilarBitsDlg::find() { search_btn->setEnabled(false); table->clear(); uint32_t selected_address = msg_cb->currentData().toUInt(); auto msg_mismatched = calcBits(src_bus_combo->currentText().toUInt(), selected_address, byte_idx_sb->value(), bit_idx_sb->value(), find_bus_combo->currentText().toUInt(), equal_combo->currentIndex() == 0, min_msgs->text().toInt()); table->setRowCount(msg_mismatched.size()); table->setColumnCount(6); table->setHorizontalHeaderLabels({"address", "byte idx", "bit idx", "mismatches", "total msgs", "% mismatched"}); 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, 'f', 2))); } search_btn->setEnabled(true); } QList FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, uint8_t find_bus, bool equal, int min_msgs_cnt) { QHash> mismatches; QHash msg_count; const auto &events = can->allEvents(); int bit_to_find = -1; for (const CanEvent *e : events) { if (e->src == bus) { if (e->address == selected_address && e->size > byte_idx) { bit_to_find = ((e->dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; } } if (e->src == find_bus) { ++msg_count[e->address]; if (bit_to_find == -1) continue; auto &mismatched = mismatches[e->address]; if (mismatched.size() < e->size * 8) { mismatched.resize(e->size * 8); } for (int i = 0; i < e->size; ++i) { for (int j = 0; j < 8; ++j) { int bit = ((e->dat[i] >> (7 - j)) & 1) != 0; mismatched[i * 8 + j] += equal ? (bit != bit_to_find) : (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 (float 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; }