openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
5.2 KiB

#include "tools/cabana/tools/findsimilarbits.h"
#include <QHeaderView>
#include <QHBoxLayout>
#include <QIntValidator>
#include <QLabel>
#include <QPushButton>
#include <QRadioButton>
#include "tools/cabana/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 *form_layout = new QHBoxLayout();
bus_combo = new QComboBox(this);
QSet<uint8_t> 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);
}
bus_combo->model()->sort(0);
bus_combo->setCurrentIndex(0);
msg_cb = new QComboBox(this);
// TODO: update when bus_combo changes
for (auto &[id, msg] : dbc()->getMessages(0)) {
msg_cb->addItem(msg.name, id.address);
}
msg_cb->model()->sort(0);
msg_cb->setCurrentIndex(0);
byte_idx_sb = new QSpinBox(this);
byte_idx_sb->setRange(0, 63);
bit_idx_sb = new QSpinBox(this);
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);
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->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)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(bus_combo->currentText().toUInt(), selected_address, byte_idx_sb->value(), bit_idx_sb->value(), 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)));
}
search_btn->setEnabled(true);
}
QList<FindSimilarBitsDlg::mismatched_struct> FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt) {
QHash<uint32_t, QVector<uint32_t>> mismatches;
QHash<uint32_t, uint32_t> msg_count;
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;
}
++msg_count[id.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);
}
}
}
}
}
QList<mismatched_struct> 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;
}