From e099e42147af23a700bf4b64e08540574aa1d285 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 16 Nov 2022 18:12:31 +0100 Subject: [PATCH 01/12] cabana: default factor to 1 (#26521) --- tools/cabana/detailwidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 192d1fd66c..8a221ed9db 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -235,7 +235,7 @@ void DetailWidget::addSignal(int start_bit, int size, bool little_endian) { } } } - Signal sig = {.is_little_endian = little_endian}; + Signal sig = {.is_little_endian = little_endian, .factor = 1}; for (int i = 1; /**/; ++i) { sig.name = "NEW_SIGNAL_" + std::to_string(i); if (msg->sigs.count(sig.name.c_str()) == 0) break; From e79a384a9bdc0f7421e2a914abf88a302a7e32a2 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Thu, 17 Nov 2022 02:13:41 +0900 Subject: [PATCH 02/12] Multilang: kor translation update (#26522) --- selfdrive/ui/translations/main_ko.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 98d46149dd..bda64c53ab 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -285,11 +285,11 @@ ExperimentalModeButton EXPERIMENTAL MODE ON - + 실험적 모드 사용 CHILL MODE ON - + 안정적 모드 사용 @@ -875,7 +875,7 @@ location set Uninstall - 삭제 + 제거 @@ -1015,15 +1015,15 @@ location set On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when using experimental openpilot longitudinal control. - + 이 차량은 openpilot 롱컨트롤 대신 차량의 내장 ACC로 기본 설정됩니다. openpilot 롱컨트롤을 사용하려면 이 옵션을 활성화하세요. 실험적 openpilot 롱컨트롤을 사용하는 경우 실험적 모드를 활성화 하세요. Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. - + 차량의 기본 ACC가 롱컨트롤에 사용되기 때문에 현재 이 차량에서는 실험적 모드를 사용할수 없습니다. Enable experimental longitudinal control to allow experimental mode. - + 실험적 롱컨트롤을 사용하려면 실험적 모드를 활성화 하세요. openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: @@ -1035,15 +1035,15 @@ location set Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - + 주행모델이 가속과 감속을 제어하도록 합니다. openpilot은 신호등과 정지표지판을 보고 멈추는 것을 포함하여 운전자가 생각하는것처럼 주행합니다. 주행 모델이 주행할 속도를 결정하므로 설정된 속도는 상한선으로만 작용합니다. 이것은 알파 기능이므로 사용에 주의해야 합니다. New Driving Visualization - + 새로운 주행 시각화 The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - + 주행 시각화는 저속에서 도로를 향하는 광각 카메라로 전환되어 일부 회전을 더 잘 보여줍니다. 실험적 모드 로고도 우측상단에 표시됩니다. From 8f9f015567a9f2dad66d31c25c514c436d1ba862 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 16 Nov 2022 18:25:36 +0100 Subject: [PATCH 03/12] add missing include (#26520) --- selfdrive/ui/qt/offroad/experimental_mode.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/offroad/experimental_mode.cc b/selfdrive/ui/qt/offroad/experimental_mode.cc index f73149cdf2..b99220c1d1 100644 --- a/selfdrive/ui/qt/offroad/experimental_mode.cc +++ b/selfdrive/ui/qt/offroad/experimental_mode.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "selfdrive/ui/ui.h" From c3e2d35963a95bfeaf99048decbd6066c52113d8 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 16 Nov 2022 14:20:00 -0800 Subject: [PATCH 04/12] offroad ui: update chill mode icon (#26523) * Add files via upload * Add files via upload * Delete thick couch.svg * Rename img_couch.svg to img_couch_old.svg * Rename thickerer couch.svg to img_couch.svg * Add files via upload * Rename img_couch.svg to img_couch_alt.svg * Rename best couch.svg to img_couch.svg * delete old files --- selfdrive/assets/img_couch.svg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/assets/img_couch.svg b/selfdrive/assets/img_couch.svg index 5b3c048318..2e86012809 100644 --- a/selfdrive/assets/img_couch.svg +++ b/selfdrive/assets/img_couch.svg @@ -1,3 +1,4 @@ - - + + + From e3c913bfa1d8c534f351d6ead5c2156ee4ee4ffa Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 17 Nov 2022 07:43:49 +0800 Subject: [PATCH 05/12] Cabana: sort signal by start bit and keep cursor position after save (#26529) sort signals by start bit and keep cursor position after save --- tools/cabana/binaryview.cc | 14 +++++++------- tools/cabana/dbcmanager.cc | 9 +++++++++ tools/cabana/dbcmanager.h | 1 + tools/cabana/detailwidget.cc | 6 +++--- tools/cabana/signaledit.cc | 11 +++++++++-- tools/cabana/signaledit.h | 2 ++ 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index bcd2b88a81..7707316877 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -166,19 +166,19 @@ void BinaryViewModel::setMessage(const QString &message_id) { row_count = dbc_msg->size; items.resize(row_count * column_count); int i = 0; - for (auto &[name, sig] : dbc_msg->sigs) { - auto [start, end] = getSignalRange(&sig); + for (auto sig : dbc_msg->getSignals()) { + auto [start, end] = getSignalRange(sig); for (int j = start; j <= end; ++j) { - int bit_index = sig.is_little_endian ? bigEndianBitIndex(j) : j; + int bit_index = sig->is_little_endian ? bigEndianBitIndex(j) : j; int idx = column_count * (bit_index / 8) + bit_index % 8; if (idx >= items.size()) { - qWarning() << "signal " << name << "out of bounds.start_bit:" << sig.start_bit << "size:" << sig.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; - if (j == end) sig.is_little_endian ? items[idx].is_msb = true : items[idx].is_lsb = true; + if (j == start) sig->is_little_endian ? items[idx].is_lsb = true : items[idx].is_msb = true; + if (j == end) sig->is_little_endian ? items[idx].is_msb = true : items[idx].is_lsb = true; items[idx].bg_color = getColor(i); - items[idx].sigs.push_back(&sig); + items[idx].sigs.push_back(sig); } ++i; } diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 18f103d34c..e7d3ead9c6 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -107,6 +107,15 @@ DBCManager *dbc() { return &dbc_manager; } +// DBCMsg + +std::vector DBCMsg::getSignals() const { + std::vector ret; + for (auto &[name, sig] : sigs) ret.push_back(&sig); + std::sort(ret.begin(), ret.end(), [](auto l, auto r) { return l->start_bit < r->start_bit; }); + return ret; +} + // helper functions static QVector BIG_ENDIAN_START_BITS = []() { diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index b1d2082969..4e0bc91069 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -9,6 +9,7 @@ struct DBCMsg { QString name; uint32_t size; std::map sigs; + std::vector getSignals() const; }; class DBCManager : public QObject { diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 8a221ed9db..99cf45f5fa 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -149,7 +149,7 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { QStringList warnings; const DBCMsg *msg = dbc()->msg(msg_id); if (msg) { - for (auto &[name, sig] : msg->sigs) { + for (auto sig : msg->getSignals()) { SignalEdit *form = i < signal_list.size() ? signal_list[i] : nullptr; if (!form) { form = new SignalEdit(i); @@ -162,8 +162,8 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { signals_layout->addWidget(form); signal_list.push_back(form); } - form->setSignal(msg_id, &sig); - form->setChartOpened(charts->isChartOpened(msg_id, &sig)); + form->setSignal(msg_id, sig); + form->setChartOpened(charts->isChartOpened(msg_id, sig)); ++i; } if (msg->size != can->lastMessage(msg_id).dat.size()) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index eb22b78d5a..6e4cf2a83a 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -116,11 +116,16 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa hline->setFrameShadow(QFrame::Sunken); main_layout->addWidget(hline); + save_timer = new QTimer(this); + save_timer->setInterval(300); + save_timer->setSingleShot(true); + save_timer->callOnTimeout(this, &SignalEdit::saveSignal); + QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); QObject::connect(plot_btn, &QToolButton::clicked, [this](bool checked) { emit showChart(msg_id, sig, checked); }); QObject::connect(seek_btn, &QToolButton::clicked, [this]() { SignalFindDlg(msg_id, sig, this).exec(); }); QObject::connect(remove_btn, &QToolButton::clicked, [this]() { emit remove(sig); }); - QObject::connect(form, &SignalForm::changed, this, &SignalEdit::saveSignal); + QObject::connect(form, &SignalForm::changed, [this]() { save_timer->start(); }); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } @@ -174,7 +179,9 @@ void SignalEdit::setChartOpened(bool opened) { void SignalEdit::updateForm(bool visible) { if (visible && sig) { form->changed_by_user = false; - form->name->setText(sig->name.c_str()); + if (form->name->text() != sig->name.c_str()) { + form->name->setText(sig->name.c_str()); + } form->endianness->setCurrentIndex(sig->is_little_endian ? 0 : 1); form->sign->setCurrentIndex(sig->is_signed ? 0 : 1); form->factor->setText(QString::number(sig->factor)); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index da0b9758c7..f889a9c096 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "selfdrive/ui/qt/widgets/controls.h" @@ -57,6 +58,7 @@ protected: QLabel *icon; int form_idx = 0; QToolButton *plot_btn; + QTimer *save_timer; }; class SignalFindDlg : public QDialog { From b6de850dd7b9935ded59895a84b3edf5c767dae0 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 17 Nov 2022 07:45:08 +0800 Subject: [PATCH 06/12] Cabana: save & restore splitter state (#26526) save & restore splitter state --- tools/cabana/mainwin.cc | 4 ++++ tools/cabana/settings.cc | 2 ++ tools/cabana/settings.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 7781ab3b75..324323ac44 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -55,6 +55,9 @@ MainWindow::MainWindow() : QMainWindow() { charts_widget = new ChartsWidget(this); detail_widget = new DetailWidget(charts_widget, this); splitter->addWidget(detail_widget); + if (!settings.splitter_state.isEmpty()) { + splitter->restoreState(settings.splitter_state); + } main_layout->addWidget(splitter); // right widgets @@ -247,6 +250,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { if (floating_window) floating_window->deleteLater(); + settings.splitter_state = splitter->saveState(); settings.save(); QWidget::closeEvent(event); } diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index b3a4ed4872..be806aa705 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -21,6 +21,7 @@ void Settings::save() { s.setValue("chart_theme", chart_theme); s.setValue("max_chart_x_range", max_chart_x_range); s.setValue("last_dir", last_dir); + s.setValue("splitter_state", splitter_state); } void Settings::load() { @@ -32,6 +33,7 @@ void Settings::load() { chart_theme = s.value("chart_theme", 0).toInt(); max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt(); last_dir = s.value("last_dir", QDir::homePath()).toString(); + splitter_state = s.value("splitter_state").toByteArray(); } // SettingsDlg diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index e08d0ae55e..624a1ce33d 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -19,6 +20,7 @@ public: int chart_theme = 0; int max_chart_x_range = 3 * 60; // 3 minutes QString last_dir; + QByteArray splitter_state; signals: void changed(); From 2cd1571f4ae9f8aa1aa5879aa8c9107028d7f937 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 17 Nov 2022 00:45:28 +0100 Subject: [PATCH 07/12] Discover Qt paths using qmake (#26501) * discover qt paths using qmake * fix device build * use subprocess.check_output --- SConstruct | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index 74680c0598..033e10a1f0 100644 --- a/SConstruct +++ b/SConstruct @@ -298,12 +298,15 @@ if arch == "Darwin": qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"] qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin")) else: - qt_env['QTDIR'] = "/usr" + qt_install_prefix = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_PREFIX'], encoding='utf8').strip() + qt_install_headers = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_HEADERS'], encoding='utf8').strip() + + qt_env['QTDIR'] = qt_install_prefix qt_dirs = [ - f"/usr/include/{real_arch}-linux-gnu/qt5", - f"/usr/include/{real_arch}-linux-gnu/qt5/QtGui/5.12.8/QtGui", + f"{qt_install_headers}", + f"{qt_install_headers}/QtGui/5.12.8/QtGui", ] - qt_dirs += [f"/usr/include/{real_arch}-linux-gnu/qt5/Qt{m}" for m in qt_modules] + qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules] qt_libs = [f"Qt5{m}" for m in qt_modules] if arch == "larch64": From 66edb15b8f558ce81b5a57af4e60fc24e1fc489c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 17 Nov 2022 07:51:05 +0800 Subject: [PATCH 08/12] Cabana: improve binary view (#26525) * improve * set minimum width * click signal to open&hide form * disable vertical header's click --- tools/cabana/binaryview.cc | 94 +++++++++++++++--------------------- tools/cabana/binaryview.h | 5 +- tools/cabana/canmessages.h | 6 --- tools/cabana/detailwidget.cc | 12 ++++- tools/cabana/detailwidget.h | 1 + tools/cabana/signaledit.cc | 3 +- 6 files changed, 54 insertions(+), 67 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 7707316877..dae4591976 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -23,11 +23,13 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { delegate = new BinaryItemDelegate(this); setItemDelegate(delegate); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + verticalHeader()->setSectionsClickable(false); horizontalHeader()->hide(); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); setFrameShape(QFrame::NoFrame); + setShowGrid(false); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); setMouseTracking(true); } @@ -46,46 +48,30 @@ void BinaryView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF return; QItemSelection selection; - auto [tl, br] = std::minmax(anchor_index, index); - if ((resize_sig && resize_sig->is_little_endian) || (!resize_sig && index < anchor_index)) { - // little_endian selection - if (tl.row() == br.row()) { - selection.merge({model->index(tl.row(), tl.column()), model->index(tl.row(), br.column())}, flags); - } else { - for (int row = tl.row(); row <= br.row(); ++row) { - int left_col = (row == br.row()) ? br.column() : 0; - int right_col = (row == tl.row()) ? tl.column() : 7; - selection.merge({model->index(row, left_col), model->index(row, right_col)}, flags); - } - } - } else { - // big endian selection - for (int row = tl.row(); row <= br.row(); ++row) { - int left_col = (row == tl.row()) ? tl.column() : 0; - int right_col = (row == br.row()) ? br.column() : 7; - selection.merge({model->index(row, left_col), model->index(row, right_col)}, flags); - } + auto [start, size, is_lb] = getSelection(index); + for (int i = start; i < start + size; ++i) { + auto idx = model->bitIndex(i, is_lb); + selection.merge({idx, idx}, flags); } selectionModel()->select(selection, flags); } void BinaryView::mousePressEvent(QMouseEvent *event) { delegate->setSelectionColor(style()->standardPalette().color(QPalette::Active, QPalette::Highlight)); - if (auto index = indexAt(event->pos()); index.isValid() && index.column() != 8) { + if (auto index = indexAt(event->pos()); index.isValid() && index.column() != 8) { anchor_index = index; auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); - if (item && item->sigs.size() > 0) { - int bit_idx = get_bit_index(anchor_index, true); - for (auto s : item->sigs) { - if (bit_idx == s->lsb || bit_idx == s->msb) { - resize_sig = s; - delegate->setSelectionColor(item->bg_color); - break; - } + int bit_idx = get_bit_index(anchor_index, true); + for (auto s : item->sigs) { + if (bit_idx == s->lsb || bit_idx == s->msb) { + anchor_index = model->bitIndex(bit_idx == s->lsb ? s->msb : s->lsb, true); + resize_sig = s; + delegate->setSelectionColor(item->bg_color); + break; } } } - QTableView::mousePressEvent(event); + event->accept(); } void BinaryView::mouseMoveEvent(QMouseEvent *event) { @@ -104,28 +90,14 @@ void BinaryView::mouseReleaseEvent(QMouseEvent *event) { auto release_index = indexAt(event->pos()); if (release_index.isValid() && anchor_index.isValid()) { - if (release_index.column() == 8) { - release_index = model->index(release_index.row(), 7); - } - bool little_endian = (resize_sig && resize_sig->is_little_endian) || (!resize_sig && release_index < anchor_index); - int release_bit_idx = get_bit_index(release_index, little_endian); - int archor_bit_idx = get_bit_index(anchor_index, little_endian); - if (resize_sig) { - auto [sig_from, sig_to] = getSignalRange(resize_sig); - int start_bit, end_bit; - if (archor_bit_idx == sig_from) { - std::tie(start_bit, end_bit) = std::minmax(release_bit_idx, sig_to); - if (start_bit >= sig_from && start_bit <= sig_to) - start_bit = std::min(start_bit + 1, sig_to); - } else { - std::tie(start_bit, end_bit) = std::minmax(release_bit_idx, sig_from); - if (end_bit >= sig_from && end_bit <= sig_to) - end_bit = std::max(end_bit - 1, sig_from); - } - emit resizeSignal(resize_sig, start_bit, end_bit - start_bit + 1); + if (selectionModel()->hasSelection()) { + auto [start_bit, size, is_lb] = getSelection(release_index); + resize_sig ? emit resizeSignal(resize_sig, start_bit, size) + : emit addSignal(start_bit, size, is_lb); } else { - auto [sart_bit, end_bit] = std::minmax(archor_bit_idx, release_bit_idx); - emit addSignal(sart_bit, end_bit - sart_bit + 1, little_endian); + auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); + if (item && item->sigs.size() > 0) + emit signalClicked(item->sigs.back()); } } clearSelection(); @@ -156,6 +128,17 @@ QSet BinaryView::getOverlappingSignals() const { return overlapping; } +std::tuple BinaryView::getSelection(QModelIndex index) { + if (index.column() == 8) { + index = model->index(index.row(), 7); + } + bool is_lb = (resize_sig && resize_sig->is_little_endian) || (!resize_sig && index < anchor_index); + int cur_bit_idx = get_bit_index(index, is_lb); + int anchor_bit_idx = get_bit_index(anchor_index, is_lb); + auto [start_bit, end_bit] = std::minmax(cur_bit_idx, anchor_bit_idx); + return {start_bit, end_bit - start_bit + 1, is_lb}; +} + // BinaryViewModel void BinaryViewModel::setMessage(const QString &message_id) { @@ -203,7 +186,7 @@ void BinaryViewModel::updateState() { 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'); + items[i * column_count + j].val = ((binary[i] >> (7 - j)) & 1) != 0 ? '1' : '0'; } hex[0] = toHex(binary[i] >> 4); hex[1] = toHex(binary[i] & 0xf); @@ -250,17 +233,16 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->save(); // background - bool hover = item->sigs.contains(bin_view->hoveredSignal()); - QColor bg_color = hover ? hoverColor(item->bg_color) : item->bg_color; if (option.state & QStyle::State_Selected) { - bg_color = selection_color; + painter->fillRect(option.rect, selection_color); + } else if (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig)) { + painter->fillRect(option.rect, item->bg_color); } - painter->fillRect(option.rect, bg_color); // text if (index.column() == 8) { // hex column painter->setFont(hex_font); - } else if (hover) { + } else if (option.state & QStyle::State_Selected || (!bin_view->resize_sig && item->sigs.contains(bin_view->hovered_sig))) { painter->setPen(Qt::white); } painter->drawText(option.rect, Qt::AlignCenter, item->val); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 2d6fc5c18b..0ea111d917 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -32,6 +32,7 @@ public: 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; } + inline QModelIndex bitIndex(int bit, bool is_lb) const { return index(bit / 8, is_lb ? (7 - bit % 8) : bit % 8); } QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override { return createIndex(row, column, (void *)&items[row * column_count + column]); } @@ -63,15 +64,16 @@ public: void setMessage(const QString &message_id); void highlight(const Signal *sig); QSet getOverlappingSignals() const; - inline const Signal *hoveredSignal() const { return hovered_sig; } inline void updateState() { model->updateState(); } signals: + void signalClicked(const Signal *sig); void signalHovered(const Signal *sig); void addSignal(int start_bit, int size, bool little_endian); void resizeSignal(const Signal *sig, int from, int size); private: + std::tuple getSelection(QModelIndex index); void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override; void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; @@ -83,4 +85,5 @@ private: BinaryItemDelegate *delegate; const Signal *resize_sig = nullptr; const Signal *hovered_sig = nullptr; + friend class BinaryItemDelegate; }; diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index ff41edad54..4cb0f403a0 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -80,11 +80,5 @@ inline const QString &getColor(int i) { return SIGNAL_COLORS[i % std::size(SIGNAL_COLORS)]; } -inline QColor hoverColor(const QColor &color) { - QColor c = color.convertTo(QColor::Hsv); - c.setHsv(color.hue(), 180, 180); - return c; -} - // A global pointer referring to the unique CANMessages object extern CANMessages *can; diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 99cf45f5fa..52ae530a56 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -17,6 +17,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { undo_stack = new QUndoStack(this); + setMinimumWidth(500); QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setSpacing(0); @@ -90,6 +91,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tab_widget->addTab(history_log, "Logs"); main_layout->addWidget(tab_widget); + QObject::connect(binary_view, &BinaryView::signalClicked, this, &DetailWidget::showForm); QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal); QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); QObject::connect(tab_widget, &QTabWidget::currentChanged, [this]() { updateState(); }); @@ -197,9 +199,15 @@ void DetailWidget::updateState(const QHash * msgs) { void DetailWidget::showFormClicked() { auto s = qobject_cast(sender()); + showForm(s->sig); +} + +void DetailWidget::showForm(const Signal *sig) { setUpdatesEnabled(false); - for (auto f : signal_list) - f->updateForm(f == s && !f->isFormVisible()); + for (auto f : signal_list) { + f->updateForm(f->sig == sig && !f->isFormVisible()); + if (f->sig == sig) scroll->ensureWidgetVisible(f); + } setUpdatesEnabled(true); } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 4346d1c5d5..41fa0edd41 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -28,6 +28,7 @@ public: QUndoStack *undo_stack = nullptr; private: + void showForm(const Signal *sig); void showFormClicked(); void updateChartState(const QString &id, const Signal *sig, bool opened); void showTabBarContextMenu(const QPoint &pt); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 6e4cf2a83a..a0660901cf 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -196,9 +196,8 @@ void SignalEdit::updateForm(bool visible) { } void SignalEdit::signalHovered(const Signal *s) { - auto bg_color = sig == s ? hoverColor(getColor(form_idx)) : QColor(getColor(form_idx)); auto color = sig == s ? "white" : "black"; - color_label->setStyleSheet(QString("color:%1; background-color:%2").arg(color).arg(bg_color.name())); + color_label->setStyleSheet(QString("color:%1; background-color:%2").arg(color).arg(getColor(form_idx))); } void SignalEdit::enterEvent(QEvent *event) { From 187f8c177a1a4d507a4ca145463f852cee3ce7aa Mon Sep 17 00:00:00 2001 From: Tim Wilson Date: Thu, 17 Nov 2022 03:03:13 -0700 Subject: [PATCH 09/12] Add video_link for GMC Sierra (#26506) * Add video_link for GMS Sierra * fix precommit Co-authored-by: Shane Smiskol --- selfdrive/car/gm/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 03392ba0f9..35f87307d6 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -100,7 +100,7 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { CAR.BOLT_EUV: GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", "https://youtu.be/xvwzGMUA210", footnotes=[], harness=Harness.gm), CAR.SILVERADO: [ GMCarInfo("Chevrolet Silverado 1500 2020-21", "Safety Package II", footnotes=[], harness=Harness.gm), - GMCarInfo("GMC Sierra 1500 2020-21", "Driver Alert Package II", footnotes=[], harness=Harness.gm), + GMCarInfo("GMC Sierra 1500 2020-21", "Driver Alert Package II", "https://youtu.be/5HbNoBLzRwE", footnotes=[], harness=Harness.gm), ], CAR.EQUINOX: GMCarInfo("Chevrolet Equinox 2019-22", footnotes=[], harness=Harness.gm), } From 37ad8f4f3fe0e730c46ba60f60e9c8db20c4c20e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 18 Nov 2022 02:52:04 +0800 Subject: [PATCH 10/12] Cabana: support for multiple series in chart (#26538) * customize axis x & y * new function chartView::addSignal * support multiple series in chartView * more * show legend * update changed signals only * fix z value * cleanup * limit trake line in plot area * display signal name in value_text *   * fix axis y * add spaces * cache min max value for axis y * cleanup * better values text * remove force_update --- tools/cabana/chartswidget.cc | 316 +++++++++++++++++++++++------------ tools/cabana/chartswidget.h | 52 ++++-- tools/cabana/signaledit.cc | 7 +- tools/cabana/signaledit.h | 2 +- 4 files changed, 253 insertions(+), 124 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 06387b3585..4bd398a93b 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -4,11 +4,9 @@ #include #include #include +#include #include -#include -#include #include -#include // ChartsWidget @@ -19,7 +17,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); title_label = new QLabel(); - title_label->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred); + title_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->addWidget(title_label); toolbar->addWidget(range_label = new QLabel()); reset_zoom_btn = toolbar->addAction("⟲"); @@ -42,21 +40,10 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(charts_scroll); - QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { removeAll(nullptr); }); - QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartsWidget::removeAll); - QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartsWidget::signalUpdated); - QObject::connect(dbc(), &DBCManager::msgRemoved, [this](uint32_t address) { - for (auto c : charts.toVector()) - if (DBCManager::parseId(c->id).second == address) removeChart(c); - }); - QObject::connect(dbc(), &DBCManager::msgUpdated, [this](uint32_t address) { - for (auto c : charts) { - if (DBCManager::parseId(c->id).second == address) c->updateTitle(); - } - }); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &CANMessages::updated, this, &ChartsWidget::updateState); - QObject::connect(remove_all_btn, &QAction::triggered, [this]() { removeAll(); }); + QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset); QObject::connect(dock_btn, &QAction::triggered, [this]() { emit dock(!docking); @@ -81,8 +68,8 @@ void ChartsWidget::zoomIn(double min, double max) { zoomed_range = {min, max}; is_zoomed = zoomed_range != display_range; updateToolBar(); - emit rangeChanged(min, max, is_zoomed); updateState(); + emit rangeChanged(min, max, is_zoomed); } void ChartsWidget::zoomReset() { @@ -108,13 +95,13 @@ void ChartsWidget::updateState() { if (prev_range != display_range) { QFutureSynchronizer future_synchronizer; for (auto c : charts) - future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, display_range)); + future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::setEventsRange, display_range)); } } const auto &range = is_zoomed ? zoomed_range : display_range; for (auto c : charts) { - c->setRange(range.first, range.second); + c->setDisplayRange(range.first, range.second); c->updateLineMarker(current_sec); } } @@ -128,49 +115,45 @@ void ChartsWidget::updateToolBar() { dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); } -void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show) { - auto it = std::find_if(charts.begin(), charts.end(), [=](auto c) { return c->id == id && c->signal == sig; }); - if (it != charts.end()) { - if (!show) removeChart((*it)); - } else if (show) { - auto chart = new ChartView(id, sig, this); - chart->updateSeries(display_range); - QObject::connect(chart, &ChartView::remove, [=]() { removeChart(chart); }); - QObject::connect(chart, &ChartView::zoomIn, this, &ChartsWidget::zoomIn); - QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); - charts_layout->insertWidget(0, chart); - charts.push_back(chart); - emit chartOpened(chart->id, chart->signal); +ChartView *ChartsWidget::findChart(const QString &id, const Signal *sig) { + for (auto c : charts) + if (c->hasSeries(id, sig)) return c; + return nullptr; +} + +void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bool merge) { + if (!show) { + if (ChartView *chart = findChart(id, sig)) { + chart->removeSeries(id, sig); + } + } else { + ChartView *chart = merge && charts.size() > 0 ? charts.back() : nullptr; + if (!chart) { + chart = new ChartView(this); + chart->setEventsRange(display_range); + QObject::connect(chart, &ChartView::remove, [=]() { removeChart(chart); }); + QObject::connect(chart, &ChartView::zoomIn, this, &ChartsWidget::zoomIn); + QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); + QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::chartClosed); + charts_layout->insertWidget(0, chart); + charts.push_back(chart); + } + chart->addSeries(id, sig); + emit chartOpened(id, sig); updateState(); } updateToolBar(); } -bool ChartsWidget::isChartOpened(const QString &id, const Signal *sig) { - auto it = std::find_if(charts.begin(), charts.end(), [=](auto c) { return c->id == id && c->signal == sig; }); - return it != charts.end(); -} - void ChartsWidget::removeChart(ChartView *chart) { charts.removeOne(chart); chart->deleteLater(); updateToolBar(); - emit chartClosed(chart->id, chart->signal); } -void ChartsWidget::removeAll(const Signal *sig) { +void ChartsWidget::removeAll() { for (auto c : charts.toVector()) - if (!sig || c->signal == sig) removeChart(c); -} - -void ChartsWidget::signalUpdated(const Signal *sig) { - for (auto c : charts) { - if (c->signal == sig) { - c->updateTitle(); - c->updateSeries(display_range); - c->setRange(display_range.first, display_range.second, true); - } - } + removeChart(c); } bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { @@ -183,14 +166,14 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { // ChartView -ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) - : id(id), signal(sig), QChartView(nullptr, parent) { - QLineSeries *series = new QLineSeries(); +ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QChart *chart = new QChart(); chart->setBackgroundRoundness(0); - chart->addSeries(series); - chart->createDefaultAxes(); - chart->legend()->hide(); + axis_x = new QValueAxis(this); + axis_y = new QValueAxis(this); + chart->addAxis(axis_x, Qt::AlignBottom); + chart->addAxis(axis_y, Qt::AlignLeft); + chart->legend()->setShowToolTips(true); chart->layout()->setContentsMargins(0, 0, 0, 0); // top margin for title chart->setMargins({0, 11, 0, 0}); @@ -213,33 +196,108 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) remove_btn->setToolTip(tr("Remove Chart")); close_btn_proxy = new QGraphicsProxyWidget(chart); close_btn_proxy->setWidget(remove_btn); + close_btn_proxy->setZValue(chart->zValue() + 11); setChart(chart); setRenderHint(QPainter::Antialiasing); setRubberBand(QChartView::HorizontalRubberBand); updateFromSettings(); - updateTitle(); QTimer *timer = new QTimer(this); timer->setInterval(100); timer->setSingleShot(true); timer->callOnTimeout(this, &ChartView::adjustChartMargins); + QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartView::signalRemoved); + QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartView::signalUpdated); + QObject::connect(dbc(), &DBCManager::msgRemoved, this, &ChartView::msgRemoved); + QObject::connect(dbc(), &DBCManager::msgUpdated, this, &ChartView::msgUpdated); QObject::connect(&settings, &Settings::changed, this, &ChartView::updateFromSettings); - QObject::connect(remove_btn, &QToolButton::clicked, [=]() { emit remove(id, sig); }); + QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove); QObject::connect(chart, &QChart::plotAreaChanged, [=](const QRectF &plotArea) { // use a singleshot timer to avoid recursion call. timer->start(); }); } +ChartView::~ChartView() { + for (auto &s : sigs) + emit seriesRemoved(s.msg_id, s.sig); +} + +void ChartView::addSeries(const QString &msg_id, const Signal *sig) { + QLineSeries *series = new QLineSeries(this); + chart()->addSeries(series); + series->attachAxis(axis_x); + series->attachAxis(axis_y); + auto [source, address] = DBCManager::parseId(msg_id); + sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series}); + updateTitle(); + updateSeries(sig); +} + +void ChartView::removeSeries(const QString &msg_id, const Signal *sig) { + auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); + if (it != sigs.end()) { + it = removeSeries(it); + } +} + +bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const { + auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); + return it != sigs.end(); +} + +QList::iterator ChartView::removeSeries(const QList::iterator &it) { + chart()->removeSeries(it->series); + it->series->deleteLater(); + emit seriesRemoved(it->msg_id, it->sig); + + auto ret = sigs.erase(it); + if (!sigs.isEmpty()) { + updateAxisY(); + } else { + emit remove(); + } + return ret; +} + +void ChartView::signalUpdated(const Signal *sig) { + auto it = std::find_if(sigs.begin(), sigs.end(), [=](auto &s) { return s.sig == sig; }); + if (it != sigs.end()) { + updateTitle(); + // TODO: don't update series if only name changed. + updateSeries(sig); + } +} + +void ChartView::signalRemoved(const Signal *sig) { + for (auto it = sigs.begin(); it != sigs.end(); /**/) { + it = (it->sig == sig) ? removeSeries(it) : ++it; + } +} + +void ChartView::msgUpdated(uint32_t address) { + auto it = std::find_if(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; }); + if (it != sigs.end()) + updateTitle(); +} + +void ChartView::msgRemoved(uint32_t address) { + for (auto it = sigs.begin(); it != sigs.end(); /**/) { + it = (it->address == address) ? removeSeries(it) : ++it; + } +} + void ChartView::resizeEvent(QResizeEvent *event) { QChartView::resizeEvent(event); close_btn_proxy->setPos(event->size().width() - close_btn_proxy->size().width() - 11, 8); } void ChartView::updateTitle() { - chart()->setTitle(tr("%1 %2 %3").arg(dbc()->msg(id)->name).arg(id).arg(signal->name.c_str())); + for (auto &s : sigs) { + s.series->setName(QString("%1 %2 %3").arg(s.sig->name.c_str()).arg(msgName(s.msg_id)).arg(s.msg_id)); + } } void ChartView::updateFromSettings() { @@ -249,9 +307,15 @@ void ChartView::updateFromSettings() { line_marker->setPen(QPen(color, 2)); } -void ChartView::setRange(double min, double max, bool force_update) { - auto axis_x = dynamic_cast(chart()->axisX()); - if (force_update || (min != axis_x->min() || max != axis_x->max())) { +void ChartView::setEventsRange(const std::pair &range) { + if (range != events_range) { + events_range = range; + updateSeries(); + } +} + +void ChartView::setDisplayRange(double min, double max) { + if (min != axis_x->min() || max != axis_x->max()) { axis_x->setRange(min, max); updateAxisY(); } @@ -268,7 +332,6 @@ void ChartView::adjustChartMargins() { } void ChartView::updateLineMarker(double current_sec) { - auto axis_x = dynamic_cast(chart()->axisX()); int x = chart()->plotArea().left() + chart()->plotArea().width() * (current_sec - axis_x->min()) / (axis_x->max() - axis_x->min()); if (int(line_marker->line().x1()) != x) { @@ -276,48 +339,72 @@ void ChartView::updateLineMarker(double current_sec) { } } -void ChartView::updateSeries(const std::pair range) { +void ChartView::updateSeries(const Signal *sig) { auto events = can->events(); if (!events) return; - vals.clear(); - vals.reserve((range.second - range.first) * 1000); // [n]seconds * 1000hz - auto [bus, address] = DBCManager::parseId(id); - double route_start_time = can->routeStartTime(); - Event begin_event(cereal::Event::Which::INIT_DATA, (route_start_time + range.first) * 1e9); - auto begin = std::lower_bound(events->begin(), events->end(), &begin_event, Event::lessThan()); - double end_ns = (route_start_time + range.second) * 1e9; - for (auto it = begin; it != events->end() && (*it)->mono_time <= end_ns; ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - for (const auto &c : (*it)->event.getCan()) { - if (bus == c.getSrc() && address == c.getAddress()) { - auto dat = c.getDat(); - double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *signal); - double ts = ((*it)->mono_time / (double)1e9) - route_start_time; // seconds - vals.push_back({ts, value}); + for (int i = 0; i < sigs.size(); ++i) { + if (auto &s = sigs[i]; !sig || s.sig == sig) { + s.vals.clear(); + s.vals.reserve((events_range.second - events_range.first) * 1000); // [n]seconds * 1000hz + s.min_y = std::numeric_limits::max(); + s.max_y = std::numeric_limits::lowest(); + + double route_start_time = can->routeStartTime(); + Event begin_event(cereal::Event::Which::INIT_DATA, (route_start_time + events_range.first) * 1e9); + auto begin = std::lower_bound(events->begin(), events->end(), &begin_event, Event::lessThan()); + double end_ns = (route_start_time + events_range.second) * 1e9; + + for (auto it = begin; it != events->end() && (*it)->mono_time <= end_ns; ++it) { + if ((*it)->which == cereal::Event::Which::CAN) { + for (const auto &c : (*it)->event.getCan()) { + if (s.source == c.getSrc() && s.address == c.getAddress()) { + auto dat = c.getDat(); + double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *s.sig); + double ts = ((*it)->mono_time / (double)1e9) - route_start_time; // seconds + s.vals.push_back({ts, value}); + + if (value < s.min_y) s.min_y = value; + if (value > s.max_y) s.max_y = value; + } + } } } + + QLineSeries *series = (QLineSeries *)chart()->series()[i]; + series->replace(s.vals); } } - QLineSeries *series = (QLineSeries *)chart()->series()[0]; - series->replace(vals); + updateAxisY(); } // auto zoom on yaxis void ChartView::updateAxisY() { - const auto axis_x = dynamic_cast(chart()->axisX()); - const auto axis_y = dynamic_cast(chart()->axisY()); - auto begin = std::lower_bound(vals.begin(), vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); - if (begin == vals.end()) - return; - - auto end = std::upper_bound(vals.begin(), vals.end(), axis_x->max(), [](double x, auto &p) { return x < p.x(); }); - const auto [min, max] = std::minmax_element(begin, end, [](auto &p1, auto &p2) { return p1.y() < p2.y(); }); - if (max->y() == min->y()) { - axis_y->setRange(min->y() - 1, max->y() + 1); + double min_y = std::numeric_limits::max(); + double max_y = std::numeric_limits::lowest(); + if (events_range == std::pair{axis_x->min(), axis_x->max()}) { + for (auto &s : sigs) { + if (s.min_y < min_y) min_y = s.min_y; + if (s.max_y > max_y) max_y = s.max_y; + } } else { - double range = max->y() - min->y(); - axis_y->setRange(min->y() - range * 0.05, max->y() + range * 0.05); + for (auto &s : sigs) { + auto begin = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); + if (begin == s.vals.end()) + return; + + auto end = std::upper_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](double x, auto &p) { return x < p.x(); }); + const auto [min, max] = std::minmax_element(begin, end, [](auto &p1, auto &p2) { return p1.y() < p2.y(); }); + if (min->y() < min_y) min_y = min->y(); + if (max->y() > max_y) max_y = max->y(); + } + } + + if (max_y == min_y) { + axis_y->setRange(min_y - 1, max_y + 1); + } else { + double range = max_y - min_y; + axis_y->setRange(min_y - range * 0.05, max_y + range * 0.05); axis_y->applyNiceNumbers(); } } @@ -333,7 +420,6 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { rubber->hide(); QRectF rect = rubber->geometry().normalized(); rect.translate(-chart()->plotArea().topLeft()); - const auto axis_x = dynamic_cast(chart()->axisX()); double min = axis_x->min() + (rect.left() / chart()->plotArea().width()) * (axis_x->max() - axis_x->min()); double max = axis_x->min() + (rect.right() / chart()->plotArea().width()) * (axis_x->max() - axis_x->min()); if (rubber->width() <= 0) { @@ -357,26 +443,40 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { void ChartView::mouseMoveEvent(QMouseEvent *ev) { auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); - if (!is_zooming) { - const auto plot_area = chart()->plotArea(); - auto axis_x = dynamic_cast(chart()->axisX()); + const auto plot_area = chart()->plotArea(); + + if (!is_zooming && plot_area.contains(ev->pos())) { double x = std::clamp((double)ev->pos().x(), plot_area.left(), plot_area.right() - 1); double sec = axis_x->min() + (axis_x->max() - axis_x->min()) * (x - plot_area.left()) / plot_area.width(); - auto value = std::upper_bound(vals.begin(), vals.end(), sec, [](double x, auto &p) { return x < p.x(); }); - if (value != vals.end()) { - QPointF pos = chart()->mapToPosition((*value)); + QStringList text_list; + QPointF pos = plot_area.bottomRight(); + double tm = 0.0; + + for (auto &s : sigs) { + auto value = std::upper_bound(s.vals.begin(), s.vals.end(), sec, [](double x, auto &p) { return x < p.x(); }); + if (value != s.vals.end()) { + text_list.push_back(QString(" %1 : %2 ").arg(sigs.size() > 1 ? s.sig->name.c_str() : "Value").arg(value->y())); + tm = value->x(); + auto y_pos = chart()->mapToPosition(*value); + if (y_pos.y() < pos.y()) pos = y_pos; + } + } + + if (!text_list.isEmpty()) { + value_text->setHtml("
 Time: " + + QString::number(tm, 'f', 3) + " 
" + text_list.join("
") + "
"); track_line->setLine(pos.x(), plot_area.top(), pos.x(), plot_area.bottom()); - track_ellipse->setRect(pos.x() - 5, pos.y() - 5, 10, 10); - value_text->setHtml(tr("
%1, %2)
") - .arg(value->x(), 0, 'f', 3).arg(value->y())); int text_x = pos.x() + 8; - if ((text_x + value_text->boundingRect().width()) > plot_area.right()) { - text_x = pos.x() - value_text->boundingRect().width() - 8; + QRectF text_rect = value_text->boundingRect(); + if ((text_x + text_rect.width()) > plot_area.right()) { + text_x = pos.x() - text_rect.width() - 8; } - value_text->setPos(text_x, pos.y() - 10); + value_text->setPos(text_x, pos.y() - text_rect.height() / 2); + track_ellipse->setRect(pos.x() - 5, pos.y() - 5, 10, 10); } - item_group->setVisible(value != vals.end()); + item_group->setVisible(!text_list.isEmpty()); } else { + item_group->setVisible(false); setViewportUpdateMode(QGraphicsView::FullViewportUpdate); } QChartView::mouseMoveEvent(ev); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 20c673a757..e32072a831 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" @@ -18,35 +20,59 @@ class ChartView : public QChartView { Q_OBJECT public: - ChartView(const QString &id, const Signal *sig, QWidget *parent = nullptr); - void updateSeries(const std::pair range); - void setRange(double min, double max, bool force_update = false); + ChartView(QWidget *parent = nullptr); + ~ChartView(); + void addSeries(const QString &msg_id, const Signal *sig); + void removeSeries(const QString &msg_id, const Signal *sig); + bool hasSeries(const QString &msg_id, const Signal *sig) const; + void updateSeries(const Signal *sig = nullptr); + void setEventsRange(const std::pair &range); + void setDisplayRange(double min, double max); void updateLineMarker(double current_sec); - void updateFromSettings(); - void updateTitle(); - QString id; - const Signal *signal; + struct SigItem { + QString msg_id; + uint8_t source = 0; + uint32_t address = 0; + const Signal *sig = nullptr; + QLineSeries *series = nullptr; + double min_y = 0; + double max_y = 0; + QVector vals; + }; signals: + void seriesRemoved(const QString &id, const Signal *sig); void zoomIn(double min, double max); void zoomReset(); - void remove(const QString &msg_id, const Signal *sig); + void remove(); + +private slots: + void msgRemoved(uint32_t address); + void msgUpdated(uint32_t address); + void signalUpdated(const Signal *sig); + void signalRemoved(const Signal *sig); private: + QList::iterator removeSeries(const QList::iterator &it); void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *ev) override; void leaveEvent(QEvent *event) override; void resizeEvent(QResizeEvent *event) override; void adjustChartMargins(); void updateAxisY(); + void updateTitle(); + void updateFromSettings(); + QValueAxis *axis_x; + QValueAxis *axis_y; QGraphicsItemGroup *item_group; QGraphicsLineItem *line_marker, *track_line; QGraphicsEllipseItem *track_ellipse; QGraphicsTextItem *value_text; QGraphicsProxyWidget *close_btn_proxy; - QVector vals; + std::pair events_range = {0, 0}; + QList sigs; }; class ChartsWidget : public QWidget { @@ -54,9 +80,9 @@ class ChartsWidget : public QWidget { public: ChartsWidget(QWidget *parent = nullptr); - void showChart(const QString &id, const Signal *sig, bool show); + void showChart(const QString &id, const Signal *sig, bool show, bool merge); void removeChart(ChartView *chart); - bool isChartOpened(const QString &id, const Signal *sig); + inline bool isChartOpened(const QString &id, const Signal *sig) { return findChart(id, sig) != nullptr; } signals: void dock(bool floating); @@ -69,10 +95,10 @@ private: void updateState(); void zoomIn(double min, double max); void zoomReset(); - void signalUpdated(const Signal *sig); void updateToolBar(); - void removeAll(const Signal *sig = nullptr); + void removeAll(); bool eventFilter(QObject *obj, QEvent *event) override; + ChartView *findChart(const QString &id, const Signal *sig); QLabel *title_label; QLabel *range_label; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index a0660901cf..93b7aa88f7 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -122,7 +123,9 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa save_timer->callOnTimeout(this, &SignalEdit::saveSignal); QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); - QObject::connect(plot_btn, &QToolButton::clicked, [this](bool checked) { emit showChart(msg_id, sig, checked); }); + QObject::connect(plot_btn, &QToolButton::clicked, [this](bool checked) { + emit showChart(msg_id, sig, checked, QGuiApplication::keyboardModifiers() & Qt::ShiftModifier); + }); QObject::connect(seek_btn, &QToolButton::clicked, [this]() { SignalFindDlg(msg_id, sig, this).exec(); }); QObject::connect(remove_btn, &QToolButton::clicked, [this]() { emit remove(sig); }); QObject::connect(form, &SignalForm::changed, [this]() { save_timer->start(); }); @@ -172,7 +175,7 @@ void SignalEdit::saveSignal() { } void SignalEdit::setChartOpened(bool opened) { - plot_btn->setToolTip(opened ? tr("Close Plot") : tr("Show Plot")); + plot_btn->setToolTip(opened ? tr("Close Plot") : tr("Show Plot\nSHIFT click to add to previous opened chart")); plot_btn->setChecked(opened); } diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index f889a9c096..f035797e72 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -42,7 +42,7 @@ public: signals: void highlight(const Signal *sig); - void showChart(const QString &name, const Signal *sig, bool show); + void showChart(const QString &name, const Signal *sig, bool show, bool merge); void remove(const Signal *sig); void save(const Signal *sig, const Signal &new_sig); void showFormClicked(); From 9c815c2081fb61dfe84a79b617f17280c0396773 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 19 Nov 2022 02:25:11 +0800 Subject: [PATCH 11/12] Cabana: draw line marker in drawForegound (#26542) draw line marker in drawForegound --- tools/cabana/chartswidget.cc | 25 ++++++++----------------- tools/cabana/chartswidget.h | 4 ++-- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 4bd398a93b..5a129b5f61 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -102,7 +102,7 @@ void ChartsWidget::updateState() { const auto &range = is_zoomed ? zoomed_range : display_range; for (auto c : charts) { c->setDisplayRange(range.first, range.second); - c->updateLineMarker(current_sec); + c->scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } } @@ -178,9 +178,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { // top margin for title chart->setMargins({0, 11, 0, 0}); - line_marker = new QGraphicsLineItem(chart); - line_marker->setZValue(chart->zValue() + 10); - track_line = new QGraphicsLineItem(chart); track_line->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); track_ellipse = new QGraphicsEllipseItem(chart); @@ -304,7 +301,6 @@ void ChartView::updateFromSettings() { setFixedHeight(settings.chart_height); chart()->setTheme(settings.chart_theme == 0 ? QChart::ChartThemeLight : QChart::QChart::ChartThemeDark); auto color = chart()->titleBrush().color(); - line_marker->setPen(QPen(color, 2)); } void ChartView::setEventsRange(const std::pair &range) { @@ -327,15 +323,6 @@ void ChartView::adjustChartMargins() { if (chart()->plotArea().left() != aligned_pos) { const float left_margin = chart()->margins().left() + aligned_pos - chart()->plotArea().left(); chart()->setMargins(QMargins(left_margin, 11, 0, 0)); - updateLineMarker(can->currentSec()); - } -} - -void ChartView::updateLineMarker(double current_sec) { - int x = chart()->plotArea().left() + - chart()->plotArea().width() * (current_sec - axis_x->min()) / (axis_x->max() - axis_x->min()); - if (int(line_marker->line().x1()) != x) { - line_marker->setLine(x, chart()->plotArea().top() - chart()->margins().top() + 3, x, height()); } } @@ -429,7 +416,6 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { // zoom in if selected range is greater than 0.5s emit zoomIn(min, max); } - viewport()->update(); event->accept(); } else if (event->button() == Qt::RightButton) { emit zoomReset(); @@ -437,7 +423,6 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } else { QGraphicsView::mouseReleaseEvent(event); } - setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); } void ChartView::mouseMoveEvent(QMouseEvent *ev) { @@ -477,7 +462,13 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { item_group->setVisible(!text_list.isEmpty()); } else { item_group->setVisible(false); - setViewportUpdateMode(QGraphicsView::FullViewportUpdate); } QChartView::mouseMoveEvent(ev); } + +void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { + qreal x = chart()->plotArea().left() + + chart()->plotArea().width() * (can->currentSec() - axis_x->min()) / (axis_x->max() - axis_x->min()); + painter->setPen(QPen(chart()->titleBrush().color(), 2)); + painter->drawLine(QPointF{x, chart()->plotArea().top() - 2}, QPointF{x, chart()->plotArea().bottom() + 2}); +} diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index e32072a831..8f0af95b1a 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -28,7 +28,6 @@ public: void updateSeries(const Signal *sig = nullptr); void setEventsRange(const std::pair &range); void setDisplayRange(double min, double max); - void updateLineMarker(double current_sec); struct SigItem { QString msg_id; @@ -63,11 +62,12 @@ private: void updateAxisY(); void updateTitle(); void updateFromSettings(); + void drawForeground(QPainter *painter, const QRectF &rect) override; QValueAxis *axis_x; QValueAxis *axis_y; QGraphicsItemGroup *item_group; - QGraphicsLineItem *line_marker, *track_line; + QGraphicsLineItem *track_line; QGraphicsEllipseItem *track_ellipse; QGraphicsTextItem *value_text; QGraphicsProxyWidget *close_btn_proxy; From 34c80a6fbdf8780ad0b75f497c226cf1d9de0ddb Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Fri, 18 Nov 2022 17:50:24 -0800 Subject: [PATCH 12/12] Albert Einstein Model (#26456) * d0bc247d-9529-4e50-a5dd-95a8a5733874/440 38fb1ce9-18d7-4292-9ffd-678f8483ebf4/700 * update model replay ref commit --- selfdrive/modeld/models/supercombo.onnx | 2 +- selfdrive/test/process_replay/model_replay_ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index 8805b3dce8..c0db988cf6 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:db746e3753de84367595fedd089c2bd41b06bd401ea28e085663533d0e63d74b +oid sha256:c73998c9f428380dd2282b451de6011469b717498ae83578cbf7aa95948910f7 size 45962473 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index f541b6a6d5..cdd6ed7a6b 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -30efb4238327d723e17a3bda7e7c19c18f8a3b18 +ca02aa240e629920ad88a6510213cb0a153af92b