diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index befbf270c6..b7cfd9dc2a 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -133,8 +133,10 @@ 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); + if (!can->liveStreaming()) { + 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("Help"), this, &MainWindow::onlineHelp)->setShortcuts(QKeySequence::HelpContents); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 3c7bdd6132..8e19f69d2a 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -50,6 +50,7 @@ public: virtual void setSpeed(float speed) {} virtual bool isPaused() const { return false; } virtual void pause(bool pause) {} + virtual const std::vector *rawEvents() const { return nullptr; } const std::unordered_map> &events() const { return events_; } virtual const std::vector> getTimeline() { return {}; } void mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last, bool append); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 6fc61f7f36..10dc804716 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -23,6 +23,7 @@ public: inline void setSpeed(float speed) override { replay->setSpeed(speed); } inline bool isPaused() const override { return replay->isPaused(); } void pause(bool pause) override; + const std::vector *rawEvents() const override { return replay->events(); } inline const std::vector> getTimeline() override { return replay->getTimeline(); } private: diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index ffd0df0501..a44ac76059 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -1,5 +1,6 @@ #include "tools/cabana/tools/findsimilarbits.h" +#include #include #include #include @@ -16,20 +17,23 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi QVBoxLayout *main_layout = new QVBoxLayout(this); - QHBoxLayout *form_layout = new QHBoxLayout(); - bus_combo = new QComboBox(this); + QHBoxLayout *src_layout = new QHBoxLayout(); + src_bus_combo = new QComboBox(this); + find_bus_combo = new QComboBox(this); QSet bus_set; for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { bus_set << it.key().source; } - for (uint8_t bus : bus_set) { - bus_combo->addItem(QString::number(bus), bus); + for (auto cb : {src_bus_combo, find_bus_combo}) { + for (uint8_t bus : bus_set) { + cb->addItem(QString::number(bus), bus); + } + cb->model()->sort(0); + cb->setCurrentIndex(0); } - bus_combo->model()->sort(0); - bus_combo->setCurrentIndex(0); msg_cb = new QComboBox(this); - // TODO: update when bus_combo changes + // TODO: update when src_bus_combo changes for (auto &[id, msg] : dbc()->getMessages(0)) { msg_cb->addItem(msg.name, id.address); } @@ -37,29 +41,44 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi 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); - form_layout->addWidget(new QLabel("Bus")); - form_layout->addWidget(bus_combo); - form_layout->addWidget(msg_cb); - form_layout->addWidget(new QLabel("Byte Index")); - form_layout->addWidget(byte_idx_sb); - form_layout->addWidget(new QLabel("Bit Index")); - form_layout->addWidget(bit_idx_sb); - - + 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"); - form_layout->addWidget(new QLabel("Min msg count")); - form_layout->addWidget(min_msgs); + find_layout->addWidget(new QLabel(tr("Min msg count"))); + find_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); + 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); @@ -70,10 +89,9 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi 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)bus_combo->currentData().toUInt(), .address = table->item(index.row(), 0)->text().toUInt(0, 16)}; + 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); } }); @@ -83,7 +101,8 @@ void FindSimilarBitsDlg::find() { search_btn->setEnabled(false); table->clear(); uint32_t selected_address = msg_cb->currentData().toUInt(); - auto msg_mismatched = calcBits(bus_combo->currentText().toUInt(), selected_address, byte_idx_sb->value(), bit_idx_sb->value(), min_msgs->text().toInt()); + 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"}); @@ -94,32 +113,41 @@ void FindSimilarBitsDlg::find() { 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))); + 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, int min_msgs_cnt) { +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; + auto events = can->rawEvents(); int bit_to_find = -1; - for (const auto &[id, msg] : can->events()) { - if (id.source == bus) { - for (const auto &c : msg) { - if (id.address == selected_address && c.size > byte_idx) { - bit_to_find = ((c.dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + for (auto e : *events) { + if (e->which == cereal::Event::Which::CAN) { + for (const auto &c : e->event.getCan()) { + uint8_t src = c.getSrc(); + uint32_t address = c.getAddress(); + const auto dat = c.getDat(); + if (src == bus) { + if (address == selected_address && dat.size() > byte_idx) { + bit_to_find = ((dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + } } - ++msg_count[id.address]; - if (bit_to_find == -1) continue; + if (src == find_bus) { + ++msg_count[address]; + if (bit_to_find == -1) continue; - auto &mismatched = mismatches[id.address]; - if (mismatched.size() < c.size * 8) { - mismatched.resize(c.size * 8); - } - for (int i = 0; i < c.size; ++i) { - for (int j = 0; j < 8; ++j) { - int bit = ((c.dat[i] >> (7 - j)) & 1) != 0; - mismatched[i * 8 + j] += (bit != bit_to_find); + auto &mismatched = mismatches[address]; + 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] += equal ? (bit != bit_to_find) : (bit == bit_to_find); + } } } } diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index 53d7806a8f..a40e2cd8df 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -22,11 +22,12 @@ private: uint32_t address, byte_idx, bit_idx, mismatches, total; float perc; }; - QList calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt); + QList calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, uint8_t find_bus, + bool equal, int min_msgs_cnt); void find(); QTableWidget *table; - QComboBox *bus_combo, *msg_cb; + QComboBox *src_bus_combo, *find_bus_combo, *msg_cb, *equal_combo; QSpinBox *byte_idx_sb, *bit_idx_sb; QPushButton *search_btn; QLineEdit *min_msgs;