From bf5a6565c0f2d6791606ff906f6ddb4cba27fb18 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 15 Oct 2022 16:05:52 -0700 Subject: [PATCH 01/34] cabana: misc touchups (#26092) * fix time formatting * disable vertical resize * Update tools/cabana/videowidget.cc --- tools/cabana/detailwidget.cc | 2 +- tools/cabana/videowidget.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 531cd4c665..4127b6c3ed 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -1,4 +1,3 @@ - #include "tools/cabana/detailwidget.h" #include @@ -138,6 +137,7 @@ BinaryView::BinaryView(QWidget *parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); table = new QTableWidget(this); + table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); table->horizontalHeader()->hide(); table->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 193a6f8788..9e2129afaf 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -11,7 +11,7 @@ #include inline QString formatTime(int seconds) { - return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh::mm::ss" : "mm::ss"); + return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { From b654ebdd25bb3903e94ca5cc6f55d53a256f5c06 Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Sat, 15 Oct 2022 20:04:35 -0700 Subject: [PATCH 02/34] Refactor model: no klblock (#26035) * ff138dc0-d097-4818-b40e-dba5ba89d5d6/449 13274b7d-b546-4b91-a587-33b4af7dec6a/700 * b1bb39be-c6ce-4744-8e63-92969fda6bfc/449 f3ebfba1-f686-448f-be9b-b4d5010be91c/700 * model ref Co-authored-by: Yassine Yousfi --- selfdrive/modeld/models/supercombo.onnx | 4 ++-- selfdrive/test/process_replay/model_replay_ref_commit | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index aee0ac37ff..59b8883d2a 100644 --- a/selfdrive/modeld/models/supercombo.onnx +++ b/selfdrive/modeld/models/supercombo.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c4d37af666344af6bb218e0b939b1152ad3784c15ac79e37bcf0124643c8286a -size 58539563 +oid sha256:022a830c39267f378f45204682060c93e3aa304bbd8cfa6b2dfe4fa8f419102d +size 56972617 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 2446ec061d..b3e9c8c488 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -c171250d2cc013b3eca1cda4fb62f3d0dda28d4d +bfb0a2a52212d2aa1619d999aaae97fa7f7ff788 From e25ea8529698053f4c1b915b7e014ebdc499e56a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 16 Oct 2022 22:55:53 +0800 Subject: [PATCH 03/34] Cabana: complete edit functions (#26097) complete forms --- tools/cabana/chartswidget.cc | 105 ++++++++-------- tools/cabana/chartswidget.h | 25 ++-- tools/cabana/dbcmanager.cc | 22 ++-- tools/cabana/dbcmanager.h | 7 +- tools/cabana/detailwidget.cc | 215 ++++++++++++++++++--------------- tools/cabana/detailwidget.h | 42 +++---- tools/cabana/historylog.cc | 5 +- tools/cabana/messageswidget.cc | 20 +-- tools/cabana/signaledit.cc | 74 +++++------- tools/cabana/signaledit.h | 29 ++--- 10 files changed, 260 insertions(+), 284 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 5dafd8ec37..d0f5356fac 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -1,7 +1,6 @@ #include "tools/cabana/chartswidget.h" #include -#include #include #include #include @@ -14,6 +13,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { // title bar title_bar = new QWidget(this); + title_bar->setVisible(false); QHBoxLayout *title_layout = new QHBoxLayout(title_bar); title_layout->setContentsMargins(0, 0, 0, 0); title_label = new QLabel(tr("Charts")); @@ -25,13 +25,11 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { title_layout->addWidget(range_label); reset_zoom_btn = new QPushButton("⟲", this); - reset_zoom_btn->setVisible(false); reset_zoom_btn->setFixedSize(30, 30); reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)")); title_layout->addWidget(reset_zoom_btn); remove_all_btn = new QPushButton("✖", this); - remove_all_btn->setVisible(false); remove_all_btn->setToolTip(tr("Remove all charts")); remove_all_btn->setFixedSize(30, 30); title_layout->addWidget(remove_all_btn); @@ -56,10 +54,20 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(charts_scroll); - updateTitleBar(); - - QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartsWidget::removeChart); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); + QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartsWidget::removeChart); + QObject::connect(dbc(), &DBCManager::signalUpdated, [this](const Signal *sig) { + if (auto it = charts.find(sig); it != charts.end()) { + it.value()->chart_view->updateSeries(); + } + }); + QObject::connect(dbc(), &DBCManager::msgUpdated, [this](const QString &id) { + for (auto chart : charts) { + if (chart->id == id) + chart->updateTitle(); + } + }); + QObject::connect(can, &CANMessages::rangeChanged, [this]() { updateTitleBar(); }); QObject::connect(reset_zoom_btn, &QPushButton::clicked, can, &CANMessages::resetRange); QObject::connect(remove_all_btn, &QPushButton::clicked, this, &ChartsWidget::removeAll); @@ -71,54 +79,43 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { } void ChartsWidget::updateTitleBar() { - if (!charts.size()) { - title_bar->setVisible(false); - return; - } - - title_label->setText(tr("Charts (%1)").arg(charts.size())); + title_bar->setVisible(!charts.isEmpty()); + if (charts.isEmpty()) return; // show select range + range_label->setVisible(can->isZoomed()); + reset_zoom_btn->setEnabled(can->isZoomed()); if (can->isZoomed()) { auto [min, max] = can->range(); range_label->setText(tr("%1 - %2").arg(min, 0, 'f', 2).arg(max, 0, 'f', 2)); - range_label->setVisible(true); - reset_zoom_btn->setEnabled(true); - } else { - reset_zoom_btn->setEnabled(false); - range_label->setVisible(false); } + title_label->setText(tr("Charts (%1)").arg(charts.size())); dock_btn->setText(docking ? "⬈" : "⬋"); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); - remove_all_btn->setVisible(!charts.empty()); - reset_zoom_btn->setVisible(!charts.empty()); - title_bar->setVisible(true); } -void ChartsWidget::addChart(const QString &id, const QString &sig_name) { - const QString char_name = id + ":" + sig_name; - if (charts.find(char_name) == charts.end()) { - auto chart = new ChartWidget(id, sig_name, this); - QObject::connect(chart, &ChartWidget::remove, [=]() { - removeChart(id, sig_name); - }); +void ChartsWidget::addChart(const QString &id, const Signal *sig) { + if (!charts.contains(sig)) { + auto chart = new ChartWidget(id, sig, this); + QObject::connect(chart, &ChartWidget::remove, [=]() { removeChart(sig); }); charts_layout->insertWidget(0, chart); - charts[char_name] = chart; + charts.insert(sig, chart); } updateTitleBar(); } -void ChartsWidget::removeChart(const QString &id, const QString &sig_name) { - if (auto it = charts.find(id + ":" + sig_name); it != charts.end()) { - it->second->deleteLater(); - charts.erase(it); +void ChartsWidget::removeChart(const Signal *sig) { + auto it = charts.find(sig); + if (it != charts.end()) { + it.value()->deleteLater(); + charts.remove(sig); } updateTitleBar(); } void ChartsWidget::removeAll() { - for (auto [_, chart] : charts) + for (auto chart : charts) chart->deleteLater(); charts.clear(); updateTitleBar(); @@ -134,19 +131,16 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { // ChartWidget -ChartWidget::ChartWidget(const QString &id, const QString &sig_name, QWidget *parent) : id(id), sig_name(sig_name), QWidget(parent) { +ChartWidget::ChartWidget(const QString &id, const Signal *sig, QWidget *parent) : id(id), signal(sig), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); - - QWidget *chart_widget = new QWidget(this); - QVBoxLayout *chart_layout = new QVBoxLayout(chart_widget); - chart_layout->setSpacing(0); - chart_layout->setContentsMargins(0, 0, 0, 0); + main_layout->setSpacing(0); + main_layout->setContentsMargins(0, 0, 0, 0); QWidget *header = new QWidget(this); header->setStyleSheet("background-color:white"); QHBoxLayout *header_layout = new QHBoxLayout(header); header_layout->setContentsMargins(11, 11, 11, 0); - QLabel *title = new QLabel(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); + title = new QLabel(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); header_layout->addWidget(title); header_layout->addStretch(); @@ -155,26 +149,28 @@ ChartWidget::ChartWidget(const QString &id, const QString &sig_name, QWidget *pa remove_btn->setToolTip(tr("Remove chart")); QObject::connect(remove_btn, &QPushButton::clicked, this, &ChartWidget::remove); header_layout->addWidget(remove_btn); - chart_layout->addWidget(header); + main_layout->addWidget(header); - chart_view = new ChartView(id, sig_name, this); + chart_view = new ChartView(id, sig, this); chart_view->setFixedHeight(300); - chart_layout->addWidget(chart_view); - chart_layout->addStretch(); - - main_layout->addWidget(chart_widget); + main_layout->addWidget(chart_view); + main_layout->addStretch(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); } +void ChartWidget::updateTitle() { + title->setText(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); +} + // ChartView -ChartView::ChartView(const QString &id, const QString &sig_name, QWidget *parent) - : id(id), sig_name(sig_name), QChartView(nullptr, parent) { +ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) + : id(id), signal(sig), QChartView(nullptr, parent) { QLineSeries *series = new QLineSeries(); series->setUseOpenGL(true); QChart *chart = new QChart(); - chart->setTitle(sig_name); + chart->setTitle(sig->name.c_str()); chart->addSeries(series); chart->createDefaultAxes(); chart->legend()->hide(); @@ -205,10 +201,7 @@ ChartView::ChartView(const QString &id, const QString &sig_name, QWidget *parent QObject::connect(can, &CANMessages::rangeChanged, this, &ChartView::rangeChanged); QObject::connect(can, &CANMessages::eventsMerged, this, &ChartView::updateSeries); QObject::connect(dynamic_cast(chart->axisX()), &QValueAxis::rangeChanged, can, &CANMessages::setRange); - QObject::connect(dbc(), &DBCManager::signalUpdated, [this](const QString &msg_id, const QString &sig_name) { - if (this->id == msg_id && this->sig_name == sig_name) - updateSeries(); - }); + updateSeries(); } @@ -219,9 +212,9 @@ void ChartView::updateState() { } void ChartView::updateSeries() { - const Signal *sig = dbc()->signal(id, sig_name); + chart()->setTitle(signal->name.c_str()); auto events = can->events(); - if (!sig || !events) return; + if (!events) return; auto l = id.split(':'); int bus = l[0].toInt(); @@ -235,7 +228,7 @@ void ChartView::updateSeries() { for (auto c : evt->event.getCan()) { if (bus == c.getSrc() && address == c.getAddress()) { auto dat = c.getDat(); - double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *sig); + double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *signal); double ts = (evt->mono_time / (double)1e9) - route_start_time; // seconds vals.push_back({ts, value}); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index af12560cc9..a3c470e960 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -9,7 +9,6 @@ #include #include #include -#include #include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" @@ -20,7 +19,8 @@ class ChartView : public QChartView { Q_OBJECT public: - ChartView(const QString &id, const QString &sig_name, QWidget *parent = nullptr); + ChartView(const QString &id, const Signal *sig, QWidget *parent = nullptr); + void updateSeries(); private: void mouseReleaseEvent(QMouseEvent *event) override; @@ -28,7 +28,6 @@ private: void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; - void updateSeries(); void rangeChanged(qreal min, qreal max); void updateAxisY(); void updateState(); @@ -38,22 +37,23 @@ private: QGraphicsLineItem *line_marker; QList vals; QString id; - QString sig_name; + const Signal *signal; }; class ChartWidget : public QWidget { Q_OBJECT public: - ChartWidget(const QString &id, const QString &sig_name, QWidget *parent); - inline QChart *chart() const { return chart_view->chart(); } + ChartWidget(const QString &id, const Signal *sig, QWidget *parent); + void updateTitle(); signals: void remove(); -protected: +public: QString id; - QString sig_name; + const Signal *signal; + QLabel *title; ChartView *chart_view = nullptr; }; @@ -62,11 +62,8 @@ class ChartsWidget : public QWidget { public: ChartsWidget(QWidget *parent = nullptr); - void addChart(const QString &id, const QString &sig_name); - void removeChart(const QString &id, const QString &sig_name); - inline bool hasChart(const QString &id, const QString &sig_name) { - return charts.find(id + sig_name) != charts.end(); - } + void addChart(const QString &id, const Signal *sig); + void removeChart(const Signal *sig); signals: void dock(bool floating); @@ -85,5 +82,5 @@ private: QPushButton *reset_zoom_btn; QPushButton *remove_all_btn; QVBoxLayout *charts_layout; - std::map charts; + QHash charts; }; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 1cb6da7fb5..5b1bddcabe 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -36,14 +36,17 @@ void DBCManager::updateMsg(const QString &id, const QString &name, uint32_t size void DBCManager::addSignal(const QString &id, const Signal &sig) { if (Msg *m = const_cast(msg(id))) { m->sigs.push_back(sig); - emit signalAdded(id, QString::fromStdString(sig.name)); + emit signalAdded(&m->sigs.back()); } } void DBCManager::updateSignal(const QString &id, const QString &sig_name, const Signal &sig) { - if (Signal *s = const_cast(signal(id, sig_name))) { - *s = sig; - emit signalUpdated(id, sig_name); + if (Msg *m = const_cast(msg(id))) { + auto it = std::find_if(m->sigs.begin(), m->sigs.end(), [=](auto &sig) { return sig_name == sig.name.c_str(); }); + if (it != m->sigs.end()) { + *it = sig; + emit signalUpdated(&(*it)); + } } } @@ -51,21 +54,12 @@ void DBCManager::removeSignal(const QString &id, const QString &sig_name) { if (Msg *m = const_cast(msg(id))) { auto it = std::find_if(m->sigs.begin(), m->sigs.end(), [=](auto &sig) { return sig_name == sig.name.c_str(); }); if (it != m->sigs.end()) { + emit signalRemoved(&(*it)); m->sigs.erase(it); - emit signalRemoved(id, sig_name); } } } -const Signal *DBCManager::signal(const QString &id, const QString &sig_name) const { - if (auto m = msg(id)) { - auto it = std::find_if(m->sigs.begin(), m->sigs.end(), [&](auto &s) { return sig_name == s.name.c_str(); }); - if (it != m->sigs.end()) - return &(*it); - } - return nullptr; -} - uint32_t DBCManager::addressFromId(const QString &id) { return id.mid(id.indexOf(':') + 1).toUInt(nullptr, 16); } diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 06c071be82..1f890a39db 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -14,7 +14,6 @@ public: void open(const QString &dbc_file_name); void save(const QString &dbc_file_name); - const Signal *signal(const QString &id, const QString &sig_name) const; void addSignal(const QString &id, const Signal &sig); void updateSignal(const QString &id, const QString &sig_name, const Signal &sig); void removeSignal(const QString &id, const QString &sig_name); @@ -31,9 +30,9 @@ public: } signals: - void signalAdded(const QString &id, const QString &sig_name); - void signalRemoved(const QString &id, const QString &sig_name); - void signalUpdated(const QString &id, const QString &sig_name); + void signalAdded(const Signal *sig); + void signalRemoved(const Signal *sig); + void signalUpdated(const Signal *sig); void msgUpdated(const QString &id); void DBCFileChanged(); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 4127b6c3ed..021e1b73cf 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -3,9 +3,9 @@ #include #include #include +#include #include #include -#include // DetailWidget @@ -32,60 +32,52 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { binary_view = new BinaryView(this); main_layout->addWidget(binary_view, 0, Qt::AlignTop); - // signal header - signals_header = new QWidget(this); - QHBoxLayout *signals_header_layout = new QHBoxLayout(signals_header); - signals_header_layout->addWidget(new QLabel(tr("Signals"))); - signals_header_layout->addStretch(); - QPushButton *add_sig_btn = new QPushButton(tr("Add signal"), this); - signals_header_layout->addWidget(add_sig_btn); - signals_header->setVisible(false); - main_layout->addWidget(signals_header); - - // scroll area + // signals + signals_container = new QWidget(this); + signals_container->setLayout(new QVBoxLayout); + signals_container->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + scroll = new ScrollArea(this); - QWidget *container = new QWidget(this); - container->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); - QVBoxLayout *container_layout = new QVBoxLayout(container); - signal_edit_layout = new QVBoxLayout(); - signal_edit_layout->setSpacing(2); - container_layout->addLayout(signal_edit_layout); - - scroll->setWidget(container); + scroll->setWidget(signals_container); scroll->setWidgetResizable(true); scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); main_layout->addWidget(scroll); + // history log history_log = new HistoryLog(this); main_layout->addWidget(history_log); - QObject::connect(add_sig_btn, &QPushButton::clicked, this, &DetailWidget::addSignal); QObject::connect(edit_btn, &QPushButton::clicked, this, &DetailWidget::editMsg); + QObject::connect(binary_view, &BinaryView::cellsSelected, this, &DetailWidget::addSignal); QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &DetailWidget::dbcMsgChanged); } void DetailWidget::setMessage(const QString &message_id) { - msg_id = message_id; - for (auto f : signal_forms) { - f->deleteLater(); + if (msg_id != message_id) { + msg_id = message_id; + dbcMsgChanged(); } - signal_forms.clear(); +} + +void DetailWidget::dbcMsgChanged() { + if (msg_id.isEmpty()) return; + qDeleteAll(signals_container->findChildren()); + QString msg_name = tr("untitled"); if (auto msg = dbc()->msg(msg_id)) { for (int i = 0; i < msg->sigs.size(); ++i) { - auto form = new SignalEdit(i, msg_id, msg->sigs[i], getColor(i)); - signal_edit_layout->addWidget(form); - QObject::connect(form, &SignalEdit::showChart, this, &DetailWidget::showChart); + auto form = new SignalEdit(i, msg_id, msg->sigs[i]); + signals_container->layout()->addWidget(form); + QObject::connect(form, &SignalEdit::showChart, [this, sig = &msg->sigs[i]]() { emit showChart(msg_id, sig); }); QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showForm); - signal_forms.push_back(form); + QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); + QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); } - name_label->setText(msg->name.c_str()); - signals_header->setVisible(true); - } else { - name_label->setText(tr("untitled")); - signals_header->setVisible(false); + msg_name = msg->name.c_str(); } edit_btn->setVisible(true); + name_label->setText(msg_name); binary_view->setMessage(msg_id); history_log->setMessage(msg_id); @@ -99,60 +91,90 @@ void DetailWidget::updateState() { history_log->updateState(); } -void DetailWidget::editMsg() { - EditMessageDialog dlg(msg_id, this); - if (dlg.exec()) { - setMessage(msg_id); +void DetailWidget::showForm() { + SignalEdit *sender = qobject_cast(QObject::sender()); + for (auto f : signals_container->findChildren()) { + f->setFormVisible(f == sender && !f->isFormVisible()); + if (f == sender) { + QTimer::singleShot(0, [=]() { scroll->ensureWidgetVisible(f); }); + } } } -void DetailWidget::addSignal() { - AddSignalDialog dlg(msg_id, this); +void DetailWidget::editMsg() { + auto msg = dbc()->msg(msg_id); + QString name = msg ? msg->name.c_str() : "untitled"; + int size = msg ? msg->size : can->lastMessage(msg_id).dat.size(); + EditMessageDialog dlg(msg_id, name, size, this); if (dlg.exec()) { - setMessage(msg_id); + dbc()->updateMsg(msg_id, dlg.name_edit->text(), dlg.size_spin->value()); + dbcMsgChanged(); } } -void DetailWidget::showForm() { - SignalEdit *sender = qobject_cast(QObject::sender()); - if (sender->isFormVisible()) { - sender->setFormVisible(false); - } else { - for (auto f : signal_forms) { - f->setFormVisible(f == sender); - if (f == sender) { - // scroll to header - QTimer::singleShot(0, [=]() { - const QPoint p = f->mapTo(scroll, QPoint(0, 0)); - scroll->verticalScrollBar()->setValue(p.y() + scroll->verticalScrollBar()->value()); - }); - } +void DetailWidget::addSignal(int start_bit, int size) { + if (dbc()->msg(msg_id)) { + AddSignalDialog dlg(msg_id, start_bit, size, this); + if (dlg.exec()) { + dbc()->addSignal(msg_id, dlg.form->getSignal()); + dbcMsgChanged(); } } } +void DetailWidget::saveSignal() { + SignalEdit *sig_form = qobject_cast(QObject::sender()); + auto s = sig_form->form->getSignal(); + dbc()->updateSignal(msg_id, sig_form->sig_name, s); + // update binary view and history log + binary_view->setMessage(msg_id); + history_log->setMessage(msg_id); +} + +void DetailWidget::removeSignal() { + SignalEdit *sig_form = qobject_cast(QObject::sender()); + QString text = tr("Are you sure you want to remove signal '%1'").arg(sig_form->sig_name); + if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove signal"), text)) { + dbc()->removeSignal(msg_id, sig_form->sig_name); + dbcMsgChanged(); + } +} + // BinaryView -BinaryView::BinaryView(QWidget *parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); - table = new QTableWidget(this); - table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); - table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); - table->horizontalHeader()->hide(); - table->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - main_layout->addWidget(table); - table->setColumnCount(9); +BinaryView::BinaryView(QWidget *parent) : QTableWidget(parent) { + horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); + horizontalHeader()->hide(); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setColumnCount(9); + + // replace selection model + auto old_model = selectionModel(); + setSelectionModel(new BinarySelectionModel(model())); + delete old_model; +} + +void BinaryView::mouseReleaseEvent(QMouseEvent *event) { + QTableWidget::mouseReleaseEvent(event); + + if (auto items = selectedItems(); !items.isEmpty()) { + int start_bit = items.first()->row() * 8 + items.first()->column(); + int size = items.back()->row() * 8 + items.back()->column() - start_bit + 1; + emit cellsSelected(start_bit, size); + } } void BinaryView::setMessage(const QString &message_id) { msg_id = message_id; + if (msg_id.isEmpty()) return; + const Msg *msg = dbc()->msg(msg_id); - const int row_count = msg ? msg->size : can->lastMessage(msg_id).dat.size(); - table->setRowCount(row_count); - table->setColumnCount(9); - for (int i = 0; i < table->rowCount(); ++i) { - for (int j = 0; j < table->columnCount(); ++j) { + int row_count = msg ? msg->size : can->lastMessage(msg_id).dat.size(); + setRowCount(row_count); + setColumnCount(9); + for (int i = 0; i < rowCount(); ++i) { + for (int j = 0; j < columnCount(); ++j) { auto item = new QTableWidgetItem(); item->setFlags(item->flags() ^ Qt::ItemIsEditable); item->setTextAlignment(Qt::AlignCenter); @@ -160,8 +182,9 @@ void BinaryView::setMessage(const QString &message_id) { QFont font; font.setBold(true); item->setFont(font); + item->setFlags(item->flags() ^ Qt::ItemIsSelectable); } - table->setItem(i, j, item); + setItem(i, j, item); } } @@ -170,71 +193,73 @@ void BinaryView::setMessage(const QString &message_id) { for (int i = 0; i < msg->sigs.size(); ++i) { const auto &sig = msg->sigs[i]; int start = sig.is_little_endian ? sig.start_bit : bigEndianBitIndex(sig.start_bit); - for (int j = start; j <= start + sig.size - 1; ++j) { - table->item(j / 8, j % 8)->setBackground(QColor(getColor(i))); + for (int j = start; j <= std::min(start + sig.size - 1, rowCount() * columnCount() - 1); ++j) { + item(j / 8, j % 8)->setBackground(QColor(getColor(i))); } } } - table->setFixedHeight(table->rowHeight(0) * std::min(row_count, 8) + 2); + + setFixedHeight(rowHeight(0) * std::min(row_count, 8) + 2); + clearSelection(); updateState(); } void BinaryView::updateState() { - if (msg_id.isEmpty()) return; - const auto &binary = can->lastMessage(msg_id).dat; - setUpdatesEnabled(false); char hex[3] = {'\0'}; for (int i = 0; i < binary.size(); ++i) { for (int j = 0; j < 8; ++j) { - table->item(i, j)->setText(QChar((binary[i] >> (7 - j)) & 1 ? '1' : '0')); + item(i, j)->setText(QChar((binary[i] >> (7 - j)) & 1 ? '1' : '0')); } hex[0] = toHex(binary[i] >> 4); hex[1] = toHex(binary[i] & 0xf); - table->item(i, 8)->setText(hex); + item(i, 8)->setText(hex); } setUpdatesEnabled(true); } +void BinarySelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) { + QItemSelection new_selection = selection; + if (auto indexes = selection.indexes(); !indexes.isEmpty()) { + auto [begin_idx, end_idx] = (QModelIndex[]){indexes.first(), indexes.back()}; + for (int row = begin_idx.row(); row <= end_idx.row(); ++row) { + int left_col = (row == begin_idx.row()) ? begin_idx.column() : 0; + int right_col = (row == end_idx.row()) ? end_idx.column() : 7; + new_selection.merge({model()->index(row, left_col), model()->index(row, right_col)}, command); + } + } + QItemSelectionModel::select(new_selection, command); +} + // EditMessageDialog -EditMessageDialog::EditMessageDialog(const QString &msg_id, QWidget *parent) : msg_id(msg_id), QDialog(parent) { +EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Edit message")); QVBoxLayout *main_layout = new QVBoxLayout(this); QFormLayout *form_layout = new QFormLayout(); form_layout->addRow("ID", new QLabel(msg_id)); - const auto msg = dbc()->msg(msg_id); - name_edit = new QLineEdit(this); - name_edit->setText(msg ? msg->name.c_str() : "untitled"); + name_edit = new QLineEdit(title, this); form_layout->addRow(tr("Name"), name_edit); size_spin = new QSpinBox(this); - size_spin->setValue(msg ? msg->size : can->lastMessage(msg_id).dat.size()); + // TODO: limit the maximum? + size_spin->setMinimum(1); + size_spin->setValue(size); form_layout->addRow(tr("Size"), size_spin); main_layout->addLayout(form_layout); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); main_layout->addWidget(buttonBox); - setFixedWidth(parent->width() * 0.9); - connect(buttonBox, &QDialogButtonBox::accepted, this, &EditMessageDialog::save); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } -void EditMessageDialog::save() { - const QString name = name_edit->text(); - if (size_spin->value() <= 0 || name_edit->text().isEmpty() || name == tr("untitled")) - return; - - dbc()->updateMsg(msg_id, name, size_spin->value()); - QDialog::accept(); -} - // ScrollArea bool ScrollArea::eventFilter(QObject *obj, QEvent *ev) { diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 99fe321012..db174873f7 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -1,12 +1,7 @@ #pragma once -#include -#include -#include #include #include -#include -#include #include "opendbc/can/common.h" #include "opendbc/can/common_dbc.h" @@ -15,29 +10,32 @@ #include "tools/cabana/historylog.h" #include "tools/cabana/signaledit.h" -class BinaryView : public QWidget { - Q_OBJECT +class BinarySelectionModel : public QItemSelectionModel { +public: + BinarySelectionModel(QAbstractItemModel *model = nullptr) : QItemSelectionModel(model) {} + void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override; +}; +class BinaryView : public QTableWidget { + Q_OBJECT public: - BinaryView(QWidget *parent); + BinaryView(QWidget *parent = nullptr); + void mouseReleaseEvent(QMouseEvent *event) override; void setMessage(const QString &message_id); void updateState(); +signals: + void cellsSelected(int start_bit, int size); private: QString msg_id; - QTableWidget *table; }; class EditMessageDialog : public QDialog { Q_OBJECT public: - EditMessageDialog(const QString &msg_id, QWidget *parent); + EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent); -protected: - void save(); - - QString msg_id; QLineEdit *name_edit; QSpinBox *size_spin; }; @@ -57,24 +55,24 @@ class DetailWidget : public QWidget { public: DetailWidget(QWidget *parent); void setMessage(const QString &message_id); + void dbcMsgChanged(); signals: - void showChart(const QString &msg_id, const QString &sig_name); - -private slots: - void showForm(); + void showChart(const QString &msg_id, const Signal *sig); + void removeChart(const Signal *sig); private: - void addSignal(); + void addSignal(int start_bit, int size); + void saveSignal(); + void removeSignal(); void editMsg(); + void showForm(); void updateState(); QString msg_id; QLabel *name_label, *time_label; QPushButton *edit_btn; - QVBoxLayout *signal_edit_layout; - QWidget *signals_header; - QList signal_forms; + QWidget *signals_container; HistoryLog *history_log; BinaryView *binary_view; ScrollArea *scroll; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 494e281cb1..5a77b5aa9e 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -52,9 +52,8 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i void HistoryLogModel::updateState() { if (msg_id.isEmpty()) return; - const auto &can_msgs = can->messages(msg_id); int prev_row_count = row_count; - row_count = can_msgs.size(); + row_count = can->messages(msg_id).size(); int delta = row_count - prev_row_count; if (delta > 0) { beginInsertRows({}, prev_row_count, row_count - 1); @@ -64,7 +63,7 @@ void HistoryLogModel::updateState() { endRemoveRows(); } if (row_count > 0) { - emit dataChanged(index(0, 0), index(row_count - 1, column_count - 1)); + emit dataChanged(index(0, 0), index(row_count - 1, column_count - 1), {Qt::DisplayRole}); emit headerDataChanged(Qt::Vertical, 0, row_count - 1); } } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index eaf84fbace..f10cbf44b4 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -68,7 +68,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { }); QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { if (current.isValid()) { - emit msgSelectionChanged(table_widget->model()->data(current, Qt::UserRole).toString()); + emit msgSelectionChanged(current.data(Qt::UserRole).toString()); } }); @@ -78,11 +78,8 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { void MessagesWidget::dbcSelectionChanged(const QString &dbc_file) { dbc()->open(dbc_file); - // update detailwidget - auto current = table_widget->selectionModel()->currentIndex(); - if (current.isValid()) { - emit msgSelectionChanged(table_widget->model()->data(current, Qt::UserRole).toString()); - } + // TODO: reset model? + table_widget->sortByColumn(0, Qt::AscendingOrder); } // MessageListModel @@ -90,9 +87,6 @@ void MessagesWidget::dbcSelectionChanged(const QString &dbc_file) { QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) return (QString[]){"Name", "ID", "Count", "Bytes"}[section]; - else if (orientation == Qt::Vertical && role == Qt::DisplayRole) { - // return QString::number(section); - } return {}; } @@ -100,17 +94,15 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { auto it = std::next(can->can_msgs.begin(), index.row()); if (it != can->can_msgs.end() && !it.value().empty()) { - const auto &d = it.value().front(); const QString &msg_id = it.key(); switch (index.column()) { case 0: { auto msg = dbc()->msg(msg_id); - QString name = msg ? msg->name.c_str() : "untitled"; - return name; + return msg ? msg->name.c_str() : "untitled"; } case 1: return msg_id; case 2: return can->counters[msg_id]; - case 3: return toHex(d.dat); + case 3: return toHex(it.value().front().dat); } } } else if (role == Qt::UserRole) { @@ -132,6 +124,6 @@ void MessageListModel::updateState() { } if (row_count > 0) { - emit dataChanged(index(0, 0), index(row_count - 1, 3)); + emit dataChanged(index(0, 0), index(row_count - 1, 3), {Qt::DisplayRole}); } } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 3f48450195..2da3e2eec2 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -3,7 +3,6 @@ #include #include #include -#include #include // SignalForm @@ -15,13 +14,10 @@ SignalForm::SignalForm(const Signal &sig, QWidget *parent) : start_bit(sig.start form_layout->addRow(tr("Name"), name); size = new QSpinBox(); + size->setMinimum(1); size->setValue(sig.size); form_layout->addRow(tr("Size"), size); - msb = new QSpinBox(); - msb->setValue(sig.msb); - form_layout->addRow(tr("Most significant bit"), msb); - endianness = new QComboBox(); endianness->addItems({"Little", "Big"}); endianness->setCurrentIndex(sig.is_little_endian ? 0 : 1); @@ -56,7 +52,8 @@ SignalForm::SignalForm(const Signal &sig, QWidget *parent) : start_bit(sig.start form_layout->addRow(tr("Value descriptions"), val_desc); } -std::optional SignalForm::getSignal() { +Signal SignalForm::getSignal() { + // TODO: Check if the size is valid, and no duplicate name Signal sig = {}; sig.start_bit = start_bit; sig.name = name->text().toStdString(); @@ -72,17 +69,17 @@ std::optional SignalForm::getSignal() { sig.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(sig.start_bit) + sig.size - 1); sig.msb = sig.start_bit; } - return (sig.name.empty() || sig.size <= 0) ? std::nullopt : std::optional(sig); + return sig; } // SignalEdit -SignalEdit::SignalEdit(int index, const QString &id, const Signal &sig, const QString &color, QWidget *parent) - : id(id), name_(sig.name.c_str()), QWidget(parent) { +SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWidget *parent) + : sig_name(sig.name.c_str()), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); - // title + // title bar QHBoxLayout *title_layout = new QHBoxLayout(); icon = new QLabel(">"); icon->setFixedSize(15, 30); @@ -90,24 +87,25 @@ SignalEdit::SignalEdit(int index, const QString &id, const Signal &sig, const QS title_layout->addWidget(icon); title = new ElidedLabel(this); title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); - title->setText(QString("%1. %2").arg(index + 1).arg(sig.name.c_str())); - title->setStyleSheet(QString("font-weight:bold; color:%1").arg(color)); + title->setText(QString("%1. %2").arg(index + 1).arg(sig_name)); + title->setStyleSheet(QString("font-weight:bold; color:%1").arg(getColor(index))); title_layout->addWidget(title); - plot_btn = new QPushButton("📈"); + QPushButton *plot_btn = new QPushButton("📈"); plot_btn->setToolTip(tr("Show Plot")); plot_btn->setFixedSize(30, 30); - QObject::connect(plot_btn, &QPushButton::clicked, [=]() { emit showChart(id, name_); }); + QObject::connect(plot_btn, &QPushButton::clicked, this, &SignalEdit::showChart); title_layout->addWidget(plot_btn); main_layout->addLayout(title_layout); + // signal form form_container = new QWidget(this); QVBoxLayout *v_layout = new QVBoxLayout(form_container); form = new SignalForm(sig, this); v_layout->addWidget(form); QHBoxLayout *h = new QHBoxLayout(); - remove_btn = new QPushButton(tr("Remove Signal")); + QPushButton *remove_btn = new QPushButton(tr("Remove Signal")); h->addWidget(remove_btn); h->addStretch(); QPushButton *save_btn = new QPushButton(tr("Save")); @@ -117,13 +115,19 @@ SignalEdit::SignalEdit(int index, const QString &id, const Signal &sig, const QS form_container->setVisible(false); main_layout->addWidget(form_container); - QFrame* hline = new QFrame(); + // bottom line + QFrame *hline = new QFrame(); hline->setFrameShape(QFrame::HLine); hline->setFrameShadow(QFrame::Sunken); main_layout->addWidget(hline); QObject::connect(remove_btn, &QPushButton::clicked, this, &SignalEdit::remove); - QObject::connect(save_btn, &QPushButton::clicked, this, &SignalEdit::save); + QObject::connect(save_btn, &QPushButton::clicked, [=]() { + QString new_name = form->getSignal().name.c_str(); + title->setText(QString("%1. %2").arg(index + 1).arg(new_name)); + emit save(); + sig_name = new_name; + }); QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); } @@ -132,40 +136,24 @@ void SignalEdit::setFormVisible(bool visible) { icon->setText(visible ? "▼" : ">"); } -void SignalEdit::save() { - if (auto s = form->getSignal()) - dbc()->updateSignal(id, name_, *s); -} - -void SignalEdit::remove() { - QMessageBox msgbox; - msgbox.setText(tr("Remove signal")); - msgbox.setInformativeText(tr("Are you sure you want to remove signal '%1'").arg(name_)); - msgbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - msgbox.setDefaultButton(QMessageBox::Cancel); - if (msgbox.exec()) { - dbc()->removeSignal(id, name_); - deleteLater(); - } -} - // AddSignalDialog -AddSignalDialog::AddSignalDialog(const QString &id, QWidget *parent) : QDialog(parent) { +AddSignalDialog::AddSignalDialog(const QString &id, int start_bit, int size, QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Add signal to %1").arg(dbc()->msg(id)->name.c_str())); QVBoxLayout *main_layout = new QVBoxLayout(this); - Signal sig = {.name = "untitled"}; - auto form = new SignalForm(sig, this); + + Signal sig = { + .name = "untitled", + .start_bit = bigEndianBitIndex(start_bit), + .is_little_endian = false, + .size = size, + }; + form = new SignalForm(sig, this); main_layout->addWidget(form); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); main_layout->addWidget(buttonBox); setFixedWidth(parent->width() * 0.9); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(buttonBox, &QDialogButtonBox::accepted, [=]() { - if (auto signal = form->getSignal()) { - dbc()->addSignal(id, *signal); - } - QDialog::accept(); - }); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); } diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 00c13948b7..f31408657f 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -1,7 +1,5 @@ #pragma once -#include - #include #include #include @@ -15,14 +13,12 @@ #include "tools/cabana/dbcmanager.h" class SignalForm : public QWidget { - Q_OBJECT - public: SignalForm(const Signal &sig, QWidget *parent); - std::optional getSignal(); + Signal getSignal(); QLineEdit *name, *unit, *comment, *val_desc; - QSpinBox *size, *msb, *lsb, *offset; + QSpinBox *size, *offset; QDoubleSpinBox *factor, *min_val, *max_val; QComboBox *sign, *endianness; int start_bit = 0; @@ -32,31 +28,26 @@ class SignalEdit : public QWidget { Q_OBJECT public: - SignalEdit(int index, const QString &id, const Signal &sig, const QString &color, QWidget *parent = nullptr); + SignalEdit(int index, const QString &msg_id, const Signal &sig, QWidget *parent = nullptr); void setFormVisible(bool show); inline bool isFormVisible() const { return form_container->isVisible(); } - void save(); + QString sig_name; + SignalForm *form; signals: - void showChart(const QString &msg_id, const QString &sig_name); + void showChart(); void showFormClicked(); - -protected: void remove(); + void save(); - QString id; - QString name_; - QPushButton *plot_btn; +protected: ElidedLabel *title; - SignalForm *form; QWidget *form_container; - QPushButton *remove_btn; QLabel *icon; }; class AddSignalDialog : public QDialog { - Q_OBJECT - public: - AddSignalDialog(const QString &id, QWidget *parent); + AddSignalDialog(const QString &id, int start_bit, int size, QWidget *parent); + SignalForm *form; }; From e3268d88c5226afaf5a300a775b8989bcff18b20 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 16 Oct 2022 23:24:34 +0800 Subject: [PATCH 04/34] cabana: use monospace font for hex string (#26102) specify monospace font for hex string --- tools/cabana/detailwidget.cc | 3 ++- tools/cabana/historylog.cc | 7 ++++++- tools/cabana/messageswidget.cc | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 021e1b73cf..a9899ec650 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -1,6 +1,7 @@ #include "tools/cabana/detailwidget.h" #include +#include #include #include #include @@ -179,7 +180,7 @@ void BinaryView::setMessage(const QString &message_id) { item->setFlags(item->flags() ^ Qt::ItemIsEditable); item->setTextAlignment(Qt::AlignCenter); if (j == 8) { - QFont font; + QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); font.setBold(true); item->setFont(font); item->setFlags(item->flags() ^ Qt::ItemIsSelectable); diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 5a77b5aa9e..cbb3b6e882 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -1,20 +1,25 @@ #include "tools/cabana/historylog.h" +#include #include #include QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { + auto msg = dbc()->msg(msg_id); if (role == Qt::DisplayRole) { const auto &can_msgs = can->messages(msg_id); if (index.row() < can_msgs.size()) { const auto &can_data = can_msgs[index.row()]; - auto msg = dbc()->msg(msg_id); if (msg && index.column() < msg->sigs.size()) { return get_raw_value((uint8_t *)can_data.dat.begin(), can_data.dat.size(), msg->sigs[index.column()]); } else { return toHex(can_data.dat); } } + } else if (role == Qt::FontRole) { + if (index.column() == 0 && !(msg && msg->sigs.size() > 0)) { + return QFontDatabase::systemFont(QFontDatabase::FixedFont); + } } return {}; } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index f10cbf44b4..3c9af67ea6 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -107,6 +108,10 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } } else if (role == Qt::UserRole) { return std::next(can->can_msgs.begin(), index.row()).key(); + } else if (role == Qt::FontRole) { + if (index.column() == 3) { + return QFontDatabase::systemFont(QFontDatabase::FixedFont); + } } return {}; } From d4f9343a2c1f5345dec07a93b25594b588cd9963 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 17 Oct 2022 03:30:23 +0800 Subject: [PATCH 05/34] Cabana: load from high quality video by default (#26100) --- tools/cabana/cabana.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 88b175663f..1096487973 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -14,6 +14,7 @@ int main(int argc, char *argv[]) { cmd_parser.addHelpOption(); cmd_parser.addPositionalArgument("route", "the drive to replay. find your drives at connect.comma.ai"); cmd_parser.addOption({"demo", "use a demo route instead of providing your own"}); + cmd_parser.addOption({"qcam", "load qcamera"}); cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"}); cmd_parser.process(app); const QStringList args = cmd_parser.positionalArguments(); @@ -23,7 +24,7 @@ int main(int argc, char *argv[]) { const QString route = args.empty() ? DEMO_ROUTE : args.first(); CANMessages p(&app); - if (!p.loadRoute(route, cmd_parser.value("data_dir"), true)) { + if (!p.loadRoute(route, cmd_parser.value("data_dir"), cmd_parser.isSet("qcam"))) { return 0; } MainWindow w; From d109dda720b502a94f914c1a29ffdea6d01fbc6f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 17 Oct 2022 03:31:26 +0800 Subject: [PATCH 06/34] Cabana: click on video to play/pause (#26099) --- tools/cabana/videowidget.cc | 19 ++++++++++--------- tools/cabana/videowidget.h | 3 +++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 9e2129afaf..b6fe8de3e2 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -39,9 +38,9 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { // btn controls QHBoxLayout *control_layout = new QHBoxLayout(); - QPushButton *play = new QPushButton("⏸"); - play->setStyleSheet("font-weight:bold"); - control_layout->addWidget(play); + play_btn = new QPushButton("⏸"); + play_btn->setStyleSheet("font-weight:bold"); + control_layout->addWidget(play_btn); QButtonGroup *group = new QButtonGroup(this); group->setExclusive(true); @@ -61,11 +60,13 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->value() / 1000.0); }); QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(formatTime(value / 1000)); }); - QObject::connect(play, &QPushButton::clicked, [=]() { - bool is_paused = can->isPaused(); - play->setText(is_paused ? "⏸" : "▶"); - can->pause(!is_paused); - }); + QObject::connect(cam_widget, &CameraViewWidget::clicked, [this]() { pause(!can->isPaused()); }); + QObject::connect(play_btn, &QPushButton::clicked, [=]() { pause(!can->isPaused()); }); +} + +void VideoWidget::pause(bool pause) { + play_btn->setText(!pause ? "⏸" : "▶"); + can->pause(pause); } void VideoWidget::rangeChanged(double min, double max) { diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index e80e3b48f9..fd896f1e11 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -29,8 +30,10 @@ public: protected: void rangeChanged(double min, double max); void updateState(); + void pause(bool pause); CameraViewWidget *cam_widget; QLabel *end_time_label; + QPushButton *play_btn; Slider *slider; }; From 00494a44f4fb8f9e18ce82e22bf40fbe6bc1a805 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 16 Oct 2022 15:54:36 -0700 Subject: [PATCH 07/34] CI speedup (#26096) * CI speedup * use the new stuff * push * no regressions * try that * don't let this slip * fix modeld tests * fix linter * modernize prebuilt * cleanup * fix those * increase a bit --- .github/workflows/prebuilt.yaml | 8 +- .github/workflows/selfdrive_tests.yaml | 109 +++++++++--------- .github/workflows/setup/action.yaml | 8 +- .github/workflows/tools_tests.yaml | 45 +++++--- .pre-commit-config.yaml | 1 + release/build_devel.sh | 4 +- selfdrive/modeld/tests/__init__.py | 0 .../modeld/{test => tests}/dmon_lag/repro.cc | 0 .../{test => tests}/snpe_benchmark/.gitignore | 0 .../snpe_benchmark/benchmark.cc | 1 + .../snpe_benchmark/benchmark.sh | 0 .../modeld/{test => tests}/test_modeld.py | 0 .../modeld/{test => tests}/tf_test/build.sh | 0 .../modeld/{test => tests}/tf_test/main.cc | 0 .../{test => tests}/tf_test/pb_loader.py | 0 .../{test => tests}/timing/benchmark.py | 0 16 files changed, 95 insertions(+), 81 deletions(-) create mode 100644 selfdrive/modeld/tests/__init__.py rename selfdrive/modeld/{test => tests}/dmon_lag/repro.cc (100%) rename selfdrive/modeld/{test => tests}/snpe_benchmark/.gitignore (100%) rename selfdrive/modeld/{test => tests}/snpe_benchmark/benchmark.cc (99%) rename selfdrive/modeld/{test => tests}/snpe_benchmark/benchmark.sh (100%) rename selfdrive/modeld/{test => tests}/test_modeld.py (100%) rename selfdrive/modeld/{test => tests}/tf_test/build.sh (100%) rename selfdrive/modeld/{test => tests}/tf_test/main.cc (100%) rename selfdrive/modeld/{test => tests}/tf_test/pb_loader.py (100%) rename selfdrive/modeld/{test => tests}/timing/benchmark.py (100%) diff --git a/.github/workflows/prebuilt.yaml b/.github/workflows/prebuilt.yaml index b659d4ceee..c8b4c51e38 100644 --- a/.github/workflows/prebuilt.yaml +++ b/.github/workflows/prebuilt.yaml @@ -2,7 +2,6 @@ name: prebuilt on: schedule: - cron: '0 * * * *' - workflow_dispatch: env: @@ -11,9 +10,7 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: | - docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true - docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true - docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . + DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . jobs: build_prebuilt: @@ -37,8 +34,7 @@ jobs: - name: Build Docker image run: | eval "$BUILD" - docker pull $DOCKER_REGISTRY/$IMAGE_NAME:latest || true - docker build --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f Dockerfile.openpilot . + DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f Dockerfile.openpilot . - name: Push to container registry run: | $DOCKER_LOGIN diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index cd34c6d27c..d84779103b 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -18,15 +18,12 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: | - docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true - docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true - docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . + DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/sh -c BUILD_CL: | - docker pull $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest || true - docker build --cache-from $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $CL_BASE_IMAGE:latest -f Dockerfile.openpilot_base_cl . + DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $CL_BASE_IMAGE:latest -f Dockerfile.openpilot_base_cl . RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/sh -c UNIT_TEST: coverage run --append -m unittest discover @@ -41,13 +38,10 @@ jobs: steps: - uses: actions/checkout@v3 with: - fetch-depth: 0 submodules: true - name: Build devel run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh - uses: ./.github/workflows/setup - with: - save-cache: true - name: Check submodules if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' run: release/check-submodules.sh @@ -72,18 +66,20 @@ jobs: build_all: name: build all runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 30 steps: - uses: actions/checkout@v3 with: submodules: true - uses: ./.github/workflows/setup + with: + save-cache: true - name: Build openpilot with all flags run: ${{ env.RUN }} "scons -j$(nproc) --extras && release/check-dirty.sh" - name: Cleanup scons cache run: | ${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \ - scons -j$(nproc) --extras --cache-populate" + scons -j$(nproc) --cache-populate" #build_mac: # name: build macos @@ -145,7 +141,7 @@ jobs: docker_push: name: docker push runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 22 if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' needs: static_analysis # hack to ensure slow tests run first since this and static_analysis are fast steps: @@ -154,12 +150,14 @@ jobs: submodules: true - name: Build Docker image run: eval "$BUILD" + timeout-minutes: 13 - name: Push to container registry run: | $DOCKER_LOGIN docker push $DOCKER_REGISTRY/$BASE_IMAGE:latest - name: Build CL Docker image run: eval "$BUILD_CL" + timeout-minutes: 4 - name: Push to container registry run: | $DOCKER_LOGIN @@ -168,7 +166,7 @@ jobs: static_analysis: name: static analysis runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: @@ -176,21 +174,23 @@ jobs: - name: Build Docker image run: eval "$BUILD" - name: pre-commit + timeout-minutes: 5 run: ${{ env.RUN }} "pre-commit run --all" valgrind: name: valgrind runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: submodules: true - uses: ./.github/workflows/setup + - name: Build openpilot + run: ${{ env.RUN }} "scons -j$(nproc)" - name: Run valgrind run: | - ${{ env.RUN }} "scons -j$(nproc) && \ - python selfdrive/test/test_valgrind_replay.py" + ${{ env.RUN }} "python selfdrive/test/test_valgrind_replay.py" - name: Print logs if: always() run: cat selfdrive/test/valgrind_logs.txt @@ -198,16 +198,18 @@ jobs: unit_tests: name: unit tests runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 30 steps: - uses: actions/checkout@v3 with: submodules: true - uses: ./.github/workflows/setup + - name: Build openpilot + run: ${{ env.RUN }} "scons -j$(nproc)" - name: Run unit tests + timeout-minutes: 15 run: | ${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \ - scons -j$(nproc) && \ $UNIT_TEST common && \ $UNIT_TEST opendbc/can && \ $UNIT_TEST selfdrive/boardd && \ @@ -220,7 +222,6 @@ jobs: $UNIT_TEST selfdrive/athena && \ $UNIT_TEST selfdrive/thermald && \ $UNIT_TEST system/hardware/tici && \ - $UNIT_TEST selfdrive/modeld && \ $UNIT_TEST tools/lib/tests && \ ./selfdrive/ui/tests/create_test_translations.sh && \ QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \ @@ -239,7 +240,7 @@ jobs: process_replay: name: process replay runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 25 steps: - uses: actions/checkout@v3 with: @@ -251,10 +252,12 @@ jobs: with: path: /tmp/comma_download_cache key: proc-replay-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/ref_commit') }} + - name: Build openpilot + run: | + ${{ env.RUN }} "scons -j$(nproc)" - name: Run replay run: | - ${{ env.RUN }} "scons -j$(nproc) && \ - CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ + ${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ coverage xml" - name: Print diff if: always() @@ -268,15 +271,14 @@ jobs: - name: Upload reference logs if: ${{ failure() && github.event_name == 'pull_request' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }} run: | - ${{ env.RUN }} "scons -j$(nproc) && \ - CI=1 AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only" + ${{ env.RUN }} "CI=1 AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only" - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v2 - model_replay_onnx: - name: model replay onnx + test_modeld: + name: model tests runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: @@ -285,29 +287,41 @@ jobs: - name: Build Docker image # Sim docker is needed to get the OpenCL drivers run: eval "$BUILD_CL" - - name: Run replay + - name: Build openpilot + run: | + ${{ env.RUN }} "scons -j$(nproc)" + - name: Run model replay with ONNX + timeout-minutes: 2 + run: | + ${{ env.RUN_CL }} "ONNXCPU=1 CI=1 coverage run selfdrive/test/process_replay/model_replay.py && \ + coverage xml" + - name: Run unit tests + timeout-minutes: 5 run: | - ${{ env.RUN_CL }} "scons -j$(nproc) && \ - ONNXCPU=1 CI=1 coverage run \ - selfdrive/test/process_replay/model_replay.py -j$(nproc) && \ + ${{ env.RUN_CL }} "$UNIT_TEST selfdrive/modeld && \ coverage xml" + - name: "Upload coverage to Codecov" + uses: codecov/codecov-action@v2 test_longitudinal: name: longitudinal runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: submodules: true - uses: ./.github/workflows/setup + - name: Build openpilot + run: | + ${{ env.RUN }} "scons -j$(nproc)" - name: Test longitudinal run: | ${{ env.RUN }} "mkdir -p selfdrive/test/out && \ - scons -j$(nproc) && \ cd selfdrive/test/longitudinal_maneuvers && \ coverage run ./test_longitudinal.py && \ coverage xml" + timeout-minutes: 2 - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v2 - uses: actions/upload-artifact@v2 @@ -320,7 +334,7 @@ jobs: test_cars: name: cars runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 20 strategy: fail-fast: false matrix: @@ -336,10 +350,12 @@ jobs: with: path: /tmp/comma_download_cache key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/car/tests/routes.py') }}-${{ matrix.job }} + - name: Build openpilot + run: ${{ env.RUN }} "scons -j$(nproc)" - name: Test car models + timeout-minutes: 12 run: | - ${{ env.RUN }} "scons -j$(nproc) && \ - coverage run -m pytest selfdrive/car/tests/test_models.py && \ + ${{ env.RUN }} "coverage run -m pytest selfdrive/car/tests/test_models.py && \ coverage xml && \ chmod -R 777 /tmp/comma_download_cache" env: @@ -348,29 +364,10 @@ jobs: - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v2 - docs: - name: build docs - runs-on: ubuntu-20.04 - timeout-minutes: 50 - steps: - - uses: actions/checkout@v3 - with: - submodules: true - - name: Build docker container - run: | - docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true - docker pull $DOCKER_REGISTRY/openpilot-docs:latest || true - DOCKER_BUILDKIT=1 docker build --cache-from $DOCKER_REGISTRY/openpilot-docs:latest -t $DOCKER_REGISTRY/openpilot-docs:latest -f docs/docker/Dockerfile . - - name: Push docker container - if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' - run: | - $DOCKER_LOGIN - docker push $DOCKER_REGISTRY/openpilot-docs:latest - car_docs_diff: - name: comment on PR with car docs diff + name: PR comments runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 20 if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/setup/action.yaml b/.github/workflows/setup/action.yaml index 79c4c890ab..186a9d9095 100644 --- a/.github/workflows/setup/action.yaml +++ b/.github/workflows/setup/action.yaml @@ -15,9 +15,9 @@ runs: # build cache - id: date shell: bash - run: echo "::set-output name=date::$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d')" + run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV - shell: bash - run: echo "${{ steps.date.outputs.date }}" + run: echo "$CACHE_COMMIT_DATE" - shell: bash run: echo "CACHE_SKIP_SAVE=true" >> $GITHUB_ENV if: github.ref != 'refs/heads/master' || inputs.save-cache == 'false' @@ -27,9 +27,9 @@ runs: uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b with: path: /tmp/scons_cache - key: scons-${{ steps.date.outputs.date }}-${{ github.sha }} + key: scons-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }} restore-keys: | - scons-${{ steps.date.outputs.date }}- + scons-${{ env.CACHE_COMMIT_DATE }}- scons- # build our docker image diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 9dc5c05837..549a2f4195 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -2,6 +2,8 @@ name: tools on: push: + branches-ignore: + - 'testing-closet*' pull_request: concurrency: @@ -15,21 +17,20 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: | - docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true - docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true - docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . + DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . + + RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/sh -c + BUILD_CL: | - docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base_cl) || true - docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true - docker build --cache-from $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $CL_BASE_IMAGE:latest -f Dockerfile.openpilot_base_cl . - RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e \ - GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c + DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $CL_BASE_IMAGE:latest -f Dockerfile.openpilot_base_cl . + RUN_CL: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/sh -c + jobs: plotjuggler: name: plotjuggler runs-on: ubuntu-20.04 - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: @@ -37,6 +38,7 @@ jobs: - name: Build Docker image run: eval "$BUILD" - name: Unit test + timeout-minutes: 2 run: | ${{ env.RUN }} "scons -j$(nproc) --directory=/tmp/openpilot/cereal && \ apt-get update && \ @@ -47,7 +49,7 @@ jobs: simulator: name: simulator runs-on: ubuntu-20.04 - timeout-minutes: 50 + timeout-minutes: 30 env: IMAGE_NAME: openpilot-sim if: github.repository == 'commaai/openpilot' @@ -61,12 +63,29 @@ jobs: run: eval "$BUILD" - name: Build base cl image run: eval "$BUILD_CL" - - name: Pull latest simulator image - run: docker pull $DOCKER_REGISTRY/$IMAGE_NAME:latest || true - name: Build simulator image - run: docker build --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f tools/sim/Dockerfile.sim . + run: DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f tools/sim/Dockerfile.sim . - name: Push to container registry if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' run: | $DOCKER_LOGIN docker push $DOCKER_REGISTRY/$IMAGE_NAME:latest + + docs: + name: build docs + runs-on: ubuntu-20.04 + timeout-minutes: 25 + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - name: Build docker container + run: | + DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/openpilot-docs:latest -t $DOCKER_REGISTRY/openpilot-docs:latest -f docs/docker/Dockerfile . + - name: Push docker container + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' + run: | + $DOCKER_LOGIN + docker push $DOCKER_REGISTRY/openpilot-docs:latest + + diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 25b8490f92..85c24b911b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,6 +53,7 @@ repos: types: [python] exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)' args: + - -j0 - -rn - -sn - --rcfile=.pylintrc diff --git a/release/build_devel.sh b/release/build_devel.sh index 7108334808..668ac0de19 100755 --- a/release/build_devel.sh +++ b/release/build_devel.sh @@ -22,8 +22,8 @@ pre-commit uninstall || true echo "[-] bringing master-ci and devel in sync T=$SECONDS" cd $TARGET_DIR -git fetch origin master-ci -git fetch origin devel +git fetch --depth 1 origin master-ci +git fetch --depth 1 origin devel git checkout -f --track origin/master-ci git reset --hard master-ci diff --git a/selfdrive/modeld/tests/__init__.py b/selfdrive/modeld/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selfdrive/modeld/test/dmon_lag/repro.cc b/selfdrive/modeld/tests/dmon_lag/repro.cc similarity index 100% rename from selfdrive/modeld/test/dmon_lag/repro.cc rename to selfdrive/modeld/tests/dmon_lag/repro.cc diff --git a/selfdrive/modeld/test/snpe_benchmark/.gitignore b/selfdrive/modeld/tests/snpe_benchmark/.gitignore similarity index 100% rename from selfdrive/modeld/test/snpe_benchmark/.gitignore rename to selfdrive/modeld/tests/snpe_benchmark/.gitignore diff --git a/selfdrive/modeld/test/snpe_benchmark/benchmark.cc b/selfdrive/modeld/tests/snpe_benchmark/benchmark.cc similarity index 99% rename from selfdrive/modeld/test/snpe_benchmark/benchmark.cc rename to selfdrive/modeld/tests/snpe_benchmark/benchmark.cc index 1e2072eea1..021e065d81 100644 --- a/selfdrive/modeld/test/snpe_benchmark/benchmark.cc +++ b/selfdrive/modeld/tests/snpe_benchmark/benchmark.cc @@ -102,6 +102,7 @@ void get_testframe(int index, std::unique_ptr &input) { fread(frame_buffer, length, 1, pFile); // std::cout << *(frame_buffer+length/4-1) << std::endl; std::copy(frame_buffer, frame_buffer+(length/4), input->begin()); + fclose(pFile); } void SaveITensor(const std::string& path, const zdl::DlSystem::ITensor* tensor) diff --git a/selfdrive/modeld/test/snpe_benchmark/benchmark.sh b/selfdrive/modeld/tests/snpe_benchmark/benchmark.sh similarity index 100% rename from selfdrive/modeld/test/snpe_benchmark/benchmark.sh rename to selfdrive/modeld/tests/snpe_benchmark/benchmark.sh diff --git a/selfdrive/modeld/test/test_modeld.py b/selfdrive/modeld/tests/test_modeld.py similarity index 100% rename from selfdrive/modeld/test/test_modeld.py rename to selfdrive/modeld/tests/test_modeld.py diff --git a/selfdrive/modeld/test/tf_test/build.sh b/selfdrive/modeld/tests/tf_test/build.sh similarity index 100% rename from selfdrive/modeld/test/tf_test/build.sh rename to selfdrive/modeld/tests/tf_test/build.sh diff --git a/selfdrive/modeld/test/tf_test/main.cc b/selfdrive/modeld/tests/tf_test/main.cc similarity index 100% rename from selfdrive/modeld/test/tf_test/main.cc rename to selfdrive/modeld/tests/tf_test/main.cc diff --git a/selfdrive/modeld/test/tf_test/pb_loader.py b/selfdrive/modeld/tests/tf_test/pb_loader.py similarity index 100% rename from selfdrive/modeld/test/tf_test/pb_loader.py rename to selfdrive/modeld/tests/tf_test/pb_loader.py diff --git a/selfdrive/modeld/test/timing/benchmark.py b/selfdrive/modeld/tests/timing/benchmark.py similarity index 100% rename from selfdrive/modeld/test/timing/benchmark.py rename to selfdrive/modeld/tests/timing/benchmark.py From f8091837c92ed096ef3b886d1b09fe758d6ae9f2 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Tue, 18 Oct 2022 02:15:03 +0900 Subject: [PATCH 08/34] kor translation update (#26111) --- selfdrive/ui/translations/main_ko.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 86cd8f990a..f84797eb60 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -60,11 +60,11 @@ Cellular Metered - + 데이터 요금제 Prevent large data uploads when on a metered connection - + 데이터 요금제 연결 시 대용량 데이터 업로드 방지 From 93346c31d3728d27eaff56a3068690a47eac86ef Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 01:20:27 +0800 Subject: [PATCH 09/34] Cabana: add chart_height setting (#26066) add chart_height setting --- tools/cabana/canmessages.cc | 5 ++++- tools/cabana/canmessages.h | 1 + tools/cabana/chartswidget.cc | 11 ++++++++++- tools/cabana/chartswidget.h | 1 + tools/cabana/mainwin.cc | 7 +++++++ tools/cabana/mainwin.h | 1 + 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index b717424ece..3cf08eaaa0 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -141,11 +141,14 @@ void Settings::save() { s.setValue("fps", fps); s.setValue("log_size", can_msg_log_size); s.setValue("cached_segment", cached_segment_limit); + s.setValue("chart_height", chart_height); + emit changed(); } void Settings::load() { QSettings s("settings", QSettings::IniFormat); fps = s.value("fps", 10).toInt(); can_msg_log_size = s.value("log_size", 100).toInt(); - cached_segment_limit = s.value("cached_segment", 3.).toInt(); + cached_segment_limit = s.value("cached_segment", 3).toInt(); + chart_height = s.value("chart_height", 200).toInt(); } diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 3d33f801a7..7f6955369b 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -19,6 +19,7 @@ public: int fps = 10; int can_msg_log_size = 100; int cached_segment_limit = 3; + int chart_height = 200; signals: void changed(); diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index d0f5356fac..e69729c03a 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -76,6 +76,11 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { docking = !docking; updateTitleBar(); }); + QObject::connect(&settings, &Settings::changed, [this]() { + for (auto chart : charts) { + chart->setHeight(settings.chart_height); + } + }); } void ChartsWidget::updateTitleBar() { @@ -152,7 +157,7 @@ ChartWidget::ChartWidget(const QString &id, const Signal *sig, QWidget *parent) main_layout->addWidget(header); chart_view = new ChartView(id, sig, this); - chart_view->setFixedHeight(300); + chart_view->setFixedHeight(settings.chart_height); main_layout->addWidget(chart_view); main_layout->addStretch(); @@ -205,6 +210,10 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) updateSeries(); } +void ChartWidget::setHeight(int height) { + chart_view->setFixedHeight(height); +} + void ChartView::updateState() { auto axis_x = dynamic_cast(chart()->axisX()); int x = chart()->plotArea().left() + chart()->plotArea().width() * (can->currentSec() - axis_x->min()) / (axis_x->max() - axis_x->min()); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index a3c470e960..3e43409dc4 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -46,6 +46,7 @@ Q_OBJECT public: ChartWidget(const QString &id, const Signal *sig, QWidget *parent); void updateTitle(); + void setHeight(int height); signals: void remove(); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index c9d9c85141..999a4816b0 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -96,6 +96,12 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { cached_segment->setValue(settings.cached_segment_limit); form_layout->addRow(tr("Cached segments limit"), cached_segment); + chart_height = new QSpinBox(this); + chart_height->setRange(100, 500); + chart_height->setSingleStep(10); + chart_height->setValue(settings.chart_height); + form_layout->addRow(tr("Chart height"), chart_height); + main_layout->addLayout(form_layout); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -110,6 +116,7 @@ void SettingsDlg::save() { settings.fps = fps->value(); settings.can_msg_log_size = log_size->value(); settings.cached_segment_limit = cached_segment->value(); + settings.chart_height = chart_height->value(); settings.save(); accept(); } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 14c4b1dfa9..594e608b59 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -33,4 +33,5 @@ public: QSpinBox *fps; QSpinBox *log_size ; QSpinBox *cached_segment; + QSpinBox *chart_height; }; From 3a8ddc191fd9a7537254399e3b9e49217de9bf16 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 01:32:31 +0800 Subject: [PATCH 10/34] Move Qt moc files to scons cache directory (#26109) --- SConstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/SConstruct b/SConstruct index 23ab37dc1e..74680c0598 100644 --- a/SConstruct +++ b/SConstruct @@ -327,6 +327,7 @@ qt_flags = [ qt_env['CXXFLAGS'] += qt_flags qt_env['LIBPATH'] += ['#selfdrive/ui'] qt_env['LIBS'] = qt_libs +qt_env['QT_MOCHPREFIX'] = cache_dir + '/moc_files/moc_' if GetOption("clazy"): checks = [ From 6d07268ee5b385010961eab206b0b42a0ae6b5f8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 01:39:07 +0800 Subject: [PATCH 11/34] tools/replay: reduce test running time (#26110) --- tools/replay/tests/test_replay.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/replay/tests/test_replay.cc b/tools/replay/tests/test_replay.cc index 5b61b6b6f2..3fd410bb6e 100644 --- a/tools/replay/tests/test_replay.cc +++ b/tools/replay/tests/test_replay.cc @@ -207,8 +207,7 @@ void TestReplay::test_seek() { } TEST_CASE("Replay") { - auto flag = GENERATE(REPLAY_FLAG_NO_FILE_CACHE, REPLAY_FLAG_NONE); - TestReplay replay(DEMO_ROUTE, flag); + TestReplay replay(DEMO_ROUTE, (uint8_t)REPLAY_FLAG_NO_VIPC); REQUIRE(replay.load()); replay.test_seek(); } From 1dffbb629a6b629b3079bcea195f64f389fc5d1d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Oct 2022 10:47:54 -0700 Subject: [PATCH 12/34] GM camera ACC: revert FCW logging (#26114) Revert FCW logging --- selfdrive/car/gm/carstate.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 21eb440d7f..b67b97093a 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -96,9 +96,7 @@ class CarState(CarStateBase): ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL if self.CP.networkLocation == NetworkLocation.fwdCamera: ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS - ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0 - ret.stockFcw = cam_cp.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"] != 0 return ret @@ -110,7 +108,6 @@ class CarState(CarStateBase): signals += [ ("AEBCmdActive", "AEBCmd"), ("RollingCounter", "ASCMLKASteeringCmd"), - ("FCWAlert", "ASCMActiveCruiseControlStatus"), ("ACCSpeedSetpoint", "ASCMActiveCruiseControlStatus"), ] checks += [ From 9e2a1121ea1103efaceaf52cca83370da73ba988 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 17 Oct 2022 12:55:40 -0700 Subject: [PATCH 13/34] athenad: small tests cleanup (#26037) * test helpers * create file helper * clearer * type * fix default create path * static methods --- selfdrive/athena/tests/test_athenad.py | 68 ++++++++++++++------------ 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/selfdrive/athena/tests/test_athenad.py b/selfdrive/athena/tests/test_athenad.py index 7f511eecf6..5e86a2e821 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/selfdrive/athena/tests/test_athenad.py @@ -9,6 +9,7 @@ import threading import queue import unittest from datetime import datetime, timedelta +from typing import Optional from multiprocessing import Process from pathlib import Path @@ -46,12 +47,26 @@ class TestAthenadMethods(unittest.TestCase): else: os.unlink(p) - def wait_for_upload(self): + + # *** test helpers *** + + @staticmethod + def _wait_for_upload(): now = time.time() while time.time() - now < 5: if athenad.upload_queue.qsize() == 0: break + @staticmethod + def _create_file(file: str, parent: Optional[str] = None) -> str: + fn = os.path.join(athenad.ROOT if parent is None else parent, file) + os.makedirs(os.path.dirname(fn), exist_ok=True) + Path(fn).touch() + return fn + + + # *** test cases *** + def test_echo(self): assert dispatcher["echo"]("bob") == "bob" @@ -85,9 +100,7 @@ class TestAthenadMethods(unittest.TestCase): filenames = ['qlog', 'qcamera.ts', 'rlog', 'fcamera.hevc', 'ecamera.hevc', 'dcamera.hevc'] files = [f'{route}--{s}/{f}' for s in segments for f in filenames] for file in files: - fn = os.path.join(athenad.ROOT, file) - os.makedirs(os.path.dirname(fn), exist_ok=True) - Path(fn).touch() + self._create_file(file) resp = dispatcher["listDataDirectory"]() self.assertTrue(resp, 'list empty!') @@ -121,16 +134,14 @@ class TestAthenadMethods(unittest.TestCase): self.assertCountEqual(resp, expected) def test_strip_bz2_extension(self): - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + fn = self._create_file('qlog.bz2') if fn.endswith('.bz2'): self.assertEqual(athenad.strip_bz2_extension(fn), fn[:-4]) @with_http_server def test_do_upload(self, host): - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + fn = self._create_file('qlog.bz2') item = athenad.UploadItem(path=fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='') with self.assertRaises(requests.exceptions.ConnectionError): @@ -142,8 +153,7 @@ class TestAthenadMethods(unittest.TestCase): @with_http_server def test_uploadFileToUrl(self, host): - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + fn = self._create_file('qlog.bz2') resp = dispatcher["uploadFileToUrl"]("qlog.bz2", f"{host}/qlog.bz2", {}) self.assertEqual(resp['enqueued'], 1) @@ -154,8 +164,7 @@ class TestAthenadMethods(unittest.TestCase): @with_http_server def test_uploadFileToUrl_duplicate(self, host): - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + self._create_file('qlog.bz2') url1 = f"{host}/qlog.bz2?sig=sig1" dispatcher["uploadFileToUrl"]("qlog.bz2", url1, {}) @@ -172,8 +181,7 @@ class TestAthenadMethods(unittest.TestCase): @with_http_server def test_upload_handler(self, host): - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + fn = self._create_file('qlog.bz2') item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) end_event = threading.Event() @@ -182,7 +190,7 @@ class TestAthenadMethods(unittest.TestCase): athenad.upload_queue.put_nowait(item) try: - self.wait_for_upload() + self._wait_for_upload() time.sleep(0.1) # TODO: verify that upload actually succeeded @@ -195,8 +203,7 @@ class TestAthenadMethods(unittest.TestCase): def test_upload_handler_retry(self, host, mock_put): for status, retry in ((500, True), (412, False)): mock_put.return_value.status_code = status - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + fn = self._create_file('qlog.bz2') item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) end_event = threading.Event() @@ -205,7 +212,7 @@ class TestAthenadMethods(unittest.TestCase): athenad.upload_queue.put_nowait(item) try: - self.wait_for_upload() + self._wait_for_upload() time.sleep(0.1) self.assertEqual(athenad.upload_queue.qsize(), 1 if retry else 0) @@ -217,8 +224,7 @@ class TestAthenadMethods(unittest.TestCase): def test_upload_handler_timeout(self): """When an upload times out or fails to connect it should be placed back in the queue""" - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + fn = self._create_file('qlog.bz2') item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) item_no_retry = item._replace(retry_count=MAX_RETRY_COUNT) @@ -228,14 +234,14 @@ class TestAthenadMethods(unittest.TestCase): try: athenad.upload_queue.put_nowait(item_no_retry) - self.wait_for_upload() + self._wait_for_upload() time.sleep(0.1) # Check that upload with retry count exceeded is not put back self.assertEqual(athenad.upload_queue.qsize(), 0) athenad.upload_queue.put_nowait(item) - self.wait_for_upload() + self._wait_for_upload() time.sleep(0.1) # Check that upload item was put back in the queue with incremented retry count @@ -256,7 +262,7 @@ class TestAthenadMethods(unittest.TestCase): thread = threading.Thread(target=athenad.upload_handler, args=(end_event,)) thread.start() try: - self.wait_for_upload() + self._wait_for_upload() time.sleep(0.1) self.assertEqual(athenad.upload_queue.qsize(), 0) @@ -269,8 +275,7 @@ class TestAthenadMethods(unittest.TestCase): ts = int(t_future.strftime("%s")) * 1000 # Item that would time out if actually uploaded - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + fn = self._create_file('qlog.bz2') item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=ts, id='', allow_cellular=True) @@ -279,7 +284,7 @@ class TestAthenadMethods(unittest.TestCase): thread.start() try: athenad.upload_queue.put_nowait(item) - self.wait_for_upload() + self._wait_for_upload() time.sleep(0.1) self.assertEqual(athenad.upload_queue.qsize(), 0) @@ -292,8 +297,7 @@ class TestAthenadMethods(unittest.TestCase): @with_http_server def test_listUploadQueueCurrent(self, host): - fn = os.path.join(athenad.ROOT, 'qlog.bz2') - Path(fn).touch() + fn = self._create_file('qlog.bz2') item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) end_event = threading.Event() @@ -302,7 +306,7 @@ class TestAthenadMethods(unittest.TestCase): try: athenad.upload_queue.put_nowait(item) - self.wait_for_upload() + self._wait_for_upload() items = dispatcher["listUploadQueue"]() self.assertEqual(len(items), 1) @@ -405,9 +409,9 @@ class TestAthenadMethods(unittest.TestCase): def test_get_logs_to_send_sorted(self): fl = list() for i in range(10): - fn = os.path.join(swaglog.SWAGLOG_DIR, f'swaglog.{i:010}') - Path(fn).touch() - fl.append(os.path.basename(fn)) + file = f'swaglog.{i:010}' + self._create_file(file, athenad.SWAGLOG_DIR) + fl.append(file) # ensure the list is all logs except most recent sl = athenad.get_logs_to_send_sorted() From 6c65e9bf9837cb00c5feeb3744232597c5b421bb Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Oct 2022 13:50:56 -0700 Subject: [PATCH 14/34] HKG FPv2: whitelist queried Ecus (#26115) * whitelist all ecus * remove engine and fwdCamera from queries they never return to --- selfdrive/car/hyundai/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 734e56c033..3585fcc313 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -293,10 +293,12 @@ FW_QUERY_CONFIG = FwQueryConfig( Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], + whitelist_ecus=[Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera], ), Request( [HYUNDAI_VERSION_REQUEST_MULTI], [HYUNDAI_VERSION_RESPONSE], + whitelist_ecus=[Ecu.engine, Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar], ), ], extra_ecus=[ From 581835df80dc2cf4d3c0e18fdf9f2772e643da5a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Oct 2022 14:04:29 -0700 Subject: [PATCH 15/34] 2018 Kia Stinger: add missing FW versions (#26117) add missing versions from 1ce52d9487767eae --- selfdrive/car/hyundai/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 3585fcc313..856bf1abd9 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -743,6 +743,7 @@ FW_VERSIONS = { b'\xf1\x81640E0051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x82CKJN3TMSDE0B\x00\x00\x00\x00', b'\xf1\x82CKKN3TMD_H0A\x00\x00\x00\x00', + b'\xe0\x19\xff\xe7\xe7g\x01\xa2\x00\x0f\x00\x9e\x00\x06\x00\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x0f\x0e\x0f\x0f\x0e\r\x00\x00\x7f\x02.\xff\x00\x00~p\x00\x00\x00\x00u\xff\xf9\xff\x00\x00\x00\x00V\t\xd5\x01\xc0\x00\x00\x00\x007\xfb\xfc\x0b\x8d\x00', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5200 4C2CL104', @@ -765,6 +766,8 @@ FW_VERSIONS = { b'\xf1\x87VDKLJ18675252DK6\x89vhgwwwwveVU\x88w\x87w\x99vgf\x97vXfgw_\xff\xc2\xfb\xf1\x89E25\x00\x00\x00\x00\x00\x00\x00\xf1\x82TCK0T33NB2', b'\xf1\x87WAJTE17552812CH4vfFffvfVeT5DwvvVVdFeegeg\x88\x88o\xff\x1a]\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00TCK2T20NB1\x19\xd2\x00\x94', b'\xf1\x87VDHLG17274082DK2wfFf\x89x\x98wUT5T\x88v\x97xgeGefTGTVvO\xff\x1c\x14\xf1\x81E19\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E19\x00\x00\x00\x00\x00\x00\x00SCK0T33UB2\xee[\x97S', + b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\t\xb7\x17\xf5', + b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\t\xb7\x17\xf5', ], }, CAR.PALISADE: { From 60586e0d5835dbb3928321700c9d4d99cdeec216 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 05:39:18 +0800 Subject: [PATCH 16/34] Cabana: align the charts properly (#26116) --- tools/cabana/chartswidget.cc | 20 +++++++++++++++++++- tools/cabana/chartswidget.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index e69729c03a..3652720e12 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -183,7 +184,6 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) font.setBold(true); chart->setTitleFont(font); chart->setMargins({0, 0, 0, 0}); - chart->layout()->setContentsMargins(0, 0, 0, 0); track_line = new QGraphicsLineItem(chart); track_line->setPen(QPen(Qt::gray, 1, Qt::DashLine)); @@ -202,14 +202,32 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) rubber->setPalette(pal); } + QTimer *timer = new QTimer(this); + timer->setInterval(100); + timer->setSingleShot(true); + timer->callOnTimeout(this, &ChartView::adjustChartMargins); + QObject::connect(can, &CANMessages::updated, this, &ChartView::updateState); QObject::connect(can, &CANMessages::rangeChanged, this, &ChartView::rangeChanged); QObject::connect(can, &CANMessages::eventsMerged, this, &ChartView::updateSeries); QObject::connect(dynamic_cast(chart->axisX()), &QValueAxis::rangeChanged, can, &CANMessages::setRange); + QObject::connect(chart, &QChart::plotAreaChanged, [=](const QRectF &plotArea) { + // use a singleshot timer to avoid recursion call. + timer->start(); + }); updateSeries(); } +void ChartView::adjustChartMargins() { + // TODO: Remove hardcoded aligned_pos + const int aligned_pos = 60; + if (chart()->plotArea().left() != aligned_pos) { + const float left_margin = chart()->margins().left() + aligned_pos - chart()->plotArea().left(); + chart()->setMargins(QMargins(left_margin, 0, 0, 0)); + } +} + void ChartWidget::setHeight(int height) { chart_view->setFixedHeight(height); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 3e43409dc4..fe2e14db9f 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -27,6 +27,7 @@ private: void mouseMoveEvent(QMouseEvent *ev) override; void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; + void adjustChartMargins(); void rangeChanged(qreal min, qreal max); void updateAxisY(); From c6b8a253e68fc62cd9eb3261e7f08d3cb3d3414d Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 17 Oct 2022 15:36:29 -0700 Subject: [PATCH 17/34] networking: fix metered setting (#26113) when metered set unknown, when unmetered set no --- selfdrive/ui/qt/offroad/wifiManager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/offroad/wifiManager.cc b/selfdrive/ui/qt/offroad/wifiManager.cc index 62de3041b9..fde8645586 100644 --- a/selfdrive/ui/qt/offroad/wifiManager.cc +++ b/selfdrive/ui/qt/offroad/wifiManager.cc @@ -368,7 +368,7 @@ void WifiManager::updateGsmSettings(bool roaming, QString apn, bool metered) { changes = true; } - int meteredInt = metered ? NM_METERED_NO : NM_METERED_UNKNOWN; + int meteredInt = metered ? NM_METERED_UNKNOWN : NM_METERED_NO; if (settings.value("connection").value("metered").toInt() != meteredInt) { qWarning() << "Changing connection.metered to" << meteredInt; settings["connection"]["metered"] = meteredInt; From e6cab24e08323ce1e8d846365a6ca1770a54f851 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 17 Oct 2022 15:38:31 -0700 Subject: [PATCH 18/34] updated: sync submodules (#26121) --- selfdrive/updated.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/updated.py b/selfdrive/updated.py index 9568b28ae3..57f957cfff 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -365,6 +365,7 @@ class Updater: ["git", "checkout", "--force", "--no-recurse-submodules", "-B", branch, "FETCH_HEAD"], ["git", "reset", "--hard"], ["git", "clean", "-xdff"], + ["git", "submodule", "sync"], ["git", "submodule", "init"], ["git", "submodule", "update"], ] From 15b8c7d1dc3a75d78c0bbaa4f6b866374f6e8672 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 17 Oct 2022 17:14:38 -0700 Subject: [PATCH 19/34] ui: publish draw times + add test (#26119) * ui: publish draw times + add test * add some checks * adjust * fix linter * update max Co-authored-by: Comma Device --- cereal | 2 +- selfdrive/debug/check_timings.py | 2 +- selfdrive/test/test_onroad.py | 23 +++++++++++++++++++++-- selfdrive/ui/qt/onroad.cc | 10 ++++++++++ selfdrive/ui/qt/onroad.h | 1 + 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/cereal b/cereal index 5766e645f2..107048c83e 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 5766e645f2ee2a131b145fb1ea9e3b7c55a4a740 +Subproject commit 107048c83ec2f488286a1be314e7aece0a20a6b1 diff --git a/selfdrive/debug/check_timings.py b/selfdrive/debug/check_timings.py index 083e084ca7..fb8467a3c4 100755 --- a/selfdrive/debug/check_timings.py +++ b/selfdrive/debug/check_timings.py @@ -19,7 +19,7 @@ if __name__ == "__main__": for m in msgs: ts[s].append(m.logMonoTime / 1e6) - if len(ts[s]): + if len(ts[s]) > 2: d = np.diff(ts[s]) print(f"{s:25} {np.mean(d):.2f} {np.std(d):.2f} {np.max(d):.2f} {np.min(d):.2f}") time.sleep(1) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index b29ca5d35b..0d3d7b367a 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -120,8 +120,8 @@ class TestOnroad(unittest.TestCase): if "DEBUG" in os.environ: segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog")), Path(ROOT).iterdir()) segs = sorted(segs, key=lambda x: x.stat().st_mtime) - print(segs[-1]) - cls.lr = list(LogReader(os.path.join(segs[-1], "rlog"))) + print(segs[-2]) + cls.lr = list(LogReader(os.path.join(segs[-2], "rlog"))) return # setup env @@ -187,6 +187,25 @@ class TestOnroad(unittest.TestCase): big_logs = [f for f, n in cnt.most_common(3) if n / sum(cnt.values()) > 30.] self.assertEqual(len(big_logs), 0, f"Log spam: {big_logs}") + def test_ui_timings(self): + result = "\n" + result += "------------------------------------------------\n" + result += "-------------- UI Draw Timing ------------------\n" + result += "------------------------------------------------\n" + + ts = [m.uiDebug.drawTimeMillis for m in self.lr if m.which() == 'uiDebug'] + result += f"min {min(ts):.2f}ms\n" + result += f"max {max(ts):.2f}ms\n" + result += f"std {np.std(ts):.2f}ms\n" + result += f"mean {np.mean(ts):.2f}ms\n" + result += "------------------------------------------------\n" + print(result) + + self.assertGreater(len(ts), 20*50, "insufficient samples") + self.assertLess(max(ts), 30.) + self.assertLess(np.mean(ts), 10.) + self.assertLess(np.std(ts), 5.) + def test_cpu_usage(self): proclogs = [m for m in self.lr if m.which() == 'procLog'] self.assertGreater(len(proclogs), service_list['procLog'].frequency * 45, "insufficient samples") diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 0fbfb0cfc2..66bc38dbfc 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -176,6 +176,8 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { // NvgWindow NvgWindow::NvgWindow(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraViewWidget("camerad", type, true, parent) { + pm = std::make_unique>({"uiDebug"}); + engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size}); dm_img = loadPixmap("../assets/img_driver_face.png", {img_size, img_size}); } @@ -542,6 +544,8 @@ void NvgWindow::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV } void NvgWindow::paintGL() { + const double start_draw_t = millis_since_boot(); + UIState *s = uiState(); const cereal::ModelDataV2::Reader &model = (*s->sm)["modelV2"].getModelV2(); CameraViewWidget::setFrameId(model.getFrameId()); @@ -575,6 +579,12 @@ void NvgWindow::paintGL() { LOGW("slow frame rate: %.2f fps", fps); } prev_draw_t = cur_draw_t; + + // publish debug msg + MessageBuilder msg; + auto m = msg.initEvent().initUiDebug(); + m.setDrawTimeMillis(cur_draw_t - start_draw_t); + pm->send("uiDebug", msg); } void NvgWindow::showEvent(QShowEvent *event) { diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 25920ccc6a..7ed2c9cc4a 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -68,6 +68,7 @@ private: bool has_eu_speed_limit = false; bool v_ego_cluster_seen = false; int status = STATUS_DISENGAGED; + std::unique_ptr pm; protected: void paintGL() override; From cd12ef4aa19a83f88532f5c1a8c3f290b87fcbf8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 08:18:04 +0800 Subject: [PATCH 20/34] cabana: add a splitter between message lists and detailview (#26118) * add a splitter between message lists and detailview * space --- tools/cabana/mainwin.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 999a4816b0..7aea8097cf 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include MainWindow::MainWindow() : QWidget() { @@ -13,12 +14,16 @@ MainWindow::MainWindow() : QWidget() { QHBoxLayout *h_layout = new QHBoxLayout(); main_layout->addLayout(h_layout); + QSplitter *splitter = new QSplitter(Qt::Horizontal, this); + messages_widget = new MessagesWidget(this); - h_layout->addWidget(messages_widget); + splitter->addWidget(messages_widget); detail_widget = new DetailWidget(this); - detail_widget->setFixedWidth(600); - h_layout->addWidget(detail_widget); + splitter->addWidget(detail_widget); + + splitter->setSizes({100, 500}); + h_layout->addWidget(splitter); // right widgets QWidget *right_container = new QWidget(this); From 409e8f5f89a38f9893a1f28f8fabd3bf526b46eb Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 08:18:24 +0800 Subject: [PATCH 21/34] cabana: faster history log with better stretch mode (#26112) --- tools/cabana/historylog.cc | 59 ++++++++++++++------------------------ tools/cabana/historylog.h | 13 +++++---- 2 files changed, 28 insertions(+), 44 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index cbb3b6e882..c0efbca280 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -5,21 +5,16 @@ #include QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { - auto msg = dbc()->msg(msg_id); + bool has_signal = dbc_msg && !dbc_msg->sigs.empty(); if (role == Qt::DisplayRole) { - const auto &can_msgs = can->messages(msg_id); - if (index.row() < can_msgs.size()) { - const auto &can_data = can_msgs[index.row()]; - if (msg && index.column() < msg->sigs.size()) { - return get_raw_value((uint8_t *)can_data.dat.begin(), can_data.dat.size(), msg->sigs[index.column()]); - } else { - return toHex(can_data.dat); - } - } - } else if (role == Qt::FontRole) { - if (index.column() == 0 && !(msg && msg->sigs.size() > 0)) { - return QFontDatabase::systemFont(QFontDatabase::FixedFont); + const auto &m = can->messages(msg_id)[index.row()]; + if (index.column() == 0) { + return QString::number(m.ts, 'f', 2); } + return has_signal ? QString::number(get_raw_value((uint8_t *)m.dat.begin(), m.dat.size(), dbc_msg->sigs[index.column() - 1])) + : toHex(m.dat); + } else if (role == Qt::FontRole && index.column() == 1 && !has_signal) { + return QFontDatabase::systemFont(QFontDatabase::FixedFont); } return {}; } @@ -27,8 +22,8 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { void HistoryLogModel::setMessage(const QString &message_id) { beginResetModel(); msg_id = message_id; - const auto msg = dbc()->msg(message_id); - column_count = msg && !msg->sigs.empty() ? msg->sigs.size() : 1; + dbc_msg = dbc()->msg(message_id); + column_count = (dbc_msg && !dbc_msg->sigs.empty() ? dbc_msg->sigs.size() : 1) + 1; row_count = 0; endResetModel(); @@ -37,18 +32,14 @@ void HistoryLogModel::setMessage(const QString &message_id) { QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { - auto msg = dbc()->msg(msg_id); - if (msg && section < msg->sigs.size()) { - if (role == Qt::BackgroundRole) { - return QBrush(QColor(getColor(section))); - } else if (role == Qt::DisplayRole || role == Qt::ToolTipRole) { - return QString::fromStdString(msg->sigs[section].name); + bool has_signal = dbc_msg && !dbc_msg->sigs.empty(); + if (role == Qt::DisplayRole || role == Qt::ToolTipRole) { + if (section == 0) { + return "Time"; } - } - } else if (role == Qt::DisplayRole) { - const auto &can_msgs = can->messages(msg_id); - if (section < can_msgs.size()) { - return QString::number(can_msgs[section].ts, 'f', 2); + return has_signal ? dbc_msg->sigs[section - 1].name.c_str() : "Data"; + } else if (role == Qt::BackgroundRole && section > 0 && has_signal) { + return QBrush(QColor(getColor(section - 1))); } } return {}; @@ -69,7 +60,6 @@ void HistoryLogModel::updateState() { } if (row_count > 0) { emit dataChanged(index(0, 0), index(row_count - 1, column_count - 1), {Qt::DisplayRole}); - emit headerDataChanged(Qt::Vertical, 0, row_count - 1); } } @@ -79,17 +69,10 @@ HistoryLog::HistoryLog(QWidget *parent) : QWidget(parent) { model = new HistoryLogModel(this); table = new QTableView(this); table->setModel(model); - table->horizontalHeader()->setStretchLastSection(true); - table->setEditTriggers(QAbstractItemView::NoEditTriggers); + table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); + table->setColumnWidth(0, 60); + table->verticalHeader()->setVisible(false); table->setStyleSheet("QTableView::item { border:0px; padding-left:5px; padding-right:5px; }"); - table->verticalHeader()->setStyleSheet("QHeaderView::section {padding-left: 5px; padding-right: 5px;min-width:40px;}"); main_layout->addWidget(table); } - -void HistoryLog::setMessage(const QString &message_id) { - model->setMessage(message_id); -} - -void HistoryLog::updateState() { - model->updateState(); -} diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index f3a9046bfa..bc6d1f9376 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -6,21 +6,22 @@ #include "tools/cabana/dbcmanager.h" class HistoryLogModel : public QAbstractTableModel { -Q_OBJECT + Q_OBJECT public: HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) {} void setMessage(const QString &message_id); void updateState(); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override { return column_count; } - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override { return row_count; } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return column_count; } private: QString msg_id; int row_count = 0; - int column_count = 0; + int column_count = 2; + const Msg *dbc_msg = nullptr; }; class HistoryLog : public QWidget { @@ -28,8 +29,8 @@ class HistoryLog : public QWidget { public: HistoryLog(QWidget *parent); - void setMessage(const QString &message_id); - void updateState(); + void setMessage(const QString &message_id) { model->setMessage(message_id); } + void updateState() { model->updateState(); } private: QTableView *table; From 99b16151fcc621832d573b9f7858eb5020f6503a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 08:19:41 +0800 Subject: [PATCH 22/34] Cabana: show MSB/LSB of signals in the BinaryView (#26103) * dispaly msb and lsb in binary view * draw at bottom * move binaryview to seperate files * increase the width of vertical header * re-draw changed cells only * correct lsb/msb position * check bounds * todo --- tools/cabana/SConscript | 2 +- tools/cabana/binaryview.cc | 184 +++++++++++++++++++++++++++++++++++ tools/cabana/binaryview.h | 72 ++++++++++++++ tools/cabana/canmessages.h | 1 + tools/cabana/detailwidget.cc | 98 +------------------ tools/cabana/detailwidget.h | 26 +---- tools/cabana/signaledit.cc | 3 + 7 files changed, 265 insertions(+), 121 deletions(-) create mode 100644 tools/cabana/binaryview.cc create mode 100644 tools/cabana/binaryview.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 8dbd4f1d1c..fd44ecd138 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -12,5 +12,5 @@ else: qt_libs = ['qt_util', 'Qt5Charts'] + base_libs cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, opendbc,'avutil', 'avcodec', 'avformat', 'bz2', 'curl', 'yuv'] + qt_libs -qt_env.Program('_cabana', ['cabana.cc', 'mainwin.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', +qt_env.Program('_cabana', ['cabana.cc', 'mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', 'canmessages.cc', 'messageswidget.cc', 'detailwidget.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc new file mode 100644 index 0000000000..3b962b6de1 --- /dev/null +++ b/tools/cabana/binaryview.cc @@ -0,0 +1,184 @@ +#include "tools/cabana/binaryview.h" + +#include +#include +#include + +#include "tools/cabana/canmessages.h" + +// BinaryView + +const int CELL_HEIGHT = 35; + +BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { + model = new BinaryViewModel(this); + setModel(model); + setItemDelegate(new BinaryItemDelegate(this)); + horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + horizontalHeader()->hide(); + verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + // replace selection model + auto old_model = selectionModel(); + setSelectionModel(new BinarySelectionModel(model)); + delete old_model; + + QObject::connect(model, &QAbstractItemModel::modelReset, [this]() { + setFixedHeight((CELL_HEIGHT + 1) * std::min(model->rowCount(), 8) + 2); + }); +} + +void BinaryView::mouseReleaseEvent(QMouseEvent *event) { + QTableView::mouseReleaseEvent(event); + + if (auto indexes = selectedIndexes(); !indexes.isEmpty()) { + int start_bit = indexes.first().row() * 8 + indexes.first().column(); + int size = indexes.back().row() * 8 + indexes.back().column() - start_bit + 1; + emit cellsSelected(start_bit, size); + } +} + +void BinaryView::setMessage(const QString &message_id) { + msg_id = message_id; + model->setMessage(message_id); + resizeRowsToContents(); + clearSelection(); + updateState(); +} + +void BinaryView::updateState() { + model->updateState(); +} + +// BinaryViewModel + +void BinaryViewModel::setMessage(const QString &message_id) { + msg_id = message_id; + + beginResetModel(); + items.clear(); + row_count = 0; + + dbc_msg = dbc()->msg(msg_id); + if (dbc_msg) { + row_count = dbc_msg->size; + items.resize(row_count * column_count); + for (int i = 0; i < dbc_msg->sigs.size(); ++i) { + const auto &sig = dbc_msg->sigs[i]; + const int start = sig.is_little_endian ? sig.start_bit : bigEndianBitIndex(sig.start_bit); + const int end = start + sig.size - 1; + for (int j = start; j <= end; ++j) { + int idx = column_count * (j / 8) + j % 8; + if (idx >= items.size()) { + qWarning() << "signal " << sig.name.c_str() << "out of bounds.start_bit:" << sig.start_bit << "size:" << sig.size; + break; + } + if (j == start) { + sig.is_little_endian ? items[idx].is_lsb = true : items[idx].is_msb = true; + } else if (j == end) { + sig.is_little_endian ? items[idx].is_msb = true : items[idx].is_lsb = true; + } + items[idx].bg_color = QColor(getColor(i)); + } + } + } + + endResetModel(); +} + +QModelIndex BinaryViewModel::index(int row, int column, const QModelIndex &parent) const { + return createIndex(row, column, (void *)&items[row * column_count + column]); +} + +Qt::ItemFlags BinaryViewModel::flags(const QModelIndex &index) const { + return (index.column() == column_count - 1) ? Qt::ItemIsEnabled : Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +void BinaryViewModel::updateState() { + auto prev_items = items; + + const auto &binary = can->lastMessage(msg_id).dat; + // data size may changed. + if (!dbc_msg && binary.size() != row_count) { + beginResetModel(); + row_count = binary.size(); + items.clear(); + items.resize(row_count * column_count); + endResetModel(); + } + + char hex[3] = {'\0'}; + for (int i = 0; i < std::min(binary.size(), row_count); ++i) { + for (int j = 0; j < column_count - 1; ++j) { + items[i * column_count + j].val = QChar((binary[i] >> (7 - j)) & 1 ? '1' : '0'); + } + hex[0] = toHex(binary[i] >> 4); + hex[1] = toHex(binary[i] & 0xf); + items[i * column_count + 8].val = hex; + } + + for (int i = 0; i < items.size(); ++i) { + if (i >= prev_items.size() || prev_items[i].val != items[i].val) { + auto idx = index(i / column_count, i % column_count); + emit dataChanged(idx, idx); + } + } +} + +QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (orientation == Qt::Vertical) { + switch (role) { + case Qt::DisplayRole: return section + 1; + case Qt::SizeHintRole: return QSize(30, CELL_HEIGHT); + case Qt::TextAlignmentRole: return Qt::AlignCenter; + } + } + return {}; +} + +// BinarySelectionModel + +void BinarySelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) { + QItemSelection new_selection = selection; + if (auto indexes = selection.indexes(); !indexes.isEmpty()) { + auto [begin_idx, end_idx] = (QModelIndex[]){indexes.first(), indexes.back()}; + for (int row = begin_idx.row(); row <= end_idx.row(); ++row) { + int left_col = (row == begin_idx.row()) ? begin_idx.column() : 0; + int right_col = (row == end_idx.row()) ? end_idx.column() : 7; + new_selection.merge({model()->index(row, left_col), model()->index(row, right_col)}, command); + } + } + QItemSelectionModel::select(new_selection, command); +} + +// BinaryItemDelegate + +BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { + // cache fonts and color + small_font.setPointSize(7); + bold_font.setBold(true); + highlight_color = QApplication::style()->standardPalette().color(QPalette::Active, QPalette::Highlight); +} + +QSize BinaryItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { + QSize sz = QStyledItemDelegate::sizeHint(option, index); + return {sz.width(), CELL_HEIGHT}; +} + +void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + auto item = (const BinaryViewModel::Item *)index.internalPointer(); + painter->save(); + // TODO: highlight signal cells on mouse over + painter->fillRect(option.rect, option.state & QStyle::State_Selected ? highlight_color : item->bg_color); + if (index.column() == 8) { + painter->setFont(bold_font); + } + painter->drawText(option.rect, Qt::AlignCenter, item->val); + if (item->is_msb || item->is_lsb) { + painter->setFont(small_font); + painter->drawText(option.rect, Qt::AlignHCenter | Qt::AlignBottom, item->is_msb ? "MSB" : "LSB"); + } + + painter->restore(); +} diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h new file mode 100644 index 0000000000..631797ca48 --- /dev/null +++ b/tools/cabana/binaryview.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +#include "tools/cabana/dbcmanager.h" + +class BinaryItemDelegate : public QStyledItemDelegate { + Q_OBJECT + +public: + BinaryItemDelegate(QObject *parent); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + +private: + QFont small_font, bold_font; + QColor highlight_color; +}; + +class BinaryViewModel : public QAbstractTableModel { + Q_OBJECT + +public: + BinaryViewModel(QObject *parent) : QAbstractTableModel(parent) {} + void setMessage(const QString &message_id); + void updateState(); + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { return {}; } + int rowCount(const QModelIndex &parent = QModelIndex()) const override { return row_count; } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return column_count; } + + struct Item { + QColor bg_color = QColor(Qt::white); + bool is_msb = false; + bool is_lsb = false; + QString val = "0"; + }; + +private: + QString msg_id; + const Msg *dbc_msg; + int row_count = 0; + const int column_count = 9; + std::vector items; +}; + +// the default QItemSelectionModel does not support our selection mode. +class BinarySelectionModel : public QItemSelectionModel { + public: + BinarySelectionModel(QAbstractItemModel *model = nullptr) : QItemSelectionModel(model) {} + void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override; +}; + +class BinaryView : public QTableView { + Q_OBJECT + +public: + BinaryView(QWidget *parent = nullptr); + void mouseReleaseEvent(QMouseEvent *event) override; + void setMessage(const QString &message_id); + void updateState(); + +signals: + void cellsSelected(int start_bit, int size); + +private: + QString msg_id; + BinaryViewModel *model; +}; diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 7f6955369b..fe71840d74 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -91,6 +91,7 @@ inline char toHex(uint value) { } inline const QString &getColor(int i) { + // TODO: add more colors static const QString SIGNAL_COLORS[] = {"#9FE2BF", "#40E0D0", "#6495ED", "#CCCCFF", "#FF7F50", "#FFBF00"}; return SIGNAL_COLORS[i % std::size(SIGNAL_COLORS)]; } diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index a9899ec650..60d0632d4c 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -1,13 +1,13 @@ #include "tools/cabana/detailwidget.h" #include -#include #include -#include #include -#include #include +#include "tools/cabana/canmessages.h" +#include "tools/cabana/dbcmanager.h" + // DetailWidget DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { @@ -141,98 +141,6 @@ void DetailWidget::removeSignal() { } } -// BinaryView - -BinaryView::BinaryView(QWidget *parent) : QTableWidget(parent) { - horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); - verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); - horizontalHeader()->hide(); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setColumnCount(9); - - // replace selection model - auto old_model = selectionModel(); - setSelectionModel(new BinarySelectionModel(model())); - delete old_model; -} - -void BinaryView::mouseReleaseEvent(QMouseEvent *event) { - QTableWidget::mouseReleaseEvent(event); - - if (auto items = selectedItems(); !items.isEmpty()) { - int start_bit = items.first()->row() * 8 + items.first()->column(); - int size = items.back()->row() * 8 + items.back()->column() - start_bit + 1; - emit cellsSelected(start_bit, size); - } -} - -void BinaryView::setMessage(const QString &message_id) { - msg_id = message_id; - if (msg_id.isEmpty()) return; - - const Msg *msg = dbc()->msg(msg_id); - int row_count = msg ? msg->size : can->lastMessage(msg_id).dat.size(); - setRowCount(row_count); - setColumnCount(9); - for (int i = 0; i < rowCount(); ++i) { - for (int j = 0; j < columnCount(); ++j) { - auto item = new QTableWidgetItem(); - item->setFlags(item->flags() ^ Qt::ItemIsEditable); - item->setTextAlignment(Qt::AlignCenter); - if (j == 8) { - QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); - font.setBold(true); - item->setFont(font); - item->setFlags(item->flags() ^ Qt::ItemIsSelectable); - } - setItem(i, j, item); - } - } - - // set background color - if (msg) { - for (int i = 0; i < msg->sigs.size(); ++i) { - const auto &sig = msg->sigs[i]; - int start = sig.is_little_endian ? sig.start_bit : bigEndianBitIndex(sig.start_bit); - for (int j = start; j <= std::min(start + sig.size - 1, rowCount() * columnCount() - 1); ++j) { - item(j / 8, j % 8)->setBackground(QColor(getColor(i))); - } - } - } - - setFixedHeight(rowHeight(0) * std::min(row_count, 8) + 2); - clearSelection(); - updateState(); -} - -void BinaryView::updateState() { - const auto &binary = can->lastMessage(msg_id).dat; - setUpdatesEnabled(false); - char hex[3] = {'\0'}; - for (int i = 0; i < binary.size(); ++i) { - for (int j = 0; j < 8; ++j) { - item(i, j)->setText(QChar((binary[i] >> (7 - j)) & 1 ? '1' : '0')); - } - hex[0] = toHex(binary[i] >> 4); - hex[1] = toHex(binary[i] & 0xf); - item(i, 8)->setText(hex); - } - setUpdatesEnabled(true); -} - -void BinarySelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) { - QItemSelection new_selection = selection; - if (auto indexes = selection.indexes(); !indexes.isEmpty()) { - auto [begin_idx, end_idx] = (QModelIndex[]){indexes.first(), indexes.back()}; - for (int row = begin_idx.row(); row <= end_idx.row(); ++row) { - int left_col = (row == begin_idx.row()) ? begin_idx.column() : 0; - int right_col = (row == end_idx.row()) ? end_idx.column() : 7; - new_selection.merge({model()->index(row, left_col), model()->index(row, right_col)}, command); - } - } - QItemSelectionModel::select(new_selection, command); -} - // EditMessageDialog EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent) : QDialog(parent) { diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index db174873f7..9d3b81dcb0 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -1,35 +1,11 @@ #pragma once #include -#include -#include "opendbc/can/common.h" -#include "opendbc/can/common_dbc.h" -#include "tools/cabana/canmessages.h" -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/binaryview.h" #include "tools/cabana/historylog.h" #include "tools/cabana/signaledit.h" -class BinarySelectionModel : public QItemSelectionModel { -public: - BinarySelectionModel(QAbstractItemModel *model = nullptr) : QItemSelectionModel(model) {} - void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override; -}; - -class BinaryView : public QTableWidget { - Q_OBJECT -public: - BinaryView(QWidget *parent = nullptr); - void mouseReleaseEvent(QMouseEvent *event) override; - void setMessage(const QString &message_id); - void updateState(); -signals: - void cellsSelected(int start_bit, int size); - -private: - QString msg_id; -}; - class EditMessageDialog : public QDialog { Q_OBJECT diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 2da3e2eec2..b52f83dab6 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -23,6 +23,9 @@ SignalForm::SignalForm(const Signal &sig, QWidget *parent) : start_bit(sig.start endianness->setCurrentIndex(sig.is_little_endian ? 0 : 1); form_layout->addRow(tr("Endianness"), endianness); + form_layout->addRow(tr("lsb"), new QLabel(QString::number(sig.lsb))); + form_layout->addRow(tr("msb"), new QLabel(QString::number(sig.msb))); + sign = new QComboBox(); sign->addItems({"Signed", "Unsigned"}); sign->setCurrentIndex(sig.is_signed ? 0 : 1); From c782e4d796e0981b3717222cb5551911fe40cb7a Mon Sep 17 00:00:00 2001 From: Jake Poznanski Date: Mon, 17 Oct 2022 17:22:47 -0700 Subject: [PATCH 23/34] loggerd: fix length of ArrayPtr in handle_encoder_msg (#26077) --- selfdrive/loggerd/loggerd.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/loggerd/loggerd.cc b/selfdrive/loggerd/loggerd.cc index e0892e68b4..9beb3c3bf1 100644 --- a/selfdrive/loggerd/loggerd.cc +++ b/selfdrive/loggerd/loggerd.cc @@ -55,7 +55,7 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct int bytes_count = 0; // extract the message - capnp::FlatArrayMessageReader cmsg(kj::ArrayPtr((capnp::word *)msg->getData(), msg->getSize())); + capnp::FlatArrayMessageReader cmsg(kj::ArrayPtr((capnp::word *)msg->getData(), msg->getSize() / sizeof(capnp::word))); auto event = cmsg.getRoot(); auto edata = (name == "driverEncodeData") ? event.getDriverEncodeData() : ((name == "wideRoadEncodeData") ? event.getWideRoadEncodeData() : From baca1cae1f71c70162374c887cf36d5cf828f2f3 Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Mon, 17 Oct 2022 18:18:01 -0700 Subject: [PATCH 24/34] UI Onroad widget renames (#26124) Consistent widget naming --- selfdrive/ui/qt/offroad/driverview.cc | 4 +-- selfdrive/ui/qt/offroad/driverview.h | 2 +- selfdrive/ui/qt/onroad.cc | 45 ++++++++++++----------- selfdrive/ui/qt/onroad.h | 6 ++-- selfdrive/ui/qt/widgets/cameraview.cc | 26 +++++++------- selfdrive/ui/qt/widgets/cameraview.h | 6 ++-- selfdrive/ui/translations/main_ar.ts | 2 +- selfdrive/ui/translations/main_ja.ts | 46 ++++++++++++------------ selfdrive/ui/translations/main_ko.ts | 46 ++++++++++++------------ selfdrive/ui/translations/main_nl.ts | 2 +- selfdrive/ui/translations/main_pl.ts | 2 +- selfdrive/ui/translations/main_pt-BR.ts | 46 ++++++++++++------------ selfdrive/ui/translations/main_th.ts | 2 +- selfdrive/ui/translations/main_zh-CHS.ts | 46 ++++++++++++------------ selfdrive/ui/translations/main_zh-CHT.ts | 46 ++++++++++++------------ selfdrive/ui/watch3.cc | 8 ++--- tools/cabana/videowidget.cc | 6 ++-- tools/cabana/videowidget.h | 2 +- 18 files changed, 173 insertions(+), 170 deletions(-) diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc index be8b84d45e..0ff786fb91 100644 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ b/selfdrive/ui/qt/offroad/driverview.cc @@ -12,11 +12,11 @@ DriverViewWindow::DriverViewWindow(QWidget* parent) : QWidget(parent) { layout = new QStackedLayout(this); layout->setStackingMode(QStackedLayout::StackAll); - cameraView = new CameraViewWidget("camerad", VISION_STREAM_DRIVER, true, this); + cameraView = new CameraWidget("camerad", VISION_STREAM_DRIVER, true, this); layout->addWidget(cameraView); scene = new DriverViewScene(this); - connect(cameraView, &CameraViewWidget::vipcThreadFrameReceived, scene, &DriverViewScene::frameUpdated); + connect(cameraView, &CameraWidget::vipcThreadFrameReceived, scene, &DriverViewScene::frameUpdated); layout->addWidget(scene); layout->setCurrentWidget(scene); } diff --git a/selfdrive/ui/qt/offroad/driverview.h b/selfdrive/ui/qt/offroad/driverview.h index 5d090ad772..255857970d 100644 --- a/selfdrive/ui/qt/offroad/driverview.h +++ b/selfdrive/ui/qt/offroad/driverview.h @@ -42,7 +42,7 @@ protected: void mouseReleaseEvent(QMouseEvent* e) override; private: - CameraViewWidget *cameraView; + CameraWidget *cameraView; DriverViewScene *scene; QStackedLayout *layout; }; diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 66bc38dbfc..1f677fc92d 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -18,7 +18,7 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { stacked_layout->setStackingMode(QStackedLayout::StackAll); main_layout->addLayout(stacked_layout); - nvg = new NvgWindow(VISION_STREAM_ROAD, this); + nvg = new AnnotatedCameraWidget(VISION_STREAM_ROAD, this); QWidget * split_wrapper = new QWidget; split = new QHBoxLayout(split_wrapper); @@ -27,7 +27,7 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { split->addWidget(nvg); if (getenv("DUAL_CAMERA_VIEW")) { - CameraViewWidget *arCam = new CameraViewWidget("camerad", VISION_STREAM_ROAD, true, this); + CameraWidget *arCam = new CameraWidget("camerad", VISION_STREAM_ROAD, true, this); split->insertWidget(0, arCam); } @@ -173,16 +173,15 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { } } -// NvgWindow -NvgWindow::NvgWindow(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraViewWidget("camerad", type, true, parent) { +AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { pm = std::make_unique>({"uiDebug"}); engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size}); dm_img = loadPixmap("../assets/img_driver_face.png", {img_size, img_size}); } -void NvgWindow::updateState(const UIState &s) { +void AnnotatedCameraWidget::updateState(const UIState &s) { const int SET_SPEED_NA = 255; const SubMaster &sm = *(s.sm); @@ -234,13 +233,13 @@ void NvgWindow::updateState(const UIState &s) { } if (s.scene.calibration_valid) { - CameraViewWidget::updateCalibration(s.scene.view_from_calib); + CameraWidget::updateCalibration(s.scene.view_from_calib); } else { - CameraViewWidget::updateCalibration(DEFAULT_CALIBRATION); + CameraWidget::updateCalibration(DEFAULT_CALIBRATION); } } -void NvgWindow::drawHud(QPainter &p) { +void AnnotatedCameraWidget::drawHud(QPainter &p) { p.save(); // Header gradient @@ -402,7 +401,11 @@ void NvgWindow::drawHud(QPainter &p) { p.restore(); } -void NvgWindow::drawText(QPainter &p, int x, int y, const QString &text, int alpha) { + +// Window that shows camera view and variety of +// info drawn on top + +void AnnotatedCameraWidget::drawText(QPainter &p, int x, int y, const QString &text, int alpha) { QRect real_rect = getTextRect(p, 0, text); real_rect.moveCenter({x, y - real_rect.height() / 2}); @@ -410,7 +413,7 @@ void NvgWindow::drawText(QPainter &p, int x, int y, const QString &text, int alp p.drawText(real_rect.x(), real_rect.bottom(), text); } -void NvgWindow::drawIcon(QPainter &p, int x, int y, QPixmap &img, QBrush bg, float opacity) { +void AnnotatedCameraWidget::drawIcon(QPainter &p, int x, int y, QPixmap &img, QBrush bg, float opacity) { p.setPen(Qt::NoPen); p.setBrush(bg); p.drawEllipse(x - radius / 2, y - radius / 2, radius, radius); @@ -419,8 +422,8 @@ void NvgWindow::drawIcon(QPainter &p, int x, int y, QPixmap &img, QBrush bg, flo } -void NvgWindow::initializeGL() { - CameraViewWidget::initializeGL(); +void AnnotatedCameraWidget::initializeGL() { + CameraWidget::initializeGL(); qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION)); qInfo() << "OpenGL vendor:" << QString((const char*)glGetString(GL_VENDOR)); qInfo() << "OpenGL renderer:" << QString((const char*)glGetString(GL_RENDERER)); @@ -430,8 +433,8 @@ void NvgWindow::initializeGL() { setBackgroundColor(bg_colors[STATUS_DISENGAGED]); } -void NvgWindow::updateFrameMat() { - CameraViewWidget::updateFrameMat(); +void AnnotatedCameraWidget::updateFrameMat() { + CameraWidget::updateFrameMat(); UIState *s = uiState(); int w = width(), h = height(); @@ -448,7 +451,7 @@ void NvgWindow::updateFrameMat() { .translate(-intrinsic_matrix.v[2], -intrinsic_matrix.v[5]); } -void NvgWindow::drawLaneLines(QPainter &painter, const UIState *s) { +void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { painter.save(); const UIScene &scene = s->scene; @@ -507,7 +510,7 @@ void NvgWindow::drawLaneLines(QPainter &painter, const UIState *s) { painter.restore(); } -void NvgWindow::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV3::Reader &lead_data, const QPointF &vd) { +void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV3::Reader &lead_data, const QPointF &vd) { painter.save(); const float speedBuff = 10.; @@ -543,13 +546,13 @@ void NvgWindow::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV painter.restore(); } -void NvgWindow::paintGL() { +void AnnotatedCameraWidget::paintGL() { const double start_draw_t = millis_since_boot(); UIState *s = uiState(); const cereal::ModelDataV2::Reader &model = (*s->sm)["modelV2"].getModelV2(); - CameraViewWidget::setFrameId(model.getFrameId()); - CameraViewWidget::paintGL(); + CameraWidget::setFrameId(model.getFrameId()); + CameraWidget::paintGL(); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); @@ -587,8 +590,8 @@ void NvgWindow::paintGL() { pm->send("uiDebug", msg); } -void NvgWindow::showEvent(QShowEvent *event) { - CameraViewWidget::showEvent(event); +void AnnotatedCameraWidget::showEvent(QShowEvent *event) { + CameraWidget::showEvent(event); ui_update_params(uiState()); prev_draw_t = millis_since_boot(); diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 7ed2c9cc4a..2a663185f4 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -25,7 +25,7 @@ private: }; // container window for the NVG UI -class NvgWindow : public CameraViewWidget { +class AnnotatedCameraWidget : public CameraWidget { Q_OBJECT Q_PROPERTY(float speed MEMBER speed); Q_PROPERTY(QString speedUnit MEMBER speedUnit); @@ -43,7 +43,7 @@ class NvgWindow : public CameraViewWidget { Q_PROPERTY(int status MEMBER status); public: - explicit NvgWindow(VisionStreamType type, QWidget* parent = 0); + explicit AnnotatedCameraWidget(VisionStreamType type, QWidget* parent = 0); void updateState(const UIState &s); private: @@ -98,7 +98,7 @@ private: void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent* e) override; OnroadAlerts *alerts; - NvgWindow *nvg; + AnnotatedCameraWidget *nvg; QColor bg = bg_colors[STATUS_DISENGAGED]; QWidget *map = nullptr; QHBoxLayout* split; diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 63d15660a0..200257235d 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -93,14 +93,14 @@ mat4 get_fit_view_transform(float widget_aspect_ratio, float frame_aspect_ratio) } // namespace -CameraViewWidget::CameraViewWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) : +CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) : stream_name(stream_name), stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { setAttribute(Qt::WA_OpaquePaintEvent); - connect(this, &CameraViewWidget::vipcThreadConnected, this, &CameraViewWidget::vipcConnected, Qt::BlockingQueuedConnection); - connect(this, &CameraViewWidget::vipcThreadFrameReceived, this, &CameraViewWidget::vipcFrameReceived); + connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); + connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived); } -CameraViewWidget::~CameraViewWidget() { +CameraWidget::~CameraWidget() { makeCurrent(); if (isValid()) { glDeleteVertexArrays(1, &frame_vao); @@ -111,7 +111,7 @@ CameraViewWidget::~CameraViewWidget() { doneCurrent(); } -void CameraViewWidget::initializeGL() { +void CameraWidget::initializeGL() { initializeOpenGLFunctions(); program = std::make_unique(context()); @@ -161,7 +161,7 @@ void CameraViewWidget::initializeGL() { #endif } -void CameraViewWidget::showEvent(QShowEvent *event) { +void CameraWidget::showEvent(QShowEvent *event) { frames.clear(); if (!vipc_thread) { vipc_thread = new QThread(); @@ -171,7 +171,7 @@ void CameraViewWidget::showEvent(QShowEvent *event) { } } -void CameraViewWidget::hideEvent(QHideEvent *event) { +void CameraWidget::hideEvent(QHideEvent *event) { if (vipc_thread) { vipc_thread->requestInterruption(); vipc_thread->quit(); @@ -180,7 +180,7 @@ void CameraViewWidget::hideEvent(QHideEvent *event) { } } -void CameraViewWidget::updateFrameMat() { +void CameraWidget::updateFrameMat() { int w = width(), h = height(); if (zoomed_view) { @@ -224,12 +224,12 @@ void CameraViewWidget::updateFrameMat() { } } -void CameraViewWidget::updateCalibration(const mat3 &calib) { +void CameraWidget::updateCalibration(const mat3 &calib) { calibration = calib; updateFrameMat(); } -void CameraViewWidget::paintGL() { +void CameraWidget::paintGL() { glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); @@ -286,7 +286,7 @@ void CameraViewWidget::paintGL() { glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } -void CameraViewWidget::vipcConnected(VisionIpcClient *vipc_client) { +void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { makeCurrent(); frames.clear(); stream_width = vipc_client->buffers[0].width; @@ -339,7 +339,7 @@ void CameraViewWidget::vipcConnected(VisionIpcClient *vipc_client) { updateFrameMat(); } -void CameraViewWidget::vipcFrameReceived(VisionBuf *buf, uint32_t frame_id) { +void CameraWidget::vipcFrameReceived(VisionBuf *buf, uint32_t frame_id) { frames.push_back(std::make_pair(frame_id, buf)); while (frames.size() > FRAME_BUFFER_SIZE) { frames.pop_front(); @@ -347,7 +347,7 @@ void CameraViewWidget::vipcFrameReceived(VisionBuf *buf, uint32_t frame_id) { update(); } -void CameraViewWidget::vipcThread() { +void CameraWidget::vipcThread() { VisionStreamType cur_stream_type = stream_type; std::unique_ptr vipc_client; VisionIpcBufExtra meta_main = {0}; diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index 081483b649..9bcad935c0 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -23,13 +23,13 @@ const int FRAME_BUFFER_SIZE = 5; static_assert(FRAME_BUFFER_SIZE <= YUV_BUFFER_COUNT); -class CameraViewWidget : public QOpenGLWidget, protected QOpenGLFunctions { +class CameraWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: using QOpenGLWidget::QOpenGLWidget; - explicit CameraViewWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr); - ~CameraViewWidget(); + explicit CameraWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr); + ~CameraWidget(); void setStreamType(VisionStreamType type) { stream_type = type; } void setBackgroundColor(const QColor &color) { bg = color; } void setFrameId(int frame_id) { draw_frame_id = frame_id; } diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index 284208720b..a94d2fbc05 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -493,7 +493,7 @@ location set - NvgWindow + AnnotatedCameraWidget km/h diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index b39c83c098..314a6b8338 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -67,6 +67,29 @@ + + AnnotatedCameraWidget + + km/h + km/h + + + mph + mph + + + MAX + 最高速度 + + + SPEED + 速度 + + + LIMIT + 制限速度 + + ConfirmationDialog @@ -406,29 +429,6 @@ location set パスワードが間違っています - - NvgWindow - - km/h - km/h - - - mph - mph - - - MAX - 最高速度 - - - SPEED - 速度 - - - LIMIT - 制限速度 - - OffroadHome diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index f84797eb60..021243595e 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -67,6 +67,29 @@ 데이터 요금제 연결 시 대용량 데이터 업로드 방지 + + AnnotatedCameraWidget + + km/h + km/h + + + mph + mph + + + MAX + MAX + + + SPEED + SPEED + + + LIMIT + LIMIT + + ConfirmationDialog @@ -406,29 +429,6 @@ location set 비밀번호가 틀렸습니다 - - NvgWindow - - km/h - km/h - - - mph - mph - - - MAX - MAX - - - SPEED - SPEED - - - LIMIT - LIMIT - - OffroadHome diff --git a/selfdrive/ui/translations/main_nl.ts b/selfdrive/ui/translations/main_nl.ts index 99646ed749..21bb66d356 100644 --- a/selfdrive/ui/translations/main_nl.ts +++ b/selfdrive/ui/translations/main_nl.ts @@ -489,7 +489,7 @@ ingesteld - NvgWindow + AnnotatedCameraWidget km/h diff --git a/selfdrive/ui/translations/main_pl.ts b/selfdrive/ui/translations/main_pl.ts index 8593d68261..92902d04a9 100644 --- a/selfdrive/ui/translations/main_pl.ts +++ b/selfdrive/ui/translations/main_pl.ts @@ -490,7 +490,7 @@ nie zostało ustawione - NvgWindow + AnnotatedCameraWidget km/h diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 8f59bf4715..2afdaf3388 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -67,6 +67,29 @@ Evite grandes uploads de dados quando estiver em uma conexão limitada + + AnnotatedCameraWidget + + km/h + km/h + + + mph + mph + + + MAX + LIMITE + + + SPEED + MAX + + + LIMIT + VELO + + ConfirmationDialog @@ -407,29 +430,6 @@ trabalho definido Senha incorreta - - NvgWindow - - km/h - km/h - - - mph - mph - - - MAX - LIMITE - - - SPEED - MAX - - - LIMIT - VELO - - OffroadHome diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index 7e7fcf2788..d502c3fce1 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -488,7 +488,7 @@ location set - NvgWindow + AnnotatedCameraWidget km/h diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 1d942387e0..9e7c354444 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -67,6 +67,29 @@ + + AnnotatedCameraWidget + + km/h + km/h + + + mph + mph + + + MAX + 最高定速 + + + SPEED + SPEED + + + LIMIT + LIMIT + + ConfirmationDialog @@ -404,29 +427,6 @@ location set 密码错误 - - NvgWindow - - km/h - km/h - - - mph - mph - - - MAX - 最高定速 - - - SPEED - SPEED - - - LIMIT - LIMIT - - OffroadHome diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 816d4fd3cc..513135c7f4 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -67,6 +67,29 @@ + + AnnotatedCameraWidget + + km/h + km/h + + + mph + mph + + + MAX + 最高 + + + SPEED + 速度 + + + LIMIT + 速限 + + ConfirmationDialog @@ -406,29 +429,6 @@ location set 密碼錯誤 - - NvgWindow - - km/h - km/h - - - mph - mph - - - MAX - 最高 - - - SPEED - 速度 - - - LIMIT - 速限 - - OffroadHome diff --git a/selfdrive/ui/watch3.cc b/selfdrive/ui/watch3.cc index d6b5cc67a7..ec35c29b6b 100644 --- a/selfdrive/ui/watch3.cc +++ b/selfdrive/ui/watch3.cc @@ -19,15 +19,15 @@ int main(int argc, char *argv[]) { { QHBoxLayout *hlayout = new QHBoxLayout(); layout->addLayout(hlayout); - hlayout->addWidget(new CameraViewWidget("navd", VISION_STREAM_MAP, false)); - hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_ROAD, false)); + hlayout->addWidget(new CameraWidget("navd", VISION_STREAM_MAP, false)); + hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_ROAD, false)); } { QHBoxLayout *hlayout = new QHBoxLayout(); layout->addLayout(hlayout); - hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_DRIVER, false)); - hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_WIDE_ROAD, false)); + hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_DRIVER, false)); + hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_WIDE_ROAD, false)); } return a.exec(); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index b6fe8de3e2..bb90d56570 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -16,8 +16,8 @@ inline QString formatTime(int seconds) { VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); - // TODO: figure out why the CameraViewWidget crashed occasionally. - cam_widget = new CameraViewWidget("camerad", VISION_STREAM_ROAD, false, this); + // TODO: figure out why the CameraWidget crashed occasionally. + cam_widget = new CameraWidget("camerad", VISION_STREAM_ROAD, false, this); cam_widget->setFixedSize(parent->width(), parent->width() / 1.596); main_layout->addWidget(cam_widget); @@ -60,7 +60,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->value() / 1000.0); }); QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(formatTime(value / 1000)); }); - QObject::connect(cam_widget, &CameraViewWidget::clicked, [this]() { pause(!can->isPaused()); }); + QObject::connect(cam_widget, &CameraWidget::clicked, [this]() { pause(!can->isPaused()); }); QObject::connect(play_btn, &QPushButton::clicked, [=]() { pause(!can->isPaused()); }); } diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index fd896f1e11..d6d036c461 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -32,7 +32,7 @@ protected: void updateState(); void pause(bool pause); - CameraViewWidget *cam_widget; + CameraWidget *cam_widget; QLabel *end_time_label; QPushButton *play_btn; Slider *slider; From 755a6c0a46f07cdadb06821ced904af458fbf4e3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 17 Oct 2022 19:15:21 -0700 Subject: [PATCH 25/34] Revert "tools/replay: reduce test running time (#26110)" This reverts commit 6d07268ee5b385010961eab206b0b42a0ae6b5f8. --- tools/replay/tests/test_replay.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/replay/tests/test_replay.cc b/tools/replay/tests/test_replay.cc index 3fd410bb6e..5b61b6b6f2 100644 --- a/tools/replay/tests/test_replay.cc +++ b/tools/replay/tests/test_replay.cc @@ -207,7 +207,8 @@ void TestReplay::test_seek() { } TEST_CASE("Replay") { - TestReplay replay(DEMO_ROUTE, (uint8_t)REPLAY_FLAG_NO_VIPC); + auto flag = GENERATE(REPLAY_FLAG_NO_FILE_CACHE, REPLAY_FLAG_NONE); + TestReplay replay(DEMO_ROUTE, flag); REQUIRE(replay.load()); replay.test_seek(); } From d522492ba0b80928adc475c1f37b995834c31a90 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Mon, 17 Oct 2022 19:40:06 -0700 Subject: [PATCH 26/34] DM: add use of e2e preds (#26078) * try ml * de56 * j914ef75a * jd1124586 * jd1124586 * d112 * oops * set * update ref * use offset * bump DM power usage * new ref --- .../modeld/models/dmonitoring_model.current | 4 ++-- .../modeld/models/dmonitoring_model.onnx | 4 ++-- .../modeld/models/dmonitoring_model_q.dlc | 4 ++-- selfdrive/monitoring/driver_monitor.py | 21 +++++++++---------- .../process_replay/model_replay_ref_commit | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- system/hardware/tici/test_power_draw.py | 2 +- 7 files changed, 19 insertions(+), 20 deletions(-) diff --git a/selfdrive/modeld/models/dmonitoring_model.current b/selfdrive/modeld/models/dmonitoring_model.current index d1e7d1136f..065bc7d489 100644 --- a/selfdrive/modeld/models/dmonitoring_model.current +++ b/selfdrive/modeld/models/dmonitoring_model.current @@ -1,2 +1,2 @@ -ee8f830b-d6a1-42ef-9b1b-50fd0b2faae4 -cac8f7b69d420506707ff7a19d573d5011ef2533 \ No newline at end of file +d1124586-761e-4e18-a771-6b5ef35124fe +6fec774f513a19e44d4316e46ad38277197d45ea \ No newline at end of file diff --git a/selfdrive/modeld/models/dmonitoring_model.onnx b/selfdrive/modeld/models/dmonitoring_model.onnx index 4cbd6bb7dd..f8bf94c061 100644 --- a/selfdrive/modeld/models/dmonitoring_model.onnx +++ b/selfdrive/modeld/models/dmonitoring_model.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:932e589e5cce66e5d9f48492426a33c74cd7f352a870d3ddafcede3e9156f30d -size 9157561 +oid sha256:517262fa9f1ad3cc8049ad3722903f40356d87ea423ee5cf011226fb6cfc3d5b +size 16072278 diff --git a/selfdrive/modeld/models/dmonitoring_model_q.dlc b/selfdrive/modeld/models/dmonitoring_model_q.dlc index 94632030ed..e4e6fb3347 100644 --- a/selfdrive/modeld/models/dmonitoring_model_q.dlc +++ b/selfdrive/modeld/models/dmonitoring_model_q.dlc @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3587976a8b7e3be274fa86c2e2233e3e464cad713f5077c4394cd1ddd3c7c6c5 -size 2636965 +oid sha256:64b94659226a1e3c6594a13c2e5d029465d5803a5c3005121ec7217acdbbef20 +size 4443461 diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py index 9ff3125c15..30781f4d1b 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -29,10 +29,10 @@ class DRIVER_MONITOR_SETTINGS(): self._FACE_THRESHOLD = 0.7 self._EYE_THRESHOLD = 0.65 self._SG_THRESHOLD = 0.9 - self._BLINK_THRESHOLD = 0.87 + self._BLINK_THRESHOLD = 0.895 - self._EE_THRESH11 = 0.75 - self._EE_THRESH12 = 3.25 + self._EE_THRESH11 = 0.275 + self._EE_THRESH12 = 3.0 self._EE_THRESH21 = 0.01 self._EE_THRESH22 = 0.35 @@ -207,11 +207,11 @@ class DriverStatus(): ee1_dist = self.eev1 > self.ee1_offseter.filtered_stat.M * self.settings._EE_THRESH12 else: ee1_dist = self.eev1 > self.settings._EE_THRESH11 - if self.ee2_calibrated: - ee2_dist = self.eev2 < self.ee2_offseter.filtered_stat.M * self.settings._EE_THRESH22 - else: - ee2_dist = self.eev2 < self.settings._EE_THRESH21 - if ee1_dist or ee2_dist: + # if self.ee2_calibrated: + # ee2_dist = self.eev2 < self.ee2_offseter.filtered_stat.M * self.settings._EE_THRESH22 + # else: + # ee2_dist = self.eev2 < self.settings._EE_THRESH21 + if ee1_dist: distracted_types.append(DistractedType.DISTRACTED_E2E) return distracted_types @@ -257,12 +257,11 @@ class DriverStatus(): self.pose.low_std = model_std_max < self.settings._POSESTD_THRESHOLD self.blink.left_blink = driver_data.leftBlinkProb * (driver_data.leftEyeProb > self.settings._EYE_THRESHOLD) * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD) self.blink.right_blink = driver_data.rightBlinkProb * (driver_data.rightEyeProb > self.settings._EYE_THRESHOLD) * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD) - self.eev1 = driver_data.notReadyProb[1] + self.eev1 = driver_data.notReadyProb[0] self.eev2 = driver_data.readyProb[0] self.distracted_types = self._get_distracted_types() - self.driver_distracted = (DistractedType.DISTRACTED_POSE in self.distracted_types or - DistractedType.DISTRACTED_BLINK in self.distracted_types) and \ + self.driver_distracted = (DistractedType.DISTRACTED_E2E in self.distracted_types or DistractedType.DISTRACTED_POSE in self.distracted_types or DistractedType.DISTRACTED_BLINK in self.distracted_types) and \ driver_data.faceProb > self.settings._FACE_THRESHOLD and self.pose.low_std self.driver_distraction_filter.update(self.driver_distracted) diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index b3e9c8c488..5bb045ec29 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -bfb0a2a52212d2aa1619d999aaae97fa7f7ff788 +865885fc49b2766326568e5cc7ec06be8a3f6fad diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 864b7019a0..998bf4e756 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -e5a86c14e2318f2dd218b3985cdbea6f875f7d83 +6bb7d8baae51d88dd61f0baf561e386664ddd266 \ No newline at end of file diff --git a/system/hardware/tici/test_power_draw.py b/system/hardware/tici/test_power_draw.py index 4830975917..2460152998 100755 --- a/system/hardware/tici/test_power_draw.py +++ b/system/hardware/tici/test_power_draw.py @@ -21,7 +21,7 @@ class Proc: PROCS = [ Proc('camerad', 2.15), Proc('modeld', 1.15, atol=0.2), - Proc('dmonitoringmodeld', 0.35), + Proc('dmonitoringmodeld', 0.4), Proc('encoderd', 0.23), ] From 988fede1858486ec0679f208540a88533e9296e3 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 12:00:07 +0800 Subject: [PATCH 27/34] cabana: reduce the padding in DetailsView (#26126) --- tools/cabana/binaryview.cc | 4 ++-- tools/cabana/signaledit.cc | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 3b962b6de1..71175e783e 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -8,7 +8,7 @@ // BinaryView -const int CELL_HEIGHT = 35; +const int CELL_HEIGHT = 30; BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { model = new BinaryViewModel(this); @@ -156,7 +156,7 @@ void BinarySelectionModel::select(const QItemSelection &selection, QItemSelectio BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { // cache fonts and color - small_font.setPointSize(7); + small_font.setPointSize(6); bold_font.setBold(true); highlight_color = QApplication::style()->standardPalette().color(QPalette::Active, QPalette::Highlight); } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index b52f83dab6..7cace48402 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -85,18 +85,17 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWid // title bar QHBoxLayout *title_layout = new QHBoxLayout(); icon = new QLabel(">"); - icon->setFixedSize(15, 30); icon->setStyleSheet("font-weight:bold"); title_layout->addWidget(icon); title = new ElidedLabel(this); title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); title->setText(QString("%1. %2").arg(index + 1).arg(sig_name)); title->setStyleSheet(QString("font-weight:bold; color:%1").arg(getColor(index))); - title_layout->addWidget(title); + title_layout->addWidget(title, 1); QPushButton *plot_btn = new QPushButton("📈"); plot_btn->setToolTip(tr("Show Plot")); - plot_btn->setFixedSize(30, 30); + plot_btn->setFixedSize(20, 20); QObject::connect(plot_btn, &QPushButton::clicked, this, &SignalEdit::showChart); title_layout->addWidget(plot_btn); main_layout->addLayout(title_layout); From b89b881bdccb0fb844c597e9d26b64d36ba4af99 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 12:00:20 +0800 Subject: [PATCH 28/34] cabana: sort DBC list alphabetically (#26127) --- tools/cabana/messageswidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 3c9af67ea6..878a852e13 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -21,6 +21,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { for (const auto &name : dbc_names) { combo->addItem(QString::fromStdString(name)); } + combo->model()->sort(0); combo->setEditable(true); combo->setCurrentText(QString()); combo->setInsertPolicy(QComboBox::NoInsert); From 544526edeb343d4b6f9c7c6f2521659c34d37012 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 12:00:36 +0800 Subject: [PATCH 29/34] cabana: fix chart margins (#26125) --- tools/cabana/chartswidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 3652720e12..811eae68cb 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -184,6 +184,7 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) font.setBold(true); chart->setTitleFont(font); chart->setMargins({0, 0, 0, 0}); + chart->layout()->setContentsMargins(0, 0, 0, 0); track_line = new QGraphicsLineItem(chart); track_line->setPen(QPen(Qt::gray, 1, Qt::DashLine)); From 60fc7274eb631559f772ea0969e0ec28026e1426 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Oct 2022 21:15:57 -0700 Subject: [PATCH 30/34] =?UTF-8?q?Hyundai=20CAN-FD:=20remove=2090=C2=B0=20s?= =?UTF-8?q?teering=20lockout=20(#26045)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bump panda * bump panda * for CAN-FD too * clean up * bump * adjust safety * fix lat active * bump panda to master * same limits * rm line * bump panda to master --- panda | 2 +- selfdrive/car/hyundai/carcontroller.py | 29 +++++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/panda b/panda index 62868c36a8..9ed3f75f67 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 62868c36a80d1f44064da7b47423f0ef331f64e9 +Subproject commit 9ed3f75f67c3e5f00f910c8d7497ebed63851b5a diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index a5d995df25..6b38297eb9 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -90,13 +90,27 @@ class CarController: addr, bus = 0x730, 5 can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus]) + # >90 degree steering fault prevention + # Count up to MAX_ANGLE_FRAMES, at which point we need to cut torque to avoid a steering fault + if CC.latActive and abs(CS.out.steeringAngleDeg) >= MAX_ANGLE: + self.angle_limit_counter += 1 + else: + self.angle_limit_counter = 0 + + # Cut steer actuation bit for two frames and hold torque with induced temporary fault + torque_fault = CC.latActive and self.angle_limit_counter > MAX_ANGLE_FRAMES + lat_active = CC.latActive and not torque_fault + + if self.angle_limit_counter >= MAX_ANGLE_FRAMES + MAX_ANGLE_CONSECUTIVE_FRAMES: + self.angle_limit_counter = 0 + # CAN-FD platforms if self.CP.carFingerprint in CANFD_CAR: hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2 hda2_long = hda2 and self.CP.openpilotLongitudinalControl # steering control - can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, CC.enabled, CC.latActive, apply_steer)) + can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, CC.enabled, lat_active, apply_steer)) # disable LFA on HDA2 if self.frame % 5 == 0 and hda2: @@ -131,19 +145,6 @@ class CarController: can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.RES_ACCEL)) self.last_button_frame = self.frame else: - # Count up to MAX_ANGLE_FRAMES, at which point we need to cut torque to avoid a steering fault - if CC.latActive and abs(CS.out.steeringAngleDeg) >= MAX_ANGLE: - self.angle_limit_counter += 1 - else: - self.angle_limit_counter = 0 - - # Cut steer actuation bit for two frames and hold torque with induced temporary fault - torque_fault = CC.latActive and self.angle_limit_counter > MAX_ANGLE_FRAMES - lat_active = CC.latActive and not torque_fault - - if self.angle_limit_counter >= MAX_ANGLE_FRAMES + MAX_ANGLE_CONSECUTIVE_FRAMES: - self.angle_limit_counter = 0 - can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, lat_active, torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled, hud_control.leftLaneVisible, hud_control.rightLaneVisible, From 12058c21c73c7777e260334827b30f4d24c8313d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 18 Oct 2022 12:44:56 +0800 Subject: [PATCH 31/34] cabana: load dbc from paste (#26098) --- opendbc | 2 +- tools/cabana/dbcmanager.cc | 12 ++++++++ tools/cabana/dbcmanager.h | 1 + tools/cabana/messageswidget.cc | 51 ++++++++++++++++++++++++++-------- tools/cabana/messageswidget.h | 13 +++++++++ 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/opendbc b/opendbc index dde0ff6f44..e37ef84f1a 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit dde0ff6f4456c167df204bf5ac1e3f2979c844c9 +Subproject commit e37ef84f1ab848e2bf37f2c755f9e56213ce14e2 diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 5b1bddcabe..fc40fc58e4 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -1,5 +1,6 @@ #include "tools/cabana/dbcmanager.h" +#include #include DBCManager::DBCManager(QObject *parent) : QObject(parent) {} @@ -16,6 +17,17 @@ void DBCManager::open(const QString &dbc_file_name) { emit DBCFileChanged(); } +void DBCManager::open(const QString &name, const QString &content) { + this->dbc_name = name; + std::istringstream stream(content.toStdString()); + dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); + msg_map.clear(); + for (auto &msg : dbc->msgs) { + msg_map[msg.address] = &msg; + } + emit DBCFileChanged(); +} + void save(const QString &dbc_file_name) { // TODO: save DBC to file } diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 1f890a39db..74d935119a 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -12,6 +12,7 @@ public: ~DBCManager(); void open(const QString &dbc_file_name); + void open(const QString &name, const QString &content); void save(const QString &dbc_file_name); void addSignal(const QString &id, const Signal &sig); diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 878a852e13..28f79adad3 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -1,12 +1,13 @@ #include "tools/cabana/messageswidget.h" -#include #include +#include #include #include #include #include #include +#include #include #include "tools/cabana/dbcmanager.h" @@ -16,20 +17,23 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // DBC file selector QHBoxLayout *dbc_file_layout = new QHBoxLayout(); - QComboBox *combo = new QComboBox(this); + dbc_combo = new QComboBox(this); auto dbc_names = dbc()->allDBCNames(); for (const auto &name : dbc_names) { - combo->addItem(QString::fromStdString(name)); + dbc_combo->addItem(QString::fromStdString(name)); } - combo->model()->sort(0); - combo->setEditable(true); - combo->setCurrentText(QString()); - combo->setInsertPolicy(QComboBox::NoInsert); - combo->completer()->setCompletionMode(QCompleter::PopupCompletion); + dbc_combo->model()->sort(0); + dbc_combo->setEditable(true); + dbc_combo->setCurrentText(QString()); + dbc_combo->setInsertPolicy(QComboBox::NoInsert); + dbc_combo->completer()->setCompletionMode(QCompleter::PopupCompletion); QFont font; font.setBold(true); - combo->lineEdit()->setFont(font); - dbc_file_layout->addWidget(combo); + dbc_combo->lineEdit()->setFont(font); + dbc_file_layout->addWidget(dbc_combo); + + QPushButton *load_from_paste = new QPushButton(tr("Load from paste"), this); + dbc_file_layout->addWidget(load_from_paste); dbc_file_layout->addStretch(); QPushButton *save_btn = new QPushButton(tr("Save DBC"), this); @@ -64,7 +68,8 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // signals/slots QObject::connect(filter, &QLineEdit::textChanged, proxy_model, &QSortFilterProxyModel::setFilterFixedString); QObject::connect(can, &CANMessages::updated, model, &MessageListModel::updateState); - QObject::connect(combo, SIGNAL(activated(const QString &)), SLOT(dbcSelectionChanged(const QString &))); + QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(dbcSelectionChanged(const QString &))); + QObject::connect(load_from_paste, &QPushButton::clicked, this, &MessagesWidget::loadFromPaste); QObject::connect(save_btn, &QPushButton::clicked, [=]() { // TODO: save DBC to file }); @@ -75,7 +80,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { }); // For test purpose - combo->setCurrentText("toyota_nodsu_pt_generated"); + dbc_combo->setCurrentText("toyota_nodsu_pt_generated"); } void MessagesWidget::dbcSelectionChanged(const QString &dbc_file) { @@ -84,6 +89,14 @@ void MessagesWidget::dbcSelectionChanged(const QString &dbc_file) { table_widget->sortByColumn(0, Qt::AscendingOrder); } +void MessagesWidget::loadFromPaste() { + LoadDBCDialog dlg(this); + if (dlg.exec()) { + dbc()->open("from paste", dlg.dbc_edit->toPlainText()); + dbc_combo->setCurrentText("loaded from paste"); + } +} + // MessageListModel QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -133,3 +146,17 @@ void MessageListModel::updateState() { emit dataChanged(index(0, 0), index(row_count - 1, 3), {Qt::DisplayRole}); } } + +LoadDBCDialog::LoadDBCDialog(QWidget *parent) : QDialog(parent) { + QVBoxLayout *main_layout = new QVBoxLayout(this); + dbc_edit = new QTextEdit(this); + dbc_edit->setAcceptRichText(false); + dbc_edit->setPlaceholderText(tr("paste DBC file here")); + main_layout->addWidget(dbc_edit); + auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + main_layout->addWidget(buttonBox); + + setFixedWidth(640); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index f6487ba2bd..1184772f3b 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -1,10 +1,21 @@ #pragma once #include +#include +#include #include +#include #include "tools/cabana/canmessages.h" +class LoadDBCDialog : public QDialog { + Q_OBJECT + +public: + LoadDBCDialog(QWidget *parent); + QTextEdit *dbc_edit; +}; + class MessageListModel : public QAbstractTableModel { Q_OBJECT @@ -28,11 +39,13 @@ public: public slots: void dbcSelectionChanged(const QString &dbc_file); + void loadFromPaste(); signals: void msgSelectionChanged(const QString &message_id); protected: QTableView *table_widget; + QComboBox *dbc_combo; MessageListModel *model; }; From dcd804e2bfe2c29287749eb5777ced5a641c5e62 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Oct 2022 22:47:54 -0700 Subject: [PATCH 32/34] bump opendbc --- opendbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc b/opendbc index e37ef84f1a..8f245e6ef5 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit e37ef84f1ab848e2bf37f2c755f9e56213ce14e2 +Subproject commit 8f245e6ef5e25814d8e6e1f096221f6dfeefe86b From 7bf70bf7d8aaccd23ad0b0a9af8235eb939a617e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Oct 2022 23:04:06 -0700 Subject: [PATCH 33/34] CAN-FD HKG: query FW versions from camera (#26063) * add adas essential ecus * add adas ecu and query * add queries * add name * after * presence of adas ecu * Revert "presence of adas ecu" (POC) This reverts commit ab88a7e7df32e1c02a175b81848bd4112b2e5c69. * no whitelist for debugging * Apply suggestions from code review * add adas response * remove adas version * temp * read pandaStates * works in debug script * only fwdCamera on tucson * fix pandaStates reading * fix test_startup * fix * simpler * use existing socket * pass in number of pandas * need to create sm using outcome of fingerprinting, which uses sm fix * move default argument * use sock * always ignore always ignore * add canfd fingerprint test * Update selfdrive/car/hyundai/tests/test_hyundai.py * set --- selfdrive/car/car_helpers.py | 8 ++-- selfdrive/car/fw_versions.py | 14 +++++-- selfdrive/car/hyundai/tests/test_hyundai.py | 29 ++++++++++++++ selfdrive/car/hyundai/values.py | 42 +++++++-------------- selfdrive/controls/controlsd.py | 30 +++++++-------- selfdrive/controls/tests/test_startup.py | 3 ++ 6 files changed, 74 insertions(+), 52 deletions(-) create mode 100755 selfdrive/car/hyundai/tests/test_hyundai.py diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 4a8fd5fbd9..61e7a3d55d 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -76,7 +76,7 @@ interfaces = load_interfaces(interface_names) # **** for use live only **** -def fingerprint(logcan, sendcan): +def fingerprint(logcan, sendcan, num_pandas): fixed_fingerprint = os.environ.get('FINGERPRINT', "") skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) ecu_rx_addrs = set() @@ -100,7 +100,7 @@ def fingerprint(logcan, sendcan): cloudlog.warning("Getting VIN & FW versions") vin_rx_addr, vin = get_vin(logcan, sendcan, bus) ecu_rx_addrs = get_present_ecus(logcan, sendcan) - car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs) + car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, num_pandas=num_pandas) cached = False exact_fw_match, fw_candidates = match_fw_to_car(car_fw) @@ -173,8 +173,8 @@ def fingerprint(logcan, sendcan): return car_fingerprint, finger, vin, car_fw, source, exact_match -def get_car(logcan, sendcan): - candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan) +def get_car(logcan, sendcan, num_pandas=1): + candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas) if candidate is None: cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index d3e8eae0de..f4d92ab960 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -194,14 +194,14 @@ def get_brand_ecu_matches(ecu_rx_addrs): return brand_matches -def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, debug=False, progress=False): +def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False): """Queries for FW versions ordering brands by likelihood, breaks when exact match is found""" all_car_fw = [] brand_matches = get_brand_ecu_matches(ecu_rx_addrs) for brand in sorted(brand_matches, key=lambda b: len(brand_matches[b]), reverse=True): - car_fw = get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, debug=debug, progress=progress) + car_fw = get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, debug=debug, progress=progress) all_car_fw.extend(car_fw) # Try to match using FW returned from this brand only matches = match_fw_to_car_exact(build_fw_dict(car_fw)) @@ -211,7 +211,7 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, debug=Fa return all_car_fw -def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, debug=False, progress=False): +def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, debug=False, progress=False): versions = VERSIONS.copy() # Each brand can define extra ECUs to query for data collection @@ -252,6 +252,10 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, for addr in tqdm(addrs, disable=not progress): for addr_chunk in chunks(addr): for brand, r in requests: + # Skip query if no panda available + if r.bus > num_pandas * 4 - 1: + continue + try: addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and (len(r.whitelist_ecus) == 0 or ecu_types[(b, a, s)] in r.whitelist_ecus)] @@ -292,6 +296,7 @@ if __name__ == "__main__": args = parser.parse_args() logcan = messaging.sub_sock('can') + pandaStates_sock = messaging.sub_sock('pandaStates') sendcan = messaging.pub_sock('sendcan') extra: Any = None @@ -305,6 +310,7 @@ if __name__ == "__main__": extra = {"any": {"debug": extra}} time.sleep(1.) + num_pandas = len(messaging.recv_one_retry(pandaStates_sock).pandaStates) t = time.time() print("Getting vin...") @@ -314,7 +320,7 @@ if __name__ == "__main__": print() t = time.time() - fw_vers = get_fw_versions(logcan, sendcan, query_brand=args.brand, extra=extra, debug=args.debug, progress=True) + fw_vers = get_fw_versions(logcan, sendcan, query_brand=args.brand, extra=extra, num_pandas=num_pandas, debug=args.debug, progress=True) _, candidates = match_fw_to_car(fw_vers) print() diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py new file mode 100755 index 0000000000..a52027f448 --- /dev/null +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +import unittest + +from cereal import car +from selfdrive.car.car_helpers import get_interface_attr +from selfdrive.car.fw_versions import FW_QUERY_CONFIGS +from selfdrive.car.hyundai.values import CANFD_CAR + +Ecu = car.CarParams.Ecu + +ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} +VERSIONS = get_interface_attr("FW_VERSIONS", ignore_none=True) + + +class TestHyundaiFingerprint(unittest.TestCase): + def test_auxiliary_request_ecu_whitelist(self): + # Asserts only auxiliary Ecus can exist in database for CAN-FD cars + config = FW_QUERY_CONFIGS['hyundai'] + whitelisted_ecus = {ecu for r in config.requests for ecu in r.whitelist_ecus if r.bus > 3} + + for car_model in CANFD_CAR: + ecus = {fw[0] for fw in VERSIONS['hyundai'][car_model].keys()} + ecus_not_in_whitelist = ecus - whitelisted_ecus + ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_in_whitelist]) + self.assertEqual(len(ecus_not_in_whitelist), 0, f'{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}') + + +if __name__ == "__main__": + unittest.main() diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 856bf1abd9..1599005d1c 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -300,6 +300,19 @@ FW_QUERY_CONFIG = FwQueryConfig( [HYUNDAI_VERSION_RESPONSE], whitelist_ecus=[Ecu.engine, Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar], ), + # CAN-FD queries + Request( + [HYUNDAI_VERSION_REQUEST_LONG], + [HYUNDAI_VERSION_RESPONSE], + whitelist_ecus=[Ecu.fwdRadar], + bus=4, + ), + Request( + [HYUNDAI_VERSION_REQUEST_LONG], + [HYUNDAI_VERSION_RESPONSE], + whitelist_ecus=[Ecu.fwdCamera, Ecu.adas], + bus=5, + ), ], extra_ecus=[ (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms @@ -1326,15 +1339,6 @@ FW_VERSIONS = { ], }, CAR.KIA_EV6: { - (Ecu.abs, 0x7d1, None): [ - b'\xf1\x00CV IEB \x02 101!\x10\x18 58520-CV100', - b'\xf1\x00CV IEB \x03 101!\x10\x18 58520-CV100', - b'\xf1\x8758520CV100\xf1\x00CV IEB \x02 101!\x10\x18 58520-CV100', - ], - (Ecu.eps, 0x7d4, None): [ - b'\xf1\x00CV1 MDPS R 1.00 1.04 57700-CV000 1B30', - b'\xf1\x00CV1 MDPS R 1.00 1.05 57700-CV000 2425', - ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ', b'\xf1\x8799110CV000\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ', @@ -1346,16 +1350,6 @@ FW_VERSIONS = { ], }, CAR.IONIQ_5: { - (Ecu.abs, 0x7d1, None): [ - b'\xf1\x00NE1 IEB \x07 106!\x11) 58520-GI010', - b'\xf1\x8758520GI010\xf1\x00NE1 IEB \x07 106!\x11) 58520-GI010', - b'\xf1\x00NE1 IEB \x08 104!\x04\x05 58520-GI000', - b'\xf1\x8758520GI000\xf1\x00NE1 IEB \x08 104!\x04\x05 58520-GI000', - ], - (Ecu.eps, 0x7d4, None): [ - b'\xf1\x00NE MDPS R 1.00 1.06 57700GI000 4NEDR106', - b'\xf1\x8757700GI000 \xf1\x00NE MDPS R 1.00 1.06 57700GI000 4NEDR106', - ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ', b'\xf1\x8799110GI000\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ', @@ -1369,16 +1363,6 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q', ], - (Ecu.eps, 0x7d4, None): [ - b'\xf1\x00NX4 MDPS C 1.00 1.01 56300-P0100 2228', - ], - (Ecu.engine, 0x7e0, None): [ - b'\xf1\x87391312MND0', - ], - (Ecu.transmission, 0x7e1, None): [ - b'\xf1\x00PSBG2441 G19_Rev\x00\x00\x00SNX4T16XXHS01NS2lS\xdfa', - b'\xf1\x8795441-3D220\x00\xf1\x81G19_Rev\x00\x00\x00\xf1\x00PSBG2441 G19_Rev\x00\x00\x00SNX4T16XXHS01NS2lS\xdfa', - ], }, } diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 8abb1a02a6..cbc54eadb8 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -82,30 +82,30 @@ class Controls: self.log_sock = messaging.sub_sock('androidLog') - if CI is None: - # wait for one pandaState and one CAN packet - print("Waiting for CAN messages...") - get_one_can(self.can_sock) - - self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan']) - else: - self.CI, self.CP = CI, CI.CP - params = Params() - self.joystick_mode = params.get_bool("JoystickDebugMode") or (self.CP.notCar and sm is None) - joystick_packet = ['testJoystick'] if self.joystick_mode else [] - self.sm = sm if self.sm is None: - ignore = [] + ignore = ['testJoystick'] if SIMULATION: ignore += ['driverCameraState', 'managerState'] if params.get_bool('WideCameraOnly'): ignore += ['roadCameraState'] self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', - 'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters'] + self.camera_packets + joystick_packet, - ignore_alive=ignore, ignore_avg_freq=['radarState', 'longitudinalPlan']) + 'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters', 'testJoystick'] + self.camera_packets, + ignore_alive=ignore, ignore_avg_freq=['radarState', 'longitudinalPlan', 'testJoystick']) + + if CI is None: + # wait for one pandaState and one CAN packet + print("Waiting for CAN messages...") + get_one_can(self.can_sock) + + num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates) + self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], num_pandas) + else: + self.CI, self.CP = CI, CI.CP + + self.joystick_mode = params.get_bool("JoystickDebugMode") or (self.CP.notCar and sm is None) # set alternative experiences from parameters self.disengage_on_accelerator = params.get_bool("DisengageOnAccelerator") diff --git a/selfdrive/controls/tests/test_startup.py b/selfdrive/controls/tests/test_startup.py index 63af4c7d95..ba2d2f5c02 100755 --- a/selfdrive/controls/tests/test_startup.py +++ b/selfdrive/controls/tests/test_startup.py @@ -94,6 +94,9 @@ class TestStartup(unittest.TestCase): time.sleep(2) # wait for controlsd to be ready + pm.send('can', can_list_to_can_capnp([[0, 0, b"", 0]])) + time.sleep(0.1) + msg = messaging.new_message('pandaStates', 1) msg.pandaStates[0].pandaType = log.PandaState.PandaType.uno pm.send('pandaStates', msg) From 5b85c2df4e2d855dc8fcb572bda33d2d456841d9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Oct 2022 23:24:34 -0700 Subject: [PATCH 34/34] Tucson Hybrid 4th gen: add missing fwdRadar (#26128) add missing fwdRadar --- selfdrive/car/hyundai/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1599005d1c..f69273ba55 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1363,6 +1363,9 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q', ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ', + ], }, }